Procházet zdrojové kódy

* Corrected some invalid syntax in skill_db.txt (wrong usage of commas)
* Renamed BA_FROSTJOKE to BA_FROSTJOKER (aegis server-side name)
* Implemented a generic framework for parsing delimited db files (allows specifying min/max column ranges and max number of rows to read)
* Corrected a typo in quest_update_objective()
* Cleaned up pc.c a bit

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@12599 54d463be-8e91-2dee-dedb-b68131a5f0ec

ultramage před 17 roky
rodič
revize
9609149c15
14 změnil soubory, kde provedl 227 přidání a 281 odebrání
  1. 5 0
      Changelog-Trunk.txt
  2. 2 2
      conf/log_athena.conf
  3. 1 1
      db/abra_db.txt
  4. 1 1
      db/mob_db.txt
  5. 6 6
      db/skill_db.txt
  6. 80 0
      src/common/strlib.c
  7. 4 0
      src/common/strlib.h
  8. 14 18
      src/map/atcommand.c
  9. 1 16
      src/map/mob.c
  10. 59 107
      src/map/pc.c
  11. 1 1
      src/map/quest.c
  12. 49 126
      src/map/skill.c
  13. 3 2
      src/map/skill.h
  14. 1 1
      src/map/status.c

+ 5 - 0
Changelog-Trunk.txt

@@ -4,6 +4,11 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
 2008/04/15
+	* Corrected some invalid syntax in skill_db.txt (wrong usage of commas)
+	* Renamed BA_FROSTJOKE to BA_FROSTJOKER (aegis server-side name)
+	* Implemented a generic framework for parsing delimited db files
+	- allows specifying min/max column ranges and max number of rows to read
+	* Cleaned up pc.c a bit [ultramage]
 	* Updated item_db.sql to latest [Toms]
 2008/04/14
 	* Fixed a possible crash in char_sql. (since r12575, later modified in r12590). [FlavioJS]

+ 2 - 2
conf/log_athena.conf

@@ -54,7 +54,7 @@ refine_items_log: 5
 // Log Items whith min drop rate <= rare_items_log
 // 1 = 0.01%, 100 = 1% drop chance, etc
 rare_items_log: 100
-// don't log it if the current item price < price_items_log
+// don't log it if the current item buy price < price_items_log
 price_items_log: 1000
 // don't log it if the current item amount < amount_items_log
 amount_items_log: 100
@@ -121,7 +121,7 @@ log_chat_db: chatlog
 // Dead Branch Log File
 log_branch_file: log/branchlog.log
 
-// Drops & Pickups  Log File
+// Drops & Pickups Log File
 log_pick_file: log/picklog.log
 
 // Zeny Log File

+ 1 - 1
db/abra_db.txt

@@ -60,7 +60,7 @@
 //49,Improve Dodge,1,0
 50,Steal,2,5000
 51,Hiding,2,5000
-52,Envenom,1,5000,
+52,Envenom,1,5000
 53,Detoxify,1,5000
 
 54,Resurrection,1,5000

+ 1 - 1
db/mob_db.txt

@@ -6,7 +6,7 @@
 
 1001,SCORPION,Scorpion,Scorpion,24,1109,0,287,176,1,80,135,30,0,1,24,24,5,52,5,10,12,0,4,23,0x3195,200,1564,864,576,0,0,0,0,0,0,0,0,990,70,904,5500,757,57,943,210,7041,100,508,200,625,20,0,0,0,0,4068,1
 1002,PORING,Poring,Poring,1,50,0,2,1,1,7,10,0,5,1,1,1,0,6,30,10,12,1,3,21,0x83,400,1872,672,480,0,0,0,0,0,0,0,0,909,7000,1202,100,938,400,512,1000,713,1500,512,150,619,20,0,0,0,0,4001,1
-//1003,TESTEGG,Test Egg,Test Egg,2,100000,0,10,10,0,3,9,99,0,1,99,1,1,1,1,10,12,0,4,22,0,512,0,512,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+1003,TESTEGG,Test Egg,Test Egg,2,100000,0,10,10,0,3,9,99,0,1,99,1,1,1,1,10,12,0,4,22,0,512,0,512,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
 1004,HORNET,Hornet,Hornet,8,169,0,19,15,1,22,27,5,5,6,20,8,10,17,5,10,12,0,4,24,0x1189,150,1292,792,216,0,0,0,0,0,0,0,0,992,80,939,9000,909,3500,1208,15,511,350,518,150,0,0,0,0,0,0,4019,1
 1005,FARMILIAR,Familiar,Familiar,8,155,0,28,15,1,20,28,0,0,1,12,8,5,28,0,10,12,0,2,27,0x3885,150,1276,576,384,0,0,0,0,0,0,0,0,913,5500,1105,20,2209,15,601,50,514,100,507,700,645,50,0,0,0,0,4020,1
 //1006,THIEF_BUG_LARVA,Thief Bug Larva,Thief Bug Larva,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,1,651,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

+ 6 - 6
db/skill_db.txt

@@ -468,24 +468,24 @@
 424,0,0,0,0,0,0,5,0,no,0,0,0,weapon,0,		TK_POWER,Kihop
 425,0,6,4,2:4:1:3:8:7:6,0x1,0,7,1,no,0,0,0,weapon,0,	TK_SEVENWIND,Mild Wind
 426,0,6,4,0,0x1,0,5,1,no,0,0,0,weapon,0,		TK_HIGHJUMP,Taekwon Jump
-427,0,6,4,0,0x1,0,3,1,yes,0,0,0,magic,0,		SG_FEEL,Feeling the Sun, Moon and Stars
+427,0,6,4,0,0x1,0,3,1,yes,0,0,0,magic,0,		SG_FEEL,Feeling the Sun Moon and Stars
 428,1,6,4,-1,0x42,1,3,1,yes,0,0,0,weapon,2,	SG_SUN_WARM,Warmth of the Sun
 429,1,6,4,-1,0x42,1,3,1,yes,0,0,0,weapon,2,	SG_MOON_WARM,Warmth of the Moon
 430,1,6,4,-1,0x42,1,3,1,yes,0,0,0,weapon,2,	SG_STAR_WARM,Warmth of the Stars
 431,0,0,4,0,0x1,0,4,1,yes,0,0,0,magic,0,		SG_SUN_COMFORT,Comfort of the Sun
 432,0,0,4,0,0x1,0,4,1,yes,0,0,0,magic,0,		SG_MOON_COMFORT,Comfort of the Moon
 433,0,0,4,0,0x1,0,4,1,yes,0,0,0,magic,0,		SG_STAR_COMFORT,Comfort of the Stars
-434,10,6,1,0,0x1,0,3,1,yes,0,0,0,magic,0,	SG_HATE,Hatred of the Sun, Moon and Stars
+434,10,6,1,0,0x1,0,3,1,yes,0,0,0,magic,0,	SG_HATE,Hatred of the Sun Moon and Stars
 435,0,0,0,0,0,0,3,0,no,0,0,0,none,0,		SG_SUN_ANGER,Anger of the Sun
 436,0,0,0,0,0,0,3,0,no,0,0,0,none,0,		SG_MOON_ANGER,Anger of the Moon
 437,0,0,0,0,0,0,3,0,no,0,0,0,none,0,		SG_STAR_ANGER,Anger of the Stars
 438,0,0,0,0,0,0,5,0,no,0,0,0,none,0,		SG_SUN_BLESS,Blessing of the Sun
 439,0,0,0,0,0,0,5,0,no,0,0,0,none,0,		SG_MOON_BLESS,Blessing of the Moon
 440,0,0,0,0,0,0,5,0,no,0,0,0,none,0,		SG_STAR_BLESS,Blessing of the Stars
-441,0,0,0,0,0,0,10,0,no,0,0,0,none,0,		SG_DEVIL,Demon of the Sun, Moon and Stars
-442,0,0,0,0,0,0,3,0,no,0,0,0,none,0,		SG_FRIEND,Friend of the Sun, Moon and Stars
-443,0,0,0,0,0,0,10,0,no,0,0,0,none,0,		SG_KNOWLEDGE,Knowledge of the Sun, Moon and Stars
-444,0,6,4,0,0x1,0,1,1,no,0,0,0,misc,0,		SG_FUSION,Union of the Sun, Moon and Stars
+441,0,0,0,0,0,0,10,0,no,0,0,0,none,0,		SG_DEVIL,Demon of the Sun Moon and Stars
+442,0,0,0,0,0,0,3,0,no,0,0,0,none,0,		SG_FRIEND,Friend of the Sun Moon and Stars
+443,0,0,0,0,0,0,10,0,no,0,0,0,none,0,		SG_KNOWLEDGE,Knowledge of the Sun Moon and Stars
+444,0,6,4,0,0x1,0,1,1,no,0,0,0,misc,0,		SG_FUSION,Union of the Sun Moon and Stars
 445,9,6,16,0,0x1,0,5,1,yes,0,0x200,0,magic,0,	SL_ALCHEMIST,Spirit of the Alchemist
 446,9,6,16,0,0x1,0,1,1,yes,0,0xC08,0,none,0,	AM_BERSERKPITCHER,Aid Berserk Potion
 447,9,6,16,0,0x1,0,5,1,yes,0,0x200,0,magic,0,	SL_MONK,Spirit of the Monk

+ 80 - 0
src/common/strlib.c

@@ -786,6 +786,86 @@ size_t sv_unescape_c(char* out_dest, const char* src, size_t len)
 	return j;
 }
 
+/// Opens and parses a file containing delim-separated columns, feeding them to the specified callback function row by row.
+/// Tracks the progress of the operation (current line number, number of successfully processed rows).
+/// Returns 'true' if it was able to process the specified file, or 'false' if it could not be read.
+///
+/// @param directory Directory
+/// @param filename File to process
+/// @param delim Field delimiter
+/// @param mincols Minimum number of columns of a valid row
+/// @param maxcols Maximum number of columns of a valid row
+/// @param parseproc User-supplied row processing function
+/// @return true on success, false if file could not be opened
+bool sv_readdb(const char* directory, const char* filename, char delim, int mincols, int maxcols, int maxrows, bool (*parseproc)(char* fields[], int columns, int current))
+{
+	FILE* fp;
+	int lines = 0;
+	int entries = 0;
+	char* fields[64]; // room for 63 fields ([0] is reserved)
+	int columns;
+	char path[1024], line[1024];
+
+	if( maxcols > ARRAYLENGTH(fields)-1 )
+	{
+		ShowError("sv_readdb: Insufficient column storage in parser for file \"%s\" (want %d, have only %d). Increase the capacity in the source code please.\n", path, maxcols, ARRAYLENGTH(fields)-1);
+		return false;
+	}
+
+	// open file
+	snprintf(path, sizeof(path), "%s/%s", directory, filename);
+	fp = fopen(path, "r");
+	if( fp == NULL )
+	{
+		ShowError("sv_readdb: can't read %s\n", path);
+		return false;
+	}
+
+	// process rows one by one
+	while( fgets(line, sizeof(line), fp) )
+	{
+		lines++;
+		if( line[0] == '/' && line[1] == '/' )
+			continue;
+		//TODO: strip trailing // comment
+		//TODO: strip trailing whitespace
+		if( line[0] == '\0' || line[0] == '\n' )
+			continue;
+
+		columns = sv_split(line, strlen(line), 0, delim, fields, ARRAYLENGTH(fields), SV_NOESCAPE_NOTERMINATE);
+
+		if( columns < mincols )
+		{
+			ShowError("sv_readdb: Insufficient columns in line %d of \"%s\" (found %d, need at least %d).\n", lines, path, columns, mincols);
+			continue; // not enough columns
+		}
+		if( columns > maxcols )
+		{
+			ShowError("sv_readdb: Too many columns in line %d of \"%s\" (found %d, maximum is %d).\n", lines, path, columns, maxcols );
+			continue; // too many columns
+		}
+		if( entries == maxrows )
+		{
+			ShowError("sv_readdb: Reached the maximum allowed number of entries (%d) when parsing file \"%s\".\n", maxrows, path);
+			break;
+		}
+
+		// parse this row
+		if( !parseproc(fields+1, columns, entries) )
+		{
+			ShowError("sv_readdb: Could not process contents of line %d of \"%s\".\n", lines, path);
+			continue; // invalid row contents
+		}
+
+		// success!
+		entries++;
+	}
+
+	fclose(fp);
+	ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, path);
+
+	return true;
+}
 
 
 /////////////////////////////////////////////////////////////////////

+ 4 - 0
src/common/strlib.h

@@ -91,6 +91,10 @@ size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* esca
 /// out_dest should be len+1 in size and can be the same buffer as src.
 size_t sv_unescape_c(char* out_dest, const char* src, size_t len);
 
+/// Opens and parses a file containing delim-separated columns, feeding them to the specified callback function row by row.
+/// Tracks the progress of the operation (current line number, number of successfully processed rows).
+/// Returns 'true' if it was able to process the specified file, or 'false' if it could not be read.
+bool sv_readdb(const char* directory, const char* filename, char delim, int mincols, int maxcols, int maxrows, bool (*parseproc)(char* fields[], int columns, int current));
 
 
 /// StringBuf - dynamic string

+ 14 - 18
src/map/atcommand.c

@@ -5674,8 +5674,8 @@ int atcommand_displayskill(const int fd, struct map_session_data* sd, const char
 int atcommand_skilltree(const int fd, struct map_session_data* sd, const char* command, const char* message)
 {
 	struct map_session_data *pl_sd = NULL;
-	int skillnum, skillidx = -1;
-	int meets = 1, j, c=0;
+	int skillnum;
+	int meets, j, c=0;
 	char target[NAME_LENGTH], *tbl;
 	struct skill_tree_entry *ent;
 	nullpo_retr(-1, sd);
@@ -5696,37 +5696,33 @@ int atcommand_skilltree(const int fd, struct map_session_data* sd, const char* c
 
 	tbl = job_name(c);
 
-	sprintf(atcmd_output, "Player is using %s skill tree (%d basic points)",
-	tbl, pc_checkskill(pl_sd, 1));
+	sprintf(atcmd_output, "Player is using %s skill tree (%d basic points)", tbl, pc_checkskill(pl_sd, 1));
 	clif_displaymessage(fd, atcmd_output);
 
-	for (j = 0; skill_tree[c][j].id != 0; j++) {
-		if (skill_tree[c][j].id == skillnum) {
-			skillidx = j;
-			break;
-		}
-	}
-
-	if (skillidx == -1) {
+	ARR_FIND( 0, MAX_SKILL_TREE, j, skill_tree[c][j].id == 0 || skill_tree[c][j].id == skillnum );
+	if( j == MAX_SKILL_TREE || skill_tree[c][j].id == 0 )
+	{
 		sprintf(atcmd_output, "I do not believe the player can use that skill");
 		clif_displaymessage(fd, atcmd_output);
 		return 0;
 	}
 
-	ent = &skill_tree[c][skillidx];
+	ent = &skill_tree[c][j];
 
+	meets = 1;
 	for(j=0;j<5;j++)
+	{
 		if( ent->need[j].id && pc_checkskill(sd,ent->need[j].id) < ent->need[j].lv)
 		{
 			sprintf(atcmd_output, "player requires level %d of skill %s", ent->need[j].lv, skill_db[ent->need[j].id].desc);
 			clif_displaymessage(fd, atcmd_output);
 			meets = 0;
 		}
-
-		if (meets == 1) {
-			sprintf(atcmd_output, "I believe the player meets all the requirements for that skill");
-			clif_displaymessage(fd, atcmd_output);
-		}
+	}
+	if (meets == 1) {
+		sprintf(atcmd_output, "I believe the player meets all the requirements for that skill");
+		clif_displaymessage(fd, atcmd_output);
+	}
 
 	return 0;
 }

+ 1 - 16
src/map/mob.c

@@ -3409,22 +3409,7 @@ int mob_clone_spawn(struct map_session_data *sd, int m, int x, int y, const char
 		if (duration) //Auto Delete after a while.
 			md->deletetimer = add_timer (gettick() + duration, mob_timer_delete, md->bl.id, 0);
 	}
-#if 0
-	//I am playing with this for packet-research purposes, enable it if you want, but don't remove it :X [Skotlex]
-	//Guardian data
-	if (sd->status.guild_id) {
-		struct guild* g = guild_search(sd->status.guild_id);
-		md->guardian_data = aCalloc(1, sizeof(struct guardian_data));
-		md->guardian_data->castle = NULL;
-		md->guardian_data->number = MAX_GUARDIANS;
-		md->guardian_data->guild_id = sd->status.guild_id;
-		if (g)
-		{
-			md->guardian_data->emblem_id = g->emblem_id;
-			memcpy(md->guardian_data->guild_name, g->name, NAME_LENGTH);
-		}
-	}
-#endif
+
 	mob_spawn(md);
 
 	return md->bl.id;

+ 59 - 107
src/map/pc.c

@@ -19,6 +19,7 @@
 #include "intif.h"
 #include "itemdb.h"
 #include "log.h"
+#include "mail.h"
 #include "map.h"
 #include "path.h"
 #include "mercenary.h" // merc_is_hom_active()
@@ -34,10 +35,6 @@
 #include "pc.h"
 #include "quest.h"
 
-#ifndef TXT_ONLY // mail system [Valaris]
-#include "mail.h"
-#endif
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -494,23 +491,19 @@ int pc_setequipindex(struct map_session_data *sd)
 			for(j=0;j<EQI_MAX;j++)
 				if(sd->status.inventory[i].equip & equip_pos[j])
 					sd->equip_index[j] = i;
-			if(sd->status.inventory[i].equip & EQP_HAND_R) {
+
+			if(sd->status.inventory[i].equip & EQP_HAND_R)
+			{
 				if(sd->inventory_data[i])
 					sd->weapontype1 = sd->inventory_data[i]->look;
 				else
 					sd->weapontype1 = 0;
 			}
-			if(sd->status.inventory[i].equip & EQP_HAND_L) {
-				if(sd->inventory_data[i]) {
-					if(sd->inventory_data[i]->type == 4) {
-						if(sd->status.inventory[i].equip == EQP_HAND_L)
-							sd->weapontype2 = sd->inventory_data[i]->look;
-						else
-							sd->weapontype2 = 0;
-					}
-					else
-						sd->weapontype2 = 0;
-				}
+
+			if( sd->status.inventory[i].equip & EQP_HAND_L )
+			{
+				if( sd->inventory_data[i] && sd->inventory_data[i]->type == 4 )
+					sd->weapontype2 = sd->inventory_data[i]->look;
 				else
 					sd->weapontype2 = 0;
 			}
@@ -521,7 +514,8 @@ int pc_setequipindex(struct map_session_data *sd)
 	return 0;
 }
 
-static int pc_isAllowedCardOn(struct map_session_data *sd,int s,int eqindex,int flag)  {
+static int pc_isAllowedCardOn(struct map_session_data *sd,int s,int eqindex,int flag)
+{
 	int i;
 	struct item *item = &sd->status.inventory[eqindex];
 	struct item_data *data;
@@ -529,14 +523,8 @@ static int pc_isAllowedCardOn(struct map_session_data *sd,int s,int eqindex,int
 	if (itemdb_isspecial(item->card[0]))
 		return 1;
 	
-	for (i=0;i<s;i++)	{
-		if (item->card[i] &&
-			(data = itemdb_exists(item->card[i])) &&
-			data->flag.no_equip&flag
-		)
-			return 0;
-	}
-	return 1;              
+	ARR_FIND( 0, s, i, item->card[i] && (data = itemdb_exists(item->card[i])) != NULL && data->flag.no_equip&flag );
+	return( i < s ) ? 0 : 1;
 }
 
 bool pc_isequipped(struct map_session_data *sd, int nameid)
@@ -3283,32 +3271,34 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun
 		return 1;
 
 	i=MAX_CART;
-	if(itemdb_isstackable2(data)){
-		for(i=0;i<MAX_CART;i++){
-			if(sd->status.cart[i].nameid==item_data->nameid &&
-				sd->status.cart[i].card[0] == item_data->card[0] && sd->status.cart[i].card[1] == item_data->card[1] &&
-				sd->status.cart[i].card[2] == item_data->card[2] && sd->status.cart[i].card[3] == item_data->card[3]){
-				if(sd->status.cart[i].amount+amount > MAX_AMOUNT)
-					return 1;
-				sd->status.cart[i].amount+=amount;
-				clif_cart_additem(sd,i,amount,0);
-				break;
-			}
-		}
+	if(itemdb_isstackable2(data))
+	{
+		ARR_FIND( 0, MAX_CART, i,
+			sd->status.cart[i].nameid == item_data->nameid &&
+			sd->status.cart[i].card[0] == item_data->card[0] && sd->status.cart[i].card[1] == item_data->card[1] &&
+			sd->status.cart[i].card[2] == item_data->card[2] && sd->status.cart[i].card[3] == item_data->card[3] );
+	};
+
+	if( i < MAX_CART )
+	{// item already in cart, stack it
+		if(sd->status.cart[i].amount+amount > MAX_AMOUNT)
+			return 1; // no room
+
+		sd->status.cart[i].amount+=amount;
+		clif_cart_additem(sd,i,amount,0);
 	}
-	if(i >= MAX_CART){
-		for(i=0;i<MAX_CART;i++){
-			if(sd->status.cart[i].nameid==0){
-				memcpy(&sd->status.cart[i],item_data,sizeof(sd->status.cart[0]));
-				sd->status.cart[i].amount=amount;
-				sd->cart_num++;
-				clif_cart_additem(sd,i,amount,0);
-				break;
-			}
-		}
-		if(i >= MAX_CART)
-			return 1;
+	else
+	{// item not stackable or not present, add it
+		ARR_FIND( 0, MAX_CART, i, sd->status.cart[i].nameid == 0 );
+		if( i == MAX_CART )
+			return 1; // no room
+
+		memcpy(&sd->status.cart[i],item_data,sizeof(sd->status.cart[0]));
+		sd->status.cart[i].amount=amount;
+		sd->cart_num++;
+		clif_cart_additem(sd,i,amount,0);
 	}
+
 	sd->cart_weight += w;
 	clif_updatestatus(sd,SP_CARTINFO);
 
@@ -3343,7 +3333,8 @@ int pc_cart_delitem(struct map_session_data *sd,int n,int amount,int type)
 /*==========================================
  * カ?トへアイテム移動
  *------------------------------------------*/
-int pc_putitemtocart(struct map_session_data *sd,int idx,int amount) {
+int pc_putitemtocart(struct map_session_data *sd,int idx,int amount)
+{
 	struct item *item_data;
 
 	nullpo_retr(0, sd);
@@ -5078,32 +5069,6 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 		}
 	}
 
-	// PK/Karma system code (not enabled yet) [celest]
-	/*
-	if(sd->status.karma > 0) {
-		int eq_num=0,eq_n[MAX_INVENTORY];
-		memset(eq_n,0,sizeof(eq_n));
-		for(i=0;i<MAX_INVENTORY;i++){
-			int k;
-			for(k=0;k<MAX_INVENTORY;k++){
-				if(eq_n[k] <= 0){
-					eq_n[k]=i;
-					break;
-				}
-			}
-			eq_num++;
-		}
-		if(eq_num > 0){
-			int n = eq_n[rand()%eq_num];
-			if(rand()%10000 < sd->status.karma){
-				if(sd->status.inventory[n].equip)
-					pc_unequipitem(sd,n,0);
-				pc_dropitem(sd,n,1);
-			}
-		}
-	}
-	*/
-
 	if(battle_config.bone_drop==2
 		|| (battle_config.bone_drop==1 && map[sd->bl.m].flag.pvp))
 	{
@@ -5182,7 +5147,8 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 		}
 	}
 
-	if(map[sd->bl.m].flag.pvp_nightmaredrop){ // Moved this outside so it works when PVP isn't enabled and during pk mode [Ancyker]
+	if(map[sd->bl.m].flag.pvp_nightmaredrop)
+	{ // Moved this outside so it works when PVP isn't enabled and during pk mode [Ancyker]
 		for(j=0;j<MAX_DROP_PER_MAP;j++){
 			int id = map[sd->bl.m].drop_list[j].drop_id;
 			int type = map[sd->bl.m].drop_list[j].drop_type;
@@ -5196,13 +5162,12 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 					int k;
 					if( (type == 1 && !sd->status.inventory[i].equip)
 						|| (type == 2 && sd->status.inventory[i].equip)
-						||  type == 3){
-						for(k=0;k<MAX_INVENTORY;k++){
-							if(eq_n[k] <= 0){
-								eq_n[k]=i;
-								break;
-							}
-						}
+						||  type == 3)
+					{
+						ARR_FIND( 0, MAX_INVENTORY, k, eq_n[k] <= 0 );
+						if( k < MAX_INVENTORY )
+							eq_n[k] = i;
+
 						eq_num++;
 					}
 				}
@@ -6848,16 +6813,6 @@ int pc_divorce(struct map_session_data *sd)
  *------------------------------------------*/
 struct map_session_data *pc_get_partner(struct map_session_data *sd)
 {
-	//struct map_session_data *p_sd = NULL;
-	//char *nick;
-	//if(sd == NULL || !pc_ismarried(sd))
-	//	return NULL;
-	//nick=map_charid2nick(sd->status.partner_id);
-	//if (nick==NULL)
-	//	return NULL;
-	//if((p_sd=map_nick2sd(nick)) == NULL )
-	//	return NULL;
-
 	if (sd && pc_ismarried(sd))
 		// charid2sd returns NULL if not found
 		return map_charid2sd(sd->status.partner_id);
@@ -7302,18 +7257,15 @@ int pc_split_atoui(char* str, unsigned int* val, char sep, int max)
 	return i;
 }
 
-//
-// 初期化物
-//
 /*==========================================
- * 設定ファイル?み?む
- * exp.txt 必要??値
- * job_db1.txt 重量,hp,sp,攻?速度
- * job_db2.txt job能力値ボ?ナス
- * skill_tree.txt 各職?のスキルツリ?
- * attr_fix.txt ?性修正テ?ブル
- * size_fix.txt サイズ補正テ?ブル
- * refine_db.txt 精?デ?タテ?ブル
+ * DB reading.
+ * exp.txt        - required experience values
+ * job_db1.txt    - weight, hp, sp, aspd
+ * job_db2.txt    - job level stat bonuses
+ * skill_tree.txt - skill tree for every class
+ * attr_fix.txt   - elemental adjustment table
+ * size_fix.txt   - size adjustment table for weapons
+ * refine_db.txt  - refining data table
  *------------------------------------------*/
 int pc_readdb(void)
 {
@@ -7436,8 +7388,8 @@ int pc_readdb(void)
 			continue;
 		idx = pc_class2idx(idx);
 		k = atoi(split[1]); //This is to avoid adding two lines for the same skill. [Skotlex]
-		for(j = 0; j < MAX_SKILL_TREE && skill_tree[idx][j].id && skill_tree[idx][j].id != k; j++);
-		if (j == MAX_SKILL_TREE)
+		ARR_FIND( 0, MAX_SKILL_TREE, j, skill_tree[idx][j].id == 0 || skill_tree[idx][j].id == k );
+		if( j == MAX_SKILL_TREE )
 		{
 			ShowWarning("Unable to load skill %d into job %d's tree. Maximum number of skills per class has been reached.\n", k, atoi(split[0]));
 			continue;

+ 1 - 1
src/map/quest.c

@@ -172,7 +172,7 @@ int quest_update_objective(TBL_PC * sd, int quest_id, int objective_num, const c
 	ARR_FIND(0, MAX_QUEST, i, sd->quest_log[i].quest_id == quest_id);
 
 	//Quest not found
-	if(i != MAX_QUEST)
+	if(i == MAX_QUEST)
 		return -1;
 
 	memcpy(&sd->quest_log[i].objectives[objective_num].name, name, NAME_LENGTH);

+ 49 - 126
src/map/skill.c

@@ -147,11 +147,14 @@ int	skill_get_unit_layout_type( int id ,int lv ){ skill_get (skill_db[id].unit_l
 
 int skill_tree_get_max(int id, int b_class)
 {
-	int i, skillid;
+	int i;
 	b_class = pc_class2idx(b_class);
-	for(i=0;(skillid=skill_tree[b_class][i].id)>0;i++)
-		if (id == skillid) return skill_tree[b_class][i].max;
-	return skill_get_max (id);
+
+	ARR_FIND( 0, MAX_SKILL_TREE, i, skill_tree[b_class][i].id == 0 || skill_tree[b_class][i].id == id );
+	if( i < MAX_SKILL_TREE && skill_tree[b_class][i].id == id )
+		return skill_tree[b_class][i].max;
+	else
+		return skill_get_max(id);
 }
 
 int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int skillid,int skilllv,unsigned int tick,int flag );
@@ -616,7 +619,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int
 		sc_start(bl,SC_BLIND,(10+3*skilllv),skilllv,skill_get_time2(skillid,skilllv));
 		break;
 
-	case BA_FROSTJOKE:
+	case BA_FROSTJOKER:
 		sc_start(bl,SC_FREEZE,(15+5*skilllv),skilllv,skill_get_time2(skillid,skilllv));
 		break;
 
@@ -2057,7 +2060,7 @@ static int skill_timerskill (int tid, unsigned int tick, int id, int data)
 							unit_warp(target, -1, x, y, 3);
 					}
 					break;
-				case BA_FROSTJOKE:
+				case BA_FROSTJOKER:
 				case DC_SCREAM:
 					range= skill_get_splash(skl->skill_id, skl->skill_lv);
 					map_foreachinarea(skill_frostjoke_scream,skl->map,skl->x-range,skl->y-range,
@@ -3787,7 +3790,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 		}
 		break;
 
-	case BA_FROSTJOKE:
+	case BA_FROSTJOKER:
 	case DC_SCREAM:
 		clif_skill_nodamage(src,bl,skillid,skilllv,1);
 		skill_addtimerskill(src,tick+2000,bl->id,src->x,src->y,skillid,skilllv,0,flag);
@@ -10726,77 +10729,13 @@ void skill_init_unit_layout (void)
  * skill_db.txt
  * skill_require_db.txt
  * skill_cast_db.txt
+ * skill_castnodex_db.txt
+ * skill_nocast_db.txt
  * skill_unit_db.txt
  * produce_db.txt 
  * create_arrow_db.txt
  * abra_db.txt
- * skill_castnodex_db.txt
- * skill_nocast_db.txt
  *------------------------------------------*/
-/// Opens and parses a CSV file into columns, feeding them to the specified callback function row by row.
-/// Tracks the progress of the operation (file position, number of successfully processed rows).
-/// Returns 'true' if it was able to process the specified file, or 'false' if it could not be read.
-static bool skill_read_csvdb( const char* directory, const char* filename, int mincolumns, bool (*parseproc)(char* split[], int columns, int current) )
-{
-	FILE* fp;
-	int lines = 0;
-	int entries = 0;
-	char path[1024], line[1024];
-
-	// open file
-	snprintf(path, sizeof(path), "%s/%s", directory, filename);
-	fp = fopen(path,"r");
-	if( fp == NULL )
-	{
-		ShowError("skill_read_db: can't read %s\n", path);
-		return false;
-	}
-
-	// process rows one by one
-	while( fgets(line, sizeof(line), fp) )
-	{
-		char* split[50];
-		int columns;
-
-		lines++;
-		if( line[0] == '/' && line[1] == '/' )
-			continue;
-		//TODO: strip trailing // comment
-		//TODO: strip trailing whitespace
-		if( line[0] == '\0' || line[0] == '\n' )
-			continue;
-
-		memset(split,0,sizeof(split));
-		columns = skill_split_str(line,split,ARRAYLENGTH(split));
-		if( columns < 2 ) // FIXME: assumes db has at least 2 mandatory columns
-			continue; // empty line
-		if( columns < mincolumns )
-		{
-			ShowError("skill_read_csvdb: Insufficient columns in line %d of \"%s\" (found %d, need at least %d).\n", lines, path, columns, mincolumns);
-			continue; // not enough columns
-		}
-		if( columns > ARRAYLENGTH(split) )
-		{
-			ShowError("skill_read_csvdb: Too many columns in line %d of \"%s\" (found %d, capacity %d). Increase the capacity in the source code please.\n", lines, path, columns, ARRAYLENGTH(split) );
-			continue; // source code problem
-		}
-
-		// parse this row
-		if( !parseproc(split, columns, entries) )
-		{
-			ShowError("skill_read_csvdb: Could not process contents of line %d of \"%s\".\n", lines, path);
-			continue; // invalid row contents?
-		}
-
-		// success!
-		entries++;
-	}
-
-	fclose(fp);
-	ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, path);
-
-	return true;
-}
 
 static bool skill_parse_row_skilldb(char* split[], int columns, int current)
 {// id,range,hit,inf,element,nk,splash,max,list_num,castcancel,cast_defence_rate,inf2,maxcount,skill_type,blow_count,name,description
@@ -10938,6 +10877,32 @@ static bool skill_parse_row_castdb(char* split[], int columns, int current)
 	return true;
 }
 
+static bool skill_parse_row_castnodexdb(char* split[], int columns, int current)
+{// Skill id,Cast,Delay (optional)
+	int i = atoi(split[0]);
+	i = skill_get_index(i);
+	if( !i ) // invalid skill id
+		return false;
+	
+	skill_split_atoi(split[1],skill_db[i].castnodex);
+	if( split[2] ) // optional column
+		skill_split_atoi(split[2],skill_db[i].delaynodex);
+
+	return true;
+}
+
+static bool skill_parse_row_nocastdb(char* split[], int columns, int current)
+{// SkillID,Flag
+	int i = atoi(split[0]);
+	i = skill_get_index(i);
+	if( !i ) // invalid skill id
+		return false;
+
+	skill_db[i].nocast |= atoi(split[1]);
+
+	return true;
+}
+
 static bool skill_parse_row_unitdb(char* split[], int columns, int current)
 {// ID,unit ID,unit ID 2,layout,range,interval,target,flag
 	int i = atoi(split[0]);
@@ -10985,8 +10950,6 @@ static bool skill_parse_row_producedb(char* split[], int columns, int current)
 	int i = atoi(split[0]);
 	if( !i )
 		return false;
-	if( current == MAX_SKILL_PRODUCE_DB )
-		return false;
 
 	skill_produce_db[current].nameid = i;
 	skill_produce_db[current].itemlv = atoi(split[1]);
@@ -10999,9 +10962,6 @@ static bool skill_parse_row_producedb(char* split[], int columns, int current)
 		skill_produce_db[current].mat_amount[y] = atoi(split[x+1]);
 	}
 
-	if( current == MAX_SKILL_PRODUCE_DB-1 )
-		ShowWarning("Reached the max number of produce_db entries (%d), consider raising the value of MAX_SKILL_PRODUCE_DB and recompile.\n", MAX_SKILL_PRODUCE_DB);
-
 	return true;
 }
 
@@ -11012,19 +10972,15 @@ static bool skill_parse_row_createarrowdb(char* split[], int columns, int curren
 	int i = atoi(split[0]);
 	if( !i )
 		return false;
-	if( current == MAX_SKILL_ARROW_DB )
-		return false;
 
 	skill_arrow_db[current].nameid = i;
 	
-	for( x = 1, y = 0; x+1 < columns && split[x] && split[x+1] && y < 5; x += 2, y++ )
+	for( x = 1, y = 0; x+1 < columns && split[x] && split[x+1] && y < MAX_ARROW_RESOURCE; x += 2, y++ )
 	{
 		skill_arrow_db[current].cre_id[y] = atoi(split[x]);
 		skill_arrow_db[current].cre_amount[y] = atoi(split[x+1]);
 	}
 
-	//TODO?: add capacity warning here
-
 	return true;
 }
 
@@ -11042,45 +10998,14 @@ static bool skill_parse_row_abradb(char* split[], int columns, int current)
 		return false;
 	}
 
-	if( current == MAX_SKILL_ABRA_DB )
-		return false;
-	
 	skill_abra_db[current].skillid = i;
 	skill_abra_db[current].req_lv = atoi(split[2]);
 	skill_abra_db[current].per = atoi(split[3]);
 
-	//TODO?: add capacity warning here
-
 	return true;
 }
 
-static bool skill_parse_row_castnodexdb(char* split[], int columns, int current)
-{// Skill id,Cast,Delay (optional)
-	int i = atoi(split[0]);
-	i = skill_get_index(i);
-	if( !i ) // invalid skill id
-		return false;
-	
-	skill_split_atoi(split[1],skill_db[i].castnodex);
-	if( split[2] ) // optional column
-		skill_split_atoi(split[2],skill_db[i].delaynodex);
-
-	return true;
-}
-
-static bool skill_parse_row_nocastdb(char* split[], int columns, int current)
-{// SkillID,Flag
-	int i = atoi(split[0]);
-	i = skill_get_index(i);
-	if( !i ) // invalid skill id
-		return false;
-
-	skill_db[i].nocast |= atoi(split[1]);
-
-	return true;
-}
-
-int skill_readdb(void)
+static void skill_readdb(void)
 {
 	// init skill db structures
 	memset(skill_db,0,sizeof(skill_db));
@@ -11089,20 +11014,18 @@ int skill_readdb(void)
 	memset(skill_abra_db,0,sizeof(skill_abra_db));
 	
 	// load skill databases
-	skill_read_csvdb(db_path, "skill_db.txt", 17, skill_parse_row_skilldb);
 	safestrncpy(skill_db[0].name, "UNKNOWN_SKILL", sizeof(skill_db[0].name));
 	safestrncpy(skill_db[0].desc, "Unknown Skill", sizeof(skill_db[0].desc));
-	skill_read_csvdb(db_path, "skill_require_db.txt", 17, skill_parse_row_requiredb);
-	skill_read_csvdb(db_path, "skill_cast_db.txt", 6, skill_parse_row_castdb);
-	skill_read_csvdb(db_path, "skill_unit_db.txt", 8, skill_parse_row_unitdb);
+	sv_readdb(db_path, "skill_db.txt"          , ',',  17, 17, MAX_SKILL_DB, skill_parse_row_skilldb);
+	sv_readdb(db_path, "skill_require_db.txt"  , ',',  32, 32, MAX_SKILL_DB, skill_parse_row_requiredb);
+	sv_readdb(db_path, "skill_cast_db.txt"     , ',',   6,  6, MAX_SKILL_DB, skill_parse_row_castdb);
+	sv_readdb(db_path, "skill_castnodex_db.txt", ',',   2,  3, MAX_SKILL_DB, skill_parse_row_castnodexdb);
+	sv_readdb(db_path, "skill_nocast_db.txt"   , ',',   2,  2, MAX_SKILL_DB, skill_parse_row_nocastdb);
+	sv_readdb(db_path, "skill_unit_db.txt"     , ',',   8,  8, MAX_SKILL_DB, skill_parse_row_unitdb);
 	skill_init_unit_layout();
-	skill_read_csvdb(db_path, "produce_db.txt", 4, skill_parse_row_producedb);
-	skill_read_csvdb(db_path, "create_arrow_db.txt", 1+2, skill_parse_row_createarrowdb);
-	skill_read_csvdb(db_path, "abra_db.txt", 4, skill_parse_row_abradb);
-	skill_read_csvdb(db_path, "skill_castnodex_db.txt", 2, skill_parse_row_castnodexdb);
-	skill_read_csvdb(db_path, "skill_nocast_db.txt", 2, skill_parse_row_nocastdb);
-	
-	return 0;
+	sv_readdb(db_path, "produce_db.txt"        , ',',   4,  4+2*MAX_PRODUCE_RESOURCE, MAX_SKILL_PRODUCE_DB, skill_parse_row_producedb);
+	sv_readdb(db_path, "create_arrow_db.txt"   , ',', 1+2,  1+2*MAX_ARROW_RESOURCE, MAX_SKILL_ARROW_DB, skill_parse_row_createarrowdb);
+	sv_readdb(db_path, "abra_db.txt"           , ',',   4,  4, MAX_SKILL_ABRA_DB, skill_parse_row_abradb);
 }
 
 void skill_reload (void)

+ 3 - 2
src/map/skill.h

@@ -16,6 +16,7 @@ struct status_change_entry;
 #define MAX_SKILL_PRODUCE_DB	150
 #define MAX_PRODUCE_RESOURCE	12
 #define MAX_SKILL_ARROW_DB		150
+#define MAX_ARROW_RESOURCE		5
 #define MAX_SKILL_ABRA_DB		350
 
 #define MAX_SKILL_LEVEL 100
@@ -186,7 +187,7 @@ extern struct s_skill_produce_db skill_produce_db[MAX_SKILL_PRODUCE_DB];
 // –î�ì�¬ƒf?ƒ^ƒx?ƒX
 struct s_skill_arrow_db {
 	int nameid, trigger;
-	int cre_id[5],cre_amount[5];
+	int cre_id[MAX_ARROW_RESOURCE],cre_amount[MAX_ARROW_RESOURCE];
 };
 extern struct s_skill_arrow_db skill_arrow_db[MAX_SKILL_ARROW_DB];
 
@@ -685,7 +686,7 @@ enum s_skill {
 	BA_MUSICALLESSON,
 	BA_MUSICALSTRIKE,
 	BA_DISSONANCE,
-	BA_FROSTJOKE,
+	BA_FROSTJOKER,
 	BA_WHISTLE,
 	BA_ASSASSINCROSS,
 	BA_POEMBRAGI,

+ 1 - 1
src/map/status.c

@@ -260,7 +260,7 @@ void initChangeTables(void)
 	add_sc( BD_ROKISWEIL         , SC_ROKISWEIL       );
 	add_sc( BD_INTOABYSS         , SC_INTOABYSS       );
 	set_sc( BD_SIEGFRIED         , SC_SIEGFRIED       , SI_BLANK           , SCB_PC );
-	add_sc( BA_FROSTJOKE         , SC_FREEZE          );
+	add_sc( BA_FROSTJOKER        , SC_FREEZE          );
 	set_sc( BA_WHISTLE           , SC_WHISTLE         , SI_BLANK           , SCB_FLEE|SCB_FLEE2 );
 	set_sc( BA_ASSASSINCROSS     , SC_ASSNCROS        , SI_BLANK           , SCB_ASPD );
 	add_sc( BA_POEMBRAGI         , SC_POEMBRAGI       );