* 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
This commit is contained in:
ultramage 2008-04-15 13:49:40 +00:00
parent 13bc9302be
commit 9609149c15
14 changed files with 227 additions and 281 deletions

View File

@ -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]

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}
/////////////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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)
/*==========================================
* ƒJ?ƒgÖƒAƒCƒeƒˆÚ®
*------------------------------------------*/
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;

View File

@ -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);

View File

@ -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)

View File

@ -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];
// 矢作成デ?タベ?ス
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,

View File

@ -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 );