* 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:
parent
13bc9302be
commit
9609149c15
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
@ -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
|
||||
|
@ -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,33 +5696,29 @@ 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);
|
||||
|
@ -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;
|
||||
|
148
src/map/pc.c
148
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,26 +491,22 @@ 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)
|
||||
|
||||
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;
|
||||
}
|
||||
else
|
||||
sd->weapontype2 = 0;
|
||||
}
|
||||
else
|
||||
sd->weapontype2 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
pc_calcweapontype(sd);
|
||||
@ -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 &&
|
||||
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]){
|
||||
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;
|
||||
return 1; // no room
|
||||
|
||||
sd->status.cart[i].amount+=amount;
|
||||
clif_cart_additem(sd,i,amount,0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(i >= MAX_CART){
|
||||
for(i=0;i<MAX_CART;i++){
|
||||
if(sd->status.cart[i].nameid==0){
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i >= MAX_CART)
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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);
|
||||
|
175
src/map/skill.c
175
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)
|
||||
|
@ -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,
|
||||
|
@ -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 );
|
||||
|
Loading…
x
Reference in New Issue
Block a user