From 021b26b8409a84b4c83eb0cc1eedbd65eedfd4e0 Mon Sep 17 00:00:00 2001 From: skotlex Date: Wed, 22 Mar 2006 23:58:16 +0000 Subject: - Merged the unit_data structure from jA for handling unit-related data (attack times, walking, auto-attack timers, skill related data) - Modified unit_skillcastcancel to receive flag&2, which stands for "cancel casting only if current skill is cancellable" - Battle config options changed from yes/no to BL_TYPE settings: skillrange_by_distance, skill_noreiteration, skill_nofootset, gvg_traps_target_all, skill_log, attack_direction_change, auto_counter_type - Clif.c will disconnect sessions that send an unknown command packet above 0x30000 instead of just ignoring it. - Cleaned up/rewrite of the pet ai, same for pet_calc_pos - Implemented use of mob variable attacked_players as it is used on jA - Cleaned up error reporting during mob-skill loading to be less spamy with non-loaded mobs. - Corrected water_height reading. I forgot to give credits to LittleWolf for providing the water-reading function :X git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@5707 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/unit.h | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/map/unit.h (limited to 'src/map/unit.h') diff --git a/src/map/unit.h b/src/map/unit.h new file mode 100644 index 000000000..d711f19c8 --- /dev/null +++ b/src/map/unit.h @@ -0,0 +1,69 @@ +// Copyright (c) jAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder +// Merged originally from jA by Skotlex +#ifndef _UNIT_H_ +#define _UNIT_H_ + +#include "map.h" + +// PC, MOB, PET に共通する処理を1つにまとめる計画 + +// 歩行開始 +// 戻り値は、0 ( 成功 ), 1 ( 失敗 ) +int unit_walktoxy( struct block_list *bl, int x, int y, int easy); + +// 歩行停止 +// typeは以下の組み合わせ : +// 1: 位置情報の送信( この関数の後に位置情報を送信する場合は不要 ) +// 2: ダメージディレイ有り +// 4: 不明(MOBのみ?) +int unit_stop_walking(struct block_list *bl,int type); +int unit_can_move(struct block_list *bl); +int unit_is_walking(struct block_list *bl); +int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int type); +int unit_walkdelay(struct block_list *bl, unsigned int tick, int adelay, int delay, int div_); + + +// 位置の強制移動(吹き飛ばしなど) +int unit_movepos(struct block_list *bl,int dst_x,int dst_y, int easy, int checkpath); +int unit_warp(struct block_list *bl, int map, int x, int y, int type); +int unit_setdir(struct block_list *bl,unsigned short dir); +int unit_getdir(struct block_list *bl); + +// そこまで歩行でたどり着けるかの判定 +int unit_can_reach(struct block_list *bl,int x,int y); + +// 攻撃関連 +int unit_stop_attack(struct block_list *bl); +int unit_attack(struct block_list *src,int target_id,int type); + +// int unit_setpos( struct block_list *bl, const char* map, int x, int y); + +// スキル使用 +int unit_skilluse_id(struct block_list *src, int target_id, int skill_num, int skill_lv); +int unit_skilluse_pos(struct block_list *src, int skill_x, int skill_y, int skill_num, int skill_lv); + +// スキル使用( 補正済みキャスト時間、キャンセル不可設定付き ) +int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int skill_lv, int casttime, int castcancel); +int unit_skilluse_pos2( struct block_list *src, int skill_x, int skill_y, int skill_num, int skill_lv, int casttime, int castcancel); + +// 詠唱キャンセル +int unit_skillcastcancel(struct block_list *bl,int type); + +int unit_counttargeted(struct block_list *bl,int target_lv); + +// unit_data の初期化処理 +void unit_dataset(struct block_list *bl); + +int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2); +// その他 +struct unit_data* unit_bl2ud(struct block_list *bl); +int unit_remove_map(struct block_list *bl, int clrtype); +int unit_free(struct block_list *bl); +int unit_changeviewsize(struct block_list *bl,short size); + +// 初期化ルーチン +int do_init_unit(void); +int do_final_unit(void); + +#endif /* _UNIT_H_ */ -- cgit v1.2.3-70-g09d2 From d8c2f065493f2daca894ef9662efb1017ab370e2 Mon Sep 17 00:00:00 2001 From: Lance Date: Thu, 23 Mar 2006 07:08:31 +0000 Subject: * Minor cleanups. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@5712 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 3 +++ src/map/script.c | 2 +- src/map/unit.c | 2 +- src/map/unit.h | 2 +- vcproj-7.1/map-server_sql.vcproj | 6 ++++++ vcproj-7.1/map-server_txt.vcproj | 6 ++++++ 6 files changed, 18 insertions(+), 3 deletions(-) (limited to 'src/map/unit.h') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index b9f74eeab..88d681974 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -4,6 +4,9 @@ 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. EVERYTHING ELSE GOES INTO TRUNK AND WILL BE MERGED INTO STABLE BY VALARIS AND WIZPUTER. -- VALARIS +2006/03/23 + * Minor cleanups. [Lance] + 2006/03/22 * Fixed function pc_isCardAllowedOn causing searches for non-existant item id 0. [Skotlex] diff --git a/src/map/script.c b/src/map/script.c index 3226a6b2f..70941e7ea 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -10244,7 +10244,7 @@ int buildin_setmobdata(struct script_state *st){ md->db->shield = (short)value; break; case 23: - md->ud.dir = (short)value; + md->ud.dir = (unsigned char)value; break; default: ShowError("buildin_setmobdata: argument id is not identified."); diff --git a/src/map/unit.c b/src/map/unit.c index c38e7fa6f..4280f9662 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -366,7 +366,7 @@ int unit_movepos(struct block_list *bl,int dst_x,int dst_y, int easy, int checkp return 1; } -int unit_setdir(struct block_list *bl,unsigned short dir) +int unit_setdir(struct block_list *bl,unsigned char dir) { struct unit_data *ud; nullpo_retr( 0, bl ); diff --git a/src/map/unit.h b/src/map/unit.h index d711f19c8..9724a8523 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -27,7 +27,7 @@ int unit_walkdelay(struct block_list *bl, unsigned int tick, int adelay, int del // 位置の強制移動(吹き飛ばしなど) int unit_movepos(struct block_list *bl,int dst_x,int dst_y, int easy, int checkpath); int unit_warp(struct block_list *bl, int map, int x, int y, int type); -int unit_setdir(struct block_list *bl,unsigned short dir); +int unit_setdir(struct block_list *bl,unsigned char dir); int unit_getdir(struct block_list *bl); // そこまで歩行でたどり着けるかの判定 diff --git a/vcproj-7.1/map-server_sql.vcproj b/vcproj-7.1/map-server_sql.vcproj index bd809ae37..c5a9fe6ca 100644 --- a/vcproj-7.1/map-server_sql.vcproj +++ b/vcproj-7.1/map-server_sql.vcproj @@ -269,6 +269,9 @@ + + @@ -414,6 +417,9 @@ + + diff --git a/vcproj-7.1/map-server_txt.vcproj b/vcproj-7.1/map-server_txt.vcproj index 7bd422c2a..8e5e54235 100644 --- a/vcproj-7.1/map-server_txt.vcproj +++ b/vcproj-7.1/map-server_txt.vcproj @@ -270,6 +270,9 @@ + + @@ -415,6 +418,9 @@ + + -- cgit v1.2.3-70-g09d2 From 7961554a72e475cd71bd34f65bb548c1b13dc685 Mon Sep 17 00:00:00 2001 From: skotlex Date: Mon, 10 Apr 2006 21:38:05 +0000 Subject: - Modified the unit_data structure to handle automatically switching between chasing and attacking a character. Note that it's a work in progress and not yet properly tested/finished... git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@5979 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 9 ++- src/map/map.c | 2 +- src/map/map.h | 2 + src/map/mob.c | 169 ++++++-------------------------------- src/map/pc.c | 33 ++++---- src/map/pet.c | 68 +++++----------- src/map/skill.h | 4 + src/map/unit.c | 227 ++++++++++++++++++++++++++++++++++++++++++++++------ src/map/unit.h | 4 +- 9 files changed, 279 insertions(+), 239 deletions(-) (limited to 'src/map/unit.h') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 53315aa8e..d0bbc2527 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -4,9 +4,14 @@ 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. 2006/04/10 - - Updated the subnet support to not require specifying the subnet mask, it + * Modified the unit_data structure to handle automatically switching + between chasing and attacking a character. Note that it's a work in + progress and not yet properly tested/finished... [Skotlex] + - DON'T USE THIS YET. There's much testing that needs be done, but I had to + commit now so I may continue work on it later.... + * Updated the subnet support to not require specifying the subnet mask, it is auto-acquired from the char/map IP and the subnet-mask. [Skotlex] - - skill_wall_check defaults to yes now. [Skotlex] + * skill_wall_check defaults to yes now. [Skotlex] 2006/04/09 * Added the missing last_thinktime initialization to pets. [Skotlex] * Reverted the change in skill_wall_check to let skills go over pits. diff --git a/src/map/map.c b/src/map/map.c index 156ae7b1c..55b7996a4 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -1412,7 +1412,7 @@ int map_search_freecell(struct block_list *src, int m, int *x,int *y, int rx, in if (map_getcell(m,*x,*y,CELL_CHKREACH)) { - if(flag&2 && !unit_can_reach(src, *x, *y)) + if(flag&2 && !unit_can_reach_pos(src, *x, *y, 1)) continue; if(flag&4 && spawn++ < battle_config.no_spawn_on_player && map_foreachinarea(map_count_sub, m, diff --git a/src/map/map.h b/src/map/map.h index a94da16df..4380cd9f5 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -359,7 +359,9 @@ struct unit_data { int skilltimer; int attacktarget; int attacktimer; + int walktarget; int walktimer; + int chaserange; unsigned int attackabletime; unsigned int canact_tick; unsigned int canmove_tick; diff --git a/src/map/mob.c b/src/map/mob.c index 509f1c359..bdf2360f2 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -515,9 +515,7 @@ int mob_spawn_guardian(struct map_session_data *sd,char *mapname, */ int mob_can_reach(struct mob_data *md,struct block_list *bl,int range, int state) { - int dx,dy; - struct walkpath_data wpd; - int i, easy = 0; + int easy = 0; nullpo_retr(0, md); nullpo_retr(0, bl); @@ -531,41 +529,7 @@ int mob_can_reach(struct mob_data *md,struct block_list *bl,int range, int state easy = 1; break; } - - if( md->bl.m != bl->m) // 違うャbプ - return 0; - - if( md->bl.x==bl->x && md->bl.y==bl->y ) // 同じマス - return 1; - - if( range>0 && !check_distance_bl(&md->bl, bl, range)) - return 0; - - // Obstacle judging - wpd.path_len=0; - wpd.path_pos=0; - wpd.path_half=0; - if(path_search_real(&wpd,md->bl.m,md->bl.x,md->bl.y,bl->x,bl->y,easy,CELL_CHKNOREACH)!=-1) - return 1; - - // It judges whether it can adjoin or not. - dx=bl->x - md->bl.x; - dy=bl->y - md->bl.y; - dx=(dx>0)?1:((dx<0)?-1:0); - dy=(dy>0)?1:((dy<0)?-1:0); - if (map_getcell(md->bl.m,bl->x+dx,bl->y+dy,CELL_CHKNOREACH)) - { //Look for a suitable cell to place in. - for(i=0;i<9 && map_getcell(md->bl.m,bl->x-1+i/3,bl->y-1+i%3,CELL_CHKNOREACH);i++); - if (i<9) { - dx = 1-i/3; - dy = 1-i%3; - } - } - - if(path_search_real(&wpd,md->bl.m,md->bl.x,md->bl.y,bl->x-dx,bl->y-dy,easy,CELL_CHKNOREACH)!=-1) - return 1; - - return 0; + return unit_can_reach_bl(&md->bl, bl, range, easy, NULL, NULL); } /*========================================== @@ -952,24 +916,8 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick) (md->master_dist>MOB_SLAVEDISTANCE || md->master_dist == 0) && unit_can_move(&md->bl)) { - int i=0,dx,dy; mob_stop_attack(md); - do { - if(i<=5){ - dx=bl->x - md->bl.x; - dy=bl->y - md->bl.y; - - if(dx<0) dx+=rand()%MOB_SLAVEDISTANCE +1; - else if(dx>0) dx-=rand()%MOB_SLAVEDISTANCE +1; - if(dy<0) dy+=rand()%MOB_SLAVEDISTANCE +1; - else if(dy>0) dy-=rand()%MOB_SLAVEDISTANCE +1; - - }else{ - old_dist = MOB_SLAVEDISTANCE*2+1; - dx=bl->x - md->bl.x + rand()%old_dist - MOB_SLAVEDISTANCE; - dy=bl->y - md->bl.y + rand()%old_dist - MOB_SLAVEDISTANCE; - } - } while(!unit_walktoxy(&md->bl,md->bl.x+dx,md->bl.y+dy,0)&& ++i<10); + unit_walktobl(&md->bl, bl, MOB_SLAVEDISTANCE, 0); } } else if (bl->m != md->bl.m && map_flag_gvg(md->bl.m)) { //Delete the summoned mob if it's in a gvg ground and the master is elsewhere. [Skotlex] @@ -1033,7 +981,7 @@ int mob_randomwalk(struct mob_data *md,int tick) nullpo_retr(0, md); speed=status_get_speed(&md->bl); - if(DIFF_TICK(md->next_walktime,tick)<0){ + if(DIFF_TICK(md->next_walktime,tick)<0 && unit_can_move(&md->bl)){ int i,x,y,c,d=12-md->move_fail_count; if(d<5) d=5; for(i=0;itype == BL_PC && !(mode&MD_BOSS) && ((struct map_session_data*)tbl)->state.gangsterparadise )) { //Unlock current target. - if (md->ud.walktimer != -1 && (battle_config.mob_ai&8 || !tbl)) //Inmediately stop chasing. + if (battle_config.mob_ai&8) //Inmediately stop chasing. mob_stop_walking(md,2); mob_unlocktarget(md, tick-(battle_config.mob_ai&8?3000:0)); //Imediately do random walk. tbl = NULL; @@ -1234,91 +1182,27 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap) mob_unlocktarget(md,tick); return 0; } - if (!check_distance_bl(&md->bl, tbl, view_range)) - { //Run towards the enemy when out of range? - if (!can_move) - { //Give it up. - if (can_walk) - mob_unlocktarget(md,tick); - return 0; - } - dx = tbl->x+(tbl->x > md->bl.x?-1:+1); - dy = tbl->y+(tbl->y > md->bl.y?-1:+1); - unit_walktoxy(&md->bl, dx, dy, 0); + if (!can_move) //Wait until you can move? return 0; - } md->state.skillstate = md->state.aggressive?MSS_FOLLOW:MSS_RUSH; - mobskill_use (md, tick, -1); - if (!can_move) //Wait until you can move? + if (md->ud.walktimer != -1 && md->ud.walktarget == tbl->id && + ( + !battle_config.mob_ai&1 || + check_distance_blxy(tbl, md->ud.to_x, md->ud.to_y, md->db->range) + )) //Current target tile is still within attack range. return 0; - if (md->ud.walktimer != -1 && - (!battle_config.mob_ai&1 || - check_distance_blxy(tbl, md->ud.to_x, md->ud.to_y, md->db->range)) //Current target tile is still within attack range. - ) { - return 0; //No need to follow, already doing it? - } //Target reachable. Locate suitable spot to move to. - i = j = 0; - dx = tbl->x - md->bl.x; - dy = tbl->y - md->bl.y; - if (dx < 0) dx=-1; - else if (dx > 0) dx=1; - if (dy < 0) dy=-1; - else if (dy > 0) dy=1; - if(!unit_walktoxy(&md->bl, tbl->x -dx, tbl->y -dy, 0)) { - j = (dy+1) + 3*(dx+1); - for (i = j+1; i%9 != j; i++) { - dx = -1+(i%9)/3; - dy = -1+(i%3); -#ifdef CELL_NOSTACK - if (map_getcell(md->bl.m, tbl->x-dx, tbl->y-dy, CELL_CHKSTACK)) - continue; -#endif - if (unit_walktoxy(&md->bl, tbl->x-dx, tbl->y-dy, 0)) - break; - } -#ifdef CELL_NOSTACK - if (i%9 == j) - { //All adjacent cells are taken. Try roaming around on 5x5 - for (i = j+1; i%9 != j; i++) { - dx = 2*(-1+(i%9)/3); - dy = 2*(-1+(i%3)); - if (map_getcell(md->bl.m, tbl->x-dx, tbl->y-dy, CELL_CHKSTACK)) - continue; - if (unit_walktoxy(&md->bl, tbl->x-dx, tbl->y-dy, 0)) { - unit_set_walkdelay(&md->bl, tick, 1000, 1); - break; - } - } - } - if (i%9 == j) - { - //On stacked mode, it is much more likely that you just can't reach the target. So unlock it - mob_unlocktarget(md, tick); - unit_set_walkdelay(&md->bl, tick, 1000, 1); - return 0; - } -#else - if (i%9 == j) - { //Failed? Try going to the other side of the target before retrying. - if (dx < 0) dx = 2; - else if (dx > 0) dx = -2; - if (dy < 0) dy = 2; - else if (dy > 0) dy = -2; - unit_walktoxy (&md->bl, tbl->x+dx, tbl->y+dy, 0); - } -#endif - } + unit_walktobl(&md->bl, tbl, md->db->range, !battle_config.mob_ai&1); return 0; } //Target within range, engage - md->state.skillstate = md->state.aggressive?MSS_ANGRY:MSS_BERSERK; mob_stop_walking(md,1); + md->state.skillstate = md->state.aggressive?MSS_ANGRY:MSS_BERSERK; unit_attack(&md->bl,tbl->id,1); return 0; } else { //Target is BL_ITEM, attempt loot. struct flooritem_data *fitem; - + int i; if (md->lootitem == NULL) { //Can't loot... mob_unlocktarget (md, tick); @@ -1335,15 +1219,10 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap) if (!can_move) // 動けない状態にある return 0; md->state.skillstate = MSS_LOOT; // ルート時スキル使用 - mobskill_use(md, tick, -1); - if (md->ud.walktimer != -1 && - check_distance_blxy(tbl, md->ud.to_x, md->ud.to_y, 0)) - { //Already on the way to looting. + if (md->ud.walktimer != -1 && md->ud.walktarget == tbl->id) + //Already on the way to looting. return 0; - } - dx = tbl->x - md->bl.x; - dy = tbl->y - md->bl.y; - if (!unit_walktoxy(&md->bl, md->bl.x+dx, md->bl.y+dy, 0)) + if (!unit_walktobl(&md->bl, tbl, 0, 1)) mob_unlocktarget(md, tick); //Can't loot... return 0; } @@ -1357,9 +1236,6 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap) memcpy (&md->lootitem[md->lootitem_count++], &fitem->item_data, sizeof(md->lootitem[0])); if(log_config.pick > 0) //Logs items, taken by (L)ooter Mobs [Lupus] log_pick((struct map_session_data*)md, "L", md->class_, md->lootitem[md->lootitem_count-1].nameid, md->lootitem[md->lootitem_count-1].amount, &md->lootitem[md->lootitem_count-1]); - } else if (battle_config.monster_loot_type == 1) { //Can't loot, stuffed! - mob_unlocktarget(md,tick); - return 0; } else { //Destroy first looted item... if (md->lootitem[0].card[0] == (short)0xff00) intif_delete_petdata( MakeDWord(md->lootitem[0].card[1],md->lootitem[0].card[2]) ); @@ -1458,10 +1334,11 @@ static int mob_ai_sub_lazy(DBKey key,void * data,va_list app) else if(rand()%1000spawn && !md->spawn->x && !md->spawn->y) - && !md->target_id && !(mode&MD_BOSS)) - unit_warp(&md->bl,-1,-1,-1,0); + // People don't want this, it seems custom, noone can prove it.... +// else if( rand()%1000spawn && !md->spawn->x && !md->spawn->y) +// && !md->target_id && !(mode&MD_BOSS)) +// unit_warp(&md->bl,-1,-1,-1,0); }else{ // Since PC is not even in the same map, suitable processing is carried out even if it takes. diff --git a/src/map/pc.c b/src/map/pc.c index 5852edc08..8502b5ce8 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -3821,26 +3821,23 @@ int pc_follow_timer(int tid,unsigned int tick,int id,int data) if (pc_isdead(sd)) return 0; - if ((tsd = map_id2sd(sd->followtarget)) != NULL) - { - if (pc_isdead(tsd)) - return 0; + if ((tsd = map_id2sd(sd->followtarget)) == NULL || pc_isdead(tsd)) + return 0; - // either player or target is currently detached from map blocks (could be teleporting), - // but still connected to this map, so we'll just increment the timer and check back later - if (sd->bl.prev != NULL && tsd->bl.prev != NULL && - sd->ud.skilltimer == -1 && sd->ud.attacktimer == -1 && sd->ud.walktimer == -1) - { - if((sd->bl.m == tsd->bl.m) && unit_can_reach(&sd->bl,tsd->bl.x,tsd->bl.y)) { - if (!check_distance_bl(&sd->bl, &tsd->bl, 5) && unit_can_move(&sd->bl)) - unit_walktoxy(&sd->bl,tsd->bl.x,tsd->bl.y, 0); - } else - pc_setpos(sd, tsd->mapindex, tsd->bl.x, tsd->bl.y, 3); - } - sd->followtimer = add_timer( - tick + sd->aspd + rand() % 1000, // increase time a bit to loosen up map's load - pc_follow_timer, sd->bl.id, 0); + // either player or target is currently detached from map blocks (could be teleporting), + // but still connected to this map, so we'll just increment the timer and check back later + if (sd->bl.prev != NULL && tsd->bl.prev != NULL && + sd->ud.skilltimer == -1 && sd->ud.attacktimer == -1 && sd->ud.walktimer == -1) + { + if((sd->bl.m == tsd->bl.m) && unit_can_reach_bl(&sd->bl,&tsd->bl, AREA_SIZE, 0, NULL, NULL)) { + if (!check_distance_bl(&sd->bl, &tsd->bl, 5)) + unit_walktobl(&sd->bl, &tsd->bl, 5, 0); + } else + pc_setpos(sd, tsd->mapindex, tsd->bl.x, tsd->bl.y, 3); } + sd->followtimer = add_timer( + tick + sd->aspd + rand() % 1000, // increase time a bit to loosen up map's load + pc_follow_timer, sd->bl.id, 0); return 0; } diff --git a/src/map/pet.c b/src/map/pet.c index 88eb26cd4..4904d1c45 100644 --- a/src/map/pet.c +++ b/src/map/pet.c @@ -81,33 +81,33 @@ static int pet_calc_pos(struct pet_data *pd,int tx,int ty,int dir) dy = -diry[dir]*2; x = tx + dx; y = ty + dy; - if(!unit_can_reach(&pd->bl,x,y)) { + if(!unit_can_reach_pos(&pd->bl,x,y,0)) { if(dx > 0) x--; else if(dx < 0) x++; if(dy > 0) y--; else if(dy < 0) y++; - if(!unit_can_reach(&pd->bl,x,y)) { + if(!unit_can_reach_pos(&pd->bl,x,y,0)) { for(i=0;i<12;i++) { k = rand()%8; dx = -dirx[k]*2; dy = -diry[k]*2; x = tx + dx; y = ty + dy; - if(unit_can_reach(&pd->bl,x,y)) + if(unit_can_reach_pos(&pd->bl,x,y,0)) break; else { if(dx > 0) x--; else if(dx < 0) x++; if(dy > 0) y--; else if(dy < 0) y++; - if(unit_can_reach(&pd->bl,x,y)) + if(unit_can_reach_pos(&pd->bl,x,y,0)) break; } } if(i>=12) { x = tx; y = ty; - if(!unit_can_reach(&pd->bl,x,y)) + if(!unit_can_reach_pos(&pd->bl,x,y,0)) return 1; } } @@ -892,7 +892,7 @@ static int pet_randomwalk(struct pet_data *pd,unsigned int tick) speed = status_get_speed(&pd->bl); - if(DIFF_TICK(pd->next_walktime,tick) < 0){ + if(DIFF_TICK(pd->next_walktime,tick) < 0 && unit_can_move(&pd->bl)) { int i,x,y,c,d=12-pd->move_fail_count; if(d<5) d=5; for(i=0;imsd; @@ -960,14 +959,13 @@ static int pet_ai_sub_hard(struct pet_data *pd,unsigned int tick) //Master too far, chase. if(pd->target_id) pet_unlocktarget(pd); - if(pd->ud.walktimer != -1 && check_distance_blxy(&sd->bl, pd->ud.to_x,pd->ud.to_y, 3)) + if(pd->ud.walktimer != -1 && pd->ud.walktarget == sd->bl.id) return 0; //Already walking to him pd->speed = (sd->speed>>1); if(pd->speed <= 0) pd->speed = 1; - pet_calc_pos(pd,sd->bl.x,sd->bl.y,sd->ud.dir); - if(!unit_walktoxy(&pd->bl,pd->ud.to_x,pd->ud.to_y,0)) + if (!unit_walktobl(&pd->bl, &sd->bl, 3, 0)); pet_randomwalk(pd,tick); return 0; } @@ -987,11 +985,12 @@ static int pet_ai_sub_hard(struct pet_data *pd,unsigned int tick) } // ペットによるルート - if(!pd->target_id && pd->loot && pd->loot->count < pd->loot->max && DIFF_TICK(tick,pd->ud.canact_tick)>0) + if(!target && pd->loot && pd->loot->count < pd->loot->max && DIFF_TICK(tick,pd->ud.canact_tick)>0) { //Use half the pet's range of sight. + int itc=0; map_foreachinrange(pet_ai_sub_hard_lootsearch,&pd->bl, - pd->db->range2/2, BL_ITEM,pd,&i); - + pd->db->range2/2, BL_ITEM,pd,&itc); + } if (!target) { //Just walk around. if (check_distance_bl(&sd->bl, &pd->bl, 3)) @@ -1014,51 +1013,26 @@ static int pet_ai_sub_hard(struct pet_data *pd,unsigned int tick) if(pd->ud.walktimer != -1 && check_distance_blxy(target, pd->ud.to_x,pd->ud.to_y, pd->db->range)) return 0; - if(!unit_can_reach(&pd->bl, target->x, target->y)) + if(!unit_walktobl(&pd->bl, target, pd->db->range, 2)) { //Unreachable target. pet_unlocktarget(pd); - return 0; - } - i=0; - do { - if(i==0) { // 最初はAEGISと同じ方法で検索 - dx=target->x - pd->bl.x; - dy=target->y - pd->bl.y; - if(dx<0) dx++; - else if(dx>0) dx--; - if(dy<0) dy++; - else if(dy>0) dy--; - } - else { // だめならAthena式(ランダム) - dx=target->x - pd->bl.x + rand()%3 - 1; - dy=target->y - pd->bl.y + rand()%3 - 1; - } - } while(!unit_walktoxy(&pd->bl,pd->bl.x+dx,pd->bl.y+dy,0) && ++i<5); - - if(i>=5) { - if(dx<0) dx=2; - else if(dx>0) dx=-2; - if(dy<0) dy=2; - else if(dy>0) dy=-2; - unit_walktoxy(&pd->bl,pd->bl.x+dx,pd->bl.y+dy,0); } return 0; } //End Chase pet_stop_walking(pd,1); + if (pd->ud.attacktimer != -1 && pd->ud.attacktarget == pd->target_id) + return 0; //Already attacking. //Continuous attack. unit_attack(&pd->bl, pd->target_id, 1); } else { //Item Targeted, attempt loot if (!check_distance_bl(&pd->bl, target, 1)) { //Out of range - if(pd->ud.walktimer != -1 && check_distance_blxy(target, pd->ud.to_x, pd->ud.to_y, 0)) - return 0; // 既に移動中 + if(pd->ud.walktimer != -1 && pd->ud.walktarget == pd->target_id) + return 0; - if(!unit_can_reach(&pd->bl, target->x, target->y)) - { //Unreachable target. + if(!unit_walktobl(&pd->bl, target, 0, 1)) //Unreachable target. pet_unlocktarget(pd); - return 0; - } - unit_walktoxy(&pd->bl, target->x, target->y, 1); + return 0; } else{ // アイテムまでたどり着いた struct flooritem_data *fitem = (struct flooritem_data *)target; pet_stop_walking(pd,1); @@ -1109,8 +1083,8 @@ int pet_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap) if(pd->loot == NULL || pd->loot->item == NULL || (pd->loot->count >= pd->loot->max) || (sd_id && pd->msd && pd->msd->bl.id != sd_id)) return 0; - if(bl->m == pd->bl.m && check_distance_bl(&pd->bl, bl, pd->db->range2) && - unit_can_reach(&pd->bl,bl->x,bl->y) && rand()%1000<1000/(++(*itc))) + if(bl->m == pd->bl.m && unit_can_reach_bl(&pd->bl,bl, pd->db->range2, 1, NULL, NULL) + && rand()%1000<1000/(++(*itc))) pd->target_id=bl->id; return 0; } diff --git a/src/map/skill.h b/src/map/skill.h index f485e3394..f27a47f5a 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -41,6 +41,10 @@ #define INF2_PARTY_ONLY 1024 #define INF2_GUILD_ONLY 2048 +//Walk intervals at which chase-skills are attempted to be triggered. +//Note that every 2 is an actual cell walked. +#define WALK_SKILL_INTERVAL 6 + // スキルデ?タベ?ス struct skill_db { char *name; diff --git a/src/map/unit.c b/src/map/unit.c index e928178cd..6b5dd0433 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -57,12 +57,12 @@ int unit_walktoxy_sub(struct block_list *bl) memcpy(&ud->walkpath,&wpd,sizeof(wpd)); + ud->state.change_walk_target=0; + if (bl->type == BL_PC) clif_walkok((TBL_PC*)bl); clif_move(bl); - ud->state.change_walk_target=0; - if(ud->walkpath.path_pos>=ud->walkpath.path_len) i = -1; else if(ud->walkpath.path[ud->walkpath.path_pos]&1) @@ -143,9 +143,6 @@ static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data) x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE, dx,dy,sd?BL_ALL:BL_PC,bl); - if(md && md->min_chase > md->db->range2) - md->min_chase--; - x += dx; y += dy; map_moveblock(bl, x, y, tick); @@ -178,11 +175,19 @@ static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data) if ( (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR && sd->sc.data[SC_MIRACLE].timer==-1 && - rand()%100000 < battle_config.sg_miracle_skill_ratio + !ud->walkpath.path_pos%WALK_SKILL_INTERVAL && + rand()%10000 < battle_config.sg_miracle_skill_ratio ) { //SG_MIRACLE [Komurka] clif_displaymessage(sd->fd,"[Miracle of the Sun, Moon and Stars]"); sc_start(&sd->bl,SC_MIRACLE,100,1,battle_config.sg_miracle_skill_duration); } + } else if (md) { + if (ud->attacktarget) { + if(md->min_chase > md->db->range2) md->min_chase--; + if(!ud->walkpath.path_pos%WALK_SKILL_INTERVAL && + mobskill_use(md, tick, -1)) + return 0; + } } } @@ -200,8 +205,23 @@ static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data) ud->walktimer = add_timer(tick+i,unit_walktoxy_timer,id,ud->walkpath.path_pos); } else if(sd && sd->sc.count && sd->sc.data[SC_RUN].timer!=-1) //Keep trying to run. pc_run(sd, sd->sc.data[SC_RUN].val1, sd->sc.data[SC_RUN].val2); - else - { //Stopped walking. Update to_x and to_y to current location [Skotlex] + else if (ud->walktarget) { + //Update target trajectory. + struct block_list *tbl = map_id2bl(ud->walktarget); + if (!tbl) { //Cancel chase. + ud->to_x = bl->x; + ud->to_y = bl->y; + return 0; + } + if (tbl->m == bl->m && check_distance_bl(bl, tbl, ud->chaserange)) + { //Reached destination. + if (ud->attacktarget == tbl->id) + unit_attack(bl, tbl->id, ud->state.attack_continue); + } else { //Update chase-path + unit_walktobl(bl, tbl, ud->chaserange, ud->state.walk_easy); + return 0; + } + } else { //Stopped walking. Update to_x and to_y to current location [Skotlex] ud->to_x = bl->x; ud->to_y = bl->y; // if (bl->type == BL_NPC) //Original eA code had this one only for BL_NPCs @@ -221,10 +241,11 @@ int unit_walktoxy( struct block_list *bl, int x, int y, int easy) { if( ud == NULL) return 0; // 移動出来ないユニットは弾く - if(!unit_can_move(bl) || !(status_get_mode(bl)&MD_CANMOVE) ) + if(!(status_get_mode(bl)&MD_CANMOVE) || !unit_can_move(bl)) return 0; ud->state.walk_easy = easy; + ud->walktarget = 0; ud->to_x = x; ud->to_y = y; @@ -242,6 +263,87 @@ int unit_walktoxy( struct block_list *bl, int x, int y, int easy) { } } +static int unit_walktobl_sub(int tid,unsigned int tick,int id,int data) +{ + struct block_list *bl = map_id2bl(id); + struct unit_data *ud = bl?unit_bl2ud(bl):NULL; + + if (ud && ud->walktimer == -1 && ud->walktarget == data) + { + if (DIFF_TICK(ud->canmove_tick, tick) > 0) //Keep waiting? + add_timer(ud->canmove_tick+1, unit_walktobl_sub, id, data); + else if (unit_can_move(bl)) + unit_walktoxy_sub(bl); + } + return 0; +} + +// Chases a tbl. If the flag&1, use hard-path seek, +// if flag&2, start attacking upon arrival within range. +int unit_walktobl(struct block_list *bl, struct block_list *tbl, int range, int flag) { + struct unit_data *ud = NULL; + struct status_change *sc = NULL; + int i; + nullpo_retr(0, bl); + nullpo_retr(0, tbl); + + ud = unit_bl2ud(bl); + if( ud == NULL) return 0; + + if (!(status_get_mode(bl)&MD_CANMOVE)) + return 0; + + i = distance_bl(bl, tbl)+1; + if (!unit_can_reach_bl(bl, tbl, i, flag&1, &ud->to_x, &ud->to_y)) { + ud->to_x = bl->x; + ud->to_y = bl->y; + return 0; + } + + ud->state.walk_easy = flag&1; + ud->walktarget = tbl->id; + ud->chaserange = range; + + if (range) { + //Adjust target cell + if (i < range) { + //We are already within required distance! + if (flag&2) //Attack + unit_attack(bl, tbl->id, 1); + return 1; + } + //Trim the last part of the path to account for range. + for (i = 1; i <= range && ud->walkpath.path_len>0; i++) { + int dir; + ud->walkpath.path_len--; + dir = ud->walkpath.path[ud->walkpath.path_len]; + ud->to_x -= dirx[dir]; + ud->to_y -= diry[dir]; + } + } + sc = status_get_sc(bl); + if (sc && sc->count && sc->data[SC_CONFUSION].timer != -1) //Randomize the target position + map_random_dir(bl, &ud->to_x, &ud->to_y); + + if (flag&2) { //Chase to attack. + ud->attacktarget = tbl->id; + ud->state.attack_continue = 1; + } + + if(ud->walktimer != -1) { + ud->state.change_walk_target = 1; + return 1; + } + if (DIFF_TICK(ud->canmove_tick, gettick()) > 0) + { //Can't move, wait a bit before invoking the movement. + add_timer(ud->canmove_tick+1, unit_walktobl_sub, bl->id, ud->walktarget); + return 1; + } else if (!unit_can_move(bl)) + return 0; + + return unit_walktoxy_sub(bl); +} + //Instant warp function. int unit_movepos(struct block_list *bl,int dst_x,int dst_y, int easy, int checkpath) { @@ -543,6 +645,13 @@ int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int return 0; } ud->canmove_tick = tick + delay; + if (ud->walktimer != -1) + { //Stop walking, if chasing, readjust timers. + delete_timer(ud->walktimer, unit_walktoxy_timer); + clif_fixpos(bl); + if(ud->walktarget) + add_timer(ud->canmove_tick+1, unit_walktobl_sub, bl->id, ud->walktarget); + } return 1; } @@ -552,8 +661,7 @@ static int unit_walkdelay_sub(int tid, unsigned int tick, int id, int data) if (!bl || status_isdead(bl)) return 0; - if (unit_set_walkdelay(bl, tick, data, 0)) - unit_stop_walking(bl,3); + unit_set_walkdelay(bl, tick, data, 0); return 0; } @@ -954,7 +1062,11 @@ int unit_stop_attack(struct block_list *bl) //Means current target is unattackable. For now only unlocks mobs. int unit_unattackable(struct block_list *bl) { struct unit_data *ud = unit_bl2ud(bl); - if (ud) ud->attacktarget = 0; + if (ud) { + ud->attacktarget = 0; + ud->walktarget = 0; + } + if(bl->type == BL_MOB) mob_unlocktarget((struct mob_data*)bl, gettick()) ; else if(bl->type == BL_PET) @@ -995,6 +1107,11 @@ int unit_attack(struct block_list *src,int target_id,int type) ud->attacktarget = target_id; ud->state.attack_continue = type; + if (type) { //If you re to attack continously, set to auto-case character + ud->walktarget = target_id; + ud->chaserange = status_get_range(src); + } + //Just change target/type. [Skotlex] if(ud->attacktimer != -1) return 0; @@ -1012,7 +1129,7 @@ int unit_attack(struct block_list *src,int target_id,int type) * *------------------------------------------ */ -int unit_can_reach(struct block_list *bl,int x,int y) +int unit_can_reach_pos(struct block_list *bl,int x,int y, int easy) { struct walkpath_data wpd; @@ -1025,9 +1142,63 @@ int unit_can_reach(struct block_list *bl,int x,int y) wpd.path_len=0; wpd.path_pos=0; wpd.path_half=0; - return (path_search_real(&wpd,bl->m,bl->x,bl->y,x,y,0,CELL_CHKNOREACH)!=-1)?1:0; + return (path_search_real(&wpd,bl->m,bl->x,bl->y,x,y,easy,CELL_CHKNOREACH)!=-1); +} + +/*========================================== + * + *------------------------------------------ + */ +int unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, int easy, short *x, short *y) +{ + struct walkpath_data wpd; + int i; + short dx,dy; + nullpo_retr(0, bl); + nullpo_retr(0, tbl); + + if( bl->m != tbl->m) + return 0; + + if( bl->x==tbl->x && bl->y==tbl->y ) + return 1; + + if(range>0 && !check_distance_bl(bl, tbl, range)) + return 0; + + wpd.path_len=0; + wpd.path_pos=0; + wpd.path_half=0; + +#ifndef CELL_NOSTACK + //Skip direct path seeking when in nostacking mode. + if(path_search_real(&wpd,bl->m,bl->x,bl->y,tbl->x,tbl->y,easy,CELL_CHKNOREACH)!=-1) { + if (x) *x = tbl->x; + if (y) *y = tbl->y; + return 1; + } +#endif + + // It judges whether it can adjoin or not. + dx=tbl->x - bl->x; + dy=tbl->y - bl->y; + dx=(dx>0)?1:((dx<0)?-1:0); + dy=(dy>0)?1:((dy<0)?-1:0); + + if (map_getcell(tbl->m,tbl->x+dx,tbl->y+dy,CELL_CHKNOREACH)) + { //Look for a suitable cell to place in. + for(i=0;i<9 && map_getcell(tbl->m,tbl->x-dirx[i],tbl->y-diry[i],CELL_CHKNOREACH);i++); + if (i==9) return 0; //No valid cells. + dx = dirx[i]; + dy = diry[i]; + } + + if (x) *x = tbl->x-dx; + if (y) *y = tbl->y-dy; + return (path_search_real(&wpd,bl->m,bl->x,bl->y,tbl->x-dx,tbl->y-dy,easy,CELL_CHKNOREACH)!=-1); } + /*========================================== * PCの攻撃 (timer関数) *------------------------------------------ @@ -1078,23 +1249,29 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t return 1; } - range = status_get_range( src ); + range = status_get_range(src); if(ud->walktimer != -1) range++; //Extra range when walking. if(!sd || sd->status.weapon != 11) range++; //Dunno why everyone but bows gets this extra range... if(unit_is_walking(target)) range++; //Extra range when chasing if(!check_distance_bl(src,target,range) ) { - if(!unit_can_reach(src,target->x,target->y)) - return 0; - if(sd) clif_movetoattack(sd,target); - return 1; + //Chase if required. + if(ud->state.attack_continue && ud->walktarget == target->id) { + if(sd) + clif_movetoattack(sd,target); + else + unit_walktobl(src,target,ud->chaserange,ud->state.walk_easy); + } + return 1; } - if(!battle_check_range(src,target,range)) { //Within range, but no direct line of attack - if(unit_can_reach(src,target->x,target->y)) - unit_walktoxy(src,target->x,target->y, ud->state.walk_easy); - if(ud->state.attack_continue) + if(!battle_check_range(src,target,range)) { + //Within range, but no direct line of attack + if(ud->state.attack_continue && ud->walktarget == target->id) { + if(ud->chaserange > 2) ud->chaserange-=2; + unit_walktobl(src,target,ud->chaserange,ud->state.walk_easy); ud->attacktimer = add_timer(tick + status_get_adelay(src),unit_attack_timer,src->id,0); + } return 1; } @@ -1141,7 +1318,7 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t // You can't move if you can't attack neither. // Only for non-players, since it makes it near impossible to run away when you are on auto-attack. - if (src->type != BL_PC) + if (src->type != BL_PC) unit_set_walkdelay(src, tick, status_get_amotion(src), 1); } @@ -1604,6 +1781,8 @@ int do_init_unit(void) { add_timer_func_list(unit_attack_timer, "unit_attack_timer"); add_timer_func_list(unit_walktoxy_timer,"unit_walktoxy_timer"); add_timer_func_list(unit_walkdelay_sub, "unit_walkdelay_sub"); + add_timer_func_list(unit_walktobl_sub, "unit_walktobl_sub"); + return 0; } diff --git a/src/map/unit.h b/src/map/unit.h index 9724a8523..f3c0c87c9 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -11,6 +11,7 @@ // 歩行開始 // 戻り値は、0 ( 成功 ), 1 ( 失敗 ) int unit_walktoxy( struct block_list *bl, int x, int y, int easy); +int unit_walktobl( struct block_list *bl, struct block_list *target, int range, int easy); // 歩行停止 // typeは以下の組み合わせ : @@ -31,7 +32,8 @@ int unit_setdir(struct block_list *bl,unsigned char dir); int unit_getdir(struct block_list *bl); // そこまで歩行でたどり着けるかの判定 -int unit_can_reach(struct block_list *bl,int x,int y); +int unit_can_reach_pos(struct block_list *bl,int x,int y,int easy); +int unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, int easy, short *x, short *y); // 攻撃関連 int unit_stop_attack(struct block_list *bl); -- cgit v1.2.3-70-g09d2 From 260c3e2fc442271410e96a89b924d54aa767d80d Mon Sep 17 00:00:00 2001 From: skotlex Date: Tue, 11 Apr 2006 23:58:55 +0000 Subject: - Changed clif_damage/clif_skill_damage to return the walk-delay based on the passed on damage-delay. - Changed battle_damage to accept the walk-delay as well. - Removed the walk-delay timers from unit.c, merged them to battle_delay_damage. - Traps will not be displayed when you walk within their range. - Added HT_DETECTING revealing traps. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@5997 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 5 +++ src/map/battle.c | 67 ++++++++++++++++-------------- src/map/battle.h | 5 +-- src/map/clif.c | 114 ++++++++++++++++++++++++++++++++++++++++------------ src/map/clif.h | 1 + src/map/skill.c | 55 +++++++++++++++---------- src/map/status.c | 12 +++--- src/map/unit.c | 43 +------------------- src/map/unit.h | 2 - 9 files changed, 176 insertions(+), 128 deletions(-) (limited to 'src/map/unit.h') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 6d797387f..be80346dc 100644 --- a/Changelog-Trunk.txt +++ b/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. 2006/04/11 + * Merged the can't walk delay code into the weapon-damage delay one, means + less timers for attacks, as well as fixing the ghost-mob issue that + reappeared recently. [Skotlex] + * Traps will not be displayed when you walk within their range. [Skotlex] + * Added HT_DETECTING revealing traps. [Skotlex] * Added ers handling for skill_timerskill structures. [Skotlex] * You don't get critical'ed when in counter-attack stance anymore. [Skotlex] * Changed the default counter-type to "always critical". [Skotlex] diff --git a/src/map/battle.c b/src/map/battle.c index 06242d98e..e97856c25 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -109,6 +109,7 @@ struct delay_damage { struct block_list *src; int target; int damage; + int delay; unsigned short distance; unsigned short skill_lv; unsigned short skill_id; @@ -124,12 +125,11 @@ int battle_delay_damage_sub (int tid, unsigned int tick, int id, int data) if (target && dat && map_id2bl(id) == dat->src && target->prev != NULL && !status_isdead(target) && target->m == dat->src->m && check_distance_bl(dat->src, target, dat->distance)) //Check to see if you haven't teleported. [Skotlex] { - battle_damage(dat->src, target, dat->damage, dat->flag); + battle_damage(dat->src, target, dat->damage, dat->delay, dat->flag); if ((dat->dmg_lv == ATK_DEF || dat->damage > 0) && dat->attack_type) { if (!status_isdead(target)) skill_additional_effect(dat->src,target,dat->skill_id,dat->skill_lv,dat->attack_type, tick); - skill_counter_additional_effect(dat->src,target,dat->skill_id,dat->skill_lv,dat->attack_type,tick); } @@ -138,19 +138,18 @@ int battle_delay_damage_sub (int tid, unsigned int tick, int id, int data) return 0; } -int battle_delay_damage (unsigned int tick, struct block_list *src, struct block_list *target, int attack_type, int skill_id, int skill_lv, int damage, int dmg_lv, int flag) +int battle_delay_damage (unsigned int tick, struct block_list *src, struct block_list *target, int attack_type, int skill_id, int skill_lv, int damage, int dmg_lv, int ddelay, int flag) { struct delay_damage *dat; nullpo_retr(0, src); nullpo_retr(0, target); if (!battle_config.delay_battle_damage) { - battle_damage(src, target, damage, flag); + battle_damage(src, target, damage, ddelay, flag); if ((damage > 0 || dmg_lv == ATK_DEF) && attack_type) { if (!status_isdead(target)) skill_additional_effect(src, target, skill_id, skill_lv, attack_type, gettick()); - skill_counter_additional_effect(src, target, skill_id, skill_lv, attack_type, gettick()); } return 0; @@ -163,6 +162,7 @@ int battle_delay_damage (unsigned int tick, struct block_list *src, struct block dat->attack_type = attack_type; dat->damage = damage; dat->dmg_lv = dmg_lv; + dat->delay = ddelay; dat->flag = flag; dat->distance = distance_bl(src, target)+10; //Attack should connect regardless unless you teleported. add_timer(tick, battle_delay_damage_sub, src->id, (int)dat); @@ -171,26 +171,24 @@ int battle_delay_damage (unsigned int tick, struct block_list *src, struct block } // 実?ロにHPを操? -int battle_damage(struct block_list *src,struct block_list *target,int damage, int flag) +int battle_damage(struct block_list *src,struct block_list *target,int damage, int walkdelay, int flag) { struct map_session_data *sd = NULL; struct status_change *sc; - + int r_damage=0; + nullpo_retr(0, target); //srcはNULLで呼ばれることがあるので他でチェック if (damage == 0 || status_isdead(target)) return 0; - - sc = status_get_sc(target); if (damage < 0) return battle_heal(src,target,-damage,0,flag); - if (src) { - if (src->prev == NULL) - return 0; + if (src) BL_CAST(BL_PC, src, sd); - } + + sc = status_get_sc(target); if (!flag && sc && sc->count) { // 凍結?A?ホ化?A?眠を?チ去 @@ -244,13 +242,23 @@ int battle_damage(struct block_list *src,struct block_list *target,int damage, i if (!flag) unit_skillcastcancel(target, 2); - if (target->type == BL_MOB) { - return mob_damage(src,(TBL_MOB*)target, damage,0); - } else if (target->type == BL_PC) { - return pc_damage(src,(TBL_PC*)target,damage); - } else if (target->type == BL_SKILL) - return skill_unit_ondamaged((struct skill_unit *)target, src, damage, gettick()); - return 0; + switch (target->type) + { + case BL_MOB: + r_damage = mob_damage(src,(TBL_MOB*)target, damage,0); + break; + case BL_PC: + r_damage = pc_damage(src,(TBL_PC*)target,damage); + break; + case BL_SKILL: + r_damage = skill_unit_ondamaged((struct skill_unit *)target, src, damage, gettick()); + break; + } + + if (walkdelay && !status_isdead(target)) + unit_set_walkdelay(target, gettick(), walkdelay, 0); + + return r_damage; } int battle_heal(struct block_list *bl,struct block_list *target,int hp,int sp, int flag) @@ -271,7 +279,7 @@ int battle_heal(struct block_list *bl,struct block_list *target,int hp,int sp, i if (sp == 0) { if (hp < 0) //Use flag 1 because heal-damage shouldn't make you flinch. - return battle_damage(bl, target, -hp, 1); + return battle_damage(bl, target, -hp, 0, 1); if (hp == 0) return 0; } @@ -505,8 +513,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,i ((struct map_session_data *)src)->status.weapon == W_2HSWORD)))){ if(rand()%100 < (15*sc->data[SC_REJECTSWORD].val1)){ damage = damage*50/100; - clif_damage(bl,src,gettick(),0,0,damage,0,0,0); - battle_damage(bl,src,damage,0); + battle_damage(bl,src,damage,clif_damage(bl,src,gettick(),0,0,damage,0,0,0),0); clif_skill_nodamage(bl,bl,ST_REJECTSWORD,sc->data[SC_REJECTSWORD].val1,1); if((--sc->data[SC_REJECTSWORD].val2)<=0) status_change_end(bl, SC_REJECTSWORD, -1); @@ -1399,7 +1406,7 @@ static struct Damage battle_calc_weapon_attack( case PA_SACRIFICE: { int hp_dmg = status_get_max_hp(src)* 9/100; - battle_damage(src, src, hp_dmg, 1); //Damage to self is always 9% + battle_damage(src, src, hp_dmg, 0, 1); //Damage to self is always 9% clif_damage(src,src, gettick(), 0, 0, hp_dmg, 0 , 0, 0); wd.damage = hp_dmg; @@ -2287,7 +2294,7 @@ static struct Damage battle_calc_weapon_attack( hp = sd->status.hp; } else hp = 5*hp/1000; - battle_damage(NULL, src, hp, 1); + battle_damage(NULL, src, hp, 0, 1); } return wd; @@ -3022,7 +3029,7 @@ int battle_weapon_attack( struct block_list *src,struct block_list *target, { struct map_session_data *sd = NULL, *tsd = NULL; struct status_change *sc, *tsc; - int race, ele, damage,rdamage=0; + int race, ele, damage,rdamage=0,rdelay=0; struct Damage wd; nullpo_retr(0, src); @@ -3107,13 +3114,13 @@ int battle_weapon_attack( struct block_list *src,struct block_list *target, if (damage > 0 && src != target) { rdamage = battle_calc_return_damage(target, &damage, wd.flag); if (rdamage > 0) { - clif_damage(src, src, tick, wd.amotion, wd.dmotion, rdamage, 1, 4, 0); + rdelay = clif_damage(src, src, tick, wd.amotion, status_get_dmotion(src), rdamage, 1, 4, 0); //Use Reflect Shield to signal this kind of skill trigger. [Skotlex] skill_additional_effect(target,src,CR_REFLECTSHIELD, 1,BF_WEAPON,tick); } } - clif_damage(src, target, tick, wd.amotion, wd.dmotion, wd.damage, wd.div_ , wd.type, wd.damage2); + wd.dmotion = clif_damage(src, target, tick, wd.amotion, wd.dmotion, wd.damage, wd.div_ , wd.type, wd.damage2); //二?流?カ手とカタ?[ル追撃のミス表示(無?やり?`) if(sd && sd->status.weapon >= MAX_WEAPON_TYPE && wd.damage2 == 0) clif_damage(src, target, tick+10, wd.amotion, wd.dmotion,0, 1, 0, 0); @@ -3123,7 +3130,7 @@ int battle_weapon_attack( struct block_list *src,struct block_list *target, map_freeblock_lock(); - battle_delay_damage(tick+wd.amotion, src, target, BF_WEAPON, 0, 0, damage, wd.dmg_lv, 0); + battle_delay_damage(tick+wd.amotion, src, target, BF_WEAPON, 0, 0, damage, wd.dmg_lv, wd.dmotion, 0); if (!status_isdead(target) && damage > 0) { if (sd) { @@ -3209,7 +3216,7 @@ int battle_weapon_attack( struct block_list *src,struct block_list *target, } } if (rdamage > 0) //By sending attack type "none" skill_additional_effect won't be invoked. [Skotlex] - battle_delay_damage(tick+wd.amotion, target, src, 0, 0, 0, rdamage, ATK_DEF, 0); + battle_delay_damage(tick+wd.amotion, target, src, 0, 0, 0, rdamage, ATK_DEF, rdelay, 0); if (tsc) { if (tsc->data[SC_POISONREACT].timer != -1 && diff --git a/src/map/battle.h b/src/map/battle.h index c7b913b54..1cae169d6 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -46,9 +46,8 @@ enum { // BF_SKILLMASK= 0x0f00, }; -// 実際にHPを増減 -int battle_delay_damage (unsigned int tick, struct block_list *src, struct block_list *target, int attack_type, int skill_id, int skill_lv, int damage, int dmg_lv, int flag); -int battle_damage(struct block_list *bl,struct block_list *target,int damage,int flag); +int battle_delay_damage (unsigned int tick, struct block_list *src, struct block_list *target, int attack_type, int skill_id, int skill_lv, int damage, int dmg_lv, int ddelay, int flag); +int battle_damage(struct block_list *bl,struct block_list *target,int damage,int walkdelay,int flag); int battle_heal(struct block_list *bl,struct block_list *target,int hp,int sp,int flag); diff --git a/src/map/clif.c b/src/map/clif.c index e16610107..bbb42a873 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -3679,20 +3679,34 @@ int clif_fixpos2(struct block_list* bl) return 0; } +//Modifies the type of damage according to status changes [Skotlex] +#define clif_calc_delay(type,delay) (type==1||type==4||type==0x0a)?type:(delay==0?9:type) + /*========================================== - * Modifies the type of damage according to status changes [Skotlex] + * Estimates walk delay based on the damage criteria. [Skotlex] *------------------------------------------ */ -static int clif_calc_delay(struct block_list *dst, int type, int delay) -{ - if (type == 1 || type == 4 || type == 0x0a) //Type 1 is the crouching animation, type 4 are non-flinching attacks, 0x0a - crits. - return type; +static int clif_calc_walkdelay(struct block_list *bl,int delay, int type, int damage, int div_) { + + if (type == 4 || type == 9 || damage <=0) + return 0; - if (delay == 0) - return 9; //Endure type attack (damage delay is 0) + if (bl->type == BL_PC) { + if (battle_config.pc_walk_delay_rate != 100) + delay = delay*battle_config.pc_walk_delay_rate/100; + } else + if (battle_config.walk_delay_rate != 100) + delay = delay*battle_config.walk_delay_rate/100; - return type; + if (div_ > 1) //Multi-hit skills mean higher delays. + delay += battle_config.multihit_delay*(div_-1); + + if (delay <= 0) + return 0; + + return delay>0?delay:0; } + /*========================================== * 通常攻撃エフェクト&ダメージ *------------------------------------------ @@ -3705,7 +3719,7 @@ int clif_damage(struct block_list *src,struct block_list *dst,unsigned int tick, nullpo_retr(0, src); nullpo_retr(0, dst); - type = clif_calc_delay(dst, type, ddelay); //Type defaults to 0 for normal attacks. + type = clif_calc_delay(type, ddelay); //Type defaults to 0 for normal attacks. sc = status_get_sc(dst); @@ -3750,11 +3764,8 @@ int clif_damage(struct block_list *src,struct block_list *dst,unsigned int tick, } clif_send(buf,packet_len_table[0x8a],dst,SELF); } - //Because the damage delay must be synced with the client, here is where the can-walk tick must be updated. [Skotlex] - if (type != 4 && type != 9 && damage+damage2 > 0) //Non-endure/Non-flinch attack, update walk delay. - unit_walkdelay(dst, tick, sdelay, ddelay, div); - - return 0; + //Return adjusted can't walk delay for further processing. + return clif_calc_walkdelay(dst,ddelay,type,damage+damage2,div); } /*========================================== @@ -3782,6 +3793,7 @@ void clif_getareachar_item(struct map_session_data* sd,struct flooritem_data* fi WFIFOB(fd,16)=fitem->suby; WFIFOSET(fd,packet_len_table[0x9d]); } + /*========================================== * 場所スキルエフェクトが視界に入る *------------------------------------------ @@ -3851,6 +3863,56 @@ int clif_getareachar_skillunit(struct map_session_data *sd,struct skill_unit *un return 0; } + +int clif_reveal_skillunit(struct skill_unit *unit) { + struct block_list *bl; + unsigned char buf[97]; + bl=map_id2bl(unit->group->src_id); +#if PACKETVER < 3 + memset(buf,0,packet_len_table[0x11f]); + WBUFW(buf, 0)=0x11f; + WBUFL(buf, 2)=unit->bl.id; + WBUFL(buf, 6)=unit->group->src_id; + WBUFW(buf,10)=unit->bl.x; + WBUFW(buf,12)=unit->bl.y; + WBUFB(buf,14)=unit->group->unit_id; + WBUFB(buf,15)=0; + clif_send(buf,packet_len_table[0x11f],&unit->bl,AREA); +#else + memset(buf,0,packet_len_table[0x1c9]); + WBUFW(buf, 0)=0x1c9; + WBUFL(buf, 2)=unit->bl.id; + WBUFL(buf, 6)=unit->group->src_id; + WBUFW(buf,10)=unit->bl.x; + WBUFW(buf,12)=unit->bl.y; + WBUFB(buf,14)=unit->group->unit_id; + WBUFB(buf,15)=1; + WBUFL(buf,15+1)=0; + WBUFL(buf,15+5)=0; + + WBUFL(buf,15+13)=unit->bl.y - 0x12; + WBUFL(buf,15+17)=0x004f37dd; + WBUFL(buf,15+21)=0x0012f674; + WBUFL(buf,15+25)=0x0012f664; + WBUFL(buf,15+29)=0x0012f654; + WBUFL(buf,15+33)=0x77527bbc; + + WBUFB(buf,15+40)=0x2d; + WBUFL(buf,15+41)=0; + WBUFL(buf,15+45)=0; + WBUFL(buf,15+49)=0; + WBUFL(buf,15+53)=0x0048d919; + WBUFL(buf,15+57)=0x0000003e; + WBUFL(buf,15+61)=0x0012f66c; + + if(bl) WBUFL(buf,15+73)=bl->y; + WBUFL(buf,15+77)=unit->bl.m; + WBUFB(buf,15+81)=0xaa; + + clif_send(buf,packet_len_table[0x1c9],&unit->bl,AREA); +#endif + return 0; +} /*========================================== * 場所スキルエフェクトが視界から消える *------------------------------------------ @@ -3907,7 +3969,9 @@ int clif_01ac(struct block_list *bl) clif_getareachar_item(sd,(struct flooritem_data*) bl); break; case BL_SKILL: - clif_getareachar_skillunit(sd,(struct skill_unit *)bl); + //Only reveal non-traps. [Skotlex] + if (!skill_get_inf2(((TBL_SKILL*)bl)->group->skill_id)&INF2_TRAP) + clif_getareachar_skillunit(sd,(TBL_SKILL*)bl); break; default: if(&sd->bl == bl) @@ -3989,7 +4053,9 @@ int clif_insight(struct block_list *bl,va_list ap) clif_getareachar_item(tsd,(struct flooritem_data*)bl); break; case BL_SKILL: - clif_getareachar_skillunit(tsd,(struct skill_unit *)bl); + //Only reveal non-traps. [Skotlex] + if (!skill_get_inf2(((TBL_SKILL*)bl)->group->skill_id)&INF2_TRAP) + clif_getareachar_skillunit(tsd,(TBL_SKILL*)bl); break; default: clif_getareachar_char(tsd,bl); @@ -4196,8 +4262,9 @@ int clif_skill_damage(struct block_list *src,struct block_list *dst, nullpo_retr(0, src); nullpo_retr(0, dst); - - type = clif_calc_delay(dst, (type>0)?type:skill_get_hit(skill_id), ddelay); + + type = (type>0)?type:skill_get_hit(skill_id); + type = clif_calc_delay(type, ddelay); sc = status_get_sc(dst); if(sc && sc->count) { @@ -4262,9 +4329,7 @@ int clif_skill_damage(struct block_list *src,struct block_list *dst, #endif //Because the damage delay must be synced with the client, here is where the can-walk tick must be updated. [Skotlex] - if (type != 4 && type != 9 && damage > 0) //Non-endure/Non-flinch attack, update walk delay. - unit_walkdelay(dst, tick, sdelay, ddelay, div); - return 0; + return clif_calc_walkdelay(dst,ddelay,type,damage,div); } /*========================================== @@ -4280,7 +4345,8 @@ int clif_skill_damage2(struct block_list *src,struct block_list *dst, nullpo_retr(0, src); nullpo_retr(0, dst); - type = clif_calc_delay(dst, (type>0)?type:skill_get_hit(skill_id), ddelay); + type = (type>0)?type:skill_get_hit(skill_id); + type = clif_calc_delay(type, ddelay); sc = status_get_sc(dst); if(sc && sc->count) { @@ -4318,9 +4384,7 @@ int clif_skill_damage2(struct block_list *src,struct block_list *dst, } //Because the damage delay must be synced with the client, here is where the can-walk tick must be updated. [Skotlex] - if (type != 4 && type != 9 && damage > 0) //Non-endure/Non-flinch attack, update walk delay. - unit_walkdelay(dst, tick, sdelay, ddelay, div); - return 0; + return clif_calc_walkdelay(dst,ddelay,type,damage,div); } /*========================================== diff --git a/src/map/clif.h b/src/map/clif.h index 252a707f8..854cf74d4 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -100,6 +100,7 @@ int clif_clearchat(struct chat_data*,int); // area or fd int clif_leavechat(struct chat_data*,struct map_session_data*); // chat int clif_changechatstatus(struct chat_data*); // chat int clif_refresh(struct map_session_data*); // self +int clif_reveal_skillunit(struct skill_unit *unit); //Area int clif_fame_blacksmith(struct map_session_data *, int); int clif_fame_alchemist(struct map_session_data *, int); diff --git a/src/map/skill.c b/src/map/skill.c index cff35389a..9e340c066 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -1905,20 +1905,20 @@ int skill_attack( int attack_type, struct block_list* src, struct block_list *ds case SG_SUN_WARM: case SG_MOON_WARM: case SG_STAR_WARM: - clif_skill_damage(dsrc,bl,tick,dmg.amotion,dmg.dmotion, damage, dmg.div_, skillid, -1, 5); + dmg.dmotion = clif_skill_damage(dsrc,bl,tick,dmg.amotion,dmg.dmotion, damage, dmg.div_, skillid, -1, 5); break; case KN_BRANDISHSPEAR: case SN_SHARPSHOOTING: { //Only display skill animation for skill's target. struct unit_data *ud = unit_bl2ud(src); if (ud && ud->skilltarget == bl->id) - clif_skill_damage(dsrc,bl,tick,dmg.amotion,dmg.dmotion, damage, dmg.div_, skillid, (lv!=0)?lv:skilllv, type); + dmg.dmotion = clif_skill_damage(dsrc,bl,tick,dmg.amotion,dmg.dmotion, damage, dmg.div_, skillid, (lv!=0)?lv:skilllv, type); else - clif_skill_damage(dsrc,bl,tick,dmg.amotion,dmg.dmotion, damage, dmg.div_, skillid, -1, 5); + dmg.dmotion = clif_skill_damage(dsrc,bl,tick,dmg.amotion,dmg.dmotion, damage, dmg.div_, skillid, -1, 5); break; } case PA_GOSPEL: //Should look like Holy Cross [Skotlex] - clif_skill_damage(dsrc,bl,tick,dmg.amotion,dmg.dmotion, damage, dmg.div_, CR_HOLYCROSS, -1, 5); + dmg.dmotion = clif_skill_damage(dsrc,bl,tick,dmg.amotion,dmg.dmotion, damage, dmg.div_, CR_HOLYCROSS, -1, 5); break; case ASC_BREAKER: // [celest] @@ -1930,7 +1930,7 @@ int skill_attack( int attack_type, struct block_list* src, struct block_list *ds damage += tmpdmg; // add weapon and magic damage tmpdmg = 0; // clear the temporary weapon damage if (damage > 0) // if both attacks missed, do not display a 2nd 'miss' - clif_skill_damage(dsrc, bl, tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skillid, skilllv, type); + dmg.dmotion = clif_skill_damage(dsrc, bl, tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skillid, skilllv, type); } break; case NPC_SELFDESTRUCTION: @@ -1940,17 +1940,17 @@ int skill_attack( int attack_type, struct block_list* src, struct block_list *ds case KN_AUTOCOUNTER: //Skills that need be passed as a normal attack for the client to display correctly. case TF_DOUBLE: case GS_CHAINACTION: - clif_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,dmg.type,dmg.damage2); + dmg.dmotion = clif_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,dmg.type,dmg.damage2); break; case CR_GRANDCROSS: case NPC_GRANDDARKNESS: //Only show animation when hitting yourself. [Skotlex] if (src!=bl) { - clif_skill_damage(dsrc,bl,tick,dmg.amotion,dmg.dmotion, damage, dmg.div_, skillid, -1, 5); + dmg.dmotion = clif_skill_damage(dsrc,bl,tick,dmg.amotion,dmg.dmotion, damage, dmg.div_, skillid, -1, 5); break; } default: - clif_skill_damage(dsrc,bl,tick,dmg.amotion,dmg.dmotion, damage, dmg.div_, skillid, (lv!=0)?lv:skilllv, (skillid==0)? 5:type ); + dmg.dmotion = clif_skill_damage(dsrc,bl,tick,dmg.amotion,dmg.dmotion, damage, dmg.div_, skillid, (lv!=0)?lv:skilllv, (skillid==0)? 5:type ); } map_freeblock_lock(); @@ -1986,7 +1986,7 @@ int skill_attack( int attack_type, struct block_list* src, struct block_list *ds damage = 0; //Only Heaven's drive may damage traps. [Skotlex] } if ((skillid || flag) && !(attack_type&BF_WEAPON)) { // do not really deal damage for ASC_BREAKER's 1st attack - battle_damage(src,bl,damage, 0); //Deal damage before knockback to allow stuff like firewall+storm gust combo. + battle_damage(src,bl,damage,dmg.dmotion,0); //Deal damage before knockback to allow stuff like firewall+storm gust combo. if (dmg.dmg_lv == ATK_DEF || damage > 0) { if (!status_isdead(bl)) skill_additional_effect(src,bl,skillid,skilllv,attack_type,tick); @@ -2001,7 +2001,7 @@ int skill_attack( int attack_type, struct block_list* src, struct block_list *ds //Delayed damage must be dealt after the knockback (it needs to know actual position of target) if ((skillid || flag) && attack_type&BF_WEAPON && skillid != ASC_BREAKER) { // do not really deal damage for ASC_BREAKER's 1st attack - battle_delay_damage(tick+dmg.amotion,src,bl,attack_type,skillid,skilllv,damage,dmg.dmg_lv,0); + battle_delay_damage(tick+dmg.amotion,src,bl,attack_type,skillid,skilllv,damage,dmg.dmg_lv,dmg.dmotion,0); } if(skillid == RG_INTIMIDATE && damage > 0 && !(status_get_mode(bl)&MD_BOSS)/* && !map_flag_gvg(src->m)*/) { @@ -2042,9 +2042,9 @@ int skill_attack( int attack_type, struct block_list* src, struct block_list *ds if (rdamage>0) { if (attack_type&BF_WEAPON) - battle_delay_damage(tick+dmg.amotion,bl,src,0,0,0,rdamage,ATK_DEF,0); + battle_delay_damage(tick+dmg.amotion,bl,src,0,0,0,rdamage,ATK_DEF,0,0); else - battle_damage(bl,src,rdamage,0); + battle_damage(bl,src,rdamage,0,0); clif_damage(src,src,tick, dmg.amotion,0,rdamage,1,4,0); //Use Reflect Shield to signal this kind of skill trigger. [Skotlex] skill_additional_effect(bl,src,CR_REFLECTSHIELD, 1,BF_WEAPON,tick); @@ -2431,6 +2431,17 @@ int skill_cleartimerskill(struct block_list *src) return 1; } +static int skill_reveal_trap( struct block_list *bl,va_list ap ) +{ + TBL_SKILL *su = (TBL_SKILL*)bl; + if (su->alive && su->group && skill_get_inf2(su->group->skill_id)&INF2_TRAP) + { //Reveal trap. + clif_reveal_skillunit(su); + return 1; + } + return 0; +} + /*========================================== * スキル使用?i詠?・完了?AID指定?U?系?j * ?iスパゲッティに向けて1?前?i?I(ダ?ポ)?j @@ -3463,7 +3474,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in break; case SA_INSTANTDEATH: clif_skill_nodamage(src,bl,skillid,skilllv,1); - battle_damage(NULL,src,status_get_hp(src)-1,1); + battle_damage(NULL,src,status_get_hp(src)-1,0,1); break; case SA_QUESTION: case SA_GRAVITY: @@ -3489,7 +3500,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in break; case SA_DEATH: clif_skill_nodamage(src,bl,skillid,skilllv,1); - battle_damage(NULL,bl,status_get_max_hp(bl),1); + battle_damage(NULL,bl,status_get_max_hp(bl),0,1); break; case SA_REVERSEORCISH: clif_skill_nodamage(src,bl,skillid,skilllv, @@ -4038,7 +4049,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in skill_get_splash(skillid, skilllv), BL_CHAR, src, skillid, skilllv, tick, flag|BCT_ENEMY, skill_castend_damage_id); - battle_damage(src, src, status_get_max_hp(src), 1); + battle_damage(src, src, status_get_max_hp(src),0,1); break; /* パ?ティスキル */ @@ -4736,7 +4747,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in sp = skill_get_sp(bl_skillid,bl_skilllv); if (dstsd) pc_damage_sp(dstsd, sp, 0); - battle_damage(NULL, bl, hp, 1); + battle_damage(NULL, bl, hp, 0, 1); if(sd && sp) { sp = sp*(25*(skilllv-1))/100; if(skilllv > 1 && sp < 1) sp = 1; @@ -4877,7 +4888,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case NPC_SUICIDE: /* 自決 */ clif_skill_nodamage(src,bl,skillid,skilllv,1); - battle_damage(NULL, src,status_get_hp(src),3); //Suicidal Mobs should give neither exp (flag&1) not items (flag&2) [Skotlex] + battle_damage(NULL, src,status_get_hp(src),0,3); //Suicidal Mobs should give neither exp (flag&1) not items (flag&2) [Skotlex] break; case NPC_SUMMONSLAVE: /* 手下?「喚 */ @@ -5286,7 +5297,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case 3: // 1000 damage, random armor destroyed { int where[] = { EQP_ARMOR, EQP_SHIELD, EQP_HELM }; - battle_damage(src, bl, 1000, 0); + battle_damage(src, bl, 1000, 0, 0); clif_damage(src,bl,tick,0,0,1000,0,0,0); skill_break_equip(bl, where[rand()%3], 10000, BCT_ENEMY); } @@ -5319,14 +5330,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in sc_start(bl,SC_CONFUSION,100,skilllv,skill_get_time2(skillid,skilllv)); break; case 10: // 6666 damage, atk matk halved, cursed - battle_damage(src, bl, 6666, 0); + battle_damage(src, bl, 6666, 0, 0); clif_damage(src,bl,tick,0,0,6666,0,0,0); sc_start(bl,SC_INCATKRATE,100,-50,skill_get_time2(skillid,skilllv)); sc_start(bl,SC_INCMATKRATE,100,-50,skill_get_time2(skillid,skilllv)); sc_start(bl,SC_CURSE,skilllv,100,skill_get_time2(skillid,skilllv)); break; case 11: // 4444 damage - battle_damage(src, bl, 4444, 0); + battle_damage(src, bl, 4444, 0, 0); clif_damage(src,bl,tick,0,0,4444,0,0,0); break; case 12: // stun @@ -5914,6 +5925,8 @@ int skill_castend_pos2( struct block_list *src, int x,int y,int skillid,int skil map_foreachinarea( status_change_timer_sub, src->m, x-i, y-i, x+i,y+i,BL_CHAR, src,status_get_sc(src),SC_SIGHT,tick); + map_foreachinarea( skill_reveal_trap, + src->m, x-i, y-i, x+i,y+i,BL_SKILL); break; case MG_SAFETYWALL: /* セイフティウォ?ル */ @@ -10249,7 +10262,7 @@ int skill_produce_mix( struct map_session_data *sd, int skill_id, } else { switch (skill_id) { case ASC_CDP: //Damage yourself, and display same effect as failed potion. - battle_damage(NULL, &sd->bl, sd->status.max_hp>>2, 1); + battle_damage(NULL, &sd->bl, sd->status.max_hp>>2, 0, 1); case AM_PHARMACY: case AM_TWILIGHT1: case AM_TWILIGHT2: diff --git a/src/map/status.c b/src/map/status.c index ffba6e1e5..7555a25aa 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -4126,7 +4126,7 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val int diff = mhp*(bl->type==BL_PC?10:15)/100; if (hp - diff < mhp>>2) diff = hp - (mhp>>2); - battle_damage(NULL, bl, diff, 1); + battle_damage(NULL, bl, diff, 0, 1); } } // fall through case SC_POISON: /* 毒 */ @@ -4354,7 +4354,7 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val } case SC_COMA: //Coma. Sends a char to 1HP - battle_damage(NULL, bl, status_get_hp(bl)-1, 1); + battle_damage(NULL, bl, status_get_hp(bl)-1, 0, 1); return 1; case SC_CLOSECONFINE2: @@ -5440,7 +5440,7 @@ int status_change_timer(int tid, unsigned int tick, int id, int data) if((++sc->data[type].val4)%5 == 0 && status_get_hp(bl) > hp>>2) { hp = hp/100; if(hp < 1) hp = 1; - battle_damage(NULL, bl, hp, 1); + battle_damage(NULL, bl, hp, 0, 1); } sc->data[type].timer=add_timer(1000+tick,status_change_timer, bl->id, data ); return 0; @@ -5452,7 +5452,7 @@ int status_change_timer(int tid, unsigned int tick, int id, int data) break; case SC_DPOISON: if ((--sc->data[type].val3) > 0 && sc->data[SC_SLOWPOISON].timer == -1) - battle_damage(NULL, bl, sc->data[type].val4, 1); + battle_damage(NULL, bl, sc->data[type].val4, 0, 1); if (sc->data[type].val3 > 0 && !status_isdead(bl)) { sc->data[type].timer = add_timer (1000 + tick, status_change_timer, bl->id, data ); @@ -5483,7 +5483,7 @@ int status_change_timer(int tid, unsigned int tick, int id, int data) // To-do: bleeding effect increases damage taken? if ((sc->data[type].val4 -= 10000) >= 0) { int hp = rand()%600 + 200; - battle_damage(NULL,bl,hp,0); + battle_damage(NULL,bl,hp,0,0); if (!status_isdead(bl)) sc->data[type].timer = add_timer(10000 + tick, status_change_timer, bl->id, data ); return 0; @@ -5651,7 +5651,7 @@ int status_change_timer(int tid, unsigned int tick, int id, int data) { if (sd) pc_damage_sp(sd, sp, 0); - battle_damage(NULL, bl, hp, 1); + battle_damage(NULL, bl, hp, 0, 1); if ((sc->data[type].val2 -= 10000) > 0) { sc->data[type].timer = add_timer( 10000+tick, status_change_timer, diff --git a/src/map/unit.c b/src/map/unit.c index a38d4bab4..599ed6a3e 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -642,45 +642,10 @@ int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int return 1; } -static int unit_walkdelay_sub(int tid, unsigned int tick, int id, int data) -{ - struct block_list *bl = map_id2bl(id); - if (!bl || status_isdead(bl)) - return 0; - - unit_set_walkdelay(bl, tick, data, 0); - return 0; -} - /*========================================== * Applies walk delay based on attack type. [Skotlex] *------------------------------------------ */ -int unit_walkdelay(struct block_list *bl, unsigned int tick, int adelay, int delay, int div_) { - - if (status_isdead(bl)) - return 0; - - if (bl->type == BL_PC) { - if (battle_config.pc_walk_delay_rate != 100) - delay = delay*battle_config.pc_walk_delay_rate/100; - } else - if (battle_config.walk_delay_rate != 100) - delay = delay*battle_config.walk_delay_rate/100; - - if (div_ > 1) //Multi-hit skills mean higher delays. - delay += battle_config.multihit_delay*(div_-1); - - if (delay <= 0) - return 0; - - if (adelay > 0) - add_timer(tick+adelay, unit_walkdelay_sub, bl->id, delay); - else - unit_set_walkdelay(bl, tick, delay, 0); - return 1; -} - int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int skill_lv, int casttime, int castcancel) { struct unit_data *ud; @@ -1373,7 +1338,6 @@ int unit_skillcastcancel(struct block_list *bl,int type) // unit_data の初期化処理 void unit_dataset(struct block_list *bl) { struct unit_data *ud; - int i; nullpo_retv(ud = unit_bl2ud(bl)); memset( ud, 0, sizeof( struct unit_data) ); @@ -1413,14 +1377,12 @@ static int unit_counttargeted_sub(struct block_list *bl, va_list ap) */ int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2) { - nullpo_retr(0, target); if(damage+damage2 <= 0) return 0; - clif_damage(target,target,tick,sdelay,ddelay,damage,div,type,damage2); - return battle_damage(src,target,damage+damage2,0); + return battle_damage(src,target,damage+damage2,clif_damage(target,target,tick,sdelay,ddelay,damage,div,type,damage2),0); } /*========================================== * 自分をロックしている対象の数を返す @@ -1484,7 +1446,7 @@ int unit_remove_map(struct block_list *bl, int clrtype) { map_freeblock_lock(); - unit_stop_walking(bl,1); // 歩行中断 + unit_stop_walking(bl,0); // 歩行中断 unit_stop_attack(bl); // 攻撃中断 unit_skillcastcancel(bl,0); // 詠唱中断 clif_clearchar_area(bl,clrtype); @@ -1760,7 +1722,6 @@ int unit_free(struct block_list *bl) { int do_init_unit(void) { add_timer_func_list(unit_attack_timer, "unit_attack_timer"); add_timer_func_list(unit_walktoxy_timer,"unit_walktoxy_timer"); - add_timer_func_list(unit_walkdelay_sub, "unit_walkdelay_sub"); add_timer_func_list(unit_walktobl_sub, "unit_walktobl_sub"); return 0; diff --git a/src/map/unit.h b/src/map/unit.h index f3c0c87c9..09eaafc30 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -22,8 +22,6 @@ int unit_stop_walking(struct block_list *bl,int type); int unit_can_move(struct block_list *bl); int unit_is_walking(struct block_list *bl); int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int type); -int unit_walkdelay(struct block_list *bl, unsigned int tick, int adelay, int delay, int div_); - // 位置の強制移動(吹き飛ばしなど) int unit_movepos(struct block_list *bl,int dst_x,int dst_y, int easy, int checkpath); -- cgit v1.2.3-70-g09d2 From 3cf706a09c00cf3ceee18a1a26446e3edafdbbec Mon Sep 17 00:00:00 2001 From: skotlex Date: Thu, 13 Apr 2006 00:45:55 +0000 Subject: - Changed slave chasing from using unit_walktobl to map_search_freecell + unit_walktoxy, since the previous behaviour makes all slaves always end up on the same cell. - Changed some function declarations to take x,y arguments as short rather than int. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@6024 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 3 +++ src/map/map.c | 2 +- src/map/map.h | 2 +- src/map/mob.c | 16 +++++++++------- src/map/mob.h | 2 +- src/map/skill.c | 4 ++-- src/map/unit.c | 2 +- src/map/unit.h | 2 +- 8 files changed, 19 insertions(+), 14 deletions(-) (limited to 'src/map/unit.h') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index f7bb34654..dd4ea28c5 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -4,6 +4,9 @@ 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. 2006/04/12 + * Changed slave chasing from using unit_walktobl to map_search_freecell + + unit_walktoxy, since the previous behaviour makes all slaves always end up + on the same cell. [Skotlex] * Removed area of effect of Assumptio. [Skotlex] * Added "can't act" delay update when an auto-spell triggers. [Skotlex] * Expanded the warp warning so that it also warns when a warps takes you to diff --git a/src/map/map.c b/src/map/map.c index bfe0f777f..a1a517ec8 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -1380,7 +1380,7 @@ static int map_count_sub(struct block_list *bl,va_list ap) * &4 = there shouldn't be any players around the target tile (use the no_spawn_on_player setting) *------------------------------------------ */ -int map_search_freecell(struct block_list *src, int m, int *x,int *y, int rx, int ry, int flag) { +int map_search_freecell(struct block_list *src, int m, short *x,short *y, int rx, int ry, int flag) { int tries, spawn=0; int bx, by; int rx2 = 2*rx+1; diff --git a/src/map/map.h b/src/map/map.h index 0fa350f8b..83c3f3cdb 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -1248,7 +1248,7 @@ int map_addobject(struct block_list *); int map_delobject(int); int map_delobjectnofree(int id); void map_foreachobject(int (*)(struct block_list*,va_list),int,...); -int map_search_freecell(struct block_list *src, int m, int *x,int *y, int rx, int ry, int flag); +int map_search_freecell(struct block_list *src, int m, short *x, short *y, int rx, int ry, int flag); // int map_quit(struct map_session_data *); // npc diff --git a/src/map/mob.c b/src/map/mob.c index f7e007bdd..8e28ff6bf 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -256,7 +256,7 @@ int mob_get_random_id(int type, int flag, int lv) { *------------------------------------------ */ int mob_once_spawn (struct map_session_data *sd, char *mapname, - int x, int y, const char *mobname, int class_, int amount, const char *event) + short x, short y, const char *mobname, int class_, int amount, const char *event) { struct mob_data *md = NULL; struct spawn_data data; @@ -633,7 +633,7 @@ int mob_spawn (struct mob_data *md) if ((md->spawn->x == 0 && md->spawn->y == 0) || md->spawn->xs || md->spawn->ys) { //Monster can be spawned on an area. - int x, y, xs, ys; + short x, y, xs, ys; if (md->spawn->x == 0 && md->spawn->y == 0) xs = ys = -1; else { @@ -917,9 +917,11 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick) (md->master_dist>MOB_SLAVEDISTANCE || md->master_dist == 0) && unit_can_move(&md->bl)) { + short x = bl->x, y = bl->y; mob_stop_attack(md); - unit_walktobl(&md->bl, bl, MOB_SLAVEDISTANCE, 0); - } + if (map_search_freecell(&md->bl, bl->m, &x, &y, MOB_SLAVEDISTANCE, MOB_SLAVEDISTANCE, 1)) + unit_walktoxy(&md->bl, x, y, 0); + } } else if (bl->m != md->bl.m && map_flag_gvg(md->bl.m)) { //Delete the summoned mob if it's in a gvg ground and the master is elsewhere. [Skotlex] if(md->special_state.ai>0) @@ -2305,7 +2307,7 @@ int mob_warpslave_sub(struct block_list *bl,va_list ap) { struct mob_data *md=(struct mob_data *)bl; struct block_list *master; - int x,y,range=0; + short x,y,range=0; master = va_arg(ap, struct block_list*); range = va_arg(ap, int); @@ -2388,7 +2390,7 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,int skill_id) amount+=k; //Increase final value by same amount to preserve total number to summon. } for(;kskill_id) { case RG_INTIMIDATE: if (unit_warp(src,-1,-1,-1,3) == 0) { - int x,y; + short x,y; map_search_freecell(src, 0, &x, &y, 1, 1, 0); if (!status_isdead(target)) unit_warp(target, -1, x, y, 3); @@ -6003,7 +6003,7 @@ int skill_castend_pos2( struct block_list *src, int x,int y,int skillid,int skil case WZ_METEOR: //?テオスト?ム { int flag=0, area = skill_get_splash(skillid, skilllv); - int tmpx, tmpy, x1 = 0, y1 = 0; + short tmpx, tmpy, x1 = 0, y1 = 0; if (sc && sc->data[SC_MAGICPOWER].timer != -1) flag = flag|2; //Store the magic power flag for future use. [Skotlex] for(i=0;i<2+(skilllv>>1);i++) { diff --git a/src/map/unit.c b/src/map/unit.c index 599ed6a3e..a24cfc723 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -423,7 +423,7 @@ int unit_getdir(struct block_list *bl) //Warps a unit/ud to a given map/position. //In the case of players, pc_setpos is used. //it respects the no warp flags, so it is safe to call this without doing nowarpto/nowarp checks. -int unit_warp(struct block_list *bl,int m,int x,int y,int type) +int unit_warp(struct block_list *bl,int m,short x,short y,int type) { struct unit_data *ud; nullpo_retr(0, bl); diff --git a/src/map/unit.h b/src/map/unit.h index 09eaafc30..5c4466351 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -25,7 +25,7 @@ int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int // 位置の強制移動(吹き飛ばしなど) int unit_movepos(struct block_list *bl,int dst_x,int dst_y, int easy, int checkpath); -int unit_warp(struct block_list *bl, int map, int x, int y, int type); +int unit_warp(struct block_list *bl, int map, short x, short y, int type); int unit_setdir(struct block_list *bl,unsigned char dir); int unit_getdir(struct block_list *bl); -- cgit v1.2.3-70-g09d2 From 14eabce08792bbf83b2f8001d3b341a6fe9dfb67 Mon Sep 17 00:00:00 2001 From: skotlex Date: Mon, 17 Apr 2006 18:12:06 +0000 Subject: - Added state.running to unit_data to make it easier to check for running characters (saves having to get the sc data and check for the corresponding timer all the time) - removed pc_run, pc_walktodir, replaced with unit_run. - moved the code that makes you walk that extra cell to unit_stop_walking, which is now invoked before resetting the walk-target. - Flag &2 in unit_stop_walking is now to make the character force-move that extra tile if the walkpath pos is 0 at hit time. - Added variable walk_count to unit_data to be use as a counter for cells walked for walk-triggered skills (walk path_pos is not good enough since it keeps resetting each time the walk path is updated) - Increased WALK_SKILL_INTERVAL to 5 (it is the closest value that makes the average mob trigger a chase skill every second) git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@6137 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 7 ++++ src/map/map.h | 2 + src/map/mob.c | 4 +- src/map/pc.c | 70 --------------------------------- src/map/pc.h | 2 - src/map/skill.h | 2 +- src/map/status.c | 17 ++++++-- src/map/unit.c | 111 ++++++++++++++++++++++++++++++++-------------------- src/map/unit.h | 1 + 9 files changed, 95 insertions(+), 121 deletions(-) (limited to 'src/map/unit.h') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index cf01951ad..accbe46a3 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -4,6 +4,13 @@ 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. 2006/04/17 + * Some cleanup in the TK_RUN related code. [Skotlex] + * Added variable walk_count to unit_data to be use as a counter for cells + walked for walk-triggered skills, on-chase skill triggers are now done + every 5 cells (it is the closest value that makes the average mob trigger a + chase skill every second). [Skotlex] + * mob_skill_db needs updating since it's current use rates for chase-skills + assume the trigger is every 100ms rather than every second. * Fixed TK_RUN having a cast-bar when attempting to stop-running and generating timer_delete errors when halting as well. [Skotlex] * Clearing the dummy npc after fooling the client. [Lance] diff --git a/src/map/map.h b/src/map/map.h index 83c3f3cdb..b2e194fc4 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -365,11 +365,13 @@ struct unit_data { unsigned int canact_tick; unsigned int canmove_tick; unsigned char dir; + unsigned char walk_count; struct { unsigned change_walk_target : 1 ; unsigned skillcastcancel : 1 ; unsigned attack_continue : 1 ; unsigned walk_easy : 1 ; + unsigned running : 1; } state; }; diff --git a/src/map/mob.c b/src/map/mob.c index 8e28ff6bf..5889903ed 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -1049,7 +1049,7 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap) return 0; if( md->ud.walktimer != -1 && md->ud.walkpath.path_pos <= 3) - return 0; //Prevent ai when it just started walking. + return 0; // Abnormalities if((md->sc.opt1 > 0 && md->sc.opt1 != OPT1_STONEWAIT) || md->sc.data[SC_BLADESTOP].timer != -1) @@ -1077,7 +1077,7 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap) ((struct map_session_data*)tbl)->state.gangsterparadise )) { //Unlock current target. if (battle_config.mob_ai&8) //Inmediately stop chasing. - mob_stop_walking(md,2); + mob_stop_walking(md,1); mob_unlocktarget(md, tick-(battle_config.mob_ai&8?3000:0)); //Imediately do random walk. tbl = NULL; } diff --git a/src/map/pc.c b/src/map/pc.c index 2dcb11a63..c8195eec5 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -52,9 +52,6 @@ struct skill_tree_entry skill_tree[MAX_PC_CLASS][MAX_SKILL_TREE]; int day_timer_tid; int night_timer_tid; -static int dirx[8]={0,-1,-1,-1,0,1,1,1}; -static int diry[8]={1,1,0,-1,-1,-1,0,1}; - struct fame_list smith_fame_list[MAX_FAME_LIST]; struct fame_list chemist_fame_list[MAX_FAME_LIST]; struct fame_list taekwon_fame_list[MAX_FAME_LIST]; @@ -3177,73 +3174,6 @@ int pc_memo(struct map_session_data *sd, int i) { return 1; } -/*========================================== - * pc駆け足要求 - *------------------------------------------ - */ -int pc_run(struct map_session_data *sd, int skilllv, int dir) -{ - int i,to_x,to_y,dir_x,dir_y; - - nullpo_retr(0, sd); - - if (!unit_can_move(&sd->bl)) { - if(sd->sc.data[SC_RUN].timer!=-1) - status_change_end(&sd->bl,SC_RUN,-1); - return 0; - } - - to_x = sd->bl.x; - to_y = sd->bl.y; - dir_x = dirx[dir]; - dir_y = diry[dir]; - - for(i=0;ibl.m,to_x+dir_x,to_y+dir_y,CELL_CHKPASS)) - break; - - to_x += dir_x; - to_y += dir_y; - } - - //進めない場合 駆け足終了 障害物で止まった場合スパート状態解除 - if(to_x == sd->bl.x && to_y == sd->bl.y){ - if(sd->sc.data[SC_RUN].timer!=-1) - status_change_end(&sd->bl,SC_RUN,-1); - return 0; - } - unit_walktoxy(&sd->bl, to_x, to_y, 1); - return 1; -} -/*========================================== - * PCの向居ているほうにstep分歩く - *------------------------------------------ - */ -int pc_walktodir(struct map_session_data *sd,int step) -{ - int i,to_x,to_y,dir_x,dir_y; - - nullpo_retr(0, sd); - - to_x = sd->bl.x; - to_y = sd->bl.y; - dir_x = dirx[(int)sd->ud.dir]; - dir_y = diry[(int)sd->ud.dir]; - - for(i=0;ibl.m,to_x+dir_x,to_y+dir_y,CELL_CHKNOPASS)) - break; - - to_x += dir_x; - to_y += dir_y; - } - unit_walktoxy(&sd->bl, to_x, to_y, 1); - - return 1; -} - // // 武器?? // diff --git a/src/map/pc.h b/src/map/pc.h index 72a3a1f18..33e8eaef0 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -245,8 +245,6 @@ void pc_addfame(struct map_session_data *sd,int count); int pc_istop10fame(int char_id, int job); int pc_eventtimer(int tid,unsigned int tick,int id,int data); // for npc_dequeue -int pc_run(struct map_session_data *sd, int skilllv, int dir); - extern struct fame_list smith_fame_list[MAX_FAME_LIST]; extern struct fame_list chemist_fame_list[MAX_FAME_LIST]; extern struct fame_list taekwon_fame_list[MAX_FAME_LIST]; diff --git a/src/map/skill.h b/src/map/skill.h index 2ba25b937..054cd1c71 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -42,7 +42,7 @@ #define INF2_GUILD_ONLY 2048 //Walk intervals at which chase-skills are attempted to be triggered. -#define WALK_SKILL_INTERVAL 2 +#define WALK_SKILL_INTERVAL 5 // スキルデ?タベ?ス struct skill_db { diff --git a/src/map/status.c b/src/map/status.c index 9b7ed47f0..2cfbbaf89 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -4758,8 +4758,12 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val clif_updatestatus(sd,updateflag); /* ステ?タスをクライアントに送る */ if (sd->pd) pet_sc_check(sd, type); //Skotlex: Pet Status Effect Healing - if (type==SC_RUN) - pc_run(sd,val1,val2); + } + + if (type==SC_RUN) { + struct unit_data *ud = unit_bl2ud(bl); + if (ud) + ud->state.running = unit_run(bl); } return 1; } @@ -4961,13 +4965,20 @@ int status_change_end( struct block_list* bl , int type,int tid ) } break; case SC_RUN://駆け足 - unit_stop_walking(bl,1); + { + struct unit_data *ud = unit_bl2ud(bl); + if (ud) { + ud->state.running = 0; + if (ud->walktimer != -1) + unit_stop_walking(bl,1); + } if (sc->data[type].val1 >= 7 && DIFF_TICK(gettick(), sc->data[type].val4) <= 1000 && (!sd || (sd->weapontype1 == 0 && sd->weapontype2 == 0)) ) sc_start(bl,SC_SPURT,100,sc->data[type].val1,skill_get_time2(StatusSkillChangeTable[type], sc->data[type].val1)); calc_flag = 1; + } break; case SC_AUTOBERSERK: if (sc->data[SC_PROVOKE].timer != -1 && sc->data[SC_PROVOKE].val2 == 1) diff --git a/src/map/unit.c b/src/map/unit.c index f1c61c934..c8e3738b6 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -85,8 +85,8 @@ int unit_walktoxy_sub(struct block_list *bl) i = status_get_speed(bl)*14/10; else i = status_get_speed(bl); - if( i > 0) //First time data is sent as 0 to always enable moving one tile when hit. - ud->walktimer = add_timer(gettick()+i,unit_walktoxy_timer,bl->id,0); + if( i > 0) + ud->walktimer = add_timer(gettick()+i,unit_walktoxy_timer,bl->id,i); return 1; } @@ -153,6 +153,7 @@ static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data) x += dx; y += dy; map_moveblock(bl, x, y, tick); + ud->walk_count++; //walked cell counter, to be used for walk-triggered skills. [Skotlex] ud->walktimer = 1; map_foreachinmovearea(clif_insight,bl->m, @@ -182,7 +183,7 @@ static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data) if ( (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR && sd->sc.data[SC_MIRACLE].timer==-1 && - ud->walkpath.path_pos && ud->walkpath.path_pos%WALK_SKILL_INTERVAL == 0 && + !(ud->walk_count%WALK_SKILL_INTERVAL) && rand()%10000 < battle_config.sg_miracle_skill_ratio ) { //SG_MIRACLE [Komurka] clif_displaymessage(sd->fd,"[Miracle of the Sun, Moon and Stars]"); @@ -191,7 +192,7 @@ static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data) } else if (md) { if (ud->target && ud->state.attack_continue) { if(md->min_chase > md->db->range2) md->min_chase--; - if(ud->walkpath.path_pos && ud->walkpath.path_pos%WALK_SKILL_INTERVAL == 0 && + if(!(ud->walk_count%WALK_SKILL_INTERVAL) && mobskill_use(md, tick, -1)) return 0; } @@ -210,9 +211,11 @@ static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data) if(i > 0) ud->walktimer = add_timer(tick+i,unit_walktoxy_timer,id,i); - else if(sd && sd->sc.count && sd->sc.data[SC_RUN].timer!=-1) //Keep trying to run. - pc_run(sd, sd->sc.data[SC_RUN].val1, sd->sc.data[SC_RUN].val2); - else if (ud->target) { + else if(ud->state.running) { + //Keep trying to run. + if (!unit_run(bl)) + ud->state.running = 0; + } else if (ud->target) { //Update target trajectory. struct block_list *tbl = map_id2bl(ud->target); if (!tbl) { //Cancel chase. @@ -329,6 +332,41 @@ int unit_walktobl(struct block_list *bl, struct block_list *tbl, int range, int return unit_walktoxy_sub(bl); } +int unit_run(struct block_list *bl) +{ + struct status_change *sc = status_get_sc(bl); + int i,to_x,to_y,dir_x,dir_y; + + if (!sc || !sc->count || sc->data[SC_RUN].timer == -1) + return 0; + + if (!unit_can_move(bl)) { + if(sc->data[SC_RUN].timer!=-1) + status_change_end(bl,SC_RUN,-1); + return 0; + } + + to_x = bl->x; + to_y = bl->y; + dir_x = dirx[sc->data[SC_RUN].val2]; + dir_y = diry[sc->data[SC_RUN].val2]; + + for(i=0;im,to_x+dir_x,to_y+dir_y,CELL_CHKPASS)) + break; + to_x += dir_x; + to_y += dir_y; + } + + if(to_x == bl->x && to_y == bl->y) { + status_change_end(bl,SC_RUN,-1); + return 0; + } + unit_walktoxy(bl, to_x, to_y, 1); + return 1; +} + //Instant warp function. int unit_movepos(struct block_list *bl,int dst_x,int dst_y, int easy, int checkpath) { @@ -495,42 +533,42 @@ int unit_warp(struct block_list *bl,int m,short x,short y,int type) */ int unit_stop_walking(struct block_list *bl,int type) { - struct unit_data *ud; - struct status_change *sc; + struct unit_data *ud; + struct TimerData *data; + unsigned int tick; nullpo_retr(0, bl); ud = unit_bl2ud(bl); if(!ud || ud->walktimer == -1) return 0; + //NOTE: We are using timer data after deleting it because we know the + //delete_timer function does not messes with it. If the function's + //behaviour changes in the future, this code could break! + data = get_timer(ud->walktimer); + delete_timer(ud->walktimer, unit_walktoxy_timer); + ud->walktimer = -1; + ud->state.change_walk_target = 0; + tick = gettick(); + if ((type&0x02 && !ud->walkpath.path_pos) //Force moving at least one cell. + || (data && DIFF_TICK(data->tick, tick) <= data->data/2)) //Enough time has passed to cover half-cell + { + ud->walkpath.path_len = ud->walkpath.path_pos+1; + unit_walktoxy_timer(-1, tick, bl->id, ud->walkpath.path_pos); + } // if(md) { md->state.skillstate = MSS_IDLE; } - if(type&0x01) // 位置補正送信が必要 + if(type&0x01) clif_fixpos(bl); - if(type&0x02 && unit_can_move(bl)) { - int dx=ud->to_x-bl->x; - int dy=ud->to_y-bl->y; - if(dx<0) dx=-1; else if(dx>0) dx=1; - if(dy<0) dy=-1; else if(dy>0) dy=1; - if(dx || dy) { - return unit_walktoxy( bl, bl->x+dx, bl->y+dy, 1); - } - } - ud->walkpath.path_len = 0; ud->walkpath.path_pos = 0; ud->to_x = bl->x; ud->to_y = bl->y; - delete_timer(ud->walktimer, unit_walktoxy_timer); - ud->walktimer = -1; - if(bl->type == BL_PET) { - if(type&~0xff) - ud->canmove_tick = gettick() + (type>>8); - } - sc = status_get_sc(bl); - if (sc && sc->count && sc->data[SC_RUN].timer != -1) - status_change_end(bl, SC_RUN, -1); + if(bl->type == BL_PET && type&~0xff) + ud->canmove_tick = gettick() + (type>>8); + if (ud->state.running) + status_change_end(bl, SC_RUN, -1); return 1; } @@ -631,20 +669,7 @@ int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int ud->canmove_tick = tick + delay; if (ud->walktimer != -1) { //Stop walking, if chasing, readjust timers. - struct TimerData *data = get_timer(ud->walktimer); - //NOTE: We are using timer data after deleting it because we know the - //delete_timer function does not messes with it. If the function's - //behaviour changes in the future, this code could break! - delete_timer(ud->walktimer, unit_walktoxy_timer); - ud->walktimer = -1; - ud->state.change_walk_target = 0; - if (data && (!data->data || DIFF_TICK(data->tick, tick) <= data->data/2)) - { //Enough time has elapsed to allow for one more tile, - //Or this is the first iteration of the walk - ud->walkpath.path_len = ud->walkpath.path_pos+1; - unit_walktoxy_timer(-1, tick, bl->id, ud->walkpath.path_pos); - } - clif_fixpos(bl); + unit_stop_walking(bl,3); if(ud->target) add_timer(ud->canmove_tick+1, unit_walktobl_sub, bl->id, ud->target); } diff --git a/src/map/unit.h b/src/map/unit.h index 5c4466351..8fc0343bc 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -12,6 +12,7 @@ // 戻り値は、0 ( 成功 ), 1 ( 失敗 ) int unit_walktoxy( struct block_list *bl, int x, int y, int easy); int unit_walktobl( struct block_list *bl, struct block_list *target, int range, int easy); +int unit_run(struct block_list *bl); // 歩行停止 // typeは以下の組み合わせ : -- cgit v1.2.3-70-g09d2 From aacfd6194a76acc9a322ebdd8379472402158d83 Mon Sep 17 00:00:00 2001 From: skotlex Date: Tue, 20 Jun 2006 22:50:33 +0000 Subject: - Corrected the line terminator setting on the unit.* files as pointed out by Irmin git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@7268 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/unit.c | 3470 ++++++++++++++++++++++++++++---------------------------- src/map/unit.h | 140 +-- 2 files changed, 1805 insertions(+), 1805 deletions(-) (limited to 'src/map/unit.h') diff --git a/src/map/unit.c b/src/map/unit.c index 8dd38f5ea..a4534f766 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1,1735 +1,1735 @@ -// Copyright (c) jAthena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder -// Merged originally from jA by Skotlex -#include -#include -#include - -#include "../common/showmsg.h" -#include "../common/timer.h" -#include "../common/nullpo.h" -#include "../common/db.h" -#include "../common/malloc.h" -#include "unit.h" -#include "map.h" -#include "pc.h" -#include "mob.h" -#include "pet.h" -#include "skill.h" -#include "clif.h" -#include "npc.h" -#include "guild.h" -#include "status.h" -#include "battle.h" -#include "chat.h" -#include "trade.h" -#include "vending.h" -#include "party.h" -#include "intif.h" -#include "chrif.h" -#include "script.h" - -static int dirx[8]={0,-1,-1,-1,0,1,1,1}; -static int diry[8]={1,1,0,-1,-1,-1,0,1}; - -struct unit_data* unit_bl2ud(struct block_list *bl) { - if( bl == NULL) return NULL; - if( bl->type == BL_PC) return &((struct map_session_data*)bl)->ud; - if( bl->type == BL_MOB) return &((struct mob_data*)bl)->ud; - if( bl->type == BL_PET) return &((struct pet_data*)bl)->ud; - if( bl->type == BL_NPC) return &((struct npc_data*)bl)->ud; - return NULL; -} - -static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data); - -int unit_walktoxy_sub(struct block_list *bl) -{ - int i; - struct walkpath_data wpd; - struct unit_data *ud = NULL; - - nullpo_retr(1, bl); - ud = unit_bl2ud(bl); - if(ud == NULL) return 0; - - if(path_search(&wpd,bl->m,bl->x,bl->y,ud->to_x,ud->to_y,ud->state.walk_easy)) - return 0; - - memcpy(&ud->walkpath,&wpd,sizeof(wpd)); - - if (ud->target && ud->chaserange>1) { - //Generally speaking, the walk path is already to an adjacent tile - //so we only need to shorten the path if the range is greater than 1. - int dir; - //Trim the last part of the path to account for range, - //but always move at least one cell when requested to move. - for (i = ud->chaserange*10; i > 0 && ud->walkpath.path_len>1;) { - ud->walkpath.path_len--; - dir = ud->walkpath.path[ud->walkpath.path_len]; - if(dir&1) - i-=14; - else - i-=10; - ud->to_x -= dirx[dir]; - ud->to_y -= diry[dir]; - } - } - - ud->state.change_walk_target=0; - - if (bl->type == BL_PC) - clif_walkok((TBL_PC*)bl); - clif_move(bl); - - if(ud->walkpath.path_pos>=ud->walkpath.path_len) - i = -1; - else if(ud->walkpath.path[ud->walkpath.path_pos]&1) - i = status_get_speed(bl)*14/10; - else - i = status_get_speed(bl); - if( i > 0) - ud->walktimer = add_timer(gettick()+i,unit_walktoxy_timer,bl->id,i); - return 1; -} - -static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data) -{ - int i; - int x,y,dx,dy,dir; - struct block_list *bl; - struct map_session_data *sd = NULL; - struct mob_data *md = NULL; - struct unit_data *ud = NULL; - - bl=map_id2bl(id); - if(bl == NULL) - return 0; - if( BL_CAST( BL_PC, bl, sd ) ) { - ud = &sd->ud; - } else if( BL_CAST( BL_MOB, bl, md ) ) { - ud = &md->ud; - } else - ud = unit_bl2ud(bl); - - if(ud == NULL) return 0; - - if(ud->walktimer != tid){ - if(battle_config.error_log) - ShowError("unit_walk_timer mismatch %d != %d\n",ud->walktimer,tid); - return 0; - } - ud->walktimer=-1; - if( bl->prev == NULL ) return 0; // block_list から抜けているので移動停止する - - if(ud->walkpath.path_pos>=ud->walkpath.path_len) - return 0; - - //歩いたので息吹のタイマーを初期化 - if(sd) { - sd->inchealspirithptick = 0; - sd->inchealspiritsptick = 0; - } - - if(ud->walkpath.path[ud->walkpath.path_pos]>=8) - return 1; - x = bl->x; - y = bl->y; - - dir = ud->walkpath.path[ud->walkpath.path_pos]; - ud->dir = dir; - if (sd) - sd->head_dir = dir; - - dx = dirx[(int)dir]; - dy = diry[(int)dir]; - - if(map_getcell(bl->m,x+dx,y+dy,CELL_CHKNOPASS)) - return unit_walktoxy_sub(bl); - - // バシリカ判定 - - map_foreachinmovearea(clif_outsight,bl->m, - x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE, - dx,dy,sd?BL_ALL:BL_PC,bl); - - x += dx; - y += dy; - map_moveblock(bl, x, y, tick); - ud->walk_count++; //walked cell counter, to be used for walk-triggered skills. [Skotlex] - - ud->walktimer = 1; - map_foreachinmovearea(clif_insight,bl->m, - x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE, - -dx,-dy,sd?BL_ALL:BL_PC,bl); - ud->walktimer = -1; - - if(sd) { - if(map_getcell(bl->m,x,y,CELL_CHKNPC)) { - npc_touch_areanpc(sd,bl->m,x,y); - if (bl->prev == NULL) //Script could have warped char, abort remaining of the function. - return 0; - } else - sd->areanpc_id=0; - if (sd->state.gmaster_flag) - { //Guild Aura: Likely needs to be recoded, this method seems inefficient. - struct guild *g = sd->state.gmaster_flag; - int skill, guildflag = 0; - if ((skill = guild_checkskill(g, GD_LEADERSHIP)) > 0) guildflag |= skill<<12; - if ((skill = guild_checkskill(g, GD_GLORYWOUNDS)) > 0) guildflag |= skill<<8; - if ((skill = guild_checkskill(g, GD_SOULCOLD)) > 0) guildflag |= skill<<4; - if ((skill = guild_checkskill(g, GD_HAWKEYES)) > 0) guildflag |= skill; - if (guildflag) - map_foreachinrange(skill_guildaura_sub, bl,2, BL_PC, - bl->id, sd->status.guild_id, &guildflag); - } - if ( - (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR && - sd->sc.data[SC_MIRACLE].timer==-1 && - !(ud->walk_count%WALK_SKILL_INTERVAL) && - rand()%10000 < battle_config.sg_miracle_skill_ratio - ) { //SG_MIRACLE [Komurka] - clif_displaymessage(sd->fd,"[Miracle of the Sun, Moon and Stars]"); - sc_start(&sd->bl,SC_MIRACLE,100,1,battle_config.sg_miracle_skill_duration); - } - } else if (md) { - if(battle_config.mob_npc_warp && map_getcell(bl->m,x,y,CELL_CHKNPC) && - npc_touch_areanpc2(bl)) // Enable mobs to step on warps. [Skotlex] - return 0; - if (md->min_chase > md->db->range2) md->min_chase--; - //Walk skills are triggered regardless of target due to the idle-walk mob state. - if(!(ud->walk_count%WALK_SKILL_INTERVAL) && - mobskill_use(md, tick, -1)) - return 0; - } - - if(tid == -1) //A directly invoked timer is from battle_stop_walking, therefore the rest is irrelevant. - return 0; - - if(ud->state.change_walk_target) - return unit_walktoxy_sub(bl); - - ud->walkpath.path_pos++; - if(ud->walkpath.path_pos>=ud->walkpath.path_len) - i = -1; - else if(ud->walkpath.path[ud->walkpath.path_pos]&1) - i = status_get_speed(bl)*14/10; - else - i = status_get_speed(bl); - - if(i > 0) - ud->walktimer = add_timer(tick+i,unit_walktoxy_timer,id,i); - else if(ud->state.running) { - //Keep trying to run. - if (!unit_run(bl)) - ud->state.running = 0; - } else if (ud->target) { - //Update target trajectory. - struct block_list *tbl = map_id2bl(ud->target); - if (!tbl) { //Cancel chase. - ud->to_x = bl->x; - ud->to_y = bl->y; - return 0; - } - if (tbl->m == bl->m && check_distance_bl(bl, tbl, ud->chaserange)) - { //Reached destination. - if (ud->state.attack_continue) { - clif_fixpos(bl); //Aegis uses one before every attack, we should - //only need this one for syncing purposes. [Skotlex] - unit_attack(bl, tbl->id, ud->state.attack_continue); - } - } else { //Update chase-path - unit_walktobl(bl, tbl, ud->chaserange, ud->state.walk_easy|(ud->state.attack_continue?2:0)); - return 0; - } - } else { //Stopped walking. Update to_x and to_y to current location [Skotlex] - ud->to_x = bl->x; - ud->to_y = bl->y; - if(md && md->nd) // Tell the script engine we've finished walking (for AI pathfinding) - mob_script_callback(md, NULL, CALLBACK_WALKACK); - } - return 0; -} - -int unit_walktoxy( struct block_list *bl, int x, int y, int easy) { - struct unit_data *ud = NULL; - struct status_change *sc = NULL; - - nullpo_retr(0, bl); - - ud = unit_bl2ud(bl); - - if( ud == NULL) return 0; - - // 移動出来ないユニットは弾く - if(!(status_get_mode(bl)&MD_CANMOVE) || !unit_can_move(bl)) - return 0; - - ud->state.walk_easy = easy; - ud->target = 0; - ud->to_x = x; - ud->to_y = y; - - sc = status_get_sc(bl); - if (sc && sc->count && sc->data[SC_CONFUSION].timer != -1) //Randomize the target position - map_random_dir(bl, &ud->to_x, &ud->to_y); - - if(ud->walktimer != -1) { - // 現在歩いている最中の目的地変更なのでマス目の中心に来た時に - // timer関数からunit_walktoxy_subを呼ぶようにする - ud->state.change_walk_target = 1; - return 1; - } else { - return unit_walktoxy_sub(bl); - } -} - -static int unit_walktobl_sub(int tid,unsigned int tick,int id,int data) -{ - struct block_list *bl = map_id2bl(id); - struct unit_data *ud = bl?unit_bl2ud(bl):NULL; - - if (ud && ud->walktimer == -1 && ud->target == data) - { - if (DIFF_TICK(ud->canmove_tick, tick) > 0) //Keep waiting? - add_timer(ud->canmove_tick+1, unit_walktobl_sub, id, data); - else if (unit_can_move(bl)) - unit_walktoxy_sub(bl); - } - return 0; -} - -// Chases a tbl. If the flag&1, use hard-path seek, -// if flag&2, start attacking upon arrival within range, otherwise just walk to that character. -int unit_walktobl(struct block_list *bl, struct block_list *tbl, int range, int flag) { - struct unit_data *ud = NULL; - struct status_change *sc = NULL; - nullpo_retr(0, bl); - nullpo_retr(0, tbl); - - ud = unit_bl2ud(bl); - if( ud == NULL) return 0; - - if (!(status_get_mode(bl)&MD_CANMOVE)) - return 0; - - if (!unit_can_reach_bl(bl, tbl, distance_bl(bl, tbl)+1, flag&1, &ud->to_x, &ud->to_y)) { - ud->to_x = bl->x; - ud->to_y = bl->y; - return 0; - } - - ud->state.walk_easy = flag&1; - ud->target = tbl->id; - ud->chaserange = range; //Note that if flag&2, this SHOULD be attack-range - ud->state.attack_continue = flag&2?1:0; //Chase to attack. - - sc = status_get_sc(bl); - if (sc && sc->count && sc->data[SC_CONFUSION].timer != -1) //Randomize the target position - map_random_dir(bl, &ud->to_x, &ud->to_y); - - - if(ud->walktimer != -1) { - ud->state.change_walk_target = 1; - return 1; - } - if (DIFF_TICK(ud->canmove_tick, gettick()) > 0) - { //Can't move, wait a bit before invoking the movement. - add_timer(ud->canmove_tick+1, unit_walktobl_sub, bl->id, ud->target); - return 1; - } else if (!unit_can_move(bl)) - return 0; - - return unit_walktoxy_sub(bl); -} - -int unit_run(struct block_list *bl) -{ - struct status_change *sc = status_get_sc(bl); - int i,to_x,to_y,dir_x,dir_y; - - if (!sc || !sc->count || sc->data[SC_RUN].timer == -1) - return 0; - - if (!unit_can_move(bl)) { - if(sc->data[SC_RUN].timer!=-1) - status_change_end(bl,SC_RUN,-1); - return 0; - } - - to_x = bl->x; - to_y = bl->y; - dir_x = dirx[sc->data[SC_RUN].val2]; - dir_y = diry[sc->data[SC_RUN].val2]; - - for(i=0;im,to_x+dir_x,to_y+dir_y,CELL_CHKPASS)) - break; - to_x += dir_x; - to_y += dir_y; - } - - if(to_x == bl->x && to_y == bl->y) { - //If you can't run forward, you must be next to a wall, so bounce back. [Skotlex] - status_change_end(bl,SC_RUN,-1); - skill_blown(bl,bl,skill_get_blewcount(TK_RUN,sc->data[SC_RUN].val1)|0x10000); - return 0; - } - unit_walktoxy(bl, to_x, to_y, 1); - return 1; -} - -//Instant warp function. -int unit_movepos(struct block_list *bl,int dst_x,int dst_y, int easy, int checkpath) -{ - int dx,dy,dir; - struct unit_data *ud = NULL; - struct map_session_data *sd = NULL; - struct walkpath_data wpd; - - nullpo_retr(0, bl); - if( BL_CAST( BL_PC, bl, sd ) ) { - ud = &sd->ud; - } else - ud = unit_bl2ud(bl); - - if( ud == NULL) return 0; - - unit_stop_walking(bl,1); - unit_stop_attack(bl); - - if(checkpath && (map_getcell(bl->m,dst_x,dst_y, CELL_CHKNOPASS) || path_search_real(&wpd,bl->m,bl->x,bl->y,dst_x,dst_y,easy, CELL_CHKNOREACH))) - return 0; - - dir = map_calc_dir(bl, dst_x,dst_y); - ud->dir = dir; - if(sd) sd->head_dir = dir; - - dx = dst_x - bl->x; - dy = dst_y - bl->y; - - map_foreachinmovearea(clif_outsight,bl->m, - bl->x-AREA_SIZE,bl->y-AREA_SIZE,bl->x+AREA_SIZE,bl->y+AREA_SIZE, - dx,dy,sd?BL_ALL:BL_PC,bl); - - map_moveblock(bl, dst_x, dst_y, gettick()); - - ud->walktimer = 1; - map_foreachinmovearea(clif_insight,bl->m, - bl->x-AREA_SIZE,bl->y-AREA_SIZE,bl->x+AREA_SIZE,bl->y+AREA_SIZE, - -dx,-dy,sd?BL_ALL:BL_PC,bl); - ud->walktimer = -1; - - if(sd) { - if(map_getcell(bl->m,bl->x,bl->y,CELL_CHKNPC)) { - npc_touch_areanpc(sd,bl->m,bl->x,bl->y); - if (bl->prev == NULL) //Script could have warped char, abort remaining of the function. - return 0; - } else - sd->areanpc_id=0; - if(sd->status.pet_id > 0 && sd->pd && sd->pet.intimate > 0) - { //Check if pet needs to be teleported. [Skotlex] - int flag = 0; - bl = &sd->pd->bl; //Note that bl now points to the pet! - if (!checkpath && path_search(&wpd,bl->m,bl->x,bl->y,dst_x,dst_y,0)) - flag = 1; - else if (!check_distance_bl(&sd->bl, bl, AREA_SIZE)) //Too far, teleport. - flag = 2; - if (flag) { - unit_movepos(bl,sd->bl.x,sd->bl.y, 0, 0); - clif_slide(bl,bl->x,bl->y); - } - //If you want to use bl afterwards, uncomment this: - //bl = &sd->bl; - } - } - return 1; -} - -int unit_setdir(struct block_list *bl,unsigned char dir) -{ - struct unit_data *ud; - nullpo_retr( 0, bl ); - ud = unit_bl2ud(bl); - if (!ud) return 0; - ud->dir = dir; - if (bl->type == BL_PC) - ((TBL_PC *)bl)->head_dir = dir; - clif_changed_dir(bl); - return 0; -} - -int unit_getdir(struct block_list *bl) -{ - struct unit_data *ud; - nullpo_retr( 0, bl ); - ud = unit_bl2ud(bl); - if (!ud) return 0; - return ud->dir; -} - -//Warps a unit/ud to a given map/position. -//In the case of players, pc_setpos is used. -//it respects the no warp flags, so it is safe to call this without doing nowarpto/nowarp checks. -int unit_warp(struct block_list *bl,int m,short x,short y,int type) -{ - struct unit_data *ud; - nullpo_retr(0, bl); - ud = unit_bl2ud(bl); - - if(bl->prev==NULL || !ud) - return 1; - - if (type < 0 || type == 1) - //Type 1 is invalid, since you shouldn't warp a bl with the "death" - //animation, it messes up with unit_remove_map! [Skotlex] - return 1; - - if( m<0 ) m=bl->m; - - switch (bl->type) { - case BL_MOB: - if (map[bl->m].flag.monster_noteleport) - return 1; - break; - case BL_PC: - if (map[bl->m].flag.noteleport) - return 1; - break; - } - - if (x<0 || y<0) - { //Random map position. - if (!map_search_freecell(NULL, m, &x, &y, -1, -1, 1)) { - if(battle_config.error_log) - ShowWarning("unit_warp failed. Unit Id:%d/Type:%d, target position map %d (%s) at [%d,%d]\n", bl->id, bl->type, m, map[m].name, x, y); - return 2; - - } - } else if (map_getcell(m,x,y,CELL_CHKNOREACH)) - { //Invalid target cell - if(battle_config.error_log) - ShowWarning("unit_warp: Specified non-walkable target cell: %d (%s) at [%d,%d]\n", m, map[m].name, x,y); - - if (!map_search_freecell(NULL, m, &x, &y, 4, 4, 1)) - { //Can't find a nearby cell - if(battle_config.error_log) - ShowWarning("unit_warp failed. Unit Id:%d/Type:%d, target position map %d (%s) at [%d,%d]\n", bl->id, bl->type, m, map[m].name, x, y); - return 2; - } - } - - if (bl->type == BL_PC) //Use pc_setpos - return pc_setpos((TBL_PC*)bl, map[m].index, x, y, type); - - if (!unit_remove_map(bl, type)) - return 3; - - bl->x=ud->to_x=x; - bl->y=ud->to_y=y; - bl->m=m; - - map_addblock(bl); - clif_spawn(bl); - skill_unit_move(bl,gettick(),1); - - if(bl->type == BL_MOB){ - TBL_MOB *md = (TBL_MOB *)bl; - if(md->nd) // Tell the script engine we've warped - mob_script_callback(md, NULL, CALLBACK_WARPACK); - } - return 0; -} - -/*========================================== - * 歩行停止 - *------------------------------------------ - */ -int unit_stop_walking(struct block_list *bl,int type) -{ - struct unit_data *ud; - struct TimerData *data; - unsigned int tick; - nullpo_retr(0, bl); - - ud = unit_bl2ud(bl); - if(!ud || ud->walktimer == -1) - return 0; - //NOTE: We are using timer data after deleting it because we know the - //delete_timer function does not messes with it. If the function's - //behaviour changes in the future, this code could break! - data = get_timer(ud->walktimer); - delete_timer(ud->walktimer, unit_walktoxy_timer); - ud->walktimer = -1; - ud->state.change_walk_target = 0; - tick = gettick(); - if ((type&0x02 && !ud->walkpath.path_pos) //Force moving at least one cell. - || (data && DIFF_TICK(data->tick, tick) <= data->data/2)) //Enough time has passed to cover half-cell - { - ud->walkpath.path_len = ud->walkpath.path_pos+1; - unit_walktoxy_timer(-1, tick, bl->id, ud->walkpath.path_pos); - } - - if(type&0x01) - clif_fixpos(bl); - - ud->walkpath.path_len = 0; - ud->walkpath.path_pos = 0; - ud->to_x = bl->x; - ud->to_y = bl->y; - if(bl->type == BL_PET && type&~0xff) - ud->canmove_tick = gettick() + (type>>8); - - if (ud->state.running) - status_change_end(bl, SC_RUN, -1); - return 1; -} - -int unit_skilluse_id(struct block_list *src, int target_id, int skill_num, int skill_lv) { - - if(skill_num < 0) return 0; - - return unit_skilluse_id2( - src, target_id, skill_num, skill_lv, - skill_castfix(src, skill_num, skill_lv), - skill_get_castcancel(skill_num) - ); -} - -int unit_is_walking(struct block_list *bl) -{ - struct unit_data *ud = unit_bl2ud(bl); - nullpo_retr(0, bl); - if(!ud) return 0; - return (ud->walktimer != -1); -} - -/*========================================== - * Determines if the bl can move based on status changes. [Skotlex] - *------------------------------------------ - */ -int unit_can_move(struct block_list *bl) -{ - struct map_session_data *sd; - struct unit_data *ud; - struct status_change *sc; - - nullpo_retr(0, bl); - ud = unit_bl2ud(bl); - sc = status_get_sc(bl); - BL_CAST(BL_PC, bl, sd); - - if (!ud) - return 0; - - if (ud->skilltimer != -1 && (!sd || pc_checkskill(sd, SA_FREECAST) <= 0)) - return 0; - - if (DIFF_TICK(ud->canmove_tick, gettick()) > 0) - return 0; - - if (sd && ( - pc_issit(sd) || - sd->state.blockedmove - )) - return 0; //Can't move - - if (sc) { - if (sc->opt1 > 0 && sc->opt1 != OPT1_STONEWAIT) - return 0; - - if ((sc->option & OPTION_HIDE) && (!sd || pc_checkskill(sd, RG_TUNNELDRIVE) <= 0)) - return 0; - - if (sc->count && ( - sc->data[SC_ANKLE].timer != -1 || - sc->data[SC_AUTOCOUNTER].timer !=-1 || - sc->data[SC_TRICKDEAD].timer !=-1 || - sc->data[SC_BLADESTOP].timer !=-1 || - sc->data[SC_BLADESTOP_WAIT].timer !=-1 || - sc->data[SC_SPIDERWEB].timer !=-1 || - (sc->data[SC_DANCING].timer !=-1 && ( - (sc->data[SC_DANCING].val4 && sc->data[SC_LONGING].timer == -1) || - sc->data[SC_DANCING].val1 == CG_HERMODE //cannot move while Hermod is active. - )) || - sc->data[SC_MOONLIT].timer != -1 || - (sc->data[SC_GOSPEL].timer !=-1 && sc->data[SC_GOSPEL].val4 == BCT_SELF) || // cannot move while gospel is in effect - sc->data[SC_STOP].timer != -1 || - sc->data[SC_CLOSECONFINE].timer != -1 || - sc->data[SC_CLOSECONFINE2].timer != -1 - )) - return 0; - } - return 1; -} - -/*========================================== - * Applies walk delay to character, considering that - * if type is 0, this is a damage induced delay: if previous delay is active, do not change it. - * if type is 1, this is a skill induced delay: walk-delay may only be increased, not decreased. - *------------------------------------------ - */ -int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int type) -{ - struct unit_data *ud = unit_bl2ud(bl); - if (delay <= 0 || !ud) return 0; - - if (type) { - if (DIFF_TICK(ud->canmove_tick, tick+delay) > 0) - return 0; - } else { - if (DIFF_TICK(ud->canmove_tick, tick) > 0) - return 0; - } - ud->canmove_tick = tick + delay; - if (ud->walktimer != -1) - { //Stop walking, if chasing, readjust timers. - if (delay == 1) - { //Minimal delay (walk-delay) disabled. Just stop walking. - unit_stop_walking(bl,0); - } else { - unit_stop_walking(bl,2); - if(ud->target) - add_timer(ud->canmove_tick+1, unit_walktobl_sub, bl->id, ud->target); - } - } - return 1; -} - -int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int skill_lv, int casttime, int castcancel) { - struct unit_data *ud; - struct status_data *tstatus; - struct status_change *sc; - struct map_session_data *sd = NULL; - struct block_list * target = NULL; - unsigned int tick = gettick(); - int temp; - - nullpo_retr(0, src); - if(status_isdead(src)) - return 0; // 死んでいないか - - if( BL_CAST( BL_PC, src, sd ) ) { - ud = &sd->ud; - } else - ud = unit_bl2ud(src); - - if(ud == NULL) return 0; - sc = status_get_sc(src); - if (sc && !sc->count) - sc = NULL; //Unneeded - //temp: used to signal combo-skills right now. - temp = (target_id == src->id && !(sd && sd->state.skill_flag) - && skill_get_inf(skill_num)&INF_SELF_SKILL - && skill_get_inf2(skill_num)&INF2_NO_TARGET_SELF); - if (temp) - target_id = ud->target; //Auto-select skills. [Skotlex] - - if (sd) { - //Target_id checking. - if(skillnotok(skill_num, sd)) // [MouseJstr] - return 0; - switch(skill_num) - { //Check for skills that auto-select target - case MO_CHAINCOMBO: - if (sc && sc->data[SC_BLADESTOP].timer != -1){ - if ((target=(struct block_list *)sc->data[SC_BLADESTOP].val4) == NULL) - return 0; - } - break; - case TK_JUMPKICK: - case TK_COUNTER: - case HT_POWER: - if (sc && sc->data[SC_COMBO].timer != -1 && sc->data[SC_COMBO].val1 == skill_num) - target_id = sc->data[SC_COMBO].val2; - break; - case WE_MALE: - case WE_FEMALE: - if (!sd->status.partner_id) - return 0; - target = (struct block_list*)map_charid2sd(sd->status.partner_id); - if (!target) { - clif_skill_fail(sd,skill_num,0,0); - return 0; - } - break; - } - if (target) - target_id = target->id; - } - if(!target && (target=map_id2bl(target_id)) == NULL ) - return 0; - if(src->m != target->m) - return 0; // 同じマップかどうか - if(!src->prev || !target->prev) - return 0; // map 上に存在するか - - //Normally not needed because clif.c checks for it, but the at/char/script commands don't! [Skotlex] - if(ud->skilltimer != -1 && skill_num != SA_CASTCANCEL) - return 0; - - if(skill_get_inf2(skill_num)&INF2_NO_TARGET_SELF && src->id == target_id) - return 0; - - if(!status_check_skilluse(src, target, skill_num, 0)) - return 0; - - tstatus = status_get_status_data(target); - //直前のスキル状況の記録 - if(sd) { - switch(skill_num){ - case SA_CASTCANCEL: - if(ud->skillid != skill_num){ - sd->skillid_old = ud->skillid; - sd->skilllv_old = ud->skilllv; - break; - } - case BD_ENCORE: - //Prevent using the dance skill if you no longer have the skill in your tree. - if(!sd->skillid_dance || pc_checkskill(sd,sd->skillid_dance)<=0){ - clif_skill_fail(sd,skill_num,0,0); - return 0; - } - sd->skillid_old = skill_num; - break; - case BD_LULLABY: - case BD_RICHMANKIM: - case BD_ETERNALCHAOS: - case BD_DRUMBATTLEFIELD: - case BD_RINGNIBELUNGEN: - case BD_ROKISWEIL: - case BD_INTOABYSS: - case BD_SIEGFRIED: - case CG_MOONLIT: - if (battle_config.player_skill_partner_check && - (!battle_config.gm_skilluncond || pc_isGM(sd) < battle_config.gm_skilluncond) && - (skill_check_pc_partner(sd, skill_num, &skill_lv, 1, 0) < 1) - ) { - clif_skill_fail(sd,skill_num,0,0); - return 0; - } - break; - } - if (!skill_check_condition(sd, skill_num, skill_lv, 0)) - return 0; - } - //TODO: Add type-independant skill_check_condition function. - if (src->type == BL_MOB) { - switch (skill_num) { - case NPC_SUMMONSLAVE: - case NPC_SUMMONMONSTER: - case AL_TELEPORT: - if (((TBL_MOB*)src)->master_id && ((TBL_MOB*)src)->special_state.ai) - return 0; - } - } - - if(src->id != target_id && - !battle_check_range(src,target,skill_get_range2(src, skill_num,skill_lv) - +(skill_num==RG_CLOSECONFINE?0:1))) //Close confine is exploitable thanks to this extra range "feature" of the client. [Skotlex] - return 0; - - if (!temp) //Stop attack on non-combo skills [Skotlex] - unit_stop_attack(src); - else if(ud->attacktimer != -1) //Elsewise, delay current attack sequence - ud->attackabletime = tick + status_get_adelay(src); - - ud->state.skillcastcancel = castcancel; - - //temp: Used to signal force cast now. - temp = 0; - - switch(skill_num){ - case ALL_RESURRECTION: - if(battle_check_undead(tstatus->race,tstatus->def_ele)){ - temp=1; - casttime = skill_castfix(src, PR_TURNUNDEAD, skill_lv); - } - break; - case MO_FINGEROFFENSIVE: - if(sd) - casttime += casttime * ((skill_lv > sd->spiritball)? sd->spiritball:skill_lv); - break; - case MO_EXTREMITYFIST: - if (sc && sc->data[SC_COMBO].timer != -1 && - (sc->data[SC_COMBO].val1 == MO_COMBOFINISH || - sc->data[SC_COMBO].val1 == CH_TIGERFIST || - sc->data[SC_COMBO].val1 == CH_CHAINCRUSH)) - casttime = 0; - temp = 1; - break; - case TK_RUN: - if (sc && sc->data[SC_RUN].timer != -1) - casttime = 0; - break; - case SA_MAGICROD: - case SA_SPELLBREAKER: - temp =1; - break; - case KN_CHARGEATK: - //Taken from jA: Casttime is increased by dist/3*100% - casttime = casttime * ((distance_bl(src,target)-1)/3+1); - break; - } - - if (sc && sc->data[SC_MEMORIZE].timer != -1 && casttime > 0) { - casttime = casttime/2; - if ((--sc->data[SC_MEMORIZE].val2) <= 0) - status_change_end(src, SC_MEMORIZE, -1); - } - - if( casttime>0 || temp){ - - clif_skillcasting(src, src->id, target_id, 0,0, skill_num,casttime); - - if (sd && target->type == BL_MOB) - { - TBL_MOB *md = (TBL_MOB*)target; - mobskill_event(md, src, tick, -1); //Cast targetted skill event. - //temp: used to store mob's mode now. - if (tstatus->mode&MD_CASTSENSOR && - battle_check_target(target, src, BCT_ENEMY) > 0) - { - switch (md->state.skillstate) { - case MSS_ANGRY: - case MSS_RUSH: - case MSS_FOLLOW: - if (!(tstatus->mode&(MD_AGGRESSIVE|MD_ANGRY))) - break; //Only Aggressive mobs change target while chasing. - case MSS_IDLE: - case MSS_WALK: - md->target_id = src->id; - md->state.aggressive = (temp&MD_ANGRY)?1:0; - md->min_chase = md->db->range3; - } - } - } - } - - if( casttime<=0 ) - ud->state.skillcastcancel=0; - - ud->canact_tick = tick + casttime + 100; - ud->skilltarget = target_id; - ud->skillx = 0; - ud->skilly = 0; - ud->skillid = skill_num; - ud->skilllv = skill_lv; - - if(sc && sc->data[SC_CLOAKING].timer != -1 && - !(sc->data[SC_CLOAKING].val4&1) && skill_num != AS_CLOAKING) - status_change_end(src,SC_CLOAKING,-1); - - if(casttime > 0) { - ud->skilltimer = add_timer( tick+casttime, skill_castend_id, src->id, 0 ); - if(sd && pc_checkskill(sd,SA_FREECAST)) - status_freecast_switch(sd); - else - unit_stop_walking(src,1); - } - else - skill_castend_id(ud->skilltimer,tick,src->id,0); - return 1; -} - -int unit_skilluse_pos(struct block_list *src, int skill_x, int skill_y, int skill_num, int skill_lv) { - if(skill_num < 0) - return 0; - return unit_skilluse_pos2( - src, skill_x, skill_y, skill_num, skill_lv, - skill_castfix(src, skill_num, skill_lv), - skill_get_castcancel(skill_num) - ); -} - -int unit_skilluse_pos2( struct block_list *src, int skill_x, int skill_y, int skill_num, int skill_lv, int casttime, int castcancel) { - struct map_session_data *sd = NULL; - struct unit_data *ud = NULL; - struct status_change *sc; - struct block_list bl; - unsigned int tick = gettick(); - - nullpo_retr(0, src); - - if(!src->prev) return 0; // map 上に存在するか - if(status_isdead(src)) return 0; - - if( BL_CAST( BL_PC, src, sd ) ) { - ud = &sd->ud; - } else - ud = unit_bl2ud(src); - if(ud == NULL) return 0; - - if(ud->skilltimer != -1) //Normally not needed since clif.c checks for it, but at/char/script commands don't! [Skotlex] - return 0; - - sc = status_get_sc(src); - if (sc && !sc->count) - sc = NULL; - - if(sd) { - if (skillnotok(skill_num, sd) || - !skill_check_condition(sd, skill_num, skill_lv,0)) - return 0; - } - - if (!status_check_skilluse(src, NULL, skill_num, 0)) - return 0; - - if (map_getcell(src->m, skill_x, skill_y, CELL_CHKNOREACH)) - { //prevent casting ground targeted spells on non-walkable areas. [Skotlex] - if (sd) clif_skill_fail(sd,skill_num,0,0); - return 0; - } - - /* 射程と障害物チェック */ - bl.type = BL_NUL; - bl.m = src->m; - bl.x = skill_x; - bl.y = skill_y; - if(skill_num != TK_HIGHJUMP && - !battle_check_range(src,&bl,skill_get_range2(src, skill_num,skill_lv)+1)) - return 0; - - unit_stop_attack(src); - ud->state.skillcastcancel = castcancel; - - if (sc && sc->data[SC_MEMORIZE].timer != -1 && casttime > 0){ - casttime = casttime/3; - if ((--sc->data[SC_MEMORIZE].val2)<=0) - status_change_end(src, SC_MEMORIZE, -1); - } - - if( casttime>0 ) { - unit_stop_walking( src, 1); - clif_skillcasting(src, src->id, 0, skill_x,skill_y, skill_num,casttime); - } - - if( casttime<=0 ) - ud->state.skillcastcancel=0; - - ud->canact_tick = tick + casttime + 100; - ud->skillid = skill_num; - ud->skilllv = skill_lv; - ud->skillx = skill_x; - ud->skilly = skill_y; - ud->skilltarget = 0; - - if (sc && sc->data[SC_CLOAKING].timer != -1 && - !(sc->data[SC_CLOAKING].val4&1)) - status_change_end(src,SC_CLOAKING,-1); - - if(casttime > 0) { - ud->skilltimer = add_timer( tick+casttime, skill_castend_pos, src->id, 0 ); - if(sd && pc_checkskill(sd,SA_FREECAST)) - status_freecast_switch(sd); - else - unit_stop_walking(src,1); - } - else { - ud->skilltimer = -1; - skill_castend_pos(ud->skilltimer,tick,src->id,0); - } - return 1; -} - -static int unit_attack_timer(int tid,unsigned int tick,int id,int data); - -int unit_stop_attack(struct block_list *bl) -{ - struct unit_data *ud = unit_bl2ud(bl); - nullpo_retr(0, bl); - - if(!ud || ud->attacktimer == -1) - return 0; - - delete_timer( ud->attacktimer, unit_attack_timer ); - ud->attacktimer = -1; - ud->target = 0; - return 0; -} - -//Means current target is unattackable. For now only unlocks mobs. -int unit_unattackable(struct block_list *bl) { - struct unit_data *ud = unit_bl2ud(bl); - if (ud) { - ud->target = 0; - ud->state.attack_continue = 0; - } - - if(bl->type == BL_MOB) - mob_unlocktarget((struct mob_data*)bl, gettick()) ; - else if(bl->type == BL_PET) - pet_unlocktarget((struct pet_data*)bl); - return 0; -} - -/*========================================== - * 攻撃要求 - * typeが1なら継続攻撃 - *------------------------------------------ - */ - -int unit_attack(struct block_list *src,int target_id,int type) -{ - struct block_list *target; - struct unit_data *ud; - - nullpo_retr(0, ud = unit_bl2ud(src)); - - target=map_id2bl(target_id); - if(target==NULL || status_isdead(target)) { - unit_unattackable(src); - return 1; - } - - if(src->type == BL_PC && target->type==BL_NPC) { // monster npcs [Valaris] - npc_click((TBL_PC*)src,target); // submitted by leinsirk10 [Celest] - return 0; - } - - if(battle_check_target(src,target,BCT_ENEMY)<=0 || - !status_check_skilluse(src, target, 0, 0) - ) { - unit_unattackable(src); - return 1; - } - - ud->target = target_id; - ud->state.attack_continue = type; - if (type) //If you re to attack continously, set to auto-case character - ud->chaserange = status_get_range(src); - - //Just change target/type. [Skotlex] - if(ud->attacktimer != -1) - return 0; - - if(DIFF_TICK(ud->attackabletime, gettick()) > 0) - //Do attack next time it is possible. [Skotlex] - ud->attacktimer=add_timer(ud->attackabletime,unit_attack_timer,src->id,0); - else //Attack NOW. - unit_attack_timer(-1,gettick(),src->id,0); - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int unit_can_reach_pos(struct block_list *bl,int x,int y, int easy) -{ - struct walkpath_data wpd; - - nullpo_retr(0, bl); - - if( bl->x==x && bl->y==y ) // 同じマス - return 1; - - // 障害物判定 - wpd.path_len=0; - wpd.path_pos=0; - wpd.path_half=0; - return (path_search_real(&wpd,bl->m,bl->x,bl->y,x,y,easy,CELL_CHKNOREACH)!=-1); -} - -/*========================================== - * - *------------------------------------------ - */ -int unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, int easy, short *x, short *y) -{ - struct walkpath_data wpd; - int i; - short dx,dy; - nullpo_retr(0, bl); - nullpo_retr(0, tbl); - - if( bl->m != tbl->m) - return 0; - - if( bl->x==tbl->x && bl->y==tbl->y ) - return 1; - - if(range>0 && !check_distance_bl(bl, tbl, range)) - return 0; - - wpd.path_len=0; - wpd.path_pos=0; - wpd.path_half=0; - - // It judges whether it can adjoin or not. - dx=tbl->x - bl->x; - dy=tbl->y - bl->y; - dx=(dx>0)?1:((dx<0)?-1:0); - dy=(dy>0)?1:((dy<0)?-1:0); - - if (map_getcell(tbl->m,tbl->x-dx,tbl->y-dy,CELL_CHKNOREACH)) - { //Look for a suitable cell to place in. - for(i=0;i<9 && map_getcell(tbl->m,tbl->x-dirx[i],tbl->y-diry[i],CELL_CHKNOREACH);i++); - if (i==9) return 0; //No valid cells. - dx = dirx[i]; - dy = diry[i]; - } - - if (x) *x = tbl->x-dx; - if (y) *y = tbl->y-dy; - return (path_search_real(&wpd,bl->m,bl->x,bl->y,tbl->x-dx,tbl->y-dy,easy,CELL_CHKNOREACH)!=-1); -} - - -/*========================================== - * PCの攻撃 (timer関数) - *------------------------------------------ - */ -static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int tick) -{ - struct block_list *target; - struct unit_data *ud; - struct status_data *sstatus; - struct map_session_data *sd = NULL; - struct mob_data *md = NULL; - int range; - - if((ud=unit_bl2ud(src))==NULL) - return 0; - if(ud->attacktimer != tid){ - if(battle_config.error_log) - ShowError("unit_attack_timer %d != %d\n",ud->attacktimer,tid); - return 0; - } - BL_CAST( BL_PC , src, sd); - BL_CAST( BL_MOB, src, md); - ud->attacktimer=-1; - target=map_id2bl(ud->target); - - if(src->prev == NULL || target==NULL || target->prev == NULL) - return 0; - - if(ud->skilltimer != -1 && (!sd || pc_checkskill(sd,SA_FREECAST) <= 0)) - return 0; - - if(src->m != target->m || status_isdead(src) || status_isdead(target) || !status_check_skilluse(src, target, 0, 0)) - return 0; - - sstatus = status_get_status_data(src); - - if(!battle_config.sdelay_attack_enable && - DIFF_TICK(ud->canact_tick,tick) > 0 && - (!sd || pc_checkskill(sd,SA_FREECAST) <= 0) - ) { - if (tid == -1) { //requested attack. - if(sd) clif_skill_fail(sd,1,4,0); - return 0; - } - //Otherwise, we are in a combo-attack, delay this until your canact time is over. [Skotlex] - if(ud->state.attack_continue) { - if (DIFF_TICK(ud->canact_tick, ud->attackabletime) > 0) - ud->attackabletime = ud->canact_tick; - ud->attacktimer=add_timer(ud->attackabletime,unit_attack_timer,src->id,0); - } - return 1; - } - - range = sstatus->rhw.range; - - if(!sd || sd->status.weapon != W_BOW) range++; //Dunno why everyone but bows gets this extra range... - if(unit_is_walking(target)) range++; //Extra range when chasing - - if(!check_distance_bl(src,target,range) ) { - //Chase if required. - if(ud->state.attack_continue) { - if(sd) - clif_movetoattack(sd,target); - else - unit_walktobl(src,target,ud->chaserange,ud->state.walk_easy|2); - } - return 1; - } - if(!battle_check_range(src,target,range)) { - //Within range, but no direct line of attack - if(ud->state.attack_continue) { - if(ud->chaserange > 2) ud->chaserange-=2; - unit_walktobl(src,target,ud->chaserange,ud->state.walk_easy|2); - } - return 1; - } - - //Sync packet only for players. - //Non-players use the sync packet on the walk timer. [Skotlex] - if (tid == -1 && sd) clif_fixpos(src); - - if(DIFF_TICK(ud->attackabletime,tick) <= 0) { - if (battle_config.attack_direction_change && - (src->type&battle_config.attack_direction_change)) { - ud->dir = map_calc_dir(src, target->x,target->y ); - if (sd) sd->head_dir = ud->dir; - } - if(ud->walktimer != -1) - unit_stop_walking(src,1); - if(md) { - if (mobskill_use(md,tick,-1)) - return 1; - if (sstatus->mode&MD_ASSIST && DIFF_TICK(md->last_linktime, tick) < MIN_MOBLINKTIME) - { // Link monsters nearby [Skotlex] - md->last_linktime = tick; - map_foreachinrange(mob_linksearch, src, md->db->range2, - BL_MOB, md->class_, target, tick); - } - } - if(src->type == BL_PET && pet_attackskill((TBL_PET*)src, target->id)) - return 1; - - map_freeblock_lock(); - ud->attacktarget_lv = battle_weapon_attack(src,target,tick,0); - - if(sd && sd->status.pet_id > 0 && sd->pd && battle_config.pet_attack_support) - pet_target_check(sd,target,0); - map_freeblock_unlock(); - - ud->attackabletime = tick + sstatus->adelay; -// You can't move if you can't attack neither. - unit_set_walkdelay(src, tick, sstatus->amotion, 1); - } - - if(ud->state.attack_continue) - ud->attacktimer = add_timer(ud->attackabletime,unit_attack_timer,src->id,0); - - return 1; -} - -static int unit_attack_timer(int tid,unsigned int tick,int id,int data) { - struct block_list *bl; - bl = map_id2bl(id); - if(bl && unit_attack_timer_sub(bl, tid, tick) == 0) - unit_unattackable(bl); - return 0; -} - -/*========================================== - * Cancels an ongoing skill cast. - * flag&1: Cast-Cancel invoked. - * flag&2: Cancel only if skill is cancellable. - *------------------------------------------ - */ -int unit_skillcastcancel(struct block_list *bl,int type) -{ - struct map_session_data *sd = NULL; - struct unit_data *ud = unit_bl2ud( bl); - unsigned int tick=gettick(); - int ret=0, skill; - - nullpo_retr(0, bl); - if (!ud || ud->skilltimer==-1) - return 0; //Nothing to cancel. - - BL_CAST(BL_PC, bl, sd); - - if (type&2) { - //See if it can be cancelled. - if (!ud->state.skillcastcancel) - return 0; - - if (sd && (sd->special_state.no_castcancel2 || - (sd->special_state.no_castcancel && !map_flag_gvg(bl->m)))) //fixed flags being read the wrong way around [blackhole89] - return 0; - } - - ud->canact_tick=tick; - if(sd && pc_checkskill(sd,SA_FREECAST)) - status_freecast_switch(sd); - - if(type&1 && sd) - skill = sd->skillid_old; - else - skill = ud->skillid; - - if (skill_get_inf(skill) & INF_GROUND_SKILL) - ret=delete_timer( ud->skilltimer, skill_castend_pos ); - else - ret=delete_timer( ud->skilltimer, skill_castend_id ); - if(ret<0) - ShowError("delete timer error : skillid : %d\n",ret); - - if(bl->type==BL_MOB) ((TBL_MOB*)bl)->skillidx = -1; - - ud->skilltimer = -1; - clif_skillcastcancel(bl); - return 1; -} - -// unit_data の初期化処理 -void unit_dataset(struct block_list *bl) { - struct unit_data *ud; - nullpo_retv(ud = unit_bl2ud(bl)); - - memset( ud, 0, sizeof( struct unit_data) ); - ud->bl = bl; - ud->walktimer = -1; - ud->skilltimer = -1; - ud->attacktimer = -1; - ud->attackabletime = - ud->canact_tick = - ud->canmove_tick = gettick(); -} - -/*========================================== - * 自分をロックしているユニットの数を数える(foreachclient) - *------------------------------------------ - */ -static int unit_counttargeted_sub(struct block_list *bl, va_list ap) -{ - int id, target_lv; - struct unit_data *ud; - id = va_arg(ap,int); - target_lv = va_arg(ap,int); - if(bl->id == id) - return 0; - - ud = unit_bl2ud(bl); - - if (ud && ud->target == id && ud->attacktimer != -1 && ud->attacktarget_lv >= target_lv) - return 1; - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2) -{ - nullpo_retr(0, target); - - if(damage+damage2 <= 0) - return 0; - - return status_fix_damage(src,target,damage+damage2,clif_damage(target,target,tick,sdelay,ddelay,damage,div,type,damage2)); -} -/*========================================== - * 自分をロックしている対象の数を返す - * 戻りは整数で0以上 - *------------------------------------------ - */ -int unit_counttargeted(struct block_list *bl,int target_lv) -{ - nullpo_retr(0, bl); - return (map_foreachinrange(unit_counttargeted_sub, bl, AREA_SIZE, BL_CHAR, - bl->id, target_lv)); -} - -/*========================================== - * 見た目のサイズを変更する - *------------------------------------------ - */ -int unit_changeviewsize(struct block_list *bl,short size) -{ - nullpo_retr(0, bl); - - size=(size<0)?-1:(size>0)?1:0; - - if(bl->type == BL_PC) { - ((TBL_PC*)bl)->state.size=size; - } else if(bl->type == BL_MOB) { - ((TBL_MOB*)bl)->special_state.size=size; - } else - return 0; - if(size!=0) - clif_misceffect2(bl,421+size); - return 0; -} - -/*========================================== - * Removes a bl/ud from the map. - * Returns 1 on success. 0 if it couldn't be removed or the bl was free'd - * if clrtype is 1 (death), appropiate cleanup is performed. - * Otherwise it is assumed bl is being warped. - * On-Kill specific stuff is not performed here, look at status_damage for that. - *------------------------------------------ - */ -int unit_remove_map(struct block_list *bl, int clrtype) { - struct unit_data *ud = unit_bl2ud(bl); - struct status_change *sc = status_get_sc(bl); - nullpo_retr(0, ud); - - if(bl->prev == NULL) - return 0; //Already removed? - - map_freeblock_lock(); - - ud->target = 0; //Unlock walk/attack target. - if (ud->walktimer != -1) - unit_stop_walking(bl,0); - if (ud->attacktimer != -1) - unit_stop_attack(bl); - if (ud->skilltimer != -1) - unit_skillcastcancel(bl,0); -// Do not reset can-act delay. [Skotlex] - ud->attackabletime = ud->canmove_tick /*= ud->canact_tick*/ = gettick(); - clif_clearchar_area(bl,clrtype); - - if(sc && sc->count ) { //map-change/warp dispells. - if(sc->data[SC_BLADESTOP].timer!=-1) - status_change_end(bl,SC_BLADESTOP,-1); - if(sc->data[SC_BASILICA].timer!=-1) - status_change_end(bl,SC_BASILICA,-1); - if(sc->data[SC_ANKLE].timer != -1) - status_change_end(bl, SC_ANKLE, -1); - if (sc->data[SC_TRICKDEAD].timer != -1) - status_change_end(bl, SC_TRICKDEAD, -1); - if (sc->data[SC_BLADESTOP].timer!=-1) - status_change_end(bl,SC_BLADESTOP,-1); - if (sc->data[SC_RUN].timer!=-1) - status_change_end(bl,SC_RUN,-1); - if (sc->data[SC_DANCING].timer!=-1) // clear dance effect when warping [Valaris] - skill_stop_dancing(bl); - if (sc->data[SC_DEVOTION].timer!=-1) - status_change_end(bl,SC_DEVOTION,-1); - if (sc->data[SC_MARIONETTE].timer!=-1) - status_change_end(bl,SC_MARIONETTE,-1); - if (sc->data[SC_MARIONETTE2].timer!=-1) - status_change_end(bl,SC_MARIONETTE2,-1); - if (sc->data[SC_CLOSECONFINE].timer!=-1) - status_change_end(bl,SC_CLOSECONFINE,-1); - if (sc->data[SC_CLOSECONFINE2].timer!=-1) - status_change_end(bl,SC_CLOSECONFINE2,-1); - if (sc->data[SC_HIDING].timer!=-1) - status_change_end(bl, SC_HIDING, -1); - if (sc->data[SC_CLOAKING].timer!=-1) - status_change_end(bl, SC_CLOAKING, -1); - if (sc->data[SC_CHASEWALK].timer!=-1) - status_change_end(bl, SC_CHASEWALK, -1); - if (sc->data[SC_GOSPEL].timer != -1 && sc->data[SC_GOSPEL].val4 == BCT_SELF) - status_change_end(bl, SC_GOSPEL, -1); - } - - if (bl->type&BL_CHAR) { - skill_unit_move(bl,gettick(),4); - skill_cleartimerskill(bl); // タイマースキルクリア - } - - if(bl->type == BL_PC) { - struct map_session_data *sd = (struct map_session_data*)bl; - - //Leave/reject all invitations. - if(sd->chatID) - chat_leavechat(sd); - if(sd->trade_partner) - trade_tradecancel(sd); - if(sd->vender_id) - vending_closevending(sd); - if(sd->state.storage_flag == 1) - storage_storage_quit(sd,0); - else if (sd->state.storage_flag == 2) - storage_guild_storage_quit(sd,0); - - if(sd->party_invite>0) - party_reply_invite(sd,sd->party_invite_account,0); - if(sd->guild_invite>0) - guild_reply_invite(sd,sd->guild_invite,0); - if(sd->guild_alliance>0) - guild_reply_reqalliance(sd,sd->guild_alliance_account,0); - - pc_stop_following(sd); - pc_delinvincibletimer(sd); - - if(sd->pvp_timer!=-1) { - delete_timer(sd->pvp_timer,pc_calc_pvprank_timer); - sd->pvp_timer = -1; - } - - if(pc_issit(sd)) { - pc_setstand(sd); - skill_gangsterparadise(sd,0); - skill_rest(sd,0); - } - party_send_dot_remove(sd);//minimap dot fix [Kevin] - guild_send_dot_remove(sd); - } else if(bl->type == BL_MOB) { - struct mob_data *md = (struct mob_data*)bl; - md->target_id=0; - md->attacked_id=0; - md->state.skillstate= MSS_IDLE; - } else if (bl->type == BL_PET) { - struct pet_data *pd = (struct pet_data*)bl; - struct map_session_data *sd = pd->msd; - - if(!sd) { - map_delblock(bl); - unit_free(bl); - map_freeblock_unlock(); - return 0; - } - if (sd->pet.intimate <= 0) - { //Remove pet. - intif_delete_petdata(sd->status.pet_id); - sd->status.pet_id = 0; - sd->pd = NULL; - pd->msd = NULL; - map_delblock(bl); - unit_free(bl); - map_freeblock_unlock(); - return 0; - } - } - map_delblock(bl); - map_freeblock_unlock(); - return 1; -} - -/*========================================== - * Function to free all related resources to the bl - * if unit is on map, it is removed using clrtype 0. - *------------------------------------------ - */ - -int unit_free(struct block_list *bl) { - struct unit_data *ud = unit_bl2ud( bl ); - nullpo_retr(0, ud); - - map_freeblock_lock(); - if( bl->prev ) //Players are supposed to logout with a "warp" effect. - unit_remove_map(bl, bl->type==BL_PC?3:0); - - if( bl->type == BL_PC ) { - struct map_session_data *sd = (struct map_session_data*)bl; - if(status_isdead(bl)) - pc_setrestartvalue(sd,2); - - //Status that are not saved... - if(sd->sc.count) { - if(sd->sc.data[SC_SPURT].timer!=-1) - status_change_end(bl,SC_SPURT,-1); - if(sd->sc.data[SC_BERSERK].timer!=-1) - status_change_end(bl,SC_BERSERK,-1); - if(sd->sc.data[SC_TRICKDEAD].timer!=-1) - status_change_end(bl,SC_TRICKDEAD,-1); - if (battle_config.debuff_on_logout) { - if(sd->sc.data[SC_ORCISH].timer!=-1) - status_change_end(bl,SC_ORCISH,-1); - if(sd->sc.data[SC_STRIPWEAPON].timer!=-1) - status_change_end(bl,SC_STRIPWEAPON,-1); - if(sd->sc.data[SC_STRIPARMOR].timer!=-1) - status_change_end(bl,SC_STRIPARMOR,-1); - if(sd->sc.data[SC_STRIPSHIELD].timer!=-1) - status_change_end(bl,SC_STRIPSHIELD,-1); - if(sd->sc.data[SC_STRIPHELM].timer!=-1) - status_change_end(bl,SC_STRIPHELM,-1); - if(sd->sc.data[SC_EXTREMITYFIST].timer!=-1) - status_change_end(bl,SC_EXTREMITYFIST,-1); - if(sd->sc.data[SC_EXPLOSIONSPIRITS].timer!=-1) - status_change_end(bl,SC_EXPLOSIONSPIRITS,-1); - } - } - // Notify friends that this char logged out. [Skotlex] - clif_foreachclient(clif_friendslist_toggle_sub, sd->status.account_id, sd->status.char_id, 0); - party_send_logout(sd); - guild_send_memberinfoshort(sd,0); - pc_cleareventtimer(sd); - pc_delspiritball(sd,sd->spiritball,1); - chrif_save_scdata(sd); //Save status changes, then clear'em out from memory. [Skotlex] - pc_makesavestatus(sd); - sd->state.waitingdisconnect = 1; - pc_clean_skilltree(sd); - } else if( bl->type == BL_PET ) { - struct pet_data *pd = (struct pet_data*)bl; - struct map_session_data *sd = pd->msd; - pet_hungry_timer_delete(pd); - if (pd->a_skill) - { - aFree(pd->a_skill); - pd->a_skill = NULL; - } - if (pd->s_skill) - { - if (pd->s_skill->timer != -1) { - if (pd->s_skill->id) - delete_timer(pd->s_skill->timer, pet_skill_support_timer); - else - delete_timer(pd->s_skill->timer, pet_heal_timer); - } - aFree(pd->s_skill); - pd->s_skill = NULL; - } - if(pd->recovery) - { - if(pd->recovery->timer != -1) - delete_timer(pd->recovery->timer, pet_recovery_timer); - aFree(pd->recovery); - pd->recovery = NULL; - } - if(pd->bonus) - { - if (pd->bonus->timer != -1) - delete_timer(pd->bonus->timer, pet_skill_bonus_timer); - aFree(pd->bonus); - pd->bonus = NULL; - } - if (pd->loot) - { - if (pd->loot->item) - aFree(pd->loot->item); - aFree (pd->loot); - pd->loot = NULL; - } - if (sd) { - if(sd->pet.intimate > 0) - intif_save_petdata(sd->status.account_id,&sd->pet); - sd->pd = NULL; - } - } else if(bl->type == BL_MOB) { - struct mob_data *md = (struct mob_data*)bl; - if(md->deletetimer!=-1) - delete_timer(md->deletetimer,mob_timer_delete); - md->deletetimer=-1; - if(md->lootitem) { - aFree(md->lootitem); - md->lootitem=NULL; - } - if (md->guardian_data) - { - if (md->guardian_data->number < MAX_GUARDIANS) - md->guardian_data->castle->guardian[md->guardian_data->number].id = 0; - aFree(md->guardian_data); - md->guardian_data = NULL; - } - if (md->spawn && md->spawn_n < 0 && --(md->spawn->num) == 0) - { //Spawning data is not attached to the map, so free it - //if this is the last mob who is pointing at it. - aFree(md->spawn); - md->spawn = NULL; - } - if(md->base_status) { - aFree(md->base_status); - md->base_status = NULL; - } - if(mob_is_clone(md->class_)) - mob_clone_delete(md->class_); - } - - skill_clear_unitgroup(bl); - status_change_clear(bl,1); - if (bl->type != BL_PC) - { //Players are handled by map_quit - map_deliddb(bl); - map_freeblock(bl); - } - map_freeblock_unlock(); - return 0; -} - -int do_init_unit(void) { - add_timer_func_list(unit_attack_timer, "unit_attack_timer"); - add_timer_func_list(unit_walktoxy_timer,"unit_walktoxy_timer"); - add_timer_func_list(unit_walktobl_sub, "unit_walktobl_sub"); - - return 0; -} - -int do_final_unit(void) { - // nothing to do - return 0; -} - +// Copyright (c) jAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder +// Merged originally from jA by Skotlex +#include +#include +#include + +#include "../common/showmsg.h" +#include "../common/timer.h" +#include "../common/nullpo.h" +#include "../common/db.h" +#include "../common/malloc.h" +#include "unit.h" +#include "map.h" +#include "pc.h" +#include "mob.h" +#include "pet.h" +#include "skill.h" +#include "clif.h" +#include "npc.h" +#include "guild.h" +#include "status.h" +#include "battle.h" +#include "chat.h" +#include "trade.h" +#include "vending.h" +#include "party.h" +#include "intif.h" +#include "chrif.h" +#include "script.h" + +static int dirx[8]={0,-1,-1,-1,0,1,1,1}; +static int diry[8]={1,1,0,-1,-1,-1,0,1}; + +struct unit_data* unit_bl2ud(struct block_list *bl) { + if( bl == NULL) return NULL; + if( bl->type == BL_PC) return &((struct map_session_data*)bl)->ud; + if( bl->type == BL_MOB) return &((struct mob_data*)bl)->ud; + if( bl->type == BL_PET) return &((struct pet_data*)bl)->ud; + if( bl->type == BL_NPC) return &((struct npc_data*)bl)->ud; + return NULL; +} + +static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data); + +int unit_walktoxy_sub(struct block_list *bl) +{ + int i; + struct walkpath_data wpd; + struct unit_data *ud = NULL; + + nullpo_retr(1, bl); + ud = unit_bl2ud(bl); + if(ud == NULL) return 0; + + if(path_search(&wpd,bl->m,bl->x,bl->y,ud->to_x,ud->to_y,ud->state.walk_easy)) + return 0; + + memcpy(&ud->walkpath,&wpd,sizeof(wpd)); + + if (ud->target && ud->chaserange>1) { + //Generally speaking, the walk path is already to an adjacent tile + //so we only need to shorten the path if the range is greater than 1. + int dir; + //Trim the last part of the path to account for range, + //but always move at least one cell when requested to move. + for (i = ud->chaserange*10; i > 0 && ud->walkpath.path_len>1;) { + ud->walkpath.path_len--; + dir = ud->walkpath.path[ud->walkpath.path_len]; + if(dir&1) + i-=14; + else + i-=10; + ud->to_x -= dirx[dir]; + ud->to_y -= diry[dir]; + } + } + + ud->state.change_walk_target=0; + + if (bl->type == BL_PC) + clif_walkok((TBL_PC*)bl); + clif_move(bl); + + if(ud->walkpath.path_pos>=ud->walkpath.path_len) + i = -1; + else if(ud->walkpath.path[ud->walkpath.path_pos]&1) + i = status_get_speed(bl)*14/10; + else + i = status_get_speed(bl); + if( i > 0) + ud->walktimer = add_timer(gettick()+i,unit_walktoxy_timer,bl->id,i); + return 1; +} + +static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data) +{ + int i; + int x,y,dx,dy,dir; + struct block_list *bl; + struct map_session_data *sd = NULL; + struct mob_data *md = NULL; + struct unit_data *ud = NULL; + + bl=map_id2bl(id); + if(bl == NULL) + return 0; + if( BL_CAST( BL_PC, bl, sd ) ) { + ud = &sd->ud; + } else if( BL_CAST( BL_MOB, bl, md ) ) { + ud = &md->ud; + } else + ud = unit_bl2ud(bl); + + if(ud == NULL) return 0; + + if(ud->walktimer != tid){ + if(battle_config.error_log) + ShowError("unit_walk_timer mismatch %d != %d\n",ud->walktimer,tid); + return 0; + } + ud->walktimer=-1; + if( bl->prev == NULL ) return 0; // block_list から抜けているので移動停止する + + if(ud->walkpath.path_pos>=ud->walkpath.path_len) + return 0; + + //歩いたので息吹のタイマーを初期化 + if(sd) { + sd->inchealspirithptick = 0; + sd->inchealspiritsptick = 0; + } + + if(ud->walkpath.path[ud->walkpath.path_pos]>=8) + return 1; + x = bl->x; + y = bl->y; + + dir = ud->walkpath.path[ud->walkpath.path_pos]; + ud->dir = dir; + if (sd) + sd->head_dir = dir; + + dx = dirx[(int)dir]; + dy = diry[(int)dir]; + + if(map_getcell(bl->m,x+dx,y+dy,CELL_CHKNOPASS)) + return unit_walktoxy_sub(bl); + + // バシリカ判定 + + map_foreachinmovearea(clif_outsight,bl->m, + x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE, + dx,dy,sd?BL_ALL:BL_PC,bl); + + x += dx; + y += dy; + map_moveblock(bl, x, y, tick); + ud->walk_count++; //walked cell counter, to be used for walk-triggered skills. [Skotlex] + + ud->walktimer = 1; + map_foreachinmovearea(clif_insight,bl->m, + x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE, + -dx,-dy,sd?BL_ALL:BL_PC,bl); + ud->walktimer = -1; + + if(sd) { + if(map_getcell(bl->m,x,y,CELL_CHKNPC)) { + npc_touch_areanpc(sd,bl->m,x,y); + if (bl->prev == NULL) //Script could have warped char, abort remaining of the function. + return 0; + } else + sd->areanpc_id=0; + if (sd->state.gmaster_flag) + { //Guild Aura: Likely needs to be recoded, this method seems inefficient. + struct guild *g = sd->state.gmaster_flag; + int skill, guildflag = 0; + if ((skill = guild_checkskill(g, GD_LEADERSHIP)) > 0) guildflag |= skill<<12; + if ((skill = guild_checkskill(g, GD_GLORYWOUNDS)) > 0) guildflag |= skill<<8; + if ((skill = guild_checkskill(g, GD_SOULCOLD)) > 0) guildflag |= skill<<4; + if ((skill = guild_checkskill(g, GD_HAWKEYES)) > 0) guildflag |= skill; + if (guildflag) + map_foreachinrange(skill_guildaura_sub, bl,2, BL_PC, + bl->id, sd->status.guild_id, &guildflag); + } + if ( + (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR && + sd->sc.data[SC_MIRACLE].timer==-1 && + !(ud->walk_count%WALK_SKILL_INTERVAL) && + rand()%10000 < battle_config.sg_miracle_skill_ratio + ) { //SG_MIRACLE [Komurka] + clif_displaymessage(sd->fd,"[Miracle of the Sun, Moon and Stars]"); + sc_start(&sd->bl,SC_MIRACLE,100,1,battle_config.sg_miracle_skill_duration); + } + } else if (md) { + if(battle_config.mob_npc_warp && map_getcell(bl->m,x,y,CELL_CHKNPC) && + npc_touch_areanpc2(bl)) // Enable mobs to step on warps. [Skotlex] + return 0; + if (md->min_chase > md->db->range2) md->min_chase--; + //Walk skills are triggered regardless of target due to the idle-walk mob state. + if(!(ud->walk_count%WALK_SKILL_INTERVAL) && + mobskill_use(md, tick, -1)) + return 0; + } + + if(tid == -1) //A directly invoked timer is from battle_stop_walking, therefore the rest is irrelevant. + return 0; + + if(ud->state.change_walk_target) + return unit_walktoxy_sub(bl); + + ud->walkpath.path_pos++; + if(ud->walkpath.path_pos>=ud->walkpath.path_len) + i = -1; + else if(ud->walkpath.path[ud->walkpath.path_pos]&1) + i = status_get_speed(bl)*14/10; + else + i = status_get_speed(bl); + + if(i > 0) + ud->walktimer = add_timer(tick+i,unit_walktoxy_timer,id,i); + else if(ud->state.running) { + //Keep trying to run. + if (!unit_run(bl)) + ud->state.running = 0; + } else if (ud->target) { + //Update target trajectory. + struct block_list *tbl = map_id2bl(ud->target); + if (!tbl) { //Cancel chase. + ud->to_x = bl->x; + ud->to_y = bl->y; + return 0; + } + if (tbl->m == bl->m && check_distance_bl(bl, tbl, ud->chaserange)) + { //Reached destination. + if (ud->state.attack_continue) { + clif_fixpos(bl); //Aegis uses one before every attack, we should + //only need this one for syncing purposes. [Skotlex] + unit_attack(bl, tbl->id, ud->state.attack_continue); + } + } else { //Update chase-path + unit_walktobl(bl, tbl, ud->chaserange, ud->state.walk_easy|(ud->state.attack_continue?2:0)); + return 0; + } + } else { //Stopped walking. Update to_x and to_y to current location [Skotlex] + ud->to_x = bl->x; + ud->to_y = bl->y; + if(md && md->nd) // Tell the script engine we've finished walking (for AI pathfinding) + mob_script_callback(md, NULL, CALLBACK_WALKACK); + } + return 0; +} + +int unit_walktoxy( struct block_list *bl, int x, int y, int easy) { + struct unit_data *ud = NULL; + struct status_change *sc = NULL; + + nullpo_retr(0, bl); + + ud = unit_bl2ud(bl); + + if( ud == NULL) return 0; + + // 移動出来ないユニットは弾く + if(!(status_get_mode(bl)&MD_CANMOVE) || !unit_can_move(bl)) + return 0; + + ud->state.walk_easy = easy; + ud->target = 0; + ud->to_x = x; + ud->to_y = y; + + sc = status_get_sc(bl); + if (sc && sc->count && sc->data[SC_CONFUSION].timer != -1) //Randomize the target position + map_random_dir(bl, &ud->to_x, &ud->to_y); + + if(ud->walktimer != -1) { + // 現在歩いている最中の目的地変更なのでマス目の中心に来た時に + // timer関数からunit_walktoxy_subを呼ぶようにする + ud->state.change_walk_target = 1; + return 1; + } else { + return unit_walktoxy_sub(bl); + } +} + +static int unit_walktobl_sub(int tid,unsigned int tick,int id,int data) +{ + struct block_list *bl = map_id2bl(id); + struct unit_data *ud = bl?unit_bl2ud(bl):NULL; + + if (ud && ud->walktimer == -1 && ud->target == data) + { + if (DIFF_TICK(ud->canmove_tick, tick) > 0) //Keep waiting? + add_timer(ud->canmove_tick+1, unit_walktobl_sub, id, data); + else if (unit_can_move(bl)) + unit_walktoxy_sub(bl); + } + return 0; +} + +// Chases a tbl. If the flag&1, use hard-path seek, +// if flag&2, start attacking upon arrival within range, otherwise just walk to that character. +int unit_walktobl(struct block_list *bl, struct block_list *tbl, int range, int flag) { + struct unit_data *ud = NULL; + struct status_change *sc = NULL; + nullpo_retr(0, bl); + nullpo_retr(0, tbl); + + ud = unit_bl2ud(bl); + if( ud == NULL) return 0; + + if (!(status_get_mode(bl)&MD_CANMOVE)) + return 0; + + if (!unit_can_reach_bl(bl, tbl, distance_bl(bl, tbl)+1, flag&1, &ud->to_x, &ud->to_y)) { + ud->to_x = bl->x; + ud->to_y = bl->y; + return 0; + } + + ud->state.walk_easy = flag&1; + ud->target = tbl->id; + ud->chaserange = range; //Note that if flag&2, this SHOULD be attack-range + ud->state.attack_continue = flag&2?1:0; //Chase to attack. + + sc = status_get_sc(bl); + if (sc && sc->count && sc->data[SC_CONFUSION].timer != -1) //Randomize the target position + map_random_dir(bl, &ud->to_x, &ud->to_y); + + + if(ud->walktimer != -1) { + ud->state.change_walk_target = 1; + return 1; + } + if (DIFF_TICK(ud->canmove_tick, gettick()) > 0) + { //Can't move, wait a bit before invoking the movement. + add_timer(ud->canmove_tick+1, unit_walktobl_sub, bl->id, ud->target); + return 1; + } else if (!unit_can_move(bl)) + return 0; + + return unit_walktoxy_sub(bl); +} + +int unit_run(struct block_list *bl) +{ + struct status_change *sc = status_get_sc(bl); + int i,to_x,to_y,dir_x,dir_y; + + if (!sc || !sc->count || sc->data[SC_RUN].timer == -1) + return 0; + + if (!unit_can_move(bl)) { + if(sc->data[SC_RUN].timer!=-1) + status_change_end(bl,SC_RUN,-1); + return 0; + } + + to_x = bl->x; + to_y = bl->y; + dir_x = dirx[sc->data[SC_RUN].val2]; + dir_y = diry[sc->data[SC_RUN].val2]; + + for(i=0;im,to_x+dir_x,to_y+dir_y,CELL_CHKPASS)) + break; + to_x += dir_x; + to_y += dir_y; + } + + if(to_x == bl->x && to_y == bl->y) { + //If you can't run forward, you must be next to a wall, so bounce back. [Skotlex] + status_change_end(bl,SC_RUN,-1); + skill_blown(bl,bl,skill_get_blewcount(TK_RUN,sc->data[SC_RUN].val1)|0x10000); + return 0; + } + unit_walktoxy(bl, to_x, to_y, 1); + return 1; +} + +//Instant warp function. +int unit_movepos(struct block_list *bl,int dst_x,int dst_y, int easy, int checkpath) +{ + int dx,dy,dir; + struct unit_data *ud = NULL; + struct map_session_data *sd = NULL; + struct walkpath_data wpd; + + nullpo_retr(0, bl); + if( BL_CAST( BL_PC, bl, sd ) ) { + ud = &sd->ud; + } else + ud = unit_bl2ud(bl); + + if( ud == NULL) return 0; + + unit_stop_walking(bl,1); + unit_stop_attack(bl); + + if(checkpath && (map_getcell(bl->m,dst_x,dst_y, CELL_CHKNOPASS) || path_search_real(&wpd,bl->m,bl->x,bl->y,dst_x,dst_y,easy, CELL_CHKNOREACH))) + return 0; + + dir = map_calc_dir(bl, dst_x,dst_y); + ud->dir = dir; + if(sd) sd->head_dir = dir; + + dx = dst_x - bl->x; + dy = dst_y - bl->y; + + map_foreachinmovearea(clif_outsight,bl->m, + bl->x-AREA_SIZE,bl->y-AREA_SIZE,bl->x+AREA_SIZE,bl->y+AREA_SIZE, + dx,dy,sd?BL_ALL:BL_PC,bl); + + map_moveblock(bl, dst_x, dst_y, gettick()); + + ud->walktimer = 1; + map_foreachinmovearea(clif_insight,bl->m, + bl->x-AREA_SIZE,bl->y-AREA_SIZE,bl->x+AREA_SIZE,bl->y+AREA_SIZE, + -dx,-dy,sd?BL_ALL:BL_PC,bl); + ud->walktimer = -1; + + if(sd) { + if(map_getcell(bl->m,bl->x,bl->y,CELL_CHKNPC)) { + npc_touch_areanpc(sd,bl->m,bl->x,bl->y); + if (bl->prev == NULL) //Script could have warped char, abort remaining of the function. + return 0; + } else + sd->areanpc_id=0; + if(sd->status.pet_id > 0 && sd->pd && sd->pet.intimate > 0) + { //Check if pet needs to be teleported. [Skotlex] + int flag = 0; + bl = &sd->pd->bl; //Note that bl now points to the pet! + if (!checkpath && path_search(&wpd,bl->m,bl->x,bl->y,dst_x,dst_y,0)) + flag = 1; + else if (!check_distance_bl(&sd->bl, bl, AREA_SIZE)) //Too far, teleport. + flag = 2; + if (flag) { + unit_movepos(bl,sd->bl.x,sd->bl.y, 0, 0); + clif_slide(bl,bl->x,bl->y); + } + //If you want to use bl afterwards, uncomment this: + //bl = &sd->bl; + } + } + return 1; +} + +int unit_setdir(struct block_list *bl,unsigned char dir) +{ + struct unit_data *ud; + nullpo_retr( 0, bl ); + ud = unit_bl2ud(bl); + if (!ud) return 0; + ud->dir = dir; + if (bl->type == BL_PC) + ((TBL_PC *)bl)->head_dir = dir; + clif_changed_dir(bl); + return 0; +} + +int unit_getdir(struct block_list *bl) +{ + struct unit_data *ud; + nullpo_retr( 0, bl ); + ud = unit_bl2ud(bl); + if (!ud) return 0; + return ud->dir; +} + +//Warps a unit/ud to a given map/position. +//In the case of players, pc_setpos is used. +//it respects the no warp flags, so it is safe to call this without doing nowarpto/nowarp checks. +int unit_warp(struct block_list *bl,int m,short x,short y,int type) +{ + struct unit_data *ud; + nullpo_retr(0, bl); + ud = unit_bl2ud(bl); + + if(bl->prev==NULL || !ud) + return 1; + + if (type < 0 || type == 1) + //Type 1 is invalid, since you shouldn't warp a bl with the "death" + //animation, it messes up with unit_remove_map! [Skotlex] + return 1; + + if( m<0 ) m=bl->m; + + switch (bl->type) { + case BL_MOB: + if (map[bl->m].flag.monster_noteleport) + return 1; + break; + case BL_PC: + if (map[bl->m].flag.noteleport) + return 1; + break; + } + + if (x<0 || y<0) + { //Random map position. + if (!map_search_freecell(NULL, m, &x, &y, -1, -1, 1)) { + if(battle_config.error_log) + ShowWarning("unit_warp failed. Unit Id:%d/Type:%d, target position map %d (%s) at [%d,%d]\n", bl->id, bl->type, m, map[m].name, x, y); + return 2; + + } + } else if (map_getcell(m,x,y,CELL_CHKNOREACH)) + { //Invalid target cell + if(battle_config.error_log) + ShowWarning("unit_warp: Specified non-walkable target cell: %d (%s) at [%d,%d]\n", m, map[m].name, x,y); + + if (!map_search_freecell(NULL, m, &x, &y, 4, 4, 1)) + { //Can't find a nearby cell + if(battle_config.error_log) + ShowWarning("unit_warp failed. Unit Id:%d/Type:%d, target position map %d (%s) at [%d,%d]\n", bl->id, bl->type, m, map[m].name, x, y); + return 2; + } + } + + if (bl->type == BL_PC) //Use pc_setpos + return pc_setpos((TBL_PC*)bl, map[m].index, x, y, type); + + if (!unit_remove_map(bl, type)) + return 3; + + bl->x=ud->to_x=x; + bl->y=ud->to_y=y; + bl->m=m; + + map_addblock(bl); + clif_spawn(bl); + skill_unit_move(bl,gettick(),1); + + if(bl->type == BL_MOB){ + TBL_MOB *md = (TBL_MOB *)bl; + if(md->nd) // Tell the script engine we've warped + mob_script_callback(md, NULL, CALLBACK_WARPACK); + } + return 0; +} + +/*========================================== + * 歩行停止 + *------------------------------------------ + */ +int unit_stop_walking(struct block_list *bl,int type) +{ + struct unit_data *ud; + struct TimerData *data; + unsigned int tick; + nullpo_retr(0, bl); + + ud = unit_bl2ud(bl); + if(!ud || ud->walktimer == -1) + return 0; + //NOTE: We are using timer data after deleting it because we know the + //delete_timer function does not messes with it. If the function's + //behaviour changes in the future, this code could break! + data = get_timer(ud->walktimer); + delete_timer(ud->walktimer, unit_walktoxy_timer); + ud->walktimer = -1; + ud->state.change_walk_target = 0; + tick = gettick(); + if ((type&0x02 && !ud->walkpath.path_pos) //Force moving at least one cell. + || (data && DIFF_TICK(data->tick, tick) <= data->data/2)) //Enough time has passed to cover half-cell + { + ud->walkpath.path_len = ud->walkpath.path_pos+1; + unit_walktoxy_timer(-1, tick, bl->id, ud->walkpath.path_pos); + } + + if(type&0x01) + clif_fixpos(bl); + + ud->walkpath.path_len = 0; + ud->walkpath.path_pos = 0; + ud->to_x = bl->x; + ud->to_y = bl->y; + if(bl->type == BL_PET && type&~0xff) + ud->canmove_tick = gettick() + (type>>8); + + if (ud->state.running) + status_change_end(bl, SC_RUN, -1); + return 1; +} + +int unit_skilluse_id(struct block_list *src, int target_id, int skill_num, int skill_lv) { + + if(skill_num < 0) return 0; + + return unit_skilluse_id2( + src, target_id, skill_num, skill_lv, + skill_castfix(src, skill_num, skill_lv), + skill_get_castcancel(skill_num) + ); +} + +int unit_is_walking(struct block_list *bl) +{ + struct unit_data *ud = unit_bl2ud(bl); + nullpo_retr(0, bl); + if(!ud) return 0; + return (ud->walktimer != -1); +} + +/*========================================== + * Determines if the bl can move based on status changes. [Skotlex] + *------------------------------------------ + */ +int unit_can_move(struct block_list *bl) +{ + struct map_session_data *sd; + struct unit_data *ud; + struct status_change *sc; + + nullpo_retr(0, bl); + ud = unit_bl2ud(bl); + sc = status_get_sc(bl); + BL_CAST(BL_PC, bl, sd); + + if (!ud) + return 0; + + if (ud->skilltimer != -1 && (!sd || pc_checkskill(sd, SA_FREECAST) <= 0)) + return 0; + + if (DIFF_TICK(ud->canmove_tick, gettick()) > 0) + return 0; + + if (sd && ( + pc_issit(sd) || + sd->state.blockedmove + )) + return 0; //Can't move + + if (sc) { + if (sc->opt1 > 0 && sc->opt1 != OPT1_STONEWAIT) + return 0; + + if ((sc->option & OPTION_HIDE) && (!sd || pc_checkskill(sd, RG_TUNNELDRIVE) <= 0)) + return 0; + + if (sc->count && ( + sc->data[SC_ANKLE].timer != -1 || + sc->data[SC_AUTOCOUNTER].timer !=-1 || + sc->data[SC_TRICKDEAD].timer !=-1 || + sc->data[SC_BLADESTOP].timer !=-1 || + sc->data[SC_BLADESTOP_WAIT].timer !=-1 || + sc->data[SC_SPIDERWEB].timer !=-1 || + (sc->data[SC_DANCING].timer !=-1 && ( + (sc->data[SC_DANCING].val4 && sc->data[SC_LONGING].timer == -1) || + sc->data[SC_DANCING].val1 == CG_HERMODE //cannot move while Hermod is active. + )) || + sc->data[SC_MOONLIT].timer != -1 || + (sc->data[SC_GOSPEL].timer !=-1 && sc->data[SC_GOSPEL].val4 == BCT_SELF) || // cannot move while gospel is in effect + sc->data[SC_STOP].timer != -1 || + sc->data[SC_CLOSECONFINE].timer != -1 || + sc->data[SC_CLOSECONFINE2].timer != -1 + )) + return 0; + } + return 1; +} + +/*========================================== + * Applies walk delay to character, considering that + * if type is 0, this is a damage induced delay: if previous delay is active, do not change it. + * if type is 1, this is a skill induced delay: walk-delay may only be increased, not decreased. + *------------------------------------------ + */ +int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int type) +{ + struct unit_data *ud = unit_bl2ud(bl); + if (delay <= 0 || !ud) return 0; + + if (type) { + if (DIFF_TICK(ud->canmove_tick, tick+delay) > 0) + return 0; + } else { + if (DIFF_TICK(ud->canmove_tick, tick) > 0) + return 0; + } + ud->canmove_tick = tick + delay; + if (ud->walktimer != -1) + { //Stop walking, if chasing, readjust timers. + if (delay == 1) + { //Minimal delay (walk-delay) disabled. Just stop walking. + unit_stop_walking(bl,0); + } else { + unit_stop_walking(bl,2); + if(ud->target) + add_timer(ud->canmove_tick+1, unit_walktobl_sub, bl->id, ud->target); + } + } + return 1; +} + +int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int skill_lv, int casttime, int castcancel) { + struct unit_data *ud; + struct status_data *tstatus; + struct status_change *sc; + struct map_session_data *sd = NULL; + struct block_list * target = NULL; + unsigned int tick = gettick(); + int temp; + + nullpo_retr(0, src); + if(status_isdead(src)) + return 0; // 死んでいないか + + if( BL_CAST( BL_PC, src, sd ) ) { + ud = &sd->ud; + } else + ud = unit_bl2ud(src); + + if(ud == NULL) return 0; + sc = status_get_sc(src); + if (sc && !sc->count) + sc = NULL; //Unneeded + //temp: used to signal combo-skills right now. + temp = (target_id == src->id && !(sd && sd->state.skill_flag) + && skill_get_inf(skill_num)&INF_SELF_SKILL + && skill_get_inf2(skill_num)&INF2_NO_TARGET_SELF); + if (temp) + target_id = ud->target; //Auto-select skills. [Skotlex] + + if (sd) { + //Target_id checking. + if(skillnotok(skill_num, sd)) // [MouseJstr] + return 0; + switch(skill_num) + { //Check for skills that auto-select target + case MO_CHAINCOMBO: + if (sc && sc->data[SC_BLADESTOP].timer != -1){ + if ((target=(struct block_list *)sc->data[SC_BLADESTOP].val4) == NULL) + return 0; + } + break; + case TK_JUMPKICK: + case TK_COUNTER: + case HT_POWER: + if (sc && sc->data[SC_COMBO].timer != -1 && sc->data[SC_COMBO].val1 == skill_num) + target_id = sc->data[SC_COMBO].val2; + break; + case WE_MALE: + case WE_FEMALE: + if (!sd->status.partner_id) + return 0; + target = (struct block_list*)map_charid2sd(sd->status.partner_id); + if (!target) { + clif_skill_fail(sd,skill_num,0,0); + return 0; + } + break; + } + if (target) + target_id = target->id; + } + if(!target && (target=map_id2bl(target_id)) == NULL ) + return 0; + if(src->m != target->m) + return 0; // 同じマップかどうか + if(!src->prev || !target->prev) + return 0; // map 上に存在するか + + //Normally not needed because clif.c checks for it, but the at/char/script commands don't! [Skotlex] + if(ud->skilltimer != -1 && skill_num != SA_CASTCANCEL) + return 0; + + if(skill_get_inf2(skill_num)&INF2_NO_TARGET_SELF && src->id == target_id) + return 0; + + if(!status_check_skilluse(src, target, skill_num, 0)) + return 0; + + tstatus = status_get_status_data(target); + //直前のスキル状況の記録 + if(sd) { + switch(skill_num){ + case SA_CASTCANCEL: + if(ud->skillid != skill_num){ + sd->skillid_old = ud->skillid; + sd->skilllv_old = ud->skilllv; + break; + } + case BD_ENCORE: + //Prevent using the dance skill if you no longer have the skill in your tree. + if(!sd->skillid_dance || pc_checkskill(sd,sd->skillid_dance)<=0){ + clif_skill_fail(sd,skill_num,0,0); + return 0; + } + sd->skillid_old = skill_num; + break; + case BD_LULLABY: + case BD_RICHMANKIM: + case BD_ETERNALCHAOS: + case BD_DRUMBATTLEFIELD: + case BD_RINGNIBELUNGEN: + case BD_ROKISWEIL: + case BD_INTOABYSS: + case BD_SIEGFRIED: + case CG_MOONLIT: + if (battle_config.player_skill_partner_check && + (!battle_config.gm_skilluncond || pc_isGM(sd) < battle_config.gm_skilluncond) && + (skill_check_pc_partner(sd, skill_num, &skill_lv, 1, 0) < 1) + ) { + clif_skill_fail(sd,skill_num,0,0); + return 0; + } + break; + } + if (!skill_check_condition(sd, skill_num, skill_lv, 0)) + return 0; + } + //TODO: Add type-independant skill_check_condition function. + if (src->type == BL_MOB) { + switch (skill_num) { + case NPC_SUMMONSLAVE: + case NPC_SUMMONMONSTER: + case AL_TELEPORT: + if (((TBL_MOB*)src)->master_id && ((TBL_MOB*)src)->special_state.ai) + return 0; + } + } + + if(src->id != target_id && + !battle_check_range(src,target,skill_get_range2(src, skill_num,skill_lv) + +(skill_num==RG_CLOSECONFINE?0:1))) //Close confine is exploitable thanks to this extra range "feature" of the client. [Skotlex] + return 0; + + if (!temp) //Stop attack on non-combo skills [Skotlex] + unit_stop_attack(src); + else if(ud->attacktimer != -1) //Elsewise, delay current attack sequence + ud->attackabletime = tick + status_get_adelay(src); + + ud->state.skillcastcancel = castcancel; + + //temp: Used to signal force cast now. + temp = 0; + + switch(skill_num){ + case ALL_RESURRECTION: + if(battle_check_undead(tstatus->race,tstatus->def_ele)){ + temp=1; + casttime = skill_castfix(src, PR_TURNUNDEAD, skill_lv); + } + break; + case MO_FINGEROFFENSIVE: + if(sd) + casttime += casttime * ((skill_lv > sd->spiritball)? sd->spiritball:skill_lv); + break; + case MO_EXTREMITYFIST: + if (sc && sc->data[SC_COMBO].timer != -1 && + (sc->data[SC_COMBO].val1 == MO_COMBOFINISH || + sc->data[SC_COMBO].val1 == CH_TIGERFIST || + sc->data[SC_COMBO].val1 == CH_CHAINCRUSH)) + casttime = 0; + temp = 1; + break; + case TK_RUN: + if (sc && sc->data[SC_RUN].timer != -1) + casttime = 0; + break; + case SA_MAGICROD: + case SA_SPELLBREAKER: + temp =1; + break; + case KN_CHARGEATK: + //Taken from jA: Casttime is increased by dist/3*100% + casttime = casttime * ((distance_bl(src,target)-1)/3+1); + break; + } + + if (sc && sc->data[SC_MEMORIZE].timer != -1 && casttime > 0) { + casttime = casttime/2; + if ((--sc->data[SC_MEMORIZE].val2) <= 0) + status_change_end(src, SC_MEMORIZE, -1); + } + + if( casttime>0 || temp){ + + clif_skillcasting(src, src->id, target_id, 0,0, skill_num,casttime); + + if (sd && target->type == BL_MOB) + { + TBL_MOB *md = (TBL_MOB*)target; + mobskill_event(md, src, tick, -1); //Cast targetted skill event. + //temp: used to store mob's mode now. + if (tstatus->mode&MD_CASTSENSOR && + battle_check_target(target, src, BCT_ENEMY) > 0) + { + switch (md->state.skillstate) { + case MSS_ANGRY: + case MSS_RUSH: + case MSS_FOLLOW: + if (!(tstatus->mode&(MD_AGGRESSIVE|MD_ANGRY))) + break; //Only Aggressive mobs change target while chasing. + case MSS_IDLE: + case MSS_WALK: + md->target_id = src->id; + md->state.aggressive = (temp&MD_ANGRY)?1:0; + md->min_chase = md->db->range3; + } + } + } + } + + if( casttime<=0 ) + ud->state.skillcastcancel=0; + + ud->canact_tick = tick + casttime + 100; + ud->skilltarget = target_id; + ud->skillx = 0; + ud->skilly = 0; + ud->skillid = skill_num; + ud->skilllv = skill_lv; + + if(sc && sc->data[SC_CLOAKING].timer != -1 && + !(sc->data[SC_CLOAKING].val4&1) && skill_num != AS_CLOAKING) + status_change_end(src,SC_CLOAKING,-1); + + if(casttime > 0) { + ud->skilltimer = add_timer( tick+casttime, skill_castend_id, src->id, 0 ); + if(sd && pc_checkskill(sd,SA_FREECAST)) + status_freecast_switch(sd); + else + unit_stop_walking(src,1); + } + else + skill_castend_id(ud->skilltimer,tick,src->id,0); + return 1; +} + +int unit_skilluse_pos(struct block_list *src, int skill_x, int skill_y, int skill_num, int skill_lv) { + if(skill_num < 0) + return 0; + return unit_skilluse_pos2( + src, skill_x, skill_y, skill_num, skill_lv, + skill_castfix(src, skill_num, skill_lv), + skill_get_castcancel(skill_num) + ); +} + +int unit_skilluse_pos2( struct block_list *src, int skill_x, int skill_y, int skill_num, int skill_lv, int casttime, int castcancel) { + struct map_session_data *sd = NULL; + struct unit_data *ud = NULL; + struct status_change *sc; + struct block_list bl; + unsigned int tick = gettick(); + + nullpo_retr(0, src); + + if(!src->prev) return 0; // map 上に存在するか + if(status_isdead(src)) return 0; + + if( BL_CAST( BL_PC, src, sd ) ) { + ud = &sd->ud; + } else + ud = unit_bl2ud(src); + if(ud == NULL) return 0; + + if(ud->skilltimer != -1) //Normally not needed since clif.c checks for it, but at/char/script commands don't! [Skotlex] + return 0; + + sc = status_get_sc(src); + if (sc && !sc->count) + sc = NULL; + + if(sd) { + if (skillnotok(skill_num, sd) || + !skill_check_condition(sd, skill_num, skill_lv,0)) + return 0; + } + + if (!status_check_skilluse(src, NULL, skill_num, 0)) + return 0; + + if (map_getcell(src->m, skill_x, skill_y, CELL_CHKNOREACH)) + { //prevent casting ground targeted spells on non-walkable areas. [Skotlex] + if (sd) clif_skill_fail(sd,skill_num,0,0); + return 0; + } + + /* 射程と障害物チェック */ + bl.type = BL_NUL; + bl.m = src->m; + bl.x = skill_x; + bl.y = skill_y; + if(skill_num != TK_HIGHJUMP && + !battle_check_range(src,&bl,skill_get_range2(src, skill_num,skill_lv)+1)) + return 0; + + unit_stop_attack(src); + ud->state.skillcastcancel = castcancel; + + if (sc && sc->data[SC_MEMORIZE].timer != -1 && casttime > 0){ + casttime = casttime/3; + if ((--sc->data[SC_MEMORIZE].val2)<=0) + status_change_end(src, SC_MEMORIZE, -1); + } + + if( casttime>0 ) { + unit_stop_walking( src, 1); + clif_skillcasting(src, src->id, 0, skill_x,skill_y, skill_num,casttime); + } + + if( casttime<=0 ) + ud->state.skillcastcancel=0; + + ud->canact_tick = tick + casttime + 100; + ud->skillid = skill_num; + ud->skilllv = skill_lv; + ud->skillx = skill_x; + ud->skilly = skill_y; + ud->skilltarget = 0; + + if (sc && sc->data[SC_CLOAKING].timer != -1 && + !(sc->data[SC_CLOAKING].val4&1)) + status_change_end(src,SC_CLOAKING,-1); + + if(casttime > 0) { + ud->skilltimer = add_timer( tick+casttime, skill_castend_pos, src->id, 0 ); + if(sd && pc_checkskill(sd,SA_FREECAST)) + status_freecast_switch(sd); + else + unit_stop_walking(src,1); + } + else { + ud->skilltimer = -1; + skill_castend_pos(ud->skilltimer,tick,src->id,0); + } + return 1; +} + +static int unit_attack_timer(int tid,unsigned int tick,int id,int data); + +int unit_stop_attack(struct block_list *bl) +{ + struct unit_data *ud = unit_bl2ud(bl); + nullpo_retr(0, bl); + + if(!ud || ud->attacktimer == -1) + return 0; + + delete_timer( ud->attacktimer, unit_attack_timer ); + ud->attacktimer = -1; + ud->target = 0; + return 0; +} + +//Means current target is unattackable. For now only unlocks mobs. +int unit_unattackable(struct block_list *bl) { + struct unit_data *ud = unit_bl2ud(bl); + if (ud) { + ud->target = 0; + ud->state.attack_continue = 0; + } + + if(bl->type == BL_MOB) + mob_unlocktarget((struct mob_data*)bl, gettick()) ; + else if(bl->type == BL_PET) + pet_unlocktarget((struct pet_data*)bl); + return 0; +} + +/*========================================== + * 攻撃要求 + * typeが1なら継続攻撃 + *------------------------------------------ + */ + +int unit_attack(struct block_list *src,int target_id,int type) +{ + struct block_list *target; + struct unit_data *ud; + + nullpo_retr(0, ud = unit_bl2ud(src)); + + target=map_id2bl(target_id); + if(target==NULL || status_isdead(target)) { + unit_unattackable(src); + return 1; + } + + if(src->type == BL_PC && target->type==BL_NPC) { // monster npcs [Valaris] + npc_click((TBL_PC*)src,target); // submitted by leinsirk10 [Celest] + return 0; + } + + if(battle_check_target(src,target,BCT_ENEMY)<=0 || + !status_check_skilluse(src, target, 0, 0) + ) { + unit_unattackable(src); + return 1; + } + + ud->target = target_id; + ud->state.attack_continue = type; + if (type) //If you re to attack continously, set to auto-case character + ud->chaserange = status_get_range(src); + + //Just change target/type. [Skotlex] + if(ud->attacktimer != -1) + return 0; + + if(DIFF_TICK(ud->attackabletime, gettick()) > 0) + //Do attack next time it is possible. [Skotlex] + ud->attacktimer=add_timer(ud->attackabletime,unit_attack_timer,src->id,0); + else //Attack NOW. + unit_attack_timer(-1,gettick(),src->id,0); + + return 0; +} + +/*========================================== + * + *------------------------------------------ + */ +int unit_can_reach_pos(struct block_list *bl,int x,int y, int easy) +{ + struct walkpath_data wpd; + + nullpo_retr(0, bl); + + if( bl->x==x && bl->y==y ) // 同じマス + return 1; + + // 障害物判定 + wpd.path_len=0; + wpd.path_pos=0; + wpd.path_half=0; + return (path_search_real(&wpd,bl->m,bl->x,bl->y,x,y,easy,CELL_CHKNOREACH)!=-1); +} + +/*========================================== + * + *------------------------------------------ + */ +int unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, int easy, short *x, short *y) +{ + struct walkpath_data wpd; + int i; + short dx,dy; + nullpo_retr(0, bl); + nullpo_retr(0, tbl); + + if( bl->m != tbl->m) + return 0; + + if( bl->x==tbl->x && bl->y==tbl->y ) + return 1; + + if(range>0 && !check_distance_bl(bl, tbl, range)) + return 0; + + wpd.path_len=0; + wpd.path_pos=0; + wpd.path_half=0; + + // It judges whether it can adjoin or not. + dx=tbl->x - bl->x; + dy=tbl->y - bl->y; + dx=(dx>0)?1:((dx<0)?-1:0); + dy=(dy>0)?1:((dy<0)?-1:0); + + if (map_getcell(tbl->m,tbl->x-dx,tbl->y-dy,CELL_CHKNOREACH)) + { //Look for a suitable cell to place in. + for(i=0;i<9 && map_getcell(tbl->m,tbl->x-dirx[i],tbl->y-diry[i],CELL_CHKNOREACH);i++); + if (i==9) return 0; //No valid cells. + dx = dirx[i]; + dy = diry[i]; + } + + if (x) *x = tbl->x-dx; + if (y) *y = tbl->y-dy; + return (path_search_real(&wpd,bl->m,bl->x,bl->y,tbl->x-dx,tbl->y-dy,easy,CELL_CHKNOREACH)!=-1); +} + + +/*========================================== + * PCの攻撃 (timer関数) + *------------------------------------------ + */ +static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int tick) +{ + struct block_list *target; + struct unit_data *ud; + struct status_data *sstatus; + struct map_session_data *sd = NULL; + struct mob_data *md = NULL; + int range; + + if((ud=unit_bl2ud(src))==NULL) + return 0; + if(ud->attacktimer != tid){ + if(battle_config.error_log) + ShowError("unit_attack_timer %d != %d\n",ud->attacktimer,tid); + return 0; + } + BL_CAST( BL_PC , src, sd); + BL_CAST( BL_MOB, src, md); + ud->attacktimer=-1; + target=map_id2bl(ud->target); + + if(src->prev == NULL || target==NULL || target->prev == NULL) + return 0; + + if(ud->skilltimer != -1 && (!sd || pc_checkskill(sd,SA_FREECAST) <= 0)) + return 0; + + if(src->m != target->m || status_isdead(src) || status_isdead(target) || !status_check_skilluse(src, target, 0, 0)) + return 0; + + sstatus = status_get_status_data(src); + + if(!battle_config.sdelay_attack_enable && + DIFF_TICK(ud->canact_tick,tick) > 0 && + (!sd || pc_checkskill(sd,SA_FREECAST) <= 0) + ) { + if (tid == -1) { //requested attack. + if(sd) clif_skill_fail(sd,1,4,0); + return 0; + } + //Otherwise, we are in a combo-attack, delay this until your canact time is over. [Skotlex] + if(ud->state.attack_continue) { + if (DIFF_TICK(ud->canact_tick, ud->attackabletime) > 0) + ud->attackabletime = ud->canact_tick; + ud->attacktimer=add_timer(ud->attackabletime,unit_attack_timer,src->id,0); + } + return 1; + } + + range = sstatus->rhw.range; + + if(!sd || sd->status.weapon != W_BOW) range++; //Dunno why everyone but bows gets this extra range... + if(unit_is_walking(target)) range++; //Extra range when chasing + + if(!check_distance_bl(src,target,range) ) { + //Chase if required. + if(ud->state.attack_continue) { + if(sd) + clif_movetoattack(sd,target); + else + unit_walktobl(src,target,ud->chaserange,ud->state.walk_easy|2); + } + return 1; + } + if(!battle_check_range(src,target,range)) { + //Within range, but no direct line of attack + if(ud->state.attack_continue) { + if(ud->chaserange > 2) ud->chaserange-=2; + unit_walktobl(src,target,ud->chaserange,ud->state.walk_easy|2); + } + return 1; + } + + //Sync packet only for players. + //Non-players use the sync packet on the walk timer. [Skotlex] + if (tid == -1 && sd) clif_fixpos(src); + + if(DIFF_TICK(ud->attackabletime,tick) <= 0) { + if (battle_config.attack_direction_change && + (src->type&battle_config.attack_direction_change)) { + ud->dir = map_calc_dir(src, target->x,target->y ); + if (sd) sd->head_dir = ud->dir; + } + if(ud->walktimer != -1) + unit_stop_walking(src,1); + if(md) { + if (mobskill_use(md,tick,-1)) + return 1; + if (sstatus->mode&MD_ASSIST && DIFF_TICK(md->last_linktime, tick) < MIN_MOBLINKTIME) + { // Link monsters nearby [Skotlex] + md->last_linktime = tick; + map_foreachinrange(mob_linksearch, src, md->db->range2, + BL_MOB, md->class_, target, tick); + } + } + if(src->type == BL_PET && pet_attackskill((TBL_PET*)src, target->id)) + return 1; + + map_freeblock_lock(); + ud->attacktarget_lv = battle_weapon_attack(src,target,tick,0); + + if(sd && sd->status.pet_id > 0 && sd->pd && battle_config.pet_attack_support) + pet_target_check(sd,target,0); + map_freeblock_unlock(); + + ud->attackabletime = tick + sstatus->adelay; +// You can't move if you can't attack neither. + unit_set_walkdelay(src, tick, sstatus->amotion, 1); + } + + if(ud->state.attack_continue) + ud->attacktimer = add_timer(ud->attackabletime,unit_attack_timer,src->id,0); + + return 1; +} + +static int unit_attack_timer(int tid,unsigned int tick,int id,int data) { + struct block_list *bl; + bl = map_id2bl(id); + if(bl && unit_attack_timer_sub(bl, tid, tick) == 0) + unit_unattackable(bl); + return 0; +} + +/*========================================== + * Cancels an ongoing skill cast. + * flag&1: Cast-Cancel invoked. + * flag&2: Cancel only if skill is cancellable. + *------------------------------------------ + */ +int unit_skillcastcancel(struct block_list *bl,int type) +{ + struct map_session_data *sd = NULL; + struct unit_data *ud = unit_bl2ud( bl); + unsigned int tick=gettick(); + int ret=0, skill; + + nullpo_retr(0, bl); + if (!ud || ud->skilltimer==-1) + return 0; //Nothing to cancel. + + BL_CAST(BL_PC, bl, sd); + + if (type&2) { + //See if it can be cancelled. + if (!ud->state.skillcastcancel) + return 0; + + if (sd && (sd->special_state.no_castcancel2 || + (sd->special_state.no_castcancel && !map_flag_gvg(bl->m)))) //fixed flags being read the wrong way around [blackhole89] + return 0; + } + + ud->canact_tick=tick; + if(sd && pc_checkskill(sd,SA_FREECAST)) + status_freecast_switch(sd); + + if(type&1 && sd) + skill = sd->skillid_old; + else + skill = ud->skillid; + + if (skill_get_inf(skill) & INF_GROUND_SKILL) + ret=delete_timer( ud->skilltimer, skill_castend_pos ); + else + ret=delete_timer( ud->skilltimer, skill_castend_id ); + if(ret<0) + ShowError("delete timer error : skillid : %d\n",ret); + + if(bl->type==BL_MOB) ((TBL_MOB*)bl)->skillidx = -1; + + ud->skilltimer = -1; + clif_skillcastcancel(bl); + return 1; +} + +// unit_data の初期化処理 +void unit_dataset(struct block_list *bl) { + struct unit_data *ud; + nullpo_retv(ud = unit_bl2ud(bl)); + + memset( ud, 0, sizeof( struct unit_data) ); + ud->bl = bl; + ud->walktimer = -1; + ud->skilltimer = -1; + ud->attacktimer = -1; + ud->attackabletime = + ud->canact_tick = + ud->canmove_tick = gettick(); +} + +/*========================================== + * 自分をロックしているユニットの数を数える(foreachclient) + *------------------------------------------ + */ +static int unit_counttargeted_sub(struct block_list *bl, va_list ap) +{ + int id, target_lv; + struct unit_data *ud; + id = va_arg(ap,int); + target_lv = va_arg(ap,int); + if(bl->id == id) + return 0; + + ud = unit_bl2ud(bl); + + if (ud && ud->target == id && ud->attacktimer != -1 && ud->attacktarget_lv >= target_lv) + return 1; + + return 0; +} + +/*========================================== + * + *------------------------------------------ + */ +int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2) +{ + nullpo_retr(0, target); + + if(damage+damage2 <= 0) + return 0; + + return status_fix_damage(src,target,damage+damage2,clif_damage(target,target,tick,sdelay,ddelay,damage,div,type,damage2)); +} +/*========================================== + * 自分をロックしている対象の数を返す + * 戻りは整数で0以上 + *------------------------------------------ + */ +int unit_counttargeted(struct block_list *bl,int target_lv) +{ + nullpo_retr(0, bl); + return (map_foreachinrange(unit_counttargeted_sub, bl, AREA_SIZE, BL_CHAR, + bl->id, target_lv)); +} + +/*========================================== + * 見た目のサイズを変更する + *------------------------------------------ + */ +int unit_changeviewsize(struct block_list *bl,short size) +{ + nullpo_retr(0, bl); + + size=(size<0)?-1:(size>0)?1:0; + + if(bl->type == BL_PC) { + ((TBL_PC*)bl)->state.size=size; + } else if(bl->type == BL_MOB) { + ((TBL_MOB*)bl)->special_state.size=size; + } else + return 0; + if(size!=0) + clif_misceffect2(bl,421+size); + return 0; +} + +/*========================================== + * Removes a bl/ud from the map. + * Returns 1 on success. 0 if it couldn't be removed or the bl was free'd + * if clrtype is 1 (death), appropiate cleanup is performed. + * Otherwise it is assumed bl is being warped. + * On-Kill specific stuff is not performed here, look at status_damage for that. + *------------------------------------------ + */ +int unit_remove_map(struct block_list *bl, int clrtype) { + struct unit_data *ud = unit_bl2ud(bl); + struct status_change *sc = status_get_sc(bl); + nullpo_retr(0, ud); + + if(bl->prev == NULL) + return 0; //Already removed? + + map_freeblock_lock(); + + ud->target = 0; //Unlock walk/attack target. + if (ud->walktimer != -1) + unit_stop_walking(bl,0); + if (ud->attacktimer != -1) + unit_stop_attack(bl); + if (ud->skilltimer != -1) + unit_skillcastcancel(bl,0); +// Do not reset can-act delay. [Skotlex] + ud->attackabletime = ud->canmove_tick /*= ud->canact_tick*/ = gettick(); + clif_clearchar_area(bl,clrtype); + + if(sc && sc->count ) { //map-change/warp dispells. + if(sc->data[SC_BLADESTOP].timer!=-1) + status_change_end(bl,SC_BLADESTOP,-1); + if(sc->data[SC_BASILICA].timer!=-1) + status_change_end(bl,SC_BASILICA,-1); + if(sc->data[SC_ANKLE].timer != -1) + status_change_end(bl, SC_ANKLE, -1); + if (sc->data[SC_TRICKDEAD].timer != -1) + status_change_end(bl, SC_TRICKDEAD, -1); + if (sc->data[SC_BLADESTOP].timer!=-1) + status_change_end(bl,SC_BLADESTOP,-1); + if (sc->data[SC_RUN].timer!=-1) + status_change_end(bl,SC_RUN,-1); + if (sc->data[SC_DANCING].timer!=-1) // clear dance effect when warping [Valaris] + skill_stop_dancing(bl); + if (sc->data[SC_DEVOTION].timer!=-1) + status_change_end(bl,SC_DEVOTION,-1); + if (sc->data[SC_MARIONETTE].timer!=-1) + status_change_end(bl,SC_MARIONETTE,-1); + if (sc->data[SC_MARIONETTE2].timer!=-1) + status_change_end(bl,SC_MARIONETTE2,-1); + if (sc->data[SC_CLOSECONFINE].timer!=-1) + status_change_end(bl,SC_CLOSECONFINE,-1); + if (sc->data[SC_CLOSECONFINE2].timer!=-1) + status_change_end(bl,SC_CLOSECONFINE2,-1); + if (sc->data[SC_HIDING].timer!=-1) + status_change_end(bl, SC_HIDING, -1); + if (sc->data[SC_CLOAKING].timer!=-1) + status_change_end(bl, SC_CLOAKING, -1); + if (sc->data[SC_CHASEWALK].timer!=-1) + status_change_end(bl, SC_CHASEWALK, -1); + if (sc->data[SC_GOSPEL].timer != -1 && sc->data[SC_GOSPEL].val4 == BCT_SELF) + status_change_end(bl, SC_GOSPEL, -1); + } + + if (bl->type&BL_CHAR) { + skill_unit_move(bl,gettick(),4); + skill_cleartimerskill(bl); // タイマースキルクリア + } + + if(bl->type == BL_PC) { + struct map_session_data *sd = (struct map_session_data*)bl; + + //Leave/reject all invitations. + if(sd->chatID) + chat_leavechat(sd); + if(sd->trade_partner) + trade_tradecancel(sd); + if(sd->vender_id) + vending_closevending(sd); + if(sd->state.storage_flag == 1) + storage_storage_quit(sd,0); + else if (sd->state.storage_flag == 2) + storage_guild_storage_quit(sd,0); + + if(sd->party_invite>0) + party_reply_invite(sd,sd->party_invite_account,0); + if(sd->guild_invite>0) + guild_reply_invite(sd,sd->guild_invite,0); + if(sd->guild_alliance>0) + guild_reply_reqalliance(sd,sd->guild_alliance_account,0); + + pc_stop_following(sd); + pc_delinvincibletimer(sd); + + if(sd->pvp_timer!=-1) { + delete_timer(sd->pvp_timer,pc_calc_pvprank_timer); + sd->pvp_timer = -1; + } + + if(pc_issit(sd)) { + pc_setstand(sd); + skill_gangsterparadise(sd,0); + skill_rest(sd,0); + } + party_send_dot_remove(sd);//minimap dot fix [Kevin] + guild_send_dot_remove(sd); + } else if(bl->type == BL_MOB) { + struct mob_data *md = (struct mob_data*)bl; + md->target_id=0; + md->attacked_id=0; + md->state.skillstate= MSS_IDLE; + } else if (bl->type == BL_PET) { + struct pet_data *pd = (struct pet_data*)bl; + struct map_session_data *sd = pd->msd; + + if(!sd) { + map_delblock(bl); + unit_free(bl); + map_freeblock_unlock(); + return 0; + } + if (sd->pet.intimate <= 0) + { //Remove pet. + intif_delete_petdata(sd->status.pet_id); + sd->status.pet_id = 0; + sd->pd = NULL; + pd->msd = NULL; + map_delblock(bl); + unit_free(bl); + map_freeblock_unlock(); + return 0; + } + } + map_delblock(bl); + map_freeblock_unlock(); + return 1; +} + +/*========================================== + * Function to free all related resources to the bl + * if unit is on map, it is removed using clrtype 0. + *------------------------------------------ + */ + +int unit_free(struct block_list *bl) { + struct unit_data *ud = unit_bl2ud( bl ); + nullpo_retr(0, ud); + + map_freeblock_lock(); + if( bl->prev ) //Players are supposed to logout with a "warp" effect. + unit_remove_map(bl, bl->type==BL_PC?3:0); + + if( bl->type == BL_PC ) { + struct map_session_data *sd = (struct map_session_data*)bl; + if(status_isdead(bl)) + pc_setrestartvalue(sd,2); + + //Status that are not saved... + if(sd->sc.count) { + if(sd->sc.data[SC_SPURT].timer!=-1) + status_change_end(bl,SC_SPURT,-1); + if(sd->sc.data[SC_BERSERK].timer!=-1) + status_change_end(bl,SC_BERSERK,-1); + if(sd->sc.data[SC_TRICKDEAD].timer!=-1) + status_change_end(bl,SC_TRICKDEAD,-1); + if (battle_config.debuff_on_logout) { + if(sd->sc.data[SC_ORCISH].timer!=-1) + status_change_end(bl,SC_ORCISH,-1); + if(sd->sc.data[SC_STRIPWEAPON].timer!=-1) + status_change_end(bl,SC_STRIPWEAPON,-1); + if(sd->sc.data[SC_STRIPARMOR].timer!=-1) + status_change_end(bl,SC_STRIPARMOR,-1); + if(sd->sc.data[SC_STRIPSHIELD].timer!=-1) + status_change_end(bl,SC_STRIPSHIELD,-1); + if(sd->sc.data[SC_STRIPHELM].timer!=-1) + status_change_end(bl,SC_STRIPHELM,-1); + if(sd->sc.data[SC_EXTREMITYFIST].timer!=-1) + status_change_end(bl,SC_EXTREMITYFIST,-1); + if(sd->sc.data[SC_EXPLOSIONSPIRITS].timer!=-1) + status_change_end(bl,SC_EXPLOSIONSPIRITS,-1); + } + } + // Notify friends that this char logged out. [Skotlex] + clif_foreachclient(clif_friendslist_toggle_sub, sd->status.account_id, sd->status.char_id, 0); + party_send_logout(sd); + guild_send_memberinfoshort(sd,0); + pc_cleareventtimer(sd); + pc_delspiritball(sd,sd->spiritball,1); + chrif_save_scdata(sd); //Save status changes, then clear'em out from memory. [Skotlex] + pc_makesavestatus(sd); + sd->state.waitingdisconnect = 1; + pc_clean_skilltree(sd); + } else if( bl->type == BL_PET ) { + struct pet_data *pd = (struct pet_data*)bl; + struct map_session_data *sd = pd->msd; + pet_hungry_timer_delete(pd); + if (pd->a_skill) + { + aFree(pd->a_skill); + pd->a_skill = NULL; + } + if (pd->s_skill) + { + if (pd->s_skill->timer != -1) { + if (pd->s_skill->id) + delete_timer(pd->s_skill->timer, pet_skill_support_timer); + else + delete_timer(pd->s_skill->timer, pet_heal_timer); + } + aFree(pd->s_skill); + pd->s_skill = NULL; + } + if(pd->recovery) + { + if(pd->recovery->timer != -1) + delete_timer(pd->recovery->timer, pet_recovery_timer); + aFree(pd->recovery); + pd->recovery = NULL; + } + if(pd->bonus) + { + if (pd->bonus->timer != -1) + delete_timer(pd->bonus->timer, pet_skill_bonus_timer); + aFree(pd->bonus); + pd->bonus = NULL; + } + if (pd->loot) + { + if (pd->loot->item) + aFree(pd->loot->item); + aFree (pd->loot); + pd->loot = NULL; + } + if (sd) { + if(sd->pet.intimate > 0) + intif_save_petdata(sd->status.account_id,&sd->pet); + sd->pd = NULL; + } + } else if(bl->type == BL_MOB) { + struct mob_data *md = (struct mob_data*)bl; + if(md->deletetimer!=-1) + delete_timer(md->deletetimer,mob_timer_delete); + md->deletetimer=-1; + if(md->lootitem) { + aFree(md->lootitem); + md->lootitem=NULL; + } + if (md->guardian_data) + { + if (md->guardian_data->number < MAX_GUARDIANS) + md->guardian_data->castle->guardian[md->guardian_data->number].id = 0; + aFree(md->guardian_data); + md->guardian_data = NULL; + } + if (md->spawn && md->spawn_n < 0 && --(md->spawn->num) == 0) + { //Spawning data is not attached to the map, so free it + //if this is the last mob who is pointing at it. + aFree(md->spawn); + md->spawn = NULL; + } + if(md->base_status) { + aFree(md->base_status); + md->base_status = NULL; + } + if(mob_is_clone(md->class_)) + mob_clone_delete(md->class_); + } + + skill_clear_unitgroup(bl); + status_change_clear(bl,1); + if (bl->type != BL_PC) + { //Players are handled by map_quit + map_deliddb(bl); + map_freeblock(bl); + } + map_freeblock_unlock(); + return 0; +} + +int do_init_unit(void) { + add_timer_func_list(unit_attack_timer, "unit_attack_timer"); + add_timer_func_list(unit_walktoxy_timer,"unit_walktoxy_timer"); + add_timer_func_list(unit_walktobl_sub, "unit_walktobl_sub"); + + return 0; +} + +int do_final_unit(void) { + // nothing to do + return 0; +} + diff --git a/src/map/unit.h b/src/map/unit.h index 8fc0343bc..4940c47a6 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -1,70 +1,70 @@ -// Copyright (c) jAthena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder -// Merged originally from jA by Skotlex -#ifndef _UNIT_H_ -#define _UNIT_H_ - -#include "map.h" - -// PC, MOB, PET に共通する処理を1つにまとめる計画 - -// 歩行開始 -// 戻り値は、0 ( 成功 ), 1 ( 失敗 ) -int unit_walktoxy( struct block_list *bl, int x, int y, int easy); -int unit_walktobl( struct block_list *bl, struct block_list *target, int range, int easy); -int unit_run(struct block_list *bl); - -// 歩行停止 -// typeは以下の組み合わせ : -// 1: 位置情報の送信( この関数の後に位置情報を送信する場合は不要 ) -// 2: ダメージディレイ有り -// 4: 不明(MOBのみ?) -int unit_stop_walking(struct block_list *bl,int type); -int unit_can_move(struct block_list *bl); -int unit_is_walking(struct block_list *bl); -int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int type); - -// 位置の強制移動(吹き飛ばしなど) -int unit_movepos(struct block_list *bl,int dst_x,int dst_y, int easy, int checkpath); -int unit_warp(struct block_list *bl, int map, short x, short y, int type); -int unit_setdir(struct block_list *bl,unsigned char dir); -int unit_getdir(struct block_list *bl); - -// そこまで歩行でたどり着けるかの判定 -int unit_can_reach_pos(struct block_list *bl,int x,int y,int easy); -int unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, int easy, short *x, short *y); - -// 攻撃関連 -int unit_stop_attack(struct block_list *bl); -int unit_attack(struct block_list *src,int target_id,int type); - -// int unit_setpos( struct block_list *bl, const char* map, int x, int y); - -// スキル使用 -int unit_skilluse_id(struct block_list *src, int target_id, int skill_num, int skill_lv); -int unit_skilluse_pos(struct block_list *src, int skill_x, int skill_y, int skill_num, int skill_lv); - -// スキル使用( 補正済みキャスト時間、キャンセル不可設定付き ) -int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int skill_lv, int casttime, int castcancel); -int unit_skilluse_pos2( struct block_list *src, int skill_x, int skill_y, int skill_num, int skill_lv, int casttime, int castcancel); - -// 詠唱キャンセル -int unit_skillcastcancel(struct block_list *bl,int type); - -int unit_counttargeted(struct block_list *bl,int target_lv); - -// unit_data の初期化処理 -void unit_dataset(struct block_list *bl); - -int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2); -// その他 -struct unit_data* unit_bl2ud(struct block_list *bl); -int unit_remove_map(struct block_list *bl, int clrtype); -int unit_free(struct block_list *bl); -int unit_changeviewsize(struct block_list *bl,short size); - -// 初期化ルーチン -int do_init_unit(void); -int do_final_unit(void); - -#endif /* _UNIT_H_ */ +// Copyright (c) jAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder +// Merged originally from jA by Skotlex +#ifndef _UNIT_H_ +#define _UNIT_H_ + +#include "map.h" + +// PC, MOB, PET に共通する処理を1つにまとめる計画 + +// 歩行開始 +// 戻り値は、0 ( 成功 ), 1 ( 失敗 ) +int unit_walktoxy( struct block_list *bl, int x, int y, int easy); +int unit_walktobl( struct block_list *bl, struct block_list *target, int range, int easy); +int unit_run(struct block_list *bl); + +// 歩行停止 +// typeは以下の組み合わせ : +// 1: 位置情報の送信( この関数の後に位置情報を送信する場合は不要 ) +// 2: ダメージディレイ有り +// 4: 不明(MOBのみ?) +int unit_stop_walking(struct block_list *bl,int type); +int unit_can_move(struct block_list *bl); +int unit_is_walking(struct block_list *bl); +int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int type); + +// 位置の強制移動(吹き飛ばしなど) +int unit_movepos(struct block_list *bl,int dst_x,int dst_y, int easy, int checkpath); +int unit_warp(struct block_list *bl, int map, short x, short y, int type); +int unit_setdir(struct block_list *bl,unsigned char dir); +int unit_getdir(struct block_list *bl); + +// そこまで歩行でたどり着けるかの判定 +int unit_can_reach_pos(struct block_list *bl,int x,int y,int easy); +int unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, int easy, short *x, short *y); + +// 攻撃関連 +int unit_stop_attack(struct block_list *bl); +int unit_attack(struct block_list *src,int target_id,int type); + +// int unit_setpos( struct block_list *bl, const char* map, int x, int y); + +// スキル使用 +int unit_skilluse_id(struct block_list *src, int target_id, int skill_num, int skill_lv); +int unit_skilluse_pos(struct block_list *src, int skill_x, int skill_y, int skill_num, int skill_lv); + +// スキル使用( 補正済みキャスト時間、キャンセル不可設定付き ) +int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int skill_lv, int casttime, int castcancel); +int unit_skilluse_pos2( struct block_list *src, int skill_x, int skill_y, int skill_num, int skill_lv, int casttime, int castcancel); + +// 詠唱キャンセル +int unit_skillcastcancel(struct block_list *bl,int type); + +int unit_counttargeted(struct block_list *bl,int target_lv); + +// unit_data の初期化処理 +void unit_dataset(struct block_list *bl); + +int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2); +// その他 +struct unit_data* unit_bl2ud(struct block_list *bl); +int unit_remove_map(struct block_list *bl, int clrtype); +int unit_free(struct block_list *bl); +int unit_changeviewsize(struct block_list *bl,short size); + +// 初期化ルーチン +int do_init_unit(void); +int do_final_unit(void); + +#endif /* _UNIT_H_ */ -- cgit v1.2.3-70-g09d2 From a2b971ef0af9491bdbd93e07e600a69df97a46a1 Mon Sep 17 00:00:00 2001 From: skotlex Date: Fri, 18 Aug 2006 13:49:24 +0000 Subject: - Changed unit_free so that it receives which cleartype should be used when the character is still on a map. Used this on status_damage so that mobs that do not respawn when killed will properly display the death animation. - Should have fixed the signed/unsigned comparison warnings in the main regen function. - Fixed Energy Coat consuming 10x less SP per hit than it should. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@8339 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 5 +++++ src/map/battle.c | 2 +- src/map/map.c | 10 +++++----- src/map/mercenary.c | 6 +++--- src/map/mob.c | 11 +++++------ src/map/npc.c | 2 +- src/map/pet.c | 2 +- src/map/script.c | 2 +- src/map/status.c | 14 +++++++------- src/map/unit.c | 10 +++++----- src/map/unit.h | 2 +- 11 files changed, 35 insertions(+), 31 deletions(-) (limited to 'src/map/unit.h') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 6d9881fe4..29e3b4729 100644 --- a/Changelog-Trunk.txt +++ b/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. 2006/08/18 + * Changed unit_free so that it receives which cleartype should be used when + the character is still on a map. Used this on status_damage so that mobs + that do not respawn when killed will properly display the death animation. + [Skotlex] + * Fixed Energy Coat consuming 10x less SP per hit than it should. * Fixed signed/unsigned comparison issues with natural heal system [Toms] 2006/08/17 * Vaporize will no fail when the homun is dead. [Skotlex] diff --git a/src/map/battle.c b/src/map/battle.c index 4f2e03e5f..0441164b9 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -375,7 +375,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,i int per = 100*status->sp / status->max_sp; per /=20; //Uses 20% SP intervals. //SP Cost: 1% + 0.5% per every 20% SP - if (!status_charge(bl, 0, (10+5*per)*status->max_sp/10000)) + if (!status_charge(bl, 0, (10+5*per)*status->max_sp/1000)) status_change_end( bl,SC_ENERGYCOAT,-1 ); //Reduction: 6% + 6% every 20% damage -= damage * 6 * (1+per) / 100; diff --git a/src/map/map.c b/src/map/map.c index 422d1f3a9..6d359e412 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -1670,9 +1670,9 @@ int map_quit(struct map_session_data *sd) { npc_script_event(sd, NPCE_LOGOUT); sd->state.waitingdisconnect = 1; - if (sd->pd) unit_free(&sd->pd->bl); - if (sd->hd) unit_free(&sd->hd->bl); - unit_free(&sd->bl); + if (sd->pd) unit_free(&sd->pd->bl,0); + if (sd->hd) unit_free(&sd->hd->bl,0); + unit_free(&sd->bl,3); chrif_save(sd,1); } else { //Try to free some data, without saving anything (this could be invoked on map server change. [Skotlex] if (sd->bl.prev != NULL) @@ -1991,7 +1991,7 @@ int mob_cache_cleanup_sub(struct block_list *bl, va_list ap) { md->status.hp < md->status.max_hp) return 0; //Do not remove damaged mobs. - unit_free(&md->bl); + unit_free(&md->bl,0); return 1; } @@ -3617,7 +3617,7 @@ int cleanup_sub(struct block_list *bl, va_list ap) { npc_unload((struct npc_data *)bl); break; case BL_MOB: - unit_free(bl); + unit_free(bl,0); break; case BL_PET: //There is no need for this, the pet is removed together with the player. [Skotlex] diff --git a/src/map/mercenary.c b/src/map/mercenary.c index fff6a23f1..00759fe0d 100644 --- a/src/map/mercenary.c +++ b/src/map/mercenary.c @@ -170,7 +170,7 @@ int merc_hom_delete(struct homun_data *hd, int emote) sd = hd->master; if (!sd) - return unit_free(&hd->bl); + return unit_free(&hd->bl,1); if (emote >= 0) clif_emotion(&sd->bl, emote); @@ -180,7 +180,7 @@ int merc_hom_delete(struct homun_data *hd, int emote) // Send homunculus_dead to client sd->homunculus.hp = 0; clif_hominfo(sd, hd, 0); - return unit_free(&hd->bl); + return unit_free(&hd->bl,1); } int merc_hom_calc_skilltree(struct map_session_data *sd) @@ -342,7 +342,7 @@ int merc_hom_evolution(struct homun_data *hd) x = hd->bl.x; y = hd->bl.y; merc_hom_vaporize(sd, 0); - unit_free(&hd->bl); + unit_free(&hd->bl,0); merc_call_homunculus(sd, x, y); clif_emotion(&sd->bl, 21) ; //no1 clif_misceffect2(&hd->bl,568); diff --git a/src/map/mob.c b/src/map/mob.c index 27743fd26..84671a70d 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -418,7 +418,7 @@ static int mob_spawn_guardian_sub(int tid,unsigned int tick,int id,int data) guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0); guild_castledatasave(md->guardian_data->castle->castle_id, 18+md->guardian_data->number,0); } - unit_free(&md->bl); //Remove guardian. + unit_free(&md->bl,0); //Remove guardian. } return 0; } @@ -594,7 +594,7 @@ int mob_setdelayspawn(struct mob_data *md) if (!md->spawn) //Doesn't has respawn data! - return unit_free(&md->bl); + return unit_free(&md->bl,1); spawntime1 = md->last_spawntime + md->spawn->delay1; spawntime2 = md->last_deadtime + md->spawn->delay2; @@ -1494,8 +1494,7 @@ int mob_timer_delete(int tid, unsigned int tick, int id, int data) return 0; //?? //for Alchemist CANNIBALIZE [Lupus] ((TBL_MOB*)bl)->deletetimer = -1; - unit_remove_map(bl, 3); - unit_free(bl); + unit_free(bl,3); return 0; } @@ -2205,7 +2204,7 @@ int mob_guardian_guildchange(struct block_list *bl,va_list ap) guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0); guild_castledatasave(md->guardian_data->castle->castle_id, 18+md->guardian_data->number,0); } - unit_free(&md->bl); //Remove guardian. + unit_free(&md->bl,0); //Remove guardian. } return 0; } @@ -2217,7 +2216,7 @@ int mob_guardian_guildchange(struct block_list *bl,va_list ap) md->guardian_data->castle->guardian[md->guardian_data->number].visible = 0; guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0); guild_castledatasave(md->guardian_data->castle->castle_id, 18+md->guardian_data->number,0); - unit_free(&md->bl); + unit_free(&md->bl,0); return 0; } diff --git a/src/map/npc.c b/src/map/npc.c index 90345feea..8b1f39b72 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -2780,7 +2780,7 @@ static int npc_cleanup_sub (struct block_list *bl, va_list ap) { npc_unload((struct npc_data *)bl); break; case BL_MOB: - unit_free(bl); + unit_free(bl,0); break; } diff --git a/src/map/pet.c b/src/map/pet.c index 68b0510e0..895ad5e89 100644 --- a/src/map/pet.c +++ b/src/map/pet.c @@ -364,7 +364,7 @@ static int pet_return_egg(struct map_session_data *sd, struct pet_data *pd) pd->state.skillbonus = 0; status_calc_pc(sd,0); } - unit_free(&pd->bl); + unit_free(&pd->bl,0); sd->status.pet_id = 0; return 1; diff --git a/src/map/script.c b/src/map/script.c index a8bedd633..070722866 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -11795,7 +11795,7 @@ int buildin_mobremove(struct script_state *st) { bl = map_id2bl(id); if (bl && bl->type == BL_MOB) - unit_free(bl); + unit_free(bl,0); return 0; } diff --git a/src/map/status.c b/src/map/status.c index 69716f387..99449554b 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -712,7 +712,7 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s memset(®en->tick, 0, sizeof(regen->tick)); } if(flag&4) //Delete from memory. (also invokes map removal code) - unit_free(target); + unit_free(target,1); else if(flag&2) //remove from map unit_remove_map(target,1); @@ -6843,13 +6843,13 @@ static int status_natural_heal(DBKey key,void * data,va_list app) rate/=2; regen->tick.hp += rate; - if(regen->tick.hp >= battle_config.natural_healhp_interval) + if(regen->tick.hp >= (unsigned int)battle_config.natural_healhp_interval) { val = 0; do { val += regen->hp; regen->tick.hp -= battle_config.natural_healhp_interval; - } while(regen->tick.hp >= battle_config.natural_healhp_interval); + } while(regen->tick.hp >= (unsigned int)battle_config.natural_healhp_interval); if (status_heal(bl, val, 0, 1) < val) flag&=~RGN_SHP; //full. } @@ -6858,7 +6858,7 @@ static int status_natural_heal(DBKey key,void * data,va_list app) { regen->tick.shp += natural_heal_diff_tick * regen->rate.shp; - while(regen->tick.shp >= battle_config.natural_heal_skill_interval) + while(regen->tick.shp >= (unsigned int)battle_config.natural_heal_skill_interval) { regen->tick.shp -= battle_config.natural_heal_skill_interval; if(status_heal(bl, regen->shp, 0, 3) < regen->shp) @@ -6869,13 +6869,13 @@ static int status_natural_heal(DBKey key,void * data,va_list app) { regen->tick.sp += natural_heal_diff_tick*(regen->rate.sp+bonus); - if(regen->tick.sp >= battle_config.natural_healsp_interval) + if(regen->tick.sp >= (unsigned int)battle_config.natural_healsp_interval) { val = 0; do { val += regen->sp; regen->tick.sp -= battle_config.natural_healsp_interval; - } while(regen->tick.sp >= battle_config.natural_healsp_interval); + } while(regen->tick.sp >= (unsigned int)battle_config.natural_healsp_interval); if (status_heal(bl, 0, val, 1) < val) flag&=~RGN_SSP; //full. } @@ -6883,7 +6883,7 @@ static int status_natural_heal(DBKey key,void * data,va_list app) if(flag&RGN_SSP) { regen->tick.ssp += natural_heal_diff_tick * regen->rate.ssp; - while(regen->tick.ssp >= battle_config.natural_heal_skill_interval) + while(regen->tick.ssp >= (unsigned int)battle_config.natural_heal_skill_interval) { regen->tick.ssp -= battle_config.natural_heal_skill_interval; if(status_heal(bl, 0, regen->ssp, 3) < regen->ssp) diff --git a/src/map/unit.c b/src/map/unit.c index 7c1e011ad..ea1efcca7 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1579,7 +1579,7 @@ int unit_remove_map(struct block_list *bl, int clrtype) { if(pd->pet.intimate <= 0) { clif_clearchar_area(bl,clrtype); map_delblock(bl); - unit_free(bl); + unit_free(bl,0); map_freeblock_unlock(); return 0; } @@ -1591,7 +1591,7 @@ int unit_remove_map(struct block_list *bl, int clrtype) { clif_emotion(bl, 28) ; //sob clif_clearchar_area(bl,clrtype); map_delblock(bl); - unit_free(bl); + unit_free(bl,0); map_freeblock_unlock(); return 0; } @@ -1604,17 +1604,17 @@ int unit_remove_map(struct block_list *bl, int clrtype) { /*========================================== * Function to free all related resources to the bl - * if unit is on map, it is removed using clrtype 0. + * if unit is on map, it is removed using the clrtype specified *------------------------------------------ */ -int unit_free(struct block_list *bl) { +int unit_free(struct block_list *bl, int clrtype) { struct unit_data *ud = unit_bl2ud( bl ); nullpo_retr(0, ud); map_freeblock_lock(); if( bl->prev ) //Players are supposed to logout with a "warp" effect. - unit_remove_map(bl, bl->type==BL_PC?3:0); + unit_remove_map(bl, clrtype); if( bl->type == BL_PC ) { struct map_session_data *sd = (struct map_session_data*)bl; diff --git a/src/map/unit.h b/src/map/unit.h index 4940c47a6..007cda5e6 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -60,7 +60,7 @@ int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int // その他 struct unit_data* unit_bl2ud(struct block_list *bl); int unit_remove_map(struct block_list *bl, int clrtype); -int unit_free(struct block_list *bl); +int unit_free(struct block_list *bl, int clrtype); int unit_changeviewsize(struct block_list *bl,short size); // 初期化ルーチン -- cgit v1.2.3-70-g09d2 From 67213795d8e2c020d0e7d743e98238b65b35630e Mon Sep 17 00:00:00 2001 From: toms Date: Fri, 18 Aug 2006 14:15:49 +0000 Subject: - Little code cleanup - Cleaned merc_hom_evolution to avoid free'ing/realloc'ing - Fixed "args of aFree is freed pointer" on Homunc deletion git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@8341 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 3 +++ src/map/map.c | 3 --- src/map/mercenary.c | 30 +++++++++++++++++++----------- src/map/pet.c | 3 --- src/map/skill.c | 3 --- src/map/unit.c | 6 +++--- src/map/unit.h | 2 ++ 7 files changed, 27 insertions(+), 23 deletions(-) (limited to 'src/map/unit.h') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 29e3b4729..24be9c9e0 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -4,6 +4,9 @@ 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. 2006/08/18 + * Little code cleanup [Toms] + * Cleaned merc_hom_evolution to avoid free'ing/realloc'ing [Toms] + * Fixed "args of aFree is freed pointer" on Homunc deletion [Toms] * Changed unit_free so that it receives which cleartype should be used when the character is still on a map. Used this on status_damage so that mobs that do not respawn when killed will properly display the death animation. diff --git a/src/map/map.c b/src/map/map.c index 6d359e412..c3e7d8f67 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -196,9 +196,6 @@ char wisp_server_name[NAME_LENGTH] = "Server"; // can be modified in char-server int console = 0; int enable_spy = 0; //To enable/disable @spy commands, which consume too much cpu time when sending packets. [Skotlex] -static const int dirx[8]={0,-1,-1,-1,0,1,1,1}; -static const int diry[8]={1,1,0,-1,-1,-1,0,1}; - /*========================================== * 全map鯖?計での接??設定 * (char鯖から送られてくる) diff --git a/src/map/mercenary.c b/src/map/mercenary.c index 00759fe0d..5c3378540 100644 --- a/src/map/mercenary.c +++ b/src/map/mercenary.c @@ -34,9 +34,6 @@ #include "mercenary.h" #include "charsave.h" -static int dirx[8]={0,-1,-1,-1,0,1,1,1}; //[orn] -static int diry[8]={1,1,0,-1,-1,-1,0,1}; //[orn] - //Better equiprobability than rand()% [orn] #define rand(a, b) a+(int) ((float)(b-a+1)*rand()/(RAND_MAX+1.0)) @@ -180,7 +177,7 @@ int merc_hom_delete(struct homun_data *hd, int emote) // Send homunculus_dead to client sd->homunculus.hp = 0; clif_hominfo(sd, hd, 0); - return unit_free(&hd->bl,1); + return unit_remove_map(&hd->bl,0); } int merc_hom_calc_skilltree(struct map_session_data *sd) @@ -323,10 +320,22 @@ int merc_hom_levelup(struct homun_data *hd) return 1 ; } +int merc_hom_change_class(struct homun_data *hd, short class_) +{ + int i; + i = search_homunculusDB_index(class_,HOMUNCULUS_CLASS); + if(i < 0) { + return 0; + } + hd->homunculusDB = &homunculus_db[i]; + hd->master->homunculus.class_ = class_; + status_set_viewdata(&hd->bl, class_); + return 1; +} + int merc_hom_evolution(struct homun_data *hd) { struct map_session_data *sd; - short x,y; nullpo_retr(0, hd); if(!hd->homunculusDB->evo_class) @@ -337,13 +346,12 @@ int merc_hom_evolution(struct homun_data *hd) sd = hd->master; if (!sd) return 0; - //TODO: Clean this up to avoid free'ing/realloc'ing. - sd->homunculus.class_ = hd->homunculusDB->evo_class; - x = hd->bl.x; - y = hd->bl.y; merc_hom_vaporize(sd, 0); - unit_free(&hd->bl,0); - merc_call_homunculus(sd, x, y); + + if (!merc_hom_change_class(hd, hd->homunculusDB->evo_class)) + ShowError("merc_hom_evolution: Can't evoluate homunc from %d to %d", hd->master->homunculus.class_, hd->homunculusDB->evo_class); + + merc_call_homunculus(sd, hd->bl.x, hd->bl.y); clif_emotion(&sd->bl, 21) ; //no1 clif_misceffect2(&hd->bl,568); return 1 ; diff --git a/src/map/pet.c b/src/map/pet.c index 895ad5e89..48427c4fc 100644 --- a/src/map/pet.c +++ b/src/map/pet.c @@ -34,9 +34,6 @@ struct pet_db pet_db[MAX_PET_DB]; static struct eri *item_drop_ers; //For loot drops delay structures. static struct eri *item_drop_list_ers; -static int dirx[8]={0,-1,-1,-1,0,1,1,1}; -static int diry[8]={1,1,0,-1,-1,-1,0,1}; - int pet_hungry_val(struct pet_data *pd) { nullpo_retr(0, pd); diff --git a/src/map/skill.c b/src/map/skill.c index 05592fefa..ff184fb20 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -627,9 +627,6 @@ const struct skill_name_db skill_names[] = { { 0, "UNKNOWN_SKILL", "Unknown_Skill" } }; -static const int dirx[8]={0,-1,-1,-1,0,1,1,1}; -static const int diry[8]={1,1,0,-1,-1,-1,0,1}; - static struct eri *skill_unit_ers = NULL; //For handling skill_unit's [Skotlex] static struct eri *skill_timer_ers = NULL; //For handling skill_timerskills [Skotlex] diff --git a/src/map/unit.c b/src/map/unit.c index ea1efcca7..4d6fdc29f 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -15,7 +15,7 @@ #include "pc.h" #include "mob.h" #include "pet.h" -#include "mercenary.h" ///[orn] +#include "mercenary.h" #include "skill.h" #include "clif.h" #include "npc.h" @@ -30,8 +30,8 @@ #include "chrif.h" #include "script.h" -static int dirx[8]={0,-1,-1,-1,0,1,1,1}; -static int diry[8]={1,1,0,-1,-1,-1,0,1}; +const int dirx[8]={0,-1,-1,-1,0,1,1,1}; +const int diry[8]={1,1,0,-1,-1,-1,0,1}; struct unit_data* unit_bl2ud(struct block_list *bl) { if( bl == NULL) return NULL; diff --git a/src/map/unit.h b/src/map/unit.h index 007cda5e6..1e4ff3956 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -67,4 +67,6 @@ int unit_changeviewsize(struct block_list *bl,short size); int do_init_unit(void); int do_final_unit(void); +extern const int dirx[8]; +extern const int diry[8]; #endif /* _UNIT_H_ */ -- cgit v1.2.3-70-g09d2 From 8cf58f2846e8a701fe61a149c5bf532732572780 Mon Sep 17 00:00:00 2001 From: skotlex Date: Thu, 7 Sep 2006 17:40:46 +0000 Subject: - Removed the Warmth "stacking" code. - Added back the effect of /doridori to skill-SP regen - Implemented a rough version of Angel of the Sun/Moon/Stars, it has a low chance of triggering on doridori-boosted SP-regen events. - Added sg_angel_skill_ratio to specify rate at which the Angel skill triggers. - Added unit_cancel_combo which takes care of ending a combo time and resuming normal attack 'inmediately' - Cleaned up some the SG_HATE code, you can't change hate targets anymore. - Increased duration of Miracle of the Sun/Moon/Stars to one hour. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@8664 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 12 ++++++++++++ conf-tmpl/Changelog.txt | 4 ++++ conf-tmpl/battle/skill.conf | 5 ++++- src/map/battle.c | 4 +++- src/map/battle.h | 1 + src/map/pc.c | 3 +-- src/map/skill.c | 33 ++++++++++++++++++++------------- src/map/status.c | 25 +++++++++++++++++-------- src/map/unit.c | 21 +++++++++++++++++++++ src/map/unit.h | 3 +-- 10 files changed, 84 insertions(+), 27 deletions(-) (limited to 'src/map/unit.h') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 6d31bd83a..710b656fb 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -3,6 +3,18 @@ Date Added AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK. IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. +2006/09/07 + * Removed the Warmth "stacking" code. [Skotlex] + * Added back the effect of /doridori to skill-SP regen [Skotlex] + * Implemented a rough version of Angel of the Sun/Moon/Stars, it has a low + chance of triggering on doridori-boosted SP-regen events. However, it has + no client-side messages yet (need to add these in) [Skotlex] + * Added sg_angel_skill_ratio to specify rate at which the Angel skill + triggers. [Skotlex] + * Added unit_cancel_combo which takes care of ending a combo time and + resuming normal attack 'inmediately' [Skotlex] + * Cleaned up some the SG_HATE code, you can't change hate targets anymore. + [Skotlex] 2006/09/06 * Fixed the memset in status_calc_pc, corrects some mysterious bugs such as item-drop bonuses suddenly not working anymore. [Skotlex] diff --git a/conf-tmpl/Changelog.txt b/conf-tmpl/Changelog.txt index 43da8f25d..c7745e453 100644 --- a/conf-tmpl/Changelog.txt +++ b/conf-tmpl/Changelog.txt @@ -1,6 +1,10 @@ Date Added 2006/09/07 + * Added sg_angel_skill_ratio to specify rate at which the Angel skill + triggers. [Skotlex] + * Increased duration of Miracle of the Sun/Moon/Stars to one hour. + [Skotlex] * Changed gvg_short_attack_damage_rate to 80, as leaked X.2 [Vicious] 2006/09/06 * Reverted back the default view/chase range of mobs to 100% since eA now diff --git a/conf-tmpl/battle/skill.conf b/conf-tmpl/battle/skill.conf index 63bb739c7..9146101b8 100644 --- a/conf-tmpl/battle/skill.conf +++ b/conf-tmpl/battle/skill.conf @@ -262,4 +262,7 @@ allow_es_magic_player: no sg_miracle_skill_ratio: 1 //Miracle of the Sun, Moon and Stars skill duration in milisecons -sg_miracle_skill_duration: 600000 +sg_miracle_skill_duration: 3600000 + +//Angel of the Sun, Moon and Stars skill ratio (100% = 10000) +sg_angel_skill_ratio: 1 diff --git a/src/map/battle.c b/src/map/battle.c index 75d48532e..a8aa4e988 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -3753,7 +3753,8 @@ static const struct battle_data_short { { "mob_luk_status_def", &battle_config.mob_luk_sc_def }, { "pc_max_status_def", &battle_config.pc_max_sc_def }, { "mob_max_status_def", &battle_config.mob_max_sc_def }, - { "sg_miracle_skill_ratio", &battle_config.sg_miracle_skill_ratio }, + { "sg_miracle_skill_ratio", &battle_config.sg_miracle_skill_ratio }, + { "sg_angel_skill_ratio", &battle_config.sg_angel_skill_ratio }, { "autospell_stacking", &battle_config.autospell_stacking }, { "override_mob_names", &battle_config.override_mob_names }, { "min_chat_delay", &battle_config.min_chat_delay }, @@ -4189,6 +4190,7 @@ void battle_set_defaults() { battle_config.pc_max_sc_def = 10000; battle_config.mob_max_sc_def = 5000; battle_config.sg_miracle_skill_ratio=1; + battle_config.sg_angel_skill_ratio=1; battle_config.sg_miracle_skill_duration=600000; battle_config.autospell_stacking = 0; battle_config.override_mob_names = 0; diff --git a/src/map/battle.h b/src/map/battle.h index f5eb6e666..56ee63cce 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -432,6 +432,7 @@ extern struct Battle_Config { unsigned short pc_max_sc_def; unsigned short mob_max_sc_def; + unsigned short sg_angel_skill_ratio; unsigned short sg_miracle_skill_ratio; int sg_miracle_skill_duration; unsigned short autospell_stacking; //Enables autospell cards to stack. [Skotlex] diff --git a/src/map/pc.c b/src/map/pc.c index 26afaf835..4af78ffe3 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -796,8 +796,7 @@ int pc_reg_received(struct map_session_data *sd) sd->feel_map[i].index = 0; sd->feel_map[i].m = -1; } - sd->hate_mob[i] = pc_readglobalreg(sd,hate_var[i]) - 1; - + sd->hate_mob[i] = pc_readglobalreg(sd,hate_var[i])-1; } if ((i = pc_checkskill(sd,RG_PLAGIARISM)) > 0) { diff --git a/src/map/skill.c b/src/map/skill.c index 6d84b7514..531cb9857 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -5408,28 +5408,36 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in break; case SG_HATE: - if (sd) { + if (sd && skilllv <= 3) { clif_skill_nodamage(src,bl,skillid,skilllv,1); + if (sd->hate_mob[skilllv-1] != -1) + { //Can't change hate targets. + clif_skill_fail(sd,skillid,0,0); + break; + } if(dstsd) //PC { sd->hate_mob[skilllv-1] = dstsd->status.class_; pc_setglobalreg(sd,"PC_HATE_MOB_STAR",sd->hate_mob[skilllv-1]+1); clif_hate_mob(sd,skilllv,sd->hate_mob[skilllv-1]); + break; } - else if(dstmd) // mob + if(dstmd) // mob { + if (sd->hate_mob[skilllv-1] || tstatus->size != skilllv-1) + { //Can't change hate targets / wrong target size + clif_skill_fail(sd,skillid,0,0); + break; + } switch(skilllv) { case 1: - if (tstatus->size==0) - { - sd->hate_mob[0] = dstmd->class_; - pc_setglobalreg(sd,"PC_HATE_MOB_SUN",sd->hate_mob[0]+1); - clif_hate_mob(sd,skilllv,sd->hate_mob[skilllv-1]); - } else clif_skill_fail(sd,skillid,0,0); + sd->hate_mob[0] = dstmd->class_; + pc_setglobalreg(sd,"PC_HATE_MOB_SUN",sd->hate_mob[0]+1); + clif_hate_mob(sd,skilllv,sd->hate_mob[skilllv-1]); break; case 2: - if (tstatus->size==1 && tstatus->max_hp>=6000) + if (tstatus->max_hp>=6000) { sd->hate_mob[1] = dstmd->class_; pc_setglobalreg(sd,"PC_HATE_MOB_MOON",sd->hate_mob[1]+1); @@ -5437,16 +5445,13 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in } else clif_skill_fail(sd,skillid,0,0); break; case 3: - if (tstatus->size==2 && tstatus->max_hp>=20000) + if (tstatus->max_hp>=20000) { sd->hate_mob[2] = dstmd->class_; pc_setglobalreg(sd,"PC_HATE_MOB_STAR",sd->hate_mob[2]+1); clif_hate_mob(sd,skilllv,sd->hate_mob[skilllv-1]); } else clif_skill_fail(sd,skillid,0,0); break; - default: - clif_skill_fail(sd,skillid,0,0); - break; } } } @@ -8088,6 +8093,8 @@ int skill_check_condition (struct map_session_data *sd, int skill, int lv, int t } else if(sc->data[SC_COMBO].val1 == skill) break; //Combo ready. + //Cancel combo wait. + unit_cancel_combo(&sd->bl); return 0; case BD_ADAPTATION: /* 繧「繝峨Μ繝 */ { diff --git a/src/map/status.c b/src/map/status.c index 352d0da62..e561b7d91 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -4701,13 +4701,6 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val if (sc->data[type].val2 > val2) return 0; break; - case SC_WARM: - { //Fetch the Group, half the attack interval. [Skotlex] - struct skill_unit_group *group = (struct skill_unit_group *)sc->data[type].val4; - if (group) - group->interval/=2; - return 1; - } case SC_STUN: case SC_SLEEP: case SC_POISON: @@ -7012,8 +7005,24 @@ static int status_natural_heal(DBKey key,void * data,va_list app) sregen->tick.sp += natural_heal_diff_tick * sregen->rate.sp; while(sregen->tick.sp >= (unsigned int)battle_config.natural_heal_skill_interval) { + val = sregen->sp; + if (sd && sd->doridori_counter) { + val*=2; + sd->doridori_counter--; + if ( + (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR && + rand()%10000 < battle_config.sg_angel_skill_ratio + ) { //Angel of the Sun/Moon/Star + malloc_set(sd->hate_mob, 0, sizeof(sd->hate_mob)); + pc_setglobalreg(sd,"PC_HATE_MOB_STAR", 0); + pc_setglobalreg(sd,"PC_HATE_MOB_SUN", 0); + pc_setglobalreg(sd,"PC_HATE_MOB_MOON", 0); + pc_resetfeel(sd); + //TODO: Figure out how to make the client-side msg show up. + } + } sregen->tick.sp -= battle_config.natural_heal_skill_interval; - if(status_heal(bl, 0, sregen->sp, 3) < sregen->sp) + if(status_heal(bl, 0, val, 3) < val) break; //Full } } diff --git a/src/map/unit.c b/src/map/unit.c index c36c14971..2db6108aa 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1139,6 +1139,27 @@ int unit_attack(struct block_list *src,int target_id,int type) return 0; } +//Cancels an ongoing combo, resets attackable time and restarts the +//attack timer to resume attacking after amotion time. [Skotlex] +int unit_cancel_combo(struct block_list *bl) +{ + struct unit_data *ud; + + if (!status_change_end(bl, SC_COMBO, -1)) + return 0; //Combo wasn't active. + + ud = unit_bl2ud(bl); + nullpo_retr(0, ud); + + ud->attackabletime = gettick() + status_get_amotion(bl); + + if (ud->attacktimer == -1) + return 1; //Nothing more to do. + + delete_timer(ud->attacktimer, unit_attack_timer); + ud->attacktimer=add_timer(ud->attackabletime,unit_attack_timer,bl->id,0); + return 1; +} /*========================================== * *------------------------------------------ diff --git a/src/map/unit.h b/src/map/unit.h index 1e4ff3956..7331f4ca5 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -37,8 +37,7 @@ int unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, i // 攻撃関連 int unit_stop_attack(struct block_list *bl); int unit_attack(struct block_list *src,int target_id,int type); - -// int unit_setpos( struct block_list *bl, const char* map, int x, int y); +int unit_cancel_combo(struct block_list *bl); // スキル使用 int unit_skilluse_id(struct block_list *src, int target_id, int skill_num, int skill_lv); -- cgit v1.2.3-70-g09d2 From 5178ca9df008ecff5e78fb52baddedac9c318702 Mon Sep 17 00:00:00 2001 From: FlavioJS Date: Sun, 31 Dec 2006 12:12:42 +0000 Subject: * Refer to http://www.eathena.ws/board/index.php?showtopic=130285 - Renamed pc_checkweighticon to pc_updateweightstatus and cleaned it. - Updated pc_is50overweight to use battle_config.natural_heal_weight_rate. - Added 90% weight check when attacking. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@9600 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 4 ++++ src/map/clif.c | 6 +++--- src/map/pc.c | 37 +++++++++++++++++-------------------- src/map/pc.h | 6 +++--- src/map/status.c | 2 +- src/map/unit.c | 23 ++++++++++++++++------- src/map/unit.h | 2 +- 7 files changed, 45 insertions(+), 35 deletions(-) (limited to 'src/map/unit.h') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index d4637634f..53b918b4f 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -4,6 +4,10 @@ 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. 2006/12/31 + * Refer to http://www.eathena.ws/board/index.php?showtopic=130285 + - Renamed pc_checkweighticon to pc_updateweightstatus and cleaned it. + - Updated pc_is50overweight to use battle_config.natural_heal_weight_rate. + - Added 90% weight check when attacking. * Updated getitem and guardian entries in script_commands.txt. * Fixed getitem trying to get from the wrong argument. * Now getitem can be run on scripts without a player attached if diff --git a/src/map/clif.c b/src/map/clif.c index 937509fa6..928855620 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -2585,8 +2585,8 @@ int clif_updatestatus(struct map_session_data *sd,int type) switch(type){ // 00b0 case SP_WEIGHT: - pc_checkweighticon(sd); - WFIFOW(fd,0)=0xb0; //Need to re-set as pc_checkweighticon can alter the buffer. [Skotlex] + pc_updateweightstatus(sd); + WFIFOW(fd,0)=0xb0; //Need to re-set as pc_updateweightstatus can alter the buffer. [Skotlex] WFIFOW(fd,2)=type; WFIFOL(fd,4)=sd->weight; break; @@ -8914,7 +8914,7 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, if(target_id<0 && -target_id == sd->bl.id) // for disguises [Valaris] target_id = sd->bl.id; - + switch(action_type) { case 0x00: // once attack case 0x07: // continuous attack diff --git a/src/map/pc.c b/src/map/pc.c index fc61a65ba..eba537d9f 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1089,37 +1089,34 @@ int pc_calc_skilltree_normalize_job(struct map_session_data *sd) { } /*========================================== - * 重量アイコンの確認 + * Updates the weight status *------------------------------------------ */ -int pc_checkweighticon(struct map_session_data *sd) +int pc_updateweightstatus(struct map_session_data *sd) { int flag=0; nullpo_retr(0, sd); - //Consider the battle option 50% criteria.... - if(sd->weight*100 >= sd->max_weight*battle_config.natural_heal_weight_rate) - flag=1; - if(sd->weight*10 >= sd->max_weight*9) + if( pc_is90overweight(sd) ) flag=2; + else if( pc_is50overweight(sd) ) + flag=1; - if(flag==1){ - if(sd->sc.data[SC_WEIGHT50].timer==-1) - sc_start(&sd->bl,SC_WEIGHT50,100,0,0); - }else{ - if(sd->sc.data[SC_WEIGHT50].timer!=-1) - status_change_end(&sd->bl,SC_WEIGHT50,-1); - } - if(flag==2){ - if(sd->sc.data[SC_WEIGHT90].timer==-1) - sc_start(&sd->bl,SC_WEIGHT90,100,0,0); - }else{ - if(sd->sc.data[SC_WEIGHT90].timer!=-1) - status_change_end(&sd->bl,SC_WEIGHT90,-1); - } + // 50% overweight icon + if( flag == 1 && sd->sc.data[SC_WEIGHT50].timer == -1 ) + sc_start(&sd->bl,SC_WEIGHT50,100,0,0); + else if( sd->sc.data[SC_WEIGHT50].timer != -1 ) + status_change_end(&sd->bl,SC_WEIGHT50,-1); + // 90% overwheight icon + if( flag == 2 && sd->sc.data[SC_WEIGHT90].timer == -1 ) + sc_start(&sd->bl,SC_WEIGHT90,100,0,0); + else if( sd->sc.data[SC_WEIGHT90].timer != -1 ) + status_change_end(&sd->bl,SC_WEIGHT90,-1); + // update overweight status if (flag != sd->regen.state.overweight) sd->regen.state.overweight = flag; + return 0; } diff --git a/src/map/pc.h b/src/map/pc.h index 0eb406c7d..c290ec696 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -98,8 +98,8 @@ enum { #define pc_isfalcon(sd) ((sd)->sc.option&OPTION_FALCON) #define pc_isriding(sd) ((sd)->sc.option&OPTION_RIDING) #define pc_isinvisible(sd) ((sd)->sc.option&OPTION_INVISIBLE) -#define pc_is50overweight(sd) (sd->weight*2 >= sd->max_weight) -#define pc_is90overweight(sd) (sd->weight*10 >= sd->max_weight*9) +#define pc_is50overweight(sd) ( (sd)->weight*100 >= (sd)->max_weight*battle_config.natural_heal_weight_rate ) +#define pc_is90overweight(sd) ( (sd)->weight*10 >= (sd)->max_weight*9 ) #define pc_maxparameter(sd) ((sd->class_&JOBL_BABY) ? battle_config.max_baby_parameter : battle_config.max_parameter) #define pc_stop_attack(sd) { if (sd->ud.attacktimer!=-1) { unit_stop_attack(&sd->bl); sd->ud.target = 0; } } @@ -159,7 +159,7 @@ int pc_cartitem_amount(struct map_session_data *sd,int idx,int amount); int pc_takeitem(struct map_session_data*,struct flooritem_data*); int pc_dropitem(struct map_session_data*,int,int); -int pc_checkweighticon(struct map_session_data *sd); +int pc_updateweightstatus(struct map_session_data *sd); int pc_bonus(struct map_session_data*,int,int); int pc_bonus2(struct map_session_data *sd,int,int,int); diff --git a/src/map/status.c b/src/map/status.c index bfc257f7b..40f18e9af 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -2273,7 +2273,7 @@ int status_calc_pc(struct map_session_data* sd,int first) clif_updatestatus(sd,SP_WEIGHT); if(b_max_weight != sd->max_weight) { clif_updatestatus(sd,SP_MAXWEIGHT); - pc_checkweighticon(sd); + pc_updateweightstatus(sd); } if(b_status.str != status->str) clif_updatestatus(sd,SP_STR); diff --git a/src/map/unit.c b/src/map/unit.c index 213168682..21175cc30 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1147,7 +1147,7 @@ int unit_unattackable(struct block_list *bl) { *------------------------------------------ */ -int unit_attack(struct block_list *src,int target_id,int type) +int unit_attack(struct block_list *src,int target_id,int continuous) { struct block_list *target; struct unit_data *ud; @@ -1160,9 +1160,18 @@ int unit_attack(struct block_list *src,int target_id,int type) return 1; } - if(src->type == BL_PC && target->type==BL_NPC) { // monster npcs [Valaris] - npc_click((TBL_PC*)src,(TBL_NPC*)target); // submitted by leinsirk10 [Celest] - return 0; + if( src->type == BL_PC ){ + TBL_PC* sd = (TBL_PC*)src; + if( target->type == BL_NPC ) + {// monster npcs [Valaris] + npc_click(sd,(TBL_NPC*)target); // submitted by leinsirk10 [Celest] + return 0; + } else if( pc_is90overweight(sd) ) + {// overwheight - stop attacking and walking + unit_stop_attack(src); + unit_stop_walking(src,1); + return 0; + } } if(battle_check_target(src,target,BCT_ENEMY)<=0 || @@ -1173,10 +1182,10 @@ int unit_attack(struct block_list *src,int target_id,int type) } ud->target = target_id; - ud->state.attack_continue = type; - if (type) //If you re to attack continously, set to auto-case character + ud->state.attack_continue = continuous; + if (continuous) //If you're to attack continously, set to auto-case character ud->chaserange = status_get_range(src); - + //Just change target/type. [Skotlex] if(ud->attacktimer != -1) return 0; diff --git a/src/map/unit.h b/src/map/unit.h index 7331f4ca5..8f44616d8 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -36,7 +36,7 @@ int unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, i // 攻撃関連 int unit_stop_attack(struct block_list *bl); -int unit_attack(struct block_list *src,int target_id,int type); +int unit_attack(struct block_list *src,int target_id,int continuous); int unit_cancel_combo(struct block_list *bl); // スキル使用 -- cgit v1.2.3-70-g09d2 From 8ff8d0f9ee285452ba7820c3fb333eddb042272b Mon Sep 17 00:00:00 2001 From: skotlex Date: Tue, 16 Jan 2007 13:56:17 +0000 Subject: - Added function unit_escape to simplify the run-away code a bit in the mob ai. - Some cleaning on the mob_ai to enable mobs to run away from their current target when they are rude-attacked by them. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@9658 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 3 +++ src/map/mob.c | 26 ++++++++++++-------------- src/map/unit.c | 13 +++++++++++++ src/map/unit.h | 1 + 4 files changed, 29 insertions(+), 14 deletions(-) (limited to 'src/map/unit.h') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 3e482d72c..a33e2f322 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -3,6 +3,9 @@ Date Added AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK. IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. +2007/01/16 + * Some cleaning on the mob_ai to enable mobs to run away from their current + target when they are rude-attacked by them. 2007/01/15 * The NPC elemental attacks will display a skill animation again. * Mob instant cast skills will use their adelay now. diff --git a/src/map/mob.c b/src/map/mob.c index d7e6f9592..fca96c965 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -1123,12 +1123,16 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap) if (md->attacked_id == md->target_id) { if (!battle_check_range(&md->bl, tbl, md->status.rhw.range) && - ((!can_move && battle_config.mob_ai&0x2) || - (!mob_can_reach(md, tbl, md->min_chase, MSS_RUSH)))) + ( + (!can_move && battle_config.mob_ai&0x2) || + (!mob_can_reach(md, tbl, md->min_chase, MSS_RUSH)) + ) && + DIFF_TICK(tick, md->ud.canmove_tick) > 0 && + md->state.attacked_count++ >= RUDE_ATTACKED_COUNT + ) { //Rude-attacked (avoid triggering due to can-walk delay). - if (DIFF_TICK(tick, md->ud.canmove_tick) > 0 && - md->state.attacked_count++ >= RUDE_ATTACKED_COUNT) - mobskill_use(md, tick, MSC_RUDEATTACKED); + if (!mobskill_use(md, tick, MSC_RUDEATTACKED) && can_move) + unit_escape(bl, tbl, rand()%10 +1); } } else if ((abl= map_id2bl(md->attacked_id)) && (!tbl || mob_can_changetarget(md, abl, mode))) { @@ -1142,15 +1146,9 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap) ((TBL_PC*)abl)->state.gangsterparadise ) ) { //Can't attack back - if (md->state.attacked_count++ >= RUDE_ATTACKED_COUNT) { - if (mobskill_use(md, tick, MSC_RUDEATTACKED) == 0 && can_move) - { - int dist = rand() % 10 + 1;//後退する距離 - int dir = map_calc_dir(abl, bl->x, bl->y); - int mask[8][2] = {{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1}}; - unit_walktoxy(&md->bl, md->bl.x + dist * mask[dir][0], md->bl.y + dist * mask[dir][1], 0); - } - } + if (md->state.attacked_count++ >= RUDE_ATTACKED_COUNT && + !mobskill_use(md, tick, MSC_RUDEATTACKED) && can_move) + unit_escape(bl, abl, rand()%10 +1); } else if (!(battle_config.mob_ai&0x2) && !status_check_skilluse(bl, abl, 0, 0)) { //Can't attack back, but didn't invoke a rude attacked skill... md->attacked_id = 0; //Simply unlock, shouldn't attempt to run away when in dumb_ai mode. diff --git a/src/map/unit.c b/src/map/unit.c index 8684c0732..a03b24d74 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -413,6 +413,19 @@ int unit_run(struct block_list *bl) return 1; } +//Makes bl attempt to run dist cells away from target. Uses hard-paths. +int unit_escape(struct block_list *bl, struct block_list *target, int dist) +{ + int dir = map_calc_dir(target, bl->x, bl->y); + while (dist > 0 && map_getcell(bl->m, + bl->x + dist*dirx[dir], bl->y + dist*diry[dir], + CELL_CHKNOREACH)) + dist--; + return (dist > 0 && unit_walktoxy(bl, + bl->x + dist*dirx[dir], bl->y + dist*diry[dir], + 0)); +} + //Instant warp function. int unit_movepos(struct block_list *bl,int dst_x,int dst_y, int easy, int checkpath) { diff --git a/src/map/unit.h b/src/map/unit.h index 8f44616d8..9b53f90bf 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -24,6 +24,7 @@ int unit_can_move(struct block_list *bl); int unit_is_walking(struct block_list *bl); int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int type); +int unit_escape(struct block_list *bl, struct block_list *target, int dist); // 位置の強制移動(吹き飛ばしなど) int unit_movepos(struct block_list *bl,int dst_x,int dst_y, int easy, int checkpath); int unit_warp(struct block_list *bl, int map, short x, short y, int type); -- cgit v1.2.3-70-g09d2 From 120b6a38af546987948505832c1d8d6fb3c853af Mon Sep 17 00:00:00 2001 From: ultramage Date: Wed, 21 Feb 2007 15:09:20 +0000 Subject: Applied a consistent look to all header files (copyright, ifdefs) git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@9891 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 1 + src/char/char.h | 3 ++- src/char/int_guild.h | 3 ++- src/char/int_homun.h | 2 +- src/char/int_party.h | 3 ++- src/char/int_pet.h | 3 ++- src/char/int_status.h | 7 ++++--- src/char/int_storage.h | 3 ++- src/char/inter.h | 3 ++- src/char_sql/char.h | 8 +++++--- src/char_sql/int_homun.c | 4 ++-- src/char_sql/int_homun.h | 10 +++++----- src/char_sql/int_party.h | 3 ++- src/char_sql/int_pet.h | 3 ++- src/char_sql/int_storage.h | 3 ++- src/char_sql/inter.h | 3 ++- src/char_sql/itemdb.h | 3 ++- src/common/cbasetypes.h | 1 + src/common/core.h | 2 +- src/common/db.h | 2 +- src/common/grfio.h | 3 ++- src/common/lock.h | 3 +-- src/common/malloc.h | 3 ++- src/common/mapindex.c | 3 +++ src/common/mapindex.h | 10 +++++++--- src/common/md5calc.h | 2 +- src/common/mmo.h | 2 +- src/common/nullpo.h | 2 +- src/common/plugin.h | 2 +- src/common/plugins.h | 2 +- src/common/showmsg.h | 2 +- src/common/socket.h | 2 +- src/common/strlib.h | 7 ++++--- src/common/timer.h | 2 +- src/common/utils.h | 6 +++--- src/common/version.h | 2 +- src/ladmin/ladmin.c | 2 +- src/ladmin/ladmin.h | 4 ++-- src/login/login.h | 3 ++- src/login_sql/login.h | 6 +++--- src/map/atcommand.h | 3 +-- src/map/battle.h | 2 +- src/map/charcommand.h | 2 +- src/map/charsave.h | 2 +- src/map/chat.h | 2 +- src/map/chrif.h | 2 +- src/map/clif.h | 4 +--- src/map/date.h | 3 ++- src/map/guild.h | 2 +- src/map/intif.h | 2 +- src/map/irc.c | 6 ++---- src/map/irc.h | 8 ++++++++ src/map/itemdb.h | 2 +- src/map/log.h | 2 +- src/map/mail.h | 6 ++++-- src/map/map.h | 2 +- src/map/mercenary.c | 3 +++ src/map/mercenary.h | 10 ++++++++-- src/map/mob.h | 2 +- src/map/npc.h | 3 +-- src/map/party.h | 2 +- src/map/pc.h | 3 ++- src/map/pet.h | 3 +-- src/map/script.h | 3 +-- src/map/skill.h | 2 +- src/map/status.h | 2 +- src/map/storage.h | 2 +- src/map/trade.h | 2 +- src/map/unit.c | 4 ++-- src/map/unit.h | 5 +++-- src/map/vending.h | 2 +- 71 files changed, 138 insertions(+), 98 deletions(-) (limited to 'src/map/unit.h') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 89ef39a7c..1c6cfb32f 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -4,6 +4,7 @@ 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. 2007/02/21 + * Applied a consistent look to all header files (copyright, ifdefs) * Minor stuff (typos, socket.c, junk in login reply packet) [ultramage] 2007/02/19 * Fixed @cartlist info message typo [Lupus] diff --git a/src/char/char.h b/src/char/char.h index e70fe7e4f..947d12d3f 100644 --- a/src/char/char.h +++ b/src/char/char.h @@ -55,4 +55,5 @@ extern char char_txt[]; int char_config_read(const char *cfgName); int mmo_char_fromstr(char *str, struct mmo_charstatus *p, struct global_reg *reg, int *reg_num); int parse_friend_txt(struct mmo_charstatus *p); -#endif + +#endif /* _CHAR_H_ */ diff --git a/src/char/int_guild.h b/src/char/int_guild.h index 616384b94..6b0e9f7b5 100644 --- a/src/char/int_guild.h +++ b/src/char/int_guild.h @@ -19,4 +19,5 @@ extern char castle_txt[1024]; //For the TXT->SQL converter int inter_guild_fromstr(char *str, struct guild *g); int inter_guildcastle_fromstr(char *str, struct guild_castle *gc); -#endif + +#endif /* _INT_GUILD_H_ */ diff --git a/src/char/int_homun.h b/src/char/int_homun.h index 5987d23f8..d56ab97a9 100644 --- a/src/char/int_homun.h +++ b/src/char/int_homun.h @@ -13,4 +13,4 @@ int inter_homun_parse_frommap(int fd); extern char homun_txt[1024]; -#endif +#endif /* _INT_HOMUN_H_ */ diff --git a/src/char/int_party.h b/src/char/int_party.h index 8f4ff5d18..453699617 100644 --- a/src/char/int_party.h +++ b/src/char/int_party.h @@ -16,4 +16,5 @@ extern char party_txt[1024]; //For the TXT->SQL converter int inter_party_fromstr(char *str, struct party *p); -#endif + +#endif /* _INT_PARTY_H_ */ diff --git a/src/char/int_pet.h b/src/char/int_pet.h index 2c72628bb..43f354798 100644 --- a/src/char/int_pet.h +++ b/src/char/int_pet.h @@ -15,4 +15,5 @@ extern char pet_txt[1024]; //Exported for use in the TXT-SQL converter. int inter_pet_fromstr(char *str,struct s_pet *p); -#endif + +#endif /* _INT_PET_H_ */ diff --git a/src/char/int_status.h b/src/char/int_status.h index bc93b1024..3ddf08299 100644 --- a/src/char/int_status.h +++ b/src/char/int_status.h @@ -1,8 +1,8 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef __INT_STATUS__ -#define __INT_STATUS__ +#ifndef _INT_STATUS_H_ +#define _INT_STATUS_H_ #include "char.h" @@ -21,4 +21,5 @@ void inter_status_save(void); void status_init(void); void status_final(void); #endif -#endif + +#endif /* _INT_STATUS_H_ */ diff --git a/src/char/int_storage.h b/src/char/int_storage.h index 7007646f9..976d77034 100644 --- a/src/char/int_storage.h +++ b/src/char/int_storage.h @@ -19,4 +19,5 @@ extern char guild_storage_txt[1024]; //Exported for use in the TXT-SQL converter. int storage_fromstr(char *str,struct storage *p); int guild_storage_fromstr(char *str,struct guild_storage *p); -#endif + +#endif /* _INT_STORAGE_H_ */ diff --git a/src/char/inter.h b/src/char/inter.h index 1789848c5..5a6a0edde 100644 --- a/src/char/inter.h +++ b/src/char/inter.h @@ -25,4 +25,5 @@ extern char main_chat_nick[16]; //For TXT->SQL conversion extern char accreg_txt[]; int inter_accreg_fromstr(const char *str, struct accreg *reg); -#endif + +#endif /* _INTER_H_ */ diff --git a/src/char_sql/char.h b/src/char_sql/char.h index 4a95fd0f8..41ce45ea6 100644 --- a/src/char_sql/char.h +++ b/src/char_sql/char.h @@ -1,7 +1,8 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _CHARSQL_H_ -#define _CHARSQL_H_ + +#ifndef _CHAR_SQL_H_ +#define _CHAR_SQL_H_ #include "../common/core.h" #include "../common/socket.h" @@ -106,4 +107,5 @@ extern int debug_mysql_query(char *file, int line, void *mysql, const char *q); //Exported for use in the TXT-SQL converter. int mmo_char_tosql(int char_id, struct mmo_charstatus *p); void sql_config_read(const char *cfgName); -#endif + +#endif /* _CHAR_SQL_H_ */ diff --git a/src/char_sql/int_homun.c b/src/char_sql/int_homun.c index 22edad8d0..2260ddf20 100644 --- a/src/char_sql/int_homun.c +++ b/src/char_sql/int_homun.c @@ -1,5 +1,5 @@ -// Homunculus saving by Albator and Orn for eAthena. -// GNU/GPL rulez ! +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder #include #include diff --git a/src/char_sql/int_homun.h b/src/char_sql/int_homun.h index 2b9af8ebc..fa49c659f 100644 --- a/src/char_sql/int_homun.h +++ b/src/char_sql/int_homun.h @@ -1,8 +1,8 @@ -// Homunculus saving by Albator and Orn for eAthena. -// GNU/GPL rulez ! +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder -#ifndef _INT_HOMUN_H_ -#define _INT_HOMUN_H_ +#ifndef _INT_HOMUN_SQL_H_ +#define _INT_HOMUN_SQL_H_ int inter_homunculus_sql_init(void); void inter_homunculus_sql_final(void); @@ -12,4 +12,4 @@ int mapif_delete_homunculus(int fd); int inter_delete_homunculus(int hom_id); int inter_homunculus_parse_frommap(int fd); -#endif +#endif /* _INT_HOMUN_SQL_H_ */ diff --git a/src/char_sql/int_party.h b/src/char_sql/int_party.h index 1e54b8b47..c244ab59e 100644 --- a/src/char_sql/int_party.h +++ b/src/char_sql/int_party.h @@ -26,4 +26,5 @@ int inter_party_CharOnline(int char_id, int party_id); int inter_party_CharOffline(int char_id, int party_id); //Required for the TXT->SQL converter int inter_party_tosql(struct party *p, int flag, int index); -#endif + +#endif /* _INT_PARTY_SQL_H_ */ diff --git a/src/char_sql/int_pet.h b/src/char_sql/int_pet.h index 1b03c9768..5c1955857 100644 --- a/src/char_sql/int_pet.h +++ b/src/char_sql/int_pet.h @@ -15,4 +15,5 @@ int inter_pet_sql_init(void); //Exported for use in the TXT-SQL converter. int inter_pet_tosql(int pet_id, struct s_pet *p); -#endif + +#endif /* _INT_PET_SQL_H_ */ diff --git a/src/char_sql/int_storage.h b/src/char_sql/int_storage.h index 3cba41e64..dd71ef9ed 100644 --- a/src/char_sql/int_storage.h +++ b/src/char_sql/int_storage.h @@ -14,4 +14,5 @@ int inter_storage_parse_frommap(int fd); //Exported for use in the TXT-SQL converter. int storage_tosql(int account_id,struct storage *p); int guild_storage_tosql(int guild_id, struct guild_storage *p); -#endif + +#endif /* _INT_STORAGE_SQL_H_ */ diff --git a/src/char_sql/inter.h b/src/char_sql/inter.h index ecfde71c0..c1567cfe6 100644 --- a/src/char_sql/inter.h +++ b/src/char_sql/inter.h @@ -53,4 +53,5 @@ extern char login_db_server_db[32]; extern char main_chat_nick[16]; int inter_accreg_tosql(int account_id, int char_id, struct accreg *reg, int type); -#endif + +#endif /* _INTER_SQL_H_ */ diff --git a/src/char_sql/itemdb.h b/src/char_sql/itemdb.h index 53b1d3e02..4fbd59f96 100644 --- a/src/char_sql/itemdb.h +++ b/src/char_sql/itemdb.h @@ -3,6 +3,7 @@ #ifndef _ITEMDB_H_ #define _ITEMDB_H_ + #include "mmo.h" //FIXME: Maybe it would be better to move this enum to mmo.h, @@ -40,4 +41,4 @@ int itemdb_isequip2(struct item_data *); void do_final_itemdb(void); int do_init_itemdb(void); -#endif +#endif /* _ITEMDB_H_ */ diff --git a/src/common/cbasetypes.h b/src/common/cbasetypes.h index 76f494851..1eea1c465 100644 --- a/src/common/cbasetypes.h +++ b/src/common/cbasetypes.h @@ -1,5 +1,6 @@ #ifndef _CBASETYPES_H_ #define _CBASETYPES_H_ + /* +--------+-----------+--------+---------+ * | ILP32 | LP64 | ILP64 | (LL)P64 | * +------------+--------+-----------+--------+---------+ diff --git a/src/common/core.h b/src/common/core.h index 06ce86448..5e396cc7a 100644 --- a/src/common/core.h +++ b/src/common/core.h @@ -20,4 +20,4 @@ extern void set_server_type(void); extern void set_termfunc(void (*termfunc)(void)); extern void do_final(void); -#endif // _CORE_H_ +#endif /* _CORE_H_ */ diff --git a/src/common/db.h b/src/common/db.h index a79c88822..0c19b5fc2 100644 --- a/src/common/db.h +++ b/src/common/db.h @@ -702,4 +702,4 @@ void* linkdb_search ( struct linkdb_node** head, void *key); void* linkdb_erase ( struct linkdb_node** head, void *key); void linkdb_final ( struct linkdb_node** head ); -#endif +#endif /* _DB_H_ */ diff --git a/src/common/grfio.h b/src/common/grfio.h index 572258b04..0d6268b0d 100644 --- a/src/common/grfio.h +++ b/src/common/grfio.h @@ -19,4 +19,5 @@ int decode_zip(unsigned char *dest, unsigned long* destLen, const unsigned char* int encode_zip(unsigned char *dest, unsigned long* destLen, const unsigned char* source, unsigned long sourceLen); int deflate_file (const char *source, const char *filename); -#endif // _GRFIO_H_ +#endif /* _GRFIO_H_ */ + diff --git a/src/common/lock.h b/src/common/lock.h index e90fbf745..537305ccf 100644 --- a/src/common/lock.h +++ b/src/common/lock.h @@ -9,5 +9,4 @@ FILE* lock_fopen(const char* filename,int *info); int lock_fclose(FILE *fp,const char* filename,int *info); -#endif - +#endif /* _LOCK_H_ */ diff --git a/src/common/malloc.h b/src/common/malloc.h index 1af9cba62..5411d670d 100644 --- a/src/common/malloc.h +++ b/src/common/malloc.h @@ -3,6 +3,7 @@ #ifndef _MALLOC_H_ #define _MALLOC_H_ + // Q: What are the 'a'-variant allocation functions? // A: They allocate memory from the stack, which is automatically // freed when the invoking function returns. @@ -157,4 +158,4 @@ unsigned int malloc_usage (void); void malloc_init (void); void malloc_final (void); -#endif +#endif /* _MALLOC_H_ */ diff --git a/src/common/mapindex.c b/src/common/mapindex.c index 070326463..be6580ae5 100644 --- a/src/common/mapindex.c +++ b/src/common/mapindex.c @@ -1,3 +1,6 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + #include #include #include diff --git a/src/common/mapindex.h b/src/common/mapindex.h index 7a0286adf..68989031d 100644 --- a/src/common/mapindex.h +++ b/src/common/mapindex.h @@ -1,5 +1,9 @@ -#ifndef _MAX_INDEX_H -#define _MAX_INDEX_H +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef _MAPINDEX_H_ +#define _MAPINDEX_H_ + //File in charge of assigning a numberic ID to each map in existance for space saving when passing map info between servers. extern char mapindex_cfgfile[80]; @@ -38,4 +42,4 @@ const char* mapindex_id2name(unsigned short); void mapindex_init(void); void mapindex_final(void); -#endif +#endif /* _MAPINDEX_H_ */ diff --git a/src/common/md5calc.h b/src/common/md5calc.h index 9bc554f69..fc1c274f2 100644 --- a/src/common/md5calc.h +++ b/src/common/md5calc.h @@ -4,4 +4,4 @@ void MD5_String(const char * string, char * output); void MD5_String2binary(const char * string, char * output); -#endif +#endif /* _MD5CALC_H_ */ diff --git a/src/common/mmo.h b/src/common/mmo.h index 48a8266e7..f946b46cb 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -511,4 +511,4 @@ enum { #endif #endif -#endif // _MMO_H_ +#endif /* _MMO_H_ */ diff --git a/src/common/nullpo.h b/src/common/nullpo.h index d5ccb8f95..71525dd00 100644 --- a/src/common/nullpo.h +++ b/src/common/nullpo.h @@ -234,4 +234,4 @@ void nullpo_info_f(const char *file, int line, const char *func, __attribute__((format(printf,4,5))); -#endif +#endif /* _NULLPO_H_ */ diff --git a/src/common/plugin.h b/src/common/plugin.h index f30a15e5e..3ddbaae98 100644 --- a/src/common/plugin.h +++ b/src/common/plugin.h @@ -80,4 +80,4 @@ typedef void Plugin_Event_Func(void); #define PLUGIN_EVENTS_TABLE struct _Plugin_Event_Table plugin_event_table[] void** plugin_call_table; -#endif // _PLUGIN_H_ +#endif /* _PLUGIN_H_ */ diff --git a/src/common/plugins.h b/src/common/plugins.h index 9cb4b94b4..70dd6b326 100644 --- a/src/common/plugins.h +++ b/src/common/plugins.h @@ -63,4 +63,4 @@ void plugin_unload(Plugin* plugin); void plugins_init(void); void plugins_final(void); -#endif // _PLUGINS_H_ +#endif /* _PLUGINS_H_ */ diff --git a/src/common/showmsg.h b/src/common/showmsg.h index cf9c16d23..31933f17a 100644 --- a/src/common/showmsg.h +++ b/src/common/showmsg.h @@ -93,4 +93,4 @@ extern int ShowDebug(const char *, ...); extern int ShowError(const char *, ...); extern int ShowFatalError(const char *, ...); -#endif +#endif /* _SHOWMSG_H_ */ diff --git a/src/common/socket.h b/src/common/socket.h index 1c4a1bd8c..0c96edb20 100644 --- a/src/common/socket.h +++ b/src/common/socket.h @@ -141,4 +141,4 @@ int socket_getips(uint32* ips, int max); extern uint32 addr_[16]; // ip addresses of local host (host byte order) extern int naddr_; // # of ip addresses -#endif // _SOCKET_H_ +#endif /* _SOCKET_H_ */ diff --git a/src/common/strlib.h b/src/common/strlib.h index f242b5cc4..8303c182f 100644 --- a/src/common/strlib.h +++ b/src/common/strlib.h @@ -1,8 +1,9 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _J_STR_LIB_H_ -#define _J_STR_LIB_H_ +#ifndef _STRLIB_H_ +#define _STRLIB_H_ + #define J_MAX_MALLOC_SIZE 65535 // String function library. // code by Jioh L. Jung (ziozzang@4wish.net) @@ -26,4 +27,4 @@ const char *stristr(const char *haystack, const char *needle); size_t strnlen (const char* string, size_t maxlen); #endif -#endif +#endif /* _STRLIB_H_ */ diff --git a/src/common/timer.h b/src/common/timer.h index 4b683d966..23cb6beaa 100644 --- a/src/common/timer.h +++ b/src/common/timer.h @@ -59,4 +59,4 @@ unsigned long get_uptime(void); void timer_init(void); void timer_final(void); -#endif // _TIMER_H_ +#endif /* _TIMER_H_ */ diff --git a/src/common/utils.h b/src/common/utils.h index efd477c9b..3e74374bc 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -1,8 +1,8 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef COMMON_UTILS_H -#define COMMON_UTILS_H +#ifndef _UTILS_H_ +#define _UTILS_H_ #include @@ -41,4 +41,4 @@ extern unsigned short GetWord(unsigned long val, size_t num); extern unsigned short MakeWord(unsigned char byte0, unsigned char byte1); extern unsigned long MakeDWord(unsigned short word0, unsigned short word1); -#endif +#endif /* _UTILS_H_ */ diff --git a/src/common/version.h b/src/common/version.h index 2560c1019..71a93dcd9 100644 --- a/src/common/version.h +++ b/src/common/version.h @@ -27,4 +27,4 @@ // C言語の仕様上、最初に0を付けると8進数になるので間違えないで下さい。 #define ATHENA_MOD_VERSION 1249 // mod version (patch No.) -#endif +#endif /* _VERSION_H_ */ diff --git a/src/ladmin/ladmin.c b/src/ladmin/ladmin.c index 343967d46..107d98d09 100644 --- a/src/ladmin/ladmin.c +++ b/src/ladmin/ladmin.c @@ -1,4 +1,4 @@ -// (c) eAthena Dev Team - Licensed under GNU GPL +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder /////////////////////////////////////////////////////////////////////////// diff --git a/src/ladmin/ladmin.h b/src/ladmin/ladmin.h index 64a67146e..b335984c7 100644 --- a/src/ladmin/ladmin.h +++ b/src/ladmin/ladmin.h @@ -1,4 +1,4 @@ -// (c) eAthena Dev Team - Licensed under GNU GPL +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder #ifndef _LADMIN_H_ @@ -10,4 +10,4 @@ // It is made into 2 at the time of passwordencrypt2. // When it is made 3, it corresponds to both. -#endif +#endif /* _LADMIN_H_ */ diff --git a/src/login/login.h b/src/login/login.h index 38901ff33..441f2bac1 100644 --- a/src/login/login.h +++ b/src/login/login.h @@ -39,4 +39,5 @@ struct mmo_char_server { extern struct mmo_char_server server[MAX_SERVERS]; extern int server_fd[MAX_SERVERS]; -#endif + +#endif /* _LOGIN_H_ */ diff --git a/src/login_sql/login.h b/src/login_sql/login.h index f3b604664..882a284e9 100644 --- a/src/login_sql/login.h +++ b/src/login_sql/login.h @@ -1,8 +1,8 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _LOGIN_H_ -#define _LOGIN_H_ +#ifndef _LOGIN_SQL_H_ +#define _LOGIN_SQL_H_ #define MAX_SERVERS 30 @@ -51,4 +51,4 @@ struct mmo_char_server { }; -#endif +#endif /* _LOGIN_SQL_H_ */ diff --git a/src/map/atcommand.h b/src/map/atcommand.h index 84b4fa0ed..644237245 100644 --- a/src/map/atcommand.h +++ b/src/map/atcommand.h @@ -325,5 +325,4 @@ extern char atcommand_symbol; #define MAX_MSG 1000 extern char* msg_table[MAX_MSG]; -#endif - +#endif /* _ATCOMMAND_H_ */ diff --git a/src/map/battle.h b/src/map/battle.h index 12e217218..c04fcfbfb 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -444,4 +444,4 @@ extern void battle_set_defaults(void); extern int battle_set_value(char *, char *); int battle_get_value(char *); -#endif +#endif /* _BATTLE_H_ */ diff --git a/src/map/charcommand.h b/src/map/charcommand.h index 5982ffe30..979594251 100644 --- a/src/map/charcommand.h +++ b/src/map/charcommand.h @@ -70,5 +70,5 @@ int get_charcommand_level(const CharCommandType type); int charcommand_config_read(const char *cfgName); extern char charcommand_symbol; -#endif +#endif /* _CHARCOMMAND_H_ */ diff --git a/src/map/charsave.h b/src/map/charsave.h index 5743c1c65..5734ebf58 100644 --- a/src/map/charsave.h +++ b/src/map/charsave.h @@ -18,4 +18,4 @@ void charsave_save_scdata(int account_id, int char_id, struct status_change* sc_data, int max_sc); #endif -#endif +#endif /* _CHARSAVE_H_ */ diff --git a/src/map/chat.h b/src/map/chat.h index 702fd7dad..bfb1a0a80 100644 --- a/src/map/chat.h +++ b/src/map/chat.h @@ -19,4 +19,4 @@ int chat_enableevent(struct chat_data *cd); int chat_disableevent(struct chat_data *cd); int chat_npckickall(struct chat_data *cd); -#endif +#endif /* _CHAT_H_ */ diff --git a/src/map/chrif.h b/src/map/chrif.h index 302b31f56..a94591cd4 100644 --- a/src/map/chrif.h +++ b/src/map/chrif.h @@ -55,4 +55,4 @@ int do_init_chrif(void); int chrif_flush_fifo(void); -#endif +#endif /* _CHRIF_H_ */ diff --git a/src/map/clif.h b/src/map/clif.h index 5ce426f96..ca3ae2278 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -362,6 +362,4 @@ int clif_hom_food(struct map_session_data *sd,int foodid,int fail); //[orn] void clif_send_homdata(struct map_session_data *sd, int type, int param); //[orn] int clif_hwalkok(struct homun_data *hd); //[orn] -#endif - - +#endif /* _CLIF_H_ */ diff --git a/src/map/date.h b/src/map/date.h index 2b8ffe991..cc19d88d1 100644 --- a/src/map/date.h +++ b/src/map/date.h @@ -3,7 +3,6 @@ #ifndef _DATE_H_ #define _DATE_H_ -#endif int date_get_year(void); int date_get_month(void); @@ -15,3 +14,5 @@ int date_get_sec(void); int is_day_of_sun(void); int is_day_of_moon(void); int is_day_of_star(void); + +#endif /* _DATE_H_ */ diff --git a/src/map/guild.h b/src/map/guild.h index 6171c72f2..e569c0d15 100644 --- a/src/map/guild.h +++ b/src/map/guild.h @@ -91,4 +91,4 @@ int guild_agit_break(struct mob_data *md); void do_final_guild(void); -#endif +#endif /* _GUILD_H_ */ diff --git a/src/map/intif.h b/src/map/intif.h index 56f2f4783..b1d82940c 100644 --- a/src/map/intif.h +++ b/src/map/intif.h @@ -70,4 +70,4 @@ int intif_homunculus_requestdelete(int homun_id); int CheckForCharServer(void); -#endif +#endif /* _INTIF_H_ */ diff --git a/src/map/irc.c b/src/map/irc.c index 55eafdcd9..2300dd3ac 100644 --- a/src/map/irc.c +++ b/src/map/irc.c @@ -1,5 +1,5 @@ -#ifndef _IRC_H_ -#define _IRC_H_ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder #include #include @@ -545,5 +545,3 @@ int irc_read_conf(char *file) { return 1; } - -#endif //_IRC_H_ diff --git a/src/map/irc.h b/src/map/irc.h index 2297f013b..163ac0793 100644 --- a/src/map/irc.h +++ b/src/map/irc.h @@ -1,3 +1,9 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef _IRC_H_ +#define _IRC_H_ + #include "map.h" // IRC .conf file [Zido] @@ -53,3 +59,5 @@ int set_access(char *nick,int level); // [Zido] int get_access(char *nick); // [Zido] int irc_rmnames(void); // [Zido] int irc_read_conf(char *file); // [Zido] + +#endif /* _IRC_H_ */ diff --git a/src/map/itemdb.h b/src/map/itemdb.h index 0b9e2a466..fb3d25964 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -142,4 +142,4 @@ void itemdb_reload(void); void do_final_itemdb(void); int do_init_itemdb(void); -#endif +#endif /* _ITEMDB_H_ */ diff --git a/src/map/log.h b/src/map/log.h index 872506ac5..9f82f61a2 100644 --- a/src/map/log.h +++ b/src/map/log.h @@ -53,4 +53,4 @@ extern struct Log_Config { char log_branch_db[32], log_pick_db[32], log_zeny_db[32], log_mvpdrop_db[32], log_gm_db[32], log_npc_db[32], log_chat_db[32]; } log_config; -#endif +#endif /* _LOG_H_ */ diff --git a/src/map/mail.h b/src/map/mail.h index d6f865f78..fca124ae4 100644 --- a/src/map/mail.h +++ b/src/map/mail.h @@ -1,8 +1,8 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -// Mail System for eAthena -// Created by Valaris +#ifndef _MAIL_H_ +#define _MAIL_H_ int mail_check(struct map_session_data *sd, int type); int mail_read(struct map_session_data *sd, int message_id); @@ -10,3 +10,5 @@ int mail_delete(struct map_session_data *sd, int message_id); int mail_send(struct map_session_data *sd, char *name, char *message, int flag); int do_init_mail(void); + +#endif /* _MAIL_H_ */ diff --git a/src/map/map.h b/src/map/map.h index a8e24d7fe..69cd1383b 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -1503,4 +1503,4 @@ typedef struct homun_data TBL_HOM; extern int lowest_gm_level; extern char main_chat_nick[16]; -#endif +#endif /* _MAP_H_ */ diff --git a/src/map/mercenary.c b/src/map/mercenary.c index f7799e500..a11373032 100644 --- a/src/map/mercenary.c +++ b/src/map/mercenary.c @@ -1,3 +1,6 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + #include #include #include diff --git a/src/map/mercenary.h b/src/map/mercenary.h index e5e194967..6103acc00 100644 --- a/src/map/mercenary.h +++ b/src/map/mercenary.h @@ -1,5 +1,9 @@ -// Homunculus and future Mercenary system code go here [Celest] -// implemented by [orn] +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef _MERCENARY_H_ +#define _MERCENARY_H_ + struct homunculus_db { int class_ ; char name[NAME_LENGTH]; @@ -81,3 +85,5 @@ int merc_skill_tree_get_max(int id, int b_class); void merc_hom_init_timers(struct homun_data * hd); void merc_skill_reload(void); void merc_reload(void); + +#endif /* _MERCENARY_H_ */ diff --git a/src/map/mob.h b/src/map/mob.h index f13cce8da..09dfb5a2a 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -203,4 +203,4 @@ int mob_clone_delete(int class_); void mob_reload(void); -#endif +#endif /* _MOB_H_ */ diff --git a/src/map/npc.h b/src/map/npc.h index ea28964f5..86bce296c 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -88,5 +88,4 @@ extern char *current_file; struct npc_data *fake_nd; -#endif - +#endif /* _NPC_H_ */ diff --git a/src/map/party.h b/src/map/party.h index 0b7c9a858..4c87dd501 100644 --- a/src/map/party.h +++ b/src/map/party.h @@ -47,4 +47,4 @@ int party_sub_count(struct block_list *bl, va_list ap); int party_foreachsamemap(int (*func)(struct block_list *,va_list),struct map_session_data *sd,int type,...); -#endif +#endif /* _PARTY_H_ */ diff --git a/src/map/pc.h b/src/map/pc.h index f95a27085..dc6be203d 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -315,4 +315,5 @@ int duel_checktime(struct map_session_data* sd); int pc_read_motd(void); // [Valaris] int pc_disguise(struct map_session_data *sd, int class_); -#endif + +#endif /* _PC_H_ */ diff --git a/src/map/pet.h b/src/map/pet.h index 3bb6d0906..821874359 100644 --- a/src/map/pet.h +++ b/src/map/pet.h @@ -65,5 +65,4 @@ int read_petdb(void); int do_init_pet(void); int do_final_pet(void); -#endif - +#endif /* _PET_H_ */ diff --git a/src/map/script.h b/src/map/script.h index 09b4a797b..bad0374dd 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -90,5 +90,4 @@ int script_reload(void); extern char mapreg_txt[]; -#endif - +#endif /* _SCRIPT_H_ */ diff --git a/src/map/skill.h b/src/map/skill.h index ddb9042a0..cab8039c0 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -956,4 +956,4 @@ enum { UNT_GROUNDDRIFT_FIRE, }; -#endif +#endif /* _SKILL_H_ */ diff --git a/src/map/status.h b/src/map/status.h index ce8fbd827..3c8d37e69 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -657,4 +657,4 @@ int status_check_visibility(struct block_list *src, struct block_list *target); int status_readdb(void); int do_init_status(void); -#endif +#endif /* _STATUS_H_ */ diff --git a/src/map/storage.h b/src/map/storage.h index 2140a2ec5..a9f109319 100644 --- a/src/map/storage.h +++ b/src/map/storage.h @@ -42,4 +42,4 @@ int storage_comp_item(const void *_i1, const void *_i2); void sortage_sortitem(struct storage* stor); void sortage_gsortitem(struct guild_storage* gstor); -#endif +#endif /* _STORAGE_H_ */ diff --git a/src/map/trade.h b/src/map/trade.h index bcd609271..cbcf34f2a 100644 --- a/src/map/trade.h +++ b/src/map/trade.h @@ -12,4 +12,4 @@ void trade_tradeok(struct map_session_data *sd); void trade_tradecancel(struct map_session_data *sd); void trade_tradecommit(struct map_session_data *sd); -#endif // _TRADE_H_ +#endif /* _TRADE_H_ */ diff --git a/src/map/unit.c b/src/map/unit.c index 80e0137cf..79dcd3a80 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1,6 +1,6 @@ -// Copyright (c) jAthena Dev Teams - Licensed under GNU GPL +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -// Merged originally from jA by Skotlex + #include #include #include diff --git a/src/map/unit.h b/src/map/unit.h index 9b53f90bf..32fc3cce7 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -1,6 +1,6 @@ -// Copyright (c) jAthena Dev Teams - Licensed under GNU GPL +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -// Merged originally from jA by Skotlex + #ifndef _UNIT_H_ #define _UNIT_H_ @@ -69,4 +69,5 @@ int do_final_unit(void); extern const int dirx[8]; extern const int diry[8]; + #endif /* _UNIT_H_ */ diff --git a/src/map/vending.h b/src/map/vending.h index f4014a894..d9db08b6d 100644 --- a/src/map/vending.h +++ b/src/map/vending.h @@ -11,4 +11,4 @@ void vending_openvending(struct map_session_data *sd,int len,char *message,int f void vending_vendinglistreq(struct map_session_data *sd,int id); void vending_purchasereq(struct map_session_data *sd,int len,int id,unsigned char *p); -#endif // _VENDING_H_ +#endif /* _VENDING_H_ */ -- cgit v1.2.3-70-g09d2 From 3c89751e48a424ce26bc1c6f78f4bf7fb6242fac Mon Sep 17 00:00:00 2001 From: ultramage Date: Sun, 19 Aug 2007 12:55:29 +0000 Subject: * Cleaned/clarified some #include relationships between headers * Changed clif_sitting() to use 'bl' instead of 'sd' (for non-player objects) * Removed way messed-up script function 'unitdeadsit' * Tagged 'FIXME' lines written by myself git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@11040 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 3 ++- conf-tmpl/Changelog.txt | 2 ++ src/map/atcommand.c | 10 +++---- src/map/atcommand.h | 3 ++- src/map/battle.c | 1 + src/map/charcommand.c | 10 +++---- src/map/chat.c | 1 + src/map/chrif.c | 8 ++++-- src/map/clif.c | 69 +++++++++++++++++++++++-------------------------- src/map/clif.h | 17 +++++++++--- src/map/guild.c | 9 ++++--- src/map/guild.h | 6 +++-- src/map/intif.c | 15 ++++++----- src/map/irc.h | 3 ++- src/map/itemdb.c | 9 ++++--- src/map/log.c | 9 ++++--- src/map/log.h | 4 ++- src/map/mail.c | 9 ++++--- src/map/map.c | 22 ++++++++-------- src/map/mercenary.c | 11 ++++---- src/map/mob.c | 13 +++++----- src/map/mob.h | 14 +++++----- src/map/npc.c | 5 ++-- src/map/npc.h | 9 ++++--- src/map/npc_chat.c | 1 + src/map/party.c | 11 ++++---- src/map/party.h | 13 ++++++---- src/map/path.c | 9 ++++--- src/map/pc.c | 53 ++++++++++++++++++------------------- src/map/pc.h | 11 +++++--- src/map/pet.c | 11 ++++---- src/map/script.c | 41 ++--------------------------- src/map/skill.c | 13 +++++----- src/map/skill.h | 4 +-- src/map/status.c | 15 ++++++----- src/map/status.h | 2 +- src/map/storage.c | 12 ++++++--- src/map/storage.h | 13 +++++++--- src/map/trade.c | 7 ++--- src/map/trade.h | 4 ++- src/map/unit.c | 9 ++++--- src/map/unit.h | 4 ++- src/map/vending.c | 7 ++--- src/map/vending.h | 3 ++- 44 files changed, 262 insertions(+), 243 deletions(-) (limited to 'src/map/unit.h') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 6900cbafe..db503d293 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -4,7 +4,8 @@ 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. 2007/08/19 - * Added 'noteleport' mapflags to Dandelion's request maps. [SinSloth] + * Cleaned/clarified some #include relationships between headers + - TODO: pc_read_gm_account() still accessses the RFIFO directly! * Again removed the IG_ list from itemdb.h (see r10100 and r10113) 2007/08/18 * Fixed a deallocation mistake and some buffer overflows in npc_chat.c diff --git a/conf-tmpl/Changelog.txt b/conf-tmpl/Changelog.txt index ba54ae956..50644ea21 100644 --- a/conf-tmpl/Changelog.txt +++ b/conf-tmpl/Changelog.txt @@ -1,5 +1,7 @@ Date Added +2007/08/19 + * Added 'noteleport' mapflags to Dandelion's request maps. [SinSloth] 2007/08/15 * Removed useless 'party_skill_penalty' config option * Removed 'Note 3' & 'Other information' since it doesn't apply anymore diff --git a/src/map/atcommand.c b/src/map/atcommand.c index c179451d8..b57f2bd75 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -1,11 +1,6 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include -#include -#include - #include "../common/cbasetypes.h" #include "../common/mmo.h" #include "../common/timer.h" @@ -42,6 +37,11 @@ #include "mail.h" #endif +#include +#include +#include +#include + char atcommand_symbol = '@'; // first char of the commands (by [Yor]) char *msg_table[MAX_MSG]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others) diff --git a/src/map/atcommand.h b/src/map/atcommand.h index a4fd609d2..e5b00046c 100644 --- a/src/map/atcommand.h +++ b/src/map/atcommand.h @@ -10,7 +10,8 @@ //Note: The range is unlimited unless this define is set. //#define AUTOLOOT_DISTANCE AREA_SIZE -#include "map.h" +//#include "map.h" +struct map_session_data; enum AtCommandType { AtCommand_None = -1, diff --git a/src/map/battle.c b/src/map/battle.c index fe7f238c3..a0ca94e75 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -26,6 +26,7 @@ #include #include + int attr_fix_table[4][ELE_MAX][ELE_MAX]; struct Battle_Config battle_config; diff --git a/src/map/charcommand.c b/src/map/charcommand.c index 008c01a5d..9154048ac 100644 --- a/src/map/charcommand.c +++ b/src/map/charcommand.c @@ -1,11 +1,6 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include -#include -#include - #include "../common/cbasetypes.h" #include "../common/socket.h" #include "../common/timer.h" @@ -34,6 +29,11 @@ #include "trade.h" #include "unit.h" +#include +#include +#include +#include + char charcommand_symbol = '#'; extern char *msg_table[1000]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others) diff --git a/src/map/chat.c b/src/map/chat.c index 3e8ebeb2c..1f8166871 100644 --- a/src/map/chat.c +++ b/src/map/chat.c @@ -16,6 +16,7 @@ #include #include + int chat_triggerevent(struct chat_data *cd); // forward declaration /// Initializes a chatroom object (common functionality for both pc and npc chatrooms). diff --git a/src/map/chrif.c b/src/map/chrif.c index 74733b548..9513c7ea7 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -320,7 +320,7 @@ int chrif_changemapserverack(int account_id, int login_id1, int login_id2, int c if (sd == NULL || sd->status.char_id != char_id) return -1; - if (login_id1 == 1) { //FIXME: charserver says '0'! + if (login_id1 == 1) { //FIXME: charserver says '0'! [ultramage] if (battle_config.error_log) ShowError("map server change failed.\n"); clif_authfail_fd(sd->fd, 0); @@ -507,6 +507,7 @@ int auth_db_cleanup(int tid, unsigned int tick, int id, int data) return 0; } + /*========================================== * *------------------------------------------*/ @@ -929,7 +930,8 @@ int chrif_reloadGMdb(void) *------------------------------------------*/ int chrif_recvgmaccounts(int fd) { - ShowInfo("From login-server: receiving information of '"CL_WHITE"%d"CL_RESET"' GM accounts.\n", pc_read_gm_account(fd)); + int nAccounts = pc_read_gm_account(fd); + ShowInfo("From login-server: receiving information of '"CL_WHITE"%d"CL_RESET"' GM accounts.\n", nAccounts); return 0; } @@ -1288,6 +1290,8 @@ int chrif_parse(int fd) if ((int)RFIFOREST(fd) < packet_len) return 0; + //ShowDebug("Received packet 0x%4x (%d bytes) from char-server (connection %d)\n", RFIFOW(fd,0), packet_len, fd); + switch(cmd) { case 0x2af9: chrif_connectack(fd); break; diff --git a/src/map/clif.c b/src/map/clif.c index b4975ff22..cede06761 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -711,7 +711,7 @@ int clif_clearunit_delayed(struct block_list* bl, unsigned int tick) return 0; } -void clif_get_weapon_view(TBL_PC* sd, unsigned short *rhand, unsigned short *lhand) +void clif_get_weapon_view(struct map_session_data* sd, unsigned short *rhand, unsigned short *lhand) { #if PACKETVER > 3 struct item_data *id; @@ -895,9 +895,9 @@ static int clif_set0078(struct block_list* bl, unsigned char* buf) WBUFW(buf,42)=sc->opt3; } WBUFW(buf,14)=vd->class_; - WBUFW(buf,16)=vd->hair_style; //Required for pets (removes attack cursor) + WBUFW(buf,16)=vd->hair_style; //Required for pets (removes attack cursor) //18W: Weapon - WBUFW(buf,20)=vd->head_bottom; //Pet armor (ignored by client) + WBUFW(buf,20)=vd->head_bottom; //Pet armor (ignored by client) if (bl->type == BL_NPC && vd->class_ == FLAG_CLASS) { //The hell, why flags work like this? WBUFL(buf,22)=emblem_id; @@ -1068,7 +1068,7 @@ static int clif_set007b(struct block_list *bl, struct view_data *vd, struct unit WBUFW(buf,16)=vd->class_; WBUFW(buf,18)=vd->hair_style; //Required for pets (removes attack cursor) //20L: Weapon/Shield - WBUFW(buf,24)=vd->head_bottom; //Pet armor + WBUFW(buf,24)=vd->head_bottom; //Pet armor WBUFL(buf,26)=gettick(); //30W: Head top //32W: Head mid @@ -1098,7 +1098,7 @@ static int clif_set007b(struct block_list *bl, struct view_data *vd, struct unit WBUFW(buf,46)=sc->opt3; } WBUFW(buf,14)=vd->class_; - WBUFW(buf,16)=vd->hair_style; //For pets (disables mob attack cursor) + WBUFW(buf,16)=vd->hair_style; //Required for pets (removes attack cursor) //18W: Weapon WBUFW(buf,20)=vd->head_bottom; //Pet armor WBUFL(buf,22)=gettick(); @@ -1315,10 +1315,9 @@ int clif_spawn(struct block_list *bl) WBUFW(buf,10)=sc->opt2; WBUFW(buf,12)=sc->option; } - WBUFW(buf,14)=vd->hair_style; //For pets (disables mob attack cursor) - //14W: Hair Style + WBUFW(buf,14)=vd->hair_style; //Required for pets (removes attack cursor) //16W: Weapon - WBUFW(buf,18)=vd->head_bottom; //Pet armor (ignored by client) + WBUFW(buf,18)=vd->head_bottom; //Pet armor (ignored by client) WBUFW(buf,20)=vd->class_; //22W: Shield //24W: Head top @@ -1364,7 +1363,7 @@ int clif_spawn(struct block_list *bl) } break; case BL_PET: - if (vd->head_bottom) //Pet armor display fix. + if (vd->head_bottom) clif_pet_equip_area((TBL_PET*)bl); // needed to display pet equip properly break; } @@ -3713,7 +3712,7 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl) clif_refreshlook(&sd->bl,bl->id,LOOK_CLOTHES_COLOR,vd->cloth_color,SELF); switch (bl->type) - { // FIXME: 'AREA' causes unneccessary spam since this should be 1:1 communication + { // FIXME: 'AREA' causes unneccessary spam since this should be 1:1 communication [ultramage] case BL_PC: { TBL_PC* tsd = (TBL_PC*)bl; @@ -3740,8 +3739,8 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl) } break; case BL_PET: - if (vd->head_bottom) //Pet armor display fix. - clif_pet_equip(sd, (TBL_PET*)bl); + if (vd->head_bottom) + clif_pet_equip(sd, (TBL_PET*)bl); // needed to display pet equip properly break; } } @@ -3858,42 +3857,40 @@ void clif_takeitem(struct block_list* src, struct block_list* dst) } /*========================================== - * inform clients in area that `sd` is sitting + * inform clients in area that `bl` is sitting *------------------------------------------*/ -void clif_sitting(struct map_session_data* sd) +void clif_sitting(struct block_list* bl) { unsigned char buf[32]; - - nullpo_retv(sd); + nullpo_retv(bl); WBUFW(buf, 0) = 0x8a; - WBUFL(buf, 2) = sd->bl.id; + WBUFL(buf, 2) = bl->id; WBUFB(buf,26) = 2; - clif_send(buf, packet_len(0x8a), &sd->bl, AREA); + clif_send(buf, packet_len(0x8a), bl, AREA); - if(disguised(&sd->bl)) { - WBUFL(buf, 2) = -sd->bl.id; - clif_send(buf, packet_len(0x8a), &sd->bl, SELF); + if(disguised(bl)) { + WBUFL(buf, 2) = - bl->id; + clif_send(buf, packet_len(0x8a), bl, SELF); } } /*========================================== - * inform clients in area that `sd` is standing + * inform clients in area that `bl` is standing *------------------------------------------*/ -void clif_standing(struct map_session_data* sd) +void clif_standing(struct block_list* bl) { unsigned char buf[32]; - - nullpo_retv(sd); + nullpo_retv(bl); WBUFW(buf, 0) = 0x8a; - WBUFL(buf, 2) = sd->bl.id; + WBUFL(buf, 2) = bl->id; WBUFB(buf,26) = 3; - clif_send(buf, packet_len(0x8a), &sd->bl, AREA); + clif_send(buf, packet_len(0x8a), bl, AREA); - if(disguised(&sd->bl)) { - WBUFL(buf, 2) = -sd->bl.id; - clif_send(buf, packet_len(0x8a), &sd->bl, SELF); + if(disguised(bl)) { + WBUFL(buf, 2) = - bl->id; + clif_send(buf, packet_len(0x8a), bl, SELF); } } @@ -6115,7 +6112,7 @@ int clif_sendegg(struct map_session_data *sd) * type = 5 -> param = hairstyle number * If sd is null, the update is sent to nearby objects, otherwise it is sent only to that player. *------------------------------------------*/ -int clif_send_petdata(struct map_session_data *sd, struct pet_data* pd, int type, int param) +int clif_send_petdata(struct map_session_data* sd, struct pet_data* pd, int type, int param) { uint8 buf[16]; nullpo_retr(0, pd); @@ -8675,7 +8672,7 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, if(pc_issit(sd)) { //Bugged client? Just refresh them. - clif_sitting(sd); + clif_sitting(&sd->bl); return; } @@ -8690,17 +8687,17 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, pc_setsit(sd); skill_sit(sd,1); - clif_sitting(sd); + clif_sitting(&sd->bl); break; case 0x03: // standup if (!pc_issit(sd)) { //Bugged client? Just refresh them. - clif_standing(sd); + clif_standing(&sd->bl); return; } pc_setstand(sd); skill_sit(sd,0); - clif_standing(sd); + clif_standing(&sd->bl); break; } } @@ -10834,7 +10831,7 @@ void clif_parse_PMIgnore(int fd, struct map_session_data *sd) WFIFOSET(fd, packet_len(0x0d1)); //Sort the ignore list. - //FIXME: why not just use a simple shift-and-insert scheme instead? + //FIXME: why not just use a simple shift-and-insert scheme instead? [ultramage] qsort (sd->ignore[0].name, MAX_IGNORE_LIST, sizeof(sd->ignore[0].name), pstrcmp); } else diff --git a/src/map/clif.h b/src/map/clif.h index 0037b832c..6dbb7f59c 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -4,7 +4,16 @@ #ifndef _CLIF_H_ #define _CLIF_H_ -#include "map.h" +#include "../common/cbasetypes.h" +//#include "../common/mmo.h" +struct storage; +struct guild_storage; +//#include "map.h" +struct block_list; +struct map_session_data; +struct homun_data; +struct unit_data; +struct flooritem_data; // server->client protocol version // v7 - 2005-04-11aSakexe+ - 0x229, 0x22a, 0x22b, 0x22c @@ -102,8 +111,8 @@ int clif_updatestatus(struct map_session_data*,int); //self int clif_changestatus(struct block_list*,int,int); //area int clif_damage(struct block_list* src,struct block_list *dst,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2); // area void clif_takeitem(struct block_list* src,struct block_list* dst); -void clif_sitting(struct map_session_data* sd); -void clif_standing(struct map_session_data* sd); +void clif_sitting(struct block_list* bl); +void clif_standing(struct block_list* bl); int clif_changelook(struct block_list *,int,int); // area void clif_changetraplook(struct block_list *bl,int val); // area void clif_refreshlook(struct block_list *bl,int id,int type,int val,int area); //area specified in 'area' @@ -346,7 +355,7 @@ int clif_timedout(struct map_session_data *sd); int clif_disp_overhead(struct map_session_data *sd, const char* mes); -void clif_get_weapon_view(TBL_PC* sd, unsigned short *rhand, unsigned short *lhand); +void clif_get_weapon_view(struct map_session_data* sd, unsigned short *rhand, unsigned short *lhand); int clif_party_xy_remove(struct map_session_data *sd); //Fix for minimap [Kevin] void clif_gospel_info(struct map_session_data *sd, int type); diff --git a/src/map/guild.c b/src/map/guild.c index b1a8ea8a2..462f2cd76 100644 --- a/src/map/guild.c +++ b/src/map/guild.c @@ -1,10 +1,6 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include -#include - #include "../common/cbasetypes.h" #include "../common/timer.h" #include "../common/nullpo.h" @@ -27,6 +23,11 @@ #include "skill.h" #include "log.h" +#include +#include +#include + + static DB guild_db; static DB castle_db; static DB guild_expcache_db; diff --git a/src/map/guild.h b/src/map/guild.h index 07a4b2520..f1bb836ea 100644 --- a/src/map/guild.h +++ b/src/map/guild.h @@ -4,12 +4,14 @@ #ifndef _GUILD_H_ #define _GUILD_H_ -struct map_session_data; -struct mob_data; +//#include "../common/mmo.h" struct guild; struct guild_member; struct guild_position; struct guild_castle; +//#include "map.h" +struct map_session_data; +struct mob_data; int guild_skill_get_max(int id); diff --git a/src/map/intif.c b/src/map/intif.c index 8e66c0e1e..9e7effef3 100644 --- a/src/map/intif.c +++ b/src/map/intif.c @@ -1,13 +1,6 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include -#include -#include -#include -#include - #include "../common/showmsg.h" #include "../common/socket.h" #include "../common/timer.h" @@ -26,6 +19,14 @@ #include "atcommand.h" #include "mercenary.h" //albator +#include +#include +#include +#include +#include +#include + + static const int packet_len_table[]={ -1,-1,27,-1, -1, 0,37, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3800-0x380f -1, 7, 0, 0, 0, 0, 0, 0, -1,11, 0, 0, 0, 0, 0, 0, //0x3810 diff --git a/src/map/irc.h b/src/map/irc.h index 1cf02692c..c1970fb0e 100644 --- a/src/map/irc.h +++ b/src/map/irc.h @@ -4,7 +4,8 @@ #ifndef _IRC_H_ #define _IRC_H_ -#include "map.h" +//#include "map.h" +struct map_session_data; // IRC .conf file [Zido] #define IRC_CONF "irc_athena.conf" diff --git a/src/map/itemdb.c b/src/map/itemdb.c index 4e93dc309..1ba86cbc4 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -1,10 +1,6 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include -#include - #include "../common/nullpo.h" #include "../common/malloc.h" #include "../common/showmsg.h" @@ -15,6 +11,11 @@ #include "script.h" // item script processing #include "pc.h" // W_MUSICAL, W_WHIP +#include +#include +#include + + static struct dbt* item_db; static struct item_group itemgroup_db[MAX_ITEMGROUP]; diff --git a/src/map/log.c b/src/map/log.c index 97726bb6e..e1e35f63d 100644 --- a/src/map/log.c +++ b/src/map/log.c @@ -1,10 +1,6 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include -#include - #include "../common/strlib.h" #include "../common/nullpo.h" #include "../common/showmsg.h" @@ -13,6 +9,11 @@ #include "log.h" #include "battle.h" +#include +#include +#include + + struct Log_Config log_config; char timestring[255]; diff --git a/src/map/log.h b/src/map/log.h index 0e03bf0d8..53fa9dd7c 100644 --- a/src/map/log.h +++ b/src/map/log.h @@ -4,7 +4,9 @@ #ifndef _LOG_H_ #define _LOG_H_ -#include "map.h" +//#include "map.h" +struct map_session_data; +struct mob_data; #ifndef TXT_ONLY diff --git a/src/map/mail.c b/src/map/mail.c index 65d6ed3f3..8433fbada 100644 --- a/src/map/mail.c +++ b/src/map/mail.c @@ -6,10 +6,6 @@ // Created by Valaris // moved all strings to msg_athena.conf [Lupus] -#include -#include -#include - #include "../common/strlib.h" #include "../common/socket.h" #include "../common/timer.h" @@ -24,6 +20,11 @@ #include "pc.h" #include "mail.h" +#include +#include +#include + + int MAIL_CHECK_TIME = 120000; int mail_timer; //extern char *msg_table[1000]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others) diff --git a/src/map/map.c b/src/map/map.c index 971ffc9f0..b2e0fc376 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -1,22 +1,12 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include -#include -#include -#include - -#ifndef _WIN32 -#include -#endif - #include "../common/cbasetypes.h" #include "../common/core.h" #include "../common/timer.h" #include "../common/grfio.h" #include "../common/malloc.h" -#include "../common/socket.h" +#include "../common/socket.h" // WFIFO*() #include "../common/showmsg.h" #include "../common/version.h" #include "../common/nullpo.h" @@ -49,6 +39,16 @@ #include "irc.h" +#include +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#endif + #ifndef TXT_ONLY #include "mail.h" diff --git a/src/map/mercenary.c b/src/map/mercenary.c index ba2898be1..ace039824 100644 --- a/src/map/mercenary.c +++ b/src/map/mercenary.c @@ -1,11 +1,6 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include -#include -#include - #include "../common/cbasetypes.h" #include "../common/malloc.h" #include "../common/socket.h" @@ -36,6 +31,12 @@ #include "mercenary.h" +#include +#include +#include +#include + + //Better equiprobability than rand()% [orn] #define rand(a, b) (a+(int) ((float)(b-a+1)*rand()/(RAND_MAX+1.0))) diff --git a/src/map/mob.c b/src/map/mob.c index 89642430e..c9b77475e 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -1,12 +1,6 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include -#include -#include -#include - #include "../common/cbasetypes.h" #include "../common/timer.h" #include "../common/db.h" @@ -35,6 +29,13 @@ #include "date.h" #include "irc.h" +#include +#include +#include +#include +#include + + #define IDLE_SKILL_INTERVAL 10 //Active idle skills should be triggered every 1 second (1000/MIN_MOBTHINKTIME) #define MOB_LAZYSKILLPERC 10 // Probability for mobs far from players from doing their IDLE skill. (rate of 1000 minute) diff --git a/src/map/mob.h b/src/map/mob.h index 71abe8d8d..944ab84ac 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -4,18 +4,18 @@ #ifndef _MOB_H_ #define _MOB_H_ -#include "unit.h" -#include "map.h" +#include "../common/mmo.h" // struct item +#include "unit.h" // unit_stop_walking(), unit_stop_attack() +#include "map.h" // struct status_data, struct view_data, struct mob_skill #define MAX_RANDOMMONSTER 4 #define MAX_MOB_RACE_DB 6 - /* Change this to increase the table size in your mob_db to accomodate - a larger mob database. Be sure to note that IDs 4001 to 4048 are reserved for advanced/baby/expanded classes. - */ + +// Change this to increase the table size in your mob_db to accomodate a larger mob database. +// Be sure to note that IDs 4001 to 4048 are reserved for advanced/baby/expanded classes. #define MAX_MOB_DB 10000 -//The number of drops all mobs have and the max drop-slot that the steal skill -//will attempt to steal from. +//The number of drops all mobs have and the max drop-slot that the steal skill will attempt to steal from. #define MAX_MOB_DROP 10 #define MAX_STEAL_DROP 7 diff --git a/src/map/npc.c b/src/map/npc.c index 352161189..40df4b678 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -31,7 +31,6 @@ #include - // linked list of npc source files struct npc_src_list { struct npc_src_list* next; @@ -1102,7 +1101,7 @@ int npc_checknear2(struct map_session_data* sd, struct block_list* bl) return 0; } -TBL_NPC* npc_checknear(struct map_session_data* sd, struct block_list* bl) +struct npc_data* npc_checknear(struct map_session_data* sd, struct block_list* bl) { struct npc_data *nd; @@ -2808,7 +2807,7 @@ void npc_parsesrcfile(const char* name) return; } -int npc_script_event(TBL_PC* sd, int type) +int npc_script_event(struct map_session_data* sd, int type) { int i; if (type < 0 || type >= NPCE_MAX) diff --git a/src/map/npc.h b/src/map/npc.h index 2ce21d473..9b3c5782b 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -4,7 +4,10 @@ #ifndef _NPC_H_ #define _NPC_H_ -#include "map.h" // TBL_NPC +//#include "map.h" +struct block_list; +struct npc_data; +struct view_data; #define START_NPC_NUM 110000000 @@ -47,7 +50,7 @@ int npc_touch_areanpc2(struct block_list* bl); // [Skotlex] int npc_check_areanpc(int flag, int m, int x, int y, int range); int npc_click(struct map_session_data* sd, struct npc_data* nd); int npc_scriptcont(struct map_session_data* sd, int id); -TBL_NPC* npc_checknear(struct map_session_data* sd, struct block_list* bl); +struct npc_data* npc_checknear(struct map_session_data* sd, struct block_list* bl); int npc_checknear2(struct map_session_data* sd, struct block_list* bl); int npc_buysellsel(struct map_session_data* sd, int id, int type); int npc_buylist(struct map_session_data* sd,int n, unsigned short* item_list); @@ -87,7 +90,7 @@ void npc_unload_duplicates (struct npc_data* nd); int npc_unload(struct npc_data* nd); int npc_reload(void); void npc_read_event_script(void); -int npc_script_event(TBL_PC* sd, int type); +int npc_script_event(struct map_session_data* sd, int type); struct npc_data *fake_nd; diff --git a/src/map/npc_chat.c b/src/map/npc_chat.c index a1fdae0bc..5094a1d90 100644 --- a/src/map/npc_chat.c +++ b/src/map/npc_chat.c @@ -19,6 +19,7 @@ #include #include + /** * Written by MouseJstr in a vision... (2/21/2005) * diff --git a/src/map/party.c b/src/map/party.c index 43835f94f..eeb3d5b9a 100644 --- a/src/map/party.c +++ b/src/map/party.c @@ -1,13 +1,9 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include -#include - #include "../common/cbasetypes.h" #include "../common/timer.h" -#include "../common/socket.h" +#include "../common/socket.h" // last_tick #include "../common/nullpo.h" #include "../common/malloc.h" #include "../common/showmsg.h" @@ -23,6 +19,11 @@ #include "status.h" #include "itemdb.h" +#include +#include +#include + + static DB party_db; int party_share_level = 10; int party_send_xy_timer(int tid,unsigned int tick,int id,int data); diff --git a/src/map/party.h b/src/map/party.h index ac08e8cf2..cb38c9d10 100644 --- a/src/map/party.h +++ b/src/map/party.h @@ -4,13 +4,16 @@ #ifndef _PARTY_H_ #define _PARTY_H_ +//#include "map.h" +struct block_list; +struct map_session_data; +struct party; +struct party_data; +struct item; + #include -#include "map.h" extern int party_share_level; -struct party; -struct map_session_data; -struct block_list; void do_init_party(void); void do_final_party(void); @@ -41,7 +44,7 @@ int party_check_conflict(struct map_session_data *sd); int party_skill_check(struct map_session_data *sd, int party_id, int skillid, int skilllv); int party_send_xy_clear(struct party_data *p); int party_exp_share(struct party_data *p,struct block_list *src,unsigned int base_exp,unsigned int job_exp,int zeny); -int party_share_loot(struct party_data* p, TBL_PC* sd, struct item* item_data, int first); +int party_share_loot(struct party_data* p, struct map_session_data* sd, struct item* item_data, int first); int party_send_dot_remove(struct map_session_data *sd); int party_sub_count(struct block_list *bl, va_list ap); int party_foreachsamemap(int (*func)(struct block_list *,va_list),struct map_session_data *sd,int type,...); diff --git a/src/map/path.c b/src/map/path.c index 471e51e71..da96433ad 100644 --- a/src/map/path.c +++ b/src/map/path.c @@ -1,10 +1,6 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include -#include - #include "../common/cbasetypes.h" #include "../common/nullpo.h" #include "../common/showmsg.h" @@ -16,6 +12,11 @@ #include "memwatch.h" #endif +#include +#include +#include + + //#define PATH_STANDALONETEST #define MAX_HEAP 150 diff --git a/src/map/pc.c b/src/map/pc.c index 2ab6fbb0c..e73f0a06e 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1,47 +1,44 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include -#include -#include - #include "../common/cbasetypes.h" -#include "../common/socket.h" // [Valaris] -#include "../common/timer.h" +#include "../common/core.h" // get_svn_revision() +#include "../common/malloc.h" #include "../common/nullpo.h" #include "../common/showmsg.h" -#include "../common/malloc.h" -#include "../common/core.h" +#include "../common/socket.h" // RFIFO*() +#include "../common/timer.h" -#include "map.h" +#include "atcommand.h" // get_atcommand_level() +#include "battle.h" // battle_config #include "chrif.h" #include "clif.h" +#include "date.h" // is_day_of_*() #include "intif.h" -#include "pc.h" -#include "status.h" -#include "npc.h" -#include "mob.h" -#include "pet.h" -#include "mercenary.h" //orn #include "itemdb.h" -#include "script.h" -#include "battle.h" -#include "skill.h" -#include "party.h" -#include "guild.h" -#include "chat.h" -#include "trade.h" -#include "storage.h" -#include "vending.h" -#include "atcommand.h" #include "log.h" -#include "date.h" +#include "map.h" +#include "mercenary.h" // merc_is_hom_active() +#include "mob.h" // MAX_MOB_RACE_DB +#include "npc.h" // fake_nd +#include "pet.h" // pet_unlocktarget() +#include "party.h" // party_search() +#include "guild.h" // guild_search(), guild_request_info() +#include "script.h" // script_config +#include "skill.h" +#include "status.h" // struct status_data +#include "vending.h" // vending_closevending() +#include "pc.h" #ifndef TXT_ONLY // mail system [Valaris] #include "mail.h" #endif +#include +#include +#include + + #define PVP_CALCRANK_INTERVAL 1000 // PVP順位計算の間隔 static unsigned int exp_table[MAX_PC_CLASS][2][MAX_LEVEL]; static unsigned int max_level[MAX_PC_CLASS][2]; @@ -6894,6 +6891,7 @@ int pc_autosave(int tid,unsigned int tick,int id,int data) int pc_read_gm_account(int fd) { + //FIXME: this implementation is a total failure (direct reading from RFIFO) [ultramage] int i = 0; if (gm_account != NULL) aFree(gm_account); @@ -6902,7 +6900,6 @@ int pc_read_gm_account(int fd) for (i = 4; i < RFIFOW(fd,2); i += 5) { gm_account[GM_num].account_id = RFIFOL(fd,i); gm_account[GM_num].level = (int)RFIFOB(fd,i+4); - //printf("GM account: %d -> level %d\n", gm_account[GM_num].account_id, gm_account[GM_num].level); GM_num++; } return GM_num; diff --git a/src/map/pc.h b/src/map/pc.h index 7e0a8f7bb..ae7aeeda5 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -4,9 +4,12 @@ #ifndef _PC_H_ #define _PC_H_ -#include "map.h" -#include "unit.h" -#include "status.h" +#include "../common/mmo.h" // JOB_*, MAX_FAME_LIST, struct fame_list, struct mmo_charstatus +#include "../common/timer.h" // INVALID_TIMER +#include "battle.h" // battle_config +#include "map.h" // MAX_PC_CLASS, struct map_session_data +#include "status.h" // OPTION_* +#include "unit.h" // unit_stop_attack(), unit_stop_walking() //Update this max as necessary. 53 is the value needed for Super Baby currently #define MAX_SKILL_TREE 53 @@ -89,7 +92,7 @@ enum { #define pc_setsit(sd) ((sd)->state.dead_sit = (sd)->vd.dead_sit = 2) #define pc_isdead(sd) ((sd)->state.dead_sit == 1) #define pc_issit(sd) ((sd)->vd.dead_sit == 2) -#define pc_isidle(sd) ((sd)->chatID || (sd)->vender_id || DIFF_TICK(last_tick, sd->idletime) >= battle_config.idle_no_share) +#define pc_isidle(sd) ((sd)->chatID || (sd)->vender_id || DIFF_TICK(last_tick, (sd)->idletime) >= battle_config.idle_no_share) #define pc_setdir(sd,b,h) ((sd)->ud.dir = (b) ,(sd)->head_dir = (h) ) #define pc_setchatid(sd,n) ((sd)->chatID = n) #define pc_ishiding(sd) ((sd)->sc.option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK)) diff --git a/src/map/pet.c b/src/map/pet.c index d9743332a..ebfbc6a0e 100644 --- a/src/map/pet.c +++ b/src/map/pet.c @@ -1,10 +1,6 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include -#include - #include "../common/db.h" #include "../common/timer.h" #include "../common/nullpo.h" @@ -28,6 +24,11 @@ #include "unit.h" #include "atcommand.h" +#include +#include +#include + + #define MIN_PETTHINKTIME 100 struct pet_db pet_db[MAX_PET_DB]; @@ -555,7 +556,7 @@ int pet_catch_process2(struct map_session_data* sd, int target_id) return 1; } - //FIXME: delete taming item here, if this was an item-invoked capture and the item was flagged as delay-consume + //FIXME: delete taming item here, if this was an item-invoked capture and the item was flagged as delay-consume [ultramage] i = search_petDB_index(md->class_,PET_CLASS); //catch_target_class == 0 is used for universal lures (except bosses for now). [Skotlex] diff --git a/src/map/script.c b/src/map/script.c index 472b4e545..86019c40e 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -8,7 +8,6 @@ //#define DEBUG_HASH #include "../common/cbasetypes.h" -#include "../common/socket.h" #include "../common/timer.h" #include "../common/malloc.h" #include "../common/lock.h" @@ -53,6 +52,7 @@ #include #include + /////////////////////////////////////////////////////////////////////////////// //## TODO possible enhancements: [FlavioJS] // - 'callfunc' supporting labels in the current npc "::LabelName" @@ -4031,7 +4031,6 @@ BUILDIN_FUNC(unitattack); BUILDIN_FUNC(unitstop); BUILDIN_FUNC(unittalk); BUILDIN_FUNC(unitemote); -BUILDIN_FUNC(unitdeadsit); BUILDIN_FUNC(unitskilluseid); // originally by Qamera [celest] BUILDIN_FUNC(unitskillusepos); // originally by Qamera [celest] // <--- [zBuffer] List of mob control commands @@ -4373,7 +4372,6 @@ struct script_function buildin_func[] = { BUILDIN_DEF(unitstop,"i"), BUILDIN_DEF(unittalk,"is"), BUILDIN_DEF(unitemote,"ii"), - BUILDIN_DEF(unitdeadsit,"ii"), BUILDIN_DEF(unitskilluseid,"iii?"), // originally by Qamera [Celest] BUILDIN_DEF(unitskillusepos,"iiiii"), // [Celest] // <--- [zBuffer] List of mob control commands @@ -10667,7 +10665,7 @@ BUILDIN_FUNC(soundeffectall) name = script_getstr(st,2); type = script_getnum(st,3); - //FIXME: enumerating map squares (map_foreach) is slower than enumerating the list of online players (map_foreachpc?) + //FIXME: enumerating map squares (map_foreach) is slower than enumerating the list of online players (map_foreachpc?) [ultramage] if(!script_hasdata(st,4)) { // area around @@ -13075,41 +13073,6 @@ BUILDIN_FUNC(unitemote) return 0; } -/// Makes the unit do an action -/// TODO actions -/// -/// unitdeadsit ,; -BUILDIN_FUNC(unitdeadsit) -{ - int unit_id; - int action; - struct block_list* bl; - - unit_id = script_getnum(st,2); - action = script_getnum(st,3); - - bl = map_id2bl(unit_id); - if( bl != NULL ) - { - if( action > -1 && action < 4 ) - { - unsigned char buf[61] = ""; - struct view_data *vd = status_get_viewdata(bl); - if (vd) vd->dead_sit = action; - WBUFW(buf, 0) = 0x8a; - WBUFL(buf, 2) = bl->id; - WBUFB(buf,26) = (unsigned char)action; - clif_send(buf, 61, bl, AREA); - } else - { - ShowWarning("script:unitdeadsit: %d is not a valid action\n", action); - return 1; - } - } - - return 0; -} - /// Makes the unit cast the skill on the target or self if no target is specified /// /// unitskilluseid ,,{,}; diff --git a/src/map/skill.c b/src/map/skill.c index 668020026..b8abc15c8 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -1,11 +1,6 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include -#include -#include - #include "../common/cbasetypes.h" #include "../common/timer.h" #include "../common/nullpo.h" @@ -33,6 +28,12 @@ #include "date.h" #include "unit.h" +#include +#include +#include +#include + + #define SKILLUNITTIMER_INVERVAL 100 //Guild Skills are shifted to these to make them stick into the skill array. #define GD_SKILLRANGEMIN 900 @@ -8006,7 +8007,7 @@ static int skill_check_condition_mob_master_sub (struct block_list *bl, va_list * Determines if a given skill should be made to consume ammo * when used by the player. [Skotlex] *------------------------------------------*/ -int skill_isammotype (TBL_PC *sd, int skill) +int skill_isammotype (struct map_session_data *sd, int skill) { return ( battle_config.arrow_decrement==2 && diff --git a/src/map/skill.h b/src/map/skill.h index a612a2798..68b5872f6 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -4,7 +4,7 @@ #ifndef _SKILL_H_ #define _SKILL_H_ -#include "map.h" +#include "map.h" // MAX_SKILL_LEVEL, ... #define MAX_SKILL_DB 1100 #define MAX_SKILL_PRODUCE_DB 150 @@ -187,7 +187,7 @@ int skill_tree_get_max( int id, int b_class ); // Celest const char* skill_get_name( int id ); // [Skotlex] const char* skill_get_desc( int id ); // [Skotlex] -int skill_isammotype(TBL_PC *sd, int skill); +int skill_isammotype(struct map_session_data *sd, int skill); int skill_castend_id( int tid, unsigned int tick, int id,int data ); int skill_castend_pos( int tid, unsigned int tick, int id,int data ); int skill_castend_map( struct map_session_data *sd,int skill_num, const char *map); diff --git a/src/map/status.c b/src/map/status.c index 21ab964a5..a08595952 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -1,12 +1,6 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include -#include -#include -#include - #include "../common/cbasetypes.h" #include "../common/timer.h" #include "../common/nullpo.h" @@ -29,6 +23,13 @@ #include "unit.h" #include "mercenary.h" +#include +#include +#include +#include +#include + + //For specifying where in the SkillStatusChangeTableArray the "out of bounds" skills get stored. [Skotlex] #define SC_HM_BASE 800 #define SC_GD_BASE 900 @@ -5323,7 +5324,7 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val case SC_TENSIONRELAX: if (sd) { pc_setsit(sd); - clif_sitting(sd); + clif_sitting(&sd->bl); } val2 = 12; //SP cost val4 = 10000; //Decrease at 10secs intervals. diff --git a/src/map/status.h b/src/map/status.h index 793989c53..551991d1c 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -4,7 +4,7 @@ #ifndef _STATUS_H_ #define _STATUS_H_ -// forward declarations from map.h +//#include "map.h" struct block_list; struct mob_data; struct pet_data; diff --git a/src/map/storage.c b/src/map/storage.c index 574028872..5d9b67778 100644 --- a/src/map/storage.c +++ b/src/map/storage.c @@ -1,14 +1,13 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include -#include - +#include "../common/cbasetypes.h" +#include "../common/db.h" #include "../common/nullpo.h" #include "../common/malloc.h" #include "../common/showmsg.h" +#include "map.h" // struct map_session_data #include "storage.h" #include "chrif.h" #include "itemdb.h" @@ -20,6 +19,11 @@ #include "atcommand.h" #include "log.h" +#include +#include +#include + + static struct dbt *storage_db; static struct dbt *guild_storage_db; diff --git a/src/map/storage.h b/src/map/storage.h index bd8c5fdc6..6764d4956 100644 --- a/src/map/storage.h +++ b/src/map/storage.h @@ -4,7 +4,12 @@ #ifndef _STORAGE_H_ #define _STORAGE_H_ -#include "../common/mmo.h" +//#include "../common/mmo.h" +struct storage; +struct guild_storage; +struct item; +//#include "map.h" +struct map_session_data; int storage_storageopen(struct map_session_data *sd); int storage_storageadd(struct map_session_data *sd,int index,int amount); @@ -15,15 +20,15 @@ int storage_storageclose(struct map_session_data *sd); int do_init_storage(void); void do_final_storage(void); void do_reconnect_storage(void); -struct storage *account2storage(int account_id); -struct storage *account2storage2(int account_id); +struct storage* account2storage(int account_id); +struct storage* account2storage2(int account_id); int storage_delete(int account_id); int storage_storage_quit(struct map_session_data *sd, int flag); int storage_storage_save(int account_id, int final); int storage_storage_saved(int account_id); //Ack from char server that guild store was saved. void storage_storage_dirty(struct map_session_data *sd); -struct guild_storage *guild2storage(int guild_id); +struct guild_storage* guild2storage(int guild_id); int guild_storage_delete(int guild_id); int storage_guild_storageopen(struct map_session_data *sd); int guild_storage_additem(struct map_session_data *sd,struct guild_storage *stor,struct item *item_data,int amount); diff --git a/src/map/trade.c b/src/map/trade.c index 73d5a6d42..a58df1eeb 100644 --- a/src/map/trade.c +++ b/src/map/trade.c @@ -1,9 +1,6 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include - #include "../common/nullpo.h" #include "clif.h" #include "itemdb.h" @@ -18,6 +15,10 @@ #include "atcommand.h" #include "log.h" +#include +#include + + //Max distance from traders to enable a trade to take place. #define TRADE_DISTANCE 2 diff --git a/src/map/trade.h b/src/map/trade.h index cbcf34f2a..cdcae7492 100644 --- a/src/map/trade.h +++ b/src/map/trade.h @@ -4,7 +4,9 @@ #ifndef _TRADE_H_ #define _TRADE_H_ -#include "map.h" +//#include "map.h" +struct map_session_data; + void trade_traderequest(struct map_session_data *sd, struct map_session_data *target_sd); void trade_tradeack(struct map_session_data *sd,int type); void trade_tradeadditem(struct map_session_data *sd,int index,int amount); diff --git a/src/map/unit.c b/src/map/unit.c index 80267bd49..ba3f9926a 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1,10 +1,6 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include -#include - #include "../common/showmsg.h" #include "../common/timer.h" #include "../common/nullpo.h" @@ -30,6 +26,11 @@ #include "chrif.h" #include "script.h" +#include +#include +#include + + const int dirx[8]={0,-1,-1,-1,0,1,1,1}; const int diry[8]={1,1,0,-1,-1,-1,0,1}; diff --git a/src/map/unit.h b/src/map/unit.h index 32fc3cce7..83858fb5d 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -4,7 +4,9 @@ #ifndef _UNIT_H_ #define _UNIT_H_ -#include "map.h" +//#include "map.h" +struct block_list; +struct unit_data; // PC, MOB, PET に共通する処理を1つにまとめる計画 diff --git a/src/map/vending.c b/src/map/vending.c index a84189407..c44cb333f 100644 --- a/src/map/vending.c +++ b/src/map/vending.c @@ -1,9 +1,6 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include -#include - #include "../common/nullpo.h" #include "clif.h" #include "itemdb.h" @@ -18,6 +15,10 @@ #include "irc.h" +#include +#include + + /*========================================== * 露店閉鎖 *------------------------------------------*/ diff --git a/src/map/vending.h b/src/map/vending.h index d9db08b6d..3b247e549 100644 --- a/src/map/vending.h +++ b/src/map/vending.h @@ -4,7 +4,8 @@ #ifndef _VENDING_H_ #define _VENDING_H_ -#include "map.h" +//#include "map.h" +struct map_session_data; void vending_closevending(struct map_session_data *sd); void vending_openvending(struct map_session_data *sd,int len,char *message,int flag,unsigned char *p); -- cgit v1.2.3-70-g09d2 From 2bc59ef9db7a86d0c483e3848ead57d6d691e6a3 Mon Sep 17 00:00:00 2001 From: ultramage Date: Thu, 18 Oct 2007 21:25:26 +0000 Subject: Fixed numerous /W4 warnings (and created more :) git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@11514 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/common/mapindex.c | 2 +- src/common/mmo.h | 1 + src/map/atcommand.c | 7 ++++--- src/map/battle.c | 39 +++++++++++++++------------------------ src/map/battle.h | 7 +++---- src/map/clif.c | 35 +++++++++++++++++++---------------- src/map/clif.h | 2 +- src/map/map.c | 4 ++-- src/map/map.h | 14 +++++++------- src/map/mob.h | 2 +- src/map/npc.c | 4 ++-- src/map/pc.c | 10 ++++------ src/map/pc.h | 2 +- src/map/script.c | 7 ++++--- src/map/skill.c | 21 ++++++++++----------- src/map/skill.h | 10 +++++----- src/map/status.c | 46 +++++++++++++++++++++++----------------------- src/map/trade.c | 5 +++-- src/map/trade.h | 2 +- src/map/unit.c | 35 +++++++++++++++++++---------------- src/map/unit.h | 26 +++++++++++++------------- src/map/vending.c | 14 +++++++------- 22 files changed, 146 insertions(+), 149 deletions(-) (limited to 'src/map/unit.h') diff --git a/src/common/mapindex.c b/src/common/mapindex.c index 0c275c41a..b76a838be 100644 --- a/src/common/mapindex.c +++ b/src/common/mapindex.c @@ -17,7 +17,7 @@ struct _indexes { char name[MAP_NAME_LENGTH]; //Stores map name } indexes[MAX_MAPINDEX]; -static unsigned short max_index = 0; +int max_index = 0; char mapindex_cfgfile[80] = "db/map_index.txt"; diff --git a/src/common/mmo.h b/src/common/mmo.h index 18b724e56..ff74b1272 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -25,6 +25,7 @@ //Number of slots carded equipment can have. Never set to less than 4 as they are also used to keep the data of forged items/equipment. [Skotlex] //Note: The client seems unable to receive data for more than 4 slots due to all related packets having a fixed size. #define MAX_SLOTS 4 +//Max amount of a single stacked item #define MAX_AMOUNT 30000 #define MAX_ZENY 1000000000 #define MAX_FAME 1000000000 diff --git a/src/map/atcommand.c b/src/map/atcommand.c index dd022b9c8..5bcd80590 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -2781,12 +2781,13 @@ static int atcommand_stopattack(struct block_list *bl,va_list ap) /*========================================== * *------------------------------------------*/ -static int atcommand_pvpoff_sub(struct block_list *bl,va_list ap) { +static int atcommand_pvpoff_sub(struct block_list *bl,va_list ap) +{ TBL_PC* sd = (TBL_PC*)bl; clif_pvpset(sd, 0, 0, 2); - if (sd->pvp_timer != UINT_MAX) { + if (sd->pvp_timer != -1) { delete_timer(sd->pvp_timer, pc_calc_pvprank_timer); - sd->pvp_timer = UINT_MAX; + sd->pvp_timer = -1; } return 0; } diff --git a/src/map/battle.c b/src/map/battle.c index a6e6d64ab..16f33ea0a 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -144,7 +144,7 @@ struct delay_damage { unsigned short distance; unsigned short skill_lv; unsigned short skill_id; - unsigned short dmg_lv; + enum damage_lv dmg_lv; unsigned short attack_type; }; @@ -168,7 +168,7 @@ int battle_delay_damage_sub (int tid, unsigned int tick, int id, int data) return 0; } -int battle_delay_damage (unsigned int tick, struct block_list *src, struct block_list *target, int attack_type, int skill_id, int skill_lv, int damage, int dmg_lv, int ddelay) +int battle_delay_damage (unsigned int tick, struct block_list *src, struct block_list *target, int attack_type, int skill_id, int skill_lv, int damage, enum damage_lv dmg_lv, int ddelay) { struct delay_damage *dat; nullpo_retr(0, src); @@ -836,10 +836,10 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * static struct Damage battle_calc_weapon_attack( struct block_list *src,struct block_list *target,int skill_num,int skill_lv,int wflag) { - unsigned short skillratio = 100; //Skill dmg modifiers. + unsigned int skillratio = 100; //Skill dmg modifiers. short skill=0; short s_ele, s_ele_, t_class; - short i, nk; + int i, nk; struct map_session_data *sd, *tsd; struct Damage wd; @@ -1838,8 +1838,8 @@ static struct Damage battle_calc_weapon_attack( //Card Fix, sd side if ((wd.damage || wd.damage2) && !(nk&NK_NO_CARDFIX_ATK)) { - short cardfix = 1000, cardfix_ = 1000; - short t_race2 = status_get_race2(target); + int cardfix = 1000, cardfix_ = 1000; + int t_race2 = status_get_race2(target); if(sd->state.arrow_atk) { cardfix=cardfix*(100+sd->right_weapon.addrace[tstatus->race]+sd->arrow_addrace[tstatus->race])/100; @@ -2097,12 +2097,11 @@ static struct Damage battle_calc_weapon_attack( /*========================================== * battle_calc_magic_attack [DracoRPG] *------------------------------------------*/ -struct Damage battle_calc_magic_attack( - struct block_list *src,struct block_list *target,int skill_num,int skill_lv,int mflag) - { - short i, nk; +struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list *target,int skill_num,int skill_lv,int mflag) +{ + int i, nk; short s_ele; - unsigned short skillratio = 100; //Skill dmg modifiers. + unsigned int skillratio = 100; //Skill dmg modifiers. struct map_session_data *sd, *tsd; struct Damage ad; @@ -2392,7 +2391,7 @@ struct Damage battle_calc_magic_attack( { //Target cards. short s_race2=status_get_race2(src); short s_class= status_get_class(src); - short cardfix=1000; + int cardfix=1000; if (!(nk&NK_NO_ELEFIX)) cardfix=cardfix*(100-tsd->subele[s_ele])/100; @@ -2598,11 +2597,7 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list } hitrate+= sstatus->hit - flee; - - if (hitrate > battle_config.max_hitrate) - hitrate = battle_config.max_hitrate; - else if (hitrate < battle_config.min_hitrate) - hitrate = battle_config.min_hitrate; + hitrate = cap_value(hitrate, battle_config.min_hitrate, battle_config.max_hitrate); if(rand()%100 < hitrate) i = 1; @@ -2733,15 +2728,11 @@ void battle_drain(TBL_PC *sd, struct block_list *tbl, int rdamage, int ldamage, hp = wd->hp_drain[type].value; if (wd->hp_drain[type].rate) - hp += battle_calc_drain(*damage, - wd->hp_drain[type].rate, - wd->hp_drain[type].per); + hp += battle_calc_drain(*damage, wd->hp_drain[type].rate, wd->hp_drain[type].per); sp = wd->sp_drain[type].value; if (wd->sp_drain[type].rate) - sp += battle_calc_drain(*damage, - wd->sp_drain[type].rate, - wd->sp_drain[type].per); + sp += battle_calc_drain(*damage, wd->sp_drain[type].rate, wd->sp_drain[type].per); if (hp) { if (wd->hp_drain[type].type) @@ -2768,7 +2759,7 @@ void battle_drain(TBL_PC *sd, struct block_list *tbl, int rdamage, int ldamage, /*========================================== * 通??U撃??まとめ *------------------------------------------*/ -int battle_weapon_attack(struct block_list* src, struct block_list* target, unsigned int tick, int flag) +enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* target, unsigned int tick, int flag) { struct map_session_data *sd = NULL, *tsd = NULL; struct status_data *sstatus, *tstatus; diff --git a/src/map/battle.h b/src/map/battle.h index abd877785..e7d385b3c 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -11,7 +11,7 @@ struct Damage { int amotion,dmotion; int blewcount; int flag; - int dmg_lv; //ATK_LUCKY,ATK_FLEE,ATK_DEF + enum damage_lv dmg_lv; //ATK_LUCKY,ATK_FLEE,ATK_DEF }; // 属性表(読み込みはpc.c、battle_attr_fixで使用) @@ -48,11 +48,10 @@ enum { // BF_SKILLMASK= 0x0f00, }; -int battle_delay_damage (unsigned int tick, struct block_list *src, struct block_list *target, int attack_type, int skill_id, int skill_lv, int damage, int dmg_lv, int ddelay); +int battle_delay_damage (unsigned int tick, struct block_list *src, struct block_list *target, int attack_type, int skill_id, int skill_lv, int damage, enum damage_lv dmg_lv, int ddelay); // 通常攻撃処理まとめ -int battle_weapon_attack( struct block_list *bl,struct block_list *target, - unsigned int tick,int flag); +enum damage_lv battle_weapon_attack( struct block_list *bl,struct block_list *target,unsigned int tick,int flag); // 各種パラメータを得る struct block_list* battle_get_master(struct block_list *src); diff --git a/src/map/clif.c b/src/map/clif.c index 0ace107aa..b67e2cd87 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -3925,7 +3925,7 @@ static void clif_getareachar_skillunit(struct map_session_data *sd, struct skill WFIFOB(fd,14)=unit->group->unit_id; WFIFOB(fd,15)=1; WFIFOB(fd,16)=1; - safestrncpy(WFIFOP(fd,17),unit->group->valstr,MESSAGE_SIZE); + safestrncpy((char*)WFIFOP(fd,17),unit->group->valstr,MESSAGE_SIZE); WFIFOSET(fd,packet_len(0x1c9)); return; } @@ -4559,7 +4559,7 @@ void clif_skill_setunit(struct skill_unit *unit) /*========================================== * ワープ場所選択 *------------------------------------------*/ -void clif_skill_warppoint(struct map_session_data* sd, int skill_num, int skill_lv, int map1, int map2, int map3, int map4) +void clif_skill_warppoint(struct map_session_data* sd, short skill_num, short skill_lv, unsigned short map1, unsigned short map2, unsigned short map3, unsigned short map4) { int fd; nullpo_retv(sd); @@ -5017,7 +5017,7 @@ int clif_solved_charname(int fd, int charid, const char* name) WFIFOHEAD(fd,packet_len(0x194)); WFIFOW(fd,0)=0x194; WFIFOL(fd,2)=charid; - safestrncpy(WFIFOP(fd,6), name, NAME_LENGTH); + safestrncpy((char*)WFIFOP(fd,6), name, NAME_LENGTH); WFIFOSET(fd,packet_len(0x194)); return 0; } @@ -8145,7 +8145,7 @@ void clif_parse_Hotkey(int fd, struct map_session_data *sd) { *------------------------------------------*/ void clif_parse_WalkToXY(int fd, struct map_session_data *sd) { - int x, y; + short x, y; int cmd; if (pc_isdead(sd)) { @@ -9112,13 +9112,13 @@ void clif_parse_TradeAck(int fd,struct map_session_data *sd) *------------------------------------------*/ void clif_parse_TradeAddItem(int fd,struct map_session_data *sd) { - int index = RFIFOW(fd,2); + short index = RFIFOW(fd,2); int amount = RFIFOL(fd,4); if( index == 0 ) trade_tradeaddzeny(sd, amount); else - trade_tradeadditem(sd, index, amount); + trade_tradeadditem(sd, index, (short)amount); } /*========================================== @@ -9218,7 +9218,7 @@ void clif_parse_SkillUp(int fd,struct map_session_data *sd) pc_skillup(sd,RFIFOW(fd,2)); } -static void clif_parse_UseSkillToId_homun(struct homun_data *hd, struct map_session_data *sd, unsigned int tick, int skillnum, int skilllv, int target_id) +static void clif_parse_UseSkillToId_homun(struct homun_data *hd, struct map_session_data *sd, unsigned int tick, short skillnum, short skilllv, int target_id) { int lv; @@ -9251,14 +9251,16 @@ static void clif_parse_UseSkillToId_homun(struct homun_data *hd, struct map_sess *------------------------------------------*/ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) { - int skillnum, skilllv, tmp, target_id; + short skillnum, skilllv; + int tmp, target_id; unsigned int tick = gettick(); skilllv = RFIFOW(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]); - if (skilllv < 1) skilllv = 1; //No clue, I have seen the client do this with guild skills :/ [Skotlex] skillnum = RFIFOW(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[1]); target_id = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[2]); + if (skilllv < 1) skilllv = 1; //No clue, I have seen the client do this with guild skills :/ [Skotlex] + //Whether skill fails or not is irrelevant, the char ain't idle. [Skotlex] sd->idletime = last_tick; @@ -9364,7 +9366,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) /*========================================== * スキル使用(場所指定) *------------------------------------------*/ -void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, int skilllv, int skillnum, int x, int y, int skillmoreinfo) +void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, short skilllv, short skillnum, short x, short y, int skillmoreinfo) { int lv; unsigned int tick = gettick(); @@ -9460,7 +9462,7 @@ void clif_parse_UseSkillToPosMoreInfo(int fd, struct map_session_data *sd) *------------------------------------------*/ void clif_parse_UseSkillMap(int fd, struct map_session_data* sd) { - int skill_num = RFIFOW(fd,2); + short skill_num = RFIFOW(fd,2); char map_name[MAP_NAME_LENGTH]; mapindex_getmapname((char*)RFIFOP(fd,4), map_name); @@ -9858,7 +9860,7 @@ void clif_parse_PartyInvite(int fd, struct map_session_data *sd) void clif_parse_PartyInvite2(int fd, struct map_session_data *sd) { struct map_session_data *t_sd; - char *name = RFIFOP(fd,2); + char *name = (char*)RFIFOP(fd,2); name[NAME_LENGTH]='\0'; if(map[sd->bl.m].flag.partylock) @@ -11239,7 +11241,7 @@ void clif_parse_HomMoveToMaster(int fd, struct map_session_data *sd) void clif_parse_HomMoveTo(int fd,struct map_session_data *sd) { //[orn] - int x,y,cmd; + short x,y,cmd; nullpo_retv(sd); if(!merc_is_hom_active(sd->hd)) @@ -11487,7 +11489,7 @@ static int packetdb_readdb(void) FILE *fp; char line[1024]; int ln=0; - int cmd,i,j,k,packet_ver; + int cmd,i,j,packet_ver; int max_cmd=-1; int skip_ver = 0; int warned = 0; @@ -11792,8 +11794,8 @@ static int packetdb_readdb(void) ShowError("packet_db: packet len error\n"); continue; } - k = atoi(str[1]); - packet_db[packet_ver][cmd].len = k; + + packet_db[packet_ver][cmd].len = (short)atoi(str[1]); if(str[2]==NULL){ packet_db[packet_ver][cmd].func = NULL; @@ -11826,6 +11828,7 @@ static int packetdb_readdb(void) exit(EXIT_FAILURE); } for(j=0,p2=str[3];p2;j++){ + short k; str2[j]=p2; p2=strchr(p2,':'); if(p2) *p2++=0; diff --git a/src/map/clif.h b/src/map/clif.h index 0b1ffe52c..3310769a8 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -203,7 +203,7 @@ int clif_skill_damage(struct block_list *src,struct block_list *dst,unsigned int int clif_skill_nodamage(struct block_list *src,struct block_list *dst,int skill_id,int heal,int fail); int clif_skill_poseffect(struct block_list *src,int skill_id,int val,int x,int y,int tick); int clif_skill_estimation(struct map_session_data *sd,struct block_list *dst); -void clif_skill_warppoint(struct map_session_data* sd, int skill_num, int skill_lv, int map1, int map2, int map3, int map4); +void clif_skill_warppoint(struct map_session_data* sd, int skill_num, int skill_lv, unsigned short map1, unsigned short map2, unsigned short map3, unsigned short map4); int clif_skill_memo(struct map_session_data *sd,int flag); int clif_skill_teleportmessage(struct map_session_data *sd,int flag); int clif_skill_produce_mix_list(struct map_session_data *sd, int trigger); diff --git a/src/map/map.c b/src/map/map.c index 3263a6ed8..db4f7d077 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -2153,9 +2153,9 @@ int map_check_dir(int s_dir,int t_dir) /*========================================== * Returns the direction of the given cell, relative to 'src' *------------------------------------------*/ -int map_calc_dir(struct block_list* src, int x, int y) +uint8 map_calc_dir(struct block_list* src, int x, int y) { - int dir = 0; + unsigned char dir = 0; int dx, dy; nullpo_retr(0, src); diff --git a/src/map/map.h b/src/map/map.h index 5cef74b07..a5f4a6357 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -290,7 +290,7 @@ struct skill_unit_group { unsigned int tick; int limit,interval; - int skill_id,skill_lv; + short skill_id,skill_lv; int val1,val2,val3; char *valstr; int unit_id; @@ -327,7 +327,7 @@ struct unit_data { unsigned int attackabletime; unsigned int canact_tick; unsigned int canmove_tick; - unsigned char dir; + uint8 dir; unsigned char walk_count; struct { unsigned change_walk_target : 1 ; @@ -397,7 +397,7 @@ struct status_change { struct s_vending { short index; - unsigned short amount; + short amount; unsigned int value; }; @@ -753,7 +753,7 @@ struct map_session_data { int trade_partner; struct { struct { - int index, amount; + short index, amount; } item[10]; int zeny, weight; } deal; @@ -780,7 +780,7 @@ struct map_session_data { }feel_map[3];// 0 - Sun; 1 - Moon; 2 - Stars short hate_mob[3]; - unsigned int pvp_timer; + int pvp_timer; short pvp_point; unsigned short pvp_rank, pvp_lastusers; unsigned short pvp_won, pvp_lost; @@ -1024,7 +1024,7 @@ struct pet_data { }; // state of a single attack attempt; used in flee/def penalty calculations when mobbed -enum { +enum damage_lv { ATK_LUCKY=1, // attack was lucky-dodged ATK_FLEE, // attack was dodged ATK_DEF // attack connected @@ -1346,7 +1346,7 @@ struct map_session_data * map_nick2sd(const char*); // その他 int map_check_dir(int s_dir,int t_dir); -int map_calc_dir( struct block_list *src,int x,int y); +unsigned char map_calc_dir( struct block_list *src,int x,int y); int map_random_dir(struct block_list *bl, short *x, short *y); // [Skotlex] // path.cより diff --git a/src/map/mob.h b/src/map/mob.h index 367640e07..5d2296d47 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -66,7 +66,7 @@ struct mob_db { char sprite[NAME_LENGTH],name[NAME_LENGTH],jname[NAME_LENGTH]; unsigned int base_exp,job_exp; unsigned int mexp,mexpper; - int range2,range3; + short range2,range3; short race2; // celest unsigned short lv; struct { int nameid,p; } dropitem[MAX_MOB_DROP]; diff --git a/src/map/npc.c b/src/map/npc.c index 622d67ec1..0c04cfb73 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -532,7 +532,7 @@ int npc_timerevent_stop(struct npc_data* nd) return 0; td = get_timer(*tid); if (td && td->data) - ers_free(timer_event_ers, (struct event_timer_data*)td->data); + ers_free(timer_event_ers, (void*)td->data); delete_timer(*tid,npc_timerevent); *tid = -1; //Set the timer tick to the time that has passed since the beginning of the timers and now. @@ -1316,7 +1316,7 @@ int npc_unload(struct npc_data* nd) struct TimerData *td = NULL; td = get_timer(nd->u.scr.timerid); if (td && td->data) - ers_free(timer_event_ers, (struct event_timer_data*)td->data); + ers_free(timer_event_ers, (void*)td->data); delete_timer(nd->u.scr.timerid, npc_timerevent); } if (nd->u.scr.timer_event) diff --git a/src/map/pc.c b/src/map/pc.c index d259bc6e0..f039f8318 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -3398,7 +3398,7 @@ int pc_steal_coin(struct map_session_data *sd,struct block_list *target) * 2 - Map not in this map-server, and failed to locate alternate map-server. * 3 - Failed to warp player because it was in transition between maps. *------------------------------------------*/ -int pc_setpos(struct map_session_data *sd,unsigned short mapindex,int x,int y,int clrtype) +int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, uint8 clrtype) { int m; @@ -6688,11 +6688,9 @@ int pc_calc_pvprank_timer(int tid,unsigned int tick,int id,int data) sd=map_id2sd(id); if(sd==NULL) return 0; - sd->pvp_timer=UINT_MAX; - if( pc_calc_pvprank(sd)>0 ) - sd->pvp_timer=add_timer( - gettick()+PVP_CALCRANK_INTERVAL, - pc_calc_pvprank_timer,id,data); + sd->pvp_timer = -1; + if( pc_calc_pvprank(sd) > 0 ) + sd->pvp_timer = add_timer(gettick()+PVP_CALCRANK_INTERVAL,pc_calc_pvprank_timer,id,data); return 0; } diff --git a/src/map/pc.h b/src/map/pc.h index b8169e954..0d3b4d8d4 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -142,7 +142,7 @@ int pc_clean_skilltree(struct map_session_data *sd); #define pc_checkoverhp(sd) (sd->battle_status.hp == sd->battle_status.max_hp) #define pc_checkoversp(sd) (sd->battle_status.sp == sd->battle_status.max_sp) -int pc_setpos(struct map_session_data*,unsigned short,int,int,int); +int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, uint8 clrtype); int pc_setsavepoint(struct map_session_data*,short,int,int); int pc_randomwarp(struct map_session_data *sd,int type); int pc_memo(struct map_session_data *sd,int i); diff --git a/src/map/script.c b/src/map/script.c index 0d2d04650..458f57fb3 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -9417,12 +9417,13 @@ BUILDIN_FUNC(pvpon) return 0; } -static int buildin_pvpoff_sub(struct block_list *bl,va_list ap) { +static int buildin_pvpoff_sub(struct block_list *bl,va_list ap) +{ TBL_PC* sd = (TBL_PC*)bl; clif_pvpset(sd, 0, 0, 2); - if (sd->pvp_timer != UINT_MAX) { + if (sd->pvp_timer != -1) { delete_timer(sd->pvp_timer, pc_calc_pvprank_timer); - sd->pvp_timer = UINT_MAX; + sd->pvp_timer = -1; } return 0; } diff --git a/src/map/skill.c b/src/map/skill.c index 1b5797742..a1f5c8b05 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -6481,7 +6481,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk /*========================================== * *------------------------------------------*/ -int skill_castend_map (struct map_session_data *sd, int skill_num, const char *map) +int skill_castend_map (struct map_session_data *sd, short skill_num, const char *map) { nullpo_retr(0, sd); @@ -6708,7 +6708,7 @@ static bool skill_dance_switch(struct skill_unit* unit, int flag) * flag&1 is used to determine when the skill 'morphs' (Warp portal becomes active, or Fire Pillar becomes active) * flag&2 is used to determine if this skill was casted with Magic Power active. *------------------------------------------*/ -struct skill_unit_group *skill_unitsetting (struct block_list *src, int skillid, int skilllv, int x, int y, int flag) +struct skill_unit_group* skill_unitsetting (struct block_list *src, short skillid, short skilllv, short x, short y, int flag) { struct skill_unit_group *group; int i,limit,val1=0,val2=0,val3=0; @@ -6975,7 +6975,8 @@ struct skill_unit_group *skill_unitsetting (struct block_list *src, int skillid, for(i=0;icount;i++) { struct skill_unit *unit; - int ux,uy,alive=1; + short ux,uy; + int alive=1; ux = x + layout->dx[i]; uy = y + layout->dy[i]; @@ -7942,13 +7943,13 @@ static int skill_check_condition_char_sub (struct block_list *bl, va_list ap) } break; } - return 0; + //return 0; } /*========================================== * Checks and stores partners for ensemble skills [Skotlex] *------------------------------------------*/ -int skill_check_pc_partner (struct map_session_data *sd, int skill_id, int* skill_lv, int range, int cast_flag) +int skill_check_pc_partner (struct map_session_data *sd, short skill_id, short* skill_lv, int range, int cast_flag) { static int c=0; static int p_sd[2] = { 0, 0 }; @@ -8039,7 +8040,7 @@ int skill_isammotype (struct map_session_data *sd, int skill) * &1: finished casting the skill (invoke hp/sp/item consumption) * &2: picked menu entry (Warp Portal, Teleport and other menu based skills) *------------------------------------------*/ -int skill_check_condition(struct map_session_data* sd, int skill, int lv, int type) +int skill_check_condition(struct map_session_data* sd, short skill, short lv, int type) { struct status_data *status; struct status_change *sc; @@ -9322,11 +9323,9 @@ int skill_sit (struct map_session_data *sd, int type) if(type) { if (map_foreachinrange(skill_sit_count,&sd->bl, range, BL_PC, flag) > 1) map_foreachinrange(skill_sit_in,&sd->bl, range, BL_PC, flag); - return 0; } else { if (map_foreachinrange(skill_sit_count,&sd->bl, range, BL_PC, flag) < 2) map_foreachinrange(skill_sit_out,&sd->bl, range, BL_PC, flag); - return 0; } return 0; } @@ -9954,7 +9953,7 @@ int skill_delunit (struct skill_unit* unit) *------------------------------------------*/ static int skill_unit_group_newid = MAX_SKILL_DB; -struct skill_unit_group *skill_initunitgroup (struct block_list *src, int count, int skillid, int skilllv, int unit_id, int limit, int interval) +struct skill_unit_group* skill_initunitgroup (struct block_list* src, int count, short skillid, short skilllv, int unit_id, int limit, int interval) { struct unit_data* ud = unit_bl2ud( src ); struct skill_unit_group* group; @@ -10406,7 +10405,7 @@ int skill_unit_move_sub (struct block_list* bl, va_list ap) { if( flag&1 ) { - unsigned int result = skill_unit_onplace(unit,target,tick); + int result = skill_unit_onplace(unit,target,tick); if( flag&2 && result ) { //Clear skill ids we have stored in onout. ARR_FIND( 0, ARRAYLENGTH(skill_unit_temp), i, skill_unit_temp[i] == result ); @@ -10416,7 +10415,7 @@ int skill_unit_move_sub (struct block_list* bl, va_list ap) } else { - unsigned int result = skill_unit_onout(unit,target,tick); + int result = skill_unit_onout(unit,target,tick); if( flag&2 && result ) { //Store this unit id. ARR_FIND( 0, ARRAYLENGTH(skill_unit_temp), i, skill_unit_temp[i] == 0 ); diff --git a/src/map/skill.h b/src/map/skill.h index 7c7cce429..7d0580945 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -191,7 +191,7 @@ const char* skill_get_desc( int id ); // [Skotlex] int skill_isammotype(struct map_session_data *sd, int skill); int skill_castend_id( int tid, unsigned int tick, int id,int data ); int skill_castend_pos( int tid, unsigned int tick, int id,int data ); -int skill_castend_map( struct map_session_data *sd,int skill_num, const char *map); +int skill_castend_map( struct map_session_data *sd,short skill_num, const char *map); int skill_cleartimerskill(struct block_list *src); int skill_addtimerskill(struct block_list *src,unsigned int tick,int target,int x,int y,int skill_id,int skill_lv,int type,int flag); @@ -203,10 +203,10 @@ int skill_blown(struct block_list* src, struct block_list* target, int count, in int skill_break_equip(struct block_list *bl, unsigned short where, int rate, int flag); int skill_strip_equip(struct block_list *bl, unsigned short where, int rate, int lv, int time); // ユニットスキル -struct skill_unit_group *skill_unitsetting( struct block_list *src, int skillid,int skilllv,int x,int y,int flag); +struct skill_unit_group *skill_unitsetting(struct block_list* src, short skillid, short skilllv, short x, short y, int flag); struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int x, int y, int val1, int val2); int skill_delunit(struct skill_unit *unit); -struct skill_unit_group *skill_initunitgroup(struct block_list *src, int count,int skillid,int skilllv,int unit_id, int limit, int interval); +struct skill_unit_group *skill_initunitgroup(struct block_list* src, int count, short skillid, short skilllv, int unit_id, int limit, int interval); int skill_delunitgroup(struct block_list *src, struct skill_unit_group *group); int skill_clear_unitgroup(struct block_list *src); int skill_clear_group(struct block_list *bl, int flag); @@ -217,8 +217,8 @@ int skill_unit_ondamaged(struct skill_unit *src,struct block_list *bl, int skill_castfix( struct block_list *bl, int skill_id, int skill_lv); int skill_castfix_sc( struct block_list *bl, int time); int skill_delayfix( struct block_list *bl, int skill_id, int skill_lv); -int skill_check_condition( struct map_session_data *sd,int skill, int lv, int type); -int skill_check_pc_partner(struct map_session_data *sd, int skill_id, int* skill_lv, int range, int cast_flag); +int skill_check_condition( struct map_session_data *sd, short skill, short lv, int type); +int skill_check_pc_partner(struct map_session_data *sd, short skill_id, short* skill_lv, int range, int cast_flag); // -- moonsoul (added skill_check_unit_cell) int skill_check_unit_cell(int skillid,int m,int x,int y,int unit_id); int skill_unit_out_all( struct block_list *bl,unsigned int tick,int range); diff --git a/src/map/status.c b/src/map/status.c index c0d81950a..666ec386c 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -3173,7 +3173,7 @@ static unsigned short status_calc_str(struct block_list *bl, struct status_chang if(sc->data[SC_SPIRIT].timer!=-1 && sc->data[SC_SPIRIT].val2 == SL_HIGH && str < 50) str = 50; - return cap_value(str,0,USHRT_MAX); + return (unsigned short)cap_value(str,0,USHRT_MAX); } static unsigned short status_calc_agi(struct block_list *bl, struct status_change *sc, int agi) @@ -3212,7 +3212,7 @@ static unsigned short status_calc_agi(struct block_list *bl, struct status_chang if(sc->data[SC_SPIRIT].timer!=-1 && sc->data[SC_SPIRIT].val2 == SL_HIGH && agi < 50) agi = 50; - return cap_value(agi,0,USHRT_MAX); + return (unsigned short)cap_value(agi,0,USHRT_MAX); } static unsigned short status_calc_vit(struct block_list *bl, struct status_change *sc, int vit) @@ -3241,7 +3241,7 @@ static unsigned short status_calc_vit(struct block_list *bl, struct status_chang if(sc->data[SC_SPIRIT].timer!=-1 && sc->data[SC_SPIRIT].val2 == SL_HIGH && vit < 50) vit = 50; - return cap_value(vit,0,USHRT_MAX); + return (unsigned short)cap_value(vit,0,USHRT_MAX); } static unsigned short status_calc_int(struct block_list *bl, struct status_change *sc, int int_) @@ -3278,7 +3278,7 @@ static unsigned short status_calc_int(struct block_list *bl, struct status_chang if(sc->data[SC_SPIRIT].timer!=-1 && sc->data[SC_SPIRIT].val2 == SL_HIGH && int_ < 50) int_ = 50; - return cap_value(int_,0,USHRT_MAX); + return (unsigned short)cap_value(int_,0,USHRT_MAX); } static unsigned short status_calc_dex(struct block_list *bl, struct status_change *sc, int dex) @@ -3320,7 +3320,7 @@ static unsigned short status_calc_dex(struct block_list *bl, struct status_chang if(sc->data[SC_SPIRIT].timer!=-1 && sc->data[SC_SPIRIT].val2 == SL_HIGH && dex < 50) dex = 50; - return cap_value(dex,0,USHRT_MAX); + return (unsigned short)cap_value(dex,0,USHRT_MAX); } static unsigned short status_calc_luk(struct block_list *bl, struct status_change *sc, int luk) @@ -3347,7 +3347,7 @@ static unsigned short status_calc_luk(struct block_list *bl, struct status_chang if(sc->data[SC_SPIRIT].timer!=-1 && sc->data[SC_SPIRIT].val2 == SL_HIGH && luk < 50) luk = 50; - return cap_value(luk,0,USHRT_MAX); + return (unsigned short)cap_value(luk,0,USHRT_MAX); } static unsigned short status_calc_batk(struct block_list *bl, struct status_change *sc, int batk) @@ -3382,7 +3382,7 @@ static unsigned short status_calc_batk(struct block_list *bl, struct status_chan batk += sc->data[SC_GATLINGFEVER].val3; if(sc->data[SC_MADNESSCANCEL].timer!=-1) batk += 100; - return cap_value(batk,0,USHRT_MAX); + return (unsigned short)cap_value(batk,0,USHRT_MAX); } static unsigned short status_calc_watk(struct block_list *bl, struct status_change *sc, int watk) @@ -3425,7 +3425,7 @@ static unsigned short status_calc_watk(struct block_list *bl, struct status_chan if(sc->data[SC_STRIPWEAPON].timer!=-1) watk -= watk * sc->data[SC_STRIPWEAPON].val2/100; - return cap_value(watk,0,USHRT_MAX); + return (unsigned short)cap_value(watk,0,USHRT_MAX); } static unsigned short status_calc_matk(struct block_list *bl, struct status_change *sc, int matk) @@ -3444,7 +3444,7 @@ static unsigned short status_calc_matk(struct block_list *bl, struct status_chan if(sc->data[SC_INCMATKRATE].timer!=-1) matk += matk * sc->data[SC_INCMATKRATE].val1/100; - return cap_value(matk,0,USHRT_MAX); + return (unsigned short)cap_value(matk,0,USHRT_MAX); } static signed short status_calc_critical(struct block_list *bl, struct status_change *sc, int critical) @@ -3461,7 +3461,7 @@ static signed short status_calc_critical(struct block_list *bl, struct status_ch if(sc->data[SC_CLOAKING].timer!=-1) critical += critical; - return cap_value(critical,10,SHRT_MAX); + return (short)cap_value(critical,10,SHRT_MAX); } static signed short status_calc_hit(struct block_list *bl, struct status_change *sc, int hit) @@ -3489,7 +3489,7 @@ static signed short status_calc_hit(struct block_list *bl, struct status_change if(sc->data[SC_INCREASING].timer!=-1) hit += 20; // RockmanEXE; changed based on updated [Reddozen] - return cap_value(hit,1,SHRT_MAX); + return (short)cap_value(hit,1,SHRT_MAX); } static signed short status_calc_flee(struct block_list *bl, struct status_change *sc, int flee) @@ -3529,7 +3529,7 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change if(sc->data[SC_SPEED].timer!=-1) flee += 10 + sc->data[SC_SPEED].val1 * 10 ; - return cap_value(flee,1,SHRT_MAX); + return (short)cap_value(flee,1,SHRT_MAX); } static signed short status_calc_flee2(struct block_list *bl, struct status_change *sc, int flee2) @@ -3540,7 +3540,7 @@ static signed short status_calc_flee2(struct block_list *bl, struct status_chang if(sc->data[SC_WHISTLE].timer!=-1) flee2 += sc->data[SC_WHISTLE].val3*10; - return cap_value(flee2,10,SHRT_MAX); + return (short)cap_value(flee2,10,SHRT_MAX); } static signed char status_calc_def(struct block_list *bl, struct status_change *sc, int def) @@ -3583,7 +3583,7 @@ static signed char status_calc_def(struct block_list *bl, struct status_change * if (sc->data[SC_FLING].timer!=-1) def -= def * (sc->data[SC_FLING].val2)/100; - return cap_value(def,0,CHAR_MAX); + return (char)cap_value(def,0,CHAR_MAX); } static signed short status_calc_def2(struct block_list *bl, struct status_change *sc, int def2) @@ -3617,7 +3617,7 @@ static signed short status_calc_def2(struct block_list *bl, struct status_change if(sc->data[SC_FLING].timer!=-1) def2 -= def2 * (sc->data[SC_FLING].val3)/100; - return cap_value(def2,1,SHRT_MAX); + return (short)cap_value(def2,1,SHRT_MAX); } static signed char status_calc_mdef(struct block_list *bl, struct status_change *sc, int mdef) @@ -3642,7 +3642,7 @@ static signed char status_calc_mdef(struct block_list *bl, struct status_change if(sc->data[SC_ENDURE].timer!=-1 && sc->data[SC_ENDURE].val4 == 0) mdef += sc->data[SC_ENDURE].val1; - return cap_value(mdef,0,CHAR_MAX); + return (char)cap_value(mdef,0,CHAR_MAX); } static signed short status_calc_mdef2(struct block_list *bl, struct status_change *sc, int mdef2) @@ -3655,7 +3655,7 @@ static signed short status_calc_mdef2(struct block_list *bl, struct status_chang if(sc->data[SC_MINDBREAKER].timer!=-1) mdef2 -= mdef2 * sc->data[SC_MINDBREAKER].val3/100; - return cap_value(mdef2,1,SHRT_MAX); + return (short)cap_value(mdef2,1,SHRT_MAX); } static unsigned short status_calc_speed(struct block_list *bl, struct status_change *sc, int speed) @@ -3731,7 +3731,7 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha if(sc->data[SC_SLOWDOWN].timer!=-1) speed = speed * 100/75; - return cap_value(speed,10,USHRT_MAX); + return (short)cap_value(speed,10,USHRT_MAX); } static short status_calc_aspd_rate(struct block_list *bl, struct status_change *sc, int aspd_rate) @@ -3830,7 +3830,7 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * aspd_rate += 100; } - return cap_value(aspd_rate,0,SHRT_MAX); + return (short)cap_value(aspd_rate,0,SHRT_MAX); } static unsigned short status_calc_dmotion(struct block_list *bl, struct status_change *sc, int dmotion) @@ -3845,7 +3845,7 @@ static unsigned short status_calc_dmotion(struct block_list *bl, struct status_c if(sc->data[SC_RUN].timer!=-1) return 0; - return cap_value(dmotion,0,USHRT_MAX); + return (unsigned short)cap_value(dmotion,0,USHRT_MAX); } static unsigned int status_calc_maxhp(struct block_list *bl, struct status_change *sc, unsigned int maxhp) @@ -3892,7 +3892,7 @@ static unsigned char status_calc_element(struct block_list *bl, struct status_ch return ELE_UNDEAD; if( sc->data[SC_ELEMENTALCHANGE].timer!=-1) return sc->data[SC_ELEMENTALCHANGE].val2; - return cap_value(element,0,UCHAR_MAX); + return (unsigned char)cap_value(element,0,UCHAR_MAX); } static unsigned char status_calc_element_lv(struct block_list *bl, struct status_change *sc, int lv) @@ -3909,7 +3909,7 @@ static unsigned char status_calc_element_lv(struct block_list *bl, struct status return 1; if(sc->data[SC_ELEMENTALCHANGE].timer!=-1) return sc->data[SC_ELEMENTALCHANGE].val1; - return cap_value(lv,1,4); + return (unsigned char)cap_value(lv,1,4); } @@ -3935,7 +3935,7 @@ unsigned char status_calc_attack_element(struct block_list *bl, struct status_ch return ELE_DARK; if( sc->data[SC_GHOSTWEAPON].timer!=-1) return ELE_GHOST; - return cap_value(element,0,UCHAR_MAX); + return (unsigned char)cap_value(element,0,UCHAR_MAX); } static unsigned short status_calc_mode(struct block_list *bl, struct status_change *sc, int mode) diff --git a/src/map/trade.c b/src/map/trade.c index 0bf7e4432..eadc115a7 100644 --- a/src/map/trade.c +++ b/src/map/trade.c @@ -228,7 +228,8 @@ int trade_check(struct map_session_data *sd, struct map_session_data *tsd) struct item inventory[MAX_INVENTORY]; struct item inventory2[MAX_INVENTORY]; struct item_data *data; - int trade_i, i, amount, n; + int trade_i, i, n; + short amount; if(sd->state.finalsave || tsd->state.finalsave) return 0; //Item transferring fails @@ -312,7 +313,7 @@ int trade_check(struct map_session_data *sd, struct map_session_data *tsd) /*========================================== * Adds an item/qty to the trade window *------------------------------------------*/ -void trade_tradeadditem(struct map_session_data *sd, int index, int amount) +void trade_tradeadditem(struct map_session_data *sd, short index, short amount) { struct map_session_data *target_sd; struct item *item; diff --git a/src/map/trade.h b/src/map/trade.h index 724ed2253..6bb39936e 100644 --- a/src/map/trade.h +++ b/src/map/trade.h @@ -9,7 +9,7 @@ struct map_session_data; void trade_traderequest(struct map_session_data *sd, struct map_session_data *target_sd); void trade_tradeack(struct map_session_data *sd,int type); -void trade_tradeadditem(struct map_session_data *sd,int index,int amount); +void trade_tradeadditem(struct map_session_data *sd,short index,short amount); void trade_tradeaddzeny(struct map_session_data *sd,int amount); void trade_tradeok(struct map_session_data *sd); void trade_tradecancel(struct map_session_data *sd); diff --git a/src/map/unit.c b/src/map/unit.c index ddc590396..5621eedc2 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -31,8 +31,8 @@ #include -const int dirx[8]={0,-1,-1,-1,0,1,1,1}; -const int diry[8]={1,1,0,-1,-1,-1,0,1}; +const short dirx[8]={0,-1,-1,-1,0,1,1,1}; +const short diry[8]={1,1,0,-1,-1,-1,0,1}; struct unit_data* unit_bl2ud(struct block_list *bl) { @@ -103,7 +103,8 @@ int unit_walktoxy_sub(struct block_list *bl) static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data) { int i; - int x,y,dx,dy,dir; + int x,y,dx,dy; + uint8 dir; struct block_list *bl; struct map_session_data *sd = NULL; struct mob_data *md = NULL; @@ -272,7 +273,7 @@ static int unit_delay_walktoxy_timer(int tid, unsigned int tick, int id, int dat //&1 -> 1/0 = easy/hard //&2 -> force walking //&4 -> Delay walking if the reason you can't walk is the canwalk delay -int unit_walktoxy( struct block_list *bl, int x, int y, int flag) +int unit_walktoxy( struct block_list *bl, short x, short y, int flag) { struct unit_data* ud = NULL; struct status_change* sc = NULL; @@ -401,7 +402,8 @@ int unit_walktobl(struct block_list *bl, struct block_list *tbl, int range, int int unit_run(struct block_list *bl) { struct status_change *sc = status_get_sc(bl); - int i,to_x,to_y,dir_x,dir_y; + short to_x,to_y,dir_x,dir_y; + int i; if (!sc || !sc->count || sc->data[SC_RUN].timer == -1) return 0; @@ -454,7 +456,7 @@ int unit_run(struct block_list *bl) } //Makes bl attempt to run dist cells away from target. Uses hard-paths. -int unit_escape(struct block_list *bl, struct block_list *target, int dist) +int unit_escape(struct block_list *bl, struct block_list *target, short dist) { int dir = map_calc_dir(target, bl->x, bl->y); while( dist > 0 && map_getcell(bl->m, bl->x + dist*dirx[dir], bl->y + dist*diry[dir], CELL_CHKNOREACH) ) @@ -463,9 +465,10 @@ int unit_escape(struct block_list *bl, struct block_list *target, int dist) } //Instant warp function. -int unit_movepos(struct block_list *bl,int dst_x,int dst_y, int easy, int checkpath) +int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, bool checkpath) { - int dx,dy,dir; + short dx,dy; + uint8 dir; struct unit_data *ud = NULL; struct map_session_data *sd = NULL; struct walkpath_data wpd; @@ -535,7 +538,7 @@ int unit_setdir(struct block_list *bl,unsigned char dir) return 0; } -int unit_getdir(struct block_list *bl) +uint8 unit_getdir(struct block_list *bl) { struct unit_data *ud; nullpo_retr( 0, bl ); @@ -547,7 +550,7 @@ int unit_getdir(struct block_list *bl) //Warps a unit/ud to a given map/position. //In the case of players, pc_setpos is used. //it respects the no warp flags, so it is safe to call this without doing nowarpto/nowarp checks. -int unit_warp(struct block_list *bl,int m,short x,short y,int type) +int unit_warp(struct block_list *bl,short m,short x,short y,uint8 type) { struct unit_data *ud; nullpo_retr(0, bl); @@ -666,7 +669,7 @@ int unit_stop_walking(struct block_list *bl,int type) return 1; } -int unit_skilluse_id(struct block_list *src, int target_id, int skill_num, int skill_lv) +int unit_skilluse_id(struct block_list *src, int target_id, short skill_num, short skill_lv) { if(skill_num < 0) return 0; @@ -780,7 +783,7 @@ int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int return 1; } -int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int skill_lv, int casttime, int castcancel) +int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, short skill_lv, int casttime, int castcancel) { struct unit_data *ud; struct status_data *tstatus; @@ -1053,7 +1056,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int return 1; } -int unit_skilluse_pos(struct block_list *src, int skill_x, int skill_y, int skill_num, int skill_lv) +int unit_skilluse_pos(struct block_list *src, short skill_x, short skill_y, short skill_num, short skill_lv) { if(skill_num < 0) return 0; @@ -1064,7 +1067,7 @@ int unit_skilluse_pos(struct block_list *src, int skill_x, int skill_y, int skil ); } -int unit_skilluse_pos2( struct block_list *src, int skill_x, int skill_y, int skill_num, int skill_lv, int casttime, int castcancel) +int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, short skill_num, short skill_lv, int casttime, int castcancel) { struct map_session_data *sd = NULL; struct unit_data *ud = NULL; @@ -1602,7 +1605,7 @@ int unit_changeviewsize(struct block_list *bl,short size) * Otherwise it is assumed bl is being warped. * On-Kill specific stuff is not performed here, look at status_damage for that. *------------------------------------------*/ -int unit_remove_map(struct block_list *bl, int clrtype) +int unit_remove_map(struct block_list *bl, uint8 clrtype) { struct unit_data *ud = unit_bl2ud(bl); struct status_change *sc = status_get_sc(bl); @@ -1750,7 +1753,7 @@ int unit_remove_map(struct block_list *bl, int clrtype) * If clrtype is <0, no saving is performed. This is only for non-authed * objects that shouldn't be on a map yet. *------------------------------------------*/ -int unit_free(struct block_list *bl, int clrtype) +int unit_free(struct block_list *bl, uint8 clrtype) { struct unit_data *ud = unit_bl2ud( bl ); nullpo_retr(0, ud); diff --git a/src/map/unit.h b/src/map/unit.h index 83858fb5d..1880b3b99 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -12,7 +12,7 @@ struct unit_data; // 歩行開始 // 戻り値は、0 ( 成功 ), 1 ( 失敗 ) -int unit_walktoxy( struct block_list *bl, int x, int y, int easy); +int unit_walktoxy( struct block_list *bl, short x, short y, int easy); int unit_walktobl( struct block_list *bl, struct block_list *target, int range, int easy); int unit_run(struct block_list *bl); @@ -26,12 +26,12 @@ int unit_can_move(struct block_list *bl); int unit_is_walking(struct block_list *bl); int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int type); -int unit_escape(struct block_list *bl, struct block_list *target, int dist); +int unit_escape(struct block_list *bl, struct block_list *target, short dist); // 位置の強制移動(吹き飛ばしなど) -int unit_movepos(struct block_list *bl,int dst_x,int dst_y, int easy, int checkpath); -int unit_warp(struct block_list *bl, int map, short x, short y, int type); +int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, bool checkpath); +int unit_warp(struct block_list *bl, short map, short x, short y, uint8 type); int unit_setdir(struct block_list *bl,unsigned char dir); -int unit_getdir(struct block_list *bl); +uint8 unit_getdir(struct block_list *bl); // そこまで歩行でたどり着けるかの判定 int unit_can_reach_pos(struct block_list *bl,int x,int y,int easy); @@ -43,12 +43,12 @@ int unit_attack(struct block_list *src,int target_id,int continuous); int unit_cancel_combo(struct block_list *bl); // スキル使用 -int unit_skilluse_id(struct block_list *src, int target_id, int skill_num, int skill_lv); -int unit_skilluse_pos(struct block_list *src, int skill_x, int skill_y, int skill_num, int skill_lv); +int unit_skilluse_id(struct block_list *src, int target_id, short skill_num, short skill_lv); +int unit_skilluse_pos(struct block_list *src, short skill_x, short skill_y, short skill_num, short skill_lv); // スキル使用( 補正済みキャスト時間、キャンセル不可設定付き ) -int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int skill_lv, int casttime, int castcancel); -int unit_skilluse_pos2( struct block_list *src, int skill_x, int skill_y, int skill_num, int skill_lv, int casttime, int castcancel); +int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, short skill_lv, int casttime, int castcancel); +int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, short skill_num, short skill_lv, int casttime, int castcancel); // 詠唱キャンセル int unit_skillcastcancel(struct block_list *bl,int type); @@ -61,15 +61,15 @@ void unit_dataset(struct block_list *bl); int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2); // その他 struct unit_data* unit_bl2ud(struct block_list *bl); -int unit_remove_map(struct block_list *bl, int clrtype); -int unit_free(struct block_list *bl, int clrtype); +int unit_remove_map(struct block_list *bl, uint8 clrtype); +int unit_free(struct block_list *bl, uint8 clrtype); int unit_changeviewsize(struct block_list *bl,short size); // 初期化ルーチン int do_init_unit(void); int do_final_unit(void); -extern const int dirx[8]; -extern const int diry[8]; +extern const short dirx[8]; +extern const short diry[8]; #endif /* _UNIT_H_ */ diff --git a/src/map/vending.c b/src/map/vending.c index 9017eab96..7c0024eb3 100644 --- a/src/map/vending.c +++ b/src/map/vending.c @@ -81,8 +81,8 @@ void vending_purchasereq(struct map_session_data* sd, int id, const uint8* data, w = 0; // weight counter for( i = 0; i < count; i++ ) { - unsigned short amount = *(uint16*)(data + 4*i + 0); - short idx = *(uint16*)(data + 4*i + 2); + short amount = *(uint16*)(data + 4*i + 0); + short idx = *(uint16*)(data + 4*i + 2); idx -= 2; if( amount <= 0 ) @@ -150,8 +150,8 @@ void vending_purchasereq(struct map_session_data* sd, int id, const uint8* data, for( i = 0; i < count; i++ ) { - unsigned short amount = *(uint16*)(data + 4*i + 0); - short idx = *(uint16*)(data + 4*i + 2); + short amount = *(uint16*)(data + 4*i + 0); + short idx = *(uint16*)(data + 4*i + 2); idx -= 2; //Logs sold (V)ending items [Lupus] @@ -248,9 +248,9 @@ void vending_openvending(struct map_session_data* sd, const char* message, bool i = 0; for( j = 0; j < count; j++ ) { - int index = *(uint16*)(data + 8*j + 0); - unsigned int amount = *(uint16*)(data + 8*j + 2); - unsigned int value = *(uint32*)(data + 8*j + 4); + short index = *(uint16*)(data + 8*j + 0); + short amount = *(uint16*)(data + 8*j + 2); + unsigned int value = *(uint32*)(data + 8*j + 4); index -= 2; // offset adjustment (client says that the first cart position is 2) -- cgit v1.2.3-70-g09d2 From f26dbc30528f8627310fa03f46cefd940ee40588 Mon Sep 17 00:00:00 2001 From: ultramage Date: Thu, 18 Oct 2007 21:59:20 +0000 Subject: Fixed some gcc-specific stuff, silenced some more warnings git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@11515 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/login/login.c | 4 ++-- src/login_sql/login.c | 4 ++-- src/map/battle.h | 7 +++++++ src/map/clif.c | 12 ++++++------ src/map/clif.h | 2 +- src/map/map.h | 7 ------- src/map/skill.c | 4 ++-- src/map/unit.c | 6 +++--- src/map/unit.h | 6 +++--- 9 files changed, 26 insertions(+), 26 deletions(-) (limited to 'src/map/unit.h') diff --git a/src/login/login.c b/src/login/login.c index 8acc10d73..311f34327 100644 --- a/src/login/login.c +++ b/src/login/login.c @@ -32,7 +32,7 @@ struct Login_Config { // bool case_sensitive; // are logins case sensitive ? bool use_md5_passwds; // work with password hashes instead of plaintext passwords? // bool login_gm_read; // should the login server handle info about gm accounts? - uint8 min_level_to_connect; // minimum level of player/GM (0: player, 1-99: GM) to connect + int min_level_to_connect; // minimum level of player/GM (0: player, 1-99: GM) to connect bool online_check; // reject incoming players that are already registered as online ? bool check_client_version; // check the clientversion set in the clientinfo ? unsigned int client_version_to_connect; // the client version needed to connect (if checking is enabled) @@ -3622,7 +3622,7 @@ int login_config_read(const char* cfgName) else if(!strcmpi(w1, "use_MD5_passwords")) login_config.use_md5_passwds = (bool)config_switch(w2); else if(!strcmpi(w1, "min_level_to_connect")) - login_config.min_level_to_connect = (uint8)atoi(w2); + login_config.min_level_to_connect = atoi(w2); else if(!strcmpi(w1, "date_format")) safestrncpy(login_config.date_format, w2, sizeof(login_config.date_format)); else if(!strcmpi(w1, "console")) diff --git a/src/login_sql/login.c b/src/login_sql/login.c index d40cfcdf5..b45ec0119 100644 --- a/src/login_sql/login.c +++ b/src/login_sql/login.c @@ -32,7 +32,7 @@ struct Login_Config { bool case_sensitive; // are logins case sensitive ? bool use_md5_passwds; // work with password hashes instead of plaintext passwords? bool login_gm_read; // should the login server handle info about gm accounts? - uint8 min_level_to_connect; // minimum level of player/GM (0: player, 1-99: GM) to connect + int min_level_to_connect; // minimum level of player/GM (0: player, 1-99: GM) to connect bool online_check; // reject incoming players that are already registered as online ? bool check_client_version; // check the clientversion set in the clientinfo ? unsigned int client_version_to_connect; // the client version needed to connect (if checking is enabled) @@ -1774,7 +1774,7 @@ int login_config_read(const char* cfgName) else if(!strcmpi(w1, "use_MD5_passwords")) login_config.use_md5_passwds = (bool)config_switch(w2); else if(!strcmpi(w1, "min_level_to_connect")) - login_config.min_level_to_connect = (uint8)atoi(w2); + login_config.min_level_to_connect = atoi(w2); else if(!strcmpi(w1, "date_format")) safestrncpy(login_config.date_format, w2, sizeof(login_config.date_format)); else if(!strcmpi(w1, "console")) diff --git a/src/map/battle.h b/src/map/battle.h index e7d385b3c..f82e8a3de 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -4,6 +4,13 @@ #ifndef _BATTLE_H_ #define _BATTLE_H_ +// state of a single attack attempt; used in flee/def penalty calculations when mobbed +enum damage_lv { + ATK_LUCKY=1, // attack was lucky-dodged + ATK_FLEE, // attack was dodged + ATK_DEF // attack connected +}; + // ダメージ struct Damage { int damage,damage2; diff --git a/src/map/clif.c b/src/map/clif.c index b67e2cd87..54812fd05 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -4569,7 +4569,7 @@ void clif_skill_warppoint(struct map_session_data* sd, short skill_num, short sk WFIFOW(fd,0) = 0x11c; WFIFOW(fd,2) = skill_num; memset(WFIFOP(fd,4), 0x00, 4*MAP_NAME_LENGTH_EXT); - if (map1 == -1) strcpy((char*)WFIFOP(fd,4), "Random"); + if (map1 == (unsigned short)-1) strcpy((char*)WFIFOP(fd,4), "Random"); if (map1 > 0) mapindex_getmapname_ext(mapindex_id2name(map1), (char*)WFIFOP(fd,4)); if (map2 > 0) mapindex_getmapname_ext(mapindex_id2name(map2), (char*)WFIFOP(fd,20)); if (map3 > 0) mapindex_getmapname_ext(mapindex_id2name(map3), (char*)WFIFOP(fd,36)); @@ -7628,9 +7628,9 @@ void clif_feel_hate_reset(struct map_session_data *sd) /// Returns true if the packet was parsed successfully. /// Formats: 0 - .w .w ( : ).?B 00 /// 1 - .w .w .24B .?B 00 -static bool clif_process_message(struct map_session_data* sd, int format, const char** name_, int* namelen_, const char** message_, int* messagelen_) +static bool clif_process_message(struct map_session_data* sd, int format, char** name_, int* namelen_, char** message_, int* messagelen_) { - const char *text, *name, *message; + char *text, *name, *message; unsigned int packetlen, textlen, namelen, messagelen; int fd = sd->fd; @@ -8240,7 +8240,7 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) const char* text = (char*)RFIFOP(fd,4); int textlen = RFIFOW(fd,2) - 4; - const char *name, *message; + char *name, *message; int namelen, messagelen; // validate packet and retrieve name and message @@ -9955,7 +9955,7 @@ void clif_parse_PartyMessage(int fd, struct map_session_data* sd) const char* text = (char*)RFIFOP(fd,4); int textlen = RFIFOW(fd,2) - 4; - const char *name, *message; + char *name, *message; int namelen, messagelen; // validate packet and retrieve name and message @@ -10228,7 +10228,7 @@ void clif_parse_GuildMessage(int fd, struct map_session_data* sd) const char* text = (char*)RFIFOP(fd,4); int textlen = RFIFOW(fd,2) - 4; - const char *name, *message; + char *name, *message; int namelen, messagelen; // validate packet and retrieve name and message diff --git a/src/map/clif.h b/src/map/clif.h index 3310769a8..543a17da1 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -203,7 +203,7 @@ int clif_skill_damage(struct block_list *src,struct block_list *dst,unsigned int int clif_skill_nodamage(struct block_list *src,struct block_list *dst,int skill_id,int heal,int fail); int clif_skill_poseffect(struct block_list *src,int skill_id,int val,int x,int y,int tick); int clif_skill_estimation(struct map_session_data *sd,struct block_list *dst); -void clif_skill_warppoint(struct map_session_data* sd, int skill_num, int skill_lv, unsigned short map1, unsigned short map2, unsigned short map3, unsigned short map4); +void clif_skill_warppoint(struct map_session_data* sd, short skill_num, short skill_lv, unsigned short map1, unsigned short map2, unsigned short map3, unsigned short map4); int clif_skill_memo(struct map_session_data *sd,int flag); int clif_skill_teleportmessage(struct map_session_data *sd,int flag); int clif_skill_produce_mix_list(struct map_session_data *sd, int trigger); diff --git a/src/map/map.h b/src/map/map.h index a5f4a6357..6eb92530e 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -1023,13 +1023,6 @@ struct pet_data { struct map_session_data *msd; }; -// state of a single attack attempt; used in flee/def penalty calculations when mobbed -enum damage_lv { - ATK_LUCKY=1, // attack was lucky-dodged - ATK_FLEE, // attack was dodged - ATK_DEF // attack connected -}; - struct map_data { char name[MAP_NAME_LENGTH]; unsigned short index; // The map index used by the mapindex* functions. diff --git a/src/map/skill.c b/src/map/skill.c index a1f5c8b05..2db05ed82 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -4565,12 +4565,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in if(skilllv == 1) { // possibility to skip menu [LuzZza] if(!battle_config.skip_teleport_lv1_menu && sd->skillitem != AL_TELEPORT) - clif_skill_warppoint(sd,skillid,skilllv, -1,0,0,0); + clif_skill_warppoint(sd,skillid,skilllv, (unsigned short)-1,0,0,0); else pc_randomwarp(sd,3); } else { if (sd->skillitem != AL_TELEPORT) - clif_skill_warppoint(sd,skillid,skilllv, -1,sd->status.save_point.map,0,0); + clif_skill_warppoint(sd,skillid,skilllv, (unsigned short)-1,sd->status.save_point.map,0,0); else //Autocasted Teleport level 2?? pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3); } diff --git a/src/map/unit.c b/src/map/unit.c index 5621eedc2..616781b7a 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -550,7 +550,7 @@ uint8 unit_getdir(struct block_list *bl) //Warps a unit/ud to a given map/position. //In the case of players, pc_setpos is used. //it respects the no warp flags, so it is safe to call this without doing nowarpto/nowarp checks. -int unit_warp(struct block_list *bl,short m,short x,short y,uint8 type) +int unit_warp(struct block_list *bl,short m,short x,short y,int type) { struct unit_data *ud; nullpo_retr(0, bl); @@ -1605,7 +1605,7 @@ int unit_changeviewsize(struct block_list *bl,short size) * Otherwise it is assumed bl is being warped. * On-Kill specific stuff is not performed here, look at status_damage for that. *------------------------------------------*/ -int unit_remove_map(struct block_list *bl, uint8 clrtype) +int unit_remove_map(struct block_list *bl, int clrtype) { struct unit_data *ud = unit_bl2ud(bl); struct status_change *sc = status_get_sc(bl); @@ -1753,7 +1753,7 @@ int unit_remove_map(struct block_list *bl, uint8 clrtype) * If clrtype is <0, no saving is performed. This is only for non-authed * objects that shouldn't be on a map yet. *------------------------------------------*/ -int unit_free(struct block_list *bl, uint8 clrtype) +int unit_free(struct block_list *bl, int clrtype) { struct unit_data *ud = unit_bl2ud( bl ); nullpo_retr(0, ud); diff --git a/src/map/unit.h b/src/map/unit.h index 1880b3b99..6c6124f5c 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -29,7 +29,7 @@ int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int int unit_escape(struct block_list *bl, struct block_list *target, short dist); // 位置の強制移動(吹き飛ばしなど) int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, bool checkpath); -int unit_warp(struct block_list *bl, short map, short x, short y, uint8 type); +int unit_warp(struct block_list *bl, short map, short x, short y, int type); int unit_setdir(struct block_list *bl,unsigned char dir); uint8 unit_getdir(struct block_list *bl); @@ -61,8 +61,8 @@ void unit_dataset(struct block_list *bl); int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2); // その他 struct unit_data* unit_bl2ud(struct block_list *bl); -int unit_remove_map(struct block_list *bl, uint8 clrtype); -int unit_free(struct block_list *bl, uint8 clrtype); +int unit_remove_map(struct block_list *bl, int clrtype); +int unit_free(struct block_list *bl, int clrtype); int unit_changeviewsize(struct block_list *bl,short size); // 初期化ルーチン -- cgit v1.2.3-70-g09d2 From ebf1cd085c9f4061318f99f9ab19b63148d19819 Mon Sep 17 00:00:00 2001 From: ultramage Date: Sat, 22 Dec 2007 13:00:48 +0000 Subject: Path code cleaning... * Added map/path.h, moved path-related function headers to path.h. * Removed the macroed _real() path functions. * Modified some functions to use boolean return values instead of 1/0 or 0/-1. * Modified path_search_long() to allow a NULL output pointer (in which case a temporary local buffer will be used instead). * Removed an unused ->path_half member variable from struct walkpath_data. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@11958 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/Makefile.in | 2 +- src/map/battle.c | 15 ++-- src/map/battle.h | 2 +- src/map/map.c | 17 ++-- src/map/map.h | 12 +-- src/map/path.c | 175 +++++++++++++++++++-------------------- src/map/skill.c | 5 +- src/map/unit.c | 45 ++++------ src/map/unit.h | 4 +- vcproj-6/map-server_sql.dsp | 4 + vcproj-6/map-server_txt.dsp | 4 + vcproj-7.1/map-server_sql.vcproj | 3 + vcproj-7.1/map-server_txt.vcproj | 3 + vcproj-8/map-server_sql.vcproj | 4 + vcproj-8/map-server_txt.vcproj | 4 + 15 files changed, 147 insertions(+), 152 deletions(-) (limited to 'src/map/unit.h') diff --git a/src/map/Makefile.in b/src/map/Makefile.in index 355086127..4276b976a 100644 --- a/src/map/Makefile.in +++ b/src/map/Makefile.in @@ -21,7 +21,7 @@ MAP_OBJ = map.o chrif.o clif.o pc.o status.o npc.o \ MAP_TXT_OBJ = $(MAP_OBJ:%=obj_txt/%) MAP_SQL_OBJ = $(MAP_OBJ:%=obj_sql/%) MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \ - chat.h itemdb.h mob.h script.h \ + chat.h itemdb.h mob.h script.h path.h \ storage.h skill.h atcommand.h charcommand.h battle.h \ intif.h trade.h party.h vending.h guild.h pet.h \ log.h mail.h date.h irc.h unit.h mercenary.h diff --git a/src/map/battle.c b/src/map/battle.c index f9dbb636e..142db46db 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -11,6 +11,7 @@ #include "../common/utils.h" #include "map.h" +#include "path.h" #include "pc.h" #include "status.h" #include "skill.h" @@ -3274,25 +3275,25 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f /*========================================== * 射程判定 *------------------------------------------*/ -int battle_check_range(struct block_list *src,struct block_list *bl,int range) +bool battle_check_range(struct block_list *src,struct block_list *bl,int range) { - nullpo_retr(0, src); - nullpo_retr(0, bl); + nullpo_retr(false, src); + nullpo_retr(false, bl); if(src->m != bl->m) // 違うマップ - return 0; + return false; if(src->type == BL_HOM && battle_config.hom_setting&0x2) range = battle_config.area_size + 1; //WTF, way to go Aegis and your awesome bugs. if (!check_distance_bl(src, bl, range)) - return 0; + return false; if(distance_bl(src, bl) < 2) //No need for path checking. - return 1; + return true; // ?瘧Q物判定 - return path_search_long(NULL,src->m,src->x,src->y,bl->x,bl->y); + return path_search_long(NULL,src->m,src->x,src->y,bl->x,bl->y,CELL_CHKWALL); } static const struct _battle_data { diff --git a/src/map/battle.h b/src/map/battle.h index a46592308..1b12dbd03 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -86,7 +86,7 @@ int battle_getcurrentskill(struct block_list *bl); int battle_check_undead(int race,int element); int battle_check_target(struct block_list *src, struct block_list *target,int flag); -int battle_check_range(struct block_list *src,struct block_list *bl,int range); +bool battle_check_range(struct block_list *src,struct block_list *bl,int range); void battle_consume_ammo(struct map_session_data* sd, int skill, int lv); // 設定 diff --git a/src/map/map.c b/src/map/map.c index 26a8931e6..e3c5aacbe 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -14,6 +14,7 @@ #include "../common/utils.h" #include "map.h" +#include "path.h" #include "chrif.h" #include "clif.h" #include "intif.h" @@ -690,7 +691,7 @@ int map_foreachinshootrange(int (*func)(struct block_list*,va_list),struct block #ifdef CIRCULAR_AREA && check_distance_bl(center, bl, range) #endif - && path_search_long(NULL,center->m,center->x,center->y,bl->x,bl->y) + && path_search_long(NULL,center->m,center->x,center->y,bl->x,bl->y,CELL_CHKWALL) && bl_list_countm,center->x,center->y,bl->x,bl->y) + && path_search_long(NULL,center->m,center->x,center->y,bl->x,bl->y,CELL_CHKWALL) && bl_list_count len_limit) //Since more skills use this, check for ending point as well. continue; - if (k > magnitude2 && !path_search_long(NULL,m,x0,y0,xi,yi)) + if (k > magnitude2 && !path_search_long(NULL,m,x0,y0,xi,yi,CELL_CHKWALL)) continue; //Targets beyond the initial ending point need the wall check. //All these shifts are to increase the precision of the intersection point and distance considering how it's @@ -1158,7 +1159,7 @@ int map_foreachinpath(int (*func)(struct block_list*,va_list),int m,int x0,int y if (k < 0 || k > len_limit) continue; - if (k > magnitude2 && !path_search_long(NULL,m,x0,y0,xi,yi)) + if (k > magnitude2 && !path_search_long(NULL,m,x0,y0,xi,yi,CELL_CHKWALL)) continue; //Targets beyond the initial ending point need the wall check. k = (k<<4)/magnitude2; //k will be between 1~16 instead of 0~1 @@ -2194,7 +2195,6 @@ uint8 map_calc_dir(struct block_list* src, int x, int y) *------------------------------------------*/ int map_random_dir(struct block_list *bl, short *x, short *y) { - struct walkpath_data wpd; short xi = *x-bl->x; short yi = *y-bl->y; short i=0, j; @@ -2210,10 +2210,9 @@ int map_random_dir(struct block_list *bl, short *x, short *y) xi = bl->x + segment*dirx[j]; segment = (short)sqrt(dist2 - segment*segment); //The complement of the previously picked segment yi = bl->y + segment*diry[j]; - } while (( - map_getcell(bl->m,xi,yi,CELL_CHKNOPASS) || - path_search_real(&wpd,bl->m,bl->x,bl->y,xi,yi,1,CELL_CHKNOREACH) == -1) - && (++i)<100); + } while ( + (map_getcell(bl->m,xi,yi,CELL_CHKNOPASS) || !path_search(NULL,bl->m,bl->x,bl->y,xi,yi,1,CELL_CHKNOREACH)) + && (++i)<100 ); if (i < 100) { *x = xi; diff --git a/src/map/map.h b/src/map/map.h index 7aa99d219..6d06bc599 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -236,7 +236,7 @@ struct block_list { }; struct walkpath_data { - unsigned char path_len,path_pos,path_half; + unsigned char path_len,path_pos; unsigned char path[MAX_WALKPATH]; }; struct shootpath_data { @@ -1344,16 +1344,6 @@ int map_check_dir(int s_dir,int t_dir); unsigned char map_calc_dir( struct block_list *src,int x,int y); int map_random_dir(struct block_list *bl, short *x, short *y); // [Skotlex] -// path.cより -int path_search_real(struct walkpath_data *wpd,int m,int x0,int y0,int x1,int y1,int flag,cell_t flag2); -#define path_search(wpd,m,x0,y0,x1,y1,flag) path_search_real(wpd,m,x0,y0,x1,y1,flag,CELL_CHKNOPASS) -#define path_search2(wpd,m,x0,y0,x1,y1,flag) path_search_real(wpd,m,x0,y0,x1,y1,flag,CELL_CHKWALL) - -bool path_search_long_real(struct shootpath_data *spd,int m,int x0,int y0,int x1,int y1,cell_t flag); -#define path_search_long(spd,m,x0,y0,x1,y1) path_search_long_real(spd,m,x0,y0,x1,y1,CELL_CHKWALL) - -int path_blownpos(int m,int x0,int y0,int dx,int dy,int count); - // distance related functions [Skotlex] #define check_distance_bl(bl1, bl2, distance) check_distance((bl1)->x - (bl2)->x, (bl1)->y - (bl2)->y, distance) #define check_distance_blxy(bl, x1, y1, distance) check_distance((bl)->x-(x1), (bl)->y-(y1), distance) diff --git a/src/map/path.c b/src/map/path.c index 3d4b99fc9..52dcd0ac8 100644 --- a/src/map/path.c +++ b/src/map/path.c @@ -7,14 +7,13 @@ #include "../common/malloc.h" #include "map.h" #include "battle.h" +#include "path.h" #include #include #include -//#define PATH_STANDALONETEST - #define MAX_HEAP 150 struct tmp_path { short x,y,dist,before,cost,flag;}; @@ -226,18 +225,22 @@ int path_blownpos(int m,int x0,int y0,int dx,int dy,int count) x0+=dx; y0+=dy; } - return (x0<<16)|y0; + return (x0<<16)|y0; //TODO: use 'struct point' here instead? } /*========================================== * is ranged attack from (x0,y0) to (x1,y1) possible? *------------------------------------------*/ -bool path_search_long_real(struct shootpath_data *spd,int m,int x0,int y0,int x1,int y1,cell_t flag) +bool path_search_long(struct shootpath_data *spd,int m,int x0,int y0,int x1,int y1,cell_t cell) { int dx, dy; int wx = 0, wy = 0; int weight; struct map_data *md; + struct shootpath_data s_spd; + + if( spd == NULL ) + spd = &s_spd; // use dummy output variable if (!map[m].gat) return false; @@ -251,43 +254,41 @@ bool path_search_long_real(struct shootpath_data *spd,int m,int x0,int y0,int x1 } dy = (y1 - y0); - if (spd) { - spd->rx = spd->ry = 0; - spd->len = 1; - spd->x[0] = x0; - spd->y[0] = y0; - } + spd->rx = spd->ry = 0; + spd->len = 1; + spd->x[0] = x0; + spd->y[0] = y0; - if (map_getcellp(md,x1,y1,flag)) + if (map_getcellp(md,x1,y1,cell)) return false; if (dx > abs(dy)) { weight = dx; - if (spd) - spd->ry=1; + spd->ry = 1; } else { weight = abs(y1 - y0); - if (spd) - spd->rx=1; + spd->rx = 1; } - while (x0 != x1 || y0 != y1) { - if (map_getcellp(md,x0,y0,flag)) + while (x0 != x1 || y0 != y1) + { + if (map_getcellp(md,x0,y0,cell)) return false; wx += dx; wy += dy; if (wx >= weight) { wx -= weight; - x0 ++; + x0++; } if (wy >= weight) { wy -= weight; - y0 ++; + y0++; } else if (wy < 0) { wy += weight; - y0 --; + y0--; } - if (spd && spd->lenlenx[spd->len] = x0; spd->y[spd->len] = y0; spd->len++; @@ -299,39 +300,48 @@ bool path_search_long_real(struct shootpath_data *spd,int m,int x0,int y0,int x1 /*========================================== * path search (x0,y0)->(x1,y1) + * wpd: path info will be written here * flag: &1 = easy path search only + * cell: type of obstruction to check for *------------------------------------------*/ -int path_search_real(struct walkpath_data *wpd,int m,int x0,int y0,int x1,int y1,int flag,cell_t flag2) +bool path_search(struct walkpath_data *wpd,int m,int x0,int y0,int x1,int y1,int flag,cell_t cell) { int heap[MAX_HEAP+1]; struct tmp_path tp[MAX_WALKPATH*MAX_WALKPATH]; - register int i,x,y,dx,dy; + register int i,j,len,x,y,dx,dy; int rp,xs,ys; struct map_data *md; + struct walkpath_data s_wpd; - nullpo_retr(0, wpd); + if( wpd == NULL ) + wpd = &s_wpd; // use dummy output variable if( !map[m].gat ) - return -1; + return false; md = &map[m]; + #ifdef CELL_NOSTACK //Do not check starting cell as that would get you stuck. if( x0 < 0 || x0 >= md->xs || y0 < 0 || y0 >= md->ys ) #else - if( x0 < 0 || x0 >= md->xs || y0 < 0 || y0 >= md->ys /*|| map_getcellp(md,x0,y0,flag2)*/ ) + if( x0 < 0 || x0 >= md->xs || y0 < 0 || y0 >= md->ys /*|| map_getcellp(md,x0,y0,cell)*/ ) #endif - return -1; - if( x1 < 0 || x1 >= md->xs || y1 < 0 || y1 >= md->ys || map_getcellp(md,x1,y1,flag2) ) - return -1; + return false; + if( x1 < 0 || x1 >= md->xs || y1 < 0 || y1 >= md->ys || map_getcellp(md,x1,y1,cell) ) + return false; // calculate (sgn(x1-x0), sgn(y1-y0)) dx = ((dx = x1-x0)) ? ((dx<0) ? -1 : 1) : 0; dy = ((dy = y1-y0)) ? ((dy<0) ? -1 : 1) : 0; // try finding direct path to target - for( x = x0, y = y0, i = 0; i < ARRAYLENGTH(wpd->path); ) + x = x0; + y = y0; + i = 0; + while( i < ARRAYLENGTH(wpd->path) ) { - wpd->path[i++] = walk_choices[-dy + 1][dx + 1]; + wpd->path[i] = walk_choices[-dy + 1][dx + 1]; + i++; x += dx; y += dy; @@ -339,9 +349,9 @@ int path_search_real(struct walkpath_data *wpd,int m,int x0,int y0,int x1,int y1 if( x == x1 ) dx = 0; if( y == y1 ) dy = 0; - if( !dx && !dy ) + if( dx == 0 && dy == 0 ) break; // success - if( map_getcellp(md,x,y,flag2) ) + if( map_getcellp(md,x,y,cell) ) break; // obstacle = failure } @@ -349,12 +359,11 @@ int path_search_real(struct walkpath_data *wpd,int m,int x0,int y0,int x1,int y1 { //easy path successful. wpd->path_len = i; wpd->path_pos = 0; - wpd->path_half = 0; - return 0; + return true; } if( flag&1 ) - return -1; + return false; memset(tp,0,sizeof(tp)); @@ -369,94 +378,78 @@ int path_search_real(struct walkpath_data *wpd,int m,int x0,int y0,int x1,int y1 push_heap_path(heap,tp,calc_index(x0,y0)); xs = md->xs-1; // あらかじめ1減算しておく ys = md->ys-1; - while(1){ + + while(1) + { int e=0,f=0,dist,cost,dc[4]={0,0,0,0}; if(heap[0]==0) - return -1; + return false; rp = pop_heap_path(heap,tp); x = tp[rp].x; y = tp[rp].y; dist = tp[rp].dist + 10; cost = tp[rp].cost; - if(x==x1 && y==y1) break; + + if(x==x1 && y==y1) + break; // dc[0] : y++ の時のコスト増分 // dc[1] : x-- の時のコスト増分 // dc[2] : y-- の時のコスト増分 // dc[3] : x++ の時のコスト増分 - if(y < ys && !map_getcellp(md,x ,y+1,flag2)) { + if(y < ys && !map_getcellp(md,x ,y+1,cell)) { f |= 1; dc[0] = (y >= y1 ? 20 : 0); e+=add_path(heap,tp,x ,y+1,dist,rp,cost+dc[0]); // (x, y+1) } - if(x > 0 && !map_getcellp(md,x-1,y ,flag2)) { + if(x > 0 && !map_getcellp(md,x-1,y ,cell)) { f |= 2; dc[1] = (x <= x1 ? 20 : 0); e+=add_path(heap,tp,x-1,y ,dist,rp,cost+dc[1]); // (x-1, y ) } - if(y > 0 && !map_getcellp(md,x ,y-1,flag2)) { + if(y > 0 && !map_getcellp(md,x ,y-1,cell)) { f |= 4; dc[2] = (y <= y1 ? 20 : 0); e+=add_path(heap,tp,x ,y-1,dist,rp,cost+dc[2]); // (x , y-1) } - if(x < xs && !map_getcellp(md,x+1,y ,flag2)) { + if(x < xs && !map_getcellp(md,x+1,y ,cell)) { f |= 8; dc[3] = (x >= x1 ? 20 : 0); e+=add_path(heap,tp,x+1,y ,dist,rp,cost+dc[3]); // (x+1, y ) } - if( (f & (2+1)) == (2+1) && !map_getcellp(md,x-1,y+1,flag2)) + if( (f & (2+1)) == (2+1) && !map_getcellp(md,x-1,y+1,cell)) e+=add_path(heap,tp,x-1,y+1,dist+4,rp,cost+dc[1]+dc[0]-6); // (x-1, y+1) - if( (f & (2+4)) == (2+4) && !map_getcellp(md,x-1,y-1,flag2)) + if( (f & (2+4)) == (2+4) && !map_getcellp(md,x-1,y-1,cell)) e+=add_path(heap,tp,x-1,y-1,dist+4,rp,cost+dc[1]+dc[2]-6); // (x-1, y-1) - if( (f & (8+4)) == (8+4) && !map_getcellp(md,x+1,y-1,flag2)) + if( (f & (8+4)) == (8+4) && !map_getcellp(md,x+1,y-1,cell)) e+=add_path(heap,tp,x+1,y-1,dist+4,rp,cost+dc[3]+dc[2]-6); // (x+1, y-1) - if( (f & (8+1)) == (8+1) && !map_getcellp(md,x+1,y+1,flag2)) + if( (f & (8+1)) == (8+1) && !map_getcellp(md,x+1,y+1,cell)) e+=add_path(heap,tp,x+1,y+1,dist+4,rp,cost+dc[3]+dc[0]-6); // (x+1, y+1) tp[rp].flag=1; if(e || heap[0]>=MAX_HEAP-5) - return -1; + return false; } - if(x==x1 && y==y1) { - int len,j; - - for(len=0,i=rp;len<100 && i!=calc_index(x0,y0);i=tp[i].before,len++); - if(len==100 || len>=sizeof(wpd->path)) - return -1; - wpd->path_len=len; - wpd->path_pos=0; - wpd->path_half=0; - for(i=rp,j=len-1;j>=0;i=tp[i].before,j--) { - int dx = tp[i].x - tp[tp[i].before].x; - int dy = tp[i].y - tp[tp[i].before].y; - int dir; - if( dx == 0 ) { - dir = (dy > 0 ? 0 : 4); - } else if( dx > 0 ) { - dir = (dy == 0 ? 6 : (dy < 0 ? 5 : 7) ); - } else { - dir = (dy == 0 ? 2 : (dy > 0 ? 1 : 3) ); - } - wpd->path[j] = dir; - } -#if 0 - // test - { - int dirx[8]={0,-1,-1,-1,0,1,1,1}; - int diry[8]={1,1,0,-1,-1,-1,0,1}; - x = x0; y = y0; - for(i = 0; i < wpd->path_len; i++) { - x += dirx[ wpd->path[i] ]; - y += diry[ wpd->path[i] ]; - if( map_getcellp(md,x,y,flag2) ) { - printf("path_search_real: cannot move(%d, %d)\n", x, y); - return -1; - } - } - if( x != x1 || y != y1 ) { - printf("path_search_real: dest position is wrong. ok:(%d, %d) ng:(%d,%d)\n", x1, y1, x, y); - return -1; - } + + if( !(x==x1 && y==y1) ) // will never happen... + return false; + + for(len=0,i=rp;len<100 && i!=calc_index(x0,y0);i=tp[i].before,len++); + if(len==100 || len>=sizeof(wpd->path)) + return false; + + wpd->path_len = len; + wpd->path_pos = 0; + for(i=rp,j=len-1;j>=0;i=tp[i].before,j--) { + int dx = tp[i].x - tp[tp[i].before].x; + int dy = tp[i].y - tp[tp[i].before].y; + int dir; + if( dx == 0 ) { + dir = (dy > 0 ? 0 : 4); + } else if( dx > 0 ) { + dir = (dy == 0 ? 6 : (dy < 0 ? 5 : 7) ); + } else { + dir = (dy == 0 ? 2 : (dy > 0 ? 1 : 3) ); } -#endif - return 0; + wpd->path[j] = dir; } - return -1; + + return true; } diff --git a/src/map/skill.c b/src/map/skill.c index f3709e93a..a54ff032a 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -12,6 +12,7 @@ #include "skill.h" #include "map.h" +#include "path.h" #include "clif.h" #include "pc.h" #include "status.h" @@ -2331,7 +2332,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int case KN_CHARGEATK: { - bool path = path_search_long(NULL, src->m, src->x, src->y, bl->x, bl->y); + bool path = path_search_long(NULL, src->m, src->x, src->y, bl->x, bl->y,CELL_CHKWALL); unsigned int dist = distance_bl(src, bl); unsigned int dir = map_calc_dir(bl, src->x, src->y); @@ -6407,7 +6408,7 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, short skilli if(alive && map_getcell(src->m,ux,uy,CELL_CHKWALL)) alive = 0; - if(alive && battle_config.skill_wall_check && !path_search_long(NULL,src->m,ux,uy,x,y)) + if( alive && battle_config.skill_wall_check && !path_search_long(NULL,src->m,ux,uy,x,y,CELL_CHKWALL) ) alive = 0; //no path between cell and center of casting. if(alive && skillid == WZ_ICEWALL) { diff --git a/src/map/unit.c b/src/map/unit.c index a101a5160..6e0eed53c 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -8,6 +8,7 @@ #include "../common/malloc.h" #include "unit.h" #include "map.h" +#include "path.h" #include "pc.h" #include "mob.h" #include "pet.h" @@ -58,7 +59,7 @@ int unit_walktoxy_sub(struct block_list *bl) ud = unit_bl2ud(bl); if(ud == NULL) return 0; - if(path_search(&wpd,bl->m,bl->x,bl->y,ud->to_x,ud->to_y,ud->state.walk_easy)) + if( !path_search(&wpd,bl->m,bl->x,bl->y,ud->to_x,ud->to_y,ud->state.walk_easy,CELL_CHKNOPASS) ) return 0; memcpy(&ud->walkpath,&wpd,sizeof(wpd)); @@ -472,7 +473,6 @@ int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, bool uint8 dir; struct unit_data *ud = NULL; struct map_session_data *sd = NULL; - struct walkpath_data wpd; nullpo_retr(0, bl); if( BL_CAST( BL_PC, bl, sd ) ) { @@ -485,8 +485,8 @@ int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, bool unit_stop_walking(bl,1); unit_stop_attack(bl); - if(checkpath && (map_getcell(bl->m,dst_x,dst_y, CELL_CHKNOPASS) || path_search_real(&wpd,bl->m,bl->x,bl->y,dst_x,dst_y,easy, CELL_CHKNOREACH))) - return 0; + if( checkpath && (map_getcell(bl->m,dst_x,dst_y,CELL_CHKNOPASS) || !path_search(NULL,bl->m,bl->x,bl->y,dst_x,dst_y,easy,CELL_CHKNOREACH)) ) + return 0; // unreachable dir = map_calc_dir(bl, dst_x,dst_y); ud->dir = dir; @@ -513,7 +513,7 @@ int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, bool { //Check if pet needs to be teleported. [Skotlex] int flag = 0; struct block_list* bl = &sd->pd->bl; - if (!checkpath && path_search(&wpd,bl->m,bl->x,bl->y,dst_x,dst_y,0)) + if( !checkpath && !path_search(NULL,bl->m,bl->x,bl->y,dst_x,dst_y,0,CELL_CHKNOPASS) ) flag = 1; else if (!check_distance_bl(&sd->bl, bl, AREA_SIZE)) //Too far, teleport. flag = 2; @@ -1273,46 +1273,35 @@ int unit_cancel_combo(struct block_list *bl) /*========================================== * *------------------------------------------*/ -int unit_can_reach_pos(struct block_list *bl,int x,int y, int easy) +bool unit_can_reach_pos(struct block_list *bl,int x,int y, int easy) { - struct walkpath_data wpd; - - nullpo_retr(0, bl); + nullpo_retr(false, bl); if( bl->x==x && bl->y==y ) // 同じマス - return 1; + return true; - // 障害物判定 - wpd.path_len=0; - wpd.path_pos=0; - wpd.path_half=0; - return (path_search_real(&wpd,bl->m,bl->x,bl->y,x,y,easy,CELL_CHKNOREACH)!=-1); + return path_search(NULL,bl->m,bl->x,bl->y,x,y,easy,CELL_CHKNOREACH); } /*========================================== * *------------------------------------------*/ -int unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, int easy, short *x, short *y) +bool unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, int easy, short *x, short *y) { - struct walkpath_data wpd; int i; short dx,dy; - nullpo_retr(0, bl); - nullpo_retr(0, tbl); + nullpo_retr(false, bl); + nullpo_retr(false, tbl); if( bl->m != tbl->m) - return 0; + return false; if( bl->x==tbl->x && bl->y==tbl->y ) - return 1; + return true; if(range>0 && !check_distance_bl(bl, tbl, range)) - return 0; + return false; - wpd.path_len=0; - wpd.path_pos=0; - wpd.path_half=0; - // It judges whether it can adjoin or not. dx=tbl->x - bl->x; dy=tbl->y - bl->y; @@ -1322,14 +1311,14 @@ int unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, i if (map_getcell(tbl->m,tbl->x-dx,tbl->y-dy,CELL_CHKNOPASS)) { //Look for a suitable cell to place in. for(i=0;i<9 && map_getcell(tbl->m,tbl->x-dirx[i],tbl->y-diry[i],CELL_CHKNOPASS);i++); - if (i==9) return 0; //No valid cells. + if (i==9) return false; //No valid cells. dx = dirx[i]; dy = diry[i]; } if (x) *x = tbl->x-dx; if (y) *y = tbl->y-dy; - return (path_search_real(&wpd,bl->m,bl->x,bl->y,tbl->x-dx,tbl->y-dy,easy,CELL_CHKNOREACH)!=-1); + return path_search(NULL,bl->m,bl->x,bl->y,tbl->x-dx,tbl->y-dy,easy,CELL_CHKNOREACH); } diff --git a/src/map/unit.h b/src/map/unit.h index 6c6124f5c..2c569607d 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -34,8 +34,8 @@ int unit_setdir(struct block_list *bl,unsigned char dir); uint8 unit_getdir(struct block_list *bl); // そこまで歩行でたどり着けるかの判定 -int unit_can_reach_pos(struct block_list *bl,int x,int y,int easy); -int unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, int easy, short *x, short *y); +bool unit_can_reach_pos(struct block_list *bl,int x,int y,int easy); +bool unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, int easy, short *x, short *y); // 攻撃関連 int unit_stop_attack(struct block_list *bl); diff --git a/vcproj-6/map-server_sql.dsp b/vcproj-6/map-server_sql.dsp index f18eda8c6..a80ded6f1 100644 --- a/vcproj-6/map-server_sql.dsp +++ b/vcproj-6/map-server_sql.dsp @@ -351,6 +351,10 @@ SOURCE=..\src\map\path.c # End Source File # Begin Source File +SOURCE=..\src\map\path.h +# End Source File +# Begin Source File + SOURCE=..\src\map\pc.c # End Source File # Begin Source File diff --git a/vcproj-6/map-server_txt.dsp b/vcproj-6/map-server_txt.dsp index 9cf688678..2f56c5a62 100644 --- a/vcproj-6/map-server_txt.dsp +++ b/vcproj-6/map-server_txt.dsp @@ -379,6 +379,10 @@ SOURCE=..\src\map\party.h # End Source File # Begin Source File +SOURCE=..\src\map\path.h +# End Source File +# Begin Source File + SOURCE=..\src\map\pc.h # End Source File # Begin Source File diff --git a/vcproj-7.1/map-server_sql.vcproj b/vcproj-7.1/map-server_sql.vcproj index ff3662304..7b6329f0d 100644 --- a/vcproj-7.1/map-server_sql.vcproj +++ b/vcproj-7.1/map-server_sql.vcproj @@ -258,6 +258,9 @@ + + diff --git a/vcproj-7.1/map-server_txt.vcproj b/vcproj-7.1/map-server_txt.vcproj index c4220e0aa..899268ebd 100644 --- a/vcproj-7.1/map-server_txt.vcproj +++ b/vcproj-7.1/map-server_txt.vcproj @@ -258,6 +258,9 @@ + + diff --git a/vcproj-8/map-server_sql.vcproj b/vcproj-8/map-server_sql.vcproj index 913422ea2..d1cd17c8c 100644 --- a/vcproj-8/map-server_sql.vcproj +++ b/vcproj-8/map-server_sql.vcproj @@ -508,6 +508,10 @@ RelativePath="..\src\map\path.c" > + + diff --git a/vcproj-8/map-server_txt.vcproj b/vcproj-8/map-server_txt.vcproj index 57e557e1f..24069e35c 100644 --- a/vcproj-8/map-server_txt.vcproj +++ b/vcproj-8/map-server_txt.vcproj @@ -356,6 +356,10 @@ RelativePath="..\src\map\path.c" > + + -- cgit v1.2.3-70-g09d2 From fd665092bbcd4be32f9d8319ffbb4aad30b40d08 Mon Sep 17 00:00:00 2001 From: skotlex Date: Thu, 21 Feb 2008 00:13:56 +0000 Subject: - Fixed new guilds displaying online-connect member count at 0 rather than 1, and the guild master not knowing it is one (eg: it cannot edit the guild notice of a newly created guild until relogging). - Fixed acc_reg2 parsing screwing up the char_id and subtracting 2 from it rather than passing it as it is. - Extended the auth_node/auth_db system in chrif.c to handle log in/out and mapserver-change procedures. This way players are not in the main dbs when they are not "active", which blocks potential invalid accesses to them. - Replaced states auth, waiting_disconnect and finalsave with active. - Cleaned some the party/guild login and creation procedures, removed the party_sent/guild_sent states. - Removed a redundant guild_check_member call which is beyond not-needed and into the realm of wasting resources. - clif_parse will no longer process packets from !sd->state.active players, this also makes checking for finalsave uneccessary (since players re already removed from the maps and dbs by this point, so you can't access them in any other way) - Separated the roles of unit_free and map_quit, the former will handle cleaning structures from the player so it can be free'd safely, while the latter performs additional routines which are unique to characters logging out normally (map-server changes will invoke unit_free and bypass map_quit). - Removed pc_isplaying, quit_db, map_knowsaccount, MAPIT_PCISPLAYING among other functions/defines which are no longer needed due to the new login scheme. - Cleand up a bit some code in the clif_send(_sub) functions. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@12223 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 11 ++ src/char/int_guild.c | 1 + src/char/inter.c | 2 +- src/char_sql/int_guild.c | 2 + src/char_sql/inter.c | 2 +- src/map/atcommand.c | 2 +- src/map/chrif.c | 317 +++++++++++++++++++++++++++++++---------------- src/map/chrif.h | 16 ++- src/map/clif.c | 183 ++++++++++++++------------- src/map/guild.c | 71 +++++++---- src/map/guild.h | 1 + src/map/intif.c | 31 ++--- src/map/mail.c | 2 +- src/map/map.c | 196 +++++++++-------------------- src/map/map.h | 12 +- src/map/party.c | 75 ++++++----- src/map/party.h | 1 + src/map/pc.c | 171 ++++++++----------------- src/map/pc.h | 5 +- src/map/status.c | 6 - src/map/storage.c | 9 -- src/map/trade.c | 3 - src/map/unit.c | 106 ++++++++-------- src/map/unit.h | 3 + 24 files changed, 603 insertions(+), 625 deletions(-) (limited to 'src/map/unit.h') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index f4e32dc62..bb24553ff 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -3,6 +3,17 @@ Date Added AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK. IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. +2007/02/21 + * Restructured the login mechanism of the map-server. The goal was to make + sure players are not found in the different dbs of the map while the + player has not yet been fully authed or while it is quitting, to avoid the + rest of the code from accessing and modifying it. It is a rather extensive + change, and I only had time to test the basic functionality, so if use with + care and report any bugs found. + * Replaced player states auth, waiting_disconnect, finalsave with active, + and removed states party_sent/guild_sent. + * Removed several of the old login methods/constants/player states which + are no longer needed due to this cleanup. [Skotlex] 2007/02/19 * Rev. 12219 Fixed a typo in /map/clif.c (acount_id -> account_id) [L0ne_W0lf] * Forgotten update to the definition of script command 'input'. diff --git a/src/char/int_guild.c b/src/char/int_guild.c index 2e2933c14..ac15b9a0a 100644 --- a/src/char/int_guild.c +++ b/src/char/int_guild.c @@ -1004,6 +1004,7 @@ int mapif_parse_CreateGuild(int fd, int account_id, char *name, struct guild_mem // ここでギルド情報計算が必要と思われる g->max_member = 16; g->average_lv = master->lv; + g->connect_member = 1; for(i = 0; i < MAX_GUILDSKILL; i++) g->skill[i].id=i + GD_SKILLBASE; diff --git a/src/char/inter.c b/src/char/inter.c index 4e617c1e6..8472d36d1 100644 --- a/src/char/inter.c +++ b/src/char/inter.c @@ -611,7 +611,7 @@ int mapif_parse_RegistryRequest(int fd) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6)); //Ask Login Server for Account2 values. if (RFIFOB(fd,10)) - request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)-2); + request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)); return 1; } diff --git a/src/char_sql/int_guild.c b/src/char_sql/int_guild.c index 5ffc96980..93b915886 100644 --- a/src/char_sql/int_guild.c +++ b/src/char_sql/int_guild.c @@ -1282,6 +1282,8 @@ int mapif_parse_CreateGuild(int fd,int account_id,char *name,struct guild_member // Initialize guild property g->max_member=16; g->average_lv=master->lv; + g->connect_member=1; + for(i=0;iskill[i].id=i + GD_SKILLBASE; g->guild_id= -1; //Request to create guild. diff --git a/src/char_sql/inter.c b/src/char_sql/inter.c index e6f955fbe..9cf89ae54 100644 --- a/src/char_sql/inter.c +++ b/src/char_sql/inter.c @@ -786,7 +786,7 @@ int mapif_parse_RegistryRequest(int fd) //Load Account Registry if (RFIFOB(fd,11)) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),2); //Ask Login Server for Account2 values. - if (RFIFOB(fd,10)) request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)-2); + if (RFIFOB(fd,10)) request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)); return 1; } diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 8da0f1265..13bbb5ef0 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -3533,7 +3533,7 @@ int atcommand_doommap(const int fd, struct map_session_data* sd, const char* com *------------------------------------------*/ static void atcommand_raise_sub(struct map_session_data* sd) { - if (!sd->state.auth || !status_isdead(&sd->bl)) + if (!status_isdead(&sd->bl)) return; if(!status_revive(&sd->bl, 100, 100)) diff --git a/src/map/chrif.c b/src/map/chrif.c index e88ee3c5d..005285da5 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -8,6 +8,7 @@ #include "../common/nullpo.h" #include "../common/showmsg.h" #include "../common/strlib.h" +#include "../common/ers.h" #include "map.h" #include "battle.h" @@ -25,7 +26,8 @@ #include #include -DBMap* auth_db; // int id -> struct auth_node* +static struct eri *auth_db_ers; //For reutilizing player login structures. +static DBMap* auth_db; // int id -> struct auth_node* static const int packet_len_table[0x3d] = { // U - used, F - free 60, 3,-1,27,10,-1, 6,-1, // 2af8-2aff: U->2af8, U->2af9, U->2afa, U->2afb, U->2afc, U->2afd, U->2afe, U->2aff @@ -101,7 +103,77 @@ int other_mapserver_count=0; //Holds count of how many other map servers are onl //This define should spare writing the check in every function. [Skotlex] #define chrif_check(a) { if(!chrif_isconnected()) return a; } +struct auth_node* chrif_search(int account_id) { + return idb_get(auth_db, account_id); +} + +struct auth_node* chrif_auth_check(int account_id, int char_id, enum sd_state state) { + struct auth_node *node = chrif_search(account_id); + return (node && node->char_id == char_id && node->state == state)?node:NULL; +} + +bool chrif_auth_delete(int account_id, int char_id, enum sd_state state) { + struct auth_node *node; + if ((node=chrif_auth_check(account_id, char_id, state))) + { + if (node->fd && session[node->fd] && node->sd && + session[node->fd]->session_data == node->sd) + session[node->fd]->session_data = NULL; + if (node->char_dat) aFree(node->char_dat); + if (node->sd) aFree(node->sd); + ers_free(auth_db_ers, node); + idb_remove(auth_db,account_id); + return true; + } + return false; +} + +//Moves the sd character to the auth_db structure. +static bool chrif_sd_to_auth(TBL_PC* sd, enum sd_state state) +{ + struct auth_node *node; + if (chrif_search(sd->status.account_id)) + return false; //Already exists? + + node = ers_alloc(auth_db_ers, struct auth_node); + memset(node, 0, sizeof(struct auth_node)); + node->account_id = sd->status.account_id; + node->char_id = sd->status.char_id; + node->login_id1 = sd->login_id1; + node->login_id2 = sd->login_id2; + node->sex = sd->status.sex; + node->fd = sd->fd; + node->sd = sd; //Data from logged on char. + node->node_created = gettick(); //timestamp for node timeouts + node->state = state; + + sd->state.active = 0; + idb_put(auth_db, node->account_id, node); + return true; +} + +static bool chrif_auth_logout(TBL_PC* sd, enum sd_state state) +{ + if(sd->fd && state == ST_LOGOUT) + { //Disassociate player, and free it after saving ack returns. [Skotlex] + //fd info must not be lost for ST_MAPCHANGE as a final packet needs to be sent to the player. + if (session[sd->fd]) + session[sd->fd]->session_data = NULL; + sd->fd = 0; + } + return chrif_sd_to_auth(sd, state); +} +bool chrif_auth_finished(TBL_PC* sd) +{ + struct auth_node *node= chrif_search(sd->status.account_id); + if (node && node->sd == sd && node->state == ST_LOGIN) { + node->sd = NULL; + chrif_auth_delete(node->account_id, node->char_id, ST_LOGIN); + return true; + } + return false; +} // sets char-server's user id void chrif_setuserid(char *id) { @@ -165,15 +237,17 @@ int chrif_save(struct map_session_data *sd, int flag) if (!flag) //The flag check is needed to prevent 'nosave' taking effect when a jailed player logs out. pc_makesavestatus(sd); + + if (flag && sd->state.active) //Store player data which is quitting. + { + //FIXME: SC are lost if there's no connection at save-time because of the way its related data is cleared immediately after this function. [Skotlex] + if (chrif_isconnected()) chrif_save_scdata(sd); + chrif_auth_logout(sd, flag==1?ST_LOGOUT:ST_MAPCHANGE); + } if(!chrif_isconnected()) - { - if (flag) sd->state.finalsave = 1; //Will save character on reconnect. - return -1; - } + return -1; //Character is saved on reconnect. - if (sd->state.finalsave) - return -1; //Refuse to save a char already tagged for final saving. [Skotlex] //For data sync if (sd->state.storage_flag == 1) storage_storage_save(sd->status.account_id, flag); @@ -198,11 +272,13 @@ int chrif_save(struct map_session_data *sd, int flag) memcpy(WFIFOP(char_fd,13), &sd->status, sizeof(sd->status)); WFIFOSET(char_fd, WFIFOW(char_fd,2)); + + if(sd->status.pet_id > 0 && sd->pd) + intif_save_petdata(sd->status.account_id,&sd->pd->pet); + if (sd->hd && merc_is_hom_active(sd->hd)) merc_save(sd->hd); - if (flag) - sd->state.finalsave = 1; //Mark the last save as done. return 0; } @@ -271,40 +347,38 @@ int chrif_removemap(int fd) } // received after a character has been "final saved" on the char-server -int chrif_save_ack(int fd) +static void chrif_save_ack(int fd) { - map_quit_ack(RFIFOL(fd,2), RFIFOL(fd,6)); - return 0; + chrif_auth_delete(RFIFOL(fd,2), RFIFOL(fd,6), ST_LOGOUT); } // request to move a character between mapservers -int chrif_changemapserver(struct map_session_data* sd, short map, int x, int y, uint32 ip, uint16 port) +int chrif_changemapserver(struct map_session_data* sd, uint32 ip, uint16 port) { nullpo_retr(-1, sd); - chrif_check(-1); - if (other_mapserver_count < 1) { //No other map servers are online! clif_authfail_fd(sd->fd, 0); return -1; } + chrif_check(-1); + WFIFOHEAD(char_fd,35); WFIFOW(char_fd, 0) = 0x2b05; WFIFOL(char_fd, 2) = sd->bl.id; WFIFOL(char_fd, 6) = sd->login_id1; WFIFOL(char_fd,10) = sd->login_id2; WFIFOL(char_fd,14) = sd->status.char_id; - WFIFOW(char_fd,18) = map; - WFIFOW(char_fd,20) = x; - WFIFOW(char_fd,22) = y; + WFIFOW(char_fd,18) = sd->mapindex; + WFIFOW(char_fd,20) = sd->bl.x; + WFIFOW(char_fd,22) = sd->bl.y; WFIFOL(char_fd,24) = htonl(ip); WFIFOW(char_fd,28) = htons(port); WFIFOB(char_fd,30) = sd->status.sex; WFIFOL(char_fd,31) = 0; // sd's IP, not used anymore WFIFOSET(char_fd,35); - return 0; } @@ -312,23 +386,18 @@ int chrif_changemapserver(struct map_session_data* sd, short map, int x, int y, /// R 2b06 .L .L .L .L .W .W .W .L .W int chrif_changemapserverack(int account_id, int login_id1, int login_id2, int char_id, short map_index, short x, short y, uint32 ip, uint16 port) { - struct map_session_data *sd; - sd = map_id2sd(account_id); - - if (sd == NULL || sd->status.char_id != char_id) + struct auth_node *node; + if (!(node=chrif_auth_check(account_id, char_id, ST_MAPCHANGE))) return -1; - if (login_id1 == 1) { //FIXME: charserver says '0'! [ultramage] + if (!login_id1) { ShowError("map server change failed.\n"); - clif_authfail_fd(sd->fd, 0); - return 0; - } - - clif_changemapserver(sd, map_index, x, y, ntohl(ip), ntohs(port)); + clif_authfail_fd(node->fd, 0); + } else + clif_changemapserver(node->sd, map_index, x, y, ntohl(ip), ntohs(port)); - //Player has been saved already, remove him from memory. [Skotlex] - map_quit(sd); - map_quit_ack(sd->status.account_id, sd->status.char_id); + //Player has been saved already, remove him from memory. [Skotlex] + chrif_auth_delete(account_id, char_id, ST_MAPCHANGE); return 0; } @@ -359,6 +428,36 @@ int chrif_connectack(int fd) return 0; } +static int chrif_reconnect(DBKey key,void *data,va_list ap) +{ + struct auth_node *node=(struct auth_node*)data; + switch (node->state) { + case ST_LOGIN: + if (node->sd && node->char_dat == NULL) + { //Since there is no way to request the char auth, make it fail. + pc_authfail(node->sd); + chrif_char_offline(node->sd); + chrif_auth_delete(node->account_id, node->char_id, ST_LOGIN); + } + break; + case ST_LOGOUT: + //Re-send final save + chrif_save(node->sd, 1); + break; + case ST_MAPCHANGE: + { //Re-send map-change request. + struct map_session_data *sd = node->sd; + uint32 ip; + uint16 port; + if(map_mapname2ipport(sd->mapindex,&ip,&port)==0) + chrif_changemapserver(sd, ip, port); + else //too much lag/timeout is the closest explanation for this error. + clif_authfail_fd(sd->fd, 3); + break; + } + } + return 0; +} /*========================================== * @@ -378,7 +477,7 @@ int chrif_sendmapack(int fd) send_users_tochar(); //Re-save any storages that were modified in the disconnection time. [Skotlex] - do_reconnect_map(); + auth_db->foreach(auth_db,chrif_reconnect); do_reconnect_storage(); return 0; @@ -406,30 +505,31 @@ int chrif_scdata_request(int account_id, int char_id) *------------------------------------------*/ void chrif_authreq(struct map_session_data *sd) { - struct auth_node *auth_data; - auth_data=idb_get(auth_db, sd->bl.id); - - if(auth_data) { - if(auth_data->char_dat && - auth_data->account_id== sd->bl.id && - auth_data->login_id1 == sd->login_id1) - { //auth ok - pc_authok(sd, auth_data->login_id2, auth_data->connect_until_time, auth_data->char_dat); - } else { //auth failed - pc_authfail(sd); - chrif_char_offline(sd); //Set him offline, the char server likely has it set as online already. + struct auth_node *node= chrif_search(sd->bl.id); + + if(!node) { + //data from char server has not arrived yet. + chrif_sd_to_auth(sd, ST_LOGIN); + return; + } + + if(node->state == ST_LOGIN && + node->char_dat && + node->account_id== sd->status.account_id && + node->login_id1 == sd->login_id1) + { //auth ok + if (!pc_authok(sd, node->login_id2, node->connect_until_time, node->char_dat)) + chrif_auth_delete(sd->status.account_id, sd->status.char_id, ST_LOGIN); + else { + //char_dat no longer needed, but player auth is not completed yet. + aFree(node->char_dat); + node->char_dat = NULL; + node->sd = sd; } - if (auth_data->char_dat) - aFree(auth_data->char_dat); - idb_remove(auth_db, sd->bl.id); - } else { //data from char server has not arrived yet. - auth_data = aCalloc(1,sizeof(struct auth_node)); - auth_data->sd = sd; - auth_data->fd = sd->fd; - auth_data->account_id = sd->bl.id; - auth_data->login_id1 = sd->login_id1; - auth_data->node_created = gettick(); - idb_put(auth_db, sd->bl.id, auth_data); + } else { //auth failed + pc_authfail(sd); + chrif_char_offline(sd); //Set him offline, the char server likely has it set as online already. + chrif_auth_delete(sd->status.account_id, sd->status.char_id, ST_LOGIN); } return; } @@ -437,65 +537,69 @@ void chrif_authreq(struct map_session_data *sd) //character selected, insert into auth db void chrif_authok(int fd) { - struct auth_node *auth_data; + struct auth_node *node; + int account_id = RFIFOL(fd, 4); + struct mmo_charstatus *status = (struct mmo_charstatus *)RFIFOP(fd, 20); + int char_id = status->char_id; TBL_PC* sd; //Check if we don't already have player data in our server - //(prevents data that is to be saved from being overwritten by - //this received status data if this auth is later successful) [Skotlex] - if ((sd = map_id2sd(RFIFOL(fd, 4))) != NULL) - { - struct mmo_charstatus *status = (struct mmo_charstatus *)RFIFOP(fd, 20); - //Auth check is because this could be the very same sd that is waiting char-server authorization. - if (sd->state.auth && sd->status.char_id == status->char_id) - return; - } + //Causes problems if the currently connected player tries to quit or this data belongs to an already connected player which is trying to re-auth. + if ((sd = map_id2sd(account_id)) != NULL) + return; - if ((auth_data =idb_get(auth_db, RFIFOL(fd, 4))) != NULL) + if ((node = chrif_search(account_id))) { //Is the character already awaiting authorization? - if (auth_data->sd) + if (node->state == ST_LOGIN && node->sd) { - //First, check to see if the session data still exists (avoid dangling pointers) - if(session[auth_data->fd] && session[auth_data->fd]->session_data == auth_data->sd) - { - if (auth_data->char_dat == NULL && - auth_data->account_id == RFIFOL(fd, 4) && - auth_data->login_id1 == RFIFOL(fd, 8)) - { //Auth Ok - pc_authok(auth_data->sd, RFIFOL(fd, 16), RFIFOL(fd, 12), (struct mmo_charstatus*)RFIFOP(fd, 20)); - } else { //Auth Failed - pc_authfail(auth_data->sd); - chrif_char_offline(auth_data->sd); //Set him offline, the char server likely has it set as online already. - } - } //else: Character no longer exists, just go through. + sd = node->sd; + if(node->char_dat == NULL && + node->account_id == account_id && + node->char_id == char_id && + node->login_id1 == RFIFOL(fd, 8)) + { //Auth Ok + if (!pc_authok(sd, RFIFOL(fd, 16), RFIFOL(fd, 12), status)) + chrif_auth_delete(account_id, char_id, ST_LOGIN); + } else { //Auth Failed + pc_authfail(sd); + chrif_char_offline(sd); //Set him offline, the char server likely has it set as online already. + chrif_auth_delete(account_id, char_id, ST_LOGIN); + } } - //Delete the data of this node... - if (auth_data->char_dat) - aFree (auth_data->char_dat); - idb_remove(auth_db, RFIFOL(fd, 4)); + //Otherwise discard the entry received as we already have information. return; } - // Awaiting for client to connect. - auth_data = (struct auth_node *)aCalloc(1,sizeof(struct auth_node)); - auth_data->char_dat = (struct mmo_charstatus *) aMalloc(sizeof(struct mmo_charstatus)); - auth_data->account_id=RFIFOL(fd, 4); - auth_data->login_id1=RFIFOL(fd, 8); - auth_data->connect_until_time=RFIFOL(fd, 12); - auth_data->login_id2=RFIFOL(fd, 16); - memcpy(auth_data->char_dat,RFIFOP(fd, 20),sizeof(struct mmo_charstatus)); - auth_data->node_created=gettick(); - idb_put(auth_db, RFIFOL(fd, 4), auth_data); + // Awaiting for client to connect. + node = ers_alloc(auth_db_ers, struct auth_node); + memset(node, 0, sizeof(struct auth_node)); + node->char_dat = (struct mmo_charstatus *) aMalloc(sizeof(struct mmo_charstatus)); + + node->account_id=account_id; + node->char_id=char_id; + node->login_id1=RFIFOL(fd, 8); + node->connect_until_time=RFIFOL(fd, 12); + node->login_id2=RFIFOL(fd, 16); + memcpy(node->char_dat,status,sizeof(struct mmo_charstatus)); + node->node_created=gettick(); + idb_put(auth_db, account_id, node); } int auth_db_cleanup_sub(DBKey key,void *data,va_list ap) { struct auth_node *node=(struct auth_node*)data; - if(DIFF_TICK(gettick(),node->node_created)>30000) { - ShowNotice("Character (aid: %d) not authed within 30 seconds of character select!\n", node->account_id); - if (node->char_dat) - aFree(node->char_dat); - db_remove(auth_db, key); + if(DIFF_TICK(gettick(),node->node_created)>60000) { + switch (node->state) + { + case ST_LOGOUT: + //Re-save attempt (->sd should never be null here). + chrif_save(node->sd, 1); + break; + default: + //Clear data. any connected players should have timed out by now. + chrif_auth_delete(node->account_id, node->char_id, node->state); + break; + } return 1; } return 0; @@ -503,11 +607,11 @@ int auth_db_cleanup_sub(DBKey key,void *data,va_list ap) int auth_db_cleanup(int tid, unsigned int tick, int id, int data) { + if(!chrif_isconnected()) return 0; auth_db->foreach(auth_db, auth_db_cleanup_sub); return 0; } - /*========================================== * *------------------------------------------*/ @@ -1010,9 +1114,6 @@ int chrif_save_scdata(struct map_session_data *sd) struct status_change *sc = &sd->sc; const struct TimerData *timer; - if (sd->state.finalsave) //Character was already saved? - return -1; - chrif_check(-1); tick = gettick(); @@ -1428,6 +1529,9 @@ int auth_db_final(DBKey k,void *d,va_list ap) struct auth_node *node=(struct auth_node*)d; if (node->char_dat) aFree(node->char_dat); + if (node->sd) + aFree(node->sd); + ers_free(auth_db_ers, node); return 0; } @@ -1438,7 +1542,9 @@ int do_final_chrif(void) { if (char_fd > 0) do_close(char_fd); + auth_db->destroy(auth_db, auth_db_final); + ers_destroy(auth_db_ers); return 0; } @@ -1447,7 +1553,8 @@ int do_final_chrif(void) *------------------------------------------*/ int do_init_chrif(void) { - auth_db = idb_alloc(DB_OPT_RELEASE_DATA); + auth_db = idb_alloc(DB_OPT_BASE); + auth_db_ers = ers_new(sizeof(struct auth_node)); add_timer_func_list(check_connect_char_server, "check_connect_char_server"); add_timer_func_list(ping_char_server, "ping_char_server"); diff --git a/src/map/chrif.h b/src/map/chrif.h index b440fcac6..bf1dbb108 100644 --- a/src/map/chrif.h +++ b/src/map/chrif.h @@ -7,12 +7,15 @@ #include "../common/cbasetypes.h" #include -struct auth_node{ - int account_id, login_id1, login_id2, sex, fd; +enum sd_state { ST_LOGIN, ST_LOGOUT, ST_MAPCHANGE }; +struct auth_node { + int account_id, char_id; + int login_id1, login_id2, sex, fd; time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) struct map_session_data *sd; //Data from logged on char. struct mmo_charstatus *char_dat; //Data from char server. - unsigned int node_created; //For node auto-deleting + unsigned int node_created; //timestamp for node timeouts + enum sd_state state; //To track whether player was login in/out or changing maps. }; void chrif_setuserid(char* id); @@ -26,12 +29,17 @@ int chrif_isconnected(void); extern int chrif_connected; extern int other_mapserver_count; +struct auth_node* chrif_search(int account_id); +struct auth_node* chrif_auth_check(int account_id, int char_id, enum sd_state state); +bool chrif_auth_delete(int account_id, int char_id, enum sd_state state); +bool chrif_auth_finished(struct map_session_data* sd); + void chrif_authreq(struct map_session_data* sd); void chrif_authok(int fd); int chrif_scdata_request(int account_id, int char_id); int chrif_save(struct map_session_data* sd, int flag); int chrif_charselectreq(struct map_session_data* sd, uint32 s_ip); -int chrif_changemapserver(struct map_session_data* sd, short map, int x, int y, uint32 ip, uint16 port); +int chrif_changemapserver(struct map_session_data* sd, uint32 ip, uint16 port); int chrif_searchcharid(int char_id); int chrif_changegm(int id,const char *pass,int len); diff --git a/src/map/clif.c b/src/map/clif.c index ed5e46bbd..5d6daaa26 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -175,7 +175,7 @@ int clif_countusers(void) for(i = 0; i < fd_max; i++) { if (session[i] && session[i]->func_parse == clif_parse && (sd = (struct map_session_data*)session[i]->session_data) && - sd->state.auth && !(battle_config.hide_GM_session && pc_isGM(sd))) + sd->state.active && !(battle_config.hide_GM_session && pc_isGM(sd))) users++; } return users; @@ -195,7 +195,7 @@ int clif_foreachclient(int (*func)(struct map_session_data*, va_list),...) //rec for(i = 0; i < fd_max; i++) { if ( session[i] && session[i]->func_parse == clif_parse) { sd = (struct map_session_data*)session[i]->session_data; - if ( sd && sd->state.auth && !sd->state.waitingdisconnect ) + if ( sd && sd->state.active ) func(sd, ap); } } @@ -246,20 +246,23 @@ int clif_send_sub(struct block_list *bl, va_list ap) break; } - if (session[fd] != NULL) { - WFIFOHEAD(fd, len); - if (WFIFOP(fd,0) == buf) { - ShowError("WARNING: Invalid use of clif_send function\n"); - ShowError(" Packet x%4x use a WFIFO of a player instead of to use a buffer.\n", WBUFW(buf,0)); - ShowError(" Please correct your code.\n"); - // don't send to not move the pointer of the packet for next sessions in the loop - WFIFOSET(fd,0);//## TODO is this ok? - } else { - if (packet_db[sd->packet_ver][RBUFW(buf,0)].len) { // packet must exist for the client version - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - } - } + if (session[fd] == NULL) + return 0; + + WFIFOHEAD(fd, len); + if (WFIFOP(fd,0) == buf) { + ShowError("WARNING: Invalid use of clif_send function\n"); + ShowError(" Packet x%4x use a WFIFO of a player instead of to use a buffer.\n", WBUFW(buf,0)); + ShowError(" Please correct your code.\n"); + // don't send to not move the pointer of the packet for next sessions in the loop + //WFIFOSET(fd,0);//## TODO is this ok? + //NO. It is not ok. There is the chance WFIFOSET actually sends the buffer data, and shifts elements around, which will corrupt the buffer. + return 0; + } + + if (packet_db[sd->packet_ver][RBUFW(buf,0)].len) { // packet must exist for the client version + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); } return 0; @@ -285,13 +288,13 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target case ALL_CLIENT: //All player clients. for (i = 0; i < fd_max; i++) { if (session[i] && session[i]->func_parse == clif_parse && - (sd = (struct map_session_data *)session[i]->session_data) != NULL&& - sd->state.auth) { - if (packet_db[sd->packet_ver][RBUFW(buf,0)].len) { // packet must exist for the client version - WFIFOHEAD(i, len); - memcpy(WFIFOP(i,0), buf, len); - WFIFOSET(i,len); - } + (sd = (struct map_session_data *)session[i]->session_data) != NULL && + sd->state.active && + packet_db[sd->packet_ver][RBUFW(buf,0)].len) + { // packet must exist for the client version + WFIFOHEAD(i, len); + memcpy(WFIFOP(i,0), buf, len); + WFIFOSET(i,len); } } break; @@ -299,12 +302,12 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target for(i = 0; i < fd_max; i++) { if (session[i] && session[i]->func_parse == clif_parse && (sd = (struct map_session_data*)session[i]->session_data) != NULL && - sd->state.auth && sd->bl.m == bl->m) { - if (packet_db[sd->packet_ver][RBUFW(buf,0)].len) { // packet must exist for the client version - WFIFOHEAD(i,len); - memcpy(WFIFOP(i,0), buf, len); - WFIFOSET(i,len); - } + sd->state.active && sd->bl.m == bl->m && + packet_db[sd->packet_ver][RBUFW(buf,0)].len) + { // packet must exist for the client version + WFIFOHEAD(i,len); + memcpy(WFIFOP(i,0), buf, len); + WFIFOSET(i,len); } } break; @@ -350,11 +353,11 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target for(i=1; ifunc_parse == clif_parse && (sd = (struct map_session_data*)session[i]->session_data) != NULL && - sd->state.mainchat && !sd->chatID && (fd=sd->fd)) + sd->state.active && sd->state.mainchat && !sd->chatID) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd, len); + WFIFOHEAD(i,len); + memcpy(WFIFOP(i,0), buf, len); + WFIFOSET(i, len); } } break; @@ -376,12 +379,9 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target if( (sd = p->data[i].sd) == NULL ) continue; - if( !(fd=sd->fd) || fd <= 0 || fd >= fd_max ) + if( !(fd=sd->fd) ) continue; - if( session[fd] == NULL || sd->state.auth == 0 || session[fd]->session_data == NULL || sd->packet_ver > MAX_PACKET_VER ) - continue; - if( sd->bl.id == bl->id && (type == PARTY_WOS || type == PARTY_SAMEMAP_WOS || type == PARTY_AREA_WOS) ) continue; @@ -404,13 +404,12 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target if (session[i] && session[i]->func_parse == clif_parse && (sd = (struct map_session_data*)session[i]->session_data) != NULL && - sd->state.auth && (fd=sd->fd) && sd->partyspy == p->party.party_id) - { - if (packet_db[sd->packet_ver][RBUFW(buf,0)].len) { // packet must exist for the client version - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - } + sd->state.active && sd->partyspy == p->party.party_id && + packet_db[sd->packet_ver][RBUFW(buf,0)].len) + { // packet must exist for the client version + WFIFOHEAD(i,len); + memcpy(WFIFOP(i,0), buf, len); + WFIFOSET(i,len); } } } @@ -423,7 +422,7 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target for (i = 0; i < fd_max; i++) { if (session[i] && session[i]->func_parse == clif_parse && (sd = (struct map_session_data *)session[i]->session_data) != NULL && - sd->state.auth && sd->duel_group == x0) { + sd->state.active && sd->duel_group == x0) { if (type == DUEL_WOS && bl->id == sd->bl.id) continue; if (packet_db[sd->packet_ver][RBUFW(buf,0)].len) { @@ -460,10 +459,7 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target for(i = 0; i < g->max_member; i++) { if( (sd = g->member[i].sd) != NULL ) { - if( !(fd=sd->fd) || fd <= 0 || fd >= fd_max ) - continue; - - if( session[fd] == NULL || sd->state.auth == 0 || session[fd]->session_data == NULL || sd->packet_ver > MAX_PACKET_VER ) + if( !(fd=sd->fd) ) continue; if( sd->bl.id == bl->id && (type == GUILD_WOS || type == GUILD_SAMEMAP_WOS || type == GUILD_AREA_WOS) ) @@ -488,12 +484,12 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target for (i = 1; i < fd_max; i++){ // guildspy [Syrus22] if (session[i] && session[i]->func_parse == clif_parse && (sd = (struct map_session_data*)session[i]->session_data) != NULL && - sd->state.auth && (fd=sd->fd) && sd->guildspy == g->guild_id) { - if (packet_db[sd->packet_ver][RBUFW(buf,0)].len) { // packet must exist for the client version - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - } + sd->state.active && sd->guildspy == g->guild_id && + packet_db[sd->packet_ver][RBUFW(buf,0)].len) + { // packet must exist for the client version + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); } } } @@ -541,6 +537,7 @@ int clif_authok(struct map_session_data *sd) * 3 - timeout/too much lag -> MsgStringTable[241] * 4 - server full -> MsgStringTable[264] * 5 - underaged -> MsgStringTable[305] + * 8 - Server sill recognizes last connection -> MsgStringTable[441] * 9 - too many connections from this ip -> MsgStringTable[529] * 10 - out of available time paid for -> MsgStringTable[530] * 15 - disconnected by a GM -> if( servicetype == taiwan ) MsgStringTable[579] @@ -1038,7 +1035,7 @@ int clif_weather(int m) for(i = 0; i < fd_max; i++) { if (session[i] && session[i]->func_parse == clif_parse && (sd = session[i]->session_data) != NULL && - sd->state.auth && sd->bl.m == m) { + sd->state.active && sd->bl.m == m) { clif_weather_check(sd); } } @@ -1327,8 +1324,7 @@ static int clif_delayquit(int tid, unsigned int tick, int id, int data) *------------------------------------------*/ void clif_quitsave(int fd,struct map_session_data *sd) { - if (sd->state.waitingdisconnect || //Was already waiting to be disconnected. - !battle_config.prevent_logout || + if (!battle_config.prevent_logout || DIFF_TICK(gettick(), sd->canlog_tick) > battle_config.prevent_logout) map_quit(sd); else if (sd->fd) @@ -1356,10 +1352,9 @@ static int clif_waitclose(int tid, unsigned int tick, int id, int data) *------------------------------------------*/ void clif_setwaitclose(int fd) { - struct map_session_data *sd; // if player is not already in the game (double connection probably) - if ((sd = (struct map_session_data*)session[fd]->session_data) == NULL) { + if (session[fd]->session_data == NULL) { // limited timer, just to send information. add_timer(gettick() + 1000, clif_waitclose, fd, 0); } else @@ -3775,7 +3770,7 @@ void clif_01ac(struct block_list* bl) sd=va_arg(ap,struct map_session_data*); - if (sd == NULL || !sd->fd || session[sd->fd] == NULL) + if (sd == NULL || !sd->fd) return 0; switch(bl->type){ @@ -5614,7 +5609,7 @@ int clif_hpmeter(struct map_session_data *sd) for (i = 0; i < fd_max; i++) { if (session[i] && session[i]->func_parse == clif_parse && (sd2 = (struct map_session_data*)session[i]->session_data) && - sd != sd2 && sd2->state.auth) { + sd != sd2 && sd2->state.active) { if (sd2->bl.m != sd->bl.m || sd2->bl.x < x0 || sd2->bl.y < y0 || sd2->bl.x > x1 || sd2->bl.y > y1 || @@ -7616,12 +7611,14 @@ static int clif_guess_PacketVer(int fd, int get_previous, int *error) *------------------------------------------*/ void clif_parse_WantToConnection(int fd, TBL_PC* sd) { + struct block_list* bl; + struct auth_node* node; int cmd, account_id, char_id, login_id1, sex; unsigned int client_tick; //The client tick is a tick, therefore it needs be unsigned. [Skotlex] int packet_ver; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) if (sd) { - ShowError("clif_parse_WantToConnection : invalid request (character already logged in)?\n"); + ShowError("clif_parse_WantToConnection : invalid request (character already logged in)\n"); return; } @@ -7646,13 +7643,12 @@ void clif_parse_WantToConnection(int fd, TBL_PC* sd) WFIFOSET(fd,packet_len(0x6a)); clif_setwaitclose(fd); return; - } else if( map_knowsaccount(account_id) ) - {// double login - sd = map_id2sd(account_id); - if( sd && sd->state.autotrade ) - map_quit(sd);// kick autotrading character - else - ShowError("clif_parse_WantToConnection: double login attempt AID/CID: %d/%d, rejecting...\n", account_id, char_id); + } + + //Check for double login. + bl = map_id2bl(account_id); + if(bl && bl->type != BL_PC) { + ShowError("clif_parse_WantToConnection: a non-player object already has id %d, please increase the starting account number\n", account_id); WFIFOHEAD(fd,packet_len(0x6a)); WFIFOW(fd,0) = 0x6a; WFIFOB(fd,2) = 3; // Rejected by server @@ -7660,19 +7656,22 @@ void clif_parse_WantToConnection(int fd, TBL_PC* sd) clif_setwaitclose(fd); return; } - else - {// packet version accepted - struct block_list* bl; - if( (bl=map_id2bl(account_id)) != NULL && bl->type != BL_PC ) - {// non-player object already has that id - ShowError("clif_parse_WantToConnection: a non-player object already has id %d, please increase the starting account number\n", account_id); - WFIFOHEAD(fd,packet_len(0x6a)); - WFIFOW(fd,0) = 0x6a; - WFIFOB(fd,2) = 3; // Rejected by server - WFIFOSET(fd,packet_len(0x6a)); - clif_setwaitclose(fd); - return; - } + + if (bl || + ((node=chrif_search(account_id)) && //An already existing node is valid only if it is for this login. + !(node->account_id == account_id && node->char_id == char_id && node->state == ST_LOGIN))) { + sd = BL_CAST(BL_PC, bl); + if (!sd) + ; //We have another char with the same account logging in/out. + else //Already connected player. + if (sd->fd) + clif_authfail_fd(sd->fd, 2); //someone else logged in + else + if(sd->state.autotrade) + map_quit(sd);// kick autotrading character + //Else do not kick character, it could be on its 10 sec penalty for Alt+F4 + clif_authfail_fd(fd, 8); //Still recognizes last connection + return; } CREATE(sd, TBL_PC, 1); @@ -7706,7 +7705,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) if(sd->bl.prev != NULL) return; - if (!sd->state.auth) + if (!sd->state.active) { //Character loading is not complete yet! //Let pc_reg_received reinvoke this when ready. sd->state.connect_new = 0; @@ -11652,12 +11651,13 @@ int clif_parse(int fd) sd->fd = 0; ShowInfo("%sCharacter '"CL_WHITE"%s"CL_RESET"' logged off (using @autotrade).\n", (pc_isGM(sd))?"GM ":"", sd->status.name); } else - if (sd->state.auth) { + if (sd->state.active) { // Player logout display [Valaris] ShowInfo("%sCharacter '"CL_WHITE"%s"CL_RESET"' logged off.\n", (pc_isGM(sd))?"GM ":"", sd->status.name); clif_quitsave(fd, sd); } else { - ShowInfo("Player AID:%d/CID:%d (not authenticated) logged off.\n", sd->bl.id, sd->status.char_id); + //Unusual logout (during log on/off/map-changer procedure) + ShowInfo("Player AID:%d/CID:%d logged off.\n", sd->status.account_id, sd->status.char_id); map_quit(sd); } } else { @@ -11723,17 +11723,14 @@ int clif_parse(int fd) if ((int)RFIFOREST(fd) < packet_len) return 0; // not enough data received to form the packet - if (sd && sd->state.waitingdisconnect == 1) { - // 切断待ちの場合パケットを処理しない - } else if (packet_db[packet_ver][cmd].func) { if (sd && sd->bl.prev == NULL && packet_db[packet_ver][cmd].func != clif_parse_LoadEndAck) ; //Only valid packet when player is not on a map is the finish-loading packet. else - if (sd + if ((sd && sd->state.active) || packet_db[packet_ver][cmd].func == clif_parse_WantToConnection || packet_db[packet_ver][cmd].func == clif_parse_debug - ) //Only execute the function when there's an sd (except for debug/wanttoconnect packets) + ) //Only execute the function when there's an active sd (except for debug/wanttoconnect packets) packet_db[packet_ver][cmd].func(fd, sd); } #if DUMP_UNKNOWN_PACKET @@ -11750,7 +11747,7 @@ int clif_parse(int fd) return 1; } else { time(&now); - if (sd && sd->state.auth) { + if (sd && sd->state.active) { fprintf(fp, "%sPlayer with account ID %d (character ID %d, player name %s) sent wrong packet:\n", asctime(localtime(&now)), sd->status.account_id, sd->status.char_id, sd->status.name); } else if (sd) // not authentified! (refused by char-server or disconnect before to be authentified) @@ -11779,7 +11776,7 @@ int clif_parse(int fd) ShowMessage("%02X ", RFIFOB(fd,i)); } ShowMessage("\n"); - if (sd && sd->state.auth) { + if (sd && sd->state.active) { if (sd->status.name != NULL) ShowMessage("\nAccount ID %d, character ID %d, player name %s.\n", sd->status.account_id, sd->status.char_id, sd->status.name); diff --git a/src/map/guild.c b/src/map/guild.c index e591fc838..5644793b2 100644 --- a/src/map/guild.c +++ b/src/map/guild.c @@ -76,7 +76,7 @@ static TBL_PC* guild_sd_check(int guild_id, int account_id, int char_id) { TBL_PC* sd = map_id2sd(account_id); - if (!(sd && sd->status.char_id == char_id && sd->state.auth && !sd->state.waitingdisconnect)) + if (!(sd && sd->status.char_id == char_id)) return NULL; if (sd->status.guild_id != guild_id) @@ -431,7 +431,6 @@ int guild_created(int account_id,int guild_id) } //struct guild *g; sd->status.guild_id=guild_id; - sd->state.guild_sent=0; clif_guild_created(sd,0); if(battle_config.guild_emperium_check) pc_delitem(sd,pc_search_inventory(sd,714),1,0); // エンペリウム消耗 @@ -485,7 +484,6 @@ int guild_check_member(struct guild *g) i = guild_getindex(g,sd->status.account_id,sd->status.char_id); if (i < 0) { sd->status.guild_id=0; - sd->state.guild_sent=0; sd->guild_emblem_id=0; ShowWarning("guild: check_member %d[%s] is not member\n",sd->status.account_id,sd->status.name); } @@ -519,10 +517,12 @@ int guild_recv_info(struct guild *sg) int i,bm,m; struct eventlist *ev,*ev2; struct map_session_data *sd; + bool guild_new = false; nullpo_retr(0, sg); if((g=idb_get(guild_db,sg->guild_id))==NULL){ + guild_new = true; g=(struct guild *)aCalloc(1,sizeof(struct guild)); idb_put(guild_db,sg->guild_id,g); before=*sg; @@ -538,7 +538,8 @@ int guild_recv_info(struct guild *sg) //Also set the guild master flag. sd->state.gmaster_flag = g; - clif_charnameupdate(sd); // [LuzZza] + clif_charnameupdate(sd); // [LuzZza] + clif_guild_masterormember(sd); } }else before=*g; @@ -579,11 +580,10 @@ int guild_recv_info(struct guild *sg) if( before.skill_point!=g->skill_point) clif_guild_skillinfo(sd); // スキル情報送信 - if( sd->state.guild_sent==0){ // 未送信なら所属情報も送る + if( guild_new ){ // 未送信なら所属情報も送る clif_guild_belonginfo(sd,g); clif_guild_notice(sd,g); sd->guild_emblem_id=g->emblem_id; - sd->state.guild_sent=1; } } @@ -702,6 +702,34 @@ int guild_reply_invite(struct map_session_data* sd, int guild_id, int flag) return 0; } + +//Invoked when a player joins. +//- If guild is not in memory, it is requested +//- Otherwise sd pointer is set up. +//- Player must be authed and must belong to a guild before invoking this method +void guild_member_joined(struct map_session_data *sd) +{ + struct guild* g; + int i; + g=guild_search(sd->status.guild_id); + if (!g) { + guild_request_info(sd->status.guild_id); + return; + } + if (strcmp(sd->status.name,g->master) == 0) + { // set the Guild Master flag + sd->state.gmaster_flag = g; + // prevent Guild Skills from being used directly after relog + if( battle_config.guild_skill_relog_delay ) + guild_block_skill(sd, 300000); + } + i = guild_getindex(g, sd->status.account_id, sd->status.char_id); + if (i == -1) + sd->status.guild_id = 0; + else + g->member[i].sd = sd; +} + // ギルドメンバが追加された int guild_member_added(int guild_id,int account_id,int char_id,int flag) { @@ -730,9 +758,12 @@ int guild_member_added(int guild_id,int account_id,int char_id,int flag) } // 成功 - sd->state.guild_sent = 0; sd->status.guild_id = g->guild_id; sd->guild_emblem_id = g->emblem_id; + //Packets which were sent in the previous 'guild_sent' implementation. + clif_guild_belonginfo(sd,g); + clif_guild_notice(sd,g); + //TODO: send new emblem info to others if( sd2!=NULL ) @@ -836,7 +867,6 @@ int guild_member_leaved(int guild_id, int account_id, int char_id, int flag, con sd->status.guild_id = 0; sd->guild_emblem_id = 0; - sd->state.guild_sent = 0; clif_charnameupdate(sd); //Update display name [Skotlex] //TODO: send emblem update to self and people around @@ -850,14 +880,10 @@ int guild_send_memberinfoshort(struct map_session_data *sd,int online) nullpo_retr(0, sd); - if(!(g = guild_search(sd->status.guild_id))) + if(sd->status.guild_id <= 0) return 0; - //Moved to place before intif_guild_memberinfoshort because - //If it's not a member, needn't send it's info to intif. [LuzZza] - guild_check_member(g); - - if(sd->status.guild_id <= 0) + if(!(g = guild_search(sd->status.guild_id))) return 0; intif_guild_memberinfoshort(g->guild_id, @@ -872,15 +898,12 @@ int guild_send_memberinfoshort(struct map_session_data *sd,int online) return 0; } - if(sd->state.guild_sent) - return 0; - - clif_guild_belonginfo(sd,g); - clif_guild_notice(sd,g); - - sd->state.guild_sent = 1; - sd->guild_emblem_id = g->emblem_id; - + if(sd->state.connect_new) + { //Note that this works because it is invoked in parse_LoadEndAck before connect_new is cleared. + clif_guild_belonginfo(sd,g); + clif_guild_notice(sd,g); + sd->guild_emblem_id = g->emblem_id; + } return 0; } @@ -915,7 +938,6 @@ int guild_recv_memberinfoshort(int guild_id,int account_id,int char_id,int onlin if(sd && sd->status.char_id == char_id) { sd->status.guild_id=0; sd->guild_emblem_id=0; - sd->state.guild_sent=0; } ShowWarning("guild: not found member %d,%d on %d[%s]\n", account_id,char_id,guild_id,g->name); return 0; @@ -1535,7 +1557,6 @@ int guild_broken(int guild_id,int flag) if(sd->state.storage_flag == 2) storage_guild_storage_quit(sd,1); sd->status.guild_id=0; - sd->state.guild_sent=0; clif_guild_broken(g->member[i].sd,0); clif_charnameupdate(sd); // [LuzZza] } diff --git a/src/map/guild.h b/src/map/guild.h index 48dcdb550..1035818d9 100644 --- a/src/map/guild.h +++ b/src/map/guild.h @@ -42,6 +42,7 @@ int guild_recv_info(struct guild *sg); int guild_npc_request_info(int guild_id,const char *ev); int guild_invite(struct map_session_data *sd,struct map_session_data *tsd); int guild_reply_invite(struct map_session_data *sd,int guild_id,int flag); +void guild_member_joined(struct map_session_data *sd); int guild_member_added(int guild_id,int account_id,int char_id,int flag); int guild_leave(struct map_session_data *sd,int guild_id, int account_id,int char_id,const char *mes); diff --git a/src/map/intif.c b/src/map/intif.c index 3566e38c4..e04710218 100644 --- a/src/map/intif.c +++ b/src/map/intif.c @@ -919,12 +919,16 @@ int intif_parse_Registers(int fd) struct map_session_data *sd; struct global_reg *reg; int *qty; - - if( (sd=map_id2sd(RFIFOL(fd,4)))==NULL) - return 1; - - if (RFIFOB(fd,12) == 3 && sd->status.char_id != RFIFOL(fd,8)) - return 1; //Character registry from another character. + int account_id = RFIFOL(fd,4), char_id = RFIFOL(fd,8); + struct auth_node *node = chrif_auth_check(account_id, char_id, ST_LOGIN); + if (node) + sd = node->sd; + else { //Normally registries should arrive for in log-in chars. + sd = map_id2sd(account_id); + if (sd && RFIFOB(fd,12) == 3 && sd->status.char_id != char_id) + sd = NULL; //Character registry from another character. + } + if (!sd) return 1; flag = (sd->save_reg.global_num == -1 || sd->save_reg.account_num == -1 || sd->save_reg.account2_num == -1); @@ -975,9 +979,6 @@ int intif_parse_LoadStorage(int fd) return 1; } - if (sd->state.finalsave) - return 1; //Player is already scheduled to leave the server. - stor = account2storage( RFIFOL(fd,4)); if (stor->storage_status == 1) { // Already open.. lets ignore this update @@ -1434,9 +1435,6 @@ int intif_parse_Mail_inboxreceived(int fd) return 1; } - if (sd->state.finalsave) - return 1; - if (RFIFOW(fd,2) - 9 != sizeof(struct mail_data)) { ShowError("intif_parse_Mail_inboxreceived: data size error %d %d\n", RFIFOW(fd,2) - 9, sizeof(struct mail_data)); @@ -1502,9 +1500,6 @@ int intif_parse_Mail_getattach(int fd) return 1; } - if (sd->state.finalsave) - return 1; - if (RFIFOW(fd,2) - 12 != sizeof(struct item)) { ShowError("intif_parse_Mail_getattach: data size error %d %d\n", RFIFOW(fd,2) - 16, sizeof(struct item)); @@ -1546,9 +1541,6 @@ int intif_parse_Mail_delete(int fd) return 1; } - if (sd->state.finalsave) - return 1; - if (!failed) { int i; @@ -1595,9 +1587,6 @@ int intif_parse_Mail_return(int fd) return 1; } - if( sd->state.finalsave ) - return 1; - if( !fail ) { int i; diff --git a/src/map/mail.c b/src/map/mail.c index 5fef604c0..0640fa521 100644 --- a/src/map/mail.c +++ b/src/map/mail.c @@ -153,7 +153,7 @@ int mail_openmail(struct map_session_data *sd) { nullpo_retr(0,sd); - if( sd->state.finalsave == 1 || sd->state.storage_flag || sd->vender_id || sd->state.trading ) + if( sd->state.storage_flag || sd->vender_id || sd->state.trading ) return 0; clif_Mail_window(sd->fd, 0); diff --git a/src/map/map.c b/src/map/map.c index c02a896a9..78e67d3d4 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -102,7 +102,6 @@ static DBMap* mobid_db=NULL; // int id -> struct mob_data* static DBMap* map_db=NULL; // unsigned int mapindex -> struct map_data* static DBMap* nick_db=NULL; // int char_id -> struct charid2nick* (requested names of offline characters) static DBMap* charid_db=NULL; // int char_id -> struct map_session_data* -static DBMap* quit_db=NULL; // int account_id -> struct map_session_data* (players that are quitting or changing map-server) static int map_users=0; static struct block_list *objects[MAX_FLOORITEM]; @@ -1540,117 +1539,76 @@ void map_deliddb(struct block_list *bl) idb_remove(id_db,bl->id); } -/// Returns true if the map server knows the account (to reject logins). -bool map_knowsaccount(int account_id) -{ - return (map_id2sd(account_id) || idb_get(quit_db,account_id) ? true : false); -} - /*========================================== - * PCのquit?理 map.c?分 - * - * quit?理の主?が違うような?もしてきた + * Standard call when a player connection is closed. *------------------------------------------*/ int map_quit(struct map_session_data *sd) { - struct map_session_data* sd2; - if(!sd->state.auth) { //Removing a player that hasn't even finished loading - TBL_PC *sd2 = map_id2sd(sd->status.account_id); - if (sd->pd) unit_free(&sd->pd->bl,-1); - if (sd->hd) unit_free(&sd->hd->bl,-1); - //Double login, let original do the cleanups below. - if (sd2 && sd2 != sd) - return 0; - map_deliddb(&sd->bl); + if(!sd->state.active) { //Removing a player that is not active. + struct auth_node *node = chrif_search(sd->status.account_id); + if (node && node->char_id == sd->status.char_id && + node->state != ST_LOGOUT) + //Except when logging out, clear the auth-connect data immediately. + chrif_auth_delete(node->account_id, node->char_id, node->state); + //Non-active players should not have loaded any data yet (or it was cleared already) so no additional cleanups are needed. return 0; } - if(!sd->state.waitingdisconnect) { - if (sd->npc_timer_id != -1) //Cancel the event timer. - npc_timerevent_quit(sd); - - npc_script_event(sd, NPCE_LOGOUT); - sd->state.waitingdisconnect = 1; - if (sd->pd) unit_free(&sd->pd->bl,0); - if (sd->hd) unit_free(&sd->hd->bl,0); - unit_free(&sd->bl,3); - chrif_save(sd,1); - } else { //Try to free some data, without saving anything (this could be invoked on map server change. [Skotlex] - if (sd->bl.prev != NULL) - unit_remove_map(&sd->bl, 0); - if (sd->pd && sd->pd->bl.prev != NULL) - unit_remove_map(&sd->pd->bl, 0); - if (sd->hd && sd->hd->bl.prev != NULL) - unit_remove_map(&sd->hd->bl, 0); - } - - map_deliddb(&sd->bl); - if( (sd2=(struct map_session_data*)idb_put(quit_db, sd->status.account_id, sd)) ) - { - ShowDebug("map_quit: Possible double login AID/CID: %d/%d AID/CID: %d/%d\n", sd2->status.account_id, sd2->status.char_id, sd->status.account_id, sd->status.char_id); - aFree(sd2); - } - if(sd->reg) - { //Double logout already freed pointer fix... [Skotlex] - aFree(sd->reg); - sd->reg = NULL; - sd->reg_num = 0; - } - if(sd->regstr) - { - int i; - for( i = 0; i < sd->regstr_num; ++i ) - if( sd->regstr[i].data ) - aFree(sd->regstr[i].data); - aFree(sd->regstr); - sd->regstr = NULL; - sd->regstr_num = 0; - } - if (sd->st) { - if (sd->st->stack) - script_free_stack (sd->st->stack); - aFree(sd->st); - sd->st = NULL; - sd->npc_id = 0; - } - if(sd->fd) - { //Player will be free'd on save-ack. [Skotlex] - if (session[sd->fd]) - session[sd->fd]->session_data = NULL; - sd->fd = 0; - } - return 0; -} - -void map_quit_ack(int account_id, int char_id) -{ - struct map_session_data* sd = (struct map_session_data*)idb_get(quit_db,account_id); - if( sd ) - { - if( sd->status.char_id != char_id ) - ShowDebug("map_quit_ack: Possible double login AID/CID: %d/%d AID/CID: %d/%d\n", account_id, char_id, sd->status.account_id, sd->status.char_id); - else - idb_remove(quit_db,account_id); - } -} - -static int do_reconnect_map_sub(DBKey key,void *data,va_list va) -{ - struct map_session_data *sd = (TBL_PC*)data; - if (sd->state.finalsave) { - sd->state.finalsave = 0; - chrif_save(sd, 1); //Resend to save! - return 1; + if (sd->npc_timer_id != -1) //Cancel the event timer. + npc_timerevent_quit(sd); + + npc_script_event(sd, NPCE_LOGOUT); + + //Unit_free handles clearing the player related data, + //map_quit handles extra specific data which is related to quitting normally + //(changing map-servers invokes unit_free but bypasses map_quit) + if(sd->sc.count) { + //Status that are not saved... + if(sd->sc.data[SC_SPURT]) + status_change_end(&sd->bl,SC_SPURT,-1); + if(sd->sc.data[SC_BERSERK]) + status_change_end(&sd->bl,SC_BERSERK,-1); + if(sd->sc.data[SC_TRICKDEAD]) + status_change_end(&sd->bl,SC_TRICKDEAD,-1); + if(sd->sc.data[SC_GUILDAURA]) + status_change_end(&sd->bl,SC_GUILDAURA,-1); + if (battle_config.debuff_on_logout&1) { + if(sd->sc.data[SC_ORCISH]) + status_change_end(&sd->bl,SC_ORCISH,-1); + if(sd->sc.data[SC_STRIPWEAPON]) + status_change_end(&sd->bl,SC_STRIPWEAPON,-1); + if(sd->sc.data[SC_STRIPARMOR]) + status_change_end(&sd->bl,SC_STRIPARMOR,-1); + if(sd->sc.data[SC_STRIPSHIELD]) + status_change_end(&sd->bl,SC_STRIPSHIELD,-1); + if(sd->sc.data[SC_STRIPHELM]) + status_change_end(&sd->bl,SC_STRIPHELM,-1); + if(sd->sc.data[SC_EXTREMITYFIST]) + status_change_end(&sd->bl,SC_EXTREMITYFIST,-1); + if(sd->sc.data[SC_EXPLOSIONSPIRITS]) + status_change_end(&sd->bl,SC_EXPLOSIONSPIRITS,-1); + if(sd->sc.data[SC_REGENERATION] && sd->sc.data[SC_REGENERATION]->val4) + status_change_end(&sd->bl,SC_REGENERATION,-1); + } + if (battle_config.debuff_on_logout&2) + { + if(sd->sc.data[SC_MAXIMIZEPOWER]) + status_change_end(&sd->bl,SC_MAXIMIZEPOWER,-1); + if(sd->sc.data[SC_MAXOVERTHRUST]) + status_change_end(&sd->bl,SC_MAXOVERTHRUST,-1); + if(sd->sc.data[SC_STEELBODY]) + status_change_end(&sd->bl,SC_STEELBODY,-1); + } } + + unit_remove_map_pc(sd,3); + pc_makesavestatus(sd); + pc_clean_skilltree(sd); + chrif_save(sd,1); + unit_free_pc(sd); return 0; } -void do_reconnect_map(void) -{ - pc_db->foreach(pc_db,do_reconnect_map_sub); - pc_db->foreach(quit_db,do_reconnect_map_sub);//## FIXME possible loss of data [FlavioJS] -} - /*========================================== * id番?のPCを探す。居なければNULL *------------------------------------------*/ @@ -1765,15 +1723,6 @@ struct block_list * map_id2bl(int id) return bl; } -static int map_getallpc_sub(DBKey key,void * data,va_list ap) -{ - struct map_session_data *sd = (struct map_session_data*) data; - if (!sd->state.auth || sd->state.waitingdisconnect || sd->state.finalsave) - return 1; //Do not count in not-yet authenticated characters or ready to disconnect ones. - - return 0; -} - /*========================================== * Returns an array of all players in the server (includes non connected ones) [Skotlex] * The int pointer given returns the count of elements in the array. @@ -1805,7 +1754,7 @@ struct map_session_data** map_getallusers(int *users) RECREATE(all_sd, struct map_session_data*, all_count); } - *users = pc_db->getall(pc_db,(void**)all_sd,all_count,map_getallpc_sub); + *users = pc_db->getall(pc_db,(void**)all_sd,all_count,NULL); if (*users > (signed int)all_count) //Which should be impossible... *users = all_count; @@ -1857,8 +1806,7 @@ struct s_mapiterator /// @return true if it matches #define MAPIT_MATCHES(_mapit_,_bl_) \ ( \ - ( (_bl_)->type & (_mapit_)->types /* type matches */ ) && \ - ( (_bl_)->type != BL_PC /* not a pc */ || !((_mapit_)->flags & MAPIT_PCISPLAYING) /* any pc state */ || pc_isplaying((TBL_PC*)(_bl_)) /* pc is playing */ ) \ + ( (_bl_)->type & (_mapit_)->types /* type matches */ ) \ ) /// Allocates a new iterator. @@ -1874,7 +1822,6 @@ struct s_mapiterator* mapit_alloc(enum e_mapitflags flags, enum bl_type types) struct s_mapiterator* mapit; CREATE(mapit, struct s_mapiterator, 1); - if( !(types & BL_PC) && (flags & MAPIT_PCISPLAYING) ) flags ^= MAPIT_PCISPLAYING;// incompatible flag mapit->flags = flags; mapit->types = types; if( types == BL_PC ) mapit->dbi = db_iterator(pc_db); @@ -3127,19 +3074,6 @@ static int cleanup_db_sub(DBKey key,void *data,va_list va) return cleanup_sub((struct block_list*)data, NULL); } -static int cleanup_db_subpc(DBKey key,void *data,va_list va) -{ - struct map_session_data *sd = (TBL_PC*)data; - if (!sd->state.finalsave) - { //Error? - ShowError("do_final: Player character in DB which was not sent to save! %d:%d\n", sd->status.account_id, sd->status.char_id); - map_quit(sd); //Attempt force-save - } - //Force remove from memory... - map_quit_ack(sd->status.account_id, sd->status.char_id); - return 1; -} - /*========================================== * map鯖終了・理 *------------------------------------------*/ @@ -3164,9 +3098,6 @@ void do_final(void) id_db->foreach(id_db,cleanup_db_sub); chrif_char_reset_offline(); chrif_flush_fifo(); - //Online players were sent to save, but the ack will not arrive on time! - //They have to be removed from memory, and assume the char-server saved them. - pc_db->foreach(pc_db,cleanup_db_subpc); do_final_atcommand(); do_final_battle(); @@ -3210,7 +3141,6 @@ void do_final(void) mobid_db->destroy(mobid_db, NULL); nick_db->destroy(nick_db, nick_db_final); charid_db->destroy(charid_db, NULL); - db_destroy(quit_db); #ifndef TXT_ONLY map_sql_close(); @@ -3222,9 +3152,6 @@ static int map_abort_sub(DBKey key,void * data,va_list ap) { struct map_session_data *sd = (TBL_PC*)data; - if (!sd->state.auth || sd->state.waitingdisconnect || sd->state.finalsave) - return 0; - chrif_save(sd,1); return 1; } @@ -3389,7 +3316,6 @@ int do_init(int argc, char *argv[]) map_db = uidb_alloc(DB_OPT_BASE); nick_db = idb_alloc(DB_OPT_BASE); charid_db = idb_alloc(DB_OPT_BASE); - quit_db = idb_alloc(DB_OPT_RELEASE_DATA); #ifndef TXT_ONLY map_sql_init(); #endif /* not TXT_ONLY */ diff --git a/src/map/map.h b/src/map/map.h index 81b55bb7a..269319ab8 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -514,10 +514,9 @@ struct map_session_data { //NOTE: When deciding to add a flag to state or special_state, take into consideration that state is preserved in //status_calc_pc, while special_state is recalculated in each call. [Skotlex] struct { - unsigned auth : 1; + unsigned active : 1; //Marks active player (not active is logging in/out, or changing map servers) unsigned menu_or_input : 1;// if a script is waiting for feedback from the player unsigned dead_sit : 2; - unsigned waitingdisconnect : 1; unsigned lr_flag : 2; unsigned connect_new : 1; unsigned arrow_atk : 1; @@ -537,12 +536,9 @@ struct map_session_data { unsigned noask :1; // [LuzZza] unsigned trading :1; //[Skotlex] is 1 only after a trade has started. unsigned deal_locked :2; //1: Clicked on OK. 2: Clicked on TRADE - unsigned party_sent :1; - unsigned guild_sent :1; unsigned monster_ignore :1; // for monsters to ignore a character [Valaris] [zzo] unsigned size :2; // for tiny/large types unsigned night :1; //Holds whether or not the player currently has the SI_NIGHT effect on. [Skotlex] - unsigned finalsave :1; //Signals whether the final save for the char was done or not yet. Meant to prevent exploits and the like. [Skotlex] unsigned blockedmove :1; unsigned using_fake_npc :1; unsigned rewarp :1; //Signals that a player should warp as soon as he is done loading a map. [Skotlex] @@ -1295,9 +1291,7 @@ int map_delobjectnofree(int id); void map_foreachobject(int (*)(struct block_list*,va_list),int,...); int map_search_freecell(struct block_list *src, int m, short *x, short *y, int rx, int ry, int flag); // -bool map_knowsaccount(int account_id); int map_quit(struct map_session_data *); -void map_quit_ack(int account_id, int char_id); // npc bool map_addnpc(int,struct npc_data *); @@ -1338,7 +1332,7 @@ struct map_session_data * map_nick2sd(const char*); enum e_mapitflags { MAPIT_NORMAL = 0, - MAPIT_PCISPLAYING = 1,// player is authed, not waiting disconnect and not in final save +// MAPIT_PCISPLAYING = 1,// Unneeded as pc_db/id_db will only hold auth'ed, active players. }; struct s_mapiterator; struct s_mapiterator* mapit_alloc(enum e_mapitflags flags, enum bl_type types); @@ -1348,7 +1342,7 @@ struct block_list* mapit_last(struct s_mapiterator* mapit); struct block_list* mapit_next(struct s_mapiterator* mapit); struct block_list* mapit_prev(struct s_mapiterator* mapit); bool mapit_exists(struct s_mapiterator* mapit); -#define mapit_getallusers() mapit_alloc(MAPIT_PCISPLAYING,BL_PC) +#define mapit_getallusers() mapit_alloc(MAPIT_NORMAL,BL_PC) #define mapit_geteachpc() mapit_alloc(MAPIT_NORMAL,BL_PC) #define mapit_geteachmob() mapit_alloc(MAPIT_NORMAL,BL_MOB) #define mapit_geteachiddb() mapit_alloc(MAPIT_NORMAL,BL_ALL) diff --git a/src/map/party.c b/src/map/party.c index 7928a3ad3..b8cd03811 100644 --- a/src/map/party.c +++ b/src/map/party.c @@ -54,7 +54,7 @@ static TBL_PC* party_sd_check(int party_id, int account_id, int char_id) { TBL_PC* sd = map_id2sd(account_id); - if (!(sd && sd->status.char_id == char_id && sd->state.auth && !sd->state.waitingdisconnect)) + if (!(sd && sd->status.char_id == char_id)) return NULL; if (sd->status.party_id != party_id) @@ -125,7 +125,6 @@ int party_create(struct map_session_data *sd,char *name,int item,int item2) int party_created(int account_id,int char_id,int fail,int party_id,char *name) { struct map_session_data *sd; - struct party_data *p; sd=map_id2sd(account_id); if (!sd || sd->status.char_id != char_id) @@ -140,16 +139,8 @@ int party_created(int account_id,int char_id,int fail,int party_id,char *name) return 0; // "party name already exists" } sd->status.party_id=party_id; - if(idb_get(party_db,party_id)!=NULL){ - ShowFatalError("party: id already exists!\n"); - exit(EXIT_FAILURE); - } - p=(struct party_data *)aCalloc(1,sizeof(struct party_data)); - p->party.party_id=party_id; - memcpy(p->party.name, name, NAME_LENGTH); - idb_put(party_db,party_id,p); clif_party_created(sd,0); //Success message - clif_charnameupdate(sd); //Update other people's display. [Skotlex] + //We don't do any further work here because the char-server sends a party info packet right after creating the party. return 1; } @@ -239,15 +230,18 @@ static void party_check_state(struct party_data *p) int party_recv_info(struct party *sp) { - struct map_session_data *sd; struct party_data *p; int i; + bool party_new = false; nullpo_retr(0, sp); p= idb_ensure(party_db, sp->party_id, create_party); if (!p->party.party_id) //party just received. + { + party_new = true; party_check_member(sp); + } memcpy(&p->party,sp,sizeof(struct party)); memset(&p->state, 0, sizeof(p->state)); memset(&p->data, 0, sizeof(p->data)); @@ -257,14 +251,17 @@ int party_recv_info(struct party *sp) p->data[i].sd = party_sd_check(p->party.party_id, p->party.member[i].account_id, p->party.member[i].char_id); } party_check_state(p); - for(i=0;idata[i].sd; - if(!sd || sd->state.party_sent) - continue; - clif_party_member_info(p,sd); - clif_party_option(p,sd,0x100); - clif_party_info(p,NULL); - sd->state.party_sent=1; + if (party_new) { + //Send party data to all players. + struct map_session_data *sd; + for(i=0;idata[i].sd; + if(!sd) continue; + clif_charnameupdate(sd); //Update other people's display. [Skotlex] + clif_party_member_info(p,sd); + clif_party_option(p,sd,0x100); + clif_party_info(p,NULL); + } } return 0; @@ -349,6 +346,26 @@ int party_reply_invite(struct map_session_data *sd,int account_id,int flag) return 1; } +//Invoked when a player joins: +//- Loads up party data if not in server +//- Sets up the pointer to him +//- Player must be authed/active and belong to a party before calling this method +void party_member_joined(struct map_session_data *sd) +{ + struct party_data* p = party_search(sd->status.party_id); + int i; + if (!p) + { + party_request_info(sd->status.party_id); + return; + } + ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == sd->status.account_id && p->party.member[i].char_id == sd->status.char_id ); + if (i < MAX_PARTY) + p->data[i].sd = sd; + else + sd->status.party_id = 0; //He does not belongs to the party really? +} + /// Invoked (from char-server) when a new member is added to the party. int party_member_added(int party_id,int account_id,int char_id, int flag) { @@ -371,9 +388,10 @@ int party_member_added(int party_id,int account_id,int char_id, int flag) } if(!flag) { - sd->state.party_sent=0; sd->status.party_id=party_id; party_check_conflict(sd); + clif_party_option(p,sd,0x100); + clif_party_info(p,sd); clif_party_member_info(p,sd); for( i = 0; i < ARRAYLENGTH(p->data); ++i ) {// hp of the other party members @@ -458,7 +476,6 @@ int party_member_leaved(int party_id, int account_id, int char_id) if( sd && sd->status.party_id == party_id && sd->status.char_id == char_id ) { sd->status.party_id = 0; - sd->state.party_sent = 0; clif_charnameupdate(sd); //Update name display [Skotlex] //TODO: hp bars should be cleared too } @@ -479,7 +496,6 @@ int party_broken(int party_id) if(p->data[i].sd!=NULL){ clif_party_leaved(p,p->data[i].sd,p->party.member[i].account_id,p->party.member[i].name,0x10); p->data[i].sd->status.party_id=0; - p->data[i].sd->state.party_sent=0; } } idb_remove(party_db,party_id); @@ -561,14 +577,11 @@ void party_send_movemap(struct map_session_data *sd) p=party_search(sd->status.party_id); if (!p) return; - if(!sd->state.party_sent) { - party_check_member(&p->party); - if(sd->status.party_id==p->party.party_id){ - clif_party_option(p,sd,0x100); - clif_party_info(p,sd); - clif_party_member_info(p,sd); - sd->state.party_sent=1; - } + if(sd->state.connect_new) { + //Note that this works because this function is invoked before connect_new is cleared. + clif_party_option(p,sd,0x100); + clif_party_info(p,sd); + clif_party_member_info(p,sd); } if (sd->fd) { // synchronize minimap positions with the rest of the party diff --git a/src/map/party.h b/src/map/party.h index 8329647b2..b04797fb1 100644 --- a/src/map/party.h +++ b/src/map/party.h @@ -24,6 +24,7 @@ int party_create(struct map_session_data *sd,char *name, int item, int item2); int party_created(int account_id,int char_id,int fail,int party_id,char *name); int party_request_info(int party_id); int party_invite(struct map_session_data *sd,struct map_session_data *tsd); +void party_member_joined(struct map_session_data *sd); int party_member_added(int party_id,int account_id,int char_id,int flag); int party_leave(struct map_session_data *sd); int party_removemember(struct map_session_data *sd,int account_id,char *name); diff --git a/src/map/pc.c b/src/map/pc.c index f76df3d0b..d1bb81c3e 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -333,9 +333,6 @@ int pc_makesavestatus(struct map_session_data *sd) { nullpo_retr(0, sd); - if (sd->state.finalsave) - return 0; //Nothing to change. - if(!battle_config.save_clothcolor) sd->status.clothes_color=0; @@ -392,10 +389,9 @@ int pc_setnewpc(struct map_session_data *sd, int account_id, int char_id, int lo sd->login_id1 = login_id1; sd->login_id2 = 0; // at this point, we can not know the value :( sd->client_tick = client_tick; - sd->state.auth = 0; + sd->state.active = 0; //to be set to 1 after player is fully authed and loaded. sd->bl.type = BL_PC; sd->canlog_tick = gettick(); - sd->state.waitingdisconnect = 0; //Required to prevent homunculus copuing a base speed of 0. sd->battle_status.speed = sd->base_status.speed = DEFAULT_WALK_SPEED; return 0; @@ -607,35 +603,17 @@ int pc_isequip(struct map_session_data *sd,int n) * session idに問題無し * char鯖から送られてきたステ?タスを設定 *------------------------------------------*/ -int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_time, struct mmo_charstatus *st) +bool pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_time, struct mmo_charstatus *st) { - TBL_PC* old_sd; int i; unsigned long tick = gettick(); - if (sd->state.auth) //Temporary debug. [Skotlex] - { - ShowDebug("pc_authok: Received auth ok for already authorized client (account id %d)!\n", sd->bl.id); - return 1; - } - sd->login_id2 = login_id2; memcpy(&sd->status, st, sizeof(*st)); if (st->sex != sd->status.sex) { clif_authfail_fd(sd->fd, 0); - return 1; - } - - if( (old_sd=map_id2sd(st->account_id)) != NULL ){ - if (old_sd->state.finalsave || !old_sd->state.auth) - ; //Previous player is not done loading/quiting, No need to kick. - else if (old_sd->fd) - clif_authfail_fd(old_sd->fd, 2); // same id - else - map_quit(old_sd); - clif_authfail_fd(sd->fd, 8); // still recognizes last connection - return 1; + return false; } //Set the map-server used job id. [Skotlex] @@ -673,9 +651,6 @@ int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_t if (!(battle_config.display_skill_fail&2)) sd->state.showdelay = 1; - // Request all registries. - intif_request_registry(sd,7); - // アイテムチェック pc_setinventorydata(sd); pc_checkitem(sd); @@ -709,21 +684,11 @@ int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_t if (pc_setpos(sd, mapindex_name2id(MAP_PRONTERA), 273, 354, 0) != 0) { // if we fail again clif_authfail_fd(sd->fd, 0); - return 1; + return false; } } - // pet - if (sd->status.pet_id > 0) - intif_request_petdata(sd->status.account_id, sd->status.char_id, sd->status.pet_id); - - // Homunculus [albator] - if (sd->status.hom_id > 0) - intif_homunculus_requestload(sd->status.account_id, sd->status.hom_id); - clif_authok(sd); - map_addiddb(&sd->bl); - map_delnickdb(sd->status.char_id, sd->status.name); //Prevent S. Novices from getting the no-death bonus just yet. [Skotlex] sd->die_counter=-1; @@ -777,22 +742,18 @@ int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_t clif_wis_message(sd->fd, wisp_server_name, tmpstr, strlen(tmpstr)+1); } - return 0; + // Request all registries (auth is considered completed whence they arrive) + intif_request_registry(sd,7); + return true; } /*========================================== * Closes a connection because it failed to be authenticated from the char server. *------------------------------------------*/ -int pc_authfail(struct map_session_data *sd) +void pc_authfail(struct map_session_data *sd) { - if (sd->state.auth) //Temporary debug. [Skotlex] - ShowDebug("pc_authfail: Received auth fail for already authentified client (account id %d)!\n", sd->bl.id); - - if (!sd->fd) - ShowDebug("pc_authfail: Received auth fail for a player with no connection (account id %d)!\n", sd->bl.id); - clif_authfail_fd(sd->fd, 0); - return 0; + return; } //Attempts to set a mob. @@ -827,7 +788,6 @@ int pc_set_hate_mob(struct map_session_data *sd, int pos, struct block_list *bl) int pc_reg_received(struct map_session_data *sd) { int i,j; - struct guild *g = NULL; sd->change_level = pc_readglobalreg(sd,"jobchange_level"); sd->die_counter = pc_readglobalreg(sd,"PC_DIE_COUNTER"); @@ -863,28 +823,33 @@ int pc_reg_received(struct map_session_data *sd) } //Weird... maybe registries were reloaded? - if (sd->state.auth) + if (sd->state.active) return 0; - sd->state.auth = 1; + sd->state.active = 1; - if (sd->status.party_id > 0 && party_search(sd->status.party_id) == NULL) - party_request_info(sd->status.party_id); - if (sd->status.guild_id > 0 && (g=guild_search(sd->status.guild_id)) == NULL) - guild_request_info(sd->status.guild_id); - else if (g && strcmp(sd->status.name,g->master) == 0) - { - // set the Guild Master flag - sd->state.gmaster_flag = g; - // prevent Guild Skills from being used directly after relog - if( battle_config.guild_skill_relog_delay ) - guild_block_skill(sd, 300000); - } + if (sd->status.party_id) + party_member_joined(sd); + if (sd->status.guild_id) + guild_member_joined(sd); + + // pet + if (sd->status.pet_id > 0) + intif_request_petdata(sd->status.account_id, sd->status.char_id, sd->status.pet_id); + + // Homunculus [albator] + if (sd->status.hom_id > 0) + intif_homunculus_requestload(sd->status.account_id, sd->status.hom_id); + + map_addiddb(&sd->bl); + map_delnickdb(sd->status.char_id, sd->status.name); + chrif_auth_finished(sd); status_calc_pc(sd,1); chrif_scdata_request(sd->status.account_id, sd->status.char_id); #ifndef TXT_ONLY intif_Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox #endif + if (!sd->state.connect_new && sd->fd) { //Character already loaded map! Gotta trigger LoadEndAck manually. sd->state.connect_new = 1; @@ -2717,9 +2682,6 @@ int pc_payzeny(struct map_session_data *sd,int zeny) { nullpo_retr(0, sd); - if( sd->state.finalsave ) - return 1; - if( zeny < 0 ) return pc_getzeny(sd, -zeny); @@ -2739,9 +2701,6 @@ int pc_getzeny(struct map_session_data *sd,int zeny) { nullpo_retr(0, sd); - if( sd->state.finalsave ) - return 1; - if( zeny < 0 ) return pc_payzeny(sd, -zeny); @@ -2785,9 +2744,6 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount) nullpo_retr(1, sd); nullpo_retr(1, item_data); - if(sd->state.finalsave) - return 1; - if(item_data->nameid <= 0 || amount <= 0) return 1; if(amount > MAX_AMOUNT) @@ -3135,9 +3091,6 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun nullpo_retr(1, sd); nullpo_retr(1, item_data); - if(sd->state.finalsave) - return 1; - if(item_data->nameid <= 0 || amount <= 0) return 1; data = itemdb_search(item_data->nameid); @@ -3191,9 +3144,6 @@ int pc_cart_delitem(struct map_session_data *sd,int n,int amount,int type) { nullpo_retr(1, sd); - if(sd->state.finalsave) - return 1; - if(sd->status.cart[n].nameid==0 || sd->status.cart[n].amountmapindex) { - uint32 ip; - uint16 port; - if(map_mapname2ipport(mapindex,&ip,&port)==0) { - unit_remove_map(&sd->bl,clrtype); - sd->mapindex = mapindex; - sd->bl.x=x; - sd->bl.y=y; - sd->state.waitingdisconnect=1; - pc_clean_skilltree(sd); - if(sd->status.pet_id > 0 && sd->pd) { - intif_save_petdata(sd->status.account_id,&sd->pd->pet); - unit_remove_map(&sd->pd->bl, clrtype); - } - if(merc_is_hom_active(sd->hd)) //Hom is auto-saved in chrif_save - unit_remove_map(&sd->hd->bl, clrtype); - - chrif_save(sd,2); - chrif_changemapserver(sd, mapindex, x, y, ip, (short)port); - return 0; - } - } - return 2; + uint32 ip; + uint16 port; + //if can't find any map-servers, just abort setting position. + if(!sd->mapindex || map_mapname2ipport(mapindex,&ip,&port)) + return 2; + + sd->mapindex = mapindex; + sd->bl.x=x; + sd->bl.y=y; + pc_clean_skilltree(sd); + unit_remove_map_pc(sd,clrtype); + chrif_save(sd,2); + chrif_changemapserver(sd, ip, (short)port); + //It is important to invoke remove_map separately from unit_free before + //saving so that the data saved corresponds to that AFTER warping. + unit_free_pc(sd); + return 0; } if(x <0 || x >= map[m].xs || y <0 || y >= map[m].ys) @@ -3500,13 +3444,9 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y } if(sd->bl.prev != NULL){ - unit_remove_map(&sd->bl, clrtype); - if(sd->status.pet_id > 0 && sd->pd) - unit_remove_map(&sd->pd->bl, clrtype); - if(merc_is_hom_active(sd->hd)) - unit_remove_map(&sd->hd->bl, clrtype); + unit_remove_map_pc(sd,clrtype); clif_changemap(sd,map[m].index,x,y); // [MouseJstr] - } else if(sd->state.auth) + } else if(sd->state.active) //Tag player for rewarping after map-loading is done. [Skotlex] sd->state.rewarp = 1; @@ -6587,7 +6527,7 @@ int pc_checkitem(struct map_session_data *sd) } pc_setequipindex(sd); - if(calc_flag && sd->state.auth) + if(calc_flag && sd->state.active) { status_calc_pc(sd,0); pc_equiplookall(sd); @@ -6881,24 +6821,11 @@ static int pc_autosave_sub(DBKey key,void * data,va_list ap) if(save_flag != 1) //Not our turn to save yet. return 0; - if (sd->state.waitingdisconnect) //Invalid char to save. - return 0; - //Save char. last_save_id = sd->bl.id; save_flag=2; - // pet - if(sd->status.pet_id > 0 && sd->pd) - intif_save_petdata(sd->status.account_id,&sd->pd->pet); - - if(sd->state.finalsave) - { //Save ack hasn't returned from char-server yet? Retry. - ShowDebug("pc_autosave: Resending to save logging out char %d:%d (save ack from char-server hasn't arrived yet)\n", sd->status.account_id, sd->status.char_id); - sd->state.finalsave = 0; - chrif_save(sd,1); - } else - chrif_save(sd,0); + chrif_save(sd,0); return 1; } diff --git a/src/map/pc.h b/src/map/pc.h index e3eb9afdb..dc55b53bd 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -126,7 +126,6 @@ extern int duel_count; #define pc_is50overweight(sd) ( (sd)->weight*100 >= (sd)->max_weight*battle_config.natural_heal_weight_rate ) #define pc_is90overweight(sd) ( (sd)->weight*10 >= (sd)->max_weight*9 ) #define pc_maxparameter(sd) ( (sd)->class_&JOBL_BABY ? battle_config.max_baby_parameter : battle_config.max_parameter ) -#define pc_isplaying(sd) ( (sd)->state.auth /* is authed */ && !(sd)->state.waitingdisconnect /* not waiting disconnect */ && !(sd)->state.finalsave /* not in final save */ ) #define pc_stop_walking(sd, type) unit_stop_walking(&(sd)->bl, type) #define pc_stop_attack(sd) unit_stop_attack(&(sd)->bl) @@ -145,8 +144,8 @@ bool pc_can_give_items(int level); int pc_setrestartvalue(struct map_session_data *sd,int type); int pc_makesavestatus(struct map_session_data *); int pc_setnewpc(struct map_session_data*,int,int,int,unsigned int,int,int); -int pc_authok(struct map_session_data*, int, time_t, struct mmo_charstatus *); -int pc_authfail(struct map_session_data *); +bool pc_authok(struct map_session_data*, int, time_t, struct mmo_charstatus *); +void pc_authfail(struct map_session_data *); int pc_reg_received(struct map_session_data *sd); int pc_isequip(struct map_session_data *sd,int n); diff --git a/src/map/status.c b/src/map/status.c index 6b6174293..10129129a 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -1616,9 +1616,6 @@ int status_calc_pc(struct map_session_data* sd,int first) int i,index; int skill,refinedef=0; - if(!sd->state.auth && !(first&1)) //Shouldn't invoke yet until player is done loading. - return -1; - if (++calculating > 10) //Too many recursive calls! return -1; @@ -4623,9 +4620,6 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val sd = BL_CAST(BL_PC, bl); - if(sd && sd->state.waitingdisconnect) - return 0; //Character logging out, all his SC were wiped already! - //Adjust tick according to status resistances if( !(flag&(1|4)) ) { diff --git a/src/map/storage.c b/src/map/storage.c index 50024fbbe..06c052d74 100644 --- a/src/map/storage.c +++ b/src/map/storage.c @@ -132,9 +132,6 @@ int storage_storageopen(struct map_session_data *sd) struct storage *stor; nullpo_retr(0, sd); - if(sd->state.finalsave) //Refuse to open storage when you had your last save done. - return 1; - if(sd->state.storage_flag) return 1; //Already open? @@ -183,9 +180,6 @@ static int storage_additem(struct map_session_data *sd,struct storage *stor,stru struct item_data *data; int i; - if (sd->state.finalsave) - return 1; - if(item_data->nameid <= 0 || amount <= 0) return 1; @@ -502,9 +496,6 @@ int storage_guild_storageopen(struct map_session_data *sd) if(sd->status.guild_id <= 0) return 2; - if(sd->state.finalsave) //Refuse to open storage when you had your last save done. - return 1; - if(sd->state.storage_flag) return 1; //Can't open both storages at a time. diff --git a/src/map/trade.c b/src/map/trade.c index 5c063621d..a9f2a2fd5 100644 --- a/src/map/trade.c +++ b/src/map/trade.c @@ -232,9 +232,6 @@ int trade_check(struct map_session_data *sd, struct map_session_data *tsd) int trade_i, i, n; short amount; - if(sd->state.finalsave || tsd->state.finalsave) - return 0; //Item transferring fails - // check zenys value against hackers (Zeny was already checked on time of adding, but you never know when you lost some zeny since then. if(sd->deal.zeny > sd->status.zeny || (tsd->status.zeny > MAX_ZENY - sd->deal.zeny)) return 0; diff --git a/src/map/unit.c b/src/map/unit.c index d0d06ff06..66f362085 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1658,13 +1658,11 @@ int unit_remove_map(struct block_list *bl, int clrtype) trade_tradecancel(sd); if(sd->vender_id) vending_closevending(sd); - if(!sd->state.waitingdisconnect) - { //when quitting, let the final chrif_save handle storage saving. - if(sd->state.storage_flag == 1) - storage_storage_quit(sd,0); - else if (sd->state.storage_flag == 2) - storage_guild_storage_quit(sd,0); - } + if(sd->state.storage_flag == 1) + storage_storage_quit(sd,0); + else if (sd->state.storage_flag == 2) + storage_guild_storage_quit(sd,0); + sd->state.storage_flag = 0; //Force close it when being warped. if(sd->party_invite>0) party_reply_invite(sd,sd->party_invite_account,0); if(sd->guild_invite>0) @@ -1708,7 +1706,7 @@ int unit_remove_map(struct block_list *bl, int clrtype) case BL_PET: { struct pet_data *pd = (struct pet_data*)bl; - if( pd->pet.intimate <= 0 && !(pd->msd && pd->msd->state.waitingdisconnect) ) + if( pd->pet.intimate <= 0 && !(pd->msd && pd->msd->state.active) ) { //If logging out, this is deleted on unit_free clif_clearunit_area(bl,clrtype); map_delblock(bl); @@ -1723,7 +1721,7 @@ int unit_remove_map(struct block_list *bl, int clrtype) { struct homun_data *hd = (struct homun_data *) bl; ud->canact_tick = ud->canmove_tick; //It appears HOM do reset the can-act tick. - if(!hd->homunculus.intimacy && !(hd->master && hd->master->state.waitingdisconnect) ) + if(!hd->homunculus.intimacy && !(hd->master && hd->master->state.active) ) { //If logging out, this is deleted on unit_free clif_emotion(bl, 28) ; //sob clif_clearunit_area(bl,clrtype); @@ -1744,6 +1742,25 @@ int unit_remove_map(struct block_list *bl, int clrtype) return 1; } +void unit_remove_map_pc(struct map_session_data *sd, int clrtype) +{ + unit_remove_map(&sd->bl,clrtype); + + if (clrtype == 3) clrtype = 0; //3 is the warp from logging out, but pets/homunc need to just 'vanish' instead of showing the warping out animation. + + if(sd->pd) + unit_remove_map(&sd->pd->bl, clrtype); + if(merc_is_hom_active(sd->hd)) + unit_remove_map(&sd->hd->bl, clrtype); +} + +void unit_free_pc(struct map_session_data *sd) +{ + if (sd->pd) unit_free(&sd->pd->bl,0); + if (sd->hd) unit_free(&sd->hd->bl,0); + unit_free(&sd->bl,3); +} + /*========================================== * Function to free all related resources to the bl * if unit is on map, it is removed using the clrtype specified @@ -1765,44 +1782,6 @@ int unit_free(struct block_list *bl, int clrtype) pc_setrestartvalue(sd,2); pc_delinvincibletimer(sd); - //Status that are not saved... - if(sd->sc.count) { - if(sd->sc.data[SC_SPURT]) - status_change_end(bl,SC_SPURT,-1); - if(sd->sc.data[SC_BERSERK]) - status_change_end(bl,SC_BERSERK,-1); - if(sd->sc.data[SC_TRICKDEAD]) - status_change_end(bl,SC_TRICKDEAD,-1); - if(sd->sc.data[SC_GUILDAURA]) - status_change_end(bl,SC_GUILDAURA,-1); - if (battle_config.debuff_on_logout&1) { - if(sd->sc.data[SC_ORCISH]) - status_change_end(bl,SC_ORCISH,-1); - if(sd->sc.data[SC_STRIPWEAPON]) - status_change_end(bl,SC_STRIPWEAPON,-1); - if(sd->sc.data[SC_STRIPARMOR]) - status_change_end(bl,SC_STRIPARMOR,-1); - if(sd->sc.data[SC_STRIPSHIELD]) - status_change_end(bl,SC_STRIPSHIELD,-1); - if(sd->sc.data[SC_STRIPHELM]) - status_change_end(bl,SC_STRIPHELM,-1); - if(sd->sc.data[SC_EXTREMITYFIST]) - status_change_end(bl,SC_EXTREMITYFIST,-1); - if(sd->sc.data[SC_EXPLOSIONSPIRITS]) - status_change_end(bl,SC_EXPLOSIONSPIRITS,-1); - if(sd->sc.data[SC_REGENERATION] && sd->sc.data[SC_REGENERATION]->val4) - status_change_end(bl,SC_REGENERATION,-1); - } - if (battle_config.debuff_on_logout&2) - { - if(sd->sc.data[SC_MAXIMIZEPOWER]) - status_change_end(bl,SC_MAXIMIZEPOWER,-1); - if(sd->sc.data[SC_MAXOVERTHRUST]) - status_change_end(bl,SC_MAXOVERTHRUST,-1); - if(sd->sc.data[SC_STEELBODY]) - status_change_end(bl,SC_STEELBODY,-1); - } - } pc_autoscript_clear(sd->autoscript, ARRAYLENGTH(sd->autoscript)); pc_autoscript_clear(sd->autoscript2, ARRAYLENGTH(sd->autoscript2)); @@ -1819,10 +1798,29 @@ int unit_free(struct block_list *bl, int clrtype) guild_send_memberinfoshort(sd,0); pc_cleareventtimer(sd); pc_delspiritball(sd,sd->spiritball,1); - if (clrtype >= 0) { - chrif_save_scdata(sd); //Save status changes, then clear'em out from memory. [Skotlex] - pc_makesavestatus(sd); - pc_clean_skilltree(sd); + + if(sd->reg) + { //Double logout already freed pointer fix... [Skotlex] + aFree(sd->reg); + sd->reg = NULL; + sd->reg_num = 0; + } + if(sd->regstr) + { + int i; + for( i = 0; i < sd->regstr_num; ++i ) + if( sd->regstr[i].data ) + aFree(sd->regstr[i].data); + aFree(sd->regstr); + sd->regstr = NULL; + sd->regstr_num = 0; + } + if (sd->st) { + if (sd->st->stack) + script_free_stack (sd->st->stack); + aFree(sd->st); + sd->st = NULL; + sd->npc_id = 0; } } else if( bl->type == BL_PET ) { struct pet_data *pd = (struct pet_data*)bl; @@ -1924,11 +1922,9 @@ int unit_free(struct block_list *bl, int clrtype) skill_clear_unitgroup(bl); status_change_clear(bl,1); - if (bl->type != BL_PC) - { //Players are handled by map_quit - map_deliddb(bl); + map_deliddb(bl); + if (bl->type != BL_PC) //Players are handled by map_quit map_freeblock(bl); - } map_freeblock_unlock(); return 0; } diff --git a/src/map/unit.h b/src/map/unit.h index 2c569607d..7575d3f5e 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -7,6 +7,7 @@ //#include "map.h" struct block_list; struct unit_data; +struct map_session_data; // PC, MOB, PET に共通する処理を1つにまとめる計画 @@ -61,6 +62,8 @@ void unit_dataset(struct block_list *bl); int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2); // その他 struct unit_data* unit_bl2ud(struct block_list *bl); +void unit_remove_map_pc(struct map_session_data *sd, int clrtype); +void unit_free_pc(struct map_session_data *sd); int unit_remove_map(struct block_list *bl, int clrtype); int unit_free(struct block_list *bl, int clrtype); int unit_changeviewsize(struct block_list *bl,short size); -- cgit v1.2.3-70-g09d2 From 3731a2ee949a424941f46a653525fcd4bfca0e3f Mon Sep 17 00:00:00 2001 From: ultramage Date: Mon, 24 Mar 2008 21:20:48 +0000 Subject: * Reorganized the contents of the mapserver's header files. - map.h is no longer a generic dumping spot of all the shared structs, and instead, each such structure now resides in its logical component - map.h now only holds mostly map-related things (needs more cleaning) - there's still a lot of room for improvement (reorganization within individual header files, etc...) git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@12429 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 5 + src/map/atcommand.c | 1 + src/map/battle.c | 1 + src/map/chat.h | 17 +- src/map/chrif.c | 1 + src/map/guild.h | 12 +- src/map/irc.c | 1 + src/map/log.c | 6 +- src/map/map.h | 784 +--------------------------------------------------- src/map/mercenary.h | 21 ++ src/map/mob.c | 1 + src/map/mob.h | 66 ++++- src/map/npc.h | 57 +++- src/map/npc_chat.c | 4 +- src/map/party.h | 22 +- src/map/path.h | 15 + src/map/pc.h | 336 +++++++++++++++++++++- src/map/pet.h | 61 ++++ src/map/script.h | 10 + src/map/skill.h | 73 ++++- src/map/status.h | 102 ++++++- src/map/unit.h | 50 ++++ src/map/vending.h | 6 + 23 files changed, 850 insertions(+), 802 deletions(-) (limited to 'src/map/unit.h') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 00a960863..30f61d74d 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -3,6 +3,11 @@ Date Added AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK. IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. +2008/03/24 + * Reorganized the contents of the mapserver's header files. + - map.h is no longer a generic dumping spot of all the shared structs, + and instead, each such structure now resides in its logical component + - map.h now only holds mostly map-related things (needs more cleaning) 2008/03/21 * Added VS9 project files. Thanks to Konard [Lupus] - removed redundant map_getallusers() function diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 73b0a2feb..233376655 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -14,6 +14,7 @@ #include "atcommand.h" #include "battle.h" +#include "chat.h" #include "clif.h" #include "chrif.h" #include "intif.h" diff --git a/src/map/battle.c b/src/map/battle.c index c43b9be96..6a60ea0a9 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -15,6 +15,7 @@ #include "pc.h" #include "status.h" #include "skill.h" +#include "mercenary.h" #include "mob.h" #include "itemdb.h" #include "clif.h" diff --git a/src/map/chat.h b/src/map/chat.h index d7bfb3f50..569e6cbe8 100644 --- a/src/map/chat.h +++ b/src/map/chat.h @@ -4,10 +4,25 @@ #ifndef _CHAT_H_ #define _CHAT_H_ -//#include "map.h" +#include "map.h" // struct block_list, CHATROOM_TITLE_SIZE struct map_session_data; struct chat_data; + +struct chat_data { + struct block_list bl; // data for this map object + char title[CHATROOM_TITLE_SIZE]; // room title + char pass[CHATROOM_PASS_SIZE]; // password + bool pub; // private/public flag + uint8 users; // current user count + uint8 limit; // join limit + uint8 trigger; // number of users needed to trigger event + struct map_session_data* usersd[20]; + struct block_list* owner; + char npc_event[50]; +}; + + int chat_createpcchat(struct map_session_data* sd, const char* title, const char* pass, int limit, bool pub); int chat_joinchat(struct map_session_data* sd, int chatid, const char* pass); int chat_leavechat(struct map_session_data* sd, bool kicked); diff --git a/src/map/chrif.c b/src/map/chrif.c index b923b427e..7194819cf 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -16,6 +16,7 @@ #include "intif.h" #include "npc.h" #include "pc.h" +#include "pet.h" #include "status.h" #include "mercenary.h" #include "chrif.h" diff --git a/src/map/guild.h b/src/map/guild.h index 1035818d9..e6383a3e3 100644 --- a/src/map/guild.h +++ b/src/map/guild.h @@ -9,10 +9,20 @@ struct guild; struct guild_member; struct guild_position; struct guild_castle; -//#include "map.h" +#include "map.h" // NAME_LENGTH struct map_session_data; struct mob_data; +//For quick linking to a guardian's info. [Skotlex] +struct guardian_data { + int number; //0-MAX_GUARDIANS-1 = Guardians. MAX_GUARDIANS = Emperium. + int guild_id; + int emblem_id; + int guardup_lv; //Level of GD_GUARDUP skill. + char guild_name[NAME_LENGTH]; + struct guild_castle* castle; +}; + int guild_skill_get_max(int id); int guild_checkskill(struct guild *g,int id); diff --git a/src/map/irc.c b/src/map/irc.c index 00afe8353..8973dd61f 100644 --- a/src/map/irc.c +++ b/src/map/irc.c @@ -13,6 +13,7 @@ #include "../common/nullpo.h" #include "map.h" +#include "mob.h" #include "pc.h" #include "intif.h" //For GM Broadcast #include "irc.h" diff --git a/src/map/log.c b/src/map/log.c index bd5079a40..0483b6387 100644 --- a/src/map/log.c +++ b/src/map/log.c @@ -4,10 +4,12 @@ #include "../common/strlib.h" #include "../common/nullpo.h" #include "../common/showmsg.h" +#include "battle.h" #include "itemdb.h" -#include "map.h" #include "log.h" -#include "battle.h" +#include "map.h" +#include "mob.h" +#include "pc.h" #include #include diff --git a/src/map/map.h b/src/map/map.h index 11e7a3731..bf168b20c 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -11,11 +11,11 @@ #include "../common/mapindex.h" #include "../common/db.h" -#include "itemdb.h" // MAX_ITEMGROUP -#include "status.h" // SC_MAX - #include +struct npc_data; +struct item_data; + //Uncomment to enable the Cell Stack Limit mod. //It's only config is the battle_config cell_stack_limit. //Only chars affected are those defined in BL_CHAR (mobs and players currently) @@ -33,10 +33,6 @@ #define AREA_SIZE battle_config.area_size #define DAMAGELOG_SIZE 30 #define LOOTITEM_SIZE 10 -#define MAX_SKILL_LEVEL 100 -#define MAX_SKILLUNITGROUP 25 -#define MAX_SKILLUNITGROUPTICKSET 25 -#define MAX_SKILLTIMERSKILL 15 #define MAX_MOBSKILL 40 #define MAX_MOB_LIST_PER_MAP 128 #define MAX_EVENTQUEUE 2 @@ -44,7 +40,6 @@ #define NATURAL_HEAL_INTERVAL 500 #define MAX_FLOORITEM 500000 #define MAX_LEVEL 99 -#define MAX_WALKPATH 32 #define MAX_DROP_PER_MAP 48 #define MAX_IGNORE_LIST 20 // official is 14 #define MAX_VENDING 12 @@ -52,9 +47,6 @@ #define MOBID_BARRICADEB 1905 #define MOBID_BARRICADEA 1906 // Undestruble -#define MAX_PC_BONUS 10 -#define MAX_DUEL 1024 - //The following system marks a different job ID system used by the map server, //which makes a lot more sense than the normal one. [Skotlex] // @@ -236,630 +228,6 @@ struct block_list { enum bl_type type; }; -struct walkpath_data { - unsigned char path_len,path_pos; - unsigned char path[MAX_WALKPATH]; -}; -struct shootpath_data { - int rx,ry,len; - int x[MAX_WALKPATH]; - int y[MAX_WALKPATH]; -}; - -struct skill_timerskill { - int timer; - int src_id; - int target_id; - int map; - short x,y; - short skill_id,skill_lv; - int type; // a BF_ type (NOTE: some places use this as general-purpose storage...) - int flag; -}; - -struct skill_unit_group; -struct skill_unit { - struct block_list bl; - - struct skill_unit_group *group; - - int limit; - int val1,val2; - short alive,range; -}; - -struct skill_unit_group { - int src_id; - int party_id; - int guild_id; - int map; - int target_flag; //Holds BCT_* flag for battle_check_target - int bl_flag; //Holds BL_* flag for map_foreachin* functions - unsigned int tick; - int limit,interval; - - short skill_id,skill_lv; - int val1,val2,val3; - char *valstr; - int unit_id; - int group_id; - int unit_count,alive_count; - struct skill_unit *unit; - struct { - unsigned ammo_consume : 1; - unsigned magic_power : 1; - unsigned song_dance : 2; //0x1 Song/Dance, 0x2 Ensemble - } state; -}; -struct skill_unit_group_tickset { - unsigned int tick; - int id; -}; - -struct unit_data { - struct block_list *bl; - struct walkpath_data walkpath; - struct skill_timerskill *skilltimerskill[MAX_SKILLTIMERSKILL]; - struct skill_unit_group *skillunit[MAX_SKILLUNITGROUP]; - struct skill_unit_group_tickset skillunittick[MAX_SKILLUNITGROUPTICKSET]; - short attacktarget_lv; - short to_x,to_y; - short skillx,skilly; - short skillid,skilllv; - int skilltarget; - int skilltimer; - int target; - int attacktimer; - int walktimer; - int chaserange; - unsigned int attackabletime; - unsigned int canact_tick; - unsigned int canmove_tick; - uint8 dir; - unsigned char walk_count; - struct { - unsigned change_walk_target : 1 ; - unsigned skillcastcancel : 1 ; - unsigned attack_continue : 1 ; - unsigned walk_easy : 1 ; - unsigned running : 1; - unsigned speed_changed : 1; - } state; -}; - -//Basic damage info of a weapon -//Required because players have two of these, one in status_data and another -//for their left hand weapon. -struct weapon_atk { - unsigned short atk, atk2; - unsigned short range; - unsigned char ele; -}; - -//For holding basic status (which can be modified by status changes) -struct status_data { - unsigned int - hp, sp, - max_hp, max_sp; - unsigned short - str, agi, vit, int_, dex, luk, - batk, - matk_min, matk_max, - speed, - amotion, adelay, dmotion, - mode; - short - hit, flee, cri, flee2, - def2, mdef2, - aspd_rate; - unsigned char - def_ele, ele_lv, - size, race; - signed char - def, mdef; - struct weapon_atk rhw, lhw; //Right Hand/Left Hand Weapon. -}; - -struct script_reg { - int index; - int data; -}; -struct script_regstr { - int index; - char* data; -}; - -struct status_change_entry { - int timer; - int val1,val2,val3,val4; -}; - -struct status_change { - unsigned int option;// effect state (bitfield) - unsigned int opt3;// skill state (bitfield) - unsigned short opt1;// body state - unsigned short opt2;// health state (bitfield) - unsigned char count; - //TODO: See if it is possible to implement the following SC's without requiring extra parameters while the SC is inactive. - unsigned char jb_flag; //Joint Beat type flag - unsigned short mp_matk_min, mp_matk_max; //Previous matk min/max for ground spells (Amplify magic power) - int sg_id; //ID of the previous Storm gust that hit you - unsigned char sg_counter; //Storm gust counter (previous hits from storm gust) - struct status_change_entry *data[SC_MAX]; -}; - -struct s_vending { - short index; - short amount; - unsigned int value; -}; - -struct weapon_data { - int atkmods[3]; - // all the variables except atkmods get zero'ed in each call of status_calc_pc - // NOTE: if you want to add a non-zeroed variable, you need to update the memset call - // in status_calc_pc as well! All the following are automatically zero'ed. [Skotlex] - int overrefine; - int star; - int ignore_def_ele; - int ignore_def_race; - int def_ratio_atk_ele; - int def_ratio_atk_race; - int addele[ELE_MAX]; - int addrace[RC_MAX]; - int addrace2[RC_MAX]; - int addsize[3]; - - struct drain_data { - short rate; - short per; - short value; - unsigned type:1; - } hp_drain[RC_MAX], sp_drain[RC_MAX]; - - struct { - short class_, rate; - } add_dmg[MAX_PC_BONUS]; -}; - -struct view_data { - unsigned short - class_, - weapon, - shield, //Or left-hand weapon. - head_top, - head_mid, - head_bottom, - hair_style, - hair_color, - cloth_color; - char sex; - unsigned dead_sit : 2; -}; - -//Additional regen data that only players have. -struct regen_data_sub { - unsigned short - hp,sp; - - //tick accumulation before healing. - struct { - unsigned int hp,sp; - } tick; - - //Regen rates (where every 1 means +100% regen) - struct { - unsigned char hp,sp; - } rate; -}; - -struct regen_data { - - unsigned short flag; //Marks what stuff you may heal or not. - unsigned short - hp,sp,shp,ssp; - - //tick accumulation before healing. - struct { - unsigned int hp,sp,shp,ssp; - } tick; - - //Regen rates (where every 1 means +100% regen) - struct { - unsigned char - hp,sp,shp,ssp; - } rate; - - struct { - unsigned walk:1; //Can you regen even when walking? - unsigned gc:1; //Tags when you should have double regen due to GVG castle - unsigned overweight :2; //overweight state (1: 50%, 2: 90%) - unsigned block :2; //Block regen flag (1: Hp, 2: Sp) - } state; - - //skill-regen, sitting-skill-regen (since not all chars with regen need it) - struct regen_data_sub *sregen, *ssregen; -}; - -struct party_member_data { - struct map_session_data *sd; - unsigned int hp; //For HP,x,y refreshing. - unsigned short x, y; -}; - -struct party_data { - struct party party; - struct party_member_data data[MAX_PARTY]; - uint8 itemc; //For item distribution, position of last picker in party - struct { - unsigned monk : 1; //There's at least one monk in party? - unsigned sg : 1; //There's at least one Star Gladiator in party? - unsigned snovice :1; //There's a Super Novice - unsigned tk : 1; //There's a taekwon - } state; -}; - -struct npc_data; -struct pet_db; -struct homunculus_db; //[orn] -struct item_data; -struct square; - -struct map_session_data { - struct block_list bl; - struct unit_data ud; - struct view_data vd; - struct status_data base_status, battle_status; - struct status_change sc; - struct regen_data regen; - struct regen_data_sub sregen, ssregen; - //NOTE: When deciding to add a flag to state or special_state, take into consideration that state is preserved in - //status_calc_pc, while special_state is recalculated in each call. [Skotlex] - struct { - unsigned active : 1; //Marks active player (not active is logging in/out, or changing map servers) - unsigned menu_or_input : 1;// if a script is waiting for feedback from the player - unsigned dead_sit : 2; - unsigned lr_flag : 2; - unsigned connect_new : 1; - unsigned arrow_atk : 1; - unsigned skill_flag : 1; - unsigned gangsterparadise : 1; - unsigned rest : 1; - unsigned storage_flag : 2; //0: closed, 1: Normal Storage open, 2: guild storage open [Skotlex] - unsigned snovice_call_flag : 2; //Summon Angel (stage 1~3) - unsigned snovice_dead_flag : 2; //Explosion spirits on death: 0 off, 1 active, 2 used. - unsigned abra_flag : 1; // Abracadabra bugfix by Aru - unsigned autotrade : 1; //By Fantik - unsigned reg_dirty : 3; //By Skotlex (marks whether registry variables have been saved or not yet) - unsigned showdelay :1; - unsigned showexp :1; - unsigned showzeny :1; - unsigned mainchat :1; //[LuzZza] - unsigned noask :1; // [LuzZza] - unsigned trading :1; //[Skotlex] is 1 only after a trade has started. - unsigned deal_locked :2; //1: Clicked on OK. 2: Clicked on TRADE - unsigned monster_ignore :1; // for monsters to ignore a character [Valaris] [zzo] - unsigned size :2; // for tiny/large types - unsigned night :1; //Holds whether or not the player currently has the SI_NIGHT effect on. [Skotlex] - unsigned blockedmove :1; - unsigned using_fake_npc :1; - unsigned rewarp :1; //Signals that a player should warp as soon as he is done loading a map. [Skotlex] - unsigned killer : 1; - unsigned killable : 1; - unsigned doridori : 1; - unsigned ignoreAll : 1; - unsigned short autoloot; - unsigned short autolootid; // [Zephyrus] - unsigned noks : 3; // [Zeph Kill Steal Protection] - bool changemap; - struct guild *gmaster_flag; - } state; - struct { - unsigned char no_weapon_damage, no_magic_damage, no_misc_damage; - unsigned restart_full_recover : 1; - unsigned no_castcancel : 1; - unsigned no_castcancel2 : 1; - unsigned no_sizefix : 1; - unsigned no_gemstone : 1; - unsigned intravision : 1; // Maya Purple Card effect [DracoRPG] - unsigned perfect_hiding : 1; // [Valaris] - unsigned no_knockback : 1; - unsigned bonus_coma : 1; - } special_state; - int login_id1, login_id2; - unsigned short class_; //This is the internal job ID used by the map server to simplify comparisons/queries/etc. [Skotlex] - - int packet_ver; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 ... 18 - struct mmo_charstatus status; - struct registry save_reg; - - struct item_data* inventory_data[MAX_INVENTORY]; // direct pointers to itemdb entries (faster than doing item_id lookups) - short equip_index[11]; - unsigned int weight,max_weight; - int cart_weight,cart_num; - int fd; - unsigned short mapindex; - unsigned short prev_speed,prev_adelay; - unsigned char head_dir; //0: Look forward. 1: Look right, 2: Look left. - unsigned int client_tick; - int npc_id,areanpc_id,npc_shopid; - int npc_item_flag; //Marks the npc_id with which you can use items during interactions with said npc (see script command enable_itemuse) - int npc_menu; - int npc_amount; - struct script_state *st; - char npc_str[CHATBOX_SIZE]; // for passing npc input box text to script engine - int npc_timer_id; //For player attached npc timers. [Skotlex] - unsigned int chatID; - time_t idletime; - - struct{ - char name[NAME_LENGTH]; - } ignore[MAX_IGNORE_LIST]; - - int followtimer; // [MouseJstr] - int followtarget; - - time_t emotionlasttime; // to limit flood with emotion packets - - short skillitem,skillitemlv; - short skillid_old,skilllv_old; - short skillid_dance,skilllv_dance; - char blockskill[MAX_SKILL]; // [celest] - int cloneskill_id; - int menuskill_id, menuskill_val; - - int invincible_timer; - unsigned int canlog_tick; - unsigned int canuseitem_tick; // [Skotlex] - unsigned int cantalk_tick; - unsigned int cansendmail_tick; // [Mail System Flood Protection] - unsigned int ks_floodprotect_tick; // [Kill Steal Protection] - - short weapontype1,weapontype2; - short disguise; // [Valaris] - - struct weapon_data right_weapon, left_weapon; - - // here start arrays to be globally zeroed at the beginning of status_calc_pc() - int param_bonus[6],param_equip[6]; //Stores card/equipment bonuses. - int subele[ELE_MAX]; - int subrace[RC_MAX]; - int subrace2[RC_MAX]; - int subsize[3]; - int reseff[SC_COMMON_MAX-SC_COMMON_MIN+1]; - int weapon_coma_ele[ELE_MAX]; - int weapon_coma_race[RC_MAX]; - int weapon_atk[16]; - int weapon_atk_rate[16]; - int arrow_addele[ELE_MAX]; - int arrow_addrace[RC_MAX]; - int arrow_addsize[3]; - int magic_addele[ELE_MAX]; - int magic_addrace[RC_MAX]; - int magic_addsize[3]; - int critaddrace[RC_MAX]; - int expaddrace[RC_MAX]; - int ignore_mdef[RC_MAX]; - int itemgrouphealrate[MAX_ITEMGROUP]; - short sp_gain_race[RC_MAX]; - // zeroed arrays end here. - // zeroed structures start here - struct s_autospell{ - short id, lv, rate, card_id, flag; - } autospell[15], autospell2[15]; - struct s_addeffect{ - short id, rate, arrow_rate; - unsigned char flag; - } addeff[MAX_PC_BONUS], addeff2[MAX_PC_BONUS]; - struct { //skillatk raises bonus dmg% of skills, skillheal increases heal%, skillblown increases bonus blewcount for some skills. - unsigned short id; - short val; - } skillatk[MAX_PC_BONUS], skillheal[5], skillblown[MAX_PC_BONUS], skillcast[MAX_PC_BONUS]; - struct { - short value; - int rate; - int tick; - } hp_loss, sp_loss, hp_regen, sp_regen; - struct { - short class_, rate; - } add_def[MAX_PC_BONUS], add_mdef[MAX_PC_BONUS], - add_mdmg[MAX_PC_BONUS]; - struct s_add_drop { - short id, group; - int race, rate; - } add_drop[MAX_PC_BONUS]; - struct { - int nameid; - int rate; - } itemhealrate[MAX_PC_BONUS]; - // zeroed structures end here - // manually zeroed structures start here. - struct s_autoscript { - unsigned short rate, flag; - struct script_code *script; - } autoscript[10], autoscript2[10]; //Auto script on attack, when attacked - // manually zeroed structures end here. - // zeroed vars start here. - int arrow_atk,arrow_ele,arrow_cri,arrow_hit; - int nsshealhp,nsshealsp; - int critical_def,double_rate; - int long_attack_atk_rate; //Long range atk rate, not weapon based. [Skotlex] - int near_attack_def_rate,long_attack_def_rate,magic_def_rate,misc_def_rate; - int ignore_mdef_ele; - int ignore_mdef_race; - int perfect_hit; - int perfect_hit_add; - int get_zeny_rate; - int get_zeny_num; //Added Get Zeny Rate [Skotlex] - int double_add_rate; - int short_weapon_damage_return,long_weapon_damage_return; - int magic_damage_return; // AppleGirl Was Here - int random_attack_increase_add,random_attack_increase_per; // [Valaris] - int break_weapon_rate,break_armor_rate; - int crit_atk_rate; - int classchange; // [Valaris] - int speed_add_rate, aspd_add; - unsigned int setitem_hash, setitem_hash2; //Split in 2 because shift operations only work on int ranges. [Skotlex] - - short splash_range, splash_add_range; - short add_steal_rate; - short sp_gain_value, hp_gain_value; - short sp_vanish_rate; - short sp_vanish_per; - unsigned short unbreakable; // chance to prevent ANY equipment breaking [celest] - unsigned short unbreakable_equip; //100% break resistance on certain equipment - unsigned short unstripable_equip; - - // zeroed vars end here. - - int castrate,delayrate,hprate,sprate,dsprate; - int atk_rate; - int speed_rate,hprecov_rate,sprecov_rate; - int matk_rate; - int critical_rate,hit_rate,flee_rate,flee2_rate,def_rate,def2_rate,mdef_rate,mdef2_rate; - - int itemid; - short itemindex; //Used item's index in sd->inventory [Skotlex] - - short catch_target_class; // pet catching, stores a pet class to catch (short now) [zzo] - - short spiritball, spiritball_old; - int spirit_timer[MAX_SKILL_LEVEL]; - - unsigned char potion_success_counter; //Potion successes in row counter - unsigned char mission_count; //Stores the bounty kill count for TK_MISSION - short mission_mobid; //Stores the target mob_id for TK_MISSION - int die_counter; //Total number of times you've died - int devotion[5]; //Stores the account IDs of chars devoted to. - int reg_num; //Number of registries (type numeric) - int regstr_num; //Number of registries (type string) - - struct script_reg *reg; - struct script_regstr *regstr; - - int trade_partner; - struct { - struct { - short index, amount; - } item[10]; - int zeny, weight; - } deal; - - int party_invite,party_invite_account; - int adopt_invite; // Adoption - - int guild_invite,guild_invite_account; - int guild_emblem_id,guild_alliance,guild_alliance_account; - short guild_x,guild_y; // For guildmate position display. [Skotlex] should be short [zzo] - int guildspy; // [Syrus22] - int partyspy; // [Syrus22] - - int vender_id; - int vend_num; - char message[MESSAGE_SIZE]; - struct s_vending vending[MAX_VENDING]; - - struct pet_data *pd; - struct homun_data *hd; // [blackhole89] - - struct{ - int m; //-1 - none, other: map index corresponding to map name. - unsigned short index; //map index - }feel_map[3];// 0 - Sun; 1 - Moon; 2 - Stars - short hate_mob[3]; - - int pvp_timer; - short pvp_point; - unsigned short pvp_rank, pvp_lastusers; - unsigned short pvp_won, pvp_lost; - - char eventqueue[MAX_EVENTQUEUE][50]; - int eventtimer[MAX_EVENTTIMER]; - unsigned short eventcount; // [celest] - - unsigned char change_level; // [celest] - - char fakename[NAME_LENGTH]; // fake names [Valaris] - - int duel_group; // duel vars [LuzZza] - int duel_invite; - - char away_message[128]; // [LuzZza] - - int cashPoints, kafraPoints; - - // Auction System [Zephyrus] - struct { - int index, amount; - } auction; - - // Mail System [Zephyrus] - struct { - short nameid; - int index, amount, zeny; - struct mail_data inbox; - } mail; -}; - -struct npc_timerevent_list { - int timer,pos; -}; -struct npc_label_list { - char name[NAME_LENGTH]; - int pos; -}; -struct npc_item_list { - unsigned int nameid,value; -}; -struct npc_data { - struct block_list bl; - struct unit_data ud; //Because they need to be able to move.... - struct view_data *vd; - struct status_change sc; //They can't have status changes, but.. they want the visual opt values. - struct npc_data *master_nd; - short class_; - short speed; - char name[NAME_LENGTH+1];// display name - char exname[NAME_LENGTH+1];// unique npc name - int chat_id; - unsigned int next_walktime; - - void* chatdb; // pointer to a npc_parse struct (see npc_chat.c) - enum npc_subtype subtype; - union { - struct { - struct script_code *script; - short xs,ys; // OnTouch area radius - int guild_id; - int timer,timerid,timeramount,rid; - unsigned int timertick; - struct npc_timerevent_list *timer_event; - int label_list_num; - struct npc_label_list *label_list; - int src_id; - } scr; - struct { - struct npc_item_list* shop_item; - int count; - } shop; - struct { - short xs,ys; // OnTouch area radius - short x,y; // destination coords - unsigned short mapindex; // destination map - } warp; - } u; -}; - -//For quick linking to a guardian's info. [Skotlex] -struct guardian_data { - int number; //0-MAX_GUARDIANS-1 = Guardians. MAX_GUARDIANS = Emperium. - int guild_id; - int emblem_id; - int guardup_lv; //Level of GD_GUARDUP skill. - char guild_name[NAME_LENGTH]; - struct guild_castle* castle; -}; - // Mob List Held in memory for Dynamic Mobs [Wizputer] // Expanded to specify all mob-related spawn data by [Skotlex] struct spawn_data { @@ -879,139 +247,6 @@ struct spawn_data { }; -struct mob_data { - struct block_list bl; - struct unit_data ud; - struct view_data *vd; - struct status_data status, *base_status; //Second one is in case of leveling up mobs, or tiny/large mobs. - struct status_change sc; - struct mob_db *db; //For quick data access (saves doing mob_db(md->class_) all the time) [Skotlex] - struct barricade_data *barricade; - char name[NAME_LENGTH]; - struct { - unsigned size : 2; //Small/Big monsters. - unsigned ai : 2; //Special ai for summoned monsters. - //0: Normal mob. - //1: Standard summon, attacks mobs. - //2: Alchemist Marine Sphere - //3: Alchemist Summon Flora - } special_state; //Special mob information that does not needs to be zero'ed on mob respawn. - struct { - unsigned skillstate : 8; - unsigned aggressive : 1; //Signals whether the mob AI is in aggressive mode or reactive mode. [Skotlex] - unsigned char steal_flag; //number of steal tries (to prevent steal exploit on mobs with few items) [Lupus] - unsigned steal_coin_flag : 1; - unsigned soul_change_flag : 1; // Celest - unsigned alchemist: 1; - unsigned no_random_walk: 1; - unsigned killer: 1; - unsigned spotted: 1; - unsigned char attacked_count; //For rude attacked. - int provoke_flag; // Celest - } state; - struct guardian_data* guardian_data; - struct { - int id; - unsigned int dmg; - unsigned flag : 1; //0: Normal. 1: Homunc exp - } dmglog[DAMAGELOG_SIZE]; - struct spawn_data *spawn; //Spawn data. - struct item *lootitem; - short class_; - unsigned int tdmg; //Stores total damage given to the mob, for exp calculations. [Skotlex] - int level; - int target_id,attacked_id; - - unsigned int next_walktime,last_thinktime,last_linktime,last_pcneartime; - short move_fail_count; - short lootitem_count; - short min_chase; - - int deletetimer; - int master_id,master_dist; - - struct npc_data *nd; - unsigned short callback_flag; - - short skillidx; - unsigned int skilldelay[MAX_MOBSKILL]; - char npc_event[50]; -}; - -/* [blackhole89] */ -struct homun_data { - struct block_list bl; - struct unit_data ud; - struct view_data *vd; - struct status_data base_status, battle_status; - struct status_change sc; - struct regen_data regen; - struct s_homunculus_db *homunculusDB; //[orn] - struct s_homunculus homunculus ; //[orn] - - struct map_session_data *master; //pointer back to its master - int hungry_timer; //[orn] - unsigned int exp_next; - char blockskill[MAX_SKILL]; // [orn] -}; - -struct pet_data { - struct block_list bl; - struct unit_data ud; - struct view_data vd; - struct s_pet pet; - struct status_data status; - struct mob_db *db; - struct s_pet_db *petDB; - int pet_hungry_timer; - int target_id; - struct { - unsigned skillbonus : 1; - } state; - int move_fail_count; - unsigned int next_walktime,last_thinktime; - short rate_fix; //Support rate as modified by intimacy (1000 = 100%) [Skotlex] - - struct pet_recovery { //Stat recovery - unsigned short type; //Status Change id - unsigned short delay; //How long before curing (secs). - int timer; - } *recovery; //[Valaris] / Reimplemented by [Skotlex] - - struct pet_bonus { - unsigned short type; //bStr, bVit? - unsigned short val; //Qty - unsigned short duration; //in secs - unsigned short delay; //Time before recasting (secs) - int timer; - } *bonus; //[Valaris] / Reimplemented by [Skotlex] - - struct pet_skill_attack { //Attack Skill - unsigned short id; - unsigned short lv; - unsigned short div_; //0 = Normal skill. >0 = Fixed damage (lv), fixed div_. - unsigned short rate; //Base chance of skill ocurrance (10 = 10% of attacks) - unsigned short bonusrate; //How being 100% loyal affects cast rate (10 = At 1000 intimacy->rate+10% - } *a_skill; //[Skotlex] - - struct pet_skill_support { //Support Skill - unsigned short id; - unsigned short lv; - unsigned short hp; //Max HP% for skill to trigger (50 -> 50% for Magnificat) - unsigned short sp; //Max SP% for skill to trigger (100 = no check) - unsigned short delay; //Time (secs) between being able to recast. - int timer; - } *s_skill; //[Skotlex] - - struct pet_loot { - struct item *item; - unsigned short count; - unsigned short weight; - unsigned short max; - } *loot; //[Valaris] / Rewritten by [Skotlex] - - struct map_session_data *msd; -}; struct flooritem_data { struct block_list bl; @@ -1022,19 +257,6 @@ struct flooritem_data { struct item item_data; }; -struct chat_data { - struct block_list bl; // data for this map object - char title[CHATROOM_TITLE_SIZE]; // room title - char pass[CHATROOM_PASS_SIZE]; // password - bool pub; // private/public flag - uint8 users; // current user count - uint8 limit; // join limit - uint8 trigger; // number of users needed to trigger event - struct map_session_data* usersd[20]; - struct block_list* owner; - char npc_event[50]; -}; - enum _sp { SP_SPEED,SP_BASEEXP,SP_JOBEXP,SP_KARMA,SP_MANNER,SP_HP,SP_MAXHP,SP_SP, // 0-7 SP_MAXSP,SP_STATUSPOINT,SP_0a,SP_BASELEVEL,SP_SKILLPOINT,SP_STR,SP_AGI,SP_VIT, // 8-15 diff --git a/src/map/mercenary.h b/src/map/mercenary.h index 95193df0a..2e90786cd 100644 --- a/src/map/mercenary.h +++ b/src/map/mercenary.h @@ -4,6 +4,9 @@ #ifndef _MERCENARY_H_ #define _MERCENARY_H_ +#include "status.h" // struct status_data, struct status_change +#include "unit.h" // struct unit_data + struct s_homunculus_db { int base_class, evo_class; char name[NAME_LENGTH]; @@ -24,6 +27,24 @@ enum { SP_HUNGRY = 0x200 }; + +struct homun_data { + struct block_list bl; + struct unit_data ud; + struct view_data *vd; + struct status_data base_status, battle_status; + struct status_change sc; + struct regen_data regen; + struct s_homunculus_db *homunculusDB; //[orn] + struct s_homunculus homunculus ; //[orn] + + struct map_session_data *master; //pointer back to its master + int hungry_timer; //[orn] + unsigned int exp_next; + char blockskill[MAX_SKILL]; // [orn] +}; + + #define homdb_checkid(id) (id >= HM_CLASS_BASE && id <= HM_CLASS_MAX) // merc_is_hom_alive(struct homun_data *) diff --git a/src/map/mob.c b/src/map/mob.c index f03b9ac9d..bd9ed5d43 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -17,6 +17,7 @@ #include "clif.h" #include "intif.h" #include "pc.h" +#include "pet.h" #include "status.h" #include "mob.h" #include "mercenary.h" //[orn] diff --git a/src/map/mob.h b/src/map/mob.h index fb4d06db4..b8a8a2394 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -5,8 +5,11 @@ #define _MOB_H_ #include "../common/mmo.h" // struct item -#include "unit.h" // unit_stop_walking(), unit_stop_attack() +#include "guild.h" // struct guardian_data #include "map.h" // struct status_data, struct view_data, struct mob_skill +#include "status.h" // struct status data, struct status_change +#include "unit.h" // unit_stop_walking(), unit_stop_attack() + #define MAX_RANDOMMONSTER 4 #define MAX_MOB_RACE_DB 6 @@ -80,6 +83,67 @@ struct mob_db { struct spawn_info spawn[10]; }; +struct mob_data { + struct block_list bl; + struct unit_data ud; + struct view_data *vd; + struct status_data status, *base_status; //Second one is in case of leveling up mobs, or tiny/large mobs. + struct status_change sc; + struct mob_db *db; //For quick data access (saves doing mob_db(md->class_) all the time) [Skotlex] + struct barricade_data *barricade; + char name[NAME_LENGTH]; + struct { + unsigned size : 2; //Small/Big monsters. + unsigned ai : 2; //Special ai for summoned monsters. + //0: Normal mob. + //1: Standard summon, attacks mobs. + //2: Alchemist Marine Sphere + //3: Alchemist Summon Flora + } special_state; //Special mob information that does not needs to be zero'ed on mob respawn. + struct { + unsigned skillstate : 8; + unsigned aggressive : 1; //Signals whether the mob AI is in aggressive mode or reactive mode. [Skotlex] + unsigned char steal_flag; //number of steal tries (to prevent steal exploit on mobs with few items) [Lupus] + unsigned steal_coin_flag : 1; + unsigned soul_change_flag : 1; // Celest + unsigned alchemist: 1; + unsigned no_random_walk: 1; + unsigned killer: 1; + unsigned spotted: 1; + unsigned char attacked_count; //For rude attacked. + int provoke_flag; // Celest + } state; + struct guardian_data* guardian_data; + struct { + int id; + unsigned int dmg; + unsigned flag : 1; //0: Normal. 1: Homunc exp + } dmglog[DAMAGELOG_SIZE]; + struct spawn_data *spawn; //Spawn data. + struct item *lootitem; + short class_; + unsigned int tdmg; //Stores total damage given to the mob, for exp calculations. [Skotlex] + int level; + int target_id,attacked_id; + + unsigned int next_walktime,last_thinktime,last_linktime,last_pcneartime; + short move_fail_count; + short lootitem_count; + short min_chase; + + int deletetimer; + int master_id,master_dist; + + struct npc_data *nd; + unsigned short callback_flag; + + short skillidx; + unsigned int skilldelay[MAX_MOBSKILL]; + char npc_event[50]; +}; + + + enum { MST_TARGET = 0, MST_RANDOM, //Random Target! diff --git a/src/map/npc.h b/src/map/npc.h index d2e87df5d..f75ede9c5 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -4,11 +4,66 @@ #ifndef _NPC_H_ #define _NPC_H_ -//#include "map.h" +#include "map.h" // struct block_list +#include "status.h" // struct status_change +#include "unit.h" // struct unit_data struct block_list; struct npc_data; struct view_data; + +struct npc_timerevent_list { + int timer,pos; +}; +struct npc_label_list { + char name[NAME_LENGTH]; + int pos; +}; +struct npc_item_list { + unsigned int nameid,value; +}; + +struct npc_data { + struct block_list bl; + struct unit_data ud; //Because they need to be able to move.... + struct view_data *vd; + struct status_change sc; //They can't have status changes, but.. they want the visual opt values. + struct npc_data *master_nd; + short class_; + short speed; + char name[NAME_LENGTH+1];// display name + char exname[NAME_LENGTH+1];// unique npc name + int chat_id; + unsigned int next_walktime; + + void* chatdb; // pointer to a npc_parse struct (see npc_chat.c) + enum npc_subtype subtype; + union { + struct { + struct script_code *script; + short xs,ys; // OnTouch area radius + int guild_id; + int timer,timerid,timeramount,rid; + unsigned int timertick; + struct npc_timerevent_list *timer_event; + int label_list_num; + struct npc_label_list *label_list; + int src_id; + } scr; + struct { + struct npc_item_list* shop_item; + int count; + } shop; + struct { + short xs,ys; // OnTouch area radius + short x,y; // destination coords + unsigned short mapindex; // destination map + } warp; + } u; +}; + + + #define START_NPC_NUM 110000000 #define WARP_CLASS 45 diff --git a/src/map/npc_chat.c b/src/map/npc_chat.c index 5094a1d90..44c9ce82e 100644 --- a/src/map/npc_chat.c +++ b/src/map/npc_chat.c @@ -9,7 +9,9 @@ #include "../common/showmsg.h" #include "../common/strlib.h" -#include "map.h" // struct mob_data, struct npc_data +#include "mob.h" // struct mob_data +#include "npc.h" // struct npc_data +#include "pc.h" // struct map_session_data #include "script.h" // set_var() #include "pcre.h" diff --git a/src/map/party.h b/src/map/party.h index 54f55a6c2..e45b62c1e 100644 --- a/src/map/party.h +++ b/src/map/party.h @@ -4,15 +4,33 @@ #ifndef _PARTY_H_ #define _PARTY_H_ -//#include "map.h" +#include "../common/mmo.h" // struct party struct block_list; struct map_session_data; struct party; -struct party_data; struct item; #include +struct party_member_data { + struct map_session_data *sd; + unsigned int hp; //For HP,x,y refreshing. + unsigned short x, y; +}; + +struct party_data { + struct party party; + struct party_member_data data[MAX_PARTY]; + uint8 itemc; //For item distribution, position of last picker in party + struct { + unsigned monk : 1; //There's at least one monk in party? + unsigned sg : 1; //There's at least one Star Gladiator in party? + unsigned snovice :1; //There's a Super Novice + unsigned tk : 1; //There's a taekwon + } state; +}; + + extern int party_share_level; void do_init_party(void); diff --git a/src/map/path.h b/src/map/path.h index 761d9de26..1dc024655 100644 --- a/src/map/path.h +++ b/src/map/path.h @@ -4,6 +4,21 @@ #ifndef _PATH_H_ #define _PATH_H_ +#include "map.h" // enum cell_chk + +#define MAX_WALKPATH 32 + +struct walkpath_data { + unsigned char path_len,path_pos; + unsigned char path[MAX_WALKPATH]; +}; + +struct shootpath_data { + int rx,ry,len; + int x[MAX_WALKPATH]; + int y[MAX_WALKPATH]; +}; + // calculates destination cell for knockback int path_blownpos(int m,int x0,int y0,int dx,int dy,int count); diff --git a/src/map/pc.h b/src/map/pc.h index 7942aab9d..c55e7f2cc 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -7,9 +7,340 @@ #include "../common/mmo.h" // JOB_*, MAX_FAME_LIST, struct fame_list, struct mmo_charstatus #include "../common/timer.h" // INVALID_TIMER #include "battle.h" // battle_config -#include "map.h" // JOB_*, struct map_session_data -#include "status.h" // OPTION_* +#include "itemdb.h" // MAX_ITEMGROUP +#include "map.h" // RC_MAX +#include "pc.h" // struct map_session_data +#include "script.h" // struct script_reg, struct script_regstr +#include "status.h" // OPTION_*, struct weapon_atk #include "unit.h" // unit_stop_attack(), unit_stop_walking() +#include "vending.h" // struct s_vending + +#define MAX_PC_BONUS 10 + +struct weapon_data { + int atkmods[3]; + // all the variables except atkmods get zero'ed in each call of status_calc_pc + // NOTE: if you want to add a non-zeroed variable, you need to update the memset call + // in status_calc_pc as well! All the following are automatically zero'ed. [Skotlex] + int overrefine; + int star; + int ignore_def_ele; + int ignore_def_race; + int def_ratio_atk_ele; + int def_ratio_atk_race; + int addele[ELE_MAX]; + int addrace[RC_MAX]; + int addrace2[RC_MAX]; + int addsize[3]; + + struct drain_data { + short rate; + short per; + short value; + unsigned type:1; + } hp_drain[RC_MAX], sp_drain[RC_MAX]; + + struct { + short class_, rate; + } add_dmg[MAX_PC_BONUS]; +}; + +struct map_session_data { + struct block_list bl; + struct unit_data ud; + struct view_data vd; + struct status_data base_status, battle_status; + struct status_change sc; + struct regen_data regen; + struct regen_data_sub sregen, ssregen; + //NOTE: When deciding to add a flag to state or special_state, take into consideration that state is preserved in + //status_calc_pc, while special_state is recalculated in each call. [Skotlex] + struct { + unsigned active : 1; //Marks active player (not active is logging in/out, or changing map servers) + unsigned menu_or_input : 1;// if a script is waiting for feedback from the player + unsigned dead_sit : 2; + unsigned lr_flag : 2; + unsigned connect_new : 1; + unsigned arrow_atk : 1; + unsigned skill_flag : 1; + unsigned gangsterparadise : 1; + unsigned rest : 1; + unsigned storage_flag : 2; //0: closed, 1: Normal Storage open, 2: guild storage open [Skotlex] + unsigned snovice_call_flag : 2; //Summon Angel (stage 1~3) + unsigned snovice_dead_flag : 2; //Explosion spirits on death: 0 off, 1 active, 2 used. + unsigned abra_flag : 1; // Abracadabra bugfix by Aru + unsigned autotrade : 1; //By Fantik + unsigned reg_dirty : 3; //By Skotlex (marks whether registry variables have been saved or not yet) + unsigned showdelay :1; + unsigned showexp :1; + unsigned showzeny :1; + unsigned mainchat :1; //[LuzZza] + unsigned noask :1; // [LuzZza] + unsigned trading :1; //[Skotlex] is 1 only after a trade has started. + unsigned deal_locked :2; //1: Clicked on OK. 2: Clicked on TRADE + unsigned monster_ignore :1; // for monsters to ignore a character [Valaris] [zzo] + unsigned size :2; // for tiny/large types + unsigned night :1; //Holds whether or not the player currently has the SI_NIGHT effect on. [Skotlex] + unsigned blockedmove :1; + unsigned using_fake_npc :1; + unsigned rewarp :1; //Signals that a player should warp as soon as he is done loading a map. [Skotlex] + unsigned killer : 1; + unsigned killable : 1; + unsigned doridori : 1; + unsigned ignoreAll : 1; + unsigned short autoloot; + unsigned short autolootid; // [Zephyrus] + unsigned noks : 3; // [Zeph Kill Steal Protection] + bool changemap; + struct guild *gmaster_flag; + } state; + struct { + unsigned char no_weapon_damage, no_magic_damage, no_misc_damage; + unsigned restart_full_recover : 1; + unsigned no_castcancel : 1; + unsigned no_castcancel2 : 1; + unsigned no_sizefix : 1; + unsigned no_gemstone : 1; + unsigned intravision : 1; // Maya Purple Card effect [DracoRPG] + unsigned perfect_hiding : 1; // [Valaris] + unsigned no_knockback : 1; + unsigned bonus_coma : 1; + } special_state; + int login_id1, login_id2; + unsigned short class_; //This is the internal job ID used by the map server to simplify comparisons/queries/etc. [Skotlex] + + int packet_ver; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 ... 18 + struct mmo_charstatus status; + struct registry save_reg; + + struct item_data* inventory_data[MAX_INVENTORY]; // direct pointers to itemdb entries (faster than doing item_id lookups) + short equip_index[11]; + unsigned int weight,max_weight; + int cart_weight,cart_num; + int fd; + unsigned short mapindex; + unsigned short prev_speed,prev_adelay; + unsigned char head_dir; //0: Look forward. 1: Look right, 2: Look left. + unsigned int client_tick; + int npc_id,areanpc_id,npc_shopid; + int npc_item_flag; //Marks the npc_id with which you can use items during interactions with said npc (see script command enable_itemuse) + int npc_menu; + int npc_amount; + struct script_state *st; + char npc_str[CHATBOX_SIZE]; // for passing npc input box text to script engine + int npc_timer_id; //For player attached npc timers. [Skotlex] + unsigned int chatID; + time_t idletime; + + struct{ + char name[NAME_LENGTH]; + } ignore[MAX_IGNORE_LIST]; + + int followtimer; // [MouseJstr] + int followtarget; + + time_t emotionlasttime; // to limit flood with emotion packets + + short skillitem,skillitemlv; + short skillid_old,skilllv_old; + short skillid_dance,skilllv_dance; + char blockskill[MAX_SKILL]; // [celest] + int cloneskill_id; + int menuskill_id, menuskill_val; + + int invincible_timer; + unsigned int canlog_tick; + unsigned int canuseitem_tick; // [Skotlex] + unsigned int cantalk_tick; + unsigned int cansendmail_tick; // [Mail System Flood Protection] + unsigned int ks_floodprotect_tick; // [Kill Steal Protection] + + short weapontype1,weapontype2; + short disguise; // [Valaris] + + struct weapon_data right_weapon, left_weapon; + + // here start arrays to be globally zeroed at the beginning of status_calc_pc() + int param_bonus[6],param_equip[6]; //Stores card/equipment bonuses. + int subele[ELE_MAX]; + int subrace[RC_MAX]; + int subrace2[RC_MAX]; + int subsize[3]; + int reseff[SC_COMMON_MAX-SC_COMMON_MIN+1]; + int weapon_coma_ele[ELE_MAX]; + int weapon_coma_race[RC_MAX]; + int weapon_atk[16]; + int weapon_atk_rate[16]; + int arrow_addele[ELE_MAX]; + int arrow_addrace[RC_MAX]; + int arrow_addsize[3]; + int magic_addele[ELE_MAX]; + int magic_addrace[RC_MAX]; + int magic_addsize[3]; + int critaddrace[RC_MAX]; + int expaddrace[RC_MAX]; + int ignore_mdef[RC_MAX]; + int itemgrouphealrate[MAX_ITEMGROUP]; + short sp_gain_race[RC_MAX]; + // zeroed arrays end here. + // zeroed structures start here + struct s_autospell{ + short id, lv, rate, card_id, flag; + } autospell[15], autospell2[15]; + struct s_addeffect{ + short id, rate, arrow_rate; + unsigned char flag; + } addeff[MAX_PC_BONUS], addeff2[MAX_PC_BONUS]; + struct { //skillatk raises bonus dmg% of skills, skillheal increases heal%, skillblown increases bonus blewcount for some skills. + unsigned short id; + short val; + } skillatk[MAX_PC_BONUS], skillheal[5], skillblown[MAX_PC_BONUS], skillcast[MAX_PC_BONUS]; + struct { + short value; + int rate; + int tick; + } hp_loss, sp_loss, hp_regen, sp_regen; + struct { + short class_, rate; + } add_def[MAX_PC_BONUS], add_mdef[MAX_PC_BONUS], + add_mdmg[MAX_PC_BONUS]; + struct s_add_drop { + short id, group; + int race, rate; + } add_drop[MAX_PC_BONUS]; + struct { + int nameid; + int rate; + } itemhealrate[MAX_PC_BONUS]; + // zeroed structures end here + // manually zeroed structures start here. + struct s_autoscript { + unsigned short rate, flag; + struct script_code *script; + } autoscript[10], autoscript2[10]; //Auto script on attack, when attacked + // manually zeroed structures end here. + // zeroed vars start here. + int arrow_atk,arrow_ele,arrow_cri,arrow_hit; + int nsshealhp,nsshealsp; + int critical_def,double_rate; + int long_attack_atk_rate; //Long range atk rate, not weapon based. [Skotlex] + int near_attack_def_rate,long_attack_def_rate,magic_def_rate,misc_def_rate; + int ignore_mdef_ele; + int ignore_mdef_race; + int perfect_hit; + int perfect_hit_add; + int get_zeny_rate; + int get_zeny_num; //Added Get Zeny Rate [Skotlex] + int double_add_rate; + int short_weapon_damage_return,long_weapon_damage_return; + int magic_damage_return; // AppleGirl Was Here + int random_attack_increase_add,random_attack_increase_per; // [Valaris] + int break_weapon_rate,break_armor_rate; + int crit_atk_rate; + int classchange; // [Valaris] + int speed_add_rate, aspd_add; + unsigned int setitem_hash, setitem_hash2; //Split in 2 because shift operations only work on int ranges. [Skotlex] + + short splash_range, splash_add_range; + short add_steal_rate; + short sp_gain_value, hp_gain_value; + short sp_vanish_rate; + short sp_vanish_per; + unsigned short unbreakable; // chance to prevent ANY equipment breaking [celest] + unsigned short unbreakable_equip; //100% break resistance on certain equipment + unsigned short unstripable_equip; + + // zeroed vars end here. + + int castrate,delayrate,hprate,sprate,dsprate; + int atk_rate; + int speed_rate,hprecov_rate,sprecov_rate; + int matk_rate; + int critical_rate,hit_rate,flee_rate,flee2_rate,def_rate,def2_rate,mdef_rate,mdef2_rate; + + int itemid; + short itemindex; //Used item's index in sd->inventory [Skotlex] + + short catch_target_class; // pet catching, stores a pet class to catch (short now) [zzo] + + short spiritball, spiritball_old; + int spirit_timer[MAX_SKILL_LEVEL]; + + unsigned char potion_success_counter; //Potion successes in row counter + unsigned char mission_count; //Stores the bounty kill count for TK_MISSION + short mission_mobid; //Stores the target mob_id for TK_MISSION + int die_counter; //Total number of times you've died + int devotion[5]; //Stores the account IDs of chars devoted to. + int reg_num; //Number of registries (type numeric) + int regstr_num; //Number of registries (type string) + + struct script_reg *reg; + struct script_regstr *regstr; + + int trade_partner; + struct { + struct { + short index, amount; + } item[10]; + int zeny, weight; + } deal; + + int party_invite,party_invite_account; + int adopt_invite; // Adoption + + int guild_invite,guild_invite_account; + int guild_emblem_id,guild_alliance,guild_alliance_account; + short guild_x,guild_y; // For guildmate position display. [Skotlex] should be short [zzo] + int guildspy; // [Syrus22] + int partyspy; // [Syrus22] + + int vender_id; + int vend_num; + char message[MESSAGE_SIZE]; + struct s_vending vending[MAX_VENDING]; + + struct pet_data *pd; + struct homun_data *hd; // [blackhole89] + + struct{ + int m; //-1 - none, other: map index corresponding to map name. + unsigned short index; //map index + }feel_map[3];// 0 - Sun; 1 - Moon; 2 - Stars + short hate_mob[3]; + + int pvp_timer; + short pvp_point; + unsigned short pvp_rank, pvp_lastusers; + unsigned short pvp_won, pvp_lost; + + char eventqueue[MAX_EVENTQUEUE][50]; + int eventtimer[MAX_EVENTTIMER]; + unsigned short eventcount; // [celest] + + unsigned char change_level; // [celest] + + char fakename[NAME_LENGTH]; // fake names [Valaris] + + int duel_group; // duel vars [LuzZza] + int duel_invite; + + char away_message[128]; // [LuzZza] + + int cashPoints, kafraPoints; + + // Auction System [Zephyrus] + struct { + int index, amount; + } auction; + + // Mail System [Zephyrus] + struct { + short nameid; + int index, amount, zeny; + struct mail_data inbox; + } mail; +}; + //Update this max as necessary. 54 is the value needed for Super Baby currently #define MAX_SKILL_TREE 54 @@ -104,6 +435,7 @@ struct duel { int max_players_limit; }; +#define MAX_DUEL 1024 extern struct duel duel_list[MAX_DUEL]; extern int duel_count; diff --git a/src/map/pet.h b/src/map/pet.h index b5dda0944..eeb48f018 100644 --- a/src/map/pet.h +++ b/src/map/pet.h @@ -33,6 +33,67 @@ extern struct s_pet_db pet_db[MAX_PET_DB]; enum { PET_CLASS,PET_CATCH,PET_EGG,PET_EQUIP,PET_FOOD }; + +struct pet_data { + struct block_list bl; + struct unit_data ud; + struct view_data vd; + struct s_pet pet; + struct status_data status; + struct mob_db *db; + struct s_pet_db *petDB; + int pet_hungry_timer; + int target_id; + struct { + unsigned skillbonus : 1; + } state; + int move_fail_count; + unsigned int next_walktime,last_thinktime; + short rate_fix; //Support rate as modified by intimacy (1000 = 100%) [Skotlex] + + struct pet_recovery { //Stat recovery + unsigned short type; //Status Change id + unsigned short delay; //How long before curing (secs). + int timer; + } *recovery; //[Valaris] / Reimplemented by [Skotlex] + + struct pet_bonus { + unsigned short type; //bStr, bVit? + unsigned short val; //Qty + unsigned short duration; //in secs + unsigned short delay; //Time before recasting (secs) + int timer; + } *bonus; //[Valaris] / Reimplemented by [Skotlex] + + struct pet_skill_attack { //Attack Skill + unsigned short id; + unsigned short lv; + unsigned short div_; //0 = Normal skill. >0 = Fixed damage (lv), fixed div_. + unsigned short rate; //Base chance of skill ocurrance (10 = 10% of attacks) + unsigned short bonusrate; //How being 100% loyal affects cast rate (10 = At 1000 intimacy->rate+10% + } *a_skill; //[Skotlex] + + struct pet_skill_support { //Support Skill + unsigned short id; + unsigned short lv; + unsigned short hp; //Max HP% for skill to trigger (50 -> 50% for Magnificat) + unsigned short sp; //Max SP% for skill to trigger (100 = no check) + unsigned short delay; //Time (secs) between being able to recast. + int timer; + } *s_skill; //[Skotlex] + + struct pet_loot { + struct item *item; + unsigned short count; + unsigned short weight; + unsigned short max; + } *loot; //[Valaris] / Rewritten by [Skotlex] + + struct map_session_data *msd; +}; + + + int pet_create_egg(struct map_session_data *sd, int item_id); int pet_hungry_val(struct pet_data *pd); int pet_target_check(struct map_session_data *sd,struct block_list *bl,int type); diff --git a/src/map/script.h b/src/map/script.h index 036036ccc..b9e5fdb01 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -101,6 +101,16 @@ struct script_state { } sleep; }; +struct script_reg { + int index; + int data; +}; + +struct script_regstr { + int index; + char* data; +}; + enum script_parse_options { SCRIPT_USE_LABEL_DB = 0x1,// records labels in scriptlabel_db SCRIPT_IGNORE_EXTERNAL_BRACKETS = 0x2,// ignores the check for {} brackets around the script diff --git a/src/map/skill.h b/src/map/skill.h index 73e1daf4f..2a1dd6a70 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -4,8 +4,13 @@ #ifndef _SKILL_H_ #define _SKILL_H_ -#include "../common/mmo.h" // MAX_SKILL -#include "map.h" // MAX_SKILL_LEVEL, ... +#include "../common/mmo.h" // MAX_SKILL, struct square +#include "map.h" // struct block_list +struct map_session_data; +struct homun_data; +struct skill_unit; +struct skill_unit_group; +struct status_change_entry; #define MAX_SKILL_DB MAX_SKILL #define MAX_SKILL_PRODUCE_DB 150 @@ -13,6 +18,8 @@ #define MAX_SKILL_ARROW_DB 150 #define MAX_SKILL_ABRA_DB 350 +#define MAX_SKILL_LEVEL 100 + //Constants to identify the skill's inf value: #define INF_ATTACK_SKILL 1 #define INF_GROUND_SKILL 2 @@ -99,6 +106,60 @@ struct s_skill_unit_layout { int dy[MAX_SKILL_UNIT_COUNT]; }; +#define MAX_SKILLTIMERSKILL 15 +struct skill_timerskill { + int timer; + int src_id; + int target_id; + int map; + short x,y; + short skill_id,skill_lv; + int type; // a BF_ type (NOTE: some places use this as general-purpose storage...) + int flag; +}; + +#define MAX_SKILLUNITGROUP 25 +struct skill_unit_group { + int src_id; + int party_id; + int guild_id; + int map; + int target_flag; //Holds BCT_* flag for battle_check_target + int bl_flag; //Holds BL_* flag for map_foreachin* functions + unsigned int tick; + int limit,interval; + + short skill_id,skill_lv; + int val1,val2,val3; + char *valstr; + int unit_id; + int group_id; + int unit_count,alive_count; + struct skill_unit *unit; + struct { + unsigned ammo_consume : 1; + unsigned magic_power : 1; + unsigned song_dance : 2; //0x1 Song/Dance, 0x2 Ensemble + } state; +}; + +struct skill_unit { + struct block_list bl; + + struct skill_unit_group *group; + + int limit; + int val1,val2; + short alive,range; +}; + +#define MAX_SKILLUNITGROUPTICKSET 25 +struct skill_unit_group_tickset { + unsigned int tick; + int id; +}; + + enum { UF_DEFNOTENEMY = 0x0001, // If 'defunit_not_enemy' is set, the target is changed to 'friend' UF_NOREITERATION = 0x0002, // Spell cannot be stacked @@ -140,11 +201,6 @@ extern struct s_skill_abra_db skill_abra_db[MAX_SKILL_ABRA_DB]; extern int enchant_eff[5]; extern int deluge_eff[5]; -struct block_list; -struct map_session_data; -struct skill_unit; -struct skill_unit_group; - int do_init_skill(void); int do_final_skill(void); @@ -213,8 +269,7 @@ int skill_delunitgroup(struct block_list *src, struct skill_unit_group *group); int skill_clear_unitgroup(struct block_list *src); int skill_clear_group(struct block_list *bl, int flag); -int skill_unit_ondamaged(struct skill_unit *src,struct block_list *bl, - int damage,unsigned int tick); +int skill_unit_ondamaged(struct skill_unit *src,struct block_list *bl,int damage,unsigned int tick); int skill_castfix( struct block_list *bl, int skill_id, int skill_lv); int skill_castfix_sc( struct block_list *bl, int time); diff --git a/src/map/status.h b/src/map/status.h index 75b558d79..8ec4fb01e 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -4,7 +4,6 @@ #ifndef _STATUS_H_ #define _STATUS_H_ -//#include "map.h" struct block_list; struct mob_data; struct pet_data; @@ -17,6 +16,7 @@ struct status_change; extern unsigned long StatusChangeFlagTable[]; + // Status changes listing. These code are for use by the server. enum sc_type { //First we enumerate common status ailments which are often used around. @@ -583,6 +583,106 @@ enum { //Define to determine who has regen #define BL_REGEN (BL_PC|BL_HOM) + +//Basic damage info of a weapon +//Required because players have two of these, one in status_data +//and another for their left hand weapon. +struct weapon_atk { + unsigned short atk, atk2; + unsigned short range; + unsigned char ele; +}; + + +//For holding basic status (which can be modified by status changes) +struct status_data { + unsigned int + hp, sp, + max_hp, max_sp; + unsigned short + str, agi, vit, int_, dex, luk, + batk, + matk_min, matk_max, + speed, + amotion, adelay, dmotion, + mode; + short + hit, flee, cri, flee2, + def2, mdef2, + aspd_rate; + unsigned char + def_ele, ele_lv, + size, race; + signed char + def, mdef; + struct weapon_atk rhw, lhw; //Right Hand/Left Hand Weapon. +}; + +//Additional regen data that only players have. +struct regen_data_sub { + unsigned short + hp,sp; + + //tick accumulation before healing. + struct { + unsigned int hp,sp; + } tick; + + //Regen rates (where every 1 means +100% regen) + struct { + unsigned char hp,sp; + } rate; +}; + +struct regen_data { + + unsigned short flag; //Marks what stuff you may heal or not. + unsigned short + hp,sp,shp,ssp; + + //tick accumulation before healing. + struct { + unsigned int hp,sp,shp,ssp; + } tick; + + //Regen rates (where every 1 means +100% regen) + struct { + unsigned char + hp,sp,shp,ssp; + } rate; + + struct { + unsigned walk:1; //Can you regen even when walking? + unsigned gc:1; //Tags when you should have double regen due to GVG castle + unsigned overweight :2; //overweight state (1: 50%, 2: 90%) + unsigned block :2; //Block regen flag (1: Hp, 2: Sp) + } state; + + //skill-regen, sitting-skill-regen (since not all chars with regen need it) + struct regen_data_sub *sregen, *ssregen; +}; + +struct status_change_entry { + int timer; + int val1,val2,val3,val4; +}; + +struct status_change { + unsigned int option;// effect state (bitfield) + unsigned int opt3;// skill state (bitfield) + unsigned short opt1;// body state + unsigned short opt2;// health state (bitfield) + unsigned char count; + //TODO: See if it is possible to implement the following SC's without requiring extra parameters while the SC is inactive. + unsigned char jb_flag; //Joint Beat type flag + unsigned short mp_matk_min, mp_matk_max; //Previous matk min/max for ground spells (Amplify magic power) + int sg_id; //ID of the previous Storm gust that hit you + unsigned char sg_counter; //Storm gust counter (previous hits from storm gust) + struct status_change_entry *data[SC_MAX]; +}; + + + int status_damage(struct block_list *src,struct block_list *target,int hp,int sp, int walkdelay, int flag); //Define for standard HP damage attacks. #define status_fix_damage(src, target, hp, walkdelay) status_damage(src, target, hp, 0, walkdelay, 0) diff --git a/src/map/unit.h b/src/map/unit.h index 7575d3f5e..192f1c7e8 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -9,6 +9,56 @@ struct block_list; struct unit_data; struct map_session_data; +#include "map.h" // struct block_list +#include "path.h" // struct walkpath_data +#include "skill.h" // struct skill_timerskill, struct skill_unit_group, struct skill_unit_group_tickset + +struct unit_data { + struct block_list *bl; + struct walkpath_data walkpath; + struct skill_timerskill *skilltimerskill[MAX_SKILLTIMERSKILL]; + struct skill_unit_group *skillunit[MAX_SKILLUNITGROUP]; + struct skill_unit_group_tickset skillunittick[MAX_SKILLUNITGROUPTICKSET]; + short attacktarget_lv; + short to_x,to_y; + short skillx,skilly; + short skillid,skilllv; + int skilltarget; + int skilltimer; + int target; + int attacktimer; + int walktimer; + int chaserange; + unsigned int attackabletime; + unsigned int canact_tick; + unsigned int canmove_tick; + uint8 dir; + unsigned char walk_count; + struct { + unsigned change_walk_target : 1 ; + unsigned skillcastcancel : 1 ; + unsigned attack_continue : 1 ; + unsigned walk_easy : 1 ; + unsigned running : 1; + unsigned speed_changed : 1; + } state; +}; + +struct view_data { + unsigned short + class_, + weapon, + shield, //Or left-hand weapon. + head_top, + head_mid, + head_bottom, + hair_style, + hair_color, + cloth_color; + char sex; + unsigned dead_sit : 2; +}; + // PC, MOB, PET に共通する処理を1つにまとめる計画 // 歩行開始 diff --git a/src/map/vending.h b/src/map/vending.h index e65f55e93..a95d6abf5 100644 --- a/src/map/vending.h +++ b/src/map/vending.h @@ -8,6 +8,12 @@ //#include "map.h" struct map_session_data; +struct s_vending { + short index; + short amount; + unsigned int value; +}; + void vending_closevending(struct map_session_data* sd); void vending_openvending(struct map_session_data* sd, const char* message, bool flag, const uint8* data, int count); void vending_vendinglistreq(struct map_session_data* sd, int id); -- cgit v1.2.3-70-g09d2 From 9bcd4b05f059e887a6f8e165d42382b5aeef77ef Mon Sep 17 00:00:00 2001 From: FlavioJS Date: Wed, 2 Apr 2008 01:03:31 +0000 Subject: * Added more debug information to track the double remove_map's git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@12457 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/unit.c | 18 +++++++++++++++--- src/map/unit.h | 3 ++- 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'src/map/unit.h') diff --git a/src/map/unit.c b/src/map/unit.c index afcd999b8..ea4cda9f5 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1577,7 +1577,7 @@ int unit_changeviewsize(struct block_list *bl,short size) * Otherwise it is assumed bl is being warped. * On-Kill specific stuff is not performed here, look at status_damage for that. *------------------------------------------*/ -int unit_remove_map(struct block_list *bl, int clrtype) +int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int line, const char* func) { struct unit_data *ud = unit_bl2ud(bl); struct status_change *sc = status_get_sc(bl); @@ -1691,17 +1691,29 @@ int unit_remove_map(struct block_list *bl, int clrtype) if( map[bl->m].users <= 0 || sd->state.debug_remove_map ) {// this is only place where map users is decreased, if the mobs were removed too soon then this function was executed too many times [FlavioJS] + if( sd->debug_file == NULL || !(sd->state.debug_remove_map) ) + { + sd->debug_file = ""; + sd->debug_line = 0; + sd->debug_func = ""; + } ShowDebug("unit_remove_map: unexpected state when removing player AID/CID:%d/%d" " (active=%d connect_new=%d rewarp=%d changemap=%d debug_remove_map=%d)" - " from map=%s (users=%d). Please report this!!!\n", + " from map=%s (users=%d)." + " Previous call from %s:%d(%s), current call from %s:%d(%s)." + " Please report this!!!\n", sd->status.account_id, sd->status.char_id, sd->state.active, sd->state.connect_new, sd->state.rewarp, sd->state.changemap, sd->state.debug_remove_map, - map[bl->m].name, map[bl->m].users); + map[bl->m].name, map[bl->m].users, + sd->debug_file, sd->debug_line, sd->debug_func, file, line, func); } else if (--map[bl->m].users == 0 && battle_config.dynamic_mobs) //[Skotlex] map_removemobs(bl->m); sd->state.debug_remove_map = 1; // temporary state to track double remove_map's [FlavioJS] + sd->debug_file = file; + sd->debug_line = line; + sd->debug_func = func; break; } diff --git a/src/map/unit.h b/src/map/unit.h index 192f1c7e8..ec2e81c5a 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -114,7 +114,8 @@ int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int struct unit_data* unit_bl2ud(struct block_list *bl); void unit_remove_map_pc(struct map_session_data *sd, int clrtype); void unit_free_pc(struct map_session_data *sd); -int unit_remove_map(struct block_list *bl, int clrtype); +#define unit_remove_map(bl,clrtype) unit_remove_map_(bl,clrtype,__FILE__,__LINE__,__func__) +int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int line, const char* func); int unit_free(struct block_list *bl, int clrtype); int unit_changeviewsize(struct block_list *bl,short size); -- cgit v1.2.3-70-g09d2 From 8cb6244382cb6e1bb8b2edd13bba6b91f9c67b1f Mon Sep 17 00:00:00 2001 From: zephyrus Date: Sun, 24 Aug 2008 13:33:36 +0000 Subject: - Implemented unit_calc_pos (copy from pet_calc_pos) to implement it on Mercenary/Homunculus and don't use x,y-1 always. - Implemented Mercenary walk to master (same packet as Homunculus). - Starting work on Stats but i will need lot of help. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@13121 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/clif.c | 24 ++++++++++++----- src/map/mercenary.c | 22 +++++---------- src/map/mercenary.h | 2 +- src/map/pet.c | 57 ++------------------------------------- src/map/status.c | 78 ++++++++++++++++++++++++++++++++++++++++------------- src/map/status.h | 5 ++-- src/map/unit.c | 56 ++++++++++++++++++++++++++++++++++++++ src/map/unit.h | 1 + 8 files changed, 147 insertions(+), 98 deletions(-) (limited to 'src/map/unit.h') diff --git a/src/map/clif.c b/src/map/clif.c index a82495aa0..78d73bca0 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -11270,10 +11270,19 @@ void clif_parse_ChangeHomunculusName(int fd, struct map_session_data *sd) void clif_parse_HomMoveToMaster(int fd, struct map_session_data *sd) { - if(!merc_is_hom_active(sd->hd)) - return; + int id = RFIFOL(fd,2); // Mercenary or Homunculus + struct block_list *bl = NULL; + struct unit_data *ud = NULL; + + if( sd->md && sd->md->bl.id == id ) + bl = &sd->md->bl; + else if( merc_is_hom_active(sd->hd) && sd->hd->bl.id == id ) + bl = &sd->hd->bl; // Moving Homunculus + else return; - unit_walktoxy(&sd->hd->bl, sd->bl.x,sd->bl.y-1, 4); + unit_calc_pos(bl, sd->bl.x, sd->bl.y, sd->ud.dir); + ud = unit_bl2ud(bl); + unit_walktoxy(bl, ud->to_x, ud->to_y, 4); } void clif_parse_HomMoveTo(int fd, struct map_session_data *sd) @@ -12349,6 +12358,7 @@ void clif_mercenary_info(struct map_session_data *sd) int fd; struct mercenary_data *md; struct status_data *status; + int atk; if( sd == NULL || (md = sd->md) == NULL ) return; @@ -12359,14 +12369,16 @@ void clif_mercenary_info(struct map_session_data *sd) WFIFOHEAD(fd,80); WFIFOW(fd,0) = 0x029b; WFIFOL(fd,2) = md->bl.id; - WFIFOW(fd,6) = cap_value(status->rhw.atk2+status->batk, 0, SHRT_MAX); + // Mercenary shows ATK as a random value between ATK ~ ATK2 + atk = rand()%(status->rhw.atk - status->rhw.atk2 + 1) + status->rhw.atk; + WFIFOW(fd,6) = cap_value(atk, 0, SHRT_MAX); WFIFOW(fd,8) = cap_value(status->matk_max, 0, SHRT_MAX); WFIFOW(fd,10) = status->hit; WFIFOW(fd,12) = status->cri/10; - WFIFOW(fd,14) = status->def + status->vit; + WFIFOW(fd,14) = status->def + (status->vit/2); WFIFOW(fd,16) = status->mdef; WFIFOW(fd,18) = status->flee; - WFIFOW(fd,20) = status->amotion; + WFIFOW(fd,20) = status->aspd_rate; safestrncpy((char*)WFIFOP(fd,22), md->db->name, NAME_LENGTH); WFIFOW(fd,46) = md->db->lv; WFIFOL(fd,48) = status->hp; diff --git a/src/map/mercenary.c b/src/map/mercenary.c index 16851d8f7..a127f7fad 100644 --- a/src/map/mercenary.c +++ b/src/map/mercenary.c @@ -120,8 +120,6 @@ int merc_data_received(struct s_mercenary *merc, bool flag) if( !sd->md ) { - short x = sd->bl.x, y = sd->bl.y; - sd->md = md = (struct mercenary_data*)aCalloc(1,sizeof(struct mercenary_data)); md->bl.type = BL_MER; md->bl.id = npc_get_new_npc_id(); @@ -137,14 +135,12 @@ int merc_data_received(struct s_mercenary *merc, bool flag) md->bl.m = sd->bl.m; md->bl.x = sd->bl.x; md->bl.y = sd->bl.y; - x = sd->bl.x + 1; - y = sd->bl.y + 1; - map_random_dir(&md->bl, &x, &y); - md->bl.x = x; - md->bl.y = y; + unit_calc_pos(&md->bl, sd->bl.x, sd->bl.y, sd->ud.dir); + md->bl.x = md->ud.to_x; + md->bl.y = md->ud.to_y; map_addiddb(&md->bl); - // status_calc_mercenary(md,1); + status_calc_mercenary(md,1); } else memcpy(&sd->md->mercenary, merc, sizeof(struct s_mercenary)); @@ -719,8 +715,6 @@ int merc_hom_alloc(struct map_session_data *sd, struct s_homunculus *hom) { struct homun_data *hd; int i = 0; - short x,y; - nullpo_retr(1, sd); Assert((sd->status.hom_id == 0 || sd->hd == 0) || sd->hd->master == sd); @@ -750,11 +744,9 @@ int merc_hom_alloc(struct map_session_data *sd, struct s_homunculus *hom) hd->bl.m = sd->bl.m; hd->bl.x = sd->bl.x; hd->bl.y = sd->bl.y; - x = sd->bl.x + 1; - y = sd->bl.y + 1; - map_random_dir(&hd->bl, &x, &y); - hd->bl.x = x; - hd->bl.y = y; + unit_calc_pos(&hd->bl, sd->bl.x, sd->bl.y, sd->ud.dir); + hd->bl.x = hd->ud.to_x; + hd->bl.y = hd->ud.to_y; map_addiddb(&hd->bl); status_calc_homunculus(hd,1); diff --git a/src/map/mercenary.h b/src/map/mercenary.h index a9e572f50..17a519cc7 100644 --- a/src/map/mercenary.h +++ b/src/map/mercenary.h @@ -28,7 +28,7 @@ struct mercenary_data { struct block_list bl; struct unit_data ud; struct view_data *vd; - struct status_data *base_status, battle_status; + struct status_data base_status, battle_status; struct status_change sc; struct regen_data regen; diff --git a/src/map/pet.c b/src/map/pet.c index f439c793f..3c3d33d1d 100644 --- a/src/map/pet.c +++ b/src/map/pet.c @@ -56,59 +56,6 @@ int pet_hungry_val(struct pet_data *pd) return 0; } -static int pet_calc_pos(struct pet_data *pd,int tx,int ty,int dir) -{ - int x,y,dx,dy; - int i,k; - - nullpo_retr(0, pd); - - pd->ud.to_x = tx; - pd->ud.to_y = ty; - - if(dir < 0 || dir >= 8) - return 1; - - dx = -dirx[dir]*2; - dy = -diry[dir]*2; - x = tx + dx; - y = ty + dy; - if(!unit_can_reach_pos(&pd->bl,x,y,0)) { - if(dx > 0) x--; - else if(dx < 0) x++; - if(dy > 0) y--; - else if(dy < 0) y++; - if(!unit_can_reach_pos(&pd->bl,x,y,0)) { - for(i=0;i<12;i++) { - k = rand()%8; - dx = -dirx[k]*2; - dy = -diry[k]*2; - x = tx + dx; - y = ty + dy; - if(unit_can_reach_pos(&pd->bl,x,y,0)) - break; - else { - if(dx > 0) x--; - else if(dx < 0) x++; - if(dy > 0) y--; - else if(dy < 0) y++; - if(unit_can_reach_pos(&pd->bl,x,y,0)) - break; - } - } - if(i>=12) { - x = tx; - y = ty; - if(!unit_can_reach_pos(&pd->bl,x,y,0)) - return 1; - } - } - } - pd->ud.to_x = x; - pd->ud.to_y = y; - return 0; -} - int pet_create_egg(struct map_session_data *sd, int item_id) { int pet_id = search_petDB_index(item_id, PET_EGG); @@ -392,7 +339,7 @@ int pet_data_init(struct map_session_data *sd, struct s_pet *pet) pd->bl.m = sd->bl.m; pd->bl.x = sd->bl.x; pd->bl.y = sd->bl.y; - pet_calc_pos(pd,sd->bl.x,sd->bl.y,sd->ud.dir); + unit_calc_pos(&pd->bl, sd->bl.x, sd->bl.y, sd->ud.dir); pd->bl.x = pd->ud.to_x; pd->bl.y = pd->ud.to_y; pd->bl.id = npc_get_new_npc_id(); @@ -920,7 +867,7 @@ static int pet_ai_sub_hard(struct pet_data *pd, struct map_session_data *sd, uns if(pd->ud.walktimer != -1 && check_distance_blxy(&sd->bl, pd->ud.to_x,pd->ud.to_y, 3)) return 0; //Already walking to him - pet_calc_pos(pd,sd->bl.x,sd->bl.y,sd->ud.dir); + unit_calc_pos(&pd->bl, sd->bl.x, sd->bl.y, sd->ud.dir); if(!unit_walktoxy(&pd->bl,pd->ud.to_x,pd->ud.to_y,0)) pet_randomwalk(pd,tick); diff --git a/src/map/status.c b/src/map/status.c index c77e0ffcc..0065ad15c 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -1247,7 +1247,7 @@ static unsigned short status_base_atk(struct block_list *bl, struct status_data void status_calc_misc(struct block_list *bl, struct status_data *status, int level) { //Non players get the value set, players need to stack with previous bonuses. - if (bl->type != BL_PC) + if( bl->type != BL_PC ) status->batk = status->hit = status->flee = status->def2 = status->mdef2 = @@ -1261,7 +1261,7 @@ void status_calc_misc(struct block_list *bl, struct status_data *status, int lev status->def2 += status->vit; status->mdef2 += status->int_ + (status->vit>>1); - if (bl->type&battle_config.enable_critical) + if( bl->type&battle_config.enable_critical ) status->cri += status->luk*3 + 10; else status->cri = 0; @@ -2374,6 +2374,31 @@ int status_calc_pc(struct map_session_data* sd,int first) return 0; } +int status_calc_mercenary(struct mercenary_data *md, int first) +{ + struct status_data *status; + struct s_mercenary *merc; + + status = &md->base_status; + merc = &md->mercenary; + + if( first ) + { + memcpy(status, &md->db->status, sizeof(struct status_data)); + status->mode = MD_CANMOVE|MD_CANATTACK; + status->hp = status->max_hp; + status->sp = status->max_sp; + md->battle_status.hp = merc->hp; + md->battle_status.sp = merc->sp; + } + + status_calc_misc(&md->bl, status, md->db->lv); + status_cpy(&md->base_status, status); + status_calc_bl(&md->bl, SCB_ALL); + + return 0; +} + int status_calc_homunculus(struct homun_data *hd, int first) { struct status_data b_status, *status; @@ -2490,30 +2515,30 @@ void status_calc_regen(struct block_list *bl, struct status_data *status, struct struct map_session_data *sd; int val, skill; - if (!(bl->type&BL_REGEN) || !regen) + if( !(bl->type&BL_REGEN) || !regen ) return; - sd = BL_CAST(BL_PC,bl); + sd = BL_CAST(BL_PC,bl); val = 1 + (status->vit/5) + (status->max_hp/200); - if (sd && sd->hprecov_rate != 100) + if( sd && sd->hprecov_rate != 100 ) val = val*sd->hprecov_rate/100; regen->hp = cap_value(val, 1, SHRT_MAX); val = 1 + (status->int_/6) + (status->max_sp/100); - if(status->int_ >= 120) + if( status->int_ >= 120 ) val += ((status->int_-120)>>1) + 4; - if(sd && sd->sprecov_rate != 100) + if( sd && sd->sprecov_rate != 100 ) val = val*sd->sprecov_rate/100; regen->sp = cap_value(val, 1, SHRT_MAX); - if(sd) + if( sd ) { struct regen_data_sub *sregen; - if((skill=pc_checkskill(sd,HP_MEDITATIO)) > 0) + if( (skill=pc_checkskill(sd,HP_MEDITATIO)) > 0 ) { val = regen->sp*(100+3*skill)/100; regen->sp = cap_value(val, 1, SHRT_MAX); @@ -2522,14 +2547,14 @@ void status_calc_regen(struct block_list *bl, struct status_data *status, struct sregen = regen->sregen; val = 0; - if((skill=pc_checkskill(sd,SM_RECOVERY)) > 0) + if( (skill=pc_checkskill(sd,SM_RECOVERY)) > 0 ) val += skill*5 + skill*status->max_hp/500; sregen->hp = cap_value(val, 0, SHRT_MAX); val = 0; - if((skill=pc_checkskill(sd,MG_SRECOVERY)) > 0) + if( (skill=pc_checkskill(sd,MG_SRECOVERY)) > 0 ) val += skill*3 + skill*status->max_sp/500; - if((skill=pc_checkskill(sd,NJ_NINPOU)) > 0) + if( (skill=pc_checkskill(sd,NJ_NINPOU)) > 0 ) val += skill*3 + skill*status->max_sp/500; sregen->sp = cap_value(val, 0, SHRT_MAX); @@ -2537,39 +2562,47 @@ void status_calc_regen(struct block_list *bl, struct status_data *status, struct sregen = regen->ssregen; val = 0; - if((skill=pc_checkskill(sd,MO_SPIRITSRECOVERY)) > 0) + if( (skill=pc_checkskill(sd,MO_SPIRITSRECOVERY)) > 0 ) val += skill*4 + skill*status->max_hp/500; - if((skill=pc_checkskill(sd,TK_HPTIME)) > 0 && sd->state.rest) + if( (skill=pc_checkskill(sd,TK_HPTIME)) > 0 && sd->state.rest ) val += skill*30 + skill*status->max_hp/500; sregen->hp = cap_value(val, 0, SHRT_MAX); val = 0; - if((skill=pc_checkskill(sd,TK_SPTIME)) > 0 && sd->state.rest) + if( (skill=pc_checkskill(sd,TK_SPTIME)) > 0 && sd->state.rest ) { val += skill*3 + skill*status->max_sp/500; if ((skill=pc_checkskill(sd,SL_KAINA)) > 0) //Power up Enjoyable Rest val += (30+10*skill)*val/100; } - if((skill=pc_checkskill(sd,MO_SPIRITSRECOVERY)) > 0) + if( (skill=pc_checkskill(sd,MO_SPIRITSRECOVERY)) > 0 ) val += skill*2 + skill*status->max_sp/500; sregen->sp = cap_value(val, 0, SHRT_MAX); } - if(bl->type==BL_HOM) + if( bl->type == BL_HOM ) { struct homun_data *hd = (TBL_HOM*)bl; - if((skill=merc_hom_checkskill(hd,HAMI_SKIN)) > 0) + if( (skill = merc_hom_checkskill(hd,HAMI_SKIN)) > 0 ) { val = regen->hp*(100+5*skill)/100; regen->hp = cap_value(val, 1, SHRT_MAX); } - if((skill = merc_hom_checkskill(hd,HLIF_BRAIN)) > 0) + if( (skill = merc_hom_checkskill(hd,HLIF_BRAIN)) > 0 ) { val = regen->sp*(100+3*skill)/100; regen->sp = cap_value(val, 1, SHRT_MAX); } } + else if( bl->type == BL_MER ) + { + val = (status->max_hp * status->vit / 10000 + 1) * 6; + regen->hp = cap_value(val, 1, SHRT_MAX); + + val = (status->max_sp * (status->int_ + 10) / 750) + 1; + regen->sp = cap_value(val, 1, SHRT_MAX); + } } //Calculates SC related regen rates. @@ -4057,6 +4090,7 @@ struct regen_data *status_get_regen_data(struct block_list *bl) switch (bl->type) { case BL_PC: return &((TBL_PC*)bl)->regen; case BL_HOM: return &((TBL_HOM*)bl)->regen; + case BL_MER: return &((TBL_MER*)bl)->regen; default: return NULL; } @@ -4071,6 +4105,7 @@ struct status_data *status_get_status_data(struct block_list *bl) case BL_MOB: return &((TBL_MOB*)bl)->status; case BL_PET: return &((TBL_PET*)bl)->status; case BL_HOM: return &((TBL_HOM*)bl)->battle_status; + case BL_MER: return &((TBL_MER*)bl)->battle_status; default: return &dummy_status; } @@ -4084,6 +4119,7 @@ struct status_data *status_get_base_status(struct block_list *bl) case BL_MOB: return ((TBL_MOB*)bl)->base_status ? ((TBL_MOB*)bl)->base_status : &((TBL_MOB*)bl)->db->status; case BL_PET: return &((TBL_PET*)bl)->db->status; case BL_HOM: return &((TBL_HOM*)bl)->base_status; + case BL_MER: return &((TBL_MER*)bl)->base_status; default: return NULL; } @@ -4133,6 +4169,10 @@ int status_get_party_id(struct block_list *bl) if (((TBL_HOM*)bl)->master) return ((TBL_HOM*)bl)->master->status.party_id; break; + case BL_MER: + if (((TBL_MER*)bl)->master) + return ((TBL_MER*)bl)->master->status.party_id; + break; case BL_SKILL: return ((TBL_SKILL*)bl)->group->party_id; } diff --git a/src/map/status.h b/src/map/status.h index 8e0ff6f85..8d9940b0f 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -595,9 +595,9 @@ enum scb_flag }; //Define to determine who gets HP/SP consumed on doing skills/etc. [Skotlex] -#define BL_CONSUME (BL_PC|BL_HOM) +#define BL_CONSUME (BL_PC|BL_HOM|BL_MER) //Define to determine who has regen -#define BL_REGEN (BL_PC|BL_HOM) +#define BL_REGEN (BL_PC|BL_HOM|BL_MER) //Basic damage info of a weapon @@ -802,6 +802,7 @@ int status_calc_pet(struct pet_data* pd, int first); // [Skotlex] int status_calc_pc(struct map_session_data* sd,int first); int status_calc_mob(struct mob_data* md, int first); //[Skotlex] int status_calc_homunculus(struct homun_data *hd, int first); +int status_calc_mercenary(struct mercenary_data *md, int first); void status_calc_misc(struct block_list *bl, struct status_data *status, int level); void status_calc_regen(struct block_list *bl, struct status_data *status, struct regen_data *regen); void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, struct status_change *sc); diff --git a/src/map/unit.c b/src/map/unit.c index 20cd20de6..23789544f 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1357,7 +1357,63 @@ bool unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, if (y) *y = tbl->y-dy; return path_search(NULL,bl->m,bl->x,bl->y,tbl->x-dx,tbl->y-dy,easy,CELL_CHKNOREACH); } +/*========================================== + * Calculates position of Pet/Mercenary/Homunculus + *------------------------------------------*/ +int unit_calc_pos(struct block_list *bl, int tx, int ty, int dir) +{ + int dx, dy, x, y, i, k; + struct unit_data *ud = unit_bl2ud(bl); + nullpo_retr(0, ud); + + if( dir < 0 || dir > 7 ) + return 1; + ud->to_x = tx; + ud->to_y = ty; + + // 2 cells from Master Position + dx = -dirx[dir] * 2; + dy = -diry[dir] * 2; + x = tx + dx; + y = ty + dy; + + if( !unit_can_reach_pos(bl, x, y, 0) ) + { + if( dx > 0 ) x--; else if( dx < 0 ) x++; + if( dy > 0 ) y--; else if( dy < 0 ) y++; + if( !unit_can_reach_pos(bl, x, y, 0) ) + { + for( i = 0; i < 12; i++ ) + { + k = rand()%8; // Pick a Random Dir + dx = -dirx[k] * 2; + dy = -diry[k] * 2; + x = tx + dx; + y = ty + dy; + if( unit_can_reach_pos(bl, x, y, 0) ) + break; + else + { + if( dx > 0 ) x--; else if( dx < 0 ) x++; + if( dy > 0 ) y--; else if( dy < 0 ) y++; + if( unit_can_reach_pos(bl, x, y, 0) ) + break; + } + } + if( i == 12 ) + { + x = tx; y = tx; // Exactly Master Position + if( !unit_can_reach_pos(bl, x, y, 0) ) + return 1; + } + } + } + ud->to_x = x; + ud->to_y = y; + + return 0; +} /*========================================== * PCの攻撃 (timer関数) diff --git a/src/map/unit.h b/src/map/unit.h index ec2e81c5a..0d8e4535e 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -66,6 +66,7 @@ struct view_data { int unit_walktoxy( struct block_list *bl, short x, short y, int easy); int unit_walktobl( struct block_list *bl, struct block_list *target, int range, int easy); int unit_run(struct block_list *bl); +int unit_calc_pos(struct block_list *bl, int tx, int ty, int dir); // 歩行停止 // typeは以下の組み合わせ : -- cgit v1.2.3-70-g09d2 From 35467de0fb6dc06a402315ea478495d74080e3c5 Mon Sep 17 00:00:00 2001 From: ai4rei Date: Tue, 23 Nov 2010 09:26:00 +0000 Subject: * Added script command pushpc, which is required by newer scripts. - Moved knockback-part of skill_blown into unit_blown, to allow unconditional knockback required by pushpc without copy-pasting code. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@14492 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 3 +++ db/const.txt | 9 +++++++++ doc/script_commands.txt | 18 ++++++++++++++++++ src/map/script.c | 39 +++++++++++++++++++++++++++++++++++++++ src/map/skill.c | 41 ++--------------------------------------- src/map/unit.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ src/map/unit.h | 1 + 7 files changed, 120 insertions(+), 39 deletions(-) (limited to 'src/map/unit.h') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index e7361b53c..84fd9c869 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -1,5 +1,8 @@ Date Added +2010/11/23 + * Added script command pushpc, which is required by newer scripts. [Ai4rei] + - Moved knockback-part of skill_blown into unit_blown, to allow unconditional knockback required by pushpc without copy-pasting code. 2010/11/22 * mail_deliveryfail no longer attempts to log (since r12910) and give items (since r11855), when there is no item attached to the mail (bugreport:3239). [Ai4rei] * Fixed a crash when shutting down char-server (TXT only), after it failed to load storage save data (since r1275). [Ai4rei] diff --git a/db/const.txt b/db/const.txt index 3fbec41fb..8bf52248a 100644 --- a/db/const.txt +++ b/db/const.txt @@ -1842,3 +1842,12 @@ VAR_HEADPALETTE 6 VAR_BODYPALETTE 7 VAR_SHIELD 8 VAR_SHOES 9 + +DIR_NORTH 0 +DIR_NORTHWEST 1 +DIR_WEST 2 +DIR_SOUTHWEST 3 +DIR_SOUTH 4 +DIR_SOUTHEAST 5 +DIR_EAST 6 +DIR_NORTHEAST 7 diff --git a/doc/script_commands.txt b/doc/script_commands.txt index 1c75bb062..29e9edee4 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -135,6 +135,8 @@ //= 3.28.20091119 //= Added showevent and searchitem commands [Skotlex] //= Added info on strcharinfo(3) [Skotlex] +//= 3.29.20101123 +//= Added 'pushpc' command. [Ai4rei] //========================================================= This document is a reference manual for all the scripting commands and functions @@ -3869,6 +3871,22 @@ example, there is a Stylist script inside the default eAthena installation that you can look at, this may help you create a Stylist of your own: 'custom\dye.txt' +--------------------------------------- + +*pushpc ,; + +This command will push the currently attached player to given direction by given +amount of square cells. Direction is the same as used when declaring npcs, and +can be specified by using one of the DIR_* constants (db/const.txt). + +The knock-back is not restricted by items or map flags, only obstacles are taken +into account. If there is not enough space to perform the push (e.g. due to a +wall), the character is pushed only up to the obstacle. + + // pushes the character 5 cells in 3 o'clock direction from it's + // current position. + pushpc DIR_EAST, 5; + --------------------------------------- \\ 4,1.- Item-related commands diff --git a/src/map/script.c b/src/map/script.c index d823ae597..906dce510 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -14380,6 +14380,44 @@ BUILDIN_FUNC(progressbar) return 0; } +BUILDIN_FUNC(pushpc) +{ + int direction, cells, dx, dy; + struct map_session_data* sd; + + if((sd = script_rid2sd(st))==NULL) + { + return 0; + } + + direction = script_getnum(st,2); + cells = script_getnum(st,3); + + if(direction<0 || direction>7) + { + ShowWarning("buildin_pushpc: Invalid direction %d specified.\n", direction); + script_reportsrc(st); + + direction%= 8; // trim spin-over + } + + if(!cells) + {// zero distance + return 0; + } + else if(cells<0) + {// pushing backwards + direction = (direction+4)%8; // turn around + cells = -cells; + } + + dx = dirx[direction]; + dy = diry[direction]; + + unit_blown(&sd->bl, dx, dy, cells, 0); + return 0; +} + // declarations that were supposed to be exported from npc_chat.c #ifdef PCRE_SUPPORT BUILDIN_FUNC(defpattern); @@ -14739,6 +14777,7 @@ struct script_function buildin_func[] = { BUILDIN_DEF(setfont,"i"), BUILDIN_DEF(areamobuseskill,"siiiiviiiii"), BUILDIN_DEF(progressbar, "si"), + BUILDIN_DEF(pushpc,"ii"), // WoE SE BUILDIN_DEF(agitstart2,""), BUILDIN_DEF(agitend2,""), diff --git a/src/map/skill.c b/src/map/skill.c index a54bedc20..ccc3d96f9 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -1467,8 +1467,7 @@ int skill_strip_equip(struct block_list *bl, unsigned short where, int rate, int -------------------------------------------------------------------------*/ int skill_blown(struct block_list* src, struct block_list* target, int count, int direction, int flag) { - int dx = 0, dy = 0, nx, ny; - int ret; + int dx = 0, dy = 0; struct skill_unit* su = NULL; nullpo_ret(src); @@ -1514,43 +1513,7 @@ int skill_blown(struct block_list* src, struct block_list* target, int count, in dy = -diry[direction]; } - ret=path_blownpos(target->m,target->x,target->y,dx,dy,count); - nx = ret>>16; - ny = ret&0xffff; - - if (!su) - unit_stop_walking(target,0); - - dx = nx - target->x; - dy = ny - target->y; - - if (!dx && !dy) //Could not knockback. - return 0; - - map_foreachinmovearea(clif_outsight, target, AREA_SIZE, dx, dy, target->type == BL_PC ? BL_ALL : BL_PC, target); - - if(su) - skill_unit_move_unit_group(su->group,target->m,dx,dy); - else - map_moveblock(target, nx, ny, gettick()); - - map_foreachinmovearea(clif_insight, target, AREA_SIZE, -dx, -dy, target->type == BL_PC ? BL_ALL : BL_PC, target); - - if(!(flag&0x1)) - clif_blown(target); - - if( target->type == BL_PC ) - { - TBL_PC *sd = (TBL_PC*)target; - if( sd->touching_id ) - npc_touchnext_areanpc(sd,false); - if( map_getcell(target->m,target->x,target->y,CELL_CHKNPC) ) - npc_touch_areanpc(sd,target->m,target->x,target->y); - else - sd->areanpc_id=0; - } - - return count; //Return amount of knocked back cells. + return unit_blown(target, dx, dy, count, flag&0x1); } diff --git a/src/map/unit.c b/src/map/unit.c index 0c16977c1..f2dcdc921 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -566,6 +566,54 @@ uint8 unit_getdir(struct block_list *bl) return ud->dir; } +// Pushes a unit by given amount of cells into given direction. Only +// map cell restrictions are respected. +// flag: +// &1 Do not send position update packets. +int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag) +{ + int nx, ny, ret; + struct skill_unit* su = BL_CAST(BL_SKILL, bl); + + ret=path_blownpos(bl->m,bl->x,bl->y,dx,dy,count); + nx = ret>>16; + ny = ret&0xffff; + + if (!su) + unit_stop_walking(bl,0); + + dx = nx - bl->x; + dy = ny - bl->y; + + if (!dx && !dy) //Could not knockback. + return 0; + + map_foreachinmovearea(clif_outsight, bl, AREA_SIZE, dx, dy, bl->type == BL_PC ? BL_ALL : BL_PC, bl); + + if(su) + skill_unit_move_unit_group(su->group,bl->m,dx,dy); + else + map_moveblock(bl, nx, ny, gettick()); + + map_foreachinmovearea(clif_insight, bl, AREA_SIZE, -dx, -dy, bl->type == BL_PC ? BL_ALL : BL_PC, bl); + + if(!(flag&0x1)) + clif_blown(bl); + + if( bl->type == BL_PC ) + { + TBL_PC *sd = (TBL_PC*)bl; + if( sd->touching_id ) + npc_touchnext_areanpc(sd,false); + if( map_getcell(bl->m,bl->x,bl->y,CELL_CHKNPC) ) + npc_touch_areanpc(sd,bl->m,bl->x,bl->y); + else + sd->areanpc_id=0; + } + + return count; //Return amount of knocked back cells. +} + //Warps a unit/ud to a given map/position. //In the case of players, pc_setpos is used. //it respects the no warp flags, so it is safe to call this without doing nowarpto/nowarp checks. diff --git a/src/map/unit.h b/src/map/unit.h index 0d8e4535e..3b82dce56 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -84,6 +84,7 @@ int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, bool int unit_warp(struct block_list *bl, short map, short x, short y, int type); int unit_setdir(struct block_list *bl,unsigned char dir); uint8 unit_getdir(struct block_list *bl); +int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag); // そこまで歩行でたどり着けるかの判定 bool unit_can_reach_pos(struct block_list *bl,int x,int y,int easy); -- cgit v1.2.3-70-g09d2 From dc1175bda087b4b4ce657a114225b5daefbcf5c4 Mon Sep 17 00:00:00 2001 From: ai4rei Date: Sun, 28 Nov 2010 21:41:38 +0000 Subject: * Added clr_type enumeration for vanish effect constants. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@14517 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 1 + src/map/atcommand.c | 22 +++++++++---------- src/map/battleground.c | 4 ++-- src/map/clif.c | 34 ++++++++++++++--------------- src/map/clif.h | 12 +++++++++-- src/map/homunculus.c | 10 ++++----- src/map/instance.c | 6 +++--- src/map/map.c | 6 +++--- src/map/mercenary.c | 4 ++-- src/map/mob.c | 16 +++++++------- src/map/npc.c | 16 +++++++------- src/map/pc.c | 16 +++++++------- src/map/pc.h | 8 +++---- src/map/pet.c | 4 ++-- src/map/script.c | 58 +++++++++++++++++++++++++------------------------- src/map/skill.c | 28 ++++++++++++------------ src/map/status.c | 10 ++++----- src/map/unit.c | 26 +++++++++++----------- src/map/unit.h | 9 ++++---- 19 files changed, 150 insertions(+), 140 deletions(-) (limited to 'src/map/unit.h') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 2ad71fe15..9277b6267 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -1,6 +1,7 @@ Date Added 2010/11/28 + * Added clr_type enumeration for vanish effect constants. [Ai4rei] * Resolved multiple issues with the party booking system (bugreport:4573, since r14412). [Ai4rei] - Fixed recruitments were limited to party leaders. - Fixed recruitment index was party id instead of an auto-increment value, causing sorting by age not working. diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 41a27bc8a..7f73a536a 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -452,7 +452,7 @@ ACMD_FUNC(mapmove) clif_displaymessage(fd, msg_txt(248)); return -1; } - if (pc_setpos(sd, mapindex, x, y, 3) != 0) { + if (pc_setpos(sd, mapindex, x, y, CLR_TELEPORT) != 0) { clif_displaymessage(fd, msg_txt(1)); // Map not found. return -1; } @@ -535,7 +535,7 @@ ACMD_FUNC(jumpto) return -1; } - pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, 3); + pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT); sprintf(atcmd_output, msg_txt(4), pl_sd->status.name); // Jumped to %s clif_displaymessage(fd, atcmd_output); @@ -572,7 +572,7 @@ ACMD_FUNC(jump) x = y = 0; //Invalid cell, use random spot. } - pc_setpos(sd, sd->mapindex, x, y, 3); + pc_setpos(sd, sd->mapindex, x, y, CLR_TELEPORT); sprintf(atcmd_output, msg_txt(5), sd->bl.x, sd->bl.y); // Jumped to %d %d clif_displaymessage(fd, atcmd_output); return 0; @@ -1114,7 +1114,7 @@ ACMD_FUNC(load) return -1; } - pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, 0); + pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_OUTSIGHT); clif_displaymessage(fd, msg_txt(7)); // Warping to save point.. return 0; @@ -2308,7 +2308,7 @@ ACMD_FUNC(go) clif_displaymessage(fd, msg_txt(248)); return -1; } - if (pc_setpos(sd, mapindex_name2id(data[town].map), data[town].x, data[town].y, 3) == 0) { + if (pc_setpos(sd, mapindex_name2id(data[town].map), data[town].x, data[town].y, CLR_TELEPORT) == 0) { clif_displaymessage(fd, msg_txt(0)); // Warped. } else { clif_displaymessage(fd, msg_txt(1)); // Map not found. @@ -3329,7 +3329,7 @@ ACMD_FUNC(recall) clif_displaymessage(fd, "You are not authorized to warp this player from its actual map."); return -1; } - pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, 2); + pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN); sprintf(atcmd_output, msg_txt(46), pl_sd->status.name); // %s recalled! clif_displaymessage(fd, atcmd_output); @@ -3988,7 +3988,7 @@ ACMD_FUNC(recallall) pc_setstand(pl_sd); pc_setrestartvalue(pl_sd,1); } - pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, 2); + pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN); } } } @@ -4047,7 +4047,7 @@ ACMD_FUNC(guildrecall) if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) count++; else - pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, 2); + pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN); } } mapit_free(iter); @@ -4106,7 +4106,7 @@ ACMD_FUNC(partyrecall) if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) count++; else - pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, 2); + pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN); } } mapit_free(iter); @@ -4704,7 +4704,7 @@ ACMD_FUNC(tonpc) } if ((nd = npc_name2id(npcname)) != NULL) { - if (pc_setpos(sd, map_id2index(nd->bl.m), nd->bl.x, nd->bl.y, 3) == 0) + if (pc_setpos(sd, map_id2index(nd->bl.m), nd->bl.x, nd->bl.y, CLR_TELEPORT) == 0) clif_displaymessage(fd, msg_txt(0)); // Warped. else return -1; @@ -7700,7 +7700,7 @@ ACMD_FUNC(size) size = atoi(message); if(sd->state.size) { sd->state.size=0; - pc_setpos(sd, sd->mapindex, sd->bl.x, sd->bl.y, 3); + pc_setpos(sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_TELEPORT); } if(size==1) { diff --git a/src/map/battleground.c b/src/map/battleground.c index fad22c38f..1c2a90d90 100644 --- a/src/map/battleground.c +++ b/src/map/battleground.c @@ -64,7 +64,7 @@ int bg_team_warp(int bg_id, unsigned short mapindex, short x, short y) struct battleground_data *bg = bg_team_search(bg_id); if( bg == NULL ) return 0; for( i = 0; i < MAX_BG_MEMBERS; i++ ) - if( bg->members[i].sd != NULL ) pc_setpos(bg->members[i].sd, mapindex, x, y, 3); + if( bg->members[i].sd != NULL ) pc_setpos(bg->members[i].sd, mapindex, x, y, CLR_TELEPORT); return 1; } @@ -145,7 +145,7 @@ int bg_member_respawn(struct map_session_data *sd) return 0; if( bg->mapindex == 0 ) return 0; // Respawn not handled by Core - pc_setpos(sd, bg->mapindex, bg->x, bg->y, 0); + pc_setpos(sd, bg->mapindex, bg->x, bg->y, CLR_OUTSIGHT); status_revive(&sd->bl, 1, 100); return 1; // Warped diff --git a/src/map/clif.c b/src/map/clif.c index 151c63e65..c99dab0b2 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -658,7 +658,7 @@ int clif_clearflooritem(struct flooritem_data *fitem, int fd) * 3 - teleported / logged out * fd : the target client *------------------------------------------*/ -int clif_clearunit_single(int id, uint8 type, int fd) +int clif_clearunit_single(int id, clr_type type, int fd) { WFIFOHEAD(fd, packet_len(0x80)); WFIFOW(fd,0) = 0x80; @@ -676,7 +676,7 @@ int clif_clearunit_single(int id, uint8 type, int fd) * 2 - respawned * 3 - teleported / logged out *------------------------------------------*/ -int clif_clearunit_area(struct block_list* bl, uint8 type) +int clif_clearunit_area(struct block_list* bl, clr_type type) { unsigned char buf[16]; @@ -686,7 +686,7 @@ int clif_clearunit_area(struct block_list* bl, uint8 type) WBUFL(buf,2) = bl->id; WBUFB(buf,6) = type; - clif_send(buf, packet_len(0x80), bl, type == 1 ? AREA : AREA_WOS); + clif_send(buf, packet_len(0x80), bl, type == CLR_DEAD ? AREA : AREA_WOS); if(disguised(bl)) { WBUFL(buf,2) = -bl->id; @@ -699,7 +699,7 @@ int clif_clearunit_area(struct block_list* bl, uint8 type) static int clif_clearunit_delayed_sub(int tid, unsigned int tick, int id, intptr data) { struct block_list *bl = (struct block_list *)data; - clif_clearunit_area(bl, 0); + clif_clearunit_area(bl, CLR_OUTSIGHT); aFree(bl); return 0; } @@ -4195,7 +4195,7 @@ int clif_outsight(struct block_list *bl,va_list ap) switch(bl->type){ case BL_PC: if (sd->vd.class_ != INVISIBLE_CLASS) - clif_clearunit_single(bl->id,0,tsd->fd); + clif_clearunit_single(bl->id,CLR_OUTSIGHT,tsd->fd); if(sd->chatID){ struct chat_data *cd; cd=(struct chat_data*)map_id2bl(sd->chatID); @@ -4213,14 +4213,14 @@ int clif_outsight(struct block_list *bl,va_list ap) break; default: if ((vd=status_get_viewdata(bl)) && vd->class_ != INVISIBLE_CLASS) - clif_clearunit_single(bl->id,0,tsd->fd); + clif_clearunit_single(bl->id,CLR_OUTSIGHT,tsd->fd); break; } } if (sd && sd->fd) { //sd is watching tbl go out of view. if ((vd=status_get_viewdata(tbl)) && vd->class_ != INVISIBLE_CLASS) - clif_clearunit_single(tbl->id,0,sd->fd); + clif_clearunit_single(tbl->id,CLR_OUTSIGHT,sd->fd); } return 0; } @@ -7742,7 +7742,7 @@ int clif_refresh(struct map_session_data *sd) if( pc_issit(sd) ) clif_sitting(&sd->bl); // FIXME: just send to self, not area if( pc_isdead(sd) ) //When you refresh, resend the death packet. - clif_clearunit_single(sd->bl.id,1,sd->fd); + clif_clearunit_single(sd->bl.id,CLR_DEAD,sd->fd); else clif_changed_dir(&sd->bl, SELF); @@ -8720,7 +8720,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) // If player is dead, and is spawned (such as @refresh) send death packet. [Valaris] if(pc_isdead(sd)) - clif_clearunit_area(&sd->bl, 1); + clif_clearunit_area(&sd->bl, CLR_DEAD); // Uncomment if you want to make player face in the same direction he was facing right before warping. [Skotlex] // else // clif_changed_dir(&sd->bl, SELF); @@ -8821,7 +8821,7 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd) int cmd; if (pc_isdead(sd)) { - clif_clearunit_area(&sd->bl, 1); + clif_clearunit_area(&sd->bl, CLR_DEAD); return; } @@ -9100,7 +9100,7 @@ void clif_parse_HowManyConnections(int fd, struct map_session_data *sd) void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, int target_id, unsigned int tick) { if (pc_isdead(sd)) { - clif_clearunit_area(&sd->bl, 1); + clif_clearunit_area(&sd->bl, CLR_DEAD); return; } @@ -9198,7 +9198,7 @@ void clif_parse_Restart(int fd, struct map_session_data *sd) { switch(RFIFOB(fd,2)) { case 0x00: - pc_respawn(sd,2); + pc_respawn(sd,CLR_RESPAWN); break; case 0x01: /* Rovert's Prevent logout option - Fixed [Valaris] */ @@ -9416,7 +9416,7 @@ void clif_parse_TakeItem(int fd, struct map_session_data *sd) do { if (pc_isdead(sd)) { - clif_clearunit_area(&sd->bl, 1); + clif_clearunit_area(&sd->bl, CLR_DEAD); break; } @@ -9483,7 +9483,7 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd) int n; if (pc_isdead(sd)) { - clif_clearunit_area(&sd->bl, 1); + clif_clearunit_area(&sd->bl, CLR_DEAD); return; } @@ -9516,7 +9516,7 @@ void clif_parse_EquipItem(int fd,struct map_session_data *sd) int index; if(pc_isdead(sd)) { - clif_clearunit_area(&sd->bl,1); + clif_clearunit_area(&sd->bl,CLR_DEAD); return; } index = RFIFOW(fd,2)-2; @@ -9559,7 +9559,7 @@ void clif_parse_UnequipItem(int fd,struct map_session_data *sd) int index; if(pc_isdead(sd)) { - clif_clearunit_area(&sd->bl,1); + clif_clearunit_area(&sd->bl,CLR_DEAD); return; } @@ -9581,7 +9581,7 @@ void clif_parse_NpcClicked(int fd,struct map_session_data *sd) struct block_list *bl; if(pc_isdead(sd)) { - clif_clearunit_area(&sd->bl,1); + clif_clearunit_area(&sd->bl,CLR_DEAD); return; } diff --git a/src/map/clif.h b/src/map/clif.h index 5989fa5c8..e93291c9a 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -78,6 +78,14 @@ typedef enum send_target { BG_AREA_WOS, } send_target; +typedef enum clr_type +{ + CLR_OUTSIGHT = 0, + CLR_DEAD, + CLR_RESPAWN, + CLR_TELEPORT, +} clr_type; + int clif_setip(const char* ip); void clif_setbindip(const char* ip); void clif_setport(uint16 port); @@ -92,8 +100,8 @@ int clif_charselectok(int); int clif_dropflooritem(struct flooritem_data *); int clif_clearflooritem(struct flooritem_data *,int); -int clif_clearunit_single(int id, uint8 type, int fd); -int clif_clearunit_area(struct block_list* bl, uint8 type); +int clif_clearunit_single(int id, clr_type type, int fd); +int clif_clearunit_area(struct block_list* bl, clr_type type); int clif_clearunit_delayed(struct block_list* bl, unsigned int tick); int clif_spawn(struct block_list*); //area int clif_walkok(struct map_session_data*); // self diff --git a/src/map/homunculus.c b/src/map/homunculus.c index 97a3274fb..6b31e2b6b 100644 --- a/src/map/homunculus.c +++ b/src/map/homunculus.c @@ -107,7 +107,7 @@ int merc_hom_vaporize(struct map_session_data *sd, int flag) memset(hd->blockskill, 0, sizeof(hd->blockskill)); clif_hominfo(sd, sd->hd, 0); merc_save(hd); - return unit_remove_map(&hd->bl, 0); + return unit_remove_map(&hd->bl, CLR_OUTSIGHT); } //delete a homunculus, completely "killing it". @@ -119,7 +119,7 @@ int merc_hom_delete(struct homun_data *hd, int emote) sd = hd->master; if (!sd) - return unit_free(&hd->bl,1); + return unit_free(&hd->bl,CLR_DEAD); if (emote >= 0) clif_emotion(&sd->bl, emote); @@ -129,7 +129,7 @@ int merc_hom_delete(struct homun_data *hd, int emote) // Send homunculus_dead to client hd->homunculus.hp = 0; clif_hominfo(sd, hd, 0); - return unit_remove_map(&hd->bl,0); + return unit_remove_map(&hd->bl,CLR_OUTSIGHT); } int merc_hom_calc_skilltree(struct homun_data *hd) @@ -317,7 +317,7 @@ int merc_hom_evolution(struct homun_data *hd) hom->luk += 10*rand(min->luk, max->luk); hom->intimacy = 500; - unit_remove_map(&hd->bl, 0); + unit_remove_map(&hd->bl, CLR_OUTSIGHT); map_addblock(&hd->bl); clif_spawn(&hd->bl); @@ -676,7 +676,7 @@ int merc_call_homunculus(struct map_session_data *sd) merc_save(hd); } else //Warp him to master. - unit_warp(&hd->bl,sd->bl.m, sd->bl.x, sd->bl.y,0); + unit_warp(&hd->bl,sd->bl.m, sd->bl.x, sd->bl.y,CLR_OUTSIGHT); return 1; } diff --git a/src/map/instance.c b/src/map/instance.c index c1d43c27b..6fa3a2c0a 100644 --- a/src/map/instance.c +++ b/src/map/instance.c @@ -235,7 +235,7 @@ int instance_del_load(struct map_session_data* sd, va_list args) if( !sd || sd->bl.m != m ) return 0; - pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, 0); + pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_OUTSIGHT); return 1; } @@ -439,9 +439,9 @@ void instance_check_kick(struct map_session_data *sd) if( map[m].instance_id ) { // User was on the instance map if( map[m].save.map ) - pc_setpos(sd, map[m].save.map, map[m].save.x, map[m].save.y, 3); + pc_setpos(sd, map[m].save.map, map[m].save.x, map[m].save.y, CLR_TELEPORT); else - pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, 3); + pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT); } } diff --git a/src/map/map.c b/src/map/map.c index b7b1c09b8..5f4a1cf16 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -1645,7 +1645,7 @@ int map_quit(struct map_session_data *sd) if( sd->pd ) pet_lootitem_drop(sd->pd, sd); if( sd->state.storage_flag == 1 ) sd->state.storage_flag = 0; // No need to Double Save Storage on Quit. - unit_remove_map_pc(sd,3); + unit_remove_map_pc(sd,CLR_TELEPORT); if( map[sd->bl.m].instance_id ) { // Avoid map conflicts and warnings on next login @@ -2150,7 +2150,7 @@ int map_removemobs_sub(struct block_list *bl, va_list ap) if( md->db->mexp > 0 ) return 0; - unit_free(&md->bl,0); + unit_free(&md->bl,CLR_OUTSIGHT); return 1; } @@ -3365,7 +3365,7 @@ int cleanup_sub(struct block_list *bl, va_list ap) npc_unload((struct npc_data *)bl); break; case BL_MOB: - unit_free(bl,0); + unit_free(bl,CLR_OUTSIGHT); break; case BL_PET: //There is no need for this, the pet is removed together with the player. [Skotlex] diff --git a/src/map/mercenary.c b/src/map/mercenary.c index 84974e906..53f70a462 100644 --- a/src/map/mercenary.c +++ b/src/map/mercenary.c @@ -244,7 +244,7 @@ int merc_delete(struct mercenary_data *md, int reply) merc_contract_stop(md); if( !sd ) - return unit_free(&md->bl, 0); + return unit_free(&md->bl, CLR_OUTSIGHT); if( md->devotion_flag ) { @@ -259,7 +259,7 @@ int merc_delete(struct mercenary_data *md, int reply) } clif_mercenary_message(sd->fd, reply); - return unit_remove_map(&md->bl, 0); + return unit_remove_map(&md->bl, CLR_OUTSIGHT); } void merc_contract_stop(struct mercenary_data *md) diff --git a/src/map/mob.c b/src/map/mob.c index 15e27b686..a52c6f087 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -547,7 +547,7 @@ static int mob_spawn_guardian_sub(int tid, unsigned int tick, int id, intptr dat md->guardian_data->castle->guardian[md->guardian_data->number].visible = 0; guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0); } - unit_free(&md->bl,0); //Remove guardian. + unit_free(&md->bl,CLR_OUTSIGHT); //Remove guardian. } return 0; } @@ -795,7 +795,7 @@ int mob_setdelayspawn(struct mob_data *md) unsigned int spawntime; if (!md->spawn) //Doesn't has respawn data! - return unit_free(&md->bl,1); + return unit_free(&md->bl,CLR_DEAD); spawntime = md->spawn->delay1; //Base respawn time if (md->spawn->delay2) //random variance @@ -826,7 +826,7 @@ int mob_spawn (struct mob_data *md) md->last_thinktime = tick; if (md->bl.prev != NULL) - unit_remove_map(&md->bl,2); + unit_remove_map(&md->bl,CLR_RESPAWN); else if (md->spawn && md->class_ != md->spawn->class_) { @@ -1121,7 +1121,7 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick) md->master_dist > MAX_MINCHASE ){ md->master_dist = 0; - unit_warp(&md->bl,bl->m,bl->x,bl->y,3); + unit_warp(&md->bl,bl->m,bl->x,bl->y,CLR_TELEPORT); return 1; } @@ -1761,7 +1761,7 @@ int mob_timer_delete(int tid, unsigned int tick, int id, intptr data) } //for Alchemist CANNIBALIZE [Lupus] md->deletetimer = INVALID_TIMER; - unit_free(bl, 3); + unit_free(bl, CLR_TELEPORT); } return 0; } @@ -2491,7 +2491,7 @@ int mob_guardian_guildchange(struct block_list *bl,va_list ap) md->guardian_data->castle->guardian[md->guardian_data->number].visible = 0; guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0); } - unit_free(&md->bl,0); //Remove guardian. + unit_free(&md->bl,CLR_OUTSIGHT); //Remove guardian. } return 0; } @@ -2505,7 +2505,7 @@ int mob_guardian_guildchange(struct block_list *bl,va_list ap) md->guardian_data->castle->guardian[md->guardian_data->number].visible = 0; guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0); } - unit_free(&md->bl,0); + unit_free(&md->bl,CLR_OUTSIGHT); return 0; } @@ -2631,7 +2631,7 @@ int mob_warpslave_sub(struct block_list *bl,va_list ap) return 0; map_search_freecell(master, 0, &x, &y, range, range, 0); - unit_warp(&md->bl, master->m, x, y,2); + unit_warp(&md->bl, master->m, x, y,CLR_RESPAWN); return 1; } diff --git a/src/map/npc.c b/src/map/npc.c index 9f988df6f..893b3c871 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -176,7 +176,7 @@ int npc_enable(const char* name, int flag) if (nd->class_ == WARP_CLASS || nd->class_ == FLAG_CLASS) { //Client won't display option changes for these classes [Toms] if (nd->sc.option&(OPTION_HIDE|OPTION_INVISIBLE)) - clif_clearunit_area(&nd->bl, 0); + clif_clearunit_area(&nd->bl, CLR_OUTSIGHT); else clif_spawn(&nd->bl); } else @@ -206,7 +206,7 @@ int npc_event_dequeue(struct map_session_data* sd) if(sd->npc_id) { //Current script is aborted. if(sd->state.using_fake_npc){ - clif_clearunit_single(sd->npc_id, 0, sd->fd); + clif_clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd); sd->state.using_fake_npc = 0; } if (sd->st) { @@ -866,7 +866,7 @@ int npc_touch_areanpc(struct map_session_data* sd, int m, int x, int y) case WARP: if( pc_ishiding(sd) ) break; // hidden chars cannot use warps - pc_setpos(sd,map[m].npc[i]->u.warp.mapindex,map[m].npc[i]->u.warp.x,map[m].npc[i]->u.warp.y,0); + pc_setpos(sd,map[m].npc[i]->u.warp.mapindex,map[m].npc[i]->u.warp.x,map[m].npc[i]->u.warp.y,CLR_OUTSIGHT); break; case SCRIPT: if( npc_ontouch_event(sd,map[m].npc[i]) > 0 && npc_ontouch2_event(sd,map[m].npc[i]) > 0 ) @@ -923,7 +923,7 @@ int npc_touch_areanpc2(struct mob_data *md) xs = map_mapindex2mapid(map[m].npc[i]->u.warp.mapindex); if( m < 0 ) break; // Cannot Warp between map servers - if( unit_warp(&md->bl, xs, map[m].npc[i]->u.warp.x, map[m].npc[i]->u.warp.y, 0) == 0 ) + if( unit_warp(&md->bl, xs, map[m].npc[i]->u.warp.x, map[m].npc[i]->u.warp.y, CLR_OUTSIGHT) == 0 ) return 1; // Warped break; case SCRIPT: @@ -1451,7 +1451,7 @@ int npc_remove_map(struct npc_data* nd) if(nd->bl.prev == NULL || nd->bl.m < 0) return 1; //Not assigned to a map. m = nd->bl.m; - clif_clearunit_area(&nd->bl,2); + clif_clearunit_area(&nd->bl,CLR_RESPAWN); npc_unsetcells(nd); map_delblock(&nd->bl); //Remove npc from map[].npc list. [Skotlex] @@ -2550,7 +2550,7 @@ void npc_setclass(struct npc_data* nd, short class_) if( nd->class_ == class_ ) return; - clif_clearunit_area(&nd->bl, 0);// fade out + clif_clearunit_area(&nd->bl, CLR_OUTSIGHT);// fade out nd->class_ = class_; status_set_viewdata(&nd->bl, class_); clif_spawn(&nd->bl);// fade in @@ -3280,7 +3280,7 @@ int npc_reload(void) npc_unload((struct npc_data *)bl); break; case BL_MOB: - unit_free(bl,0); + unit_free(bl,CLR_OUTSIGHT); break; } } @@ -3360,7 +3360,7 @@ int do_final_npc(void) if (bl->type == BL_NPC) npc_unload((struct npc_data *)bl); else if (bl->type&(BL_MOB|BL_PET|BL_HOM|BL_MER)) - unit_free(bl, 0); + unit_free(bl, CLR_OUTSIGHT); } } diff --git a/src/map/pc.c b/src/map/pc.c index 6c8b94485..902463cb0 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -910,11 +910,11 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim sd->hate_mob[i] = -1; // 位置の設定 - if ((i=pc_setpos(sd,sd->status.last_point.map, sd->status.last_point.x, sd->status.last_point.y, 0)) != 0) { + if ((i=pc_setpos(sd,sd->status.last_point.map, sd->status.last_point.x, sd->status.last_point.y, CLR_OUTSIGHT)) != 0) { ShowError ("Last_point_map %s - id %d not found (error code %d)\n", mapindex_id2name(sd->status.last_point.map), sd->status.last_point.map, i); // try warping to a default map instead (church graveyard) - if (pc_setpos(sd, mapindex_name2id(MAP_PRONTERA), 273, 354, 0) != 0) { + if (pc_setpos(sd, mapindex_name2id(MAP_PRONTERA), 273, 354, CLR_OUTSIGHT) != 0) { // if we fail again clif_authfail_fd(sd->fd, 0); return false; @@ -1439,7 +1439,7 @@ int pc_disguise(struct map_session_data *sd, int class_) if (sd->bl.prev != NULL) { pc_stop_walking(sd, 0); - clif_clearunit_area(&sd->bl, 0); + clif_clearunit_area(&sd->bl, CLR_OUTSIGHT); } if (!class_) { @@ -4038,7 +4038,7 @@ int pc_steal_coin(struct map_session_data *sd,struct block_list *target) * 1 - Invalid map index. * 2 - Map not in this map-server, and failed to locate alternate map-server. *------------------------------------------*/ -int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, uint8 clrtype) +int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, clr_type clrtype) { struct party_data *p; int m; @@ -4196,7 +4196,7 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y /*========================================== * PCのランダムワ?プ *------------------------------------------*/ -int pc_randomwarp(struct map_session_data *sd, int type) +int pc_randomwarp(struct map_session_data *sd, clr_type type) { int x,y,i=0; int m; @@ -4704,7 +4704,7 @@ int pc_follow_timer(int tid, unsigned int tick, int id, intptr data) if (!check_distance_bl(&sd->bl, tbl, 5)) unit_walktobl(&sd->bl, tbl, 5, 0); } else - pc_setpos(sd, map_id2index(tbl->m), tbl->x, tbl->y, 3); + pc_setpos(sd, map_id2index(tbl->m), tbl->x, tbl->y, CLR_TELEPORT); } sd->followtimer = add_timer( tick + 1000, // increase time a bit to loosen up map's load @@ -5520,7 +5520,7 @@ int pc_skillheal2_bonus(struct map_session_data *sd, int skill_num) return bonus; } -void pc_respawn(struct map_session_data* sd, uint8 clrtype) +void pc_respawn(struct map_session_data* sd, clr_type clrtype) { if( !pc_isdead(sd) ) return; // not applicable @@ -5539,7 +5539,7 @@ static int pc_respawn_timer(int tid, unsigned int tick, int id, intptr data) if( sd != NULL ) { sd->pvp_point=0; - pc_respawn(sd,0); + pc_respawn(sd,CLR_OUTSIGHT); } return 0; diff --git a/src/map/pc.h b/src/map/pc.h index 9c9408da6..16c8ec3fc 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -545,7 +545,7 @@ bool pc_can_give_items(int level); int pc_setrestartvalue(struct map_session_data *sd,int type); int pc_makesavestatus(struct map_session_data *); -void pc_respawn(struct map_session_data* sd, uint8 clrtype); +void pc_respawn(struct map_session_data* sd, clr_type clrtype); int pc_setnewpc(struct map_session_data*,int,int,int,unsigned int,int,int); bool pc_authok(struct map_session_data* sd, int, time_t, int gmlevel, struct mmo_charstatus* status); void pc_authfail(struct map_session_data *); @@ -566,11 +566,11 @@ int pc_clean_skilltree(struct map_session_data *sd); #define pc_checkoverhp(sd) (sd->battle_status.hp == sd->battle_status.max_hp) #define pc_checkoversp(sd) (sd->battle_status.sp == sd->battle_status.max_sp) -int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, uint8 clrtype); +int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, clr_type clrtype); int pc_setsavepoint(struct map_session_data*,short,int,int); -int pc_randomwarp(struct map_session_data *sd,int type); +int pc_randomwarp(struct map_session_data *sd,clr_type type); int pc_memo(struct map_session_data* sd, int pos); -int pc_remove_map(struct map_session_data *sd,int clrtype); +int pc_remove_map(struct map_session_data *sd,clr_type clrtype); int pc_checkadditem(struct map_session_data*,int,int); int pc_inventoryblank(struct map_session_data*); diff --git a/src/map/pet.c b/src/map/pet.c index d02f93446..d3758b9e5 100644 --- a/src/map/pet.c +++ b/src/map/pet.c @@ -306,7 +306,7 @@ static int pet_return_egg(struct map_session_data *sd, struct pet_data *pd) map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } pd->pet.incuvate = 1; - unit_free(&pd->bl,0); + unit_free(&pd->bl,CLR_OUTSIGHT); status_calc_pc(sd,0); sd->status.pet_id = 0; @@ -523,7 +523,7 @@ int pet_catch_process2(struct map_session_data* sd, int target_id) if(rand()%10000 < pet_catch_rate) { - unit_remove_map(&md->bl,0); + unit_remove_map(&md->bl,CLR_OUTSIGHT); status_kill(&md->bl); clif_pet_roulette(sd,1); intif_create_pet(sd->status.account_id,sd->status.char_id,pet_db[i].class_,mob_db(pet_db[i].class_)->lv, diff --git a/src/map/script.c b/src/map/script.c index 589129b2e..c6c9c3591 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -3335,7 +3335,7 @@ void run_script_main(struct script_state *st) if ((sd = map_id2sd(st->rid))!=NULL) { //Restore previous stack and save char. if(sd->state.using_fake_npc){ - clif_clearunit_single(sd->npc_id, 0, sd->fd); + clif_clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd); sd->state.using_fake_npc = 0; } //Restore previous script if any. @@ -4136,11 +4136,11 @@ BUILDIN_FUNC(warp) y = script_getnum(st,4); if(strcmp(str,"Random")==0) - ret = pc_randomwarp(sd,3); + ret = pc_randomwarp(sd,CLR_TELEPORT); else if(strcmp(str,"SavePoint")==0 || strcmp(str,"Save")==0) - ret = pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3); + ret = pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT); else - ret = pc_setpos(sd,mapindex_name2id(str),x,y,0); + ret = pc_setpos(sd,mapindex_name2id(str),x,y,CLR_OUTSIGHT); if( ret ) { ShowError("buildin_warp: moving player '%s' to \"%s\",%d,%d failed.\n", sd->status.name, str, x, y); @@ -4160,9 +4160,9 @@ static int buildin_areawarp_sub(struct block_list *bl,va_list ap) x=va_arg(ap,int); y=va_arg(ap,int); if(map == 0) - pc_randomwarp((TBL_PC *)bl,3); + pc_randomwarp((TBL_PC *)bl,CLR_TELEPORT); else - pc_setpos((TBL_PC *)bl,map,x,y,0); + pc_setpos((TBL_PC *)bl,map,x,y,CLR_OUTSIGHT); return 0; } BUILDIN_FUNC(areawarp) @@ -4248,12 +4248,12 @@ BUILDIN_FUNC(warpchar) return 0; if(strcmp(str, "Random") == 0) - pc_randomwarp(sd, 3); + pc_randomwarp(sd, CLR_TELEPORT); else if(strcmp(str, "SavePoint") == 0) - pc_setpos(sd, sd->status.save_point.map,sd->status.save_point.x, sd->status.save_point.y, 3); + pc_setpos(sd, sd->status.save_point.map,sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT); else - pc_setpos(sd, mapindex_name2id(str), x, y, 3); + pc_setpos(sd, mapindex_name2id(str), x, y, CLR_TELEPORT); return 0; } @@ -4310,15 +4310,15 @@ BUILDIN_FUNC(warpparty) { case 0: // Random if(!map[pl_sd->bl.m].flag.nowarp) - pc_randomwarp(pl_sd,3); + pc_randomwarp(pl_sd,CLR_TELEPORT); break; case 1: // SavePointAll if(!map[pl_sd->bl.m].flag.noreturn) - pc_setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,3); + pc_setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,CLR_TELEPORT); break; case 2: // SavePoint if(!map[pl_sd->bl.m].flag.noreturn) - pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3); + pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT); break; case 3: // Leader for(j = 0; j < MAX_PARTY && !p->party.member[j].leader; j++); @@ -4334,12 +4334,12 @@ BUILDIN_FUNC(warpparty) continue; if(map[pl_sd->bl.m].flag.noreturn || map[pl_sd->bl.m].flag.nowarp) continue; - pc_setpos(pl_sd,mapindex,x,y,3); + pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT); } break; case 4: // m,x,y if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp) - pc_setpos(pl_sd,mapindex_name2id(str),x,y,3); + pc_setpos(pl_sd,mapindex_name2id(str),x,y,CLR_TELEPORT); break; } } @@ -4388,19 +4388,19 @@ BUILDIN_FUNC(warpguild) { case 0: // Random if(!map[pl_sd->bl.m].flag.nowarp) - pc_randomwarp(pl_sd,3); + pc_randomwarp(pl_sd,CLR_TELEPORT); break; case 1: // SavePointAll if(!map[pl_sd->bl.m].flag.noreturn) - pc_setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,3); + pc_setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,CLR_TELEPORT); break; case 2: // SavePoint if(!map[pl_sd->bl.m].flag.noreturn) - pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3); + pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT); break; case 3: // m,x,y if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp) - pc_setpos(pl_sd,mapindex_name2id(str),x,y,3); + pc_setpos(pl_sd,mapindex_name2id(str),x,y,CLR_TELEPORT); break; } } @@ -9104,16 +9104,16 @@ BUILDIN_FUNC(warpwaitingpc) mapreg_setreg(add_str("$@warpwaitingpc")+(i<<24), sd->bl.id); if( strcmp(map_name,"Random") == 0 ) - pc_randomwarp(sd,3); + pc_randomwarp(sd,CLR_TELEPORT); else if( strcmp(map_name,"SavePoint") == 0 ) { if( map[sd->bl.m].flag.noteleport ) return 0;// can't teleport on this map - pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, 3); + pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT); } else - pc_setpos(sd, mapindex_name2id(map_name), x, y, 0); + pc_setpos(sd, mapindex_name2id(map_name), x, y, CLR_OUTSIGHT); } mapreg_setreg(add_str("$@warpwaitingpcnum"), i); return 0; @@ -9547,7 +9547,7 @@ static int buildin_maprespawnguildid_sub_pc(struct map_session_data* sd, va_list (sd->status.guild_id != g_id && flag&2) || //Warp out outsiders (sd->status.guild_id == 0) // Warp out players not in guild [Valaris] ) - pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3); + pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT); return 1; } @@ -10021,7 +10021,7 @@ BUILDIN_FUNC(mapwarp) // Added by RoVeRT for( i=0; i < g->max_member; i++) { if(g->member[i].sd && g->member[i].sd->bl.m==m){ - pc_setpos(g->member[i].sd,index,x,y,3); + pc_setpos(g->member[i].sd,index,x,y,CLR_TELEPORT); } } } @@ -10031,7 +10031,7 @@ BUILDIN_FUNC(mapwarp) // Added by RoVeRT if(p){ for(i=0;idata[i].sd && p->data[i].sd->bl.m == m){ - pc_setpos(p->data[i].sd,index,x,y,3); + pc_setpos(p->data[i].sd,index,x,y,CLR_TELEPORT); } } } @@ -10194,7 +10194,7 @@ BUILDIN_FUNC(warppartner) mapindex = mapindex_name2id(str); if (mapindex) { - pc_setpos(p_sd,mapindex,x,y,0); + pc_setpos(p_sd,mapindex,x,y,CLR_OUTSIGHT); script_pushint(st,1); } else script_pushint(st,0); @@ -12203,7 +12203,7 @@ BUILDIN_FUNC(setnpcdisplay) npc_setclass(nd, class_); else if( size != -1 ) { // Required to update the visual size - clif_clearunit_area(&nd->bl, 0); + clif_clearunit_area(&nd->bl, CLR_OUTSIGHT); clif_spawn(&nd->bl); } @@ -13068,7 +13068,7 @@ BUILDIN_FUNC(unitwarp) bl = map_id2bl(unit_id); if( map >= 0 && bl != NULL ) - script_pushint(st, unit_warp(bl,map,x,y,0)); + script_pushint(st, unit_warp(bl,map,x,y,CLR_OUTSIGHT)); else script_pushint(st, 0); @@ -13860,7 +13860,7 @@ BUILDIN_FUNC(waitingroom2bg_single) if( bg_team_join(bg_id, sd) ) { - pc_setpos(sd, mapindex, x, y, 3); + pc_setpos(sd, mapindex, x, y, CLR_TELEPORT); script_pushint(st,1); } else @@ -14329,7 +14329,7 @@ BUILDIN_FUNC(instance_warpall) mapindex = map_id2index(m); for( i = 0; i < MAX_PARTY; i++ ) - if( (pl_sd = p->data[i].sd) && map[pl_sd->bl.m].instance_id == st->instance_id ) pc_setpos(pl_sd,mapindex,x,y,3); + if( (pl_sd = p->data[i].sd) && map[pl_sd->bl.m].instance_id == st->instance_id ) pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT); return 0; } diff --git a/src/map/skill.c b/src/map/skill.c index ccc3d96f9..4db0b1e2b 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -2307,11 +2307,11 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr data) switch(skl->skill_id) { case RG_INTIMIDATE: - if (unit_warp(src,-1,-1,-1,3) == 0) { + if (unit_warp(src,-1,-1,-1,CLR_TELEPORT) == 0) { short x,y; map_search_freecell(src, 0, &x, &y, 1, 1, 0); if (target != src && !status_isdead(target)) - unit_warp(target, -1, x, y, 3); + unit_warp(target, -1, x, y, CLR_TELEPORT); } break; case BA_FROSTJOKER: @@ -4418,9 +4418,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in if( sd->state.autocast || ( (sd->skillitem == AL_TELEPORT || battle_config.skip_teleport_lv1_menu) && skilllv == 1 ) || skilllv == 3 ) { if( skilllv == 1 ) - pc_randomwarp(sd,3); + pc_randomwarp(sd,CLR_TELEPORT); else - pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3); + pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT); break; } @@ -4430,12 +4430,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in else clif_skill_warppoint(sd,skillid,skilllv, (unsigned short)-1,sd->status.save_point.map,0,0); } else - unit_warp(bl,-1,-1,-1,3); + unit_warp(bl,-1,-1,-1,CLR_TELEPORT); break; case NPC_EXPULSION: clif_skill_nodamage(src,bl,skillid,skilllv,1); - unit_warp(bl,-1,-1,-1,3); + unit_warp(bl,-1,-1,-1,CLR_TELEPORT); break; case AL_HOLYWATER: @@ -5360,7 +5360,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case 5: // 2000HP heal, random teleported status_heal(src, 2000, 0, 0); if( !map_flag_vs(bl->m) ) - unit_warp(bl, -1,-1,-1, 3); + unit_warp(bl, -1,-1,-1, CLR_TELEPORT); break; case 6: // random 2 other effects if (count == -1) @@ -5530,7 +5530,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in continue; if(map_getcell(src->m,src->x+dx[j],src->y+dy[j],CELL_CHKNOREACH)) dx[j] = dy[j] = 0; - pc_setpos(dstsd, map_id2index(src->m), src->x+dx[j], src->y+dy[j], 2); + pc_setpos(dstsd, map_id2index(src->m), src->x+dx[j], src->y+dy[j], CLR_RESPAWN); } } if (sd) @@ -6643,9 +6643,9 @@ int skill_castend_map (struct map_session_data *sd, short skill_num, const char { case AL_TELEPORT: if(strcmp(map,"Random")==0) - pc_randomwarp(sd,3); + pc_randomwarp(sd,CLR_TELEPORT); else if (sd->menuskill_val > 1) //Need lv2 to be able to warp here. - pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3); + pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT); break; case AL_WARP: @@ -7259,7 +7259,7 @@ static int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, un if( --sg->val1 <= 0 ) skill_delunitgroup(sg); - pc_setpos(sd,m,x,y,3); + pc_setpos(sd,m,x,y,CLR_TELEPORT); sg = src->group; // avoid dangling pointer (pc_setpos can cause deletion of 'sg') } } else @@ -7267,7 +7267,7 @@ static int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, un { int m = map_mapindex2mapid(sg->val3); if (m < 0) break; //Map not available on this map-server. - unit_warp(bl,m,sg->val2>>16,sg->val2&0xffff,3); + unit_warp(bl,m,sg->val2>>16,sg->val2&0xffff,CLR_TELEPORT); } break; @@ -10404,13 +10404,13 @@ static int skill_unit_timer_sub (DBKey key, void* data, va_list ap) sd = map_charid2sd(group->val1); group->val1 = 0; if (sd && !map[sd->bl.m].flag.nowarp) - pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,3); + pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,CLR_TELEPORT); } if(group->val2) { sd = map_charid2sd(group->val2); group->val2 = 0; if (sd && !map[sd->bl.m].flag.nowarp) - pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,3); + pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,CLR_TELEPORT); } skill_delunit(unit); } diff --git a/src/map/status.c b/src/map/status.c index a9bf031e1..3b9213ca5 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -831,16 +831,16 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s status_change_clear(target,0); if(flag&4) //Delete from memory. (also invokes map removal code) - unit_free(target,1); + unit_free(target,CLR_DEAD); else if(flag&2) //remove from map - unit_remove_map(target,1); + unit_remove_map(target,CLR_DEAD); else { //Some death states that would normally be handled by unit_remove_map unit_stop_attack(target); unit_stop_walking(target,1); unit_skillcastcancel(target,0); - clif_clearunit_area(target,1); + clif_clearunit_area(target,CLR_DEAD); skill_unit_move(target,gettick(),4); skill_cleartimerskill(target); } @@ -5953,7 +5953,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val int pos = (bl->x&0xFFFF)|(bl->y<<16), //Current Coordinates map = sd->mapindex; //Current Map //1. Place in Jail (val2 -> Jail Map, val3 -> x, val4 -> y - pc_setpos(sd,(unsigned short)val2,val3,val4, 3); + pc_setpos(sd,(unsigned short)val2,val3,val4, CLR_TELEPORT); //2. Set restore point (val3 -> return map, val4 return coords val3 = map; val4 = pos; @@ -6736,7 +6736,7 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid) break; //natural expiration. if(sd && sd->mapindex == sce->val2) - pc_setpos(sd,(unsigned short)sce->val3,sce->val4&0xFFFF, sce->val4>>16, 3); + pc_setpos(sd,(unsigned short)sce->val3,sce->val4&0xFFFF, sce->val4>>16, CLR_TELEPORT); break; //guess hes not in jail :P case SC_CHANGE: if (tid == -1) diff --git a/src/map/unit.c b/src/map/unit.c index c6f50f819..a1e523fa1 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -641,7 +641,7 @@ int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag) //Warps a unit/ud to a given map/position. //In the case of players, pc_setpos is used. //it respects the no warp flags, so it is safe to call this without doing nowarpto/nowarp checks. -int unit_warp(struct block_list *bl,short m,short x,short y,int type) +int unit_warp(struct block_list *bl,short m,short x,short y,clr_type type) { struct unit_data *ud; nullpo_ret(bl); @@ -650,7 +650,7 @@ int unit_warp(struct block_list *bl,short m,short x,short y,int type) if(bl->prev==NULL || !ud) return 1; - if (type == 1) + if (type == CLR_DEAD) //Type 1 is invalid, since you shouldn't warp a bl with the "death" //animation, it messes up with unit_remove_map! [Skotlex] return 1; @@ -1811,7 +1811,7 @@ int unit_changeviewsize(struct block_list *bl,short size) * Otherwise it is assumed bl is being warped. * On-Kill specific stuff is not performed here, look at status_damage for that. *------------------------------------------*/ -int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int line, const char* func) +int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, int line, const char* func) { struct unit_data *ud = unit_bl2ud(bl); struct status_change *sc = status_get_sc(bl); @@ -1960,7 +1960,7 @@ int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int l { //If logging out, this is deleted on unit_free clif_clearunit_area(bl,clrtype); map_delblock(bl); - unit_free(bl,0); + unit_free(bl,CLR_OUTSIGHT); map_freeblock_unlock(); return 0; } @@ -1976,7 +1976,7 @@ int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int l clif_emotion(bl, 28) ; //sob clif_clearunit_area(bl,clrtype); map_delblock(bl); - unit_free(bl,0); + unit_free(bl,CLR_OUTSIGHT); map_freeblock_unlock(); return 0; } @@ -1990,7 +1990,7 @@ int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int l { clif_clearunit_area(bl,clrtype); map_delblock(bl); - unit_free(bl,0); + unit_free(bl,CLR_OUTSIGHT); map_freeblock_unlock(); return 0; } @@ -2005,11 +2005,11 @@ int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int l return 1; } -void unit_remove_map_pc(struct map_session_data *sd, int clrtype) +void unit_remove_map_pc(struct map_session_data *sd, clr_type clrtype) { unit_remove_map(&sd->bl,clrtype); - if (clrtype == 3) clrtype = 0; //3 is the warp from logging out, but pets/homunc need to just 'vanish' instead of showing the warping out animation. + if (clrtype == CLR_TELEPORT) clrtype = CLR_OUTSIGHT; //CLR_TELEPORT is the warp from logging out, but pets/homunc need to just 'vanish' instead of showing the warping out animation. if(sd->pd) unit_remove_map(&sd->pd->bl, clrtype); @@ -2021,17 +2021,17 @@ void unit_remove_map_pc(struct map_session_data *sd, int clrtype) void unit_free_pc(struct map_session_data *sd) { - if (sd->pd) unit_free(&sd->pd->bl,0); - if (sd->hd) unit_free(&sd->hd->bl,0); - if (sd->md) unit_free(&sd->md->bl,0); - unit_free(&sd->bl,3); + if (sd->pd) unit_free(&sd->pd->bl,CLR_OUTSIGHT); + if (sd->hd) unit_free(&sd->hd->bl,CLR_OUTSIGHT); + if (sd->md) unit_free(&sd->md->bl,CLR_OUTSIGHT); + unit_free(&sd->bl,CLR_TELEPORT); } /*========================================== * Function to free all related resources to the bl * if unit is on map, it is removed using the clrtype specified *------------------------------------------*/ -int unit_free(struct block_list *bl, int clrtype) +int unit_free(struct block_list *bl, clr_type clrtype) { struct unit_data *ud = unit_bl2ud( bl ); nullpo_ret(ud); diff --git a/src/map/unit.h b/src/map/unit.h index 3b82dce56..fd5a83208 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -9,6 +9,7 @@ struct block_list; struct unit_data; struct map_session_data; +#include "clif.h" // clr_type #include "map.h" // struct block_list #include "path.h" // struct walkpath_data #include "skill.h" // struct skill_timerskill, struct skill_unit_group, struct skill_unit_group_tickset @@ -81,7 +82,7 @@ int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int int unit_escape(struct block_list *bl, struct block_list *target, short dist); // 位置の強制移動(吹き飛ばしなど) int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, bool checkpath); -int unit_warp(struct block_list *bl, short map, short x, short y, int type); +int unit_warp(struct block_list *bl, short map, short x, short y, clr_type type); int unit_setdir(struct block_list *bl,unsigned char dir); uint8 unit_getdir(struct block_list *bl); int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag); @@ -114,11 +115,11 @@ void unit_dataset(struct block_list *bl); int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2); // その他 struct unit_data* unit_bl2ud(struct block_list *bl); -void unit_remove_map_pc(struct map_session_data *sd, int clrtype); +void unit_remove_map_pc(struct map_session_data *sd, clr_type clrtype); void unit_free_pc(struct map_session_data *sd); #define unit_remove_map(bl,clrtype) unit_remove_map_(bl,clrtype,__FILE__,__LINE__,__func__) -int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int line, const char* func); -int unit_free(struct block_list *bl, int clrtype); +int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, int line, const char* func); +int unit_free(struct block_list *bl, clr_type clrtype); int unit_changeviewsize(struct block_list *bl,short size); // 初期化ルーチン -- cgit v1.2.3-70-g09d2 From 432ec6db58f1c10a4c1050d5af6ebe329c03cf91 Mon Sep 17 00:00:00 2001 From: ai4rei Date: Sat, 16 Apr 2011 20:15:20 +0000 Subject: * Added support for visible garments/robes. - For SQL apply upgrade_svn14797.sql to upgrade table `char`; for TXT no action is necessary, as it upgrades itself. - This also fixes NPCs not being visible with clients 2011-01-11aRagexeRE+ (bugreport:4865). git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@14797 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 3 +++ db/Changelog.txt | 2 ++ db/item_db.txt | 2 ++ db/packet_db.txt | 5 +++- sql-files/main.sql | 1 + sql-files/upgrade_svn14797.sql | 1 + src/char/char.c | 31 ++++++++++++++++++++---- src/char_sql/char.c | 14 +++++++---- src/common/mmo.h | 2 ++ src/map/clif.c | 53 +++++++++++++++++++++++++++++++++++------- src/map/map.h | 5 +++- src/map/pc.c | 14 +++++++++++ src/map/pc.h | 7 ++++++ src/map/unit.h | 3 ++- 14 files changed, 122 insertions(+), 21 deletions(-) create mode 100644 sql-files/upgrade_svn14797.sql (limited to 'src/map/unit.h') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 41c7f759e..69789a602 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -1,6 +1,9 @@ Date Added 2011/04/16 + * Added support for visible garments/robes. [Ai4rei] + - For SQL apply upgrade_svn14797.sql to upgrade table `char`; for TXT no action is necessary, as it upgrades itself. + - This also fixes NPCs not being visible with clients 2011-01-11aRagexeRE+ (bugreport:4865). * Updated field `weapon` in table `char` to default to '0' (bare-handed) rather than '1' (knife) (follow up to r11696). [Ai4rei] - Apply upgrade_svn14796.sql to reflect the change on existing setups. * Some cleanups related to player and monster states. [Ai4rei] diff --git a/db/Changelog.txt b/db/Changelog.txt index 394e837ce..c1b2a26ed 100644 --- a/db/Changelog.txt +++ b/db/Changelog.txt @@ -9,6 +9,8 @@ 13005 Angelic Wing Dagger: NEED INFO. ======================= +2011/04/16 + * Rev. 14797 Added Archangel Wings (2573) and their respective Box (16998) item based on client-side kRO description. [Ai4rei] 2011/03/19 * Rev. 14748 Fixed Beast Strafing (HT_POWER) SP requirement as provided by Playtester (bugreport:4675). [Gepard] 2011/03/06 diff --git a/db/item_db.txt b/db/item_db.txt index 3effafee9..047bcd9fe 100644 --- a/db/item_db.txt +++ b/db/item_db.txt @@ -1445,6 +1445,7 @@ //2558,Freya_Soul_Scarf4,Freya Soul Scarf, //2559,Guardian_Manteau,Guardian Manteau, //2560,Para_Team_Manteau,Eden Team Manteau,5,0,,0,,14,,0,0xFFFFFFFF,7,2,4,,12,0,0,{ bonus2 bSubEle,Ele_Neutral,10; },{},{} +2573,Archangel_Wings,Archangel Wings,5,0,,200,,18,,1,0xFFFFFFFF,7,2,4,,0,1,1,{},{},{} // Accessories //=================================================================== 2601,Ring,Ring,5,30000,,100,,0,,0,0xFFFFFFFE,7,2,136,,20,0,0,{ bonus bStr,2; },{},{} @@ -6192,6 +6193,7 @@ 16680,Universal_Catalog_Gold_Box50,Universal Catalog Gold 50 Box,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ getitem 12581,50; },{},{} 16776,Universal_Catalog_Gold_Box10,Universal Catalog Gold 10 Box,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ getitem 12581,10; },{},{} 16777,Universal_Catalog_Gold_Box50,Universal Catalog Gold 50 Box,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ getitem 12581,50; },{},{} +16998,Archangel_Wings_Box,Archangel Wings Box,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ getitem 2573,1; },{},{} //18000,Cannon_Ball //18001,Holy_Cannon_Ball //18002,Dark_Cannon_Ball diff --git a/db/packet_db.txt b/db/packet_db.txt index 48d262845..dc5b72346 100644 --- a/db/packet_db.txt +++ b/db/packet_db.txt @@ -1586,7 +1586,7 @@ packet_ver: 25 0x0842,6,recall2,2 0x0843,6,remove2,2 -//2010-11-23aRagexeRE +//2010-11-24aRagexeRE packet_ver: 26 0x0436,19,wanttoconnection,2:6:10:14:18 0x035f,5,walktoxy,2 @@ -1600,6 +1600,9 @@ packet_ver: 26 0x0367,90,useskilltoposinfo,2:4:6:8:10 0x0368,6,getcharnamerequest,2 0x0369,6,solvecharname,2 +0x0856,-1 +0x0857,-1 +0x0858,-1 //Add new packets here //packet_ver: 27 diff --git a/sql-files/main.sql b/sql-files/main.sql index c2a30e086..feafcae3e 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -88,6 +88,7 @@ CREATE TABLE IF NOT EXISTS `char` ( `head_top` smallint(6) unsigned NOT NULL default '0', `head_mid` smallint(6) unsigned NOT NULL default '0', `head_bottom` smallint(6) unsigned NOT NULL default '0', + `robe` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0', `last_map` varchar(11) NOT NULL default '', `last_x` smallint(4) unsigned NOT NULL default '53', `last_y` smallint(4) unsigned NOT NULL default '111', diff --git a/sql-files/upgrade_svn14797.sql b/sql-files/upgrade_svn14797.sql new file mode 100644 index 000000000..acf6fb33d --- /dev/null +++ b/sql-files/upgrade_svn14797.sql @@ -0,0 +1 @@ +ALTER TABLE `char` ADD `robe` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0' AFTER `head_bottom`; diff --git a/src/char/char.c b/src/char/char.c index 237e04638..178a20262 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -525,7 +525,7 @@ int mmo_char_tostr(char *str, struct mmo_charstatus *p, struct global_reg *reg, "%d\t%d,%d\t%s\t%d,%d,%d\t%u,%u,%d" //Up to Zeny field "\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" //Up to Skill Point "\t%d,%d,%d\t%d,%d,%d,%d" //Up to hom id - "\t%d,%d,%d\t%d,%d,%d,%d,%d" //Up to head bottom + "\t%d,%d,%d\t%d,%d,%d,%d,%d,%d" //Up to robe "\t%d,%d,%d\t%d,%d,%d" //last point + save point ",%d,%d,%d,%d,%d,%lu\t", //Family info + delete date p->char_id, p->account_id, p->slot, p->name, // @@ -537,7 +537,7 @@ int mmo_char_tostr(char *str, struct mmo_charstatus *p, struct global_reg *reg, p->option, p->karma, p->manner, // p->party_id, p->guild_id, p->pet_id, p->hom_id, p->hair, p->hair_color, p->clothes_color, - p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, + p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, p->robe, p->last_point.map, p->last_point.x, p->last_point.y, // p->save_point.map, p->save_point.x, p->save_point.y, p->partner_id,p->father,p->mother,p->child,p->fame, // @@ -599,7 +599,26 @@ int mmo_char_fromstr(char *str, struct mmo_charstatus *p, struct global_reg *reg // initilialise character memset(p, '\0', sizeof(struct mmo_charstatus)); -// Char structure of version 146xx (delete date) +// Char structure of version 14797 (robe) + if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" + "\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d,%d" + "\t%d,%d,%d\t%d,%d,%d,%d,%d,%d,%d,%d,%lu%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], + &tmp_int[3], &tmp_int[4], &tmp_int[5], + &tmp_uint[0], &tmp_uint[1], &tmp_int[8], + &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], + &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], + &tmp_int[19], &tmp_int[20], + &tmp_int[21], &tmp_int[22], &tmp_int[23], // + &tmp_int[24], &tmp_int[25], &tmp_int[26], &tmp_int[44], + &tmp_int[27], &tmp_int[28], &tmp_int[29], + &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], &tmp_int[47], + &tmp_int[45], &tmp_int[35], &tmp_int[36], + &tmp_int[46], &tmp_int[37], &tmp_int[38], &tmp_int[39], + &tmp_int[40], &tmp_int[41], &tmp_int[42], &tmp_int[43], &tmp_ulong[0], &next) != 50) + { + tmp_int[47] = 0; // robe +// Char structure of version 14700 (delete date) if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" "\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" "\t%d,%d,%d\t%d,%d,%d,%d,%d,%d,%d,%d,%lu%n", @@ -742,7 +761,8 @@ int mmo_char_fromstr(char *str, struct mmo_charstatus *p, struct global_reg *reg tmp_int[45] = mapindex_name2id(tmp_str[1]); tmp_int[46] = mapindex_name2id(tmp_str[2]); } // Char structure of version 1500 (homun + mapindex maps) - } // Char structure of version 146xx (delete date) + } // Char structure of version 14700 (delete date) + } // Char structure of version 14797 (robe) safestrncpy(p->name, tmp_str[0], NAME_LENGTH); //Overflow protection [Skotlex] p->char_id = tmp_int[0]; @@ -793,6 +813,7 @@ int mmo_char_fromstr(char *str, struct mmo_charstatus *p, struct global_reg *reg p->last_point.map = tmp_int[45]; p->save_point.map = tmp_int[46]; p->delete_date = tmp_ulong[0]; + p->robe = tmp_int[47]; #ifndef TXT_SQL_CONVERT // Some checks @@ -1837,7 +1858,7 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p) offset += 4; #endif #if PACKETVER >= 20110111 - WBUFL(buf,128) = 0; // robe sprite id + WBUFL(buf,128) = p->robe; offset += 4; #endif return 106+offset; diff --git a/src/char_sql/char.c b/src/char_sql/char.c index 517ebed10..3b2e508b6 100644 --- a/src/char_sql/char.c +++ b/src/char_sql/char.c @@ -474,7 +474,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p) (p->pet_id != cp->pet_id) || (p->weapon != cp->weapon) || (p->hom_id != cp->hom_id) || (p->shield != cp->shield) || (p->head_top != cp->head_top) || (p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom) || (p->delete_date != cp->delete_date) || - (p->rename != cp->rename) + (p->rename != cp->rename) || (p->robe != cp->robe) ) { //Save status if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `base_level`='%d', `job_level`='%d'," @@ -484,7 +484,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p) "`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d'," "`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d'," "`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d'," - "`delete_date`='%lu'" + "`delete_date`='%lu',`robe`='%d'" " WHERE `account_id`='%d' AND `char_id` = '%d'", char_db, p->base_level, p->job_level, p->base_exp, p->job_exp, p->zeny, @@ -495,6 +495,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p) mapindex_id2name(p->last_point.map), p->last_point.x, p->last_point.y, mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename, (unsigned long)p->delete_date, // FIXME: platform-dependent size + p->robe, p->account_id, p->char_id) ) { Sql_ShowDebug(sql_handle); @@ -844,7 +845,8 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) "`char_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`," "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," "`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`," - "`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`rename`,`delete_date`" + "`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`rename`,`delete_date`," + "`robe`" " FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", char_db, sd->account_id, MAX_CHARS) || SQL_ERROR == SqlStmt_Execute(stmt) || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p.char_id, 0, NULL, NULL) @@ -882,6 +884,7 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p.rename, 0, NULL, NULL) || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_UINT32, &p.delete_date, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p.robe, 0, NULL, NULL) ) { SqlStmt_ShowDebug(stmt); @@ -940,7 +943,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," "`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`hair`," "`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`," - "`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`" + "`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`" " FROM `%s` WHERE `char_id`=? LIMIT 1", char_db) || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) || SQL_ERROR == SqlStmt_Execute(stmt) @@ -994,6 +997,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything || SQL_ERROR == SqlStmt_BindColumn(stmt, 47, SQLDT_INT, &p->fame, 0, NULL, NULL) || SQL_ERROR == SqlStmt_BindColumn(stmt, 48, SQLDT_SHORT, &p->rename, 0, NULL, NULL) || SQL_ERROR == SqlStmt_BindColumn(stmt, 49, SQLDT_UINT32, &p->delete_date, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 50, SQLDT_SHORT, &p->robe, 0, NULL, NULL) ) { SqlStmt_ShowDebug(stmt); @@ -1615,7 +1619,7 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p) offset += 4; #endif #if PACKETVER >= 20110111 - WBUFL(buf,128) = 0; // robe sprite id + WBUFL(buf,128) = p->robe; offset += 4; #endif return 106+offset; diff --git a/src/common/mmo.h b/src/common/mmo.h index 857d42581..c45cec9a0 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -39,6 +39,7 @@ // 20100721 - 2010-07-21aRagexeRE+ - 0x6b, 0x6d // 20100727 - 2010-07-27aRagexeRE+ - 0x6b, 0x6d // 20100803 - 2010-08-03aRagexeRE+ - 0x6b, 0x6d, 0x827, 0x828, 0x829, 0x82a, 0x82b, 0x82c, 0x842, 0x843 +// 20101124 - 2010-11-24aRagexeRE+ - 0x856, 0x857, 0x858 // 20110111 - 2011-01-11aRagexeRE+ - 0x6b, 0x6d #ifndef PACKETVER @@ -330,6 +331,7 @@ struct mmo_charstatus { short weapon; // enum weapon_type short shield; // view-id short head_top,head_mid,head_bottom; + short robe; char name[NAME_LENGTH]; unsigned int base_level,job_level; diff --git a/src/map/clif.c b/src/map/clif.c index d1338314f..0bd3519ff 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -797,13 +797,19 @@ static int clif_set_unit_idle(struct block_list* bl, unsigned char* buffer, bool WBUFW(buf,0) = spawn?0x22b:0x22a; #elif PACKETVER < 20091103 WBUFW(buf,0) = spawn?0x2ed:0x2ee; -#else +#elif PACKETVER < 20101124 WBUFW(buf,0) = spawn?0x7f8:0x7f9; +#else + WBUFW(buf,0) = spawn?0x858:0x857; #endif #if PACKETVER >= 20091103 name = status_get_name(bl); +#if PACKETVER < 20110111 WBUFW(buf,2) = (spawn?62:63)+strlen(name); +#else + WBUFW(buf,2) = (spawn?64:65)+strlen(name); +#endif WBUFB(buf,4) = clif_bl_type(bl); offset+=3; buf = WBUFP(buffer,offset); @@ -876,6 +882,11 @@ static int clif_set_unit_idle(struct block_list* bl, unsigned char* buffer, bool WBUFB(buf,40) = 0; return packet_len(0x7c); } +#endif +#if PACKETVER >= 20110111 + WBUFW(buf,34) = vd->robe; + offset+= 2; + buf = WBUFP(buf,offset); #endif WBUFL(buf,34) = status_get_guild_id(bl); WBUFW(buf,38) = status_get_emblem_id(bl); @@ -946,13 +957,19 @@ static int clif_set_unit_walking(struct block_list* bl, struct unit_data* ud, un WBUFW(buf, 0) = 0x22c; #elif PACKETVER < 20091103 WBUFW(buf, 0) = 0x2ec; -#else +#elif PACKETVER < 20101124 WBUFW(buf, 0) = 0x7f7; +#else + WBUFW(buf, 0) = 0x856; #endif #if PACKETVER >= 20091103 name = status_get_name(bl); +#if PACKETVER < 20110111 WBUFW(buf, 2) = 69+strlen(name); +#else + WBUFW(buf, 2) = 71+strlen(name); +#endif offset+=2; buf = WBUFP(buffer,offset); #endif @@ -989,6 +1006,11 @@ static int clif_set_unit_walking(struct block_list* bl, struct unit_data* ud, un WBUFW(buf,32) = vd->hair_color; WBUFW(buf,34) = vd->cloth_color; WBUFW(buf,36) = (sd)? sd->head_dir : 0; +#if PACKETVER >= 20110111 + WBUFW(buf,38) = vd->robe; + offset+= 2; + buf = WBUFP(buf,offset); +#endif WBUFL(buf,38) = status_get_guild_id(bl); WBUFW(buf,42) = status_get_emblem_id(bl); WBUFW(buf,44) = (sd)? sd->status.manner : 0; @@ -2057,7 +2079,7 @@ void clif_inventorylist(struct map_session_data *sd) WBUFW(bufe,ne*se+28)=0; //Unknown #endif #if PACKETVER >= 20100629 - if (sd->inventory_data[i]->equip&EQP_HELM) + if (sd->inventory_data[i]->equip&EQP_VISIBLE) WBUFW(bufe,ne*se+30)= sd->inventory_data[i]->look; else WBUFW(bufe,ne*se+30)=0; @@ -2140,7 +2162,7 @@ void clif_equiplist(struct map_session_data *sd) WBUFW(buf,n*cmd+28)=0; //Unknown #endif #if PACKETVER >= 20100629 - if (sd->inventory_data[i]->equip&EQP_HELM) + if (sd->inventory_data[i]->equip&EQP_VISIBLE) WBUFW(buf,n*cmd+30)= sd->inventory_data[i]->look; else WBUFW(buf,n*cmd+30)=0; @@ -2705,6 +2727,17 @@ void clif_changelook(struct block_list *bl,int type,int val) #endif //Shoes? No packet uses this.... break; + case LOOK_BODY: + case LOOK_FLOOR: + // unknown purpose + break; + case LOOK_ROBE: +#if PACKETVER < 20110111 + return; +#else + vd->robe = val; +#endif + break; } // prevent leaking the presence of GM-hidden objects @@ -2726,8 +2759,7 @@ void clif_changelook(struct block_list *bl,int type,int val) WBUFW(buf,9)=vd->shield; } else { WBUFB(buf,6)=type; - WBUFW(buf,7)=val; - WBUFW(buf,9)=0; + WBUFL(buf,7)=val; } clif_send(buf,packet_len(0x1d7),bl,target); #endif @@ -2952,7 +2984,7 @@ int clif_equipitemack(struct map_session_data *sd,int n,int pos,int ok) #if PACKETVER < 20100629 WFIFOB(fd,6)=ok; #else - if (ok && sd->inventory_data[n]->equip&EQP_HELM) + if (ok && sd->inventory_data[n]->equip&EQP_VISIBLE) WFIFOW(fd,6)=sd->inventory_data[n]->look; else WFIFOW(fd,6)=0; @@ -8072,7 +8104,7 @@ void clif_viewequip_ack(struct map_session_data* sd, struct map_session_data* ts WFIFOL(fd, n*s+63) = tsd->status.inventory[i].expire_time; WFIFOW(fd, n*s+67) = 0; #if PACKETVER >= 20100629 - if (tsd->inventory_data[i]->equip&EQP_HELM) + if (tsd->inventory_data[i]->equip&EQP_VISIBLE) WFIFOW(fd, n*s+69) = tsd->inventory_data[i]->look; else WFIFOW(fd, n*s+69) = 0; @@ -14978,6 +15010,11 @@ static int packetdb_readdb(void) 3, -1, 8, -1, 86, 2, 6, 6, -1, -1, 4, 10, 10, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 3, 2, 66, 5, 2, 12, 6, 0, 0, + //#0x0840 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -1, -1, -1, 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, 0, 0, 0, 0, 0, 0, 0, }; struct { void (*func)(int, struct map_session_data *); diff --git a/src/map/map.h b/src/map/map.h index 3b1775e46..8e0c11a03 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -354,7 +354,10 @@ enum _look { LOOK_HAIR_COLOR, LOOK_CLOTHES_COLOR, LOOK_SHIELD, - LOOK_SHOES + LOOK_SHOES, + LOOK_BODY, + LOOK_FLOOR, + LOOK_ROBE, }; // used by map_setcell() diff --git a/src/map/pc.c b/src/map/pc.c index 4cfec2de8..e1ecc171e 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -6398,6 +6398,7 @@ int pc_equiplookall(struct map_session_data *sd) clif_changelook(&sd->bl,LOOK_HEAD_BOTTOM,sd->status.head_bottom); clif_changelook(&sd->bl,LOOK_HEAD_TOP,sd->status.head_top); clif_changelook(&sd->bl,LOOK_HEAD_MID,sd->status.head_mid); + clif_changelook(&sd->bl, LOOK_ROBE, sd->status.robe); return 0; } @@ -6454,6 +6455,9 @@ int pc_changelook(struct map_session_data *sd,int type,int val) break; case LOOK_SHOES: break; + case LOOK_ROBE: + sd->status.robe = val; + break; } clif_changelook(&sd->bl,type,val); return 0; @@ -7184,6 +7188,11 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) } if(pos & EQP_SHOES) clif_changelook(&sd->bl,LOOK_SHOES,0); + if( pos&EQP_GARMENT ) + { + sd->status.robe = id ? id->look : 0; + clif_changelook(&sd->bl, LOOK_ROBE, sd->status.robe); + } pc_checkallowskill(sd); //Check if status changes should be halted. @@ -7274,6 +7283,11 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) } if(sd->status.inventory[n].equip & EQP_SHOES) clif_changelook(&sd->bl,LOOK_SHOES,0); + if( sd->status.inventory[n].equip&EQP_GARMENT ) + { + sd->status.robe = 0; + clif_changelook(&sd->bl, LOOK_ROBE, 0); + } clif_unequipitemack(sd,n,sd->status.inventory[n].equip,1); diff --git a/src/map/pc.h b/src/map/pc.h index 7b14d45d8..9ed474b13 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -494,6 +494,13 @@ enum equip_pos { #define EQP_HELM (EQP_HEAD_LOW|EQP_HEAD_MID|EQP_HEAD_TOP) #define EQP_ACC (EQP_ACC_L|EQP_ACC_R) +/// Equip positions that use a visible sprite +#if PACKETVER < 20110111 + #define EQP_VISIBLE EQP_HELM +#else + #define EQP_VISIBLE (EQP_HELM|EQP_GARMENT) +#endif + //Equip indexes constants. (eg: sd->equip_index[EQI_AMMO] returns the index //where the arrows are equipped) enum equip_index { diff --git a/src/map/unit.h b/src/map/unit.h index fd5a83208..e349a7466 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -47,9 +47,10 @@ struct unit_data { struct view_data { unsigned short - class_, + class_, weapon, shield, //Or left-hand weapon. + robe, head_top, head_mid, head_bottom, -- cgit v1.2.3-70-g09d2 From ce9b9e74f648f3dd52e4161d3183612ecd002f80 Mon Sep 17 00:00:00 2001 From: shennetsind Date: Mon, 5 Dec 2011 20:51:58 +0000 Subject: Merging RREmu into rAthena -- quite a few stuff yet to be renamed, but we'll get it sorted. Some of the stuff included in RREmu that is now part of rAthena: - RE Drop Rate Modifier - RE Experience Rate Modifier - RE Weapon MATK - RE Shield ASPD job-specific penalty - RE Cast Time - Renewal-specific item DEF - 3.1 classes. - All-New Mounts - Official Magical Reflection - And other perks, such as fully-functional @mapflag also merged eAthena 15006 into rAthena. For Bugs, Comments and Suggestions: http://rathena.org/board/tracker/ git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@15009 54d463be-8e91-2dee-dedb-b68131a5f0ec --- RAthena-6.dsw | 149 -- RAthena-7.1.sln | 69 - RAthena-8.sln | 139 -- conf/battle/player.conf | 3 + conf/map_athena.conf | 8 + db/exp.txt | 4 + db/item_db.txt | 230 +-- db/item_db_re.txt | 305 ++++ db/job_db1.txt | 71 + db/job_db2.txt | 71 + db/magicmushroom_db.txt | 26 + db/mob_db.txt | 14 +- db/mob_skill_db.txt | 25 + db/packet_db.txt | 4 +- db/produce_db.txt | 47 + db/quest_db.txt | 26 +- db/re_job_db.txt | 230 +++ db/skill_cast_db.txt | 1673 ++++++++++++----- db/skill_db.txt | 173 +- db/skill_require_db.txt | 160 +- db/skill_tree.txt | 670 ++++++- db/skill_unit_db.txt | 21 + db/spellbook_db.txt | 29 + db/statpoint_renewal.txt | 255 +++ sql-files/main.sql | 2 +- sql-files/upgrade_svn15003.sql | 1 + src/common/mmo.h | 55 +- src/common/showmsg.c | 27 + src/common/showmsg.h | 1 + src/map/Makefile.in | 4 +- src/map/RRConfig/Core.h | 28 + src/map/RRConfig/Data/Const.h | 33 + src/map/RRConfig/Renewal.h | 53 + src/map/RRConfig/Secure.h | 36 + src/map/RRConfig/Skills/General.h | 23 + src/map/RRConfig/Skills/Mage_Classes.h | 19 + src/map/RRConfig/Skills/Swordsman_Classes.h | 19 + src/map/atcommand.c | 330 +++- src/map/battle.c | 620 ++++++- src/map/battle.h | 7 +- src/map/chrif.c | 8 +- src/map/clif.c | 696 +++++--- src/map/clif.h | 30 +- src/map/itemdb.c | 49 +- src/map/itemdb.h | 42 +- src/map/map.c | 156 +- src/map/map.h | 43 +- src/map/mob.c | 27 +- src/map/mob.h | 5 + src/map/npc.c | 44 +- src/map/npc.h | 7 + src/map/party.c | 63 +- src/map/party.h | 5 + src/map/pc.c | 228 ++- src/map/pc.h | 47 +- src/map/script.c | 182 +- src/map/skill.c | 2570 +++++++++++++++++++++++++-- src/map/skill.h | 59 +- src/map/status.c | 1764 +++++++++++++++++- src/map/status.h | 281 ++- src/map/unit.c | 80 +- src/map/unit.h | 4 + vcproj-10/map-server_sql.vcxproj | 7 + vcproj-10/map-server_sql.vcxproj.filters | 3 + vcproj-10/map-server_txt.vcxproj | 7 + vcproj-10/map-server_txt.vcxproj.filters | 3 + vcproj-10/mapcache.vcxproj.filters | 6 + vcproj-6/char-server_sql.dsp | 324 ---- vcproj-6/char-server_txt.dsp | 300 ---- vcproj-6/login-server_sql.dsp | 276 --- vcproj-6/login-server_txt.dsp | 276 --- vcproj-6/map-server_sql.dsp | 528 ------ vcproj-6/map-server_txt.dsp | 528 ------ vcproj-6/mapcache.dsp | 160 -- vcproj-6/plugin-console.dsp | 107 -- vcproj-6/plugin-pid.dsp | 107 -- vcproj-6/txt-converter-char.dsp | 576 ------ vcproj-6/txt-converter-login.dsp | 200 --- vcproj-7.1/char-server_sql.vcproj | 332 ---- vcproj-7.1/char-server_txt.vcproj | 307 ---- vcproj-7.1/login-server_sql.vcproj | 291 --- vcproj-7.1/login-server_txt.vcproj | 288 --- vcproj-7.1/map-server_sql.vcproj | 490 ----- vcproj-7.1/map-server_txt.vcproj | 484 ----- vcproj-7.1/mapcache.vcproj | 199 --- vcproj-8/char-server_sql.vcproj | 445 ----- vcproj-8/char-server_txt.vcproj | 411 ----- vcproj-8/dbghelpplug.vcproj | 211 --- vcproj-8/login-server_sql.vcproj | 391 ---- vcproj-8/login-server_txt.vcproj | 374 ---- vcproj-8/map-server_sql.vcproj | 654 ------- vcproj-8/map-server_txt.vcproj | 645 ------- vcproj-8/mapcache.vcproj | 269 --- vcproj-8/plugin-console.vcproj | 234 --- vcproj-8/plugin-pid.vcproj | 234 --- vcproj-8/txt-converter-char.vcproj | 505 ------ vcproj-8/txt-converter-login.vcproj | 301 ---- vcproj-9/char-server_sql.vcproj | 2 +- vcproj-9/char-server_txt.vcproj | 2 +- vcproj-9/login-server_sql.vcproj | 2 +- vcproj-9/login-server_txt.vcproj | 2 +- vcproj-9/map-server_sql.vcproj | 70 +- vcproj-9/map-server_txt.vcproj | 28 + vcproj-9/mapcache.vcproj | 4 +- vcproj-9/plugin-console.vcproj | 2 +- vcproj-9/plugin-pid.vcproj | 2 +- vcproj-9/txt-converter-char.vcproj | 2 +- vcproj-9/txt-converter-login.vcproj | 2 +- 108 files changed, 10547 insertions(+), 12094 deletions(-) delete mode 100644 RAthena-6.dsw delete mode 100644 RAthena-7.1.sln delete mode 100644 RAthena-8.sln create mode 100644 db/item_db_re.txt create mode 100644 db/magicmushroom_db.txt create mode 100644 db/re_job_db.txt create mode 100644 db/spellbook_db.txt create mode 100644 db/statpoint_renewal.txt create mode 100644 sql-files/upgrade_svn15003.sql create mode 100644 src/map/RRConfig/Core.h create mode 100644 src/map/RRConfig/Data/Const.h create mode 100644 src/map/RRConfig/Renewal.h create mode 100644 src/map/RRConfig/Secure.h create mode 100644 src/map/RRConfig/Skills/General.h create mode 100644 src/map/RRConfig/Skills/Mage_Classes.h create mode 100644 src/map/RRConfig/Skills/Swordsman_Classes.h delete mode 100644 vcproj-6/char-server_sql.dsp delete mode 100644 vcproj-6/char-server_txt.dsp delete mode 100644 vcproj-6/login-server_sql.dsp delete mode 100644 vcproj-6/login-server_txt.dsp delete mode 100644 vcproj-6/map-server_sql.dsp delete mode 100644 vcproj-6/map-server_txt.dsp delete mode 100644 vcproj-6/mapcache.dsp delete mode 100644 vcproj-6/plugin-console.dsp delete mode 100644 vcproj-6/plugin-pid.dsp delete mode 100644 vcproj-6/txt-converter-char.dsp delete mode 100644 vcproj-6/txt-converter-login.dsp delete mode 100644 vcproj-7.1/char-server_sql.vcproj delete mode 100644 vcproj-7.1/char-server_txt.vcproj delete mode 100644 vcproj-7.1/login-server_sql.vcproj delete mode 100644 vcproj-7.1/login-server_txt.vcproj delete mode 100644 vcproj-7.1/map-server_sql.vcproj delete mode 100644 vcproj-7.1/map-server_txt.vcproj delete mode 100644 vcproj-7.1/mapcache.vcproj delete mode 100644 vcproj-8/char-server_sql.vcproj delete mode 100644 vcproj-8/char-server_txt.vcproj delete mode 100644 vcproj-8/dbghelpplug.vcproj delete mode 100644 vcproj-8/login-server_sql.vcproj delete mode 100644 vcproj-8/login-server_txt.vcproj delete mode 100644 vcproj-8/map-server_sql.vcproj delete mode 100644 vcproj-8/map-server_txt.vcproj delete mode 100644 vcproj-8/mapcache.vcproj delete mode 100644 vcproj-8/plugin-console.vcproj delete mode 100644 vcproj-8/plugin-pid.vcproj delete mode 100644 vcproj-8/txt-converter-char.vcproj delete mode 100644 vcproj-8/txt-converter-login.vcproj (limited to 'src/map/unit.h') diff --git a/RAthena-6.dsw b/RAthena-6.dsw deleted file mode 100644 index ffacdb23c..000000000 --- a/RAthena-6.dsw +++ /dev/null @@ -1,149 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "char_sql"=".\vcproj-6\char-server_sql.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "char_txt"=".\vcproj-6\char-server_txt.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "login_sql"=".\vcproj-6\login-server_sql.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "login_txt"=".\vcproj-6\login-server_txt.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "map_sql"=".\vcproj-6\map-server_sql.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "map_txt"=".\vcproj-6\map-server_txt.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "mapcache"=".\vcproj-6\mapcache.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "plugin_console"=".\vcproj-6\plugin-console.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "plugin_pid"=".\vcproj-6\plugin-pid.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "txt_converter_char"=".\vcproj-6\txt-converter-char.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "txt_converter_login"=".\vcproj-6\txt-converter-login.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff --git a/RAthena-7.1.sln b/RAthena-7.1.sln deleted file mode 100644 index 812905073..000000000 --- a/RAthena-7.1.sln +++ /dev/null @@ -1,69 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 8.00 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "map-server_txt", "vcproj-7.1\map-server_txt.vcproj", "{D356871D-58E1-450B-967A-E1E9646175AF}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "login-server_txt", "vcproj-7.1\login-server_txt.vcproj", "{D356871D-58E1-450B-967A-E2E9646175AF}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "char-server_txt", "vcproj-7.1\char-server_txt.vcproj", "{D356871D-58E1-450B-967A-E3E9646175AF}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "char-server_sql", "vcproj-7.1\char-server_sql.vcproj", "{D356871D-58E1-450B-967A-E4E9646175AF}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "login-server_sql", "vcproj-7.1\login-server_sql.vcproj", "{D356871D-58E1-450B-967A-E5E9646175AF}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "map-server_sql", "vcproj-7.1\map-server_sql.vcproj", "{D356871D-58E1-450B-967A-E6E9646175AF}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mapcache", "vcproj-7.1\mapcache.vcproj", "{CB8556B8-9673-42FD-B2F6-3826534E64E2}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfiguration) = preSolution - Debug = Debug - Release = Release - EndGlobalSection - GlobalSection(ProjectConfiguration) = postSolution - {D356871D-58E1-450B-967A-E1E9646175AF}.Debug.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Debug.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Release.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Release.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Debug.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Debug.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Release.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Release.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Debug.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Debug.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Release.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Release.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Debug.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Debug.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Release.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Release.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Debug.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Debug.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Release.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Release.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Debug.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Debug.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Release.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Release.Build.0 = Release|Win32 - {CB8556B8-9673-42FD-B2F6-3826534E64E2}.Debug.ActiveCfg = Debug|Win32 - {CB8556B8-9673-42FD-B2F6-3826534E64E2}.Debug.Build.0 = Debug|Win32 - {CB8556B8-9673-42FD-B2F6-3826534E64E2}.Release.ActiveCfg = Release|Win32 - {CB8556B8-9673-42FD-B2F6-3826534E64E2}.Release.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - EndGlobalSection - GlobalSection(ExtensibilityAddIns) = postSolution - EndGlobalSection -EndGlobal diff --git a/RAthena-8.sln b/RAthena-8.sln deleted file mode 100644 index 9348cc476..000000000 --- a/RAthena-8.sln +++ /dev/null @@ -1,139 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "map-server_txt", "vcproj-8\map-server_txt.vcproj", "{D356871D-58E1-450B-967A-E1E9646175AF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "login-server_txt", "vcproj-8\login-server_txt.vcproj", "{D356871D-58E1-450B-967A-E2E9646175AF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "char-server_txt", "vcproj-8\char-server_txt.vcproj", "{D356871D-58E1-450B-967A-E3E9646175AF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "char-server_sql", "vcproj-8\char-server_sql.vcproj", "{D356871D-58E1-450B-967A-E4E9646175AF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "login-server_sql", "vcproj-8\login-server_sql.vcproj", "{D356871D-58E1-450B-967A-E5E9646175AF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "map-server_sql", "vcproj-8\map-server_sql.vcproj", "{D356871D-58E1-450B-967A-E6E9646175AF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mapcache", "vcproj-8\mapcache.vcproj", "{D356871D-58E1-450B-967A-E7E9646175AF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "txt-converter-login", "vcproj-8\txt-converter-login.vcproj", "{D356871D-58E1-450B-967A-E9E9646175AF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "txt-converter-char", "vcproj-8\txt-converter-char.vcproj", "{D356871D-58E1-450B-967A-EAE9646175AF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plugin-console", "vcproj-8\plugin-console.vcproj", "{73E1101A-310C-4453-8F45-FD2795ABEF15}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plugin-pid", "vcproj-8\plugin-pid.vcproj", "{9509E1B9-DA2B-4153-9EE0-CBCA6597F198}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug-sql|Win32 = Debug-sql|Win32 - Debug-txt|Win32 = Debug-txt|Win32 - Release|Win32 = Release|Win32 - Release-sql|Win32 = Release-sql|Win32 - Release-txt|Win32 = Release-txt|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D356871D-58E1-450B-967A-E1E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Debug-txt|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Release-txt|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Debug-txt|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Release-txt|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Debug-txt|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Release-txt|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Debug-sql|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Release-sql|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Debug-sql|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Release-sql|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Debug-sql|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Release-sql|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Debug-sql|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Debug-txt|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Release-sql|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Release-txt|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Debug-txt|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Release-txt|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Debug-txt|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Release-txt|Win32.Build.0 = Release|Win32 - {73E1101A-310C-4453-8F45-FD2795ABEF15}.Debug|Win32.ActiveCfg = Debug|Win32 - {73E1101A-310C-4453-8F45-FD2795ABEF15}.Debug|Win32.Build.0 = Debug|Win32 - {73E1101A-310C-4453-8F45-FD2795ABEF15}.Release|Win32.ActiveCfg = Release|Win32 - {73E1101A-310C-4453-8F45-FD2795ABEF15}.Release|Win32.Build.0 = Release|Win32 - {9509E1B9-DA2B-4153-9EE0-CBCA6597F198}.Debug|Win32.ActiveCfg = Debug|Win32 - {9509E1B9-DA2B-4153-9EE0-CBCA6597F198}.Debug|Win32.Build.0 = Debug|Win32 - {9509E1B9-DA2B-4153-9EE0-CBCA6597F198}.Release|Win32.ActiveCfg = Release|Win32 - {9509E1B9-DA2B-4153-9EE0-CBCA6597F198}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/conf/battle/player.conf b/conf/battle/player.conf index d93337429..870bdd0d5 100644 --- a/conf/battle/player.conf +++ b/conf/battle/player.conf @@ -88,6 +88,9 @@ max_sp: 1000000 // Max limit of char stats. (agi, str, etc.) max_parameter: 99 +// Same as max_parameter, but for 3rd classes. +max_third_parameter: 120 + // Same as max_parameter, but for baby classes. max_baby_parameter: 80 diff --git a/conf/map_athena.conf b/conf/map_athena.conf index 0b837b61f..f25f6a695 100644 --- a/conf/map_athena.conf +++ b/conf/map_athena.conf @@ -59,6 +59,14 @@ map_port: 5121 //If redirected output contains escape sequences (color codes) stdout_with_ansisequence: no +//Makes server log selected message types to a file in the /log/ folder +//1: Log Warning Messages +//2: Log Error and SQL Error messages. +//4: Log Debug Messages +//Example: "console_msg_log: 7" logs all 3 kinds +//Messages logged by this overrides console_silent setting +console_msg_log: 0 + //Makes server output more silent by ommitting certain types of messages: //1: Hide Information messages //2: Hide Status messages diff --git a/db/exp.txt b/db/exp.txt index 58310fe24..3733f3050 100644 --- a/db/exp.txt +++ b/db/exp.txt @@ -4,6 +4,8 @@ 99,0:1:2:3:4:5:6:7:8:9:10:11:12:13:14:15:16:17:18:19:20:21:23:24:25:26:4023:4024:4025:4026:4027:4028:4029:4030:4031:4032:4033:4034:4035:4036:4037:4038:4039:4040:4041:4042:4043:4044:4045:4046:4047:4048:4049,0,9,16,25,36,77,112,153,200,253,320,385,490,585,700,830,970,1120,1260,1420,1620,1860,1990,2240,2504,2950,3426,3934,4474,6889,7995,9174,10425,11748,13967,15775,17678,19677,21773,30543,34212,38065,42102,46323,53026,58419,64041,69892,75973,102468,115254,128692,142784,157528,178184,196300,215198,234879,255341,330188,365914,403224,442116,482590,536948,585191,635278,687211,740988,925400,1473746,1594058,1718928,1848355,1982340,2230113,2386162,2547417,2713878,3206160,3681024,4022472,4377024,4744680,5125440,5767272,6204000,6655464,7121664,7602600,9738720,11649960,13643520,18339300,23836800,35658000,48687000,58135000,99999999 //Base - Adv Jobs 99,4001:4002:4003:4004:4005:4006:4007:4008:4009:4010:4011:4012:4013:4014:4015:4016:4017:4018:4019:4020:4021:4022,0,10,18,28,40,85,123,168,220,278,400,481,613,731,875,1038,1213,1400,1575,1775,2268,2604,2786,3136,3506,4130,4796,5508,6264,9645,12392,14220,16159,18209,21649,24451,27401,30499,33748,47342,58160,64711,71573,78749,90144,99312,108870,118816,129154,174196,213220,238080,264150,291427,329640,363155,398116,434526,472381,610848,731828,806448,884232,965180,1073896,1170382,1270556,1374422,1481976,1850800,3389616,3666333,3953534,4251217,4559382,5129260,5488173,5859059,6241919,7374168,9570662,10458427,11380262,12336168,13326144,14994907,16130400,17304200,18516326,19766760,29216160,34949880,40930560,55017900,71510400,106974000,146061000,174405000,343210000 +//Base - 3rd Jobs +150,4054:4055:4056:4057:4058:4059:4060:4061:4062:4063:4064:4065:4066:4067:4068:4069:4070:4071:4072:4073:4074:4075:4076:4077:4078:4079:4080:4081:4082:4083:4084:4085:4086:4087,0,10,18,28,40,85,123,168,220,278,400,481,613,731,875,1038,1213,1400,1575,1775,2268,2604,2786,3136,3506,4130,4796,5508,6264,9645,12392,14220,16159,18209,21649,24451,27401,30499,33748,47342,58160,64711,71573,78749,90144,99312,108870,118816,129154,174196,213220,238080,264150,291427,329640,363155,398116,434526,472381,610848,731828,806448,884232,965180,1073896,1170382,1270556,1374422,1481976,1850800,3389616,3666333,3953534,4251217,4559382,5129260,5488173,5859059,6241919,7374168,9570662,10458427,11380262,12336168,13326144,14994907,16130400,17304200,18516326,19766760,29216160,34949880,40930560,55017900,71510400,106974000,146061000,174405000,343210000,360090500,377815025,396425776,415967065,436485418,459055606,470340701,482190050,494631866,507695773,523372462,531210807,535913813,540851970,546037035,552259113,555370152,558636742,562066663,565668079,569989779,572150629,573447138,574808474,576237876,577953159,579325385,580766222,582279101,583867625,588633194,592445650,596639351,601252423,606326801,616475558,624594564,633525470,643349467,654155864,691978251,722236162,755519863,792131935,832405213,912951771,977389016,1031157636,1153302698,1236233433,1650887110 //Job - Novice 10,0:4023,1,10,18,28,40,91,151,205,268,340 //Job - 1st Classes @@ -22,3 +24,5 @@ 50,4047:4048,1,27434,27434,27434,27434,27434,27434,27434,27434,27434,27434,27434,27434,27434,27434,27434,27434,27434,27434,54868,70216,77154,84412,105416,133942,165376,179088,193338,235642,289842,348402,373354,399168,477234,572732,674294,716870,760752,895370,1053978,1220492,1289472,1587070,1843620,2213516,2521910,2974608,3115314,3981264,4166772 //Job - Ninja/Gunslinger 70,24:25,1,72,92,142,174,301,443,548,799,1270,1838,2145,2473,3339,4746,6385,7172,8002,10321,13717,17554,19288,21103,26354,33485,41344,44772,48334,58910,72460,87100,93338,99792,119308,143183,231068,257377,274363,314246,371105,431038,476309,588548,665256,801731,916689,1130023,1188623,1477408,1551289,1746582,1845236,1954741,2124555,2345698,2548763,2759555,3021488,3254111,3489547,3695474,4012251,4181112,4302211,4496584,4578951,4869523,5022114,5123654,5395117 +//Job - 3rd Jobs (650 3CeAM) +50,4054:4055:4056:4057:4058:4059:4060:4061:4062:4063:4064:4065:4066:4067:4068:4069:4070:4071:4072:4073:4074:4075:4076:4077:4078:4079:4080:4081:4082:4083:4084:4085:4086:4087,1,100000,160000,232000,318400,413440,498976,593066,696564,903561,1069159,1267876,1506337,1792490,2221719,2565102,2977162,3471634,4065001,5251734,6201120,7340384,8707500,10348040,12808849,14777497,17139874,19974727,23376550,30180196,39705300,53992957,75424442,107571670,200798630,247412110,303348286,370471698,451019791,547677504,596006360,646751659,700034223,755980915,814724942,832348150,850852518,870282105,890683171,899999999 diff --git a/db/item_db.txt b/db/item_db.txt index 66e8edc3b..391bd86b1 100644 --- a/db/item_db.txt +++ b/db/item_db.txt @@ -1697,17 +1697,17 @@ 2797,Magical_Stone_,Rocks,5,0,,200,,0,,0,0x00810204,7,2,136,,99,0,0,{ bonus2 bAddDamageClass,2049,10; bonus2 bAddDefClass,2050,-10; bonus3 bAddClassDropItem,6151,2049,70; },{},{} 2798,Will_Of_Exhausted_Angel,Will Of Exhausted Angel,5,0,,200,,0,,0,0x00008100,7,2,136,,99,0,0,{ getmapxy .@map$,.@x,.@y,0; if(.@map$ == "job3_arch02") { bonus2 bAddDefClass,1761,50; bonus2 bAddDefClass,1762,50; } },{},{} 2799,Kuirpenring,Kuirpenring,5,0,,100,,0,,1,0xFFFFFFFF,7,2,136,,0,0,0,{ bonus bMdef,1; },{},{} -2800,Accelerator,Accelerator,5,100000,,100,,0,,1,0x00000000,7,2,136,,99,0,0,{ bonus bAgi,2; },{},{} -2801,Hovering_Booster,Hovering Booster,5,100000,,2000,,0,,1,0x00000000,7,2,136,,99,0,0,{ bonus bAgi,1; },{},{} -2802,Suicidal_Device,Suicidal Device,5,500000,,1000,,0,,1,0x00000000,7,2,136,,99,0,0,{},{},{} -2803,Shape_Shifter,Shape Shifter,5,100000,,500,,0,,1,0x00000000,7,2,136,,99,0,0,{ bonus bInt,3; },{},{} -2804,Cooling_Device,Cooling Device,5,100000,,2500,,0,,1,0x00000000,7,2,136,,99,0,0,{ bonus bDex,1; },{},{} -2805,Magnetic_Field_Generator,Magnetic Field Generator,5,100000,,6000,,0,,1,0x00000000,7,2,136,,99,0,0,{ bonus bDex,1; },{},{} -2806,Barrier_Builder,Barrier Builder,5,150000,,8000,,3,,1,0x00000000,7,2,136,,99,0,0,{ bonus bDex,1; },{},{} -2807,Repair_Kit,Repair Kit,5,200000,,400,,0,,1,0x00000000,7,2,136,,99,0,0,{},{},{} -2808,Camouflage_Generator,Camouflague Generator,5,250000,,1000,,0,,1,0x00000000,7,2,136,,99,0,0,{ bonus bAgi,3; },{},{} -2809,High_Quality_Cooler,High Quality Cooler,5,100000,,2500,,0,,1,0x00000000,7,2,136,,99,0,0,{ bonus bDex,1; },{},{} -2810,Special_Cooler,Special Cooler,5,100000,,2500,,0,,1,0x00000000,7,2,136,,99,0,0,{ bonus bDex,1; },{},{} +2800,Accelerator,Accelerator,5,100000,,100,,0,,1,0x00000400,8,2,136,,99,0,0,{ bonus bAgi,2; },{},{} +2801,Hovering_Booster,Hovering Booster,5,100000,,2000,,0,,1,0x00000400,8,2,136,,99,0,0,{ bonus bAgi,1; },{},{} +2802,Suicidal_Device,Suicidal Device,5,500000,,1000,,0,,1,0x00000400,8,2,136,,99,0,0,{},{},{} +2803,Shape_Shifter,Shape Shifter,5,100000,,500,,0,,1,0x00000400,8,2,136,,99,0,0,{ bonus bInt,3; },{},{} +2804,Cooling_Device,Cooling Device,5,100000,,2500,,0,,1,0x00000400,8,2,136,,99,0,0,{ bonus bDex,1; },{},{} +2805,Magnetic_Field_Generator,Magnetic Field Generator,5,100000,,6000,,0,,1,0x00000400,8,2,136,,99,0,0,{ bonus bDex,1; },{},{} +2806,Barrier_Builder,Barrier Builder,5,150000,,8000,,3,,1,0x00000400,8,2,136,,99,0,0,{ bonus bDex,1; },{},{} +2807,Repair_Kit,Repair Kit,5,200000,,400,,0,,1,0x00000400,8,2,136,,99,0,0,{},{},{} +2808,Camouflage_Generator,Camouflague Generator,5,250000,,1000,,0,,1,0x00000400,8,2,136,,99,0,0,{ bonus bAgi,3; },{},{} +2809,High_Quality_Cooler,High Quality Cooler,5,100000,,2500,,0,,1,0x00000400,8,2,136,,99,0,0,{ bonus bDex,1; },{},{} +2810,Special_Cooler,Special Cooler,5,100000,,2500,,0,,1,0x00000400,8,2,136,,99,0,0,{ bonus bDex,1; },{},{} //2811,Freyja_SBracelet7,Freyja's Spirit Bracelet,5,20,,200,,1,,0,0xFFFFFFFF,7,2,136,,20,0,0,{ bonus bAllStats,1; },{},{} //2812,Freyja_SBracelet30,Freyja's Spirit Bracelet,5,20,,200,,1,,0,0xFFFFFFFF,7,2,136,,20,0,0,{ bonus bAllStats,1; },{},{} //2813,Freyja_SBracelet60,Freyja's Spirit Bracelet,5,20,,200,,1,,0,0xFFFFFFFF,7,2,136,,20,0,0,{ bonus bAllStats,1; },{},{} @@ -3075,21 +3075,21 @@ //5743,Orange_Stem_Hat,Orange Stem Hat,5,20,,100,,0,,0,0x00000000,7,2,256,,1,0,620,{ bonus bLuk,3; },{},{} //5744,Capricon_Crown,Capricon Crown,5,20,,300,,3,,1,0xFFFFFFFF,7,2,256,,1,1,621,{ bonus bVit,2; bonus bDex,2; },{},{} //5745,Capricon_Diadem,Capricon Diadem,5,20,,300,,3,,0,0xFFFFFFFF,7,2,256,,1,1,622,{ bonus bDex,2; bonus bMdef,5; },{},{} -5746,Rune_Circlet,Rune Circlet,5,20,,100,,12,,1,0x00000080,7,2,256,,100,1,623,{ bonus bStr,1; bonus bInt,1; bonus bMdef,5; },{},{} -5747,Mitra,Mitra,5,20,,100,,12,,1,0x00000100,7,2,256,,100,1,624,{ bonus bInt,1; bonus bVit,1; bonus bMdef,5; },{},{} -5748,Sniper_Goggle,Sniper Goggles,5,20,,100,,12,,1,0x00000800,7,2,768,,100,1,625,{ bonus bDex,1;bonus bAgi,1;bonus bMdef,5; },{},{} -5749,Driver_Band,Driver Band,5,20,,100,,12,,1,0x00000400,7,2,256,,100,1,626,{ bonus bStr,1; bonus bDex,1; bonus bMdef,5; },{},{} -5750,Shadow_Handicraft,Shadow Handicraft,5,20,,100,,12,,1,0x00020000,7,2,256,,100,1,627,{ bonus bInt,1; bonus bAgi,1; bonus bMdef,5; },{},{} -5751,Minstrel_Song_Hat,Minstrel Song Hat,5,20,,100,,12,,1,0x00080000,7,1,256,,100,1,628,{ bonus bInt,1; bonus bLuk,1; bonus bMdef,5; },{},{} -5752,Midas_Whisper,Midas Whisper,5,20,,100,,12,,1,0x00040000,7,2,256,,100,1,629,{ bonus bStr,1; bonus bDex,1; bonus bMdef,5; },{},{} -5753,Magic_Stone_Hat,Magic Stone Hat,5,20,,100,,12,,1,0x00000200,7,2,256,,100,1,630,{ bonus bInt,1; bonus bDex,1; bonus bMdef,5; },{},{} -5754,Blazing_Soul,Blazing Soul,5,20,,100,,12,,1,0x00008000,7,2,256,,100,1,631,{ bonus bStr,1; bonus bVit,1; bonus bMdef,5; },{},{} -5755,Silent_Executer,Silence Executer,5,20,,100,,6,,0,0x00001000,,2,513,,100,0,632,{ bonus bAgi,1;bonus bMdef,5; },{},{} -5756,Wind_Whisper,Wind Whisper,5,20,,100,,12,,1,0x00010000,7,2,256,,100,1,633,{ bonus bInt,1; bonus bDex,1; bonus bMdef,5; },{},{} -5757,Schmidt_Helm,Dip Schmidt Helm,5,20,,100,,17,,1,0x00004000,7,2,768,,100,1,634,{ bonus bInt,1;bonus bVit,2;bonus bMdef,5; },{},{} -5758,Dying_Swan,Dying Swan,5,20,,100,,12,,1,0x00080000,7,0,256,,100,1,635,{ bonus bInt,1; bonus bLuk,1; bonus bMdef,5; },{},{} +5746,Rune_Circlet,Rune Circlet,5,20,,100,,12,,1,0x00000080,8,2,256,,100,1,623,{ bonus bStr,1; bonus bInt,1; bonus bMdef,5; if(readparam(bStr)>=120){ bonus bAtk,10; bonus bMatk,5; } },{},{} +5747,Mitra,Mitra,5,20,,100,,12,,1,0x00000100,8,2,256,,100,1,624,{ bonus bVit,1; bonus bInt,1; bonus bMdef,5; bonus bHealPower,5; if(readparam(bInt)>=120){ bonus bMatk,10; } },{},{} +5748,Sniper_Goggles,Sniper Goggles,5,20,,100,,12,,1,0x00000800,8,2,768,,100,1,625,{ bonus bAgi,1; bonus bDex,1; bonus bMdef,5; if(readparam(bAgi)>=120){ bonus bLongAtkRate,4; bonus bAspd,1; } },{},{} +5749,Driver_Band_M,Driver Band,5,20,,100,,12,,1,0x00000400,8,1,256,,100,1,626,{ bonus bStr,1; bonus bDex,1; bonus bMdef,5; if(readparam(bStr)>=120){ bonus bAtk,10; bonus bCritical,3; } },{},{} +5750,Shadow_Crown,Shadow Crown,5,20,,100,,12,,1,0x00020000,8,2,256,,100,1,627,{ bonus bAgi,1; bonus bInt,1; bonus bMdef,1; if(readparam(bAgi)>=120){ bonus bAtk,10; bonus bFlee,3; } },{},{} +5751,Minstrel_Song_Hat,Minstrel Song Hat,5,20,,100,,12,,1,0x00080000,8,1,256,,100,1,628,{ bonus bInt,1; bonus bLuk,1; bonus bMdef,5; bonus bLongAtkRate,4; bonus bUseSPrate,-10; },{},{} +5752,Midas_Whispers,Midas Whispers,5,20,,100,,12,,1,0x00040000,8,2,256,,100,1,629,{ bonus bStr,1; bonus bDex,1; bonus bMdef,5; if(readparam(bStr)>=120){ bonus bAtk,5; bonus bAspd,1; } },{},{} +5753,Magic_Stone_Hat,Magic Stone Hat,5,20,,100,,12,,1,0x00000200,8,2,256,,100,1,630,{ bonus bInt,1; bonus bDex,1; bonus bMdef,5; if(readparam(bDex)>=120){ bonus bMatkRate,10; bonus bCastrate,-2; } },{},{} +5754,Burning_Spirit,Burning Spirit,5,20,,100,,12,,1,0x00008000,8,2,256,,100,1,631,{ bonus bStr,1; bonus bVit,1; bonus bMdef,5; if(readparam(bStr)>=120){ bonus bAtk,10; bonus bHit,3; } },{},{} +5755,Silent_Enforcer,Silent Enforcer,5,20,,100,,12,,0,0x00001000,8,2,513,,100,1,632,{ bonus bAgi,1; bonus bMdef,5; if(readparam(bAgi)>=120){ bonus bAtk,10; bonus bFlee2,5; } },{},{} +5756,Wispers_of_Wind,Wispers of Wind,5,20,,100,,12,,1,0x00010000,8,2,256,,100,1,633,{ bonus bInt,1; bonus bDex,1; bonus bMdef,5; if(readparam(bInt)>=120){ bonus bMatkRate,10; bonus bFlee,3; } },{},{} +5757,Reissue_Schmitz_Helm,Reissue Schmitz Helm,5,20,,100,,12,,1,0x00004000,8,2,768,,100,1,634,{ bonus bVit,2; bonus bInt,1; bonus bMdef,5; if(readparam(bInt)>=120){ bonus bMatkRate,10; bonus bDef,5; } },{},{} +5758,Resting_Swan,Resting Swan,5,20,,100,,17,,1,0x00080000,8,0,256,,100,1,635,{ bonus bInt,1; bonus bLuk,1; bonus bMdef,5; bonus bAtkRate,5; bonus bUseSPrate,-10; },{},{} //5759,Noah_Hat,Noah Hat,5,20,,500,,1,,1,0xFFFFFFFF,7,2,256,,1,1,636,{ bonus bMdef,3; },{},{} -5760,Driver_Band_,Driver Band,5,20,,100,,12,,1,0x00000000,7,2,256,,100,1,637,{ bonus bStr,1; bonus bDex,1; bonus bMdef,5; },{},{} +5760,Driver_Band_F,Driver Band,5,20,,100,,12,,1,0x00000400,8,0,256,,100,1,637,{ bonus bStr,1; bonus bDex,1; bonus bMdef,5; if(readparam(bStr)>=120){ bonus bAtk,10; bonus bCritical,3; } },{},{} //5761,Sloth_Hat,Sloth Hat,5,20,,800,,3,,1,0xFFFFFFFF,7,2,256,,1,1,638,{ bonus bAgi,2; },{},{} //5762,Duneyrr_Helm,Duneyrr Helm,5,20,,100,,5,,0,0xFFFFFFFF,7,2,256,,1,1,639,{ bonus bAllStats,1; bonus bMdef,5; },{},{} //5763,Red_Bunny_Band,Red Bunny Band,5,0,,200,,4,,0,0xFFFFFFFF,7,2,256,,1,1,640,{ bonus bAgi,2; bonus bMdef,3; },{},{} @@ -3233,8 +3233,8 @@ 6043,Letter_From_Lugen,Letter from Lugen,3,0,,10,,,,,,,,,,,,,{},{},{} 6044,Letter_From_Otto,Letter from Otto,3,0,,10,,,,,,,,,,,,,{},{},{} 6045,Supply_Box,Supply Box,3,0,,0,,,,,,,,,,,,,{},{},{} -6046,Clothing_Dye_Coupon,New Clothing Dye Coupon,3,0,,0,,,,,,,,,,,,,{},{},{} -6047,Clothing_Dye_Coupon2,Original Clothing Dye Coupon,3,0,,0,,,,,,,,,,,,,{},{},{} +6046,Clothing_Dye_Coupon,Clothing Dye Coupon,2,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ callfunc "SetPalete",1; },{},{} +6047,Clothing_Dye_Coupon_II,Clothing Dye Coupon II,2,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ callfunc "SetPalete",2; },{},{} 6048,Unidentified_Mineral,Unidentified Mineral,3,0,,10,,,,,,,,,,,,,{},{},{} 6049,Marlin,Marlin,3,0,,10,,,,,,,,,,,,,{},{},{} 6050,Mercenary_Contract,Mercenary Contract,3,0,,10,,,,,,,,,,,,,{},{},{} @@ -4659,7 +4659,7 @@ 11053,SN_Book_Practice,SN Book Practice,3,20,,10,,,,,,,,,,,,,{},{},{} 11054,SN_Book_Misc,SN Book Misc,3,20,,10,,,,,,,,,,,,,{},{},{} 11055,Basic_Adventure,Basic Adventure,3,20,,10,,,,,,,,,,,,,{},{},{} -//11056,Spiritualism_Guide, +11056,Elemental_Spirit_Guide,Elemental Spirit Guide,3,1000,,10,,,,,,,,,,,,,{},{},{} // More Usable Items //=================================================================== 11500,Light_Yellow_Pot,Light Yellow Potion,0,550,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ itemheal rand(175,235),0; },{},{} @@ -5045,7 +5045,7 @@ 12338,Grilled_Corn,Grilled Corn,2,100,,100,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_INCSTR,180000,2; sc_start SC_INCINT,180000,2; sc_start SC_INCAGI,180000,2; },{},{} 12339,Cherish_Box_Ori,Treasure Edition Box,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ getitem groupranditem(IG_Cherish_Box_Ori),1; },{},{} 12340,Mysterious_Rice_Powder,Chewy Rice Powder,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ pet 1815; },{},{} -12341,Special_Alloy_Trap_Box,Special Alloy Trap Box,2,20000,,100,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} +12341,Special_Alloy_Trap_Box,Special Alloy Trap Box,2,,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ getitem 7940,100; },{},{} 12342,Manuk's_Opportunity,Manuk's Opportunity,2,0,,50,,,,,0xFFFFFFFF,7,2,,,,,,{ specialeffect2 EF_POTION_BERSERK; sc_start SC_MANU_ATK,600000,10; },{},{} 12343,Manuk's_Courage,Manuk's Courage,2,0,,50,,,,,0xFFFFFFFF,7,2,,,,,,{ specialeffect2 EF_GUARD; sc_start SC_MANU_DEF,600000,10; },{},{} 12344,Pinguicula's_fruit_Jam,Pinguicula's Fruit Jam,2,0,,50,,,,,0xFFFFFFFF,7,2,,,,,,{ specialeffect2 EF_POTION_BERSERK; sc_start SC_SPL_ATK,600000,10; },{},{} @@ -5096,9 +5096,9 @@ 12389,Runstone_Storm,Pertz Runestone For Apprentice,11,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ /* getmapxy .@map$,.@x,.@y,0; if(.@map$ == "job3_rune02") { itemskill "RK_STORMBLAST",1; } */ },{},{} 12390,Runstone_Millennium,Verkana Runestone For Apprentice,11,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ /* getmapxy .@map$,.@x,.@y,0; if(.@map$ == "job3_rune02") { itemskill "RK_MILLENNIUMSHIELD",1; } */ },{},{} 12391,Lucky_Egg_C,Lucky Egg,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12392,RepairA,Repair A,2,220,,100,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12393,RepairB,Repair B,2,500,,140,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12394,RepairC,Repair C,2,1100,,180,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} +12392,Repair_A,Repair A,0,220,,70,,,,,0x00000400,8,2,,,,,,{/* madoheal rand(200,300),0; */},{},{} +12393,Repair_B,Repair B,0,500,,70,,,,,0x00000400,8,2,,,,,,{/* madoheal rand(300,400),0; */},{},{} +12394,Repair_C,Repair C,0,1100,,70,,,,,0x00000400,8,2,,,,,,{/* madoheal rand(400,500),0; */},{},{} 12395,Tantanmen,Tantan Noodle,2,20,,50,,,,,0xFFFFFFFF,7,2,,,,,,{ pet 1519; },{},{} 12396,Fools_Day_Box,Gift Box?,11,20,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ if(rand(1,10)==1) itemskill "AL_TELEPORT",1; else if(rand(1,10)==2) itemskill "AL_TELEPORT",3; else if(rand(1,10)==3) percentheal 50,0; else if(rand(1,10)==4) percentheal 0,50; else if(rand(1,10)==5) end; else if(rand(1,10)==6) getitem 512,1; else if(rand(1,10)==7) itemskill "ALL_REVERSEORCISH",1; else if(rand(1,10)==8) specialeffect2 247; else if(rand(1,10)==9) specialeffect2 338; else specialeffect2 10; },{},{} 12397,Fools_Day_Box2,Gift Box?,11,20,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ if(rand(1,10)==1) itemskill "TF_DETOXIFY",1; else if(rand(1,10)==2) itemskill "TF_PICKSTONE",1; else if(rand(1,10)==3) itemskill "BA_FROSTJOKER",1; else if(rand(1,10)==4) itemskill "DC_SCREAM",1; else if(rand(1,10)==5) end; else if(rand(1,10)==6) getitem 909,1; else if(rand(1,10)==7) itemskill "AL_RUWACH",1; else if(rand(1,10)==8) specialeffect2 328; else if(rand(1,10)==9) specialeffect2 68; else specialeffect2 196; },{},{} @@ -5125,23 +5125,27 @@ 12418,Full_SwingK,Full SwingK,2,100,,50,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} 12419,Mana_Plus,Mana Plus,2,100,,50,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} 12420,Stamina_Up_M,Stamina Up M,2,100,,50,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12421,Digestive_F,Digestive F,2,100,,50,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12422,HP_Increase_PotionS,HP Increase PotionS,2,100,,20,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12423,HP_Increase_PotionM,HP Increase PotionM,2,100,,40,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12424,HP_Increase_PotionL,HP Increase PotionL,2,100,,80,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12425,SP_Increase_PotionS,SP Increase PotionS,2,100,,20,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12426,SP_Increase_PotionM,SP Increase PotionM,2,100,,40,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12427,SP_Increase_PotionL,SP Increase PotionL,2,100,,80,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12428,Enrich_White_PotionZ,Enrich White PotionZ,2,100,,70,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12429,Savage_BBQ,Savage BBQ,2,1000,,50,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12430,Wug_Blood_Cocktail,Wug Blood Cocktail,2,1000,,50,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12431,Minor_Brisket,Minor Brisket,2,1000,,50,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12432,Siroma_Icetea,Siroma Icetea,2,1000,,50,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12433,Drocera_Herb_Stew,Drocera Herb Stew,2,1000,,50,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12434,Petti_Tail_Noodle,Petti Tail Noodle,2,1000,,50,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12435,Black_Thing,Black Thing,2,1000,,50,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12436,Vitata500,Vitata500,2,100,,50,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12437,Enrich_Celermine_Juice,Enrich Celermine Juice,2,100,,50,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} +12417,Boost_500,Boost 500,2,10,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_BOOST500,500000,20; },{},{} +12418,Full_Swing_K,Full Swing K,3,10,,10,,,,,,,,,,,,,{},{},{} +12419,Manaplus,Manaplus,3,10,,10,,,,,,,,,,,,,{},{},{} +12420,Muramura_M,Muramura M,3,10,,10,,,,,,,,,,,,,{},{},{} +12421,Falmons_F,Falmons F,3,10,,10,,,,,,,,,,,,,{},{},{} +12422,HP_Increase_Potion_(Small),HP Increase Potion (Small),0,10,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_INCMHPRATE,500000,1; percentheal 2,0; },{},{} +12423,HP_Increase_Potion_(Medium),HP Increase Potion (Medium),0,10,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_INCMHPRATE,500000,2; percentheal 3,0; },{},{} +12424,HP_Increase_Potion_(Large),HP Increase Potion (Large),0,10,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_INCMHPRATE,500000,5; percentheal 5,0; },{},{} +12425,SP_Increase_Potion_(Small),SP Increase Potion (Small),0,10,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_INCMSPRATE,500000,2; percentheal 0,2; },{},{} +12426,SP_Increase_Potion_(Medium),SP Increase Potion (Medium),0,10,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_INCMSPRATE,500000,4; percentheal 0,4; },{},{} +12427,SP_Increase_Potion_(Large),SP Increase Potion (Large),0,10,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_INCMSPRATE,500000,8; percentheal 0,8; },{},{} +12428,Concentrated_White_Potion_Z,Concentrated White Potion Z,0,10,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_WHITEPOTIONZ,500000,0; itemheal rand(1500,1600),0; },{},{} +12429,Savage_Full_Roast,Savage Full Roast,2,,,50,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_SAVAGE_STEAK, 300000, 20; },{},{} +12430,Cocktail_Warg_Blood,Cocktail Warg Blood,2,,,50,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_COCKTAIL_WARG_BLOOD, 300000, 20; },{},{} +12431,Minor_Stew,Minor Stew,2,,,50,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_MINOR_BBQ, 300000, 20; },{},{} +12432,Siroma_Iced_Tea,Siroma Iced Tea,2,,,50,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_SIROMA_ICE_TEA, 300000, 20; },{},{} +12433,Drosera_Herb_Salad,Drosera Herb Salad,2,,,50,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_DROCERA_HERB_STEAMED, 300000, 20; },{},{} +12434,Petite_Tail_Noodles,Petite Tail Noodles,2,,,50,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_PUTTI_TAILS_NOODLES, 300000, 20; },{},{} +12435,Black_Mass,Black Mass,2,,,50,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_STOMACHACHE, 60000, rand(5,10); },{},{} +12436,Vitata_500,Vitata 500,0,10,,10,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} +12437,Concentrated_Ceromain_Soup,Concentrated Ceromain Soup,2,10,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ itemheal rand(1500,1600),0; },{},{} 12438,F_Giant_Fly_Wing,F Giant Fly Wing,2,2,,10,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} 12439,F_Battle_Manual,F Battle Manual,2,2,,10,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} 12440,F_Insurance,F Insurance,2,2,,10,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} @@ -5285,6 +5289,7 @@ 12580,Vending_Search_Scroll,Universal Catalog Silver,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ searchstores 10,0; },{},{} 12581,Vending_Search_Scroll2,Universal Catalog Gold,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ searchstores 10,1; },{},{} 12591,Vending_Search_Scroll3,Universal Catalog Bronze,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ searchstores 10,1; },{},{} +12622,Reins_Of_Mount,Reins Of Mount,11,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ itemskill "ALL_RIDING",1; },{},{} 12701,Old_Blue_Box_F,Old Blue Box,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} 12702,Old_Bleu_Box,Old Navy Box,2,0,,200,,,,,0xFFFFFFFF,7,2,,,,,,{ getitem groupranditem(IG_BleuBox),1; getitem groupranditem(IG_BleuBox),1; },{},{} 12703,Holy_Egg_2,Holy Egg,11,0,,50,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} @@ -5301,28 +5306,34 @@ 12714,Easter_Scroll,Easter Scroll,2,1,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ getitem groupranditem(IG_Easter_Scroll),1; },{},{} 12715,Black_Treasure_Box,Black Treasure Box,2,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} 12716,Indian_Rice_Cake,Indian Rice Cake,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12717,Poison_Paralysis,Paralysis,2,2,,20,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12718,Poison_Leech,Leech End,2,2,,20,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12719,Poison_Oblivion,Oblivion Curse,2,2,,20,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12720,Poison_Contamination,Death Hurt,2,2,,20,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12721,Poison_Numb,Toxin,2,2,,20,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12722,Poison_Fever,Pyrexia,2,2,,20,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12723,Poison_Laughing,Magic Mushroom,2,2,,20,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12724,Poison_Fatigue,Venom Bleed,2,2,,20,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12725,Runstone_Nosiege,Nosiege Runestone,2,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12726,Runstone_Rhydo,Rhydo Runestone,2,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12727,Runstone_Verkana,Verkana Runestone,2,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12728,Runstone_Isia,Isia Runestone,2,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12729,Runstone_Asir,Asir Runestone,2,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12730,Runstone_Urj,Urj Runestone,2,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12731,Runstone_Turisus,Turisus Runestone,2,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12732,Runstone_Pertz,Pertz Runestone,2,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12733,Runstone_Hagalas,Hagalas Runestone,2,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12734,Runstone_Quality,Quality Rough Runestone,2,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12735,Runstone_Ancient,Ancient Rough Runestone,2,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12736,Runstone_Mystic,Mystic Rough Runestone,2,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12737,Runstone_Ordinary,General Rough Runestone,2,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12738,Runstone_Rare,Rare Rough Runestone,2,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} +// Guillotine Cross Poisons +12717,Poison_Paralysis,Paralyze,0,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{ if(rand(10000) < 10) sc_start SC_PARALYSE,300000,0; },{},{} +12718,Poison_Leech,Leech End,0,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{ if(rand(10000) < 10) sc_start SC_LEECHESEND,300000,0; },{},{} +12719,Poison_Oblivion,Oblivion Curse,0,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{ if(rand(10000) < 10) sc_start SC_OBLIVIONCURSE,300000,0; },{},{} +12720,Poison_Disheart,Disheart,0,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{ if(rand(10000) < 10) sc_start SC_DEATHHURT,300000,0; },{},{} +12721,Poison_Numb,Toxin,0,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{ if(rand(10000) < 10) sc_start SC_TOXIN,300000,0; },{},{} +12722,Poison_Fever,Pyrexia,0,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{ if(rand(10000) < 10) sc_start SC_PYREXIA,300000,0; },{},{} +12723,Poison_Laughing,Magic Mushroom,0,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{ if(rand(10000) < 10) sc_start SC_MAGICMUSHROOM,300000,0; },{},{} +12724,Poison_Fatigue,Venom Bleed,0,2,,100,,,,,0xFFFFFFFF,7,2,,,,,,{ if(rand(10000) < 10) sc_start SC_VENOMBLEED,15000,0; },{},{} + +// Rune Knight's Rune Stones +12725,Runstone_Nosiege,Nauthiz Rune,11,100,,100,,,,,0xFFFFFFFF,8,2,,,,,,{ itemskill "RK_REFRESH",1; },{},{} +12726,Runstone_Rhydo,Raido Rune,11,100,,100,,,,,0xFFFFFFFF,8,2,,,,,,{ itemskill "RK_CRUSHSTRIKE",1; },{},{} +12727,Runstone_Verkana,Berkana Rune,11,100,,100,,,,,0xFFFFFFFF,8,2,,,,,,{ itemskill "RK_MILLENNIUMSHIELD",1; },{},{} +12728,Runstone_Isia,Isa Rune,11,100,,100,,,,,0xFFFFFFFF,8,2,,,,,,{ itemskill "RK_VITALITYACTIVATION",1; },{},{} +12729,Runstone_Asir,Othila Rune,11,100,,100,,,,,0xFFFFFFFF,8,2,,,,,,{ itemskill "RK_FIGHTINGSPIRIT",1; },{},{} +12730,Runstone_Urj,Uruz Rune,11,100,,100,,,,,0xFFFFFFFF,8,2,,,,,,{ itemskill "RK_ABUNDANCE",1; },{},{} +12731,Runstone_Turisus,Thurisaz Rune,11,100,,100,,,,,0xFFFFFFFF,8,2,,,,,,{ itemskill "RK_GIANTGROWTH",1; },{},{} +12732,Runstone_Pertz,Wyrd Rune,11,100,,100,,,,,0xFFFFFFFF,8,2,,,,,,{ itemskill "RK_STORMBLAST",1; },{},{} +12733,Runstone_Hagalas,Hagalaz Rune,11,100,,100,,,,,0xFFFFFFFF,8,2,,,,,,{ itemskill "RK_STONEHARDSKIN",1; },{},{} + +// Rune Knight Rune Ores +12734,Runstone_Quality,Luxurious Rune,0,2,,100,,,,,0x00000080,8,2,,,,,,{ makerune 1; },{},{} +12735,Runstone_Ancient,Ancient Rune,0,2,,100,,,,,0x00000080,8,2,,,,,,{ makerune 2; },{},{} +12736,Runstone_Mystic,Mystic Rune,0,2,,100,,,,,0x00000080,8,2,,,,,,{ makerune 3; },{},{} +12737,Runstone_Ordinary,General Rune,0,2,,100,,,,,0x00000080,8,2,,,,,,{ makerune 4; },{},{} +12738,Runstone_Rare,Rare Rune,0,2,,100,,,,,0x00000080,8,2,,,,,,{ makerune 5; },{},{} + 12739,Snow_Flower,Snow Flowers,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} 12740,Inc_Str_Scroll,Amplification Scroll,2,1,,0,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} 12741,Inc_Int_Scroll,Intellect Amplification Scroll,2,1,,0,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} @@ -5589,38 +5600,37 @@ 13257,Kunai_Of_Furious_Wind,High Wind Kunai,10,10,,20,30,,,,0x02000000,7,2,32768,,1,,7,{ bonus bAtkEle,Ele_Wind; },{},{} 13258,Kunai_Of_Fierce_Flame,Heat Wave Kunai,10,10,,20,30,,,,0x02000000,7,2,32768,,1,,7,{ bonus bAtkEle,Ele_Fire; },{},{} 13259,Kunai_Of_Deadly_Poison,Fell Poison Kunai,10,10,,20,30,,,,0x02000000,7,2,32768,,1,,7,{ bonus bAtkEle,Ele_Poison; bonus2 bAddEff,Eff_Poison,500; },{},{} -// TODO: Update job for Cenetics only -13260,Apple_Bomb,Apple Bomb,10,100,,1,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13261,Coconut_Bomb,Coconut Bomb,10,100,,1,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13262,Melon_Bomb,Melon Bomb,10,100,,1,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13263,Pineapple_Bomb,Pineapple Bomb,10,100,,1,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13264,Banana_Bomb,Banana Bomb,10,100,,1,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13265,Black_Lump,Black Lump,10,100,,50,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13266,Black_Hard_Lump,Black Hard Lump,10,100,,50,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13267,Very_Hard_Lump,Very Hard Lump,10,100,,50,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13268,Mysterious_Powder,Mysterious Powder,10,100,,10,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13269,Throwing_Boost500,Throwing Boost500,10,100,,10,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13270,Full_SwingK_Throw,Full SwingK Throw,10,100,,50,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13271,Mana_Plus_to_Throw,Mana + Throw,10,100,,50,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13272,Cure_Free_Throw,Cure Free Throw,10,100,,50,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13273,Stamina_Up_M_To_Throw,Stamina Up M To Throw,10,100,,10,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13274,Digestive_F_To_Throw,Digestive Up F To Throw,10,100,,10,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13275,HP_Inc_PotS_To_Throw,HP Increase Potion(Small) Throw,10,100,,20,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13276,HP_Inc_PotM_To_Throw,HP Increase Potion(Mid) Throw,10,100,,40,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13277,HP_Inc_PotL_To_Throw,HP Increase Potion(Large) Throw,10,100,,80,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13278,SP_Inc_PotS_To_Throw,HP_Increase Potion(Small) Throw,10,100,,20,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13279,SP_Inc_PotM_To_Throw,SP_Increase Potion(Mid) Throw,10,100,,40,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13280,SP_Inc_PotL_To_Throw,SP_Increase Potion(Large) Throw,10,100,,80,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13281,En_White_PotZ_To_Throw,Enriched White PotionZ Throw,10,100,,70,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13282,Vitata500_To_Throw,Vitata50 Throw0,10,100,,50,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13283,En_Cel_Juice_To_Throw,Enrich Celermine Juice Throw,10,100,,50,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13284,Savage_BBQ_To_Throw,Savage BBQ Throw,10,100,,50,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13285,Wug_Cocktail_To_Throw,Wug Cocktail To Throw,10,100,,50,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13286,M_Brisket_To_Throw,Brisket To Throw,10,100,,50,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13287,Siroma_Iced_Tea_To_Throw,Siroma Iced Tea To Throw,10,100,,50,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13288,Drosera_Stew_To_Throw,Drosera Stew To Throw,10,100,,50,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13289,Petite_Noodle_To_Throw,Petite Noodle To Throw,10,100,,50,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} -13290,Black_Thing_To_Throw,Black Thing To Throw,10,100,,50,0,,,,0x0000000,7,2,32768,,99,,7,{},{},{} +13260,Apple_Bomb,Apple Bomb,17,10,,1,100,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13261,Coconut_Bomb,Coconut Bomb,17,1,,10,100,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13262,Melon_Bomb,Melon Bomb,17,10,,1,100,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13263,Pineapple_Bomb,Pineapple Bomb,17,10,,1,100,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13264,Banana_Bomb,Banana Bomb,17,10,,1,100,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13265,Black_Lump,Black Lump,17,10,,50,100,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13266,Hard_Black_Lump,Hard Black Lump,17,10,,50,100,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13267,Extremely_Hard_Black_Lump,Extremely Hard Black Lump,17,10,,50,100,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13268,Mysterious_Powder,Mysterious Powder,17,10,,10,100,,,,0xFFFFFFFF,7,2,32768,,1,,9,{ sc_start SC_MYSTERIOUS_POWDER,10000,2; },{},{} +13269,Throwing_Boost_500,Throwing Boost 500,17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13270,Throwing_Full_Swing_K,Throwing Full Swing K,17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13271,Throwing_Manaplus,Throwing Manaplus,17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13272,Throwing_Cure_Free,Throwing Cure Free,17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13273,Throwing_Muramura_M,Throwing Muramura M,17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13274,Throwing_Falmons_F,Throwing Falmons F,17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13275,Throwing_Increase_HP_Potion_(Small),Throwing Increase HP Potion (Small),17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{ sc_start SC_INCMHPRATE,500000,1; itemheal 840,0; },{},{} +13276,Throwing_Increase_HP_Potion_(Medium),Throwing Increase HP Potion (Medium),17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{ sc_start SC_INCMHPRATE,500000,2; itemheal 1040,0; },{},{} +13277,Throwing_Increase_HP_Potion_(Large),Throwing Increase HP Potion (Large),17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{ sc_start SC_INCMHPRATE,500000,5; itemheal 1240,0; },{},{} +13278,Throwing_Increase_SP_Potion_(Small),Throwing Increase SP Potion (Small),17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{ sc_start SC_INCMSPRATE,500000,2; itemheal 0,200; },{},{} +13279,Throwing_Increase_SP_Potion_(Medium),Throwing Increase SP Potion (Medium),17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{ sc_start SC_INCMSPRATE,500000,4; itemheal 0,300; },{},{} +13280,Throwing_Increase_SP_Potion_(Large),Throwing Increase SP Potion (Large),17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{ sc_start SC_INCMSPRATE,500000,8; itemheal 0,400; },{},{} +13281,Throwing_Concentrated_White_Potion_Z,Throwing Concentrated White Potion Z,17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13282,Throwing_Vitata_500,Throwing Vitata 500,17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13283,Throwing_Ceromain_Soup,Throwing Ceromain Soup,17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13284,Throwing_Savage_Full_Roast,Throwing Savage Full Roast,17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13285,Throwing_Cocktail_Warg_Blood,Throwing Cocktail Warg Blood,17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13286,Throwing_Minor_Stew,Throwing Minor Stew,17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13287,Throwing_Siroma_Iced_Tea,Throwing Siroma Iced Tea,17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13288,Throwing_Drosera_Herb_Salad,Throwing Drosera Herb Salad,17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13289,Throwing_Petite_Tail_Soup,Throwing Petite Tail Soup,17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} +13290,Throwing_Black_Mass,Throwing Black Mass,17,10,,100,0,,,,0xFFFFFFFF,7,2,32768,,1,,9,{},{},{} // Ninja Fuuma Shurikens 13300,Huuma_Bird_Wing,Huuma Wing Shuriken,4,90000,,3000,150,,1,0,0x02000000,7,2,34,4,65,1,22,{ bonus bUnbreakableWeapon,0; bonus bAtkEle,Ele_Wind; bonus bDex,-2; bonus bAgi,-1; },{},{} 13301,Huuma_Giant_Wheel,Huuma Giant Wheel Shuriken,4,40000,,2500,50,,1,3,0x02000000,7,2,34,4,42,1,22,{ bonus bUnbreakableWeapon,0; bonus2 bAddEff,Eff_Bleeding,100; },{},{} @@ -6735,16 +6745,16 @@ 16776,Universal_Catalog_Gold_Box10,Universal Catalog Gold 10 Box,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ getitem 12581,10; },{},{} 16777,Universal_Catalog_Gold_Box50,Universal Catalog Gold 50 Box,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ getitem 12581,50; },{},{} 16998,Archangel_Wings_Box,Archangel Wings Box,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ getitem 2573,1; },{},{} -// TODO: Update job for Mechanic only. -18000,Cannon_Ball,Cannon Ball,10,100,,10,100,,,,0x000A1848,7,2,32768,,1,,1,{},{},{} -18001,Holy_Cannon_Ball,Holy Cannon Ball,10,200,,100,120,,,,0x000A1848,7,2,32768,,1,,1,{},{},{} -18002,Dark_Cannon_Ball,Dark Cannon Ball,10,200,,100,120,,,,0x000A1848,7,2,32768,,1,,1,{},{},{} -18003,Soul_Cannon_Ball,Soul Cannon Ball,10,200,,100,120,,,,0x000A1848,7,2,32768,,1,,1,{},{},{} -18004,Iron_Cannon_Ball,Iron Cannon Ball,10,500,,100,250,,,,0x000A1848,7,2,32768,,1,,1,{},{},{} +//Mechanic Cannon Balls +18000,Cannon_Ball,Cannon Ball,10,100,,10,100,,,,0x00000400,8,2,32768,,1,,8,{},{},{} +18001,Holy_Cannon_Ball,Holy Cannon Ball,10,200,,100,120,,,,0x00000400,8,2,32768,,1,,8,{ bonus bAtkEle,Ele_Holy; },{},{} +18002,Dark_Cannon_Ball,Dark Cannon Ball,10,200,,100,120,,,,0x00000400,8,2,32768,,1,,8,{ bonus bAtkEle,Ele_Dark; },{},{} +18003,Soul_Cannon_Ball,Soul Cannon Ball,10,200,,100,120,,,,0x00000400,8,2,32768,,1,,8,{ bonus bAtkEle,Ele_Ghost; },{},{} +18004,Iron_Cannon_Ball,Iron Cannon Ball,10,500,,100,250,,,,0x00000400,8,2,32768,,1,,8,{ bonus bAtkEle,Ele_Neutral; },{},{} //18100,Shooting_Star_C, 18101,F_Bow_Of_Rudra_C,Rudra Bow,4,2,,0,185,,5,0,0x000A0848,7,2,34,4,0,0,11,{ bonus bAtkEle,Ele_Holy; bonus bInt,5; skill "AL_CURE",1; skill "AL_HEAL",1; bonus2 bResEff,Eff_Poison,5000; bonus2 bResEff,Eff_Curse,5000; bonus2 bResEff,Eff_Silence,5000; bonus2 bResEff,Eff_Confusion,5000; bonus2 bResEff,Eff_Blind,5000; },{},{} 18102,E_Bow_Of_Rudra_C,Rudra Bow,4,2,,0,185,,5,0,0x000A0848,7,2,34,4,0,0,11,{ bonus bAtkEle,Ele_Holy; bonus bInt,5; skill "AL_CURE",1; skill "AL_HEAL",1; bonus2 bResEff,Eff_Poison,5000; bonus2 bResEff,Eff_Curse,5000; bonus2 bResEff,Eff_Silence,5000; bonus2 bResEff,Eff_Confusion,5000; bonus2 bResEff,Eff_Blind,5000; },{},{} -18103,Mystic_Bow,Mystic Bow,4,0,,1700,75,,5,0,0x000A0848,7,2,34,3,105,1,11,{ bonus bInt,4; },{},{} +18103,Mystic_Bow,Mystic Bow,4,0,,1700,75,,5,0,0x00000400,8,2,34,3,105,1,11,{ bonus bInt,4; },{},{} //18500,Cheer_Scarf6, //18501,Cheer_Scarf8, //18502,Cheer_Scarf10, diff --git a/db/item_db_re.txt b/db/item_db_re.txt new file mode 100644 index 000000000..9d0796d49 --- /dev/null +++ b/db/item_db_re.txt @@ -0,0 +1,305 @@ +// Renewal-Specific Database +// specially for renewal-modified items, when compiled in RRMODE entries in this file override item_db.txt and are overriden by item_db2.txt +// +// Structure of Database: +// ID,Name,Name,Type,Price,Sell,Weight,ATK:MATK,DEF,Range,Slot,Job,Upper,Gender,Loc,wLV,eLV,Refineable,View,{ Script },{ OnEquip_Script },{ OnUnequip_Script } +// +// Note (ATK field) +// - in RE this field is able to store a optional value, for the weapons' matk +// - You may use, for example: 10:25 for a item to give 10 atk and 25 weapon matk. + +//ASPD in RE they give a fixed +4/+6/+9 ASPD +645,Center_Potion,Concentration Potion,2,800,,100,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_ASPDPOTION0,1800000,4; },{},{} +656,Awakening_Potion,Awakening Potion,2,1500,,150,,,,,0xFFF7FEEF,7,2,,,40,,,{ sc_start SC_ASPDPOTION1,1800000,6; },{},{} +657,Berserk_Potion,Berserk Potion,2,3000,,200,,,,,0x01E646A6,7,2,,,85,,,{ sc_start SC_ASPDPOTION2,1800000,9; },{},{} + +// Matk updates. Work in progress. +// Daggers +13010,Asura,Asura,4,3000,,600,50:50,,1,2,0x02000000,7,2,2,1,12,1,1,{},{},{} +13011,Asura_,Asura,4,3000,,600,50:50,,1,3,0x02000000,7,2,2,1,12,1,1,{},{},{} +1231,Bazerald,Bazerald,4,20,,500,70:105,,1,0,0x028F5EEE,7,2,2,4,36,1,1,{ bonus bAtkEle,Ele_Fire; bonus bInt,5; },{},{} + +// Staffs +1472,Staff_Of_Soul,Soul Staff,4,20,,1400,25:200,,1,0,0x00810204,7,2,34,3,73,1,10,{ bonus bInt,5; bonus bAgi,2; if(isequipped(2677) || isequipped(2711)){ bonus bMatkRate,6; bonus bDex,2; bonus bCastrate,-getrefine(); } },{},{} +1601,Rod,Rod,4,50,,400,15:30,,1,3,0x00818315,7,2,2,1,1,1,10,{},{},{} +1602,Rod_,Rod,4,50,,400,15:30,,1,4,0x00818315,7,2,2,1,1,1,10,{},{},{} +1603,Rod__,Rod,4,50,,400,15:30,,1,0,0x00818315,7,2,2,1,1,1,10,{},{},{} +1604,Wand,Wand,4,2500,,400,25:45,,1,2,0x00818315,7,2,2,2,12,1,10,{},{},{} +1605,Wand_,Wand,4,2500,,400,25:45,,1,3,0x00818315,7,2,2,2,12,1,10,{},{},{} +1606,Wand__,Wand,4,2500,,400,25:45,,1,0,0x00818315,7,2,2,2,12,1,10,{ bonus bInt,1; },{},{} +1607,Staff,Staff,4,9500,,400,40:70,,1,2,0x00818314,7,2,2,2,12,1,10,{ bonus bInt,2; },{},{} +1608,Staff_,Staff,4,9500,,400,40:70,,1,3,0x00818314,7,2,2,2,12,1,10,{ bonus bInt,2; },{},{} +1609,Staff__,Staff,4,9500,,400,40:70,,1,0,0x00818314,7,2,2,2,12,1,10,{ bonus bInt,2; },{},{} +1610,Arc_Wand,Arc Wand,4,45000,,400,60:95,,1,1,0x00818314,7,2,2,3,24,1,10,{ bonus bInt,3; },{},{} +1611,Arc_Wand_,Arc Wand,4,45000,,400,60:95,,1,2,0x00818314,7,2,2,3,24,1,10,{ bonus bInt,3; },{},{} +1612,Arc_Wand__,Arc Wand,4,45000,,400,60:95,,1,0,0x00818314,7,2,2,3,24,1,10,{ bonus bInt,3; },{},{} +1613,Mighty_Staff,Mighty Staff,4,20,,700,130:100,,1,0,0x00818314,7,2,2,3,24,1,10,{ bonus bStr,10; bonus bSPDrainValue,-2; },{},{} +1614,Blessed_Wand,Wand of Occult,4,20,,700,75:105,,1,0,0x00818314,7,2,2,3,24,1,10,{ bonus bInt,3; },{},{} +1616,Staff_Of_Wing,Wing Staff,4,20,,500,60:115,,1,0,0x00810204,7,2,2,4,40,1,10,{ bonus bCastrate,-5; },{},{} +1617,Survival_Rod,Survivor's Rod,4,85000,,1000,50:120,,1,0,0x00818314,7,2,2,3,24,1,10,{ bonus bDex,2; bonus bMaxHP,300; },{},{} +1618,Survival_Rod_,Survivor's Rod,4,85000,,1000,50:120,,1,1,0x00818314,7,2,2,3,24,1,10,{ bonus bDex,3; bonus bMaxHP,400; },{},{} +1619,Survival_Rod2,Survivor's Rod,4,85000,,1000,50:120,,1,0,0x00818314,7,2,2,3,24,1,10,{ bonus bInt,2; bonus bMaxHP,300; },{},{} +1620,Survival_Rod2_,Survivor's Rod,4,85000,,1000,50:120,,1,1,0x00818314,7,2,2,3,24,1,10,{ bonus bInt,3; bonus bMaxHP,400; },{},{} +1621,Hypnotist's_Staff,Hypnotist's Staff,4,43000,,500,70:120,,1,1,0x00000001,7,2,2,3,30,1,10,{ bonus bInt,1; },{},{} +1622,Hypnotist's_Staff_,Hypnotist's Staff,4,20,,500,70:120,,1,2,0x00000001,7,2,2,3,30,1,10,{ bonus bInt,1; },{},{} +1624,Lich_Bone_Wand,Lich's Bone Wand,4,20,,800,60:170,,1,2,0x00018314,2,2,2,3,70,1,10,{ bonus bInt,1; bonus bDex,1; bonus bAtkEle,Ele_Undead; bonus3 bAutoSpellWhenHit,"NPC_WIDECURSE",5,10+getrefine(); if(getrefine()>=9){ bonus bMatkRate,3; bonus bMaxSP,300; } },{},{} +1625,Healing_Staff,Healing Staff,4,20,,400,10:105,,1,0,0x00008110,7,2,2,3,55,1,10,{ bonus bAtkEle,Ele_Holy; bonus bHealPower,(getrefine()*3/2); },{},{} +1626,Piercing_Staff,Piercing Staff,4,20,,500,80:145,,1,0,0x00018314,2,2,2,3,70,1,10,{ bonus bInt,4; bonus bIgnoreMdefRate,10+getrefine(); },{},{} +1629,Walking_Stick,Gentleman's Staff,4,20,,500,40:125,,1,1,0x00818314,7,2,2,4,50,1,10,{ bonus bDex,1; if (isequipped(5045)) { bonus bDex,2; bonus bInt,2; bonus bSPrecovRate,5; bonus bMatkRate,getrefine(); } },{},{} +1630,Release_Of_Wish,Release of Wish,4,20,,500,30:125,,1,0,0x00810204,7,2,2,3,50,1,10,{ bonus bInt,3; bonus bHealPower,5; autobonus "{ bonus2 bSPRegenRate,100,2000; bonus2 bHPRegenRate,50,2000; }",10,10000,BF_MAGIC,"{ specialeffect2 EF_HEAL; }"; },{},{} +1636,Thorn_Staff,Thorn Staff of Darkness,4,20,,700,60:160,,1,0,0x00018314,2,2,2,4,75,1,10,{ bonus bInt,3; bonus bDex,3; bonus bIgnoreMdefRate,getrefine(); bonus bDelayRate,-(getrefine()*3/2); },{},{} +1637,Eraser,Eraser,4,20,,500,80:170,,1,0,0x00018314,2,2,2,4,70,1,10,{ bonus bInt,3; bonus bDex,2; bonus bSPrecovRate,8; if( getrefine() > 9 ) bonus5 bAutoSpell,"NPC_WIDESOULDRAIN",3,5,BF_MAGIC,0; else bonus5 bAutoSpell,"NPC_WIDESOULDRAIN",1,5,BF_MAGIC,0; },{},{} +2000,Destruction_Rod,Staff of Destruction,4,20,,2500,130:280,,1,1,0x00000200,2,2,34,4,80,1,23,{ bonus bInt,3; bonus bAgi,10; bonus bUseSPrate,(getrefine()*2); bonus3 bAutoSpellWhenHit,"WZ_JUPITEL",5,(getrefine()*20); bonus2 bCastrate,366,-50; },{},{} +2001,Divine_Cross,Divine Cross,4,20,,1500,120:210,,1,0,0x00008100,7,2,34,4,70,1,23,{ bonus bAtkEle,Ele_Holy; bonus bDex,4; bonus2 bSubRace,RC_Demon,15; bonus2 bSubRace,RC_Undead,15; if (isequipped(2677) || isequipped(2711)) { bonus bMatkRate,10; bonus bDex,2; bonus2 bSubRace,RC_Demon,10; bonus2 bSubRace,RC_Undead,10; }; },{},{} + +// Books +1560,Diary_Of_Great_Sage,Sage's Diary,4,20,,1100,100:120,,1,2,0x00410100,7,2,2,3,60,1,15,{ if(readparam(bStr)>=50) bonus bAspdRate,5; if(readparam(bInt)>=70) bonus bMatkRate,5; },{},{} +1561,Hardback,Hardcover Book,4,20,,1500,140,,1,1,0x00410100,7,2,2,4,55,1,15,{ bonus bStr,3; bonus bDex,2; },{},{} +1572,Principles_Of_Magic,Principles of Magic,4,20,,300,60:160,,1,2,0x00410100,7,2,2,3,60,1,15,{ bonus bInt,3; bonus bSPrecovRate,5; },{},{} +1573,Ancient_Magic,Ancient Magic,4,20,,700,30:140,,1,2,0x00410100,7,2,2,3,70,1,15,{ if (isequipped(2334) || isequipped(2372)) { bonus bMdef,8; bonus bMaxSPRate,10; bonus bInt,4; }; },{},{} +1564,Encyclopedia,Encyclopedia,4,20,,2000,110:100,,1,2,0x00410100,7,2,2,3,70,1,15,{ bonus bInt,3; bonus bDex,2; bonus bCritical,20+((readparam(bLuk)*2)/10); },{},{} + +// DEF updates +// Headgears - Work in progress. +2208,Ribbon,Ribbon,5,800,,100,,1,,0,0xFFFFFFFF,7,0,256,,0,1,17,{ bonus bMdef,3; },{},{} +2209,Ribbon_,Ribbon,5,800,,100,,1,,1,0xFFFFFFFF,7,0,256,,0,1,17,{ bonus bMdef,3; },{},{} +2216,Biretta,Biretta,5,9000,,100,,8,,0,0x00008110,7,2,256,,0,1,11,{},{},{} +2217,Biretta_,Biretta,5,9000,,100,,8,,1,0x00008110,7,2,256,,0,1,11,{},{},{} +2252,Star_Sparkling,Wizard Hat,5,20,,300,,7,,0,0x00810204,7,2,256,,0,1,36,{ bonus bMaxSP,100; },{},{} +2266,Iron_Cane,Iron Cain,5,20,,300,,4,,0,0x00004082,7,2,1,,50,0,53,{},{},{} +2280,Sahkkat,Sakkat,5,20,,300,,4,,0,0xFFFFFFFF,7,2,256,,0,1,67,{ bonus bAgi,1; },{},{} +2285,Apple_Of_Archer,Apple of Archer,5,20,,200,,1,,0,0xFFFFFFFE,7,2,256,,30,1,72,{ bonus bDex,3; },{},{} +2287,Pirate_Bandana,Pirate Bandana,5,20,,100,,4,,0,0xFFFFFFFE,7,2,256,,0,1,74,{ bonus bStr,1; },{},{} +2299,Viking_Helm,Orc Helm,5,20,,500,,9,,0,0x000654E2,7,2,256,,0,1,86,{},{},{} +5007,Loard_Circlet,Grand Circlet,5,20,,200,,7,,0,0xFFFFFFFE,7,2,256,,55,1,93,{ bonus bStr,1; bonus bInt,1; bonus bLuk,1; bonus bMdef,4; },{},{} +5010,Indian_Hair_Piece,Indian Fillet,5,20,,100,,5,,0,0xFFFFFFFF,7,2,256,,0,1,96,{},{},{} +5015,Egg_Shell,Egg Shell,5,20,,200,,6,,0,0xFFFFFFFF,7,2,256,,0,0,101,{},{},{} +5017,Bone_Helm,Bone Helm,5,20,,800,,15,,0,0x000444A2,7,2,256,,70,1,103,{ bonus2 bSubEle,Ele_Dark,-15; },{},{} +5058,Drooping_Kitty,Drooping Cat,5,250000,,500,,3,,0,0xFFFFFFFE,7,2,256,,0,1,142,{ bonus bMdef,15; bonus2 bResEff,Eff_Curse,3000; },{},{} +5111,Galapago_Cap,Galapago Cap,5,20,,500,,4,,0,0xFFFFFFFF,7,2,256,,55,1,192,{ bonus2 bAddMonsterDropItem,605,100; },{},{} +5118,Ear_Of_Puppy,Puppy Headband,5,20,,100,,3,,0,0xFFFFFFFF,7,2,256,,0,1,199,{},{},{} +5122,Magni_Cap,Magni's Cap,5,30000,,1000,,9,,0,0xFFFFFFFE,7,2,256,,65,1,250,{ bonus bStr,2; },{},{} +5128,Goibne's_Helmet,Goibne's Helm,5,30000,,500,,10,,0,0xFFFFFFFE,7,2,256,,54,1,258,{ bonus bVit,3; bonus bMdef,3; if(isequipped(2354,2419,2520)) { bonus bVit,5; bonus bMaxHPrate,15; bonus bMaxSPrate,5; bonus bDef,5; bonus bMdef,15; bonus2 bSubEle,Ele_Water,10; bonus2 bSubEle,Ele_Earth,10; bonus2 bSubEle,Ele_Fire,10; bonus2 bSubEle,Ele_Wind,10; } },{},{} +5157,Viking_Helm_,Orc Helm,5,20,,500,,9,,1,0x000654E2,7,2,256,,0,1,86,{},{},{} +5350,Pirate_Bandana_,Pirate Bandana,5,20,,100,,4,,1,0xFFFFFFFE,7,2,256,,0,1,74,{ bonus bStr,1; },{},{} + +// Shields +2101,Guard,Guard,5,500,,300,,20,,0,0xFFFFFFFF,7,2,32,,0,1,1,{},{},{} +2102,Guard_,Guard,5,500,,300,,20,,1,0xFFFFFFFF,7,2,32,,0,1,1,{},{},{} +2103,Buckler,Buckler,5,14000,,600,,40,,0,0x000ED5F2,7,2,32,,0,1,2,{},{},{} +2104,Buckler_,Buckler,5,14000,,600,,40,,1,0x000ED5F2,7,2,32,,0,1,2,{},{},{} +2105,Shield,Shield,5,56000,,1300,,60,,0,0x00004082,7,2,32,,0,1,3,{},{},{} +2106,Shield_,Shield,5,56000,,1300,,60,,1,0x00004082,7,2,32,,0,1,3,{},{},{} +2107,Mirror_Shield,Mirror Shield,5,60000,,1000,,45,,0,0x00404082,7,2,32,,0,1,4,{ bonus bMdef,5; },{},{} +2108,Mirror_Shield_,Mirror Shield,5,60000,,1000,,45,,1,0x00404082,7,2,32,,0,1,4,{ bonus bMdef,5; },{},{} +2109,Memorize_Book,Memory Book,5,20,,1000,,25,,0,0x00810204,7,2,32,,0,1,5,{ bonus bInt,1; bonus bMdef,2; if (isequipped(2717,2239)) { bonus bHPrecovRate,15; bonus bSPrecovRate,15; bonus bMatkRate,7; }; },{},{} +2110,Holy_Guard,Holy Guard,5,85000,,1400,,110,,0,0x00004000,7,2,32,,68,0,4,{ bonus bVit,2; bonus bMdef,2; },{},{} +2111,Herald_Of_GOD,Sacred Mission,5,128000,,1600,,120,,0,0x00004000,7,2,32,,83,1,4,{ bonus bVit,3; bonus bInt,2; bonus bMdef,3; bonus bUnbreakableShield,0; },{},{} +2112,Novice_Guard,Novice Guard,5,1,,1,,20,,0,0x00000001,7,2,32,,0,0,1,{},{},{} +2113,Novice_Shield,Novice Shield,5,5000,,1000,,20,,1,0x00000001,7,2,32,,40,1,3,{ bonus2 bSubEle,Ele_Water,20; bonus2 bSubEle,Ele_Earth,20; bonus2 bSubEle,Ele_Fire,20; bonus2 bSubEle,Ele_Wind,20; bonus2 bSubEle,Ele_Poison,20; bonus2 bSubEle,Ele_Ghost,20; bonus2 bSubEle,Ele_Undead,20; },{},{} +2114,Stone_Buckler,Stone Buckler,5,30000,,1500,,45,,1,0xFFFFFFFE,7,2,32,,65,1,2,{ bonus2 bSubSize,2,5; if (isequipped(2353,5122)) { bonus bStr,2; bonus bDef,5; bonus bMdef,5; if(BaseClass == Job_Swordman) bonus bDef,6; } },{},{} +2115,Valkyrja's_Shield,Valkyrja's Shield,5,30000,,500,,80,,1,0xFFFFFFFE,7,2,32,,65,1,4,{ bonus2 bSubEle,Ele_Water,20; bonus2 bSubEle,Ele_Fire,20; bonus2 bSubEle,Ele_Dark,20; bonus2 bSubEle,Ele_Undead,20; bonus bMdef,5; if(isequipped(2353,5124)) { bonus bDef,2-getrefine()-getequiprefinerycnt(EQI_HEAD_TOP); bonus bMdef,5+getrefine()+getequiprefinerycnt(EQI_HEAD_TOP); } },{},{} +2116,Angel's_Safeguard,Angelic Guard,5,10000,,400,,30,,1,0x00000001,7,2,32,,20,1,1,{ bonus2 bSubRace,RC_Demon,5; },{},{} +2117,Arm_Guard,Arm Guard,5,10000,,150,,50,,0,0x02000000,7,2,32,,20,1,1,{},{},{} +2118,Arm_Guard_,Arm Guard,5,10000,,150,,50,,1,0x02000000,7,2,32,,20,1,1,{},{},{} +2119,Improved_Arm_Guard,Advanced Arm Guard,5,40000,,150,,45,,0,0x02000000,7,2,32,,50,1,1,{ bonus bMdef,5; },{},{} +2120,Improved_Arm_Guard_,Advanced Arm Guard,5,40000,,150,,45,,1,0x02000000,7,2,32,,50,1,1,{ bonus bMdef,5; },{},{} +2121,Memorize_Book_,Memory Book,5,20,,1000,,25,,1,0x00810204,7,2,32,,0,1,5,{ bonus bInt,1; bonus bMdef,2; if (isequipped(2717,2239)) { bonus bHPrecovRate,15; bonus bSPrecovRate,15; bonus bMatkRate,7; }; },{},{} +2122,Platinum_Shield,Platinum Shield,5,20,,1200,,95,,0,0xFFFFFFFE,2,2,32,,68,1,4,{ bonus bMdef,5; bonus2 bSubSize,1,15; bonus2 bSubSize,2,15; bonus2 bSubRace,RC_Undead,10; bonus5 bAutoSpellWhenHit,NPC_MAGICMIRROR,2,150,BF_MAGIC,0; },{},{} +2123,Orleans_Server,Orleans's Server,5,20,,1000,,75,,1,0xFFFFFFFE,2,2,32,,55,1,4,{ bonus bMdef,2; bonus bMagicDamageReturn,5; if (isequipped(2701)) bonus bCastrate,-10; },{},{} +2124,Thorny_Buckler,Thorny Buckler,5,20,,1000,,85,,1,0xFFFFFFFE,2,2,32,,55,1,2,{ bonus bMdef,2; if (isequipped(2702)) { bonus bAspdRate,10; bonus bShortWeaponDamageReturn,5; } },{},{} +2125,Strong_Shield,Strong Shield,5,20,,2500,,90,,1,0xFFFFFFFE,2,2,32,,75,1,4,{ bonus bNoKnockback,0; bonus2 bSubEle,Ele_Neutral,-20; bonus2 bSubEle,Ele_Fire,-20; bonus2 bSubEle,Ele_Water,-20; bonus2 bSubEle,Ele_Wind,-20; bonus2 bSubEle,Ele_Earth,-20; bonus2 bSubEle,Ele_Dark,-20; bonus2 bSubEle,Ele_Holy,-20; bonus2 bSubEle,Ele_Ghost,-20; },{},{} +2128,Herald_Of_GOD_,Sacred Mission,5,128000,,1600,,120,,1,0x00004000,7,2,32,,83,1,4,{ bonus bVit,3; bonus bInt,2; bonus bMdef,3; bonus bUnbreakableShield,0; },{},{} +2129,Exorcism_Bible,Exorcism Bible,5,20,,600,,80,,0,0x00008100,7,2,32,,50,1,5,{ bonus bHPrecovRate,3; bonus bSPrecovRate,3; bonus bInt,1; if(isequipped(1631)) { bonus2 bSkillAtk,"PR_MAGNUS",20; bonus3 bAutoSpellWhenHit,"PR_TURNUNDEAD",1,20; } },{},{} +2130,Cross_Shield,Cross Shield,5,20,,2000,,130,,1,0x00004000,7,2,32,,80,1,4,{ bonus bStr,1; bonus2 bSkillAtk,PA_SHIELDCHAIN,30; bonus2 bSkillAtk,CR_SHIELDBOOMERANG,30; bonus bUseSPrate,10; },{},{} +2131,Magic_Study_Vol1,Magic Bible Vol1,5,20,,1000,,18,,1,0x00810204,2,2,32,,70,1,5,{ bonus bMdef,3; bonus bInt,2; bonus2 bAddEffWhenHit,Eff_Stun,1000; },{},{} +2133,Tournament_Shield,Tournament Shield,5,20,,1000,,105,,1,0x00004082,2,2,32,,50,1,4,{ bonus2 bAddRace,RC_NonBoss,1; bonus2 bAddRace,RC_Boss,1; if( Class == Job_Lord_Knight ) bonus bAspdRate,-5; if( isequipped(1420) || isequipped(1421) || isequipped(1422) ) { bonus2 bAddRace,RC_NonBoss,4; bonus2 bAddRace,RC_Boss,4; bonus bDef,2; } },{},{} +2134,Shield_Of_Naga,Shield of Naga,5,20,,500,,35,,1,0x00CFFF80,2,2,32,,70,1,2,{ bonus bMdef,3; autobonus2 "{ bonus bShortWeaponDamageReturn,(getrefine()*3); }",10,5000,BF_WEAPON,"{ specialeffect2 EF_GUARD; }"; },{},{} +2135,Shadow_Guard,Shadow Guard,5,20,,800,,52,,1,0x00020000,2,2,32,,70,1,2,{ if( isequipped(2426) ) { bonus2 bAddEff,Eff_Blind,500; autobonus "{ bonus bFlee,20; }",200,10000,BF_WEAPON,"{ specialeffect2 EF_INCAGILITY; }"; } },{},{} +2138,Bradium_Shield,Bradium Shield,5,20,,1800,,98,,1,0x00CFFF80,2,2,32,,65,1,3,{ bonus2 bSkillAtk,CR_SHIELDBOOMERANG,60; bonus bAgi,-1; bonus bMaxHP,500; },{},{} +2139,Flame_Thrower,Flame Thrower,5,20000,,2000,,60,,0,0xFFFFFFFF,7,2,32,,99,0,1,{},{},{} + +// Footgear +2401,Sandals,Sandals,5,400,,200,,5,,0,0xFFFFFFFF,7,2,64,,0,1,0,{},{},{} +2402,Sandals_,Sandals,5,400,,200,,5,,1,0xFFFFFFFF,7,2,64,,0,1,0,{},{},{} +2403,Shoes,Shoes,5,3500,,400,,10,,0,0xFFFFFFFE,7,2,64,,0,1,0,{},{},{} +2404,Shoes_,Shoes,5,3500,,400,,10,,1,0xFFFFFFFE,7,2,64,,0,1,0,{},{},{} +2405,Boots,Boots,5,18000,,600,,16,,0,0x016E5CEA,7,2,64,,0,1,0,{},{},{} +2406,Boots_,Boots,5,18000,,600,,16,,1,0x016E5CEA,7,2,64,,0,1,0,{},{},{} +2407,Chrystal_Pumps,Crystal Pumps,5,20,,100,,5,,0,0xFFFFFFFE,7,0,64,,0,1,0,{ bonus bMdef,10; bonus bLuk,5; },{},{} +2408,Cuffs,Shackles,5,5000,,3000,,15,,0,0xFFFFFFFF,7,2,64,,0,1,0,{ if (isequipped(2655)) { bonus bBaseAtk,50; bonus2 bAddDefClass,1196,20; bonus2 bAddDefClass,1197,20; } },{},{} +2409,Spiky_Heel,High Heels,5,8500,,600,,4,,0,0xFFFFFFFE,7,2,64,,0,1,0,{ bonus bMdef,5; },{},{} +2410,Sleipnir,Sleipnir,5,20,,3500,,40,,0,0xFFFFFFFF,7,2,64,,94,0,0,{ bonus bMdef,10; bonus bMaxHPrate,20; bonus bMaxSPrate,20; bonus bSPrecovRate,15; bonus bSpeedRate,25; },{},{} +2411,Grave,Greaves,5,48000,,750,,27,,0,0x00004080,7,2,64,,65,1,0,{},{},{} +2412,Grave_,Greaves,5,54000,,750,,15,,1,0x00004080,7,2,64,,65,1,0,{},{},{} +2414,Novice_Boots,Novice Slippers,5,1,,1,,5,,0,0x00000001,7,2,64,,0,0,0,{},{},{} +2416,Novice_Shoes,Novice Shoes,5,35000,,500,,8,,1,0x00000001,7,2,64,,40,1,0,{ bonus bMaxHPrate,5; },{},{} +2417,Fricco_Shoes,Fricco's Shoes,5,30000,,500,,12,,0,0xFFFFFFFE,7,2,64,,65,1,0,{ bonus bAgi,2; bonus2 bAddItemHealRate,IG_Potion,20; if(isequipped(2353,2516)){ bonus bAgi,3; bonus bMaxHPrate,5; bonus bMaxSPrate,5; } },{},{} +2418,Vidar's_Boots,Vidar's Boots,5,30000,,650,,13,,0,0xFFFFFFFE,7,2,64,,65,1,0,{ bonus bMaxHPrate,9; bonus bMaxSPrate,9; if(isequipped(2353,2517)){ bonus bVit,5; bonus bHPrecovRate,10; bonus bSPrecovRate,10; } },{},{} +2419,Goibne's_Combat_Boots,Goibne's Greaves,5,30000,,700,,13,,0,0xFFFFFFFE,7,2,64,,54,1,0,{ bonus bMdef,3; bonus bMaxHPrate,5; bonus bMaxSPrate,5; },{},{} +2420,Angel's_Arrival,Angel's Reincarnation,5,10000,,300,,8,,1,0x00000001,7,2,64,,25,1,0,{ bonus bMaxHP,100; },{},{} +2421,Valkyrie_Shoes,Valkyrian Shoes,5,0,,500,,13,,1,0xFFFFFFFE,2,2,64,,1,1,0,{ bonus bUnbreakableShoes,0; if(BaseClass==Job_Mage||BaseClass==Job_Archer||BaseClass==Job_Acolyte) bonus bMaxHP,(BaseLevel*5); else if(BaseClass==Job_Swordman||BaseClass==Job_Merchant||BaseClass==Job_Thief) bonus bMaxSP,(JobLevel*2); },{},{} +2422,High_Fashion_Sandals,High Fashion Sandals,5,24000,,200,,7,,1,0x00818314,7,2,64,,40,1,0,{ bonus bMdef,10; },{},{} +2423,Variant_Shoes,Variant Shoes,5,20,,500,,13,,0,0xFFFFFFFE,2,2,64,,85,1,0,{ bonus bMaxHPRate,20-getrefine(); bonus bMaxSPRate,20-getrefine(); bonus bDef,getrefine()/2; },{},{} +2424,Tidal_Shoes,Tidal Shoes,5,20,,300,,13,,1,0xFFFFFFFE,2,2,64,,55,1,0,{ bonus2 bSubEle,Ele_Water,5; if (isequipped(2528)) { bonus bHPrecovRate,5; bonus bMaxHPrate,10; } },{},{} +2425,Black_Leather_Boots,Black Leather Boots,5,20,,500,,16,,0,0xFFFFFFFE,2,2,64,,55,1,0,{ bonus bAgi,1; if(getrefine() >= 9) bonus bAgi,2; },{},{} +2426,Shadow_Walk,Shadow Walk,5,20,,2000,,0,,0,0xFFFFFFFE,2,2,64,,75,1,0,{ bonus bMdef,10; if(getskilllv("AS_CLOAKING") < 3){ bonus5 bAutoSpellWhenHit,"AS_CLOAKING",3,100,BF_MAGIC,0; } else bonus5 bAutoSpellWhenHit,"AS_CLOAKING",getskilllv("AS_CLOAKING"),100,BF_MAGIC,0; },{},{} +2432,Spiky_Heel_,High Heels,5,8500,,600,,10,,1,0xFFFFFFFE,7,2,64,,0,1,0,{ bonus bMdef,5; },{},{} +2433,Diabolus_Boots,Diabolus Boots,5,20,,250,,15,,1,0x00CFFF80,2,2,64,,0,1,0,{ bonus bMaxHP,(BaseLevel*10); },{},{} +2434,Black_Leather_Boots_,Black Leather Boots,5,20,,500,,16,,1,0xFFFFFFFE,2,2,64,,55,1,0,{ bonus bAgi,1; if(getrefine() >= 9) bonus bAgi,2; },{},{} +2435,Battle_Greave,Battle Greaves,5,10,,0,,15,,1,0x026654E2,7,2,64,,80,1,0,{ bonus bMaxHP,100; bonus bMdef,1; bonus2 bSubRace,RC_DemiHuman,1; },{},{} +2436,Combat_Boots,Combat Boots,5,10,,0,,9,,1,0x00898B1C,7,2,64,,80,1,0,{ bonus bMaxHP,100; bonus bMdef,1; bonus2 bSubRace,RC_DemiHuman,1; },{},{} +2437,Battle_Boots,Battle Boots,5,10,,0,,9,,1,0x01000000,7,2,64,,80,1,0,{ bonus bMaxHP,100; bonus bMdef,1; bonus2 bSubRace,RC_DemiHuman,1; },{},{} +2440,Sprint_Shoes,Sprint Shoes,5,20,,300,,10,,1,0x00CFFF80,2,2,64,,70,1,0,{ bonus bAgi,1; bonus bSPrecovRate,5; },{},{} +2444,Krieger_Shoes1,Glorious Shoes,5,20,,0,,0,,0,0xFFFFFFFE,7,2,64,,81,1,0,{ bonus bMaxHPRate,10; bonus2 bSubRace,RC_DemiHuman,4; bonus3 bAutoSpellWhenHit,"AL_INCAGI",1,10; },{},{} +2445,Krieger_Shoes2,Glorious Popularized Shoes,5,20,,0,,0,,0,0xFFFFFFFE,7,2,64,,61,1,0,{ bonus bMaxHPRate,5; bonus bMaxSPRate,5; },{},{} +2446,Krieger_Shoes3,Glorious Mass-Production Shoes,5,20,,0,,10,,0,0xFFFFFFFE,7,2,64,,0,1,0,{ bonus bMaxHPRate,5; },{},{} +2447,Military_Boots,Army Boots,5,0,,1000,,5,,0,0xFFFFFFFE,7,2,64,,0,1,0,{},{},{} +2450,Vital_Tree_Shoes,Vital Tree Shoes,5,20,,500,,16,,0,0xFFFFFFFE,2,2,64,,60,1,0,{ bonus bMaxHPrate,10; bonus2 bHPRegenRate,30,10000; bonus bHealpower2,5; bonus bAddItemHealRate,5; bonus bMdef,3; bonus bVit,2; },{},{} +2456,Para_Team_Boots1,Eden Team Boots I,5,0,,0,,14,,0,0xFFFFFFFF,7,2,64,,12,0,0,{ bonus bHPrecovRate,10; bonus bSPrecovRate,2; },{},{} +2457,Para_Team_Boots2,Eden Team Boots II,5,0,,0,,16,,0,0xFFFFFFFF,7,2,64,,26,0,0,{ bonus bHPrecovRate,12; bonus bSPrecovRate,4; },{},{} +2458,Para_Team_Boots3,Eden Team Boots III,5,0,,0,,18,,0,0xFFFFFFFF,7,2,64,,40,0,0,{ bonus bHPrecovRate,14; bonus bSPrecovRate,6; },{},{} +2463,Feral_Boots,Feral Boots,5,20,,0,,12,,0,0xFFFFFFFF,7,2,64,,75,0,0,{ bonus bMdef,2; },{},{} + +// Armor +2301,Cotton_Shirt,Cotton Shirt,5,10,,100,,10,,0,0xFFFFFFFF,7,2,16,,0,1,0,{},{},{} +2302,Cotton_Shirt_,Cotton Shirt,5,10,,100,,10,,1,0xFFFFFFFF,7,2,16,,0,1,0,{},{},{} +2303,Leather_Jacket,Jacket,5,200,,200,,15,,0,0xFFFFFFFF,7,2,16,,0,1,0,{},{},{} +2304,Leather_Jacket_,Jacket,5,200,,200,,15,,1,0xFFFFFFFF,7,2,16,,0,1,0,{},{},{} +2305,Adventure_Suit,Adventurer's Suit,5,1000,,300,,20,,0,0xFFFFFFFF,7,2,16,,0,1,0,{},{},{} +2306,Adventurere's_Suit_,Adventurer's Suit,5,1000,,300,,20,,1,0xFFFFFFFF,7,2,16,,0,1,0,{},{},{} +2307,Mantle,Mantle,5,10000,,600,,37,,0,0xFFFFFFFE,7,2,16,,0,1,0,{},{},{} +2308,Mantle_,Mantle,5,10000,,600,,37,,1,0xFFFFFFFE,7,2,16,,0,1,0,{},{},{} +2309,Coat,Coat,5,22000,,1200,,42,,0,0xFFFFFFFE,7,2,16,,0,1,0,{},{},{} +2310,Coat_,Coat,5,22000,,1200,,42,,1,0xFFFFFFFE,7,2,16,,0,1,0,{},{},{} +2311,Mink_Coat,Mink Coat,5,20,,2300,,30,,1,0xFFFFFFFE,7,2,16,,30,1,0,{},{},{} +2312,Padded_Armor,Padded Armor,5,48000,,2800,,35,,0,0x000654E2,7,2,16,,0,1,0,{ if(isequipped(2656)) { bonus bDef,5; bonus bMaxHP,150; } },{},{} +2313,Padded_Armor_,Padded Armor,5,48000,,2800,,35,,1,0x000654E2,7,2,16,,0,1,0,{ if(isequipped(2656)) { bonus bDef,5; bonus bMaxHP,150; } },{},{} +2314,Chain_Mail,Chain Mail,5,65000,,3300,,55,,0,0x000654E2,7,2,16,,0,1,0,{},{},{} +2315,Chain_Mail_,Chain Mail,5,65000,,3300,,55,,1,0x000654E2,7,2,16,,0,1,0,{},{},{} +2316,Plate_Armor,Full Plate,5,80000,,4500,,70,,0,0x00004082,7,2,16,,40,1,0,{},{},{} +2317,Plate_Armor_,Full Plate,5,80000,,4500,,70,,1,0x00004082,7,2,16,,40,1,0,{},{},{} +2318,Clothes_Of_The_Lord,Lord's Clothes,5,20,,2500,,59,,1,0x00040420,7,2,16,,70,1,0,{ bonus bMdef,5; bonus bInt,1; },{},{} +2319,Glittering_Clothes,Glittering Jacket,5,20,,2500,,58,,1,0xFFFFFFFE,7,2,16,,60,1,0,{ bonus bMdef,5; bonus2 bAddEff,Eff_Blind,300; },{},{} +2320,Formal_Suit,Formal Suit,5,20,,300,,40,,1,0xFFFFFFFE,7,2,16,,0,1,0,{},{},{} +2321,Silk_Robe,Silk Robe,5,8000,,400,,20,,0,0x0085C7B6,7,2,16,,0,1,0,{ bonus bMdef,10; },{},{} +2322,Silk_Robe_,Silk Robe,5,8000,,400,,20,,1,0x0085C7B6,7,2,16,,0,1,0,{ bonus bMdef,10; },{},{} +2323,Scapulare,Scapulare,5,6500,,400,,24,,0,0x00008110,7,2,16,,0,1,0,{},{},{} +2324,Scapulare_,Scapulare,5,6500,,400,,24,,1,0x00008110,7,2,16,,0,1,0,{},{},{} +2325,Saint_Robe,Saint's Robe,5,54000,,600,,50,,0,0x00048530,7,2,16,,0,1,0,{ bonus bMdef,5; },{},{} +2326,Saint_Robe_,Saint's Robe,5,54000,,600,,50,,1,0x00048530,7,2,16,,0,1,0,{ bonus bMdef,5; },{},{} +2327,Holy_Robe,Holy Robe,5,20,,1700,,57,,0,0x00008110,7,2,16,,60,1,0,{ bonus bMdef,5; bonus2 bSubRace,RC_Demon,15; bonus2 bSubEle,Ele_Dark,10; },{},{} +2328,Wooden_Mail,Wooden Mail,5,5500,,1000,,25,,0,0x000444A2,7,2,16,,0,1,0,{},{},{} +2329,Wooden_Mail_,Wooden Mail,5,5500,,1000,,25,,1,0x000444A2,7,2,16,,0,1,0,{},{},{} +2330,Tights,Tights,5,71000,,500,,27,,0,0x00080808,7,2,16,,45,1,0,{ bonus bDex,1; },{},{} +2331,Tights_,Tights,5,71000,,500,,27,,1,0x00080808,7,2,16,,45,1,0,{ bonus bDex,1; },{},{} +2332,Silver_Robe,Silver Robe,5,7000,,700,,23,,0,0x00810204,7,2,16,,0,1,0,{},{},{} +2333,Silver_Robe_,Silver Robe,5,7000,,700,,23,,1,0x00810204,7,2,16,,0,1,0,{},{},{} +2334,Mage_Coat,Mage Coat,5,20,,600,,40,,0,0x00810204,7,2,16,,50,1,0,{ bonus bMdef,5; bonus bInt,1; },{},{} +2335,Thief_Clothes,Thief Clothes,5,74000,,100,,40,,0,0x02021040,7,2,16,,0,1,0,{ bonus bAgi,1; },{},{} +2336,Thief_Clothes_,Thief Clothes,5,74000,,100,,40,,1,0x02021040,7,2,16,,0,1,0,{ bonus bAgi,1; },{},{} +2337,Ninja_Suit,Ninja Suit,5,20,,1500,,58,,0,0x02021040,7,2,16,,50,1,0,{ bonus bAgi,1; bonus bMdef,3; if(isequipped(2654)) { bonus bUseSPrate,-20; bonus bMaxHP,300; } },{},{} +2338,Wedding_Dress,Wedding Dress,5,43000,,500,,10,,0,0xFFFFFFFE,7,2,16,,0,1,0,{ bonus bMdef,15; },{},{} +2339,G_Strings,Pantie,5,1000,,100,,22,,0,0xFFFFFFFF,7,2,16,,0,1,0,{},{},{} +2341,Full_Plate_Armor,Legion Plate Armor,5,94000,,5500,,79,,0,0x00004000,7,2,16,,70,1,0,{},{},{} +2342,Full_Plate_Armor_,Legion Plate Armor,5,102500,,5500,,79,,1,0x00004000,7,2,16,,70,1,0,{},{},{} +2343,Robe_Of_Casting,Robe of Cast,5,124800,,1100,,40,,0,0x00810200,7,2,16,,75,1,0,{ bonus bCastrate,-3; bonus bMdef,4; },{},{} +2344,Flame_Sprits_Armor,Lucius's Fierce Armor of Volcano,5,136000,,2200,,25,,0,0x000444A2,7,2,16,,45,1,0,{ bonus bDefEle,Ele_Fire; },{},{} +2345,Flame_Sprits_Armor_,Lucius's Fierce Armor of Volcano,5,136000,,2200,,25,,1,0xFFFFFFFE,7,2,16,,45,1,0,{ bonus bDefEle,Ele_Fire; },{},{} +2346,Water_Sprits_Armor,Saphien's Armor of Ocean,5,136000,,2200,,25,,0,0x000444A2,7,2,16,,45,1,0,{ bonus bDefEle,Ele_Water; },{},{} +2347,Water_Sprits_Armor_,Saphien's Armor of Ocean,5,136000,,2200,,25,,1,0xFFFFFFFE,7,2,16,,45,1,0,{ bonus bDefEle,Ele_Water; },{},{} +2348,Wind_Sprits_Armor,Aebecee's Raging Typhoon Armor,5,136000,,2200,,25,,0,0x000444A2,7,2,16,,45,1,0,{ bonus bDefEle,Ele_Wind; },{},{} +2349,Wind_Sprits_Armor_,Aebecee's Raging Typhoon Armor,5,136000,,2200,,25,,1,0xFFFFFFFE,7,2,16,,45,1,0,{ bonus bDefEle,Ele_Wind; },{},{} +2350,Earth_Sprits_Armor,Claytos Cracking Earth Armor,5,136000,,2200,,25,,0,0x000444A2,7,2,16,,45,1,0,{ bonus bDefEle,Ele_Earth; },{},{} +2351,Earth_Sprits_Armor_,Claytos Cracking Earth Armor,5,136000,,2200,,25,,1,0xFFFFFFFE,7,2,16,,45,1,0,{ bonus bDefEle,Ele_Earth; },{},{} +2352,Novice_Plate,Tattered Novice Ninja Suit,5,1,,1,,25,,0,0x00000001,7,2,16,,0,0,0,{},{},{} +2353,Odin's_Blessing,Odin's Blessing,5,30000,,2500,,53,,1,0xFFFFFFFE,7,2,16,,65,1,0,{},{},{} +2354,Goibne's_Armor,Goibne's Armor,5,50000,,3500,,58,,0,0xFFFFFFFE,7,2,16,,54,1,0,{ bonus bVit,2; bonus bMaxHPrate,10; },{},{} +2355,Angel's_Protection,Angelic Protection,5,10000,,600,,25,,1,0x00000001,7,2,16,,40,1,0,{ bonus bMdef,20; if(isequipped(2116,2420,2521,5125)) { bonus bMaxHP,900; bonus bMaxSP,100; bonus3 bAutoSpellWhenHit,HP_ASSUMPTIO,1,30; } },{},{} +2356,Vestment_Of_Grace,Blessed Holy Robe,5,20,,2500,,45,,1,0x00008100,7,2,16,,70,1,0,{ bonus bMdef,5; bonus2 bResEff,Eff_Blind,8000; },{},{} +2357,Valkyrie_Armor,Valkyrian Armor,5,0,,2800,,55,,1,0xFFFFFFFE,2,2,16,,1,1,0,{ bonus bAllStats,1; bonus bUnbreakableArmor,0; if(BaseClass==Job_Mage||BaseClass==Job_Archer||BaseClass==Job_Acolyte) bonus2 bResEff,Eff_Silence,5000; else if(BaseClass==Job_Swordman||BaseClass==Job_Merchant||BaseClass==Job_Thief) bonus2 bResEff,Eff_Stun,5000; },{},{} +2359,Ninja_Suit_,Ninja Suit,5,20,,1500,,58,,1,0x02021040,7,2,16,,50,1,0,{ bonus bAgi,1; bonus bMdef,3; if(isequipped(2654)) { bonus bUseSPrate,-20; bonus bMaxHP,300; } },{},{} +2360,Robe_Of_Casting_,Robe of Cast,5,124800,,1100,,40,,1,0x00810200,7,2,16,,75,1,0,{ bonus bCastrate,-3; bonus bMdef,4; },{},{} +2364,Meteo_Plate_Armor,Meteo Plate Armor,5,20,,3000,,85,,1,0x000444A2,2,2,16,,55,1,0,{ bonus2 bResEff,Eff_Stun,3000; bonus2 bResEff,Eff_Freeze,3000; },{},{} +2365,Orleans_Gown,Orleans's Gown,5,20,,300,,15,,1,0xFFFFFFFE,2,2,16,,55,1,0,{ bonus bCastrate,15; bonus bNoCastCancel,0; },{},{} +2366,Divine_Cloth,Divine Cloth,5,20,,1500,,50,,1,0xFFFFFFFE,2,2,16,,55,1,0,{ bonus2 bResEff,Eff_Curse,500; bonus2 bResEff,Eff_Silence,500; bonus2 bResEff,Eff_Stun,500; bonus2 bResEff,Eff_Stone,500; bonus2 bResEff,Eff_Sleep,500; },{},{} +2367,Sniping_Suit,Sniping Suit,5,20,,750,,42,,1,0x00000800,2,2,16,,50,1,0,{ bonus bMdef,5; bonus bCritical,6+(readparam(bLuk)/10); bonus bDelayRate,-23; },{},{} +2371,G_Strings_,Pantie,5,1000,,100,,22,,1,0xFFFFFFFF,7,2,16,,0,1,0,{},{},{} +2372,Mage_Coat_,Mage Coat,5,20,,600,,40,,1,0x00810204,7,2,16,,50,1,0,{ bonus bMdef,5; bonus bInt,1; },{},{} +2373,Holy_Robe_,Holy Robe,5,20,,1700,,57,,1,0x00008110,7,2,16,,60,1,0,{ bonus bMdef,5; bonus2 bSubRace,RC_Demon,15; bonus2 bSubEle,Ele_Dark,10; },{},{} +2374,Diabolus_Robe,Diabolus Robe,5,20,,300,,57,,1,0x00098B1C,2,2,16,,55,1,0,{ bonus bMaxSP,150; bonus bMdef,5; bonus bHealPower,6; bonus bDelayRate,-10; if (isequipped(2729)) { bonus2 bAddRace,RC_NonBoss,3; bonus2 bAddRace,RC_Boss,3; bonus bMatkRate,3; } },{},{} +2375,Diabolus_Armor,Diabolus Armor,5,20,,600,,79,,1,0x000654E2,2,2,16,,55,1,0,{ bonus bStr,2; bonus bDex,1; bonus bMaxHP,150; bonus2 bResEff,Eff_Stun,500; bonus2 bResEff,Eff_Stone,500; if (isequipped(2729)) { bonus2 bAddRace,RC_NonBoss,3; bonus2 bAddRace,RC_Boss,3; bonus bMatkRate,3; } },{},{} +2376,Assaulter_Plate,Assaulter Plate,5,10,,0,,57,,1,0x006444A2,7,2,16,,80,1,0,{ bonus bMaxHP,150; bonus bMdef,2; bonus2 bSubRace,RC_DemiHuman,2; if (isequipped(2538,2435)) { bonus2 bSubRace,RC_NonDemiHuman,-300; bonus bVit,3; bonus bMaxHPRate,12; bonus bHealpower2,10; bonus bAddItemHealRate,10; autobonus2 "{ bonus2 bHPRegenRate,600,1000; }",5,10000,BF_WEAPON,"{ specialeffect2 EF_HEAL; }"; }; },{},{} +2377,Elite_Engineer_Armor,Elite Engineer Armor,5,10,,0,,50,,1,0x00040420,7,2,16,,80,1,0,{ bonus bMaxHP,150; bonus bMdef,2; bonus2 bSubRace,RC_DemiHuman,2; if (isequipped(2538,2435)) { bonus2 bSubRace,RC_NonDemiHuman,-300; bonus bStr,3; bonus bMaxHPRate,12; bonus2 bSkillAtk,"MC_MAMMONITE",20; bonus2 bSkillHeal,"AM_POTIONPITCHER",10; bonus2 bSkillHeal2,"AM_POTIONPITCHER",10; bonus2 bSkillHeal2,"AL_HEAL",10; bonus bUnbreakableArmor,0; }; },{},{} +2378,Assassin_Robe,Assassin Robe,5,10,,0,,41,,1,0x02021040,7,2,16,,80,1,0,{ bonus bMaxHP,150; bonus bMdef,2; bonus2 bSubRace,RC_DemiHuman,2; if (isequipped(2538,2435)) { bonus2 bSubRace,RC_NonDemiHuman,-300; bonus bAgi,3; bonus bMaxHPRate,12; bonus bCritical,5; bonus bAspdRate,5; autobonus "{ bonus2 bHPRegenRate,300,1000; }",10,10000,BF_WEAPON,"{ specialeffect2 EF_HEAL; }"; }; },{},{} +2379,Warlock_Battle_Robe,Warlock's Battle Robe,5,10,,0,,36,,1,0x00810204,7,2,16,,80,1,0,{ bonus bMaxHP,150; bonus bMdef,2; bonus2 bSubRace,RC_DemiHuman,2; if (isequipped(2539,2436)) { bonus2 bSubRace,RC_NonDemiHuman,-300; bonus bInt,3; bonus bMaxHPRate,12; bonus2 bResEff,Eff_Stun,2000; autobonus2 "{ bonus bDefEle,Ele_Ghost; }",30,10000,BF_WEAPON,"{ specialeffect2 EF_ENERGYCOAT; }"; }; },{},{} +2380,Medic_Robe,Medic's Robe,5,10,,0,,25,,1,0x00008110,7,2,16,,80,1,0,{ bonus bMaxHP,150; bonus bMdef,2; bonus2 bSubRace,RC_DemiHuman,2; if (isequipped(2539,2436)) { bonus2 bSubRace,RC_NonDemiHuman,-300; bonus bInt,3; bonus bMaxHPRate,12; bonus2 bCastrate,156,-50; bonus bHealPower,6; autobonus2 "{ bonus bDefEle,Ele_Ghost; }",30,10000,BF_WEAPON,"{ specialeffect2 EF_ENERGYCOAT; }"; }; },{},{} +2381,Elite_Archer_Suit,Elite Archer Suit,5,10,,0,,35,,1,0x00080808,7,2,16,,80,1,0,{ bonus bMaxHP,150; bonus bMdef,2; bonus2 bSubRace,RC_DemiHuman,2; if (isequipped(2539,2436)) { bonus2 bSubRace,RC_NonDemiHuman,-300; bonus bDex,3; bonus bMaxHPRate,12; bonus bLongAtkDef,10; bonus bDelayRate,-25; }; },{},{} +2382,Elite_Shooter_Suit,Elite Shooter Suit,5,10,,0,,25,,1,0x01000000,7,2,16,,80,1,0,{ bonus bMaxHP,150; bonus bMdef,2; bonus2 bSubRace,RC_DemiHuman,2; if (isequipped(2540,2437)) { bonus2 bSubRace,RC_NonDemiHuman,-300; bonus bDex,3; bonus bMaxHPRate,12; bonus bLongAtkDef,10; bonus bDelayRate,-25; }; },{},{} +2383,Brynhild,Brynhild,5,20,,400,,120,,0,0xFFFFFFFF,7,2,16,,94,0,0,{ bonus bMdef,10; bonus bMaxHP,20*BaseLevel; bonus bMaxSP,5*BaseLevel; bonus2 bAddRace,RC_NonBoss,10; bonus2 bAddRace,RC_Boss,10; bonus bMatkRate,10; bonus bUnbreakableArmor,0; bonus bNoKnockback,0; },{},{} +2386,Chameleon_Armor,Chameleon Armor,5,20,,1700,,55,,0,0x00CFFF80,2,2,16,,70,1,0,{ bonus bMaxHP,(BaseLevel*7); bonus bMaxSP,(BaseLevel/2); autobonus2 "{ bonus bNoMagicDamage,100; }",10,2000,BF_MAGIC,"{ specialeffect2 EF_ENERGYCOAT; }"; if( BaseClass == Job_Mage || BaseClass == Job_Archer || BaseClass == Job_Acolyte ) bonus bMdef,5; else if( BaseClass == Job_Swordman || BaseClass == Job_Merchant || BaseClass == Job_Thief ) bonus bDef,3; },{},{} +2387,Sprint_Mail,Sprint Mail,5,20,,1000,,20,,1,0x00CFFF80,2,2,16,,70,1,0,{ bonus bVit,1; bonus bHPrecovRate,5; bonus bAddItemHealRate,3; bonus2 bSkillHeal,AL_HEAL,3; if( isequipped(2440,2744) ) { bonus bMaxHPrate,7; bonus bMaxSPrate,7; bonus bCastrate,-3; bonus bDelayrate,-15; } },{},{} +2388,Kandura,Kandura,5,20,,300,,36,,1,0x00001000,2,2,16,,70,1,0,{ bonus bAgi,1; bonus bFlee,5; bonus bAspdRate,2; },{},{} +2389,Armor_Of_Naga,Armor of Naga,5,20,,1000,,45,,1,0x00CFFF80,2,2,16,,70,1,0,{ bonus bMdef,2; autobonus "{ bonus bBaseAtk,20; }",10,10000,BF_WEAPON,"{ specialeffect2 EF_ENHANCE; }"; },{},{} +2390,Improved_Tights,Improved Tights,5,20,,400,,38,,1,0x00080808,2,2,16,,75,1,0,{ bonus bMdef,2; bonus bFlee2,3; },{},{} +2391,Life_Link,Life Link,5,20,,3500,,75,,1,0x00004082,2,2,16,,82,1,0,{ bonus bVit,2; bonus bMdef,5; bonus bHPrecovRate,50; },{},{} + +// Garment +2501,Hood,Hood,5,1000,,200,,4,,0,0xFFFFFFFF,7,2,4,,0,1,0,{},{},{} +2502,Hood_,Hood,5,1000,,200,,4,,1,0xFFFFFFFF,7,2,4,,0,1,0,{},{},{} +2503,Muffler,Muffler,5,5000,,400,,8,,0,0xFFFFFFFE,7,2,4,,0,1,0,{},{},{} +2504,Muffler_,Muffler,5,5000,,400,,8,,1,0xFFFFFFFE,7,2,4,,0,1,0,{},{},{} +2505,Manteau,Manteau,5,32000,,600,,13,,0,0x006654E2,7,2,4,,0,1,0,{},{},{} +2506,Manteau_,Manteau,5,32000,,600,,13,,1,0x006654E2,7,2,4,,0,1,0,{},{},{} +2507,Cape_Of_Ancient_Lord,Ancient Cape,5,82000,,600,,9,,0,0xFFFFFFFE,7,2,4,,40,1,0,{ bonus bAgi,1; },{},{} +2508,Ragamuffin_Cape,Ragamuffin Manteau,5,56000,,500,,4,,0,0xFFFFFFFE,7,2,4,,0,1,0,{ bonus bUnbreakableGarment,0; bonus bMdef,10; },{},{} +2509,Clack_Of_Servival,Survivor's Manteau,5,20000,,550,,10,,0,0x00810204,7,2,4,,75,1,0,{ bonus bMdef,5; bonus bVit,10; if(isequipped(1618) || isequipped(1620)){ bonus bMaxHP,300; bonus bMatkRate,getequiprefinerycnt(EQI_HAND_R)-5; bonus2 bSubEle,Ele_Neutral,getrefine()*3; } },{},{} +2510,Novice_Hood,Somber Novice Hood,5,1,,1,,4,,0,0x00000001,7,2,4,,0,0,0,{ bonus2 bSubEle,Ele_Neutral,20; },{},{} +2512,Novice_Manteau,Novice Manteau,5,50000,,500,,7,,1,0x00000001,7,2,4,,40,1,0,{ bonus2 bSubEle,Ele_Neutral,10; },{},{} +2513,Celestial_Robe,Heavenly Maiden Robe,5,20,,500,,18,,1,0xFFFFFFFE,7,2,4,,80,1,0,{},{},{} +2514,Pauldron,Pauldron,5,20,,800,,25,,1,0x000654E2,7,2,4,,80,1,0,{},{},{} +2515,Wing_Of_Eagle,Eagle Wing,5,20000,,300,,12,,1,0x00810204,7,2,4,,85,1,0,{ if(isequipped(1616)) bonus bSpeedRate,25; },{},{} +2516,Falcon_Robe,Falcon Muffler,5,30000,,400,,8,,0,0xFFFFFFFE,7,2,4,,65,1,0,{ bonus bFlee,15; bonus bFlee2,5; },{},{} +2517,Vali's_Manteau,Vali's Manteau,5,30000,,600,,13,,0,0xFFFFFFFE,7,2,4,,65,1,0,{ bonus2 bSubEle,Ele_Neutral,15; },{},{} +2518,Morpheus's_Shawl,Morpheus's Shawl,5,30000,,600,,8,,0,0xFFFFFFFE,7,2,4,,33,1,0,{ bonus bMaxSPrate,10; bonus bMdef,3; },{},{} +2519,Morrigane's_Manteau,Morrigane's Manteau,5,30000,,600,,9,,0,0xFFFFFFFE,7,2,4,,61,1,0,{ bonus bLuk,2; bonus bFlee2,8; },{},{} +2520,Goibne's_Shoulder_Arms,Goibne's Spaulders,5,30000,,700,,11,,0,0xFFFFFFFE,7,2,4,,54,1,0,{ bonus bLongAtkDef,10; bonus bMdef,2; bonus bVit,1; },{},{} +2521,Angel's_Warmth,Angelic Cardigan,5,10000,,400,,5,,1,0x00000001,7,2,4,,20,1,0,{ bonus bHPrecovRate,5; },{},{} +2522,Undershirt,Undershirt,5,20000,,150,,5,,0,0xFFFFFFFF,7,2,4,,1,1,0,{ bonus bMdef,1; if(isequipped(2339) || isequipped(2371)) { bonus bAgi,5; bonus bFlee,10; } },{},{} +2523,Undershirt_,Undershirt,5,20000,,150,,5,,1,0xFFFFFFFF,7,2,4,,1,1,0,{ bonus bMdef,1; if(isequipped(2339) || isequipped(2371)) { bonus bAgi,5; bonus bFlee,10; } },{},{} +2524,Valkyrie_Manteau,Valkyrian Manteau,5,0,,500,,10,,1,0xFFFFFFFE,2,2,4,,1,1,0,{ bonus bUnbreakableGarment,0; if(BaseClass==Job_Mage||BaseClass==Job_Archer||BaseClass==Job_Acolyte) bonus bFlee2,5+(getequiprefinerycnt(EQI_GARMENT)*2); else if(BaseClass==Job_Swordman||BaseClass==Job_Merchant||BaseClass==Job_Thief) bonus bShortWeaponDamageReturn,5+(getequiprefinerycnt(EQI_GARMENT)*2); },{},{} +2525,Cape_Of_Ancient_Lord_,Ancient Cape,5,82000,,600,,9,,1,0xFFFFFFFE,7,2,4,,40,1,0,{ bonus bAgi,1; },{},{} +2527,Dragon_Breath,Dragon Breath,5,20,,600,,16,,1,0xFFFFFFFE,2,2,4,,48,1,0,{ bonus2 bSubRace,RC_Dragon,15; if (isequipped(1166) || isequipped(13001) || isequipped(1474)) bonus2 bAddRace,RC_Dragon,5; },{},{} +2528,Wool_Scarf,Wool Scarf,5,20,,500,,11,,1,0xFFFFFFFE,2,2,4,,55,1,0,{ bonus bMdef,4; },{},{} +2529,Rider_Insignia,Rider Insignia,5,20,,500,,13,,0,0xFFFFFFFE,2,2,4,,55,1,0,{ bonus bAgi,2; if (isequipped(2425) || isequipped(2434)) bonus bFlee,10; },{},{} +2530,Rider_Insignia_,Rider Insignia,5,20,,500,,13,,1,0xFFFFFFFE,2,2,4,,55,1,0,{ bonus bAgi,2; if (isequipped(2425) || isequipped(2434)) bonus bFlee,10; },{},{} +2531,Ulfhedinn,Ulfhedinn,5,20,,700,,13,,1,0x000654E2,2,2,4,,70,1,0,{ bonus3 bAutoSpellWhenHit,NPC_STONESKIN,1,20; },{},{} +2532,Mithril_Magic_Cape,Mithril Magic Cape,5,20,,400,,8,,1,0x00098B1C,2,2,4,,70,1,0,{ bonus bMdef,3; bonus5 bAutoSpellWhenHit,NPC_ANTIMAGIC,1,200,BF_MAGIC,0; },{},{} +2536,Skin_Of_Ventus,Skin of Ventus,5,20,,250,,7,,1,0xFFFFFFFE,7,2,4,,60,1,0,{ bonus bMdef,2; bonus bMaxHP,200; bonus bFlee,10; },{},{} +2537,Diabolus_Manteau,Diabolus Manteau,5,20,,250,,15,,1,0x00CFFF80,2,2,4,,0,1,0,{ bonus2 bSubEle,Ele_Neutral,5; bonus bMaxHP,100; bonus2 bAddDamageClass,1916,10; bonus2 bAddDamageClass,1917,10; if (isequipped(2433)) bonus bMaxHPRate,6; },{},{} +2538,Commander_Manteau,Captain's Manteau,5,10,,0,,28,,1,0x026654E2,7,2,4,,80,1,0,{ bonus bMaxHP,50; bonus bMdef,1; bonus2 bSubRace,RC_DemiHuman,1; },{},{} +2539,Commander_Manteau_,Commander's Manteau,5,10,,0,,20,,1,0x00898B1C,7,2,4,,80,1,0,{ bonus bMaxHP,50; bonus bMdef,1; bonus2 bSubRace,RC_DemiHuman,1; },{},{} +2540,Sheriff_Manteau,Sheriff's Manteau,5,10,,0,,20,,1,0x01000000,7,2,4,,80,1,0,{ bonus bMaxHP,50; bonus bMdef,1; bonus2 bSubRace,RC_DemiHuman,1; },{},{} +2541,Asprika,Asprika,5,20,,400,,40,,0,0xFFFFFFFF,7,2,4,,94,0,0,{ bonus bMdef,5; bonus3 bSubEle,Ele_Neutral,30,BF_SHORT; bonus3 bSubEle,Ele_Water,30,BF_SHORT; bonus3 bSubEle,Ele_Earth,30,BF_SHORT; bonus3 bSubEle,Ele_Fire,30,BF_SHORT; bonus3 bSubEle,Ele_Wind,30,BF_SHORT; bonus3 bSubEle,Ele_Poison,30,BF_SHORT; bonus3 bSubEle,Ele_Holy,30,BF_SHORT; bonus3 bSubEle,Ele_Dark,30,BF_SHORT; bonus3 bSubEle,Ele_Ghost,30,BF_SHORT; bonus3 bSubEle,Ele_Undead,30,BF_SHORT; bonus bFlee,30; skill "AL_TELEPORT",1; bonus bUnbreakableGarment,0; },{},{} +2542,Flame_Manteau,Flame Manteau of Naght Sieger,5,20,,70,,16,,1,0xFFFFFFFE,2,2,4,,70,1,0,{ bonus bMaxHPRate,5; bonus bMdef,2; bonus bMatkRate,1; bonus2 bAddEle,Ele_Fire,2; },{},{} +2544,Leather_Of_Tendrilion,Leather of Tendrilion,5,20,,300,,14,,1,0x00CFDF80,2,2,4,,0,1,0,{ bonus2 bSubEle,Ele_Water,5; bonus2 bSubEle,Ele_Earth,5; bonus2 bSubRace,RC_Plant,5; bonus2 bSubRace,RC_Brute,5; },{},{} +2545,Musika,Musika,5,20,,500,,10,,1,0x00008100,2,2,4,,70,1,0,{ bonus bMdef,3; bonus3 bAutoSpellwhenhit,AL_HEAL,getskilllv("AL_HEAL") ? getskilllv("AL_HEAL") : 1,20; },{},{} +2548,Muffler_C,Neo Muffler,5,0,,0,,5,,0,0xFFFFFFFE,2,2,4,,95,0,0,{ bonus2 bSubRace,RC_DemiHuman,10; bonus bMaxHPrate,10; bonus2 bSubEle,Ele_Water,5; bonus2 bSubEle,Ele_Fire,5; bonus2 bSubEle,Ele_Holy,5; bonus2 bSubEle,Ele_Dark,5; },{},{} +2549,Krieger_Muffler1,Glorious Muffler,5,20,,0,,0,,0,0xFFFFFFFE,7,2,4,,81,1,0,{ bonus bMaxHPRate,5; bonus2 bSubRace,RC_DemiHuman,5; },{},{} +2553,Dragon_Manteau,Dragon Manteau,5,20,,1000,,14,,1,0xFFFFFFFE,2,2,4,,0,1,0,{ bonus bAgi,1; bonus bMdef,5; },{},{} +2554,Piece_Of_Angent_Skin,Nydhorgg's Shadow Garb,5,20,,400,,25,,1,0xFFFFFFFE,2,2,4,,90,1,0,{ bonus2 bSubEle,Ele_Neutral,7; bonus2 bSubEle,Ele_Water,7; bonus2 bSubEle,Ele_Earth,7; bonus2 bSubEle,Ele_Fire,7; bonus2 bSubEle,Ele_Wind,7; bonus2 bSubEle,Ele_Poison,7; bonus2 bSubEle,Ele_Holy,7; bonus2 bSubEle,Ele_Dark,7; bonus2 bSubEle,Ele_Ghost,7; bonus2 bSubEle,Ele_Undead,7; bonus bMaxSP,(BaseLevel/3)+(getrefine()*10); bonus3 bSPDrainRate,1,1,0; bonus bMdef,3; },{},{} +2560,Para_Team_Manteau,Eden Team Manteau,5,0,,0,,14,,0,0xFFFFFFFF,7,2,4,,12,0,0,{ bonus2 bSubEle,Ele_Neutral,10; },{},{} +2564,Feral_Tail,Feral Tail,5,20,,0,,16,,0,0xFFFFFFFF,7,2,4,,75,0,0,{},{},{} + + +//[Ind] keeping these 2 here until we confirm: these ids are conflicting, I think they're wrong. +// Minstrel And Wanderer Cough Drop +//11513,Cough_Drop,Cough Drop,3,200,,10,,,,,,,,,,,,,{},{},{} + +// Genetic Cure Free +//11518,Cure_Free,Cure Free,0,10,,30,,,,,0xFFFFFFFF,7,2,,,,,,{ itemheal rand(1000,1200),0; sc_end SC_Silence; sc_end SC_Bleeding; sc_end SC_Curse; },{},{} + + +// Unknown Item. Rune Knight Armor??? +//15002,Rune_Plate,Rune Plate,3,10,,10,,,,,,,,,,,,,{},{},{} + diff --git a/db/job_db1.txt b/db/job_db1.txt index fb1fe7fdd..10f2ff922 100644 --- a/db/job_db1.txt +++ b/db/job_db1.txt @@ -153,3 +153,74 @@ 4048, 28000,90 ,650 ,470 ,400 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,500 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 // Soul Linker 4049, 24000,75 ,500 ,900 ,500 ,575 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,625 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 , 625 +//************************************************************* +//* 3rds (base 650 3CeAM) +//************************************************************* +// Rune Knight (Base 2nd to 3rd) +4054, 28000,150 ,500 ,300 ,400 ,500 ,500 ,550 ,600 ,600 ,700 ,700 ,650 ,700 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Warlock (Base 2nd to 3rd) +4055, 24000,55 ,500 ,900 ,500 ,575 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,625 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 , 625 +// Ranger (Base 2nd to 3rd) +4056, 27000,85 ,500 ,400 ,400 ,600 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,600 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Arch Bishop (Base 2nd to 3rd) +4057, 26000,75 ,500 ,800 ,400 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,600 ,600 ,600 ,2000 ,2000 ,2000 ,2000 ,600 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 , 600 +// Mechanic (Base 2nd to 3rd) +4058, 30000,90 ,500 ,400 ,400 ,600 ,650 ,2000 ,2000 ,2000 ,650 ,650 ,675 ,675 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Guillotine Cross(Base 2nd to 3rd) +4059, 24000,110 ,500 ,400 ,400 ,500 ,650 ,2000 ,2000 ,2000 ,800 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,500 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Rune Knight (Trans 2nd to 3rd) +4060, 28000,150 ,500 ,300 ,400 ,500 ,500 ,550 ,600 ,600 ,700 ,700 ,650 ,700 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Warlock (Trans 2nd to 3rd) +4061, 24000,55 ,500 ,900 ,500 ,575 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,625 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 , 625 +// Ranger (Trans 2nd to 3rd) +4062, 27000,85 ,500 ,400 ,400 ,600 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,600 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Arch Bishop (Trans 2nd to 3rd) +4063, 26000,75 ,500 ,800 ,400 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,600 ,600 ,600 ,2000 ,2000 ,2000 ,2000 ,600 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 , 600 +// Mechanic (Trans 2nd to 3rd) +4064, 30000,90 ,500 ,400 ,400 ,600 ,650 ,2000 ,2000 ,2000 ,650 ,650 ,675 ,675 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Guillotine Cross(Trans 2nd to 3rd) +4065, 24000,110 ,500 ,400 ,400 ,500 ,650 ,2000 ,2000 ,2000 ,800 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,500 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Royal Guard (Base 2nd to 3rd) +4066, 28000,110 ,700 ,470 ,400 ,500 ,500 ,550 ,600 ,600 ,700 ,700 ,650 ,700 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Sorcerer (Base 2nd to 3rd) +4067, 24000,75 ,500 ,700 ,450 ,525 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,625 ,2000 ,2000 ,2000 ,2000 ,550 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 , 625 +// Minstrel (Base 2nd to 3rd) +4068, 27000,75 ,300 ,600 ,400 ,550 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,650 ,2000 ,575 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Wanderer (Base 2nd to 3rd) +4069, 27000,75 ,300 ,600 ,400 ,550 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,650 ,2000 ,2000 ,575 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Sura (Base 2nd to 3rd) +4070, 26000,90 ,650 ,470 ,400 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,575 ,575 ,575 ,2000 ,475 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 , 575 +// Genetic (Base 2nd to 3rd) +4071, 30000,90 ,500 ,400 ,400 ,550 ,575 ,2000 ,2000 ,2000 ,675 ,700 ,650 ,650 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Shadow Chaser (Base 2nd to 3rd) +4072, 24000,85 ,500 ,500 ,400 ,500 ,550 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,650 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Royal Guard (Trans 2nd to 3rd) +4073, 28000,110 ,700 ,470 ,400 ,500 ,500 ,550 ,600 ,600 ,700 ,700 ,650 ,700 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Sorcerer (Trans 2nd to 3rd) +4074, 24000,75 ,500 ,700 ,450 ,525 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,625 ,2000 ,2000 ,2000 ,2000 ,550 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 , 625 +// Minstrel (Trans 2nd to 3rd) +4075, 27000,75 ,300 ,600 ,400 ,550 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,650 ,2000 ,575 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Wanderer (Trans 2nd to 3rd) +4076, 27000,75 ,300 ,600 ,400 ,550 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,650 ,2000 ,2000 ,575 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Sura (Trans 2nd to 3rd) +4077, 26000,90 ,650 ,470 ,400 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,575 ,575 ,575 ,2000 ,475 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 , 575 +// Genetic (Trans 2nd to 3rd) +4078, 30000,90 ,500 ,400 ,400 ,550 ,575 ,2000 ,2000 ,2000 ,675 ,700 ,650 ,650 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Shadow Chaser (Trans 2nd to 3rd) +4079, 24000,85 ,500 ,500 ,400 ,500 ,550 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,650 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Rune Knight Mount (Base 2nd to 3rd) +4080, 28000,150 ,500 ,300 ,400 ,500 ,500 ,550 ,600 ,600 ,700 ,700 ,650 ,700 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Rune Knight Mount (Trans 2nd to 3rd) +4081, 28000,150 ,500 ,300 ,400 ,500 ,500 ,550 ,600 ,600 ,700 ,700 ,650 ,700 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Royal Guard Mount (Base 2nd to 3rd) +4082, 28000,110 ,700 ,470 ,400 ,500 ,500 ,550 ,600 ,600 ,700 ,700 ,650 ,700 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Royal Guard Mount (Trans 2nd to 3rd) +4083, 28000,110 ,700 ,470 ,400 ,500 ,500 ,550 ,600 ,600 ,700 ,700 ,650 ,700 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Ranger Mount (Base 2nd to 3rd) +4084, 27000,85 ,500 ,400 ,400 ,600 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,600 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Ranger Mount (Trans 2nd to 3rd) +4085, 27000,85 ,500 ,400 ,400 ,600 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,600 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Mechanic Mount (Base 2nd to 3rd) +4086, 30000,90 ,500 ,400 ,400 ,600 ,650 ,2000 ,2000 ,2000 ,650 ,650 ,675 ,675 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 +// Mechanic Mount (Trans 2nd to 3rd) +4087, 30000,90 ,500 ,400 ,400 ,600 ,650 ,2000 ,2000 ,2000 ,650 ,650 ,675 ,675 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 ,2000 \ No newline at end of file diff --git a/db/job_db2.txt b/db/job_db2.txt index 0144624b9..a0c88121d 100644 --- a/db/job_db2.txt +++ b/db/job_db2.txt @@ -161,3 +161,74 @@ 4048,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2 // Soul Linker 4049,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5 +//************************************************************* +//* 3rds (base 650 3CeAM) +//************************************************************* +// Rune Knight (Base 2nd to 3rd) +4054,4,4,5,3,4,0,0,0,0,1,1,4,4,3,5,0,0,0,5,2,2,4,3,5,0,0,0,0,0,4,5,3,1,0,0,0,0,0,4,5,2,0,0,5,3,4,6,6,6,4 +// Warlock (Base 2nd to 3rd) +4055,4,4,5,0,0,5,4,2,0,0,0,0,5,0,3,0,0,3,5,2,0,0,4,3,3,0,0,5,2,0,6,0,0,1,4,4,0,0,5,2,4,0,0,4,4,0,2,0,0,4 +// Ranger (Base 2nd to 3rd) +4056,5,4,4,2,0,0,2,5,4,0,0,3,3,3,0,0,5,2,0,0,4,3,5,0,0,1,1,0,0,5,2,3,0,0,0,4,4,4,2,0,0,0,2,5,2,0,0,0,4,2 +// Arch Bishop (Base 2nd to 3rd) +4057,4,0,3,0,5,0,4,4,0,3,3,0,0,5,5,0,0,1,1,0,0,4,0,1,0,2,2,1,0,0,0,4,0,3,0,5,0,2,2,4,4,0,0,5,3,1,0,0,4,5 +// Mechanic (Base 2nd to 3rd) +4058,6,1,0,0,1,0,6,2,5,4,0,0,4,6,0,0,2,0,3,3,4,5,0,0,3,6,0,0,3,0,1,1,3,6,0,0,4,4,0,0,0,3,3,1,1,0,0,5,2,0 +// Guillotine Cross (Base 2nd to 3rd) +4059,2,5,0,1,1,0,0,0,1,2,5,0,0,3,3,1,0,0,3,1,0,0,2,2,5,0,0,4,4,1,3,0,0,0,2,5,5,0,0,0,4,3,2,2,0,0,0,4,5,5 +// Rune Knight (Trans 2nd to 3rd) +4060,4,4,5,3,4,0,0,0,0,1,1,4,4,3,5,0,0,0,5,2,2,4,3,5,0,0,0,0,0,4,5,3,1,0,0,0,0,0,4,5,2,0,0,5,3,4,6,6,6,4 +// Warlock (Trans 2nd to 3rd) +4061,4,4,5,0,0,5,4,2,0,0,0,0,5,0,3,0,0,3,5,2,0,0,4,3,3,0,0,5,2,0,6,0,0,1,4,4,0,0,5,2,4,0,0,4,4,0,2,0,0,4 +// Ranger (Trans 2nd to 3rd) +4062,5,4,4,2,0,0,2,5,4,0,0,3,3,3,0,0,5,2,0,0,4,3,5,0,0,1,1,0,0,5,2,3,0,0,0,4,4,4,2,0,0,0,2,5,2,0,0,0,4,2 +// Arch Bishop (Trans 2nd to 3rd) +4063,4,0,3,0,5,0,4,4,0,3,3,0,0,5,5,0,0,1,1,0,0,4,0,1,0,2,2,1,0,0,0,4,0,3,0,5,0,2,2,4,4,0,0,5,3,1,0,0,4,5 +// Mechanic (Trans 2nd to 3rd) +4064,6,1,0,0,1,0,6,2,5,4,0,0,4,6,0,0,2,0,3,3,4,5,0,0,3,6,0,0,3,0,1,1,3,6,0,0,4,4,0,0,0,3,3,1,1,0,0,5,2,0 +// Guillotine Cross (Trans 2nd to 3rd) +4065,2,5,0,1,1,0,0,0,1,2,5,0,0,3,3,1,0,0,3,1,0,0,2,2,5,0,0,4,4,1,3,0,0,0,2,5,5,0,0,0,4,3,2,2,0,0,0,4,5,5 +// Royal Guard (Base 2nd to 3rd) +4066,5,5,5,5,5,0,0,0,2,2,2,2,2,0,0,0,1,1,1,1,1,0,0,0,0,6,6,6,6,6,0,0,0,0,0,3,3,3,3,3,0,0,0,0,0,4,4,4,4,4 +// Sorcerer (Base 2nd to 3rd) +4067,4,4,5,3,4,0,0,0,0,1,1,4,4,3,5,0,0,0,5,2,2,4,3,5,0,0,0,0,0,4,5,3,1,0,0,0,0,0,4,5,2,0,0,5,3,4,6,6,6,4 +// Minstrel (Base 2nd to 3rd) +4068,0,0,3,0,5,0,4,4,0,3,3,0,0,5,5,0,0,1,1,0,0,4,0,1,0,2,2,1,0,0,0,4,0,3,0,5,0,2,0,4,4,0,0,5,3,1,0,0,4,5 +// Wanderer (Base 2nd to 3rd) +4069,5,4,4,2,0,0,2,5,4,0,0,3,3,3,0,0,5,2,0,0,4,3,5,0,0,1,1,0,0,5,2,3,0,0,0,4,4,4,2,0,0,0,2,5,2,0,0,0,4,2 +// Sura (Base 2nd to 3rd) +4070,2,5,0,1,1,0,0,0,1,2,5,0,0,3,3,1,0,0,3,1,0,0,2,2,5,0,0,4,4,1,3,0,0,0,2,5,5,0,0,0,4,3,2,2,0,0,0,4,5,5 +// Genetic (Base 2nd to 3rd) +4071,4,4,5,0,0,5,4,2,0,0,0,4,5,0,0,0,0,3,5,2,0,0,4,3,3,0,0,5,2,0,6,0,0,0,4,4,1,0,5,2,4,0,0,4,4,0,2,0,0,4 +// Shadow Chaser (Base 2nd to 3rd) +4072,6,1,0,0,1,0,6,2,5,4,0,0,4,6,0,0,2,0,3,3,4,5,0,0,3,6,0,0,3,0,1,1,3,6,0,0,4,4,0,0,0,3,3,1,1,0,0,5,2,0 +// Royal Guard (Trans 2nd to 3rd) +4073,5,5,5,5,5,0,0,0,2,2,2,2,2,0,0,0,1,1,1,1,1,0,0,0,0,6,6,6,6,6,0,0,0,0,0,3,3,3,3,3,0,0,0,0,0,4,4,4,4,4 +// Sorcerer (Trans 2nd to 3rd) +4074,4,4,5,3,4,0,0,0,0,1,1,4,4,3,5,0,0,0,5,2,2,4,3,5,0,0,0,0,0,4,5,3,1,0,0,0,0,0,4,5,2,0,0,5,3,4,6,6,6,4 +// Minstrel (Trans 2nd to 3rd) +4075,0,0,3,0,5,0,4,4,0,3,3,0,0,5,5,0,0,1,1,0,0,4,0,1,0,2,2,1,0,0,0,4,0,3,0,5,0,2,0,4,4,0,0,5,3,1,0,0,4,5 +// Wanderer (Trans 2nd to 3rd) +4076,5,4,4,2,0,0,2,5,4,0,0,3,3,3,0,0,5,2,0,0,4,3,5,0,0,1,1,0,0,5,2,3,0,0,0,4,4,4,2,0,0,0,2,5,2,0,0,0,4,2 +// Sura (Trans 2nd to 3rd) +4077,2,5,0,1,1,0,0,0,1,2,5,0,0,3,3,1,0,0,3,1,0,0,2,2,5,0,0,4,4,1,3,0,0,0,2,5,5,0,0,0,4,3,2,2,0,0,0,4,5,5 +// Genetic (Trans 2nd to 3rd) +4078,4,4,5,0,0,5,4,2,0,0,0,4,5,0,0,0,0,3,5,2,0,0,4,3,3,0,0,5,2,0,6,0,0,0,4,4,1,0,5,2,4,0,0,4,4,0,2,0,0,4 +// Shadow Chaser (Trans 2nd to 3rd) +4079,6,1,0,0,1,0,6,2,5,4,0,0,4,6,0,0,2,0,3,3,4,5,0,0,3,6,0,0,3,0,1,1,3,6,0,0,4,4,0,0,0,3,3,1,1,0,0,5,2,0 +// Rune Knight Mount (Base 2nd to 3rd) +4080,4,4,5,3,4,0,0,0,0,1,1,4,4,3,5,0,0,0,5,2,2,4,3,5,0,0,0,0,0,4,5,3,1,0,0,0,0,0,4,5,2,0,0,5,3,4,6,6,6,4 +// Rune Knight Mount (Trans 2nd to 3rd) +4081,4,4,5,3,4,0,0,0,0,1,1,4,4,3,5,0,0,0,5,2,2,4,3,5,0,0,0,0,0,4,5,3,1,0,0,0,0,0,4,5,2,0,0,5,3,4,6,6,6,4 +// Royal Guard Mount (Base 2nd to 3rd) +4082,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +// Royal Guard Mount (Trans 2nd to 3rd) +4083,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +// Ranger Mount (Base 2nd to 3rd) +4084,5,4,4,2,0,0,2,5,4,0,0,3,3,3,0,0,5,2,0,0,4,3,5,0,0,1,1,0,0,5,2,3,0,0,0,4,4,4,2,0,0,0,2,5,2,0,0,0,4,2 +// Ranger Mount (Trans 2nd to 3rd) +4085,5,4,4,2,0,0,2,5,4,0,0,3,3,3,0,0,5,2,0,0,4,3,5,0,0,1,1,0,0,5,2,3,0,0,0,4,4,4,2,0,0,0,2,5,2,0,0,0,4,2 +// Mechanic Mount (Base 2nd to 3rd) +4086,6,1,0,0,1,0,6,2,5,4,0,0,4,6,0,0,2,0,3,3,4,5,0,0,3,6,0,0,3,0,1,1,3,6,0,0,4,4,0,0,0,3,3,1,1,0,0,5,2,0 +// Mechanic Mount (Trans 2nd to 3rd) +4087,6,1,0,0,1,0,6,2,5,4,0,0,4,6,0,0,2,0,3,3,4,5,0,0,3,6,0,0,3,0,1,1,3,6,0,0,4,4,0,0,0,3,3,1,1,0,0,5,2,0 diff --git a/db/magicmushroom_db.txt b/db/magicmushroom_db.txt new file mode 100644 index 000000000..9be7f9dff --- /dev/null +++ b/db/magicmushroom_db.txt @@ -0,0 +1,26 @@ +// Magic Mushroom DB. +// Database for skills that are randomly used trough Magic Mushroom status change. +// Format: SkillID + +7 //SM_MAGNUM +8 //SM_ENDURE +10 //MG_SIGHT +24 //AL_RUWACH +32 //AL_CRUCIS +33 //AL_ANGELUS +45 //AC_CONCENTRATION +61 //KN_AUTOCOUNTER +74 //PR_MAGNIFICAT +110 //BS_HAMMERFALL +114 //BS_MAXIMIZE +142 //NV_FIRSTAID +150 //TF_BACKSLIDING +151 //TF_PICKSTONE +157 //MG_ENERGYCOAT +249 //CR_AUTOGUARD +261 //MO_CALLSPIRITS +256 //CR_PROVIDENCE +318 //BA_FROSTJOKER +500 //GS_GLITTERING +527 //NJ_TATAMIGAESHI +531 //NJ_UTSUSEMI \ No newline at end of file diff --git a/db/mob_db.txt b/db/mob_db.txt index f49eae46c..67b2b072b 100644 --- a/db/mob_db.txt +++ b/db/mob_db.txt @@ -1095,11 +1095,15 @@ //2039,EXECUTIONER_R,Executioner,Executioner,65,28980,0,0,0,2,570,950,35,35,64,85,40,25,88,60,10,12,2,0,47,0x120,200,768,500,384,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 //2040,TIRFING_R,Tirfing,Ogretooth,71,29900,0,0,0,1,950,1146,30,35,58,87,55,35,132,65,10,12,1,0,67,0x120,100,816,500,240,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 //2041,MYSTELTAINN_R,Mysteltainn,Mysteltainn,76,33350,0,0,0,2,1160,1440,30,30,77,139,80,35,159,65,10,12,2,0,87,0x120,250,1152,500,240,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 -//2042,SILVERSNIPER,Silver Sniper,Silver Sniper,1,50,0,0,0,1,7,10,0,5,1,1,1,1,6,30,10,12,1,3,21,0x120,400,1872,672,480,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 -//2043,MAGICDECOY_FIRE,Magic Decoy,Magic Decoy,1,50,0,0,0,1,7,10,0,5,1,1,1,1,6,30,10,12,1,3,21,0x120,400,1872,672,480,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 -//2044,MAGICDECOY_WATER,Magic Decoy,Magic Decoy,1,50,0,0,0,1,7,10,0,5,1,1,1,1,6,30,10,12,1,3,21,0x120,400,1872,672,480,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 -//2045,MAGICDECOY_EARTH,Magic Decoy,Magic Decoy,1,50,0,0,0,1,7,10,0,5,1,1,1,1,6,30,10,12,1,3,21,0x120,400,1872,672,480,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 -//2046,MAGICDECOY_WIND,Magic Decoy,Magic Decoy,1,50,0,0,0,1,7,10,0,5,1,1,1,1,6,30,10,12,1,3,21,0x120,400,1872,672,480,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 + +//**** +// NC Mechanic Summons +2042,SILVERSNIPER,Silver Sniper,Silver Sniper,100,4500,0,0,0,9,300,300,80,10,10,60,10,10,100,10,10,12,1,0,20,0x3394,2000,504,1020,360,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 +2043,MAGICDECOY_FIRE,Magic Decoy Fire,Magic Decoy Fire,100,2500,0,0,0,7,150,150,16,60,10,10,10,100,50,10,10,12,1,0,23,0x3394,2000,504,1020,360,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 +2044,MAGICDECOY_WATER,Magic Decoy Water,Magic Decoy Water,100,2500,0,0,0,7,150,150,16,60,10,10,10,100,50,10,10,12,1,0,21,0x3394,2000,504,1020,360,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 +2045,MAGICDECOY_EARTH,Magic Decoy Earth,Magic Decoy Earth,100,2500,0,0,0,7,150,150,16,60,10,10,10,100,50,10,10,12,1,0,22,0x3394,2000,504,1020,360,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 +2046,MAGICDECOY_WIND,Magic Decoy Wind,Magic Decoy Wind,100,2500,0,0,0,7,150,150,16,60,10,10,10,100,50,10,10,12,1,0,24,0x3394,2000,504,1020,360,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 + //2047,W_NAGA,Naga,Naga,1,50,0,0,0,1,7,10,0,5,1,1,1,1,6,30,10,12,1,3,21,0x120,400,1872,672,480,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 //2048,W_PINGUICULA_D,Dark Pinguicula,Dark Pinguicula,1,50,0,0,0,1,7,10,0,5,1,1,1,1,6,30,10,12,1,3,21,0x120,400,1872,672,480,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 //2049,W_BRADIUM_GOLEM,Bradium Golem,Bradium Golem,1,50,0,0,0,1,7,10,0,5,1,1,1,1,6,30,10,12,1,3,21,0x120,400,1872,672,480,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 diff --git a/db/mob_skill_db.txt b/db/mob_skill_db.txt index c0dacc9c3..d1e801739 100644 --- a/db/mob_skill_db.txt +++ b/db/mob_skill_db.txt @@ -5781,3 +5781,28 @@ 2082,Piranha@MG_COLDBOLT,chase,14,3,500,1000,5000,yes,target,always,0,,,,,,, 2082,Piranha@WZ_WATERBALL,attack,86,3,500,1000,5000,yes,target,always,0,,,,,,6, 2082,Piranha@NPC_BLOODDRAIN,attack,199,1,500,0,5000,yes,target,always,0,,,,,,, +//**** +// NC Mechanic Summons +2042,Silver Sniper@AL_HEAL,chase,28,10,10000,0,1000,no,self,myhpltmaxrate,99,,,,,,, +2042,Silver Sniper@AL_HEAL,idle,28,10,10000,0,1000,no,self,myhpltmaxrate,99,,,,,,, +2042,Silver Sniper@AL_HEAL,attack,28,10,10000,0,1000,no,self,myhpltmaxrate,99,,,,,,, +2043,Magic Decoy Fire@MG_FIREBOLT,attack,19,10,10000,800,3500,no,target,always,0,,,,,,, +2043,Magic Decoy Fire@MG_FIREBOLT,chase,19,10,10000,800,3500,no,target,always,0,,,,,,, +2043,Magic Decoy Fire@AL_HEAL,chase,28,10,10000,0,1000,no,self,myhpltmaxrate,99,,,,,,, +2043,Magic Decoy Fire@AL_HEAL,idle,28,10,10000,0,1000,no,self,myhpltmaxrate,99,,,,,,, +2043,Magic Decoy Fire@AL_HEAL,attack,28,10,10000,0,1000,no,self,myhpltmaxrate,99,,,,,,, +2044,Magic Decoy Water@MG_COLDBOLT,attack,14,10,10000,800,3500,no,target,always,0,,,,,,, +2044,Magic Decoy Water@MG_COLDBOLT,chase,14,10,10000,800,3500,no,target,always,0,,,,,,, +2044,Magic Decoy Water@AL_HEAL,chase,28,10,10000,0,1000,no,self,myhpltmaxrate,99,,,,,,, +2044,Magic Decoy Water@AL_HEAL,idle,28,10,10000,0,1000,no,self,myhpltmaxrate,99,,,,,,, +2044,Magic Decoy Water@AL_HEAL,attack,28,10,10000,0,1000,no,self,myhpltmaxrate,99,,,,,,, +2045,Magic Decoy Earth@WZ_EARTHSPIKE,attack,90,10,10000,800,3500,no,target,always,0,,,,,,, +2045,Magic Decoy Earth@WZ_EARTHSPIKE,chase,90,10,10000,800,3500,no,target,always,0,,,,,,, +2045,Magic Decoy Earth@AL_HEAL,chase,28,10,10000,0,1000,no,self,myhpltmaxrate,99,,,,,,, +2045,Magic Decoy Earth@AL_HEAL,idle,28,10,10000,0,1000,no,self,myhpltmaxrate,99,,,,,,, +2045,Magic Decoy Earth@AL_HEAL,attack,28,10,10000,0,1000,no,self,myhpltmaxrate,99,,,,,,, +2046,Magic Decoy Wind@MG_LIGHTNINGBOLT,attack,20,10,10000,800,3500,no,target,always,0,,,,,,, +2046,Magic Decoy Wind@MG_LIGHTNINGBOLT,chase,20,10,10000,800,3500,no,target,always,0,,,,,,, +2046,Magic Decoy Wind@AL_HEAL,chase,28,10,10000,0,1000,no,self,myhpltmaxrate,99,,,,,,, +2046,Magic Decoy Wind@AL_HEAL,idle,28,10,10000,0,1000,no,self,myhpltmaxrate,99,,,,,,, +2046,Magic Decoy Wind@AL_HEAL,attack,28,10,10000,0,1000,no,self,myhpltmaxrate,99,,,,,,, diff --git a/db/packet_db.txt b/db/packet_db.txt index f423d1c14..a9517e0c0 100644 --- a/db/packet_db.txt +++ b/db/packet_db.txt @@ -33,8 +33,8 @@ // Main packet version of the DB to use (default = max available version) // Client detection is faster when all clients use this version. // Version 23 is the latest Sakexe (above versions are for Renewal clients) -packet_db_ver: 23 -//packet_db_ver: default +//packet_db_ver: 23 +packet_db_ver: default packet_ver: 5 diff --git a/db/produce_db.txt b/db/produce_db.txt index 938bdeb7d..78252447c 100644 --- a/db/produce_db.txt +++ b/db/produce_db.txt @@ -395,3 +395,50 @@ 12117,23,1007,1,7433,1,1013,3 //============================================== + +//===== Ancilla And Runes === ItemLV=24 ======== +//---- Ancilla --------------------------------- +//-- Ancilla <-- AB_ANCILLA & 1 Blue Gemstone +12333,24,2039,1,717,1 + +//---- Rune Stones ----------------------------- +//-- Runstone Nosiege <-- RK_RUNEMASTERY Lv8, 1 Broken Armor Piece, 1 Old Magic Circle, 1 Light Granule, 1 Elder Branch +12725,24,2010,8,7069,1,7099,1,7938,1,7939,1 +//-- Runstone Rhydo <-- RK_RUNEMASTERY Lv7, 1 Red Gemstone, 1 Light Granule, 1 Elder Branch +12726,24,2010,7,716,1,7938,1,7939,1 +//-- Runstone Verkana <-- RK_RUNEMASTERY Lv9, 1 Dullahan Armor, 1 Elder Branch +12727,24,2010,9,7210,1,7939,1 +//-- Runstone Isia <-- RK_RUNEMASTERY Lv2, 1 Burning Heart, 1 Elder Branch +12728,24,2010,2,7097,1,7939,1 +//-- Runstone Asir <-- RK_RUNEMASTERY Lv5, 1 Ogre Tooth, 1 Light Granule, 1 Elder Branch +12729,24,2010,5,7002,1,7938,1,7939,1 +//-- Runstone Urj <-- RK_RUNEMASTERY Lv6, 1 Honey, 1 Slender Snake, 1 Elder Branch +12730,24,2010,6,518,1,1048,1,7939,1 +//-- Runstone Turisus <-- RK_RUNEMASTERY Lv1, 1 Cobold Hair, 1 Claw Of Desert Wolf, 1 Elder Branch +12731,24,2010,1,1034,1,7030,1,7939,1 +//-- Runstone Pertz <-- RK_RUNEMASTERY Lv3, 1 Dragon Canine, 1 Tangled Chain, 1 Light Granule, 1 Elder Branch +12732,24,2010,3,1035,1,7221,1,7938,1,7939,1 +//-- Runstone Hagalas <-- RK_RUNEMASTERY Lv4, 1 Round Shell, 1 Dragon's Skin, 1 Elder Branch +12733,24,2010,4,1096,1,7123,1,7939,1 +//============================================== + +//===== Guillotine Cross Poisons === ItemLv=25 = +//-- Guillotine Antidote <-- GC_RESEARCHNEWPOISON Lv5, 1 White Herb, 1 Blue Herb, 2 Green Herb +6128,25,2024,5,509,1,510,1,511,2 +//-- Poison Paralysis <-- GC_RESEARCHNEWPOISON Lv1, 1 Medicine Bowl, 20 Poison Toad's Skin, 1 Poison Kit, 1 Poison Herb Amoena +12717,25,2024,1,7134,1,7155,20,7931,1,7937,1 +//-- Poison Leech <-- GC_RESEARCHNEWPOISON Lv4, 1 Medicine Bowl, 1 Poison Kit, 1 Poison Herb Nerium, 1 Poison Herb Scopolia +12718,25,2024,4,7134,1,7931,1,7932,1,7936,1 +//-- Poison Oblivion <-- GC_RESEARCHNEWPOISON Lv9, 1 Izidor, 10 Heart Of Mermaid, 1 Medicine Bowl, 1 Poison Kit +12719,25,2024,9,709,1,950,10,7134,1,7931,1 +//-- Poison Contamination <-- GC_RESEARCHNEWPOISON Lv3, 25 Decayed Nail, 1 Medicine Bowl, 1 Poison Kit, 1 Poison Herb Seratum +12720,25,2024,3,957,25,7134,1,7931,1,7935,1 +//-- Poison Numb <-- GC_RESEARCHNEWPOISON Lv8, 1 Medicine Bowl, 10 Sticky Poison, 1 Poison Kit, 1 Poison Herb Nerium +12721,25,2024,8,7134,1,7565,10,7931,1,7932,1 +//-- Poison Fever <-- GC_RESEARCHNEWPOISON Lv2, 20 Anolian Skin, 1 Medicine Bowl, 1 Poison Kit, 1 Poison Herb Rantana +12722,25,2024,2,7003,20,7134,1,7931,1,7933,1 +//-- Poison Laughing <-- GC_RESEARCHNEWPOISON Lv7, 10 Poison Spore, 1 Medicine Bowl, 1 Poison Kit, 1 Poison Herb Makulata +12723,25,2024,7,7033,10,7134,1,7931,1,7934,1 +//-- Poison Fatigue <-- GC_RESEARCHNEWPOISON Lv6, 1 Izidor, 1 Medicine Bowl, 10 Sticky Poison, 1 Poison Kit +12724,25,2024,6,709,1,7134,1,7565,10,7931,1 +//============================================== diff --git a/db/quest_db.txt b/db/quest_db.txt index 000e7f1de..6932de5dd 100644 --- a/db/quest_db.txt +++ b/db/quest_db.txt @@ -1161,24 +1161,24 @@ 11114,0,1004,10,0,0,0,0,"Request : Hunt Honet" 11115,0,1009,20,0,0,0,0,"Request : Hunt Condor" -11116,0,1052,10,0,0,0,0,"Request : Hunt grasshopper's leg" +11116,0,1052,10,0,0,0,0,"Request : Hunt Grasshopper's Leg" 11117,0,1024,20,0,0,0,0,"Request : Hunt Worm tail" 11118,0,1014,30,0,0,0,0,"Request : Hunt Spore" -11119,0,1048,20,0,0,0,0,"Request : Pest control" +11119,0,1048,20,0,0,0,0,"Request : Pest Control" 11120,0,1055,20,0,0,0,0,"Request : Hunt Muka" 11121,0,1005,20,0,0,0,0,"Request : Hunt Farmiliar" -11122,0,1019,30,0,0,0,0,"Request : Collect feather" -11123,0,1077,30,0,0,0,0,"Request : Collect Poison spore" -11124,86400,0,0,0,0,0,0,"Request : Hunt honet - Complete" -11125,86400,0,0,0,0,0,0,"Request : Hunt condor - Complete" -11126,86400,0,0,0,0,0,0,"Request : Hunt grasshopper's leg - Complete" -11127,86400,0,0,0,0,0,0,"Request : Hunt Worm tail - Complete" -11128,86400,0,0,0,0,0,0,"Request : Hunt spore - Complete" -11129,86400,0,0,0,0,0,0,"Request : Pest control - Complete" -11130,86400,0,0,0,0,0,0,"Request : Hunt muka - Complete" +11122,0,1019,30,0,0,0,0,"Request : Collect Feather" +11123,0,1077,30,0,0,0,0,"Request : Collect Poison Spore" +11124,86400,0,0,0,0,0,0,"Request : Hunt Honet - Complete" +11125,86400,0,0,0,0,0,0,"Request : Hunt Condor - Complete" +11126,86400,0,0,0,0,0,0,"Request : Hunt Grasshopper's Leg - Complete" +11127,86400,0,0,0,0,0,0,"Request : Hunt Worm Tail - Complete" +11128,86400,0,0,0,0,0,0,"Request : Hunt Spore - Complete" +11129,86400,0,0,0,0,0,0,"Request : Pest Control - Complete" +11130,86400,0,0,0,0,0,0,"Request : Hunt Muka - Complete" 11131,86400,0,0,0,0,0,0,"Request : Hunt Farmiliar - Complete" -11132,86400,0,0,0,0,0,0,"Request : Collect feather - Complete" -11133,86400,0,0,0,0,0,0,"Request : Collect Poison spore - Complete" +11132,86400,0,0,0,0,0,0,"Request : Collect Feather - Complete" +11133,86400,0,0,0,0,0,0,"Request : Collect Poison Spore - Complete" 11135,0,0,0,0,0,0,0,"Looking for Maestro Song" 11136,0,0,0,0,0,0,0,"Looking for Maestro Song" diff --git a/db/re_job_db.txt b/db/re_job_db.txt new file mode 100644 index 000000000..d062c8587 --- /dev/null +++ b/db/re_job_db.txt @@ -0,0 +1,230 @@ +// Job-specific values database, +// Used for Renewal-exclusive values, such as the shield ASPD penalty +// Job ID, Shield ASPD Penalty (value / 10) + +//Novice +0,100 +//Swordman +1,50 +//Mage +2,50 +//Archer +3,50 +//Acolyte +4,50 +//Merchant +5,50 +//Thief +6,60 +//Knight +7,50 +//Priest +8,50 +//Wizard +9,50 +//Blacksmith +10,50 +//Hunter +11,90 +//Assassin +12,60 +//Knight2 +13,50 +//Crusader +14,50 +//Monk +15,50 +//Sage +16,50 +//Rogue +17,50 +//Alchem +18,50 +//Alchemist +18,50 +//Bard +19,70 +//Dancer +20,70 +//Crusader2 +21,50 +//Wedding +22,50 +//SuperNovice +23,50 +//Gunslinger +24,60 +//Ninja +25,60 +//Xmas +26,50 +//Summer +27,50 +//NoviceHigh +4001,100 +//SwordmanHigh +4002,50 +//MageHigh +4003,50 +//ArcherHigh +4004,50 +//AcolyteHigh +4005,50 +//MerchantHigh +4006,50 +//ThiefHigh +4007,60 +//LordKnight +4008,50 +//HighPriest +4009,50 +//HighWizard +4010,50 +//Whitesmith +4011,50 +//Sniper +4012,90 +//AssassinCross +4013,60 +//LordKnight2 +4014,50 +//Paladin +4015,50 +//Champion +4016,50 +//Professor +4017,50 +//Stalker +4018,50 +//Creator +4019,50 +//Clown +4020,70 +//Gypsy +4021,70 +//Paladin2 +4022,50 +//Baby +4023,100 +//BabySwordman +4024,50 +//BabyMage +4025,50 +//BabyArcher +4026,50 +//BabyAcolyte +4027,50 +//BabyMerchant +4028,50 +//BabyThief +4029,60 +//BabyKnight +4030,50 +//BabyPriest +4031,50 +//BabyWizard +4032,50 +//BabyBlacksmith +4033,50 +//BabyHunter +4034,90 +//BabyAssassin +4035,60 +//BabyKnight2 +4036,50 +//BabyCrusader +4037,50 +//BabyMonk +4038,50 +//BabySage +4039,50 +//BabyRogue +4040,50 +//BabyAlchem +4041,50 +//BabyAlchemist +4041,50 +//BabyBard +4042,70 +//BabyDancer +4043,70 +//BabyCrusader2 +4044,50 +//SuperBaby +4045,50 +//Taekwon +4046,50 +//StarGladiator +4047,50 +//StarGladiator2 +4048,50 +//SoulLinker +4049,80 +//RuneKnight +4054,50 +//Warlock +4055,50 +//Ranger +4056,80 +//ArchBishop +4057,100 +//Mechanic +4058,60 +//GuillotineCross +4059,90 +//RuneKnightT +4060,50 +//WarlockT +4061,50 +//RangerT +4062,80 +//ArchBishopT +4063,100 +//MechanicT +4064,60 +//GuillotineCrossT +4065,90 +//RoyalGuard +4066,50 +//Sorcerer +4067,50 +//Minstrel +4068,70 +//Wanderer +4069,70 +//Sura +4070,50 +//Genetic +4071,50 +//ShadowChaser +4072,40 +//RoyalGuardT +4073,50 +//SorcererT +4074,50 +//MinstrelT +4075,50 +//WandererT +4076,50 +//SuraT +4077,50 +//GeneticT +4078,50 +//ShadowChaserT +4079,40 +//RuneKnight2 +4080,50 +//RuneKnightT2 +4081,50 +//RoyalGuard2 +4082,50 +//RoyalGuardT2 +4083,50 +//Ranger2 +4084,50 +//RangerT2 +4085,50 +//Mechanic2 +4086,50 +//MechanicT2 +4087,50 \ No newline at end of file diff --git a/db/skill_cast_db.txt b/db/skill_cast_db.txt index 7ded81500..05e44e02b 100644 --- a/db/skill_cast_db.txt +++ b/db/skill_cast_db.txt @@ -1,1137 +1,1860 @@ // Skill Times Database // // Structure of Database: -// SkillID,CastingTime,AfterCastActDelay,AfterCastWalkDelay,Duration1,Duration2 -// -//========================================== -// Rough list of Contents: -//========================================== -// 1. 1st Jobs Skills -// 2. 2-1 Jobs Skills -// 3. 1st Jobs Quest Skills -// 4. NPC Skills (1) -// 5. 2-2 Jobs Skills -// 6. Wedding Skills -// 7. NPC Skills (2) -// 8. Advanced Jobs Skills (1) -// 9. Adoption Skills -// 10. Taekwon Jobs Skills (1) -// 11. Advanced Jobs Skills (2) -// 12. Taekwon Jobs Skills (2) -// 13. 2nd Jobs Quest Skills -// 14. Homunculus Skills -// 15. Mercenary Skills -// 16. Guild Skills -//========================================== -// This is just a rough overview to help -// giving an overview on the document and -// help navigating through it. (Vedurin) +// SkillID,CastingTime,AfterCastActDelay,AfterCastWalkDelay,Duration1,Duration2,Cool Down +//== Explained: +// CastingTime : time to cast this skill, in miliseconds +// AfterCastActDelay : "normal" delay, character cannot use skills, in miliseconds +// AfterCastWalkDleay : amount of time before character can move again, in miliseconds +// Duration1 / Duration2 : usually the durations used by the skill, at special cases it is used to hold special data +// Cool Down : amount of time until character can re-use this skill, in miliseconds +//== Extra +// On all fields you can use ':' as a delimiter to level-specific values, +// - Example using SM_PROVOKE +// - Original:6,0,0,0,30000,0,1000 +// - ModifiedTo:6,0,0,0,30000,0,1000:2500:3000:etc +// - Makes lvl 1 have 1000 (1s) cool down, lvl 2 2500 (2.5s), lvl 3 3000, and so on. //========================================== - - - //===== Swordman =========================== //-- SM_PROVOKE -6,0,0,0,30000,0 +6,0,0,0,30000,0,1000 //-- SM_MAGNUM -7,0,0,0,2000,10000 +7,0,0,0,2000,10000,2000 //-- SM_ENDURE -8,0,0,0,10000:13000:16000:19000:22000:25000:28000:31000:34000:37000,10000 +8,0,0,0,10000:13000:16000:19000:22000:25000:28000:31000:34000:37000,10000,10000 //========================================== //===== Mage =============================== //-- MG_SIGHT -10,0,0,0,10000,0 +10,0,0,0,10000,0,0 //-- MG_NAPALMBEAT -11,1000,1000:1000:1000:900:900:800:800:700:600:500,0,0,0 +11,1000,1000:1000:1000:900:900:800:800:700:600:500,0,0,0,0 //-- MG_SAFETYWALL -12,4000:3500:3500:2500:2000:1500:1000:1000:1000:1000,0,0,5000:10000:15000:20000:25000:30000:35000:40000:45000:50000,0 +12,4000:3500:3500:2500:2000:1500:1000:1000:1000:1000,0,0,5000:10000:15000:20000:25000:30000:35000:40000:45000:50000,0,0 //-- MG_SOULSTRIKE -13,500,1200:1000:1400:1200:1600:1400:1800:1600:2000:1800,0,0,0 +13,500,1200:1000:1400:1200:1600:1400:1800:1600:2000:1800,0,0,0,0 //-- MG_COLDBOLT -14,700:1400:2100:2800:3500:4200:4900:5600:6300:7000,1000:1200:1400:1600:1800:2000:2200:2400:2600:2800,0,0,0 +14,700:1400:2100:2800:3500:4200:4900:5600:6300:7000,1000:1200:1400:1600:1800:2000:2200:2400:2600:2800,0,0,0,0 //-- MG_FROSTDRIVER -15,800,1500,0,0,3000:6000:9000:12000:15000:18000:21000:24000:27000:30000 +15,800,1500,0,0,3000:6000:9000:12000:15000:18000:21000:24000:27000:30000,0 //-- MG_STONECURSE -16,1000,0,0,5000,20000 +16,1000,0,0,5000,20000,0 //-- MG_FIREBALL -17,1500:1500:1500:1500:1500:1000:1000:1000:1000:1000,1500:1500:1500:1500:1500:1000:1000:1000:1000:1000,0,0,0 +17,1500:1500:1500:1500:1500:1000:1000:1000:1000:1000,1500:1500:1500:1500:1500:1000:1000:1000:1000:1000,0,0,0,0 //-- MG_FIREWALL -18,2000:1850:1700:1550:1400:1250:1100:950:800:650,0,0,5000:6000:7000:8000:9000:10000:11000:12000:13000:14000,0 +18,2000:1850:1700:1550:1400:1250:1100:950:800:650,0,0,5000:6000:7000:8000:9000:10000:11000:12000:13000:14000,0,0 //-- MG_FIREBOLT -19,700:1400:2100:2800:3500:4200:4900:5600:6300:7000,1000:1200:1400:1600:1800:2000:2200:2400:2600:2800,0,0,0 +19,700:1400:2100:2800:3500:4200:4900:5600:6300:7000,1000:1200:1400:1600:1800:2000:2200:2400:2600:2800,0,0,0,0 //-- MG_LIGHTNINGBOLT -20,700:1400:2100:2800:3500:4200:4900:5600:6300:7000,1000:1200:1400:1600:1800:2000:2200:2400:2600:2800,0,0,0 +20,700:1400:2100:2800:3500:4200:4900:5600:6300:7000,1000:1200:1400:1600:1800:2000:2200:2400:2600:2800,0,0,0,0 //-- MG_THUNDERSTORM -21,1000:2000:3000:4000:5000:6000:7000:8000:9000:10000,2000,0,500,0 +21,1000:2000:3000:4000:5000:6000:7000:8000:9000:10000,2000,0,500,0,0 //========================================== //===== Acolyte ============================ //-- AL_RUWACH -24,0,0,0,10000,0 +24,0,0,0,10000,0,0 //-- AL_PNEUMA -25,0,0,0,10000,0 +25,0,0,0,10000,0,0 //-- AL_TELEPORT -26,0,0,0,0,0 +26,0,0,0,0,0,0 //-- AL_WARP -27,1000,0,0,5000:10000:15000:20000:25000:30000:35000:40000:45000:50000,0 +27,1000,0,0,5000:10000:15000:20000:25000:30000:35000:40000:45000:50000,0,0 //-- AL_HEAL -28,0,1000,0,0,0 +28,0,1000,0,0,0,0 //-- AL_INCAGI -29,1000,1000,0,60000:80000:100000:120000:140000:160000:180000:200000:220000:240000,0 +29,1000,1000,0,60000:80000:100000:120000:140000:160000:180000:200000:220000:240000,0,0 //-- AL_DECAGI -30,1000,1000,0,40000:50000:60000:70000:80000:90000:100000:110000:120000:130000,0 +30,1000,1000,0,40000:50000:60000:70000:80000:90000:100000:110000:120000:130000,0,0 //-- AL_HOLYWATER -31,1000,500,0,0,0 +31,1000,500,0,0,0,0 //-- AL_CRUCIS -32,500,2000,0,60000,0 +32,500,2000,0,0,0,0 //-- AL ANGELUS -33,500,3500,0,30000:60000:90000:120000:150000:180000:210000:240000:270000:300000,0 +33,500,3500,0,30000:60000:90000:120000:150000:180000:210000:240000:270000:300000,0,0 //-- AL_BLESSING -34,0,0,0,60000:80000:100000:120000:140000:160000:180000:200000:220000:240000,0 +34,0,0,0,60000:80000:100000:120000:140000:160000:180000:200000:220000:240000,0,0 //-- AL_CURE -35,0,1000,0,0,6000 +35,0,1000,0,0,6000,0 //========================================== //===== Archer ============================= //-- AC_CONCENTRATION -45,0,0,0,60000:80000:100000:120000:140000:160000:180000:200000:220000:240000,0 +45,0,0,0,60000:80000:100000:120000:140000:160000:180000:200000:220000:240000,0,0 //-- AC_DOUBLE -46,0,0,0,100,0 +46,0,0,0,100,0,0 //-- AC_SHOWER -47,0,0,0,100,0 +47,0,0,0,100,0,0 //========================================== //===== Thief ============================== //-- TF_HIDING -51,0,0,0,30000:60000:90000:120000:150000:180000:210000:240000:270000:300000,0 +51,0,0,0,30000:60000:90000:120000:150000:180000:210000:240000:270000:300000,0,0 //-- TF_POISON -52,0,0,0,0,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000 +52,0,0,0,0,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000,0 //========================================== //===== First planned to be shared ========= //-- ALL_RESURRECTION -54,6000:4000:2000:0,0:1000:2000:3000,0,0,0 +54,6000:4000:2000:0,0:1000:2000:3000,0,0,0,0 //========================================== //===== Knight ============================= //-- KN_BRANDISHSPEAR -57,700,0,0,0,0 +57,700,0,0,0,0,0 //-- KN_SPEARBOOMERANG -59,0,1000,0,0,0 +59,0,1000,0,0,0,0 //-- KN_TWOHANDQUICKEN -60,0,0,0,30000:60000:90000:120000:150000:180000:210000:240000:270000:300000,0 +60,0,0,0,30000:60000:90000:120000:150000:180000:210000:240000:270000:300000,0,0 //-- KN_AUTOCOUNTER -61,0,0,0,400:800:1200:1600:2000,0 +61,0,0,0,400:800:1200:1600:2000,0,0 //-- KN_BOWLINGBASH -62,700,0,0,0,0 +62,700,0,0,0,0,0 //========================================== //===== Priest ============================= //-- PR_IMPOSITIO -66,0,3000,0,60000,0 +66,0,3000,0,60000,0,0 //-- PR_SUFFRAGIUM -67,0,2000,0,30000:20000:10000,0 +67,0,2000,0,30000:20000:10000,0,0 //-- PR_ASPERSIO -68,0,2000,0,60000:90000:120000:150000:180000,0 +68,0,2000,0,60000:90000:120000:150000:180000,0,0 //-- PR_BENEDICTIO -69,0,0,0,40000:80000:120000:160000:200000,0 +69,0,0,0,40000:80000:120000:160000:200000,0,0 //-- PR_SANCTUARY -70,5000,0,0,4000:7000:10000:13000:16000:19000:22000:25000:28000:31000,0 +70,5000,0,0,4000:7000:10000:13000:16000:19000:22000:25000:28000:31000,0,0 //-- PR_SLOWPOISON -71,0,0,0,10000:20000:30000:40000,0 +71,0,0,0,10000:20000:30000:40000,0,0 //-- PR_STRECOVERY -72,0,2000,0,0,30000 +72,0,2000,0,0,30000,0 //-- PR_KYRIE -73,2000,2000,0,120000,0 +73,2000,2000,0,120000,0,0 //-- PR_MAGNIFICAT -74,4000,2000,0,30000:45000:60000:75000:90000,0 +74,4000,2000,0,30000:45000:60000:75000:90000,0,0 //-- PR_GLORIA -75,0,2000,0,10000:15000:20000:25000:30000,0 +75,0,2000,0,10000:15000:20000:25000:30000,0,0 //-- PR_LEXDIVINA -76,0,3000,0,30000:35000:40000:45000:50000:60000:60000:60000:60000:60000,0 +76,0,3000,0,30000:35000:40000:45000:50000:60000:60000:60000:60000:60000,0,0 //-- PR_TURNUNDEAD -77,1000,3000,0,0,0 +77,1000,3000,0,0,0,0 //-- PR_LEXAETERNA -78,0,3000,0,600000,0 +78,0,3000,0,600000,0,0 //-- PR_MAGNUS -79,15000,4000,0,5000:6000:7000:8000:9000:10000:11000:12000:13000:14000,0 +79,15000,4000,0,5000:6000:7000:8000:9000:10000:11000:12000:13000:14000,0,0 //========================================== //===== Wizard ============================= //-- WZ_FIREPILLAR -80,3000:2700:2400:2100:1800:1500:1200:900:600:300,1000,0,30000,600:800:1000:1200:1400:1600:1800:2000:2200:2400 +80,3000:2700:2400:2100:1800:1500:1200:900:600:300,1000,0,30000,600:800:1000:1200:1400:1600:1800:2000:2200:2400,0 //-- WZ_SIGHTRASHER -81,700,2000,0,500,0 - +81,700,2000,0,500,0,0 +//-- WZ_FIREIVY +82,5000:4500:4000:3500:3000:2500:2000:1500:1000:500,800,600,5000,5000,0 //-- WZ_METEOR -83,15000,2000:3000:3000:4000:4000:5000:5000:6000:6000:7000,0,500,5000 +83,15000,2000:3000:3000:4000:4000:5000:5000:6000:6000:7000,0,500,5000,0 //-- WZ_JUPITEL -84,2500:3000:3500:4000:4500:5000:5500:6000:6500:7000,0,0,0,0 +84,2500:3000:3500:4000:4500:5000:5500:6000:6500:7000,0,0,0,0,0 //-- WZ_VERMILION -85,15000:14500:14000:13500:13000:12500:12000:11500:11000:10500,5000,0,4000,5500:6000:6500:7000:7500:8000:8500:9000:9500:10000 +85,15000:14500:14000:13500:13000:12500:12000:11500:11000:10500,5000,0,4000,5500:6000:6500:7000:7500:8000:8500:9000:9500:10000,0 //-- WZ_WATERBALL -86,1000:2000:3000:4000:5000:6000:7000:8000:9000:10000,0,0,0,0 +86,1000:2000:3000:4000:5000:6000:7000:8000:9000:10000,0,0,0,0,0 //-- WZ_ICEWALL -87,0,0,0,5000:10000:15000:20000:25000:30000:35000:40000:45000:50000,0 +87,0,0,0,5000:10000:15000:20000:25000:30000:35000:40000:45000:50000,0,0 //-- WZ_FROSTNOVA -88,5000:4700:4400:4100:3800:3500:3200:2900:2700:2500,1000,0,0,1500:3000:4500:6000:7500:9000:10500:12000:13500:15000 +88,5000:4700:4400:4100:3800:3500:3200:2900:2700:2500,1000,0,0,1500:3000:4500:6000:7500:9000:10500:12000:13500:15000,0 //-- WZ_STORMGUST -89,6000:7000:8000:9000:10000:11000:12000:13000:14000:15000,5000,0,4600,12000 +89,6000:7000:8000:9000:10000:11000:12000:13000:14000:15000,5000,0,4600,12000,0 //-- WZ_EARTHSPIKE -90,1000:2000:3000:4000:5000,700,0,0,0 +90,1000:2000:3000:4000:5000,700,0,0,0,0 //-- WZ_HEAVENDRIVE -91,1000:2000:3000:4000:5000,700,0,500,0 +91,1000:2000:3000:4000:5000,700,0,500,0,0 //-- WZ_QUAGMIRE -92,0,1000,0,5000:10000:15000:20000:25000,5000:10000:15000:20000:25000 +92,0,1000,0,5000:10000:15000:20000:25000,5000:10000:15000:20000:25000,0 //========================================== //===== Blacksmith ========================= //-- BS_REPAIRWEAPON -108,7500,0,0,0,0 +108,7500,0,0,0,0,0 //-- BS_HAMMERFALL -110,0,0,0,0,5000 +110,0,0,0,0,5000,0 //-- BS_ADRENALINE -111,0,0,0,30000:60000:90000:120000:150000,0 +111,0,0,0,30000:60000:90000:120000:150000,0,0 //-- BS_WEAPONPEFECT -112,0,0,0,10000:20000:30000:40000:50000,0 +112,0,0,0,10000:20000:30000:40000:50000,0,0 //-- BS_OVERTHRUST -113,0,0,0,20000:40000:60000:80000:100000,0 +113,0,0,0,20000:40000:60000:80000:100000,0,0 //-- BS_MAXIMIZE -114,0,0,0,1000:2000:3000:4000:5000,0 +114,0,0,0,1000:2000:3000:4000:5000,0,0 //========================================== //===== Hunter ============================= //-- HT_SKIDTRAP -115,0,0,0,300000:240000:180000:120000:60000,0 +115,0,0,0,300000:240000:180000:120000:60000,0,0 //-- HT_LANDMINE -116,0,0,0,200000:160000:120000:80000:40000,5000 +116,0,0,0,200000:160000:120000:80000:40000,5000,0 //-- HT_ANKLESNARE -117,0,0,0,250000:200000:150000:100000:50000,4000:8000:12000:16000:20000 +117,0,0,0,250000:200000:150000:100000:50000,4000:8000:12000:16000:20000,0 //-- HT_SHOCKWAVE -118,0,0,0,200000:160000:120000:80000:40000,0 +118,0,0,0,200000:160000:120000:80000:40000,0,0 //-- HT_SANDMAN -119,0,0,0,150000:120000:90000:60000:30000,12000:14000:16000:18000:20000 +119,0,0,0,150000:120000:90000:60000:30000,12000:14000:16000:18000:20000,0 //-- HT_FLASHER -120,0,0,0,150000:120000:90000:60000:30000,10000:11000:12000:13000:14000 +120,0,0,0,150000:120000:90000:60000:30000,10000:11000:12000:13000:14000,0 //-- HT_FREEZINGTRAP -121,0,0,0,150000:120000:90000:60000:30000,3000:6000:9000:12000:15000 +121,0,0,0,150000:120000:90000:60000:30000,3000:6000:9000:12000:15000,0 //-- HT_BLASTMINE -122,0,0,0,25000:20000:15000:10000:5000,0 +122,0,0,0,25000:20000:15000:10000:5000,0,0 //-- HT_CLAYMORETRAP -123,0,0,0,20000:40000:60000:80000:100000,0 +123,0,0,0,20000:40000:60000:80000:100000,0,0 //-- HT_TALKIEBOX -125,0,0,0,600000,0 +125,0,0,0,600000,0,0 //-- HT_BLITZBEAT -129,1500,1000,0,0,0 +129,1500,1000,0,0,0,0 //========================================== //===== Assassin =========================== //-- AS_CLOAKING -135,0,0,0,500:1000:2000:3000:4000:5000:6000:7000:8000:9000,0 +135,0,0,0,500:1000:2000:3000:4000:5000:6000:7000:8000:9000,0,0 //-- AS_SONICBLOW -136,0,2000,2000,0,5000 +136,0,2000,2000,0,5000,0 //-- AS_ENCHANTPOISON -138,0,0,0,30000:45000:60000:75000:90000:105000:120000:135000:150000:165000,10000:20000:30000:40000:50000:60000:70000:80000:90000:100000 +138,0,0,0,30000:45000:60000:75000:90000:105000:120000:135000:150000:165000,10000:20000:30000:40000:50000:60000:70000:80000:90000:100000,0 //-- AS_POISONREACT -139,0,0,0,20000:25000:30000:35000:40000:45000:50000:55000:60000:65000,0 +139,0,0,0,20000:25000:30000:35000:40000:45000:50000:55000:60000:65000,0,0 //-- AS_VENOMDUST -140,0,0,0,5000:10000:15000:20000:25000:30000:35000:40000:45000:50000,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000 +140,0,0,0,5000:10000:15000:20000:25000:30000:35000:40000:45000:50000,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000,0 //-- AS_SPLASHER -141,1000,0,0,5000:5500:6000:6500:7000:7500:8000:8500:9000:9500,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000 +141,1000,0,0,5000:5500:6000:6500:7000:7500:8000:8500:9000:9500,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000,0 //========================================== //===== 1st Jobs Quest Skills=============== //-- NV_TRICKDEAD -143,0,0,0,600000,0 +143,0,0,0,600000,0,0 //-- SM_FATALBLOW -145,0,0,0,0,5000 +145,0,0,0,0,5000,0 //-- AC_CHARGEARROW -148,1500,0,0,0,0 +148,1500,0,0,0,0,0 //-- TF_SPRINKLESAND -149,0,0,0,0,10000 +149,0,0,0,0,10000,0 //-- TF_PICKSTONE -151,500,0,0,0,0 +151,500,0,0,0,0,0 //-- TF_THROWSTONE -152,0,0,0,5000,8000 +152,0,0,0,5000,8000,0 //-- MC_LOUD -155,0,0,0,300000,0 +155,0,0,0,300000,0,0 //-- AL_HOLYLIGHT -156,2000,0,0,0,0 +156,2000,0,0,0,0,0 //-- MG_ENERGYCOAT -157,5000,0,0,300000,0 +157,5000,0,0,300000,0,0 //========================================== //===== NPC Skills Part 1 ================== //-- NPC_ATTRICHANGE -161,0,0,0,1800000,0 +161,0,0,0,1800000,0,0 //-- NPC_CHANGEWATER -162,0,0,0,1800000,0 +162,0,0,0,1800000,0,0 //-- NPC_CHANGEGROUND -163,0,0,0,1800000,0 +163,0,0,0,1800000,0,0 //-- NPC_CHANGEFIRE -164,0,0,0,1800000,0 +164,0,0,0,1800000,0,0 //-- NPC_CHANGEWIND -165,0,0,0,1800000,0 +165,0,0,0,1800000,0,0 //-- NPC_CHANGEPOISON -166,0,0,0,1800000,0 +166,0,0,0,1800000,0,0 //-- NPC_CHANGEHOLY -167,0,0,0,1800000,0 +167,0,0,0,1800000,0,0 //-- NPC_CHANGEDARKNESS -168,0,0,0,1800000,0 +168,0,0,0,1800000,0,0 //-- NPC_CHANGETELEKINESIS -169,0,0,0,1800000,0 +169,0,0,0,1800000,0,0 //-- NPC_SELFDESTRUCTION -173,0,0,0,3500,0 +173,0,0,0,3500,0,0 //-- NPC_POISON -176,0,0,0,0,60000 +176,0,0,0,0,60000,0 //-- NPC_BLINDATTACK -177,0,0,0,0,30000 +177,0,0,0,0,30000,0 //-- NPC_SILENCEATTACK -178,0,0,0,0,30000 -//-- NPC_STUNATTACK -179,0,0,0,0,5000 +178,0,0,0,0,30000,0 +//-- NPC0,_STUNATTACK +179,0,0,0,0,5000,0 //-- NPC_PETRIFYATTACK -180,0,0,0,0,20000 +180,0,0,0,0,20000,0 //-- NPC_CURSEATTACK -181,0,0,0,0,30000 +181,0,0,0,0,30000,0 //-- NPC_SLEEPATTACK -182,0,0,0,0,30000 +182,0,0,0,0,30000,0 //-- NPC_MAGICALATTACK -192,0,0,0,15000,0 +192,0,0,0,15000,0,0 //-- NPC_KEEPING -201,0,0,0,60000:70000:80000:90000:100000:110000:120000:130000:140000:150000,0 +201,0,0,0,60000:70000:80000:90000:100000:110000:120000:130000:140000:150000,0,0 //-- NPC_BARRIER -204,0,0,0,60000:70000:80000:90000:100000:110000:120000:130000:140000:150000,0 +204,0,0,0,60000:70000:80000:90000:100000:110000:120000:130000:140000:150000,0,0 //-- NPC_DEFENDER -205,0,0,0,60000:70000:80000:90000:100000:110000:120000:130000:140000:150000,0 +205,0,0,0,60000:70000:80000:90000:100000:110000:120000:130000:140000:150000,0,0 //-- NPC_LICK -206,0,0,0,0,3000 +206,0,0,0,0,3000,0 //-- NPC_HALLUCINATION -207,0,0,0,30000:40000:50000:60000:70000:80000:90000:100000:110000:120000,0 +207,0,0,0,30000:40000:50000:60000:70000:80000:90000:100000:110000:120000,0,0 //========================================== //===== Rogue ============================== //-- RG_BACKSTAB -212,0,500,0,0,0 +212,0,500,0,0,0,0 //-- RG_RAID -214,0,0,0,5000,8000:9000:10000:11000:12000 +214,0,0,0,5000,8000:9000:10000:11000:12000,0 //-- RG_STRIPEWEAPON -215,1000,1000,0,75000:90000:105000:120000:135000,0 +215,1000,1000,0,75000:90000:105000:120000:135000,0,0 //-- RG_STRIPSHIELD -216,1000,1000,0,75000:90000:105000:120000:135000,0 +216,1000,1000,0,75000:90000:105000:120000:135000,0,0 //-- RG_STRIPWEAPON -217,1000,1000,0,75000:90000:105000:120000:135000,0 +217,1000,1000,0,75000:90000:105000:120000:135000,0,0 //-- RG_STRIPHELM -218,1000,1000,0,75000:90000:105000:120000:135000,0 +218,1000,1000,0,75000:90000:105000:120000:135000,0,0 //-- RG_GRAFITTI -220,0,0,0,180000,0 +220,0,0,0,180000,0,0 //========================================== //===== Alchemist ========================== //-- AM_DEMONSTRATION -229,1000,0,0,40000:45000:50000:55000:60000,0 +229,1000,0,0,40000:45000:50000:55000:60000,0,0 //-- AM_ACIDTERROR -230,1000,0,0,3:7:10:12:13,120000 +230,1000,0,0,3:7:10:12:13,120000,0 //-- AM_POTIONPITCHER -231,0,500,0,0,0 +231,0,500,0,0,0,0 //-- AM_CANNIBALIZE -232,2000,500,0,300000:240000:180000:120000:60000,0 +232,2000,500,0,300000:240000:180000:120000:60000,0,0 //-- AM_SPHEREMINE -233,2000,500,0,30000,0 +233,2000,500,0,30000,0,0 //-- AM_CP_WEAPON -234,2000,0,0,120000:240000:360000:480000:600000,0 +234,2000,0,0,120000:240000:360000:480000:600000,0,0 //-- AM_CP_SHIELD -235,2000,0,0,120000:240000:360000:480000:600000,0 +235,2000,0,0,120000:240000:360000:480000:600000,0,0 //-- AM_CP_ARMOR -236,2000,0,0,120000:240000:360000:480000:600000,0 +236,2000,0,0,120000:240000:360000:480000:600000,0,0 //-- AM_CP_HELM -237,2000,0,0,120000:240000:360000:480000:600000,0 +237,2000,0,0,120000:240000:360000:480000:600000,0,0 //-- AM_RESURRECTHOMUN -247,2000,0,0,0,0 +247,2000,0,0,0,0,0 //========================================== //===== Crusader =========================== //-- CR_AUTOGUARD -249,0,0,0,300000,0 +249,0,0,0,300000,0,0 //-- CR_SHIELDCHARGE -250,0,0,0,0,5000 +250,0,0,0,0,5000,0 //-- CR_SHIELDBOOMERANG -251,0,700,0,0,0 +251,0,700,0,0,0,0 //-- CR_REFLECTSHIELD -252,0,0,0,300000,0 +252,0,0,0,300000,0,0 //-- CR_HOLYCROSS -253,0,0,0,0,10000:11000:12000:13000:14000:15000:16000:17000:18000:19000 +253,0,0,0,0,10000:11000:12000:13000:14000:15000:16000:17000:18000:19000,0 //-- CR_GRANDCROSS -254,2000,1500,900,900,10000:11000:12000:13000:14000:15000:16000:17000:18000:19000 +254,2000,1500,900,900,10000:11000:12000:13000:14000:15000:16000:17000:18000:19000,0 //-- CR_DEVOTION -255,3000,0,0,0,30000:45000:60000:75000:90000 +255,3000,0,0,0,30000:45000:60000:75000:90000,0 //-- CR_PROVIDENCE -256,3000,0,0,180000,0 +256,3000,0,0,180000,0,0 //-- CR_DEFENDER -257,0,800,0,180000,0 +257,0,800,0,180000,0,0 //-- CR_SPEARQUICKEN -258,0,0,0,30000:60000:90000:120000:150000:180000:210000:240000:270000:300000,0 +258,0,0,0,30000:60000:90000:120000:150000:180000:210000:240000:270000:300000,0,0 //========================================== //===== Monk =============================== //-- MO_CALLSPIRITS -261,1000,0,0,600000,0 +261,1000,0,0,600000,0,0 //-- MO_ABSORBSPIRITS -262,2000,0,0,0,0 +262,2000,0,0,0,0,0 //-- MO_TRIPLEATTACK -263,0,1000,0,0,0 +263,0,1000,0,0,0,0 //-- MO_INVESTIGATE -266,1000,500,0,0,0 +266,1000,500,0,0,0,0 //-- MO_FINGEROFFENSIVE -267,1000,500,0:200:400:600:800,0,0 +267,1000,500,0:200:400:600:800,0,0,0 //-- MO_STEELBODY -268,5000,0,0,30000:60000:90000:120000:150000,0 +268,5000,0,0,30000:60000:90000:120000:150000,0,0 //-- MO_BLADESTOP -269,0,0,0,500:700:900:1100:1300,20000:30000:40000:50000:60000 +269,0,0,0,500:700:900:1100:1300,20000:30000:40000:50000:60000,0 //-- MO_EXPLOSIONSPIRITS -270,0,0,0,180000,0 +270,0,0,0,180000,0,0 //-- MO_EXTREMITYFIST -271,4000:3500:3000:2500:2000,3000:2500:2000:1500:1000,0,0,300000 +271,4000:3500:3000:2500:2000,3000:2500:2000:1500:1000,0,0,300000,0 //-- MO_CHAINCOMBO -272,0,1000,0,0,0 +272,0,1000,0,0,0,0 //-- MO_COMBOFINISH -273,0,700,0,0,0 +273,0,700,0,0,0,0 //========================================== //===== Sage =============================== //-- SA_MAGICROD -276,0,0,0,400:600:800:1000:1200,0 +276,0,0,0,400:600:800:1000:1200,0,0 //-- SA_SPELLBREAKER -277,700,0,0,0,0 +277,700,0,0,0,0,0 //-- SA_AUTOSPELL -279,3000,0,0,120000:150000:180000:210000:240000:270000:300000:330000:360000:390000,0 +279,3000,0,0,120000:150000:180000:210000:240000:270000:300000:330000:360000:390000,0,0 //-- SA_FLAMELAUNCHER -280,3000,0,0,1200000:1200000:1200000:1200000:1800000,0 +280,3000,0,0,1200000:1200000:1200000:1200000:1800000,0,0 //-- SA_FROSTWEAPON -281,3000,0,0,1200000:1200000:1200000:1200000:1800000,0 +281,3000,0,0,1200000:1200000:1200000:1200000:1800000,0,0 //-- SA_LIGHTNINGLOADER -282,3000,0,0,1200000:1200000:1200000:1200000:1800000,0 +282,3000,0,0,1200000:1200000:1200000:1200000:1800000,0,0 //-- SA_SEISMICWEAPON -283,3000,0,0,1200000:1200000:1200000:1200000:1800000,0 +283,3000,0,0,1200000:1200000:1200000:1200000:1800000,0,0 //-- SA_VOLCANO -285,5000,0,0,60000:120000:180000:240000:300000,0 +285,5000,0,0,60000:120000:180000:240000:300000,0,0 //-- SA_DELUGE -286,5000,0,0,60000:120000:180000:240000:300000,0 +286,5000,0,0,60000:120000:180000:240000:300000,0,0 //-- SA_VIOLENTGALE -287,5000,0,0,60000:120000:180000:240000:300000,0 +287,5000,0,0,60000:120000:180000:240000:300000,0,0 //-- SA_LANDPROTECTOR -288,5000,0,0,165000:210000:255000:300000:345000,0 +288,5000,0,0,165000:210000:255000:300000:345000,0,0 //-- SA_DISPELL -289,2000,0,0,0,0 +289,2000,0,0,0,0,0 //-- SA_REVERSEORCISH -294,0,0,0,1200000,0 +294,0,0,0,1200000,0,0 //========================================== //===== Bard & Dancer (Ensemble Skills) ==== //-- BD_ADAPTATION -304,0,0,0,0,5000 +304,0,0,0,0,5000,0 //-- BD_LULLABY -306,0,0,0,60000,15000 +306,0,0,0,60000,15000,0 //-- BD_RICHMANKIM -307,0,0,0,60000,60000 +307,0,0,0,60000,60000,0 //-- BD_ETERNALCHAOS -308,0,0,0,60000,60000 +308,0,0,0,60000,60000,0 //-- BD_DRUMBATTLEFIELD -309,0,0,0,60000,60000 +309,0,0,0,60000,60000,0 //-- BD_RINGNIBELUNGEN -310,0,0,0,60000,60000 +310,0,0,0,60000,60000,0 //-- BD_ROKISWEIL -311,0,0,0,60000,60000 +311,0,0,0,60000,60000,0 //-- BD_INTOABYSS -312,0,0,0,60000,60000 +312,0,0,0,60000,60000,0 //-- BD_SIEGFRIED -313,0,0,0,60000,60000 +313,0,0,0,60000,60000,0 //========================================== //===== Bard =============================== //-- BA_MUSICALSTRIKE -316,1500,0,0,0,0 +316,1500,0,0,0,0,0 //-- BA_DISSONANCE -317,0,0,0,30000,3000 +317,0,0,0,30000,3000,0 //-- BA_FROSTJOKE -318,0,3000,0,0,10000:11000:12000:13000:14000 +318,0,3000,0,0,10000:11000:12000:13000:14000,0 //-- BA_WHISTLE -319,0,0,0,60000,20000 +319,0,0,0,60000,20000,0 //-- BA_ASSASSINCROSS -320,0,0,0,120000,20000 +320,0,0,0,120000,20000,0 //-- BA_POEMBRAGI -321,0,0,0,180000,20000 +321,0,0,0,180000,20000,0 //-- BA_APPLEIDUN -322,0,0,0,180000,20000 +322,0,0,0,180000,20000,0 //========================================== //===== Dancer ============================= //-- DC_THROWARROW -324,1500,0,0,0,0 +324,1500,0,0,0,0,0 //-- DC_UGLYDANCE -325,0,0,0,30000,3000 +325,0,0,0,30000,3000,0 //-- DC_SCREAM -326,0,3000,0,0,5000 +326,0,3000,0,0,5000,0 //-- DC_HUMMING -327,0,0,0,60000,20000 +327,0,0,0,60000,20000,0 //-- DC_DONTFORGETME -328,0,0,0,180000,20000 +328,0,0,0,180000,20000,0 //-- DC_FORTUNEKISS -329,0,0,0,120000,20000 +329,0,0,0,120000,20000,0 //-- DC_SERVICEFORYOU -330,0,0,0,180000,20000 +330,0,0,0,180000,20000,0 //========================================== //===== Wedding Skills ===================== //-- WE_MALE -334,3000,0,0,0,0 +334,3000,0,0,0,0,0 //-- WE_FEMALE -335,3000,0,0,0,0 +335,3000,0,0,0,0,0 //-- WE_CALLPARTNER -336,0,0,0,20000,0 +336,0,0,0,20000,0,0 //========================================== //===== NPC Skills Part 2 ================== //-- NPC_GRANDDARKNESS -339,2000,1500,900,900,10000:11000:12000:13000:14000:15000:16000:17000:18000:19000 +339,2000,1500,900,900,10000:11000:12000:13000:14000:15000:16000:17000:18000:19000,0 //-- NPC_STOP -342,0,0,0,10000,0 +342,0,0,0,10000,0,0 //-- NPC_CHANGEUNDEAD -348,0,0,0,30000,0 +348,0,0,0,30000,0,0 //-- NPC_POWERUP -349,0,0,0,10000:15000:20000:25000:30000,0 +349,0,0,0,10000:15000:20000:25000:30000,0,0 //-- NPC_AGIUP -350,0,0,0,10000:15000:20000:25000:30000,0 +350,0,0,0,10000:15000:20000:25000:30000,0,0 //-- NPC_INVISIBLE -353,0,0,0,30000,0 +353,0,0,0,30000,0,0 //-- NPC_RUN -354,0,0:500:1000:1500:2000:2500,0,0,0 +354,0,0:500:1000:1500:2000:2500,0,0,0,0 //========================================== //===== Lord Knight ======================== //-- LK_AURABLADE -355,0,0,0,40000:60000:80000:100000:120000,0 +355,0,0,0,40000:60000:80000:100000:120000,0,0 //-- LK_PARRYING -356,0,0,0,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000,0 +356,0,0,0,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000,0,0 //-- LK_CONCENTRATION -357,0,0,0,25000:30000:35000:40000:45000,0 +357,0,0,0,25000:30000:35000:40000:45000,0,0 //-- LK_TENSIONRELAX -358,0,0,0,180000,0 +358,0,0,0,180000,0,0 //-- LK_BERSERK -359,0,0,0,300000,15000 +359,0,0,0,300000,15000,0 //-- LK_FURY -360,0,0,0,300000,0 +360,0,0,0,300000,0,0 //========================================== //===== High Priest ======================== //-- HP_ASSUMPTIO -361,1000:1500:2000:2500:3000,1100:1200:1300:1400:1500,0,20000:40000:60000:80000:100000,0 +361,1000:1500:2000:2500:3000,1100:1200:1300:1400:1500,0,20000:40000:60000:80000:100000,0,0 //-- HP_BASILICA -362,5000:6000:7000:8000:9000,2000:3000:4000:5000:6000,0,20000:25000:30000:35000:40000,20000:25000:30000:35000:40000 +362,5000:6000:7000:8000:9000,2000:3000:4000:5000:6000,0,20000:25000:30000:35000:40000,20000:25000:30000:35000:40000,0 //========================================== //===== High Wzard ========================= //-- HW_MAGICCRASHER -365,300,300,0,0,0 +365,300,300,0,0,0,0 //-- HW_MAGICPOWER -366,700,0,0,30000,0 +366,700,0,0,30000,0,0 //========================================== //===== Paladin ============================ //-- PA_PRESSURE -367,2000:2500:3000:3500:4000,2000:2500:3000:3500:4000,0,0,2000:3000:4000:5000:6000 +367,2000:2500:3000:3500:4000,2000:2500:3000:3500:4000,0,0,2000:3000:4000:5000:6000,0 //-- PA_SACRIFICE -368,0,2000,0,0,0 +368,0,2000,0,0,0,0 //-- PA_GOSPEL -369,0,0,0,60000,60000 +369,0,0,0,60000,60000,0 //========================================== //===== Champion =========================== //-- CH_PALMSTRIKE -370,0,300,0,0,0 +370,0,300,0,0,0,0 //-- CH_TIGERFIST -371,0,700,0,0,2000:4000:6000:8000:10000 +371,0,700,0,0,2000:4000:6000:8000:10000,0 //-- CH_CHAINCRUSH -372,0,800:800:800:800:800:1000:1000:1000:1000:1000,0,0,0 +372,0,800:800:800:800:800:1000:1000:1000:1000:1000,0,0,0,0 //========================================== //===== Professor ========================== //-- PF_HPCONVERSION -373,0,1000:1200:1400:1600:1800,0,0,0 +373,0,1000:1200:1400:1600:1800,0,0,0,0 //-- PF_SOULCHANGE -374,3000,5000,0,0,0 +374,3000,5000,0,0,0,0 //-- PF_SOULBURN -375,0,0,0,0,0 +375,0,0,0,0,0,10000:10000:10000:10000:15000 //========================================== //===== Assassin Cross ===================== //-- ASC_EDP -378,0,2000,0,40000:45000:50000:55000:60000,20000:30000:40000:50000:60000 +378,0,2000,0,40000:45000:50000:55000:60000,20000:30000:40000:50000:60000,0 //-- ASC_BREAKER -379,700,1000:1200:1400:1600:1800:2000:2200:2400:2600:2800,0,0,0 +379,700,1000:1200:1400:1600:1800:2000:2200:2400:2600:2800,0,0,0,0 //========================================== //===== Sniper ============================= //-- SN_SIGHT -380,0,0,0,30000,0 +380,0,0,0,30000,0,0 //-- SN_FALCONASSAULT -381,1000,3000,0,0,0 +381,1000,3000,0,0,0,0 //-- SN_SHARPSHOOTING -382,2000,1500,0,0,0 +382,2000,1500,0,0,0,0 //-- SN_WINDWALK -383,2000:2400:2800:3200:3600:4000:4400:4800:5200:5600,2000,0,130000:160000:190000:220000:250000:280000:310000:340000:370000:400000,0 +383,2000:2400:2800:3200:3600:4000:4400:4800:5200:5600,2000,0,130000:160000:190000:220000:250000:280000:310000:340000:370000:400000,0,0 //========================================== //===== Whitesmith ========================= //-- WS_MELTDOWN -384,500:500:600:600:700:700:800:800:900:1000,0,0,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000,5000 +384,500:500:600:600:700:700:800:800:900:1000,0,0,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000,5000,0 //-- WS_CARTBOOST -387,0,0,0,60000,0 +387,0,0,0,60000,0,0 //========================================== //===== Stalker ============================ //-- ST_CHASEWALK -389,1200,0,0,10000,30000 +389,1200,0,0,10000,30000,0 //-- ST_REJECTSWORD -390,0,0,0,300000,0 +390,0,0,0,300000,0,0 //========================================== //===== Clown / Gypsy ====================== //-- CG_ARROWVULCAN -394,2000:2200:2400:2600:2800:3000:3200:3400:3600:3800,2800:2800:2800:2800:2800:3000:3000:3000:3000:3000,2000,0,0 +394,2000:2200:2400:2600:2800:3000:3200:3400:3600:3800,2800:2800:2800:2800:2800:3000:3000:3000:3000:3000,2000,0,0,0 //-- CG_MOONLIT -395,0,0,0,20000:25000:30000:35000:40000,0 +395,0,0,0,20000:25000:30000:35000:40000,0,0 //-- CG_MARIONETTE -396,0,0,0,1000,0 +396,0,0,0,1000,0,0 //========================================== //===== Mixed Advanced Skills ============== //-- LK_SPIRALPIERCE -397,300:500:700:900:1000,1200:1400:1600:1800:2000,0,0,1000 +397,300:500:700:900:1000,1200:1400:1600:1800:2000,0,0,1000,0 //-- LK_HEADCRUSH -398,0,500,0,0,120000 +398,0,500,0,0,120000,0 //-- LK_JOINTBEAT -399,0,800:800:800:800:800:1000:1000:1000:1000:1000,0,0,30000 +399,0,800:800:800:800:800:1000:1000:1000:1000:1000,0,0,30000,0 //-- HW_NAPALMVULCAN -400,1000,1000,0,0,45000 +400,1000,1000,0,0,45000,0 //-- CH_SOULCOLLECT -401,2000,0,0,600000,0 +401,2000,0,0,600000,0,0 //-- PF_MINDBREAKER -402,0,800:900:1000:1100:1200,0,30000,0 +402,0,800:900:1000:1100:1200,0,30000,0,0 //-- PF_MEMORIZE -403,5000,0,0,0,0 +403,5000,0,0,0,0,0 //-- PF_FOGWALL -404,0,0,0,20000,10000 +404,0,0,0,20000,10000,0 //-- PF_SPIDERWEB -405,0,0,0,30000,8000 +405,0,0,0,30000,8000,0 //-- ASC_METEORASSAULT (Upkeep2 times are duration of: blind(lv1), stun(lv2) or bleeding (lv3)) -406,500,500,0,0,10000:5000:120000 +406,500,500,0,0,10000:5000:120000,0 //-- ASC_CDP -407,0,500,0,0,0 +407,0,500,0,0,0,0 //========================================== //===== Adoption Skills ==================== //-- WE_BABY -408,3000,0,0,300000,0 +408,3000,0,0,300000,0,0 //-- WE_CALLPARENT -409,0,0,0,20000,0 +409,0,0,0,20000,0,0 //-- WE_CALLBABY -410,0,0,0,20000,0 +410,0,0,0,20000,0,0 //========================================== //===== Taekwon ============================ //-- TK_RUN -411,6000:5000:4000:3000:2000:1000:0:0:0:0,0,0,1000,150000 +411,6000:5000:4000:3000:2000:1000:0:0:0:0,0,0,1000,150000,0 //-- TK_DOWNKICK -415,0,0,0,0,3000 +415,0,0,0,0,3000,0 //-- TK_TURNKICK -417,0,0,0,0,2000 +417,0,0,0,0,2000,0 //-- TK_SPTIME -423,0,0,0,1800000,0 +423,0,0,0,1800000,0,0 //-- TK_SEVENWIND -425,0,0,0,300000,0 +425,0,0,0,300000,0,0 //-- TK_HIGHJUMP -426,5000:4000:3000:2000:1000,0,0,0,0 +426,5000:4000:3000:2000:1000,0,0,0,0,0 //========================================== //===== Star Gladiator ===================== //-- SG_FEEL -427,1000,0,0,0,0 +427,1000,0,0,0,0,0 //SG_SUN_WARM -428,0,1000,0,10000:20000:60000,0 +428,0,1000,0,10000:20000:60000,0,0 //SG_MOON_WARM -429,0,1000,0,10000:20000:60000,0 +429,0,1000,0,10000:20000:60000,0,0 //SG_STAR_WARM -430,0,1000,0,10000:20000:60000,0 +430,0,1000,0,10000:20000:60000,0,0 //SG_SUN_COMFORT -431,0,1000,0,80000:160000:240000:320000,0 +431,0,1000,0,80000:160000:240000:320000,0,0 //SG_MOON_COMFORT -432,0,1000,0,80000:160000:240000:320000,0 +432,0,1000,0,80000:160000:240000:320000,0,0 //SG_STAR_COMFORT -433,0,1000,0,80000:160000:240000:320000,0 +433,0,1000,0,80000:160000:240000:320000,0,0 //-- SG_HATE -434,1000,0,0,0,0 +434,1000,0,0,0,0,0 //SG_FRIEND -442,0,0,0,10000,0 +442,0,0,0,10000,0,0 //SG_KNOWLEDGE -443,0,0,0,600000,0 +443,0,0,0,600000,0,0 //SG_FUSION -444,0,1000,0,600000,0 +444,0,1000,0,600000,0,0 //========================================== //===== Soul Linker ======================== //-- SL_ALCHEMIST -445,1000,500,0,150000:200000:250000:300000:350000,0 +445,1000,500,0,150000:200000:250000:300000:350000,0,0 //-- AM_BERSERKPITCHER - Copy of AM_POTIONPITCHER for now -446,0,500,0,0,0 +446,0,500,0,0,0,0 //-- SL_MONK -447,1000,500,0,150000:200000:250000:300000:350000,0 +447,1000,500,0,150000:200000:250000:300000:350000,0,0 //-- SL_STAR -448,1000,500,0,150000:200000:250000:300000:350000,0 +448,1000,500,0,150000:200000:250000:300000:350000,0,0 //-- SL_SAGE -449,1000,500,0,150000:200000:250000:300000:350000,0 +449,1000,500,0,150000:200000:250000:300000:350000,0,0 //-- SL_CRUSADER -450,1000,500,0,150000:200000:250000:300000:350000,0 +450,1000,500,0,150000:200000:250000:300000:350000,0,0 //-- SL_SUPERNOVICE -451,1000,500,0,150000:200000:250000:300000:350000,0 +451,1000,500,0,150000:200000:250000:300000:350000,0,0 //-- SL_KNIGHT -452,1000,500,0,150000:200000:250000:300000:350000,0 +452,1000,500,0,150000:200000:250000:300000:350000,0,0 //-- SL_WIZARD -453,1000,500,0,150000:200000:250000:300000:350000,0 +453,1000,500,0,150000:200000:250000:300000:350000,0,0 //-- SL_PRIEST -454,1000,500,0,150000:200000:250000:300000:350000,0 +454,1000,500,0,150000:200000:250000:300000:350000,0,0 //-- SL_BARDDANCER -455,1000,500,0,150000:200000:250000:300000:350000,0 +455,1000,500,0,150000:200000:250000:300000:350000,0,0 //-- SL_ROGUE -456,1000,500,0,150000:200000:250000:300000:350000,0 +456,1000,500,0,150000:200000:250000:300000:350000,0,0 //-- SL_ASSASSIN -457,1000,500,0,150000:200000:250000:300000:350000,0 +457,1000,500,0,150000:200000:250000:300000:350000,0,0 //-- SL_BLACKSMITH -458,1000,500,0,150000:200000:250000:300000:350000,0 +458,1000,500,0,150000:200000:250000:300000:350000,0,0 //-- BS_ADRENALINE2 -459,0,0,0,150000,0 +459,0,0,0,150000,0,0 //-- SL_HUNTER -460,1000,500,0,150000:200000:250000:300000:350000,0 +460,1000,500,0,150000:200000:250000:300000:350000,0,0 //-- SL_SOULLINKER -461,1000,500,0,150000:200000:250000:300000:350000,0 +461,1000,500,0,150000:200000:250000:300000:350000,0,0 //-- SL_KAIZEL -462,4500:4000:3500:3000:2500:2000:1500,0,0,1800000,2000 +462,4500:4000:3500:3000:2500:2000:1500,0,0,1800000,2000,0 //-- SL_KAAHI -463,0,500,0,1800000,500 +463,0,500,0,1800000,500,0 //-- SL_KAUPE -464,500,500,0,600000,0 +464,500,500,0,600000,0,0 //-- SL_KAITE -465,6000:5500:5000:4500:4000:3500:3000,0,0,60000:120000:180000:240000:300000:360000:600000,0 +465,6000:5500:5000:4500:4000:3500:3000,0,0,60000:120000:180000:240000:300000:360000:600000,0,0 //-- SL_STIN -467,100,500,0,0,0 +467,100,500,0,0,0,0 //-- SL_STUN -468,100,500,0,2000,0 +468,100,500,0,2000,0,0 //-- SL_SMA -469,2000,500,0,3000,0 +469,2000,500,0,3000,0,0 //-- SL_SWOO -470,1000,500,0,1000:2000:3000:4000:5000:6000:7000,0 +470,1000,500,0,1000:2000:3000:4000:5000:6000:7000,0,0 //-- SL_SKE -471,3000:2000:1000,500,0,10000:20000:30000,3000 +471,3000:2000:1000,500,0,10000:20000:30000,3000,0 //-- SL_SKA -472,3000:2000:1000,500,0,10000:20000:30000,0 +472,3000:2000:1000,500,0,10000:20000:30000,0,0 //========================================== //-- SM_SELFPROVOKE -473,0,0,0,30000,0 +473,0,0,0,30000,0,0 //===== Mixed Advanced Skills ============== //-- ST_PRESERVE -475,1000,0,0,600000,0 +475,1000,0,0,600000,0,0 //-- ST_FULLSTRIP -476,0,1000,0,75000:90000:105000:120000:135000,0 +476,0,1000,0,75000:90000:105000:120000:135000,0,0 //-- CR_SLIMPITCHER -478,1000,1000,0,0,0 +478,1000,1000,0,0,0,0 //-- CR_FULLPROTECTION -479,2000,0,0,120000:240000:360000:480000:600000,0 +479,2000,0,0,120000:240000:360000:480000:600000,0,0 //-- PA_SHIELDCHAIN -480,1000,1000,0,0,0 +480,1000,1000,0,0,0,0 //-- PF_DOUBLECASTING -482,2000,0,0,90000,0 +482,2000,0,0,90000,0,0 //-- HW_GANBANTEIN -483,3000,2000,0,0,0 +483,3000,2000,0,0,0,0 //-- HW_GRAVITATION -484,5000,2000,0,5000:6000:7000:8000:9000,0 +484,5000,2000,0,5000:6000:7000:8000:9000,0,0 //-- WS_CARTTERMINATION -485,0,0,0,0,5000 +485,0,0,0,0,5000,0 //-- WS_OVERTHRUSTMAX -486,0,0,0,180000,0 +486,0,0,0,180000,0,0 //-- CG_LONGINGFREEDOM -487,0,0,0,180000,0 +487,0,0,0,180000,0,0 //-- CG_HERMODE -488,0,0,0,10000:15000:20000:25000:30000,10000:15000:20000:25000:30000 +488,0,0,0,10000:15000:20000:25000:30000,10000:15000:20000:25000:30000,0 //-- CG_TAROTCARD -489,1000,3000,0,0,30000 +489,1000,3000,0,0,30000,0 //-- CR_ACIDDEMONSTRATION -490,1000,1000,0,0,0 +490,1000,1000,0,0,0,0 //-- CR_CULTIVATION -491,0,0,0,300000,0 +491,0,0,0,300000,0,0 //========================================== //-- ITEM_ENCHANTARMS -492,0,0,0,180000,0 +492,0,0,0,180000,0,0 //===== Mixed Taekwon Skills =============== //-- TK_MISSION -493,1000,0,0,0,0 +493,1000,0,0,0,0,0 //-- SL_HIGH -494,1000,500,0,150000:200000:250000:300000:350000,0 +494,1000,500,0,150000:200000:250000:300000:350000,0,0 //-- KN_ONEHAND -495,0,0,0,300000,0 +495,0,0,0,300000,0,0 //-- AM_TWILIGHT1 -496,3000,10000,0,0,0 +496,3000,10000,0,0,0,0 //-- AM_TWILIGHT2 -497,3000,10000,0,0,0 +497,3000,10000,0,0,0,0 //-- AM_TWILIGHT3 -498,3000,10000,0,0,0 +498,3000,10000,0,0,0,0 //-- HT_POWER -499,0,0,0,100,0 +499,0,0,0,100,0,0 //========================================== //===== Gunslinger ========================= //-- GS_GLITTERING -500,0,0,0,600000,0 +500,0,0,0,600000,0,0 //-- GS_FLING -501,0,0,0,30000,0 +501,0,0,0,30000,0,0 //-- GS_BULLSEYE -503,500,0,0,0,0 +503,500,0,0,0,0,0 //-- GS_MADNESSCANCEL -504,3000,4000,0,15000,0 +504,3000,4000,0,15000,0,0 //-- GS_ADJUSTMENT -505,1000,1000,0,30000,0 +505,1000,1000,0,30000,0,0 //-- GS_INCREASING -506,0,1000,0,60000,0 +506,0,1000,0,60000,0,0 //-- GS_CRACKER -508,0,1000,0,0,5000 +508,0,1000,0,0,5000,0 //-- GS_TRACKING -512,1200:1400:1600:1800:2000:2200:2400:2600:2800:3000,0,0,0,0 +512,1200:1400:1600:1800:2000:2200:2400:2600:2800:3000,0,0,0,0,0 //-- GS_DISARM -513,0,0,0,30000,0 +513,0,0,0,30000,0,0 //-- GS_PIERCINGSHOT -514,1500,0,0,0,120000 +514,1500,0,0,0,120000,0 //-- GS_RAPIDSHOWER -515,0,1000,0,0,0 +515,0,1000,0,0,0,0 //-- GS_DESPERADO -516,0,1000,1000,1000,0 +516,0,1000,1000,1000,0,0 //-- GS_GATLINGFEVER -517,0,0,0,30000:45000:60000:75000:90000:105000:120000:135000:150000:165000,0 +517,0,0,0,30000:45000:60000:75000:90000:105000:120000:135000:150000:165000,0,0 //-- GS_DUST -518,1000,1000,0,0,0 +518,1000,1000,0,0,0,0 //-- GS_FULLBUSTER -519,0,1200:1400:1600:1800:2000:2200:2400:2600:2800:3000,0,0,10000 +519,0,1200:1400:1600:1800:2000:2200:2400:2600:2800:3000,0,0,10000,0 //-- GS_GROUNDDRIFT -521,2000,0,0,3000:6000:9000:12000:15000:18000:21000:24000:27000:30000,10000 +521,2000,0,0,3000:6000:9000:12000:15000:18000:21000:24000:27000:30000,10000,0 //========================================== //===== Ninja ============================== //-- NJ_KUNAI -524,0,1000,0,0,0 +524,0,1000,0,0,0,0 //-- NJ_HUUMA -525,3000,2000,0,0,0 +525,3000,2000,0,0,0,0 //-- NJ_ZENYNAGE -526,0,5000,0,0,0 +526,0,5000,0,0,0,0 //-- NJ_TATAMIGAESHI -527,0,3000,0,3000,3000 +527,0,3000,0,3000,3000,0 //-- NJ_KASUMIKIRI -528,0,1000,0,30000:60000:90000:120000:150000:180000:210000:240000:270000:300000,0 +528,0,1000,0,30000:60000:90000:120000:150000:180000:210000:240000:270000:300000,0,0 //-- NJ_SHADOWJUMP -529,0,1000,0,0,0 +529,0,1000,0,0,0,0 //-- NJ_KIRIKAGE // Seems to have no delay (English Translation Project) -530,0,0,0,0,0 +530,0,0,0,0,0,0 //-- NJ_UTSUSEMI -531,0,1000,0,20000:30000:40000:50000:60000,0 +531,0,1000,0,20000:30000:40000:50000:60000,0,0 //-- NJ_BUNSINJYUTSU -532,4000:3500:3000:2500:2000:1500:1000:1000:1000:1000,1000,0,60000:80000:100000:120000:140000:160000:180000:200000:220000:240000,0 +532,4000:3500:3000:2500:2000:1500:1000:1000:1000:1000,1000,0,60000:80000:100000:120000:140000:160000:180000:200000:220000:240000,0,0 //-- NJ_KOUENKA -534,700:1400:2100:2800:3500:4200:4900:5600:6300:7000,0,0,0,0 +534,700:1400:2100:2800:3500:4200:4900:5600:6300:7000,0,0,0,0,0 //-- NJ_KAENSIN -535,6000:5500:5000:4500:4000:3500:3000:2500:2000:1500,1000,0,20000,0 +535,6000:5500:5000:4500:4000:3500:3000:2500:2000:1500,1000,0,20000,0,0 //-- NJ_BAKUENRYU -536,3000,2000,0,0,0 +536,3000,2000,0,0,0,0 //-- NJ_HYOUSENSOU -537,700:1400:2100:2800:3500:4200:4900:5600:6300:7000,0,0,0,0 +537,700:1400:2100:2800:3500:4200:4900:5600:6300:7000,0,0,0,0,0 //-- NJ_SUITON -538,3000,0,0,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000 +538,3000,0,0,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000,0 //-- NJ_HYOUSYOURAKU -539,2000:2500:3000:3500:4000,2000,0,0,10000:11000:12000:13000:14000:15000:16000:17000:18000:19000 +539,2000:2500:3000:3500:4000,2000,0,0,10000:11000:12000:13000:14000:15000:16000:17000:18000:19000,0 //-- NJ_HUUJIN -540,1000:1500:2000:2500:3000:3500:4000:5000:5500:6000,1000,0,0,0 +540,1000:1500:2000:2500:3000:3500:4000:5000:5500:6000,1000,0,0,0,0 //-- NJ_RAIGEKISAI -541,4000,0,0,0,0 +541,4000,0,0,0,0,0 //-- NJ_KAMAITACHI -542,4000,0,0,0,0 +542,4000,0,0,0,0,0 //-- NJ_NEN -543,5000:4000:3000:2000:1000,0,0,30000:45000:60000:75000:90000,0 +543,5000:4000:3000:2000:1000,0,0,30000:45000:60000:75000:90000,0,0 +//========================================== + +//===== Gangsi Branch and Other Skills ===== +//-- MB_PETPITCHER +//551,1000:1000:1000:1000:1000:500:500:500:500:500,0,0,0,0,0 + +//-- MB_B_GAIN +//556,2200:2000:1800:1600:1400:1200:1000,0,0,0,0,0 + +//-- MB_MUNAKBALL +//560,1500:1500:1500:1500:1000:1000:1000:1000:500:500,0,0,0,0,0 + +//-- MB_B_GATHERING +//562,10000,0,0,0,0,0 + +//-- MB_B_EXCLUDE +//564,30000:25000:20000:15000:10000,0,0,0,0,0 + +//-- MB_B_WALLSHIFT +//568,1000:800:600:400:200,0,0,0,0,0 + +//-- SL_DEATHKNIGHT +572,1000,500,0,150000:200000:250000:300000:350000,0,0 +//-- SL_COLLECTOR +573,1000,500,0,150000:200000:250000:300000:350000,0,0 +//-- SL_NINJA +574,1000,500,0,150000:200000:250000:300000:350000,0,0 +//-- SL_GUNNER +575,1000,500,0,150000:200000:250000:300000:350000,0,0 +//-- AM_TWILIGHT4 +//576,3000,10000,0,0,0,0 + +//-- DE_WINDATTACK +//617,1000:1000:1000:1000:1000:0:0:0:0:0,0,0,0,0,0 + +//-- DA_EXPLOSION +//625,7000:6000:5000:4000:3000,0,0,0,0,0 + +//-- DA_MAGICCART +//640,5000:4000:3000:2000:1000,0,0,0,0,0 +//-- DA_COPY +//641,20000,0,0,0,0,0 + +//-- DA_EDARKNESS +//647,13000:11000:9000:7000:5000,0,0,0,0,0 + +//-- DA_TIMEOUT +//649,5000:3000:1000,0,0,0,0,0 +//-- ALL_TIMEIN +//650,0,0,0,0,0,0,1000 //========================================== //===== New Monster Skills ================= //-- NPC_ICEBREATH -655,0,0,0,0,12000 +655,0,0,0,0,12000,0 //-- NPC_ACIDBREATH -657,0,0,0,0,60000 +657,0,0,0,0,60000,0 //-- NPC_DRAGONFEAR (Upkeep2 times are duration of: Stun(lv1), Silence(lv2), Confusion(lv3) and Bleeding(lv4)) -659,0,0,0,0,5000:30000:30000:120000 +659,0,0,0,0,5000:30000:30000:120000,0 //-- NPC_BLEEDING -660,0,0,0,0,120000 +660,0,0,0,0,120000,0 //-- NPC_HELLJUDGEMENT -662,0,0,0,0,30000 +662,0,0,0,0,30000,0 //-- NPC_WIDESILENCE -663,0,0,0,0,30000 +663,0,0,0,0,30000,0 //-- NPC_WIDEFREEZE -664,0,0,0,0,12000 +664,0,0,0,0,12000,0 //-- NPC_WIDEBLEEDING -665,0,0,0,0,120000 +665,0,0,0,0,120000,0 //-- NPC_WIDESTONE -666,0,0,0,0,20000 +666,0,0,0,0,20000,0 //-- NPC_WIDECONFUSE -667,0,0,0,0,30000 +667,0,0,0,0,30000,0 //-- NPC_WIDESLEEP -668,0,0,0,0,30000 +668,0,0,0,0,30000,0 //-- NPC_WIDESIGHT -669,0,0,0,10000,0 +669,0,0,0,10000,0,0 //-- NPC_EVILLAND -670,0,0,0,30000,30000 +670,0,0,0,30000,30000,0 //-- NPC_MAGICMIRROR -671,0,0,0,30000,0 +671,0,0,0,30000,0,0 //-- NPC_SLOWCAST -672,0,0,0,0,30000 +672,0,0,0,0,30000,0 //-- NPC_CRITICALWOUND -673,0,0,0,0,30000 +673,0,0,0,0,30000,0 //-- NPC_STONESKIN -675,0,0,0,30000,0 +675,0,0,0,30000,0,0 //-- NPC_ANTIMAGIC -676,0,0,0,30000,0 +676,0,0,0,30000,0,0 //-- NPC_WIDECURSE -677,0,0,0,0,30000 +677,0,0,0,0,30000,0 //-- NPC_WIDESTUN -678,0,0,0,0,5000 +678,0,0,0,0,5000,0 //========================================== //===== New Monster Skills (12.1) ========== //-- NPC_HELLPOWER -683,0,0,0,0,300000 +683,0,0,0,0,300000,0 //-- NPC_WIDEHELLDIGNITY -684,0,0,0,0,300000 +684,0,0,0,0,300000,0 //-- NPC_INVINCIBLE -685,0,0,0,-1,0 +685,0,0,0,-1,0,0 //-- NPC_INVINCIBLEOFF -686,0,0,0,60000,0 +686,0,0,0,60000,0,0 //===== Item Use-Only Skills =============== //-- CASH_BLESSING -689,0,0,0,60000:80000:100000:120000:140000:160000:180000:200000:220000:240000,0 +689,0,0,0,60000:80000:100000:120000:140000:160000:180000:200000:220000:240000,0,0 //-- CASH_INCAGI -690,0,0,0,60000:80000:100000:120000:140000:160000:180000:200000:220000:240000,0 +690,0,0,0,60000:80000:100000:120000:140000:160000:180000:200000:220000:240000,0,0 //-- CASH_ASSUMPTIO -691,0,0,0,20000:40000:60000:80000:100000,0 +691,0,0,0,20000:40000:60000:80000:100000,0,0 +//-- ALL_CATCRY +692,0,5000,0,0,0,0 + +//-- ALL_DREAM_SUMMERNIGHT +695,0,12000,0,0,0,0 + //-- ALL_WEWISH -698,0,20000,0,0,0 +698,0,20000,0,0,0,0 //========================================== //===== 2nd Jobs Quest Skills ============== //-- KN_CHARGEATK -1001,300,300,0,0,0 +1001,300,300,0,0,0,0 //-- CR_SHRINK -1002,0,0,0,300000,0 +1002,0,0,0,300000,0,0 //-- AS_VENOMKNIFE -1004,0,0,0,0,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000 +1004,0,0,0,0,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000,0 //-- RG_CLOSECONFINE -1005,0,0,0,10000,0 +1005,0,0,0,10000,0,0 //-- WZ_SIGHTBLASTER -1006,2000,0,0,120000,0 +1006,2000,0,0,120000,0,0 //-- SA_ELEMENTWATER -1008,2000,1000,0,1800000,0 +1008,2000,1000,0,1800000,0,0 //-- HT_PHANTASMIC -1009,0,0,0,0,0 +1009,0,0,0,0,0,0 //-- BA_PANGVOICE -1010,1000,2000,0,17000,0 +1010,1000,2000,0,17000,0,0 //-- DC_WINKCHARM (time1: Charm, time2: Confusion) -1011,1000,2000,0,10000,17000 +1011,1000,2000,0,10000,17000,0 //-- BS_GREED -1013,0,1000,0,0,0 +1013,0,1000,0,0,0,0 //-- PR_REDEMPTIO -1014,4000,0,0,0,0 +1014,4000,0,0,0,0,0 //-- MO_KITRANSLATION -1015,2000,1000,0,600000,0 +1015,2000,1000,0,600000,0,0 //-- MO_BALKYOUNG -1016,0,2000,0,0,2000 +1016,0,2000,0,0,2000,0 //-- SA_ELEMENTGROUND -1017,2000,1000,0,1800000,0 +1017,2000,1000,0,1800000,0,0 //-- SA_ELEMENTFIRE -1018,2000,1000,0,1800000,0 +1018,2000,1000,0,1800000,0,0 //-- SA_ELEMENTWIND -1019,2000,1000,0,1800000,0 +1019,2000,1000,0,1800000,0,0 +//========================================== + +//===== Rune Knight ======================== +//-- RK_ENCHANTBLADE +2001,1000,0,0,300000,0,0 +//-- RK_SONICWAVE +2002,0,1000,0,0,0,2000 +//-- RK_DEATHBOUND +2003,0,2000,0,2000,0,3000 +//-- RK_HUNDREDSPEAR +2004,1000,500,0,0,0,0 +//-- RK_WINDCUTTER //CHECK duration 1 +2005,0,0,0,0,0,2000 +//-- RK_IGNITIONBREAK +2006,1000,0,0,0,0,2000 + +//-- RK_DRAGONBREATH //CHECK duration 1 burning +2008,500:500:500:1500:1500:1500:2000:2000:2500:2500,2000,0,5000,0,0 +//-- RK_DRAGONHOWLING +2009,0,0,0,15000,0,60000 + +//-- RK_MILLENNIUMSHIELD //CHECK duration 2 +2011,0,1000,0,300000,0,60000 +//-- RK_CRUSHSTRIKE +2012,1000,0,0,0,0,30000 +//-- RK_REFRESH //CHECK duration 1 +2013,1000,0,0,30000,0,120000 +//-- RK_GIANTGROWTH +2014,1000,0,0,300000,0,0 +//-- RK_STONEHARDSKIN //CHECK duration 2 +2015,2000,0,0,300000,10000,0 +//-- RK_VITALITYACTIVATION +2016,0,0,0,30000,0,0 +//-- RK_STORMBLAST //CHECK duration 1 +2017,2000,1000,0,1000,0,0 +//-- RK_FIGHTINGSPIRIT +2018,0,0,0,300000,0,0 +//-- RK_ABUNDANCE +2019,0,0,0,300000,0,0 +//========================================== + +//===== Gillotine Cross ==================== +//-- GC_VENOMIMPRESS +2021,0,3000:2500:2000:1500:1000,0,10000:20000:30000:40000:50000,0,0 +//-- GC_CROSSIMPACT +2022,0,2500:2000:1500:1000:500,2000,0,0,0 +//-- GC_DARKILLUSION +2023,0,1500,0,0,0,0 + +//-- GC_CREATENEWPOISON +2025,0,500,0,0,0,0 +//-- GC_ANTIDOTE +2026,0,0,0,0,0,0 +//-- GC_POISONINGWEAPON -- VenomBleed Note : As poison says 15 seconds, on kRO is doing 300 seconds. +2027,0,1000,0,60000:120000:180000:240000:300000,300000:300000:300000:300000:0:300000:300000:300000:300000:0,0 +//-- GC_WEAPONBLOCKING +2028,0,2000,0,180000,0,0 +//-- GC_COUNTERSLASH +2029,0,2000,0,0,0,0 +//-- GC_WEAPONCRUSH //CHECK duration 1 devist +2030,0,1000,0,40000:80000:120000:160000:200000,0,0 +//-- GC_VENOMPRESSURE +2031,0,1000,0,0,0,0 +//-- GC_POISONSMOKE //CHECK Cast time is said 2 second fixed, but no variable. Check duration 1 (was added / thought to be AoE duration) +2032,2000,2000,0,6000:8000:10000:12000:14000,0,0 +//-- GC_CLOAKINGEXCEED +2033,0,2000,0,0,0,0 +//-- GC_PHANTOMMENACE +2034,0,1000,0,0,0,0 +//-- GC_HALLUCINATIONWALK +2035,0,0,0,30000:35000:40000:45000:50000,25000,300000 +//-- GC_ROLLINGCUTTER //CHECK duration 1 (should be as long as esma status?) +2036,0,200,0,4000,0,0 +//-- GC_CROSSRIPPERSLASHER +2037,0,1000,0,0,0,0 +//========================================== + +//===== Arch Bishop ======================== +//-- AB_JUDEX +2038,2500,500,0,0,0,0 +//-- AB_ANCILLA +2039,1000,1000,0,0,0,0 +//-- AB_ADORAMUS //CHECK Duration 1 is blindness and duration 2 is reduced AGI. FIX ME!!!! +2040,2000,500,0,6000:7000:8000:9000:10000:11000:12000:13000:14000:15000,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000,2000 +//-- AB_CLEMENTIA +2041,4000,0,0,120000:180000:240000,0,0 +//-- AB_CANTO +2042,4000,0,0,120000:180000:240000,0,0 +//-- AB_CHEAL +2043,4000:3500:3000,0,0,0,0,1000:2000:3000 +//-- AB_EPICLESIS +2044,4000:4500:5000:5500:6000,2000,0,18000:21000:24000:27000:30000,0,60000 +//-- AB_PRAEFATIO +2045,3000,0,0,120000,0,13000:16000:19000:22000:25000:28000:31000:34000:37000:40000 +//-- AB_ORATIO +2046,5000,0,0,30000,0,2000 +//-- AB_LAUDAAGNUS +2047,1000,0,0,60000,0,3000 +//-- AB_LAUDARAMUS +2048,1000,0,0,60000,0,3000 + +//-- AB_RENOVATIO +2050,5000,0,0,90000,0,1000 +//-- AB_HIGHNESSHEAL +2051,1000,1000,0,0,0,3000:6000:9000:12000:15000 +//-- AB_CLEARANCE +2052,4000,0,0,0,0,10000 +//-- AB_EXPIATIO +2053,2000,0,0,150000:180000:210000:240000:270000,0,0 +//-- AB_DUPLELIGHT +2054,4000,1000,0,90000:120000:150000:180000:210000:240000:270000:300000:330000:360000,0,0 + +//-- AB_SILENTIUM +2057,4000,0,0,20000:30000:40000:50000:60000,0,15000 +//========================================== + +//===== Warlock ============================ +//-- WL_WHITEIMPRISON //CHECK Is reuse delay hard coded to work only if successful? Duration 1 may be incorrect. Is duration 2 for if casted on self? +2201,0,0,0,10000:12000:14000:16000:18000,5000,0 +//-- WL_SOULEXPANSION +2202,2000,500,0,0,0,0 +//-- WL_FROSTMISTY +2203,2500,2000,0,40000,0,8000 +//-- WL_JACKFROST +2204,3000,2000,0,10000:15000:20000:25000:30000,0,0 +//-- WL_MARSHOFABYSS //CHECK Duration 1 time +2205,500,1000,0,20000,0,2500:3000:3500:4000:4500 +//-- WL_RECOGNIZEDSPELL +2206,2000,1000,0,20000:30000:40000:50000:60000,0,60000 +//-- WL_SIENNAEXECRATE // Duration of the status for this skill appears to be hard coded. Fix later???? +2207,2000,2000,0,10000:12000:14000:16000:18000,0,0 + +//-- WL_STASIS // Duration for the status will need to be hard coded soon to make stats reduce the duration. +2209,4000,2000,0,20000:30000:40000:50000:60000,0,180000:190000:200000:210000:220000 +//-- WL_DRAINLIFE +2210,5000,0,0,0,0,2000 +//-- WL_CRIMSONROCK //CHECK Whats duration 1 for? +2211,6000,2000,0,3000:4000:5000:6000:7000,0,5000 +//-- WL_HELLINFERNO +2212,4000,1000,0,20000:30000:40000:50000:60000,0,0 +//-- WL_COMET //CHECK Is burning on duration 1 correct? +2213,11000:12500:14000:15500:17000,5000,0,20000,0,180000 +//-- WL_CHAINLIGHTNING //CHECK Whats duration 1 used for? +2214,4500:5000:5500:6000:6500,3000,0,1000,0,0 + +//-- WL_EARTHSTRAIN //CHECK What is duration 2 used for? +2216,3000:4000:5000:6000:7000,1000,0,500,60000,10000 +//-- WL_TETRAVORTEX //CHECK Duration 1 might be correct? +2217,6000:7000:8000:9000:10000,2000,0,20000,0,15000 + +//-- WL_SUMMONFB +2222,2000,0,0,30000:40000:50000:60000:70000,0,0 +//-- WL_SUMMONBL +2223,2000,0,0,30000:40000:50000:60000:70000,0,0 +//-- WL_SUMMONWB +2224,2000,0,0,30000:40000:50000:60000:70000,0,0 + +//-- WL_SUMMONSTONE +2229,2000,0,0,30000:40000:50000:60000:70000,0,0 + +//-- WL_READING_SB //CHECK Is duration 1 how long the spell will be stored for? +2231,4000,500,0,30000,0,5000 +//========================================== + +//===== Ranger ============================= +//-- RA_ARROWSTORM +2233,2500,0,0,0,0,3000 +//-- RA_FEARBREEZE +2234,2000,0,0,60000:90000:120000:150000:180000,0,0 + +//-- RA_AIMEDBOLT +2236,5000,1000,0,0,0,0 +//-- RA_DETONATOR //CHECK Is this timer needed for this skill at all??? +2237,0,0,0,1000,0,0 +//-- RA_ELECTRICSHOCKER //CHECK Is duration 1 and 2 what I think it is? +2238,0,0,0,15000,20000,0 +//-- RA_CLUSTERBOMB //CHECK Thinking the same for this one too. +2239,0,0,0,15000,0,0 +//-- RA_WUGMASTERY +2240,0,1000,0,0,0,0 +//-- RA_WUGRIDER +2241,0,500,0,0,0,0 +//-- RA_WUGDASH +2242,0,2000,0,0,0,0 + +//-- RA_WUGBITE //CHECK Its found that the no movement duration is bugged. Keeping this at 10 sec for now. +2244,0,2000,0,10000,0,5000 + +//-- RA_SENSITIVEKEEN +2246,0,3000,0,0,0,0 +//-- RA_CAMOUFLAGE +2247,0,0,0,10000,0,0 + +//-- RA_MAGENTATRAP //CHECK Duration 1 and 2 should be correct? +2249,0,2000,0,15000,10000,0 +//-- RA_COBALTTRAP +2250,0,2000,0,15000,10000,0 +//-- RA_MAIZETRAP +2251,0,2000,0,15000,10000,0 +//-- RA_VERDURETRAP +2252,0,2000,0,15000,10000,0 +//-- RA_FIRINGTRAP +2253,0,0,0,15000,25000,0 +//-- RA_ICEBOUNDTRAP +2254,0,0,0,15000,25000,0 +//========================================== + +//===== Mechanic =========================== +//-- NC_BOOSTKNUCKLE +2256,1000:1200:1400:1600:1800,0,0,0,0,0 +//-- NC_PILEBUNKER +2257,0,2000,0,0,0,5000 +//-- NC_VULCANARM +2258,0,500:300:100,0,0,0,0 +//-- NC_FLAMELAUNCHER +2259,1500:1900:2300,1500:1000:500,0,7000:14000:21000,0,0 +//-- NC_COLDSLOWER //CHECK Are freezing and frozen durations correct? +2260,1000,1000:2000:3000,0,5000:10000:15000,10000:15000:20000,0 +// -- NC_ARMSCANNON +2261,1400:1600:1800,500:1000:2000,0,0,0,0 +//-- NC_ACCELERATION +2262,0,0,0,30000:60000:90000,0,0 +//-- NC_HOVERING +2263,0,0,0,30000,0,0 +//-- NC_F_SIDESLIDE +2264,0,500,0,0,0,0 +//-- NC_B_SIDESLIDE +2265,0,500,0,0,0,0 + +//-- NC_SELFDESTRUCTION +2267,3500:3000:2500,0,0,0,0,0 +//-- NC_SHAPESHIFT +2268,2000,2000,0,300000,0,0 +//-- NC_EMERGENCYCOOL +2269,0,500,0,0,0,5000 +//-- NC_INFRAREDSCAN +2270,1000,500,0,10000,0,15000 +//-- NC_ANALYZE +2271,1000,1000,0,20000,0,0 +//-- NC_MAGNETICFIELD +2272,500:1000:1500,0,0,15000,0,300000 +//-- NC_NEUTRALBARRIER +2273,500:1000:1500,0,0,30000:45000:60000,0,120000 +//-- NC_STEALTHFIELD +2274,500:1000:1500,0,0,15000:20000:25000,0,120000 +//-- NC_REPAIR +2275,500,1000,0,0,0,0 + +//-- NC_AXEBOOMERANG +2278,0,0,0,0,0,5000 +//-- NC_POWERSWING //CHECK Duration 1 is stun? +2279,0,1000,0,3000,0,0 +//-- NC_AXETORNADO +2280,0,500,0,0,0,4000:3500:3000:2500:2000 +//-- NC_SILVERSNIPER +2281,1800:1600:1400:1200:1000,0,0,10000:15000:20000:25000:30000,0,0 +//-- NC_MAGICDECOY +2282,1800:1600:1400:1200:1000,0,0,10000:15000:20000:25000:30000,0,0 +//-- NC_DISJOINT +2283,2000,0,0,0,0,0 +//========================================== + +//===== Shadow Chaser ====================== +//-- SC_FATALMENACE +2284,0,500,0,0,0,0 +//-- SC_REPRODUCE //CHECK Does a duration limit still exist, or it just stays on until reused? +2285,0,1000,0,60000,0,0 +//-- SC_AUTOSHADOWSPELL +2286,6000:5600:5200:4800:4400:4000:3600:3200:2800:2400,0,0,60000:80000:100000:120000:140000:160000:180000:200000:220000:300000,0,0 +//-- SC_SHADOWFORM +2287,0,1000,0,30000:40000:50000:60000:70000,0,0 +//-- SC_TRIANGLESHOT +2288,1000,500,0,0,0,0 +//-- SC_BODYPAINT //CHECK Whats duration 2 do? +2289,0,1000,0,5000:7000:9000:11000:13000,5000,2000 +//-- SC_INVISIBILITY //CHECK Is duration 1 needed for this or it lasts until your out of SP? +2290,1000,1000,0,20000,0,300000 +//-- SC_DEADLYINFECT +2291,0,1000,0,10000:15000:20000:25000:30000,0,2000 +//-- SC_ENERVATION +2292,2000,1000,0,10000:15000:20000,0,2000 +//-- SC_GROOMY +2293,2000,1000,0,10000:15000:20000,0,2000 +//-- SC_IGNORANCE +2294,2000,1000,0,10000:15000:20000,0,2000 +//-- SC_LAZINESS +2295,2000,1000,0,10000:15000:20000,0,2000 +//-- SC_UNLUCKY +2296,2000,1000,0,10000:15000:20000,0,2000 +//-- SC_WEAKNESS +2297,2000,1000,0,10000:15000:20000,0,2000 +//-- SC_STRIPACCESORY +2298,1000,1000,0,60000:70000:80000:90000:100000,0,0 +//-- SC_MANHOLE +2299,1000,2000,0,5000:1000:15000,5000:1000:15000,0 +//-- SC_DIMENSIONDOOR +2300,1000,2000,0,4000:8000:12000,0,0 +//-- SC_CHAOSPANIC +2301,2000,2000,0,5000:10000:15000,30000,0 +//-- SC_MAELSTROM +2302,2000,2000,0,7000:14000:21000,0,0 +//-- SC_BLOODYLUST +2303,2000,2000,0,10000:20000:30000,30000,0 +//-- SC_FEINTBOMB +2304,1000,0,0,1000,0,5000 +//========================================== + +//==== Royal Guard skills ================== +//-- LG_CANNONSPEAR +2307,0,0,0,0,0,2000 + +//-- LG_TRAMPLE +2309,0,1000,0,0,0,0 +//-- LG_SHIELDPRESS +2310,0,0,0,5500:6000:6500:7000:7500,0,2000 +//-- LG_REFLECTDAMAGE +2311,0,0,0,300000,0,0 +//-- LG_PINPOINTATTACK //CHECK Whats duration 1 for? +2312,0,1000,0,5000,0,5000 +//-- LG_FORCEOFVANGUARD +2313,1000,1000,0,120000,0,0 +//-- LG_RAGEBURST +2314,0,3000,0,0,0,0 +//-- LG_SHIELDSPELL //CHECK Shound spells the shield casts use the original duration of that skill? +2315,1000,1000,0,3000:30000:30000,0,2000 +//-- LG_EXEEDBREAK +2316,5000:5500:6000:6500:7000,1000,0,300000,0,0 +//-- LG_OVERBRAND +2317,500,2000,0,0,0,0 +//-- LG_PRESTIGE +2318,3000,0,0,30000:45000:60000:75000:90000,0,60000 +//-- LG_BANDING +2319,0,0,0,-1,2000:4000:6000:8000:10000,0 +//-- LG_MOONSLASHER +2320,1000,1000,0,0,0,6000:5000:4000:3000:2000 +//-- LG_RAYOFGENESIS +2321,2500:3000:3500:4000:4500,2000,0,10000,0,5000 +//-- LG_PIETY +2322,3000:2500:2000:1500:1000,0,0,60000:80000:100000:120000:140000,0,0 +//-- LG_EARTHDRIVE +2323,1000,1000,0,3000:6000:9000:12000:15000,0,7000:6000:5000:4000:3000 +//-- LG_HESPERUSLIT +2324,1000,3000,0,0,0,20000 +//-- LG_INSPIRATION +2325,3000,2000,0,30000:45000:60000:75000:90000,0,540000:480000:420000:360000:300000 +//========================================== + +//===== Sura Skills ======================== +//-- SR_DRAGONCOMBO //CHECK Is stun on duration 1 correct? +2326,0,0,0,3000,0,0 +//-- SR_SKYNETBLOW +2327,0,500,0,0,0,0 +//-- SR_EARTHSHAKER //CHECK Duration 1 is correct, but is the stun working? +2328,0,0,0,1000:2000:2000:3000:3000,0,3000 +//-- SR_FALLENEMPIRE //CHECK The immoble is working? +2329,0,0,0,500:1000:1500:2000:2500,0,0 +//-- SR_TIGERCANNON +2330,1100:1200:1300:1400:1500:1600:1700:1800:1900:2000,1000,0,0,0,5000 + +//-- SR_RAMPAGEBLASTER +2332,0,1000,0,0,0,10000 +//-- SR_CRESCENTELBOW +2333,0,1000,0,10000:15000:20000:25000:30000,0,5000 +//-- SR_CURSEDCIRCLE +2334,0,1000,0,3000:4000:5000:6000:7000,0,10000 +//-- SR_LIGHTNINGWALK +2335,0,1000,0,10000:15000:20000:25000:30000,0,5000 +//-- SR_KNUCKLEARROW +2336,0,1000,0,0,0,0 +//-- SR_WINDMILL +2337,1000,500,0,0,0,3000 +//-- SR_RAISINGDRAGON //CHECK Whats the set 5 seconds in the last column for? +2338,0,1000,0,30000:45000:60000:75000:90000:105000:120000:135000:150000:165000,5000,30000 + +//-- SR_ASSIMILATEPOWER +2340,0,1000,0,0,0,5000 +//-- SR_POWERVELOCITY +2341,2000,0,0,0,0,0 + +//-- SR_GATEOFHELL +2343,1000:1200:1400:1600:1800:2000:2200:2400:2600:2800,100:200:300:400:500:600:700:800:900:1000,0,0,0,5000 +//-- SR_GENTLETOUCH_QUIET +2344,0,0,0,5000:7000:9000:11000:13000,0,1000:1500:2000:2500:3000 +//-- SR_GENTLETOUCH_CURE +2345,0,1000,0,0,0,0 +//-- SR_GENTLETOUCH_ENERGYGAIN //CHECK Desc shows these durations. Are they good as is? +2346,1000,1000,0,60000:120000:180000:240000:300000,0,0 +//-- SR_GENTLETOUCH_CHANGE +2347,1000,1000,0,60000:120000:180000:240000:300000,0,0 +//-- SR_GENTLETOUCH_REVITALIZE +2348,1000,1000,0,60000:120000:180000:240000:300000,0,0 +//========================================== + +//==== Wanderer skills ===================== +//-- WA_SWING_DANCE +2350,1000,2000,0,60000,0,0 +//-- WA_SYMPHONY_OF_LOVER +2351,1000,2000,0,60000,0,0 +//-- WA_MOONLIT_SERENADE +2352,1000,2000,0,60000,0,0 +//========================================== + +//==== Minstresl skills ==================== +//-- MI_RUSH_WINDMILL +2381,1000,2000,0,60000,0,0 +//-- MI_ECHOSONG +2382,1000,2000,0,60000,0,0 +//-- MI_HARMONIZE +2383,1000,1000,0,60000,0,5000 +//========================================== + +//==== Minstrel/Wanderer skills ============ +//-- WM_METALICSOUND +2413,1000:1500:2000:2500:3000,1000,0,0,0,2000:2500:3000:3500:4000 +//-- WM_REVERBERATION +2414,1100:1200:1300:1400:1500,1000,0,9000:10000:11000:12000:13000,0,0 + +//-- WM_DOMINION_IMPULSE +2417,0,1000,0,0,0,0 +//-- WM_SEVERE_RAINSTORM +2418,2000:2500:3000:3500:4000,1000,0,900:1500:2100:2700:3000,0,5000 +//-- WM_POEMOFNETHERWORLD +2419,3000,0,0,9000:11000:13000:15000:17000,8000:10000:12000:14000:16000,0 +//-- WM_VOICEOFSIREN +2420,2000:2200:2400:2600:2800,1000,0,15000:18000:21000:24000:27000,0,5000 +//-- WM_DEADHILLHERE +2421,4000:3500:3000:2500:2000,1000,0,0,0,0 +//-- WM_LULLABY_DEEPSLEEP +2422,3000,1000,0,12000:14000:16000:18000:20000,0,10000 +//-- WM_SIRCLEOFNATURE +2423,2000,1000,0,60000,0,15000 +//-- WM_RANDOMIZESPELL +2424,0,1000,0,0,0,3000 +//-- WM_GLOOMYDAY +2425,1500,1000,0,30000:45000:60000:75000:90000,0,3000 +//-- WM_GREAT_ECHO +2426,2500:2700:2900:3100:3300,1000,0,0,0,10000 +//-- WM_SONG_OF_MANA +2427,1500,1000,0,30000:60000:90000:120000:150000,0,90000 +//-- WM_DANCE_WITH_WUG +2428,2000:2500:3000:3500:4000,1000,0,30000:60000:90000:120000:150000,0,90000 +//-- WM_SOUND_OF_DESTRUCTION +2429,500:1000:1500:2000:2500,1000,0,0,0,20000 +//-- WM_SATURDAY_NIGHT_FEVER +2430,2000:3000:4000:5000:6000,1000,0,20000:30000:40000:50000:60000,3000,180000 +//-- WM_LERADS_DEW +2431,1500,1000,0,20000:30000:40000:50000:60000,0,180000 +//-- WM_MELODYOFSINK +2432,1500,1000,0,20000:30000:40000:50000:60000,0,180000 +//-- WM_BEYOND_OF_WARCRY +2433,1500,1000,0,20000:30000:40000:50000:60000,0,180000 +//-- WM_UNLIMITED_HUMMING_VOICE +2434,1500,1000,0,20000:30000:40000:50000:60000,0,180000 +//========================================== + +//==== Sorcerer skills ===================== +//-- SO_FIREWALK //CHECK Duration 2 needs to be added for the PROPERTYWALK status ID. Ask me for more info. [Rytech] +2443,1000,1000,0,12000,0,0 +//-- SO_ELECTRICWALK //CHECK Duration 2 needs to be added for the PROPERTYWALK status ID. Ask me for more info. [Rytech] +2444,1000,1000,0,12000,0,0 +//-- SO_SPELLFIST +2445,0,1000,0,20000:25000:30000:35000:40000,0,0 +//-- SO_EARTHGRAVE +2446,2200:2400:2600:2800:3000,1000,0,500,8000:11000:14000:17000:20000,5000 +//-- SO_DIAMONDDUST +2447,5500:6000:6500:7000:7500,1000,0,500,12000:14000:16000:18000:20000,5000 +//-- SO_POISON_BUSTER +2450,2000:3000:4000:5000:6000,1000,0,0,0,2000 +//-- SO_PSYCHIC_WAVE +2449,9000:9900:10800:11700:12600,1000,0,1200:1700:2200:2700:3200,0,5000 +//-- SO_CLOUD_KILL +2450,3300:3500:3700:3900:4100,1000,0,8000:10000:12000:14000:16000,10000:15000:20000:25000:30000,5000 +//-- SO_STRIKING +2451,3000,1000,0,60000,0,2000 +//-- SO_WARMER +2452,1700:1900:2100:2300:2500,1000,0,40000:45000:50000:55000:60000,30000,60000 +//-- SO_VACUUM_EXTREME //CHECK Whats duration 2 used for? Is it part of holding the player in place until duration 1 ends? +2453,1000:1500:2000:2500:3000,1000,0,4000:6000:8000:10000:12000,1000,5000 +//-- SO_VARETYR_SPEAR //CHECK Duration 2 is used for the stun? +2454,1700:1900:2100:2300:2500,1000,0,0,3000,2000 +//-- SO_ARULLO +2455,1500:2000:2500:3000:3500,1000,0,8000:10000:12000:14000:16000,0,5000:6000:7000:8000:9000 +//-- SO_EL_CONTROL +2456,2000,0,0,0,0,5000 +//-- SO_SUMMON_AGNI //CHECK Yoyo says the cooldown is 5 seconds. Need to confirm. +2457,3000:4000:5000,0,0,600000:900000:1200000,0,60000 +//-- SO_SUMMON_AQUA //CHECK Yoyo says the cooldown is 5 seconds. Need to confirm. +2458,3000:4000:5000,0,0,600000:900000:1200000,0,60000 +//-- SO_SUMMON_VENTUS //CHECK Yoyo says the cooldown is 5 seconds. Need to confirm. +2459,3000:4000:5000,0,0,600000:900000:1200000,0,60000 +//-- SO_SUMMON_TERA //CHECK Yoyo says the cooldown is 5 seconds. Need to confirm. +2460,3000:4000:5000,0,0,600000:900000:1200000,0,60000 +//-- SO_EL_ACTION +2461,0,0,0,0,0,5000 +//-- SO_EL_ANALYSIS +2462,2000,0,0,0,0,0 + +//-- SO_EL_CURE +2464,2000,1000,0,0,0,0 +//-- SO_FIRE_INSIGNIA +2465,2000,0,0,60000,0,60000 +//-- SO_WATER_INSIGNIA +2466,2000,0,0,60000,0,60000 +//-- SO_WIND_INSIGNIA +2467,2000,0,0,60000,0,60000 +//-- SO_EARTH_INSIGNIA +2468,2000,0,0,60000,0,60000 +//========================================== + +//==== Genetic skills ====================== +//-- GN_CART_TORNADO //CHECK Duration 1 used for stun? +2476,0,500,0,5000,0,0:500:1000:1500:2000 +//-- GN_CARTCANNON +2477,1000:1500:2000:2500:3000,500,0,0,0,0 +//-- GN_CARTBOOST +2478,1500,500,0,90000,0,0 +//-- GN_THORNS_TRAP +2479,1500,500,0,10000:12000:14000:16000:18000,20000,0 +//-- GN_BLOOD_SUCKER +2480,1500,500,0,20000:22000:24000:26000:28000,0,0 +//-- GN_SPORE_EXPLOSION +2481,1500,500,0,2000:2000:3000:3000:4000,0,5000 +//-- GN_WALLOFTHORN +2482,1500,500,0,10000:11000:12000:13000:14000,0,5000 +//-- GN_CRAZYWEED //CHECK Will need to recheck this skill later if durations needs to be set. +2483,3000:3500:4000:4500:5000:5500:6000:6500:7000:7500,500,0,0,0,5000 + +//-- GN_DEMONIC_FIRE //CHECK Is duration 2 the burning? +2485,3000:3500:4000:4500:5000,500,0,10000:12000:14000:16000:18000,10000,5000 +//-- GN_FIRE_EXPANSION +2486,2000,500,0,0,0,0 +//-- GN_FIRE_EXPANSION_SMOKE_POWDER +2487,0,0,0,10000:12000:14000:16000:18000,0,0 +//-- GN_FIRE_EXPANSION_TEAR_GAS +2488,0,0,0,10000:12000:14000:16000:18000,0,0 + +//-- GN_HELLS_PLANT +2490,3000:3500:4000:4500:5000,500,0,40000,0,0 +//-- GN_HELLS_PLANT_ATK //CHECK Guessing durations 1 and 2 are for stun and bleeding. +2491,0,0,0,6000,16000,0 +//-- GN_MANDRAGORA +2492,1000,500,0,30000,0,10000 +//-- GN_SLINGITEM //CHECK Whats durations 1 and 2 used for? +2493,0,0,0,77000,10000,1000 + +//-- GN_SLINGITEM_RANGEMELEEATK //CHECK Whats duration 1 used for? +2498,0,0,0,3000,0,0 +//========================================== + +//===== Extra 3rd Class Skills ============= +//-- AB_SECRAMENT +2515,2000,500,0,60000:90000:120000:150000:180000,0,0 + +//-- SR_HOWLINGOFLION //CHECK Is duration 1 correct for fear? +2517,1500,0,0,10000,0,10000 +//-- SR_RIDEINLIGHTNING +2518,0,200,0,0,0,1000 +//========================================== + +//===== Misc. Skills ======================= +//-- ALL_ODINS_RECALL +2533,10000,0,0,0,0,300000 +//-- RETURN_TO_ELDICASTES +2534,2000,0,0,0,2000,300000 + +//-- ALL_GUARDIAN_RECALL +//2536,2000,0,0,0,2000,300000 //========================================== //===== Homunculus Skills ================== //-- HLIF_HEAL -8001,0,2000,0,0,0 +8001,0,2000,0,0,0,0 //-- HLIF_AVOID -8002,0,35000,0,40000:35000:30000:25000:20000,0 +8002,0,35000,0,40000:35000:30000:25000:20000,0,0 //-- HLIF_CHANGE -8004,0,600000:900000:1200000,0,60000:120000:180000,0 +8004,0,600000:900000:1200000,0,60000:120000:180000,0,0 //-- HAMI_CASTLE -8005,0,0,0,0,60000:70000:80000:90000:129000 +8005,0,0,0,0,60000:70000:80000:90000:129000,0 //-- HAMI_DEFENCE -8006,0,0,0,40000:35000:30000:25000:20000,0 +8006,0,0,0,40000:35000:30000:25000:20000,0,0 //-- HAMI_BLOODLUST -8008,0,0,0,60000:180000:300000,300000:600000:900000 +8008,0,0,0,60000:180000:300000,300000:600000:900000,0 //-- HFLI_MOON -8009,0,0,1000,0,0 +8009,0,0,1000,0,0,0 //-- HFLI_FLEET -8010,0,0,0,60000:55000:50000:45000:40000,60000:70000:80000:90000:120000 +8010,0,0,0,60000:55000:50000:45000:40000,60000:70000:80000:90000:120000,0 //-- HFLI_SPEED -8011,0,0,0,60000:55000:50000:45000:40000,60000:70000:80000:90000:120000 +8011,0,0,0,60000:55000:50000:45000:40000,60000:70000:80000:90000:120000,0 //-- HVAN_CAPRICE -8013,0,1000:1200:1400:1600:1800,0,0,0 +8013,0,1000:1200:1400:1600:1800,0,0,0,0 //-- HVAN_CHAOTIC -8014,0,1000,1000,0,0 +8014,0,1000,1000,0,0,0 //-- HVAN_EXPLOSION -8016,0,0,1000,0,0 +8016,0,0,1000,0,0,0 +//========================================== + +//===== Mutated Homunculus Skills ========== CHECK - Need Aftercast and Cooldown times for these skills [Rytech] +//-- MH_SUMMON_LEGION +8018,2000,0,0,20000:30000:40000:50000:60000,0,0 +//-- MH_NEEDLE_OF_PARALYZE = Whats the duration of the paralyze status? [Rytech] +8019,1500,0,0,0,0,0 +//-- MH_POISON_MIST +8020,1000:1200:1400:1600:1800,0,0,12000:14000:16000:18000:20000,0,0 +//-- MH_PAIN_KILLER +8021,2000,0,0,20000:30000:40000:50000:60000,0,0 +//-- MH_LIGHT_OF_REGENE +8022,1600:1400:1200:1000:800,0,0,360000:420000:480000:540000:600000,0,0 +//-- MH_OVERED_BOOST +8023,1000,0,0,30000:45000:60000:75000:90000,0,0 +//-- MH_ERASER_CUTTER +8024,1000:1500:2000:2500:3000,0,0,0,0,0 +//-- MH_XENO_SLASHER - CHECK Whats the duration of bleeding status? [Rytech] +8025,2000:3000:4000:5000:6000,0,0,500,0,0 +//-- MH_SILENT_BREEZE +8026,2000,0,0,9000:12000:15000:18000:21000,0,0 +//-- MH_STYLE_CHANGE +//8027,0,0,0,0,0,0,0 +//-- MH_SONIC_CRAW +//8028,0,0,0,0,0,0,0 +//-- MH_SILVERVEIN_RUSH +//8029,0,0,0,0,0,0,0 +//-- MH_MIDNIGHT_FRENZY +//8030,0,0,0,0,0,0,0 +//-- MH_STAHL_HORN - CHECK Stun duration is the same as regular stun? [Rytech] +8031,1000,0,0,0,0,0 +//-- MH_GOLDENE_FERSE +8032,1000:1200:1400:1600:1800,0,0,30000:45000:60000:75000:90000,0,0 +//-- MH_STEINWAND +8033,1000,0,0,30000:45000:60000:75000:90000,0,0 +//-- MH_HEILIGE_STANGE +8034,2000,0,0,0,0,0 +//-- MH_ANGRIFFS_MODUS +8035,200:400:600:800:1000,0,0,30000:45000:60000:75000:90000,0,0 +//-- MH_TINDER_BREAKER +//8036,0,0,0,0,0,0,0 +//-- MH_CBC +//8037,0,0,0,0,0,0,0 +//-- MH_EQC +//8038,0,0,0,0,0,0,0 +//-- MH_MAGMA_FLOW +8039,4000,0,0,30000:45000:60000:75000:90000,0,0 +//-- MH_GRANITIC_ARMOR +8040,6000:5500:5000:4500:4000,0,0,0,0,0 +//-- MH_LAVA_SLIDE +8041,6000:5500:5000:4500:4000,0,0,12000:14000:16000:18000:20000,0,0 +//-- MH_PYROCLASTIC +8042,6000:5500:5000:4500:4000,0,0,60000:90000:120000:150000:180000,0,0 +//-- MH_VOLCANIC_ASH +8043,5000:4500:4000:3500:3000,0,0,12000:14000:16000:18000:20000,0,0 //========================================== //===== Mercenary Skills =================== //-- MS_MAGNUM -8202,0,0,0,2000,10000 +8202,0,0,2000,2000,10000,0 //-- KN_BOWLINGBASH -8203,700,0,0,0,0 +8203,700,0,0,0,0,0 //-- LK_PARRYING -8204,0,0,0,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000,0 +8204,0,0,0,15000:20000:25000:30000:35000:40000:45000:50000:55000:60000,0,0 //-- CR_REFLECTSHIELD -8205,0,0,0,300000,0 +8205,0,0,0,300000,0,0 //-- MS_BERSERK -8206,0,0,0,300000,15000 +8206,0,0,0,300000,15000,0 //-- MA_DOUBLE -8207,0,0,0,100,0 +8207,0,0,0,100,0,0 //-- MA_SHOWER -8208,0,0,0,100,0 +8208,0,0,0,100,0,0 //-- MA_SKIDTRAP -8209,0,0,0,300000:240000:180000:120000:60000,0 +8209,0,0,0,300000:240000:180000:120000:60000,0,0 //-- MA_LANDMINE -8210,0,0,0,200000:160000:120000:80000:40000,5000 +8210,0,0,0,200000:160000:120000:80000:40000,5000,0 //-- MA_SANDMAN -8211,0,0,0,150000:120000:90000:60000:30000,12000:14000:16000:18000:20000 +8211,0,0,0,150000:120000:90000:60000:30000,12000:14000:16000:18000:20000,0 //-- MA_FREEZINGTRAP -8212,0,0,0,150000:120000:90000:60000:30000,3000:6000:9000:12000:15000 +8212,0,0,0,150000:120000:90000:60000:30000,3000:6000:9000:12000:15000,0 //-- MA_CHARGEARROW -8214,1500,0,0,0,0 +8214,1500,0,0,0,0,0 //-- MA_SHARPSHOOTING -8215,2000,1500,0,0,0 +8215,2000,1500,0,0,0,0 //-- ML_BRANDISHSPEAR -8217,700,0,0,0,0 +8217,700,0,0,0,0,0 //-- ML_SPIRALPIERCE -8218,300:500:700:900:1000,1200:1400:1600:1800:2000,0,0,1000 +8218,300:500:700:900:1000,1200:1400:1600:1800:2000,0,0,1000,0 //-- ML_DEFENDER -8219,0,800,0,180000,0 +8219,0,800,0,180000,0,0 //-- ML_AUTOGUARD -8220,0,0,0,300000,0 +8220,0,0,0,300000,0,0 //-- ML_DEVOTION -8221,3000,0,0,0,30000:45000:60000:75000:90000 +8221,3000,0,0,0,30000:45000:60000:75000:90000,0 //-- MER_MAGNIFICAT -8222,4000,2000,0,30000:45000:60000:75000:90000,0 +8222,4000,2000,0,30000:45000:60000:75000:90000,0,0 //-- MER_QUICKEN -8223,0,0,0,30000:60000:90000:120000:150000:180000:210000:240000:270000:300000,0 +8223,0,0,0,30000:60000:90000:120000:150000:180000:210000:240000:270000:300000,0,0 //-- MER_SIGHT -8224,0,0,0,10000,0 +8224,0,0,0,10000,0,0 //-- MER_CRASH -8225,1000,2000,0,0,5000 +8225,1000,2000,0,0,5000,0 //-- MER_PROVOKE -8232,0,0,0,30000,0 +8232,0,0,0,30000,0,0 //-- MER_DECAGI -8234,1000,1000,0,40000:50000:60000:70000:80000:90000:100000:110000:120000:130000,0 +8234,1000,1000,0,40000:50000:60000:70000:80000:90000:100000:110000:120000:130000,0,0 //-- MER_SCAPEGOAT -8235,3000,0,0,0,0 +8235,3000,0,0,0,0,0 //-- MER_LEXDIVINA -8236,0,3000,0,30000:35000:40000:45000:50000:60000:60000:60000:60000:60000,0 +8236,0,3000,0,30000:35000:40000:45000:50000:60000:60000:60000:60000:60000,0,0 //-- MER_KYRIE -8238,2000,2000,0,120000,0 +8238,2000,2000,0,120000,0,0 //-- MER_BLESSING -8239,0,0,0,60000:80000:100000:120000:140000:160000:180000:200000:220000:240000,0 +8239,0,0,0,60000:80000:100000:120000:140000:160000:180000:200000:220000:240000,0,0 //-- MER_INCAGI -8240,1000,1000,0,60000:80000:100000:120000:140000:160000:180000:200000:220000:240000,0 +8240,1000,1000,0,60000:80000:100000:120000:140000:160000:180000:200000:220000:240000,0,0 +//========================================== + +//===== Elemental Skills ======================= +//-- EL_CIRCLE_OF_FIRE +8401,0,0,0,-1,0,0 +//-- EL_FIRE_CLOAK +8402,0,0,0,-1,0,0 +//-- EL_FIRE_MANTLE +8403,0,0,0,15000,0,0 +//-- EL_WATER_SCREEN +8404,0,0,0,-1,0,0 +//-- EL_WATER_DROP +8405,0,0,0,-1,0,0 +//-- EL_WATER_BARRIER +8406,1000,0,0,15000,0,0 +//-- EL_WIND_STEP +8407,0,0,0,-1,0,0 +//-- EL_WIND_CURTAIN +8408,0,0,0,-1,0,0 +//-- EL_ZEPHYR +8409,0,0,0,15000,0,0 +//-- EL_STONE_SHIELD +8411,0,0,0,-1,0,0 +//-- EL_POWER_OF_GAIA +8412,0,0,0,15000,0,0 +//-- EL_PYROTECHNIC +8413,0,0,0,-1,0,0 +//-- EL_HEATER +8414,0,0,0,-1,0,0 +//-- EL_TROPIC +8415,0,0,0,-1,0,0 +//-- EL_AQUAPLAY +8416,0,0,0,-1,0,0 +//-- EL_COOLER +8417,0,0,0,-1,0,0 +//-- EL_CHILLY_AIR +8418,0,0,0,-1,0,0 +//-- EL_GUST +8419,0,0,0,-1,0,0 +//-- EL_BLAST +8420,0,0,0,-1,0,0 +//-- EL_WILD_STORM +8421,0,0,0,-1,0,0 +//-- EL_PETROLOGY +8422,0,0,0,-1,0,0 +//-- EL_CURSED_SOIL +8423,0,0,0,-1,0,0 +//-- EL_UPHEAVAL +8424,0,0,0,-1,0,0 +//-- EL_TIDAL_WEAPON +8433,0,0,0,-1,0,0 +//-- EL_TYPOON_MIS +8437,0,0,0,15000,0,0 +//-- EL_STONE_HAMMER +8439,0,0,0,5000,0,0 +//-- EL_ROCK_CRUSHER +8440,0,0,0,15000,0,0 +//-- EL_ROCK_CRUSHER_ATK +8441,0,0,0,15000,0,0 //========================================== //===== Guild Skills ======================= //-- GD_LEADERSHIP -10006,0,0,0,300000,0 +10006,0,0,0,300000,0,0 //-- GD_GLORYWOUNDS -10007,0,0,0,300000,0 +10007,0,0,0,300000,0,0 //-- GD_SOULCOLD -10008,0,0,0,300000,0 +10008,0,0,0,300000,0,0 //-- GD_HAWKEYES -10009,0,0,0,300000,0 +10009,0,0,0,300000,0,0 //-- GD_BATTLEORDER -10010,0,0,0,60000,300000 +10010,0,0,0,60000,300000,0 //-- GD_REGENERATION -10011,0,0,0,60000,300000 +10011,0,0,0,60000,300000,0 //-- GD_RESTORE -10012,10000,0,0,0,300000 +10012,10000,0,0,0,300000,0 //-- GD_EMERGENCYCALL -10013,5000,0,0,0,300000 +10013,5000,0,0,0,300000,0 //========================================== diff --git a/db/skill_db.txt b/db/skill_db.txt index 2a39740df..eba695928 100644 --- a/db/skill_db.txt +++ b/db/skill_db.txt @@ -124,7 +124,8 @@ 79,9,8,2,6,0,0,10,1:2:3:4:5:6:7:8:9:10,yes,0,0,0,magic,0, PR_MAGNUS,Magnus Exorcismus 80,9,8,2,3,0x20,1:1:1:1:1:2:2:2:2:2:2,10,3:4:5:6:7:8:9:10:11:12:12,yes,0,0x80,5,magic,0, WZ_FIREPILLAR,Fire Pillar 81,0,6,4,3,0,3,10,1,yes,0,0,0,magic,5, WZ_SIGHTRASHER,Sightrasher -//82,9,6,2,3,0,0,10,1,yes,0,0,0,magic,0, WZ_FIREIVY,Fire Ivy +82,9,8,2,4,0,0,10,1:2:3:4:5:6:7:8:9:10,yes,0,0,0,magic,0, WZ_FIREIVY,Fire Ivy +//82,9,6,2,3,0,0,10,1,yes,0,0x200,1,magic,0, WZ_FIREIVY,Fire Ivy 83,9,8,2,3,0,3:3:3:3:3:3:3:3:3:3:14,10,1:1:2:2:3:3:4:4:5:5:15,yes,0,0,0,magic,0, WZ_METEOR,Meteor Storm 84,9,8,1,4,0,0,10,3:4:5:6:7:8:9:10:11:12,yes,0,0,0,magic,2:3:3:4:4:5:5:6:6:7, WZ_JUPITEL,Jupitel Thunder 85,9,8,2,4,0,0,10,-10,yes,0,0,0,magic,0, WZ_VERMILION,Lord of Vermilion @@ -663,27 +664,155 @@ 1018,9,6,1,3,0x1,0,1,1,yes,0,0x1,0,magic,0, SA_ELEMENTFIRE,Elemental Change Fire 1019,9,6,1,4,0x1,0,1,1,yes,0,0x1,0,magic,0, SA_ELEMENTWIND,Elemental Change Wind -// Third Job Skills -//2001,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_ENCHANTBLADE, -//2002,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_SONICWAVE, -//2003,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_DEATHBOUND, -//2004,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_HUNDREDSPEAR, -//2005,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_WINDCUTTER, -//2006,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_IGNITIONBREAK, -//2007,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_DRAGONTRAINING, -//2008,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_DRAGONBREATH, -//2009,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_DRAGONHOWLING, -//2010,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_RUNEMASTERY, -//2011,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_MILLENNIUMSHIELD, -//2012,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_CRUSHSTRIKE, -//2013,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_REFRESH, -//2014,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_GIANTGROWTH, -//2015,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_STONEHARDSKIN, -//2016,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_VITALITYACTIVATION, -//2017,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_STORMBLAST, -//2018,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_FIGHTINGSPIRIT, -//2019,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_ABUNDANCE, -//2020,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RK_PHANTOMTHRUST, +//**** +// RK Rune Knight +//**** +2001,1,6,16,0,0x1,0,5,1,yes,0,0,0,none,0, RK_ENCHANTBLADE,Enchant Blade +2002,7:8:9:10:11,6,1,-1,0,0,5,1,no,0,0,0,weapon,0, RK_SONICWAVE,Sonic Wave +2003,0,6,4,0,0x1,0,10,1,no,0,0,0,weapon,0, RK_DEATHBOUND,Death Bound +2004,1,8,1,-1,0,0,10,-5,no,0,0,0,weapon,0, RK_HUNDREDSPEAR,Hundred Spear +2005,1,6,2,4,0x2,2,5,1,no,0,0,0,weapon,3, RK_WINDCUTTER,Wind Cutter +2006,0,6,4,-1,0x2,5,5,1,no,0,0,0,weapon,0, RK_IGNITIONBREAK,Ignition Break +2007,0,0,0,0,0,0,5,0,no,0,0,0,weapon,0, RK_DRAGONTRAINING,Dragon Training +2008,9,6,2,3,0xC2,1:1:1:2:2:2:3:3:4:4,10,1,no,0,0,0,misc,0, RK_DRAGONBREATH,Dragon Breath //CHECK May have to change this back to a weapon type attack. +2009,0,6,4,0,0x3,3:4:5:6:7,5,1,yes,0,0,0,weapon,0, RK_DRAGONHOWLING,Dragon Howling +2010,0,0,0,0,0,0,10,0,no,0,0,0,none,0, RK_RUNEMASTERY,Rune Mastery +2011,0,6,4,0,0x1,0,1,1,yes,0,0,0,none,0, RK_MILLENNIUMSHIELD,Millenium Shield +2012,1,6,1,-1,0,0x8,1,1,yes,0,0,0,weapon,0, RK_CRUSHSTRIKE,Crush Strike +2013,0,6,4,0,0x1,0,1,1,yes,0,0,0,none,0, RK_REFRESH,Refresh +2014,0,6,4,0,0x1,0,1,1,yes,0,0,0,none,0, RK_GIANTGROWTH,Giant Growth +2015,0,6,4,0,0x1,0,1,1,yes,0,0,0,none,0, RK_STONEHARDSKIN,Stone Hard Skin +2016,0,6,4,0,0x1,0,1,1,yes,0,0,0,none,0, RK_VITALITYACTIVATION,Vitality Activation +2017,0,6,4,-1,0x2,3,1,1,no,0,0,0,weapon,7, RK_STORMBLAST,Storm Blast +2018,0,6,4,0,0x3,-1,1,1,yes,0,0,0,none,0, RK_FIGHTINGSPIRIT,Fighting Spirit //CHECK Is this splash needed? +2019,9,6,4,6,0x1,0,1,1,yes,0,0,0,none,0, RK_ABUNDANCE,Abundance +2020,5:6:7:8:9,6,1,-1,0,0,5,1,yes,0,0,0,weapon,0, RK_PHANTOMTHRUST,Phantom Thrust + +//**** +// WL Warlock +//**** +2201,11,6,16,0,0,0,5,1,yes,0,0,0,magic,0, WL_WHITEIMPRISON,White Imprison +2202,11,8,1,8,0x2,1:1:1:2:2,5,-2,yes,0,0,0,magic,0, WL_SOULEXPANSION,Soul Expansion +2203,0,8,4,1,0x2,13,5,-3:-4:-5:-6:-7,yes,0,0,0,magic,0, WL_FROSTMISTY,Frosty Misty +2204,0,8,4,1,0x2,13,5,-5,yes,0,0,0,magic,0, WL_JACKFROST,Jack Frost +2205,11,6,1,0,0x1,0,5,1,yes,0,0,0,magic,0, WL_MARSHOFABYSS,Marsh of Abyss +2206,0,6,4,0,0x1,0,5,1,yes,0,0,0,magic,0, WL_RECOGNIZEDSPELL,Recognized Spell +2207,7,6,1,2,0x3,1:2:2:3:3,5,1,yes,0,0,0,magic,0, WL_SIENNAEXECRATE,Sienna Execrate +2208,0,0,0,0,0,0,3,0,no,0,0,0,none,0, WL_RADIUS,Radius +2209,0,6,4,0,0x3,9:10:11:12:13,5,1,yes,0,0,0,magic,0, WL_STASIS,Stasis +2210,11,6,1,0,0,0,5,1,yes,0,0,0,magic,0, WL_DRAINLIFE,Drain Life +2211,11,8,1,3,0x2,3,5,-7,yes,0,0,0,magic,3, WL_CRIMSONROCK,Crimson Rock +2212,11,6,1,3,0,0,5,1,yes,0,0,0,magic,0, WL_HELLINFERNO,Hell Inferno +2213,11,8,2,0,0x2,15,5,-20,yes,0,0,0,magic,2, WL_COMET,Comet //CHECK AoE in official code appears to be 15 x 15, yet casting circle is much bigger then that. +2214,11,6,1,0,0,3,5,1,yes,0,0,0,magic,0, WL_CHAINLIGHTNING,Chain Lightning //CHECK Is the splash being used for the target search? +2215,11,6,1,4,0,0,5,1,no,0,0,0,magic,0, WL_CHAINLIGHTNING_ATK,Chain Lightning Attack +2216,3,8,2,2,0,0,5,-6:-7:-8:-9:-10,yes,0,0,0,magic,0, WL_EARTHSTRAIN,Earth Strain +2217,11,6,1,0,0,0,5,1,yes,0,0,0,magic,0, WL_TETRAVORTEX,Tetra Vortex +2218,11,6,1,3,0,0,5,1,no,0,0,0,magic,0, WL_TETRAVORTEX_FIRE,Tetra Vortex Fire +2219,11,6,1,1,0,0,5,1,no,0,0,0,magic,0, WL_TETRAVORTEX_WATER,Tetra Vortex Water +2220,11,6,1,4,0,0,5,1,no,0,0,0,magic,0, WL_TETRAVORTEX_WIND,Tetra Vortex Wind +2221,11,6,1,2,0,0,5,1,no,0,0,0,magic,0, WL_TETRAVORTEX_GROUND,Tetra Vortex Earth +2222,0,6,4,3,0x1,0,5,1,yes,0,0,0,magic,0, WL_SUMMONFB,Summon Fire Ball +2223,0,6,4,4,0x1,0,5,1,yes,0,0,0,magic,0, WL_SUMMONBL,Summon Lightning Ball +2224,0,6,4,1,0x1,0,5,1,yes,0,0,0,magic,0, WL_SUMMONWB,Summon Water Ball +2225,11,6,1,3,0,0,5,1,no,0,0,1,magic,0, WL_SUMMON_ATK_FIRE,Summon Attack Fire //CHECK Summon attack ID's dont appear to have a range. +2226,11,6,1,4,0,0,5,1,no,0,0,1,magic,0, WL_SUMMON_ATK_WIND,Summon Attack Wind +2227,11,6,1,1,0,0,5,1,no,0,0,1,magic,0, WL_SUMMON_ATK_WATER,Summon Attack Water +2228,11,6,1,2,0,0,5,1,no,0,0,1,magic,0, WL_SUMMON_ATK_GROUND,Summon Attack Earth +2229,0,6,4,2,0x1,0,5,1,yes,0,0,0,magic,0, WL_SUMMONSTONE,Summon Stone +2230,11,8,1,0,0,0,2,1,yes,0,0,0,magic,0, WL_RELEASE,Release //CHECK Should it be left to do multi hit or single hit? +2231,0,6,4,0,0x1,0,1,1,yes,0,0,0,magic,0, WL_READING_SB,Reading Spellbook +2232,0,0,0,0,0,0,5,0,no,0,0,0,none,0, WL_FREEZE_SP,Freeze Spell + + +//**** +// GC Guillotine Cross +//**** + +//**** +// AB Arch Bishop +//**** +2038,11,8,1,6,0x2,3,5,-3,yes,0,0,0,magic,0, AB_JUDEX,Judex +2039,0,6,4,0,0x1,0,1,1,yes,0,0,0,magic,0, AB_ANCILLA,Ancilla +2040,11,8,1,6,0,0,10,-10,yes,0,0,0,magic,0, AB_ADORAMUS,Adoramus +2041,0,6,4,6,0x3,3:7:15,3,1,yes,0,0,0,magic,0, AB_CLEMENTIA,Crementia +2042,0,6,4,6,0x3,3:7:15,3,1,yes,0,0,0,magic,0, AB_CANTO,Canto Candidus +2043,0,6,4,6,0x3,3:7:15,3,1,yes,0,0,0,magic,0, AB_CHEAL,Coluceo Heal +2044,11,6,2,6,0x1,0,5,1,yes,0,0,1,magic,0, AB_EPICLESIS,Epiclesis +2045,0,6,4,6,0x3,15,10,1,yes,0,0,0,magic,0, AB_PRAEFATIO,Praefatio +2046,0,6,4,6,0x3,15,10,1,yes,0,0,0,magic,0, AB_ORATIO,Oratio +2047,0,6,4,6,0x3,15,4,1,yes,0,0,0,magic,0, AB_LAUDAAGNUS,Lauda Agnus +2048,0,6,4,6,0x3,15,4,1,yes,0,0,0,magic,0, AB_LAUDARAMUS,Lauda Ramus +2049,0,0,0,0,0,0,10,0,no,0,0,0,none,0, AB_EUCHARISTICA,Eucharistica +2050,11,6,16,6,0x1,0,1,1,yes,0,0,0,magic,0, AB_RENOVATIO,Renovatio +2051,11,6,16,6,0x21,0,5,1,yes,0,0,0,magic,0, AB_HIGHNESSHEAL,Highness Heal //CHECK Info shows this has magic attack. +2052,11,6,1,0,0x1,0,5,1,yes,0,0xA00,0,magic,0, AB_CLEARANCE,Clearance //CHECK Also shows this as a magic attack. Why? +2053,0,6,4,0,0x1,0,5,1,yes,0,0,0,magic,0, AB_EXPIATIO,Expiatio //CHECK Does this also give the buff to party members? +2054,0,6,4,6,0x1,0,10,1,yes,0,0,0,none,0, AB_DUPLELIGHT,Duple Light //CHECK Had issues adding a skill level check to make the % go higher with the skills level. Will do later. +2055,-1,6,1,-1,0,0,10,1,no,0,0,0,weapon,0, AB_DUPLELIGHT_MELEE,Duple Light Melee +2056,-1,6,1,0,0,0,10,1,no,0,0,0,magic,0, AB_DUPLELIGHT_MAGIC,Duple Light Magic +2057,0,6,4,6,0x3,4:5:6:7:8,5,1,yes,0,0,0,magic,0, AB_SILENTIUM,Silentium //CHECk Marked magic attack as well. Hmmmm.... + +2515,11,6,16,0,0x1,0,5,1,yes,0,0,0,magic,0, AB_SECRAMENT,Secrament + +//**** +// RA Ranger +//**** +2233,9,8,1,-1,0x2,2:2:2:2:2:3:3:3:3:4,10,3,yes,0,0,0,weapon,0, RA_ARROWSTORM,Arrow Storm +2234,0,6,4,0,0,0,5,1,yes,0,0,0,none,0, RA_FEARBREEZE,Fear Breeze +2235,0,0,0,0,0,0,10,0,no,0,0,0,none,0, RA_RANGERMAIN,Ranger Main +2236,9,8,1,-1,0,0,10,1,yes,0,0,0,weapon,0, RA_AIMEDBOLT,Aimed Bolt +2237,9,6,2,0,0x3,3,1,1,no,0,0,0,none,0, RA_DETONATOR,Detonator +2238,3,6,2,0,0x3,2,5,1,no,0,0x80,3,misc,0, RA_ELECTRICSHOCKER,Electric Shocker +2239,3,6,2,0,0x42,3,5,1,no,0,0x80,3,misc,0, RA_CLUSTERBOMB,Cluster Bomb +2240,0,6,4,0,0,0,1,1,no,0,0,0,none,0, RA_WUGMASTERY,Warg Mastery +2241,0,6,4,0,0,0,3,1,no,0,0,0,none,0, RA_WUGRIDER,Warg Rider +2242,0,6,4,-1,0x2,1,1,0,no,0,0,0,weapon,0, RA_WUGDASH,Warg Dash +2243,9,6,1,-1,0,0,5,1,no,0,0,0,weapon,0, RA_WUGSTRIKE,Warg Strike +2244,9,6,1,-1,0,0,5,1,no,0,0,0,weapon,0, RA_WUGBITE,Warg Bite +2245,0,0,0,0,0,0,10,0,no,0,0,0,none,0, RA_TOOTHOFWUG,Tooth of Warg +2246,0,6,4,0,0x2,3:4:5:6:7,5,1,no,0,0,0,weapon,0, RA_SENSITIVEKEEN,Sensitive Keen +2247,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0, RA_CAMOUFLAGE,Camouflage +2248,0,0,0,0,0,0,5,0,no,0,0,0,none,0, RA_RESEARCHTRAP,Research Trap +2249,3,6,2,3,0x43,2,1,1,no,0,0x80,1,misc,0, RA_MAGENTATRAP,Magenta Trap +2250,3,6,2,1,0x43,2,1,1,no,0,0x80,1,misc,0, RA_COBALTTRAP,Cobalt Trap +2251,3,6,2,2,0x43,2,1,1,no,0,0x80,1,misc,0, RA_MAIZETRAP,Maize Trap +2252,3,6,2,4,0x43,2,1,1,no,0,0x80,1,misc,0, RA_VERDURETRAP,Verdure Trap +2253,3,6,2,0,0x42,2,5,1,no,0,0x80,2,misc,0, RA_FIRINGTRAP,Firing Trap +2254,3,6,2,0,0x42,2,5,1,no,0,0x80,2,misc,0, RA_ICEBOUNDTRAP,Icebound Trap + +//**** +// NC Mechanic +2255,0,0,0,0,0,0,5,0,no,0,0,0,none,0, NC_MADOLICENCE,Mado License +2256,11,6,1,-1,0,0,5,1,no,0,0,0,weapon,0, NC_BOOSTKNUCKLE,Boost Knuckle +2257,3,6,1,-1,0,0,3,1,no,0,0,0,weapon,0, NC_PILEBUNKER,Pile Bunker +2258,13,6,1,-1,0,0,3,1,no,0,0,0,weapon,0, NC_VULCANARM,Vulcan Arm +2259,5,6,1,3,0,2,3,1,no,0,0,5,weapon,0, NC_FLAMELAUNCHER,Flame Launcher +2260,7,6,2,1,0x2,2:3:4,3,1,no,0,0,0,weapon,0, NC_COLDSLOWER,Cold Slower +2261,7,6,2,-1,0x42,3:2:1,3,1,no,0,0,0,weapon,0, NC_ARMSCANNON,Arm Cannon +2262,0,6,4,0,0x1,0,3,1,no,0,0,0,none,0, NC_ACCELERATION,Acceleration +2263,0,6,4,0,0x1,0,1,1,no,0,0,0,none,0, NC_HOVERING,Hovering +2264,0,6,4,0,0x1,0,1,1,no,0,0,0,none,7, NC_F_SIDESLIDE,Front-Side Slide +2265,0,6,4,0,0x1,0,1,1,no,0,0,0,none,7, NC_B_SIDESLIDE,Back-Side Slide +2266,0,0,0,0,0,0,4,0,no,0,0,0,none,0, NC_MAINFRAME,Mainframe Restructure // Check me. Part of the code notes translated to "The amount of fuel have". +2267,0,6,4,-1,0x42,2:3:4,3,1,no,0,0,0,misc,5, NC_SELFDESTRUCTION,Self Destruction +2268,0,6,4,0,0x1,0,4,1,yes,0,0,0,none,0, NC_SHAPESHIFT,Shape Shift +2269,0,6,4,0,0x1,0,1,1,no,0,0,0,none,0, NC_EMERGENCYCOOL,Emergency Cool +2270,0,6,4,0,0x3,7,1,1,yes,0,0,0,none,0, NC_INFRAREDSCAN,Infrared Scan +2271,9,6,1,0,0x1,0,3,1,yes,0,0,0,none,0, NC_ANALYZE,Analyze +2272,0,6,4,0,0x3,1:2:3,3,1,yes,0,0,0,none,0, NC_MAGNETICFIELD,Magnetic Field +2273,0,6,4,0,0x1,0,3,1,yes,0,0,0,none,0, NC_NEUTRALBARRIER,Neutral Barrier +2274,0,6,4,0,0x1,0,3,1,yes,0,0,0,none,0, NC_STEALTHFIELD,Stealth Field +2275,5,6,16,0,0x1,0,5,1,yes,0,0,0,magic,0, NC_REPAIR,Repair +2276,0,0,0,0,0,0,10,0,no,0,0,0,none,0, NC_TRAININGAXE,Axe Training +2277,0,0,0,0,0,0,5,0,no,0,0,0,none,0, NC_RESEARCHFE,Research Fire/Earth +2278,4:5:6:7:8,6,1,-1,0,0,5,1,no,0,0,0,weapon,2:3:4:5:6, NC_AXEBOOMERANG,Axe Boomerang +2279,1,6,1,-1,0,0,5,1,no,0,0,0,weapon,0, NC_POWERSWING,Power Swing +2280,0,8,4,-1,0x2,2:2:3:3:3,5,-6,no,0,0,0,weapon,0, NC_AXETORNADO,Axe Tornado // Check me. Takes 20 * Skill LV amount of HP each use. +2281,2,6,2,0,0x1,0,5,1,yes,0,0,2,none,0, NC_SILVERSNIPER,FAW - Silver Sniper +2282,2,6,2,0,0x1,0,5,1,yes,0,0,2,none,0, NC_MAGICDECOY,FAW - Magic Decoy //CHECK FIX ME!!!! Wind and Earth stones spawning opposite decoys. +2283,2,6,1,0,0x1,0,1,1,no,0,0,0,none,0, NC_DISJOINT,FAW Removal + //2021,0,0,0,0,0,0,9,0,no,0,0,0,none,0 GC_VENOMIMPRESS, //2022,0,0,0,0,0,0,9,0,no,0,0,0,none,0 GC_CROSSIMPACT, //2023,0,0,0,0,0,0,9,0,no,0,0,0,none,0 GC_DARKILLUSION, diff --git a/db/skill_require_db.txt b/db/skill_require_db.txt index 9e9f385f0..08ea26839 100644 --- a/db/skill_require_db.txt +++ b/db/skill_require_db.txt @@ -89,7 +89,7 @@ 79,0,0,40:42:44:46:48:50:52:54:56:58,0,0,0,99,0,0,none,0,717,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //PR_MAGNUS#マグヌスエクソシズム# 80,0,0,75,0,0,0,99,0,0,none,0,717,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WZ_FIREPILLAR#ファイア?ピラ?# 81,0,0,35:37:39:41:43:45:47:49:51:53,0,0,0,99,0,0,sight,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WZ_SIGHTRASHER#サイトラッシャ?# - +82,0,0,12:14:16:18:20:22:24:26:28:30,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WZ_FIREIVY#ユピテルサンダ?# 83,0,0,20:24:30:34:40:44:50:54:60:64,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WZ_METEOR#メテオスト?ム# 84,0,0,20:23:26:29:32:35:38:41:44:47,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WZ_JUPITEL#ユピテルサンダ?# 85,0,0,60:64:68:72:76:80:84:88:92:96,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WZ_VERMILION#ロ?ドオブヴァ?ミリオン# @@ -454,6 +454,164 @@ 1018,0,0,30,0,0,0,99,0,0,none,0,12114,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //SA_ELEMENTFIRE 1019,0,0,30,0,0,0,99,0,0,none,0,12117,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //SA_ELEMENTWIND +//***** +// RK Rune Knight +2001,0,0,40:45:50:55:60,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RK_ENCHANTBLADE#Enchant Blade# +2002,0,0,30:35:40:45:50,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RK_SONICWAVE#Sonic Wave# +2003,0,0,55:60:65:70:75:80:85:90:95:100,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RK_DEATHBOUND#Death Bound# +2004,0,0,60,0,0,0,4:5,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RK_HUNDREDSPEAR#Hundred Spear# +2005,0,0,20:24:28:32:36,0,0,0,1:2:3:4:5,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RK_WINDCUTTER#Wind Cutter# +2006,0,0,35:40:45:50:55,0,0,0,1:2:3:4:5,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RK_IGNITIONBREAK#Ignition Break# +2008,0,0,30:35:40:45:50:55:60:65:70:75,0,0,0,99,0,0,dragon,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RK_DRAGONBREATH#Dragon Breath# +2009,0,0,70,0,0,0,99,0,0,dragon,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RK_DRAGONHOWLING#Dragon Howling# +2011,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RK_MILLENNIUMSHIELD#Millenium Shield# +2012,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RK_CRUSHSTRIKE#Crush Strike# +2013,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RK_REFRESH#Refresh# +2014,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RK_GIANTGROWTH#Giant Growth# +2015,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RK_STONEHARDSKIN#Stone Hard Skin# +2016,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RK_VITALITYACTIVATION#Vitality Activation# +2017,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RK_STORMBLAST#Storm Blast# +2018,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RK_FIGHTINGSPIRIT#Fighting Spirit# +2019,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RK_ABUNDANCE#Abundance# +2020,0,0,15:18:21:24:27,0,0,0,4:5,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RK_PHANTOMTHRUST#Phantom Thrust# + +//**** +// GC Guilottine Cross +2021,0,0,12:16:20:24:28,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GC_VENOMIMPRESS#Venom Impress# +2022,0,0,25,0,0,0,99,0,0,move_enable,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GC_CROSSIMPACT#Cross Impact# //CHECK Is this move_enable needed? +2023,0,0,40,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GC_DARKILLUSION#Dark Illusion# + +2025,0,0,10,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GC_CREATENEWPOISON#Create New Poison# +2026,0,0,10,0,0,0,99,0,0,none,0,6128,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GC_ANTIDOTE#Antidote# +2027,0,0,20:24:28:32:36,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GC_POISONINGWEAPON#Poisoning Weapon# +2028,0,0,40:36:32:28:24,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GC_WEAPONBLOCKING#Weapon Blocking# +2029,0,0,5:8:11:14:17,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GC_COUNTERSLASH#Counter Slash# +2030,0,0,20,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GC_WEAPONCRUSH#Weapon Crush# +2031,0,0,30:40:50:60:70,0,0,0,99,0,0,poisonweapon,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GC_VENOMPRESSURE#Venom Pressure# +2032,0,0,40,0,0,0,99,0,0,poisonweapon,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GC_POISONSMOKE#Poison Smoke# +2033,0,0,45,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GC_CLOAKINGEXCEED#Cloaking Exceed# +2034,0,0,30,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GC_PHANTOMMENACE#Phantom Menace# +2035,0,0,100,10,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GC_HALLUCINATIONWALK#Hallucination Walk# +2036,0,0,5,0,0,0,16,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GC_ROLLINGCUTTER#Rolling Cutter# +2037,0,0,20:24:28:32:36,0,0,0,16,0,0,rollingcutter,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GC_CROSSRIPPERSLASHER#Cross Ripper Slasher# + + +//**** +// WL Warlock +2201,0,0,50:55:60:65:70,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_WHITEIMPRISON#White Imprison# +2202,0,0,30:35:40:45:50,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_SOULEXPANSION#Soul Expansion# +2203,0,0,40:48:56:64:72,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_FROSTMISTY#Frosty Misty# +2204,0,0,50:60:70:80:90,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_JACKFROST#Jack Frost# +2205,0,0,40:42:44:46:48,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_MARSHOFABYSS#Marsh of Abyss# +2206,0,0,50:60:70:80:90,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_RECOGNIZEDSPELL#Recognized Spell# +2207,0,0,32:34:36:38:40,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_SIENNAEXECRATE#Sienna Execrate# + +2209,0,0,50:60:70:80:90,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_STASIS#Stasis# +2210,0,0,20:24:28:32:36,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_DRAINLIFE#Drain Life# +2211,0,0,60:70:80:90:100,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_CRIMSONROCK#Crimson Rock# +2212,0,0,35:40:45:50:55,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_HELLINFERNO#Hell Inferno# +2213,0,0,240:280:320:360:400,0,0,0,99,0,0,none,0,716,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_COMET#Comet# +2214,0,0,80:90:100:110:120,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_CHAINLIGHTNING#Chain Lightning# +2215,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_CHAINLIGHTNING_ATK#Chain Lightning Attack# +2216,0,0,70:78:86:94:102,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_EARTHSTRAIN#Earth Strain# +2217,0,0,120:150:180:210:240,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_TETRAVORTEX#Tetra Vortex# +2218,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_TETRAVORTEX_FIRE#Tetra Vortex Fire# +2219,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_TETRAVORTEX_WATER#Tetra Vortex Water# +2220,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_TETRAVORTEX_WIND#Tetra Vortex Wind# +2221,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_TETRAVORTEX_GROUND#Tetra Vortex Earth# +2222,0,0,10:12:14:16:18,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_SUMMONFB#Summon Fire Ball# +2223,0,0,10:12:14:16:18,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_SUMMONBL#Summon Lightning Ball# +2224,0,0,10:12:14:16:18,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_SUMMONWB#Summon Water Ball# +2225,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_SUMMON_ATK_FIRE#Summon Attack Fire# +2226,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_SUMMON_ATK_WIND#Summon Attack Wind# +2227,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_SUMMON_ATK_WATER#Summon Attack Water# +2228,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_SUMMON_ATK_GROUND#Summon Attack Earth# +2229,0,0,10:12:14:16:18,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_SUMMONSTONE#Summon Stone# +2230,0,0,3:20,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_RELEASE#Release# +2231,0,0,40,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_READING_SB#Reading Spellbook# +//2232,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //WL_FREEZE_SP#Freeze Spell# (Passive Skill) + + +//**** +// AB Arch Bishop +2038,0,0,20:23:26:29:32,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_JUDEX#Judex# +2039,0,0,30,0,-30,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_ANCILLA#Ancilla# +2040,0,0,20:24:28:32:36:40:44:48:52:56,0,0,0,99,0,0,none,0,717,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_ADORAMUS#Adoramus# +2041,0,0,200:220:240,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_CLEMENTIA#Crementia# +2042,0,0,145:160:175,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_CANTO#Canto Candidus# +2043,0,0,130:145:160,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_CHEAL#Coluceo Heal# +2044,0,0,300,0,0,0,99,0,0,none,0,12333,1,523,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_EPICLESIS#Epiclesis# +2045,0,0,60:70:80:90:100:110:120:130:140:150,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_PRAEFATIO#Praefatio# +2046,0,0,35:38:41:44:47:50:53:56:59:62,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_ORATIO#Oratio# +2047,0,0,50:60:70:80,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_LAUDAAGNUS#Lauda Agnus# +2048,0,0,50:60:70:80,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_LAUDARAMUS#Lauda Ramus# + +2050,0,0,70,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_RENOVATIO#Renovatio# +2051,0,0,70:100:130:160:190,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_HIGHNESSHEAL#Highness Heal# +2052,0,0,54:60:66:72:78,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_CLEARANCE#Clearance# +2053,0,0,35:40:45:50:55,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_EXPIATIO#Expiatio# +2054,0,0,55:60:65:70:75:80:85:90:95:100,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_DUPLELIGHT#Duple Light# +2055,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_DUPLELIGHT_MELEE#Duple Light Melee# +2056,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_DUPLELIGHT_MAGIC#Duple Light Magic# +2057,0,0,64:68:72:76:80,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_SILENTIUM#Silentium# + +2515,0,0,100:120:140:160:180,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //AB_SECRAMENT#Sacrament# + +//**** +// RA Ranger +2233,0,0,30:32:34:36:38:40:42:44:46:48,0,0,0,11,1,10,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_ARROWSTORM#Arrow Storm# +2234,0,0,36:40:44:48:52,0,0,0,11,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_FEARBREEZE#Fear Breeze# + +2236,0,0,30:32:34:36:38:40:42:44:46:48,0,0,0,11,1,1,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_AIMEDBOLT#Aimed Bolt# //How many arrows does it require??? +2237,0,0,15,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_DETONATOR#Detonator# +2238,0,0,35,0,0,0,99,0,0,none,0,7940,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_ELECTRICSHOCKER#Electric Shocker# +2239,0,0,20,0,0,0,99,0,0,none,0,7940,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_CLUSTERBOMB#Cluster Bomb# +2240,0,0,5,0,0,0,99,0,0,none,0,6124,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_WUGMASTERY#Warg Mastery# +2241,0,0,20,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_WUGRIDER#Warg Rider# +2242,0,0,40,0,0,0,99,0,0,move_enable,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_WUGDASH#Warg Dash# +2243,0,0,20:22:24:26:28,0,0,0,99,0,0,ridingwarg,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_WUGSTRIKE#Warg Strike# +2244,0,0,42:44:46:48:50,0,0,0,99,0,0,warg,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_WUGBITE#Warg Bite# + +2246,0,0,12,0,0,0,99,0,0,warg,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_SENSITIVEKEEN#Sensitive Keen# +2247,0,0,40,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_CAMOUFLAGE#Camouflage# + +2249,0,0,10,0,0,0,99,0,0,none,0,7940,1,990,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_MAGENTATRAP#Magenta Trap# +2250,0,0,10,0,0,0,99,0,0,none,0,7940,1,991,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_COBALTTRAP#Cobalt Trap# +2251,0,0,10,0,0,0,99,0,0,none,0,7940,1,993,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_MAIZETRAP#Maize Trap# +2252,0,0,10,0,0,0,99,0,0,none,0,7940,1,992,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_VERDURETRAP#Verdure Trap# +2253,0,0,10,0,0,0,99,0,0,none,0,7940,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_FIRINGTRAP#Firing Trap# +2254,0,0,10,0,0,0,99,0,0,none,0,7940,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //RA_ICEBOUNDTRAP#Icebound Trap# + +//**** +// NC Mechanic +2256,0,0,3:6:9:12:15,0,0,0,99,0,0,mado,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_BOOSTKNUCKLE#Boost Knuckle# +2257,0,0,50,0,0,0,99,0,0,mado,0,1549,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_PILEBUNKER#Pile Bunker# +2258,0,0,2,0,0,0,99,0,0,mado,0,6145,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_VULCANARM#Vulcan Arm# +2259,0,0,20,0,0,0,99,0,0,mado,0,2139,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_FLAMELAUNCHER#Flame Launcher# +2260,0,0,20,0,0,0,99,0,0,mado,0,6147,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_COLDSLOWER#Cold Slower# +2261,0,0,30:45:60,0,0,0,99,8,1,mado,0,6146,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_ARMSCANNON#Arm Cannon# +2262,0,0,20:40:60,0,0,0,99,0,0,mado,0,6146,1,2800,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_ACCELERATION#Acceleration# +2263,0,0,25,0,0,0,99,0,0,mado,0,6146,1,2801,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_HOVERING#Hovering# +2264,0,0,5,0,0,0,99,0,0,mado,0,6146,1,,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_F_SIDESLIDE#Front - Side Slide# +2265,0,0,5,0,0,0,99,0,0,mado,0,6146,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_B_SIDESLIDE#Back - Side Slide# + +2267,0,0,200,0,0,0,99,0,0,mado,0,6146,5,2802,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_SELFDESTRUCTION#Self Destruction# +2268,0,0,100,0,0,0,99,0,0,mado,0,994,1,997,1,996,1,995,1,6146,2,2803,0,0,0,0,0,0,0,0,0 //NC_SHAPESHIFT#Shape Shift# //CHECK Shouldnt the different stones all be in the same slot? +2269,0,0,20,0,0,0,99,0,0,mado,0,6146,2,2804,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_EMERGENCYCOOL#Emergency Cool# +2270,0,0,45,0,0,0,99,0,0,mado,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_INFRAREDSCAN#Infrared Scan# +2271,0,0,30,0,0,0,99,0,0,mado,0,6146,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_ANALYZE#Analyze# +2272,0,0,90,0,0,0,99,0,0,mado,0,6146,3,2805,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_MAGNETICFIELD#Magnetic Field# +2273,0,0,90,0,0,0,99,0,0,mado,0,6146,1,2806,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_NEUTRALBARRIER#Neutral Barrier# +2274,0,0,100:150:200,0,0,0,99,0,0,mado,0,6146,2,2808,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_STEALTHFIELD#Stealth Field# +2275,0,0,25:30:35:40:45,0,0,0,99,0,0,mado,0,2807,0,6146,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_REPAIR#Repair# + +2278,0,0,20:22:24:26:28,0,0,0,6:7,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_AXEBOOMERANG#Axe Boomerang# +2279,0,0,10:12:14:16:18,0,0,0,6:7,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_POWERSWING#Power Swing# +2280,0,0,18:20:22:24:26,0,0,0,6:7,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_AXETORNADO#Axe Tornado# +2281,0,0,25:30:35:40:45,0,0,0,99,0,0,none,0,998,1,999,2,612,0,615,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_SILVERSNIPER#FAW - Silver Sniper# +2282,0,0,40:45:50:55:60,0,0,0,99,0,0,none,0,998,2,7054,1,612,0,615,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_MAGICDECOY#FAW - Magic Decoy# +2283,0,0,15,0,0,0,99,0,0,none,0,6186,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_DISJOINT#FAW Removal# + 2535,0,0,1,0,0,0,99,0,0,none,0,6377,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //ALL_BUYING_STORE#Open Buying Store 10010,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GD_BATTLEORDER## diff --git a/db/skill_tree.txt b/db/skill_tree.txt index 27f616c11..51c30f181 100644 --- a/db/skill_tree.txt +++ b/db/skill_tree.txt @@ -187,7 +187,7 @@ 9,157,1,0,0,0,0,0,0,0,0,0,0 //MG_ENERGYCOAT#Energy Coat# 9,80,10,18,1,0,0,0,0,0,0,0,0 //WZ_FIREPILLAR#Fire Pillar# 9,81,10,20,1,10,1,0,0,0,0,0,0 //WZ_SIGHTRASHER#Sightrasher# -//9,82,10,0,0,0,0,0,0,0,0,0,0 //WZ_FIREIVY#Fire Ivy# +9,82,10,19,3,0,0,0,0,0,0,0,0 //WZ_FIREIVY#Fire Ivy# 9,83,10,81,2,21,1,0,0,0,0,0,0 //WZ_METEOR#Meteor Storm# 9,84,10,11,1,20,1,0,0,0,0,0,0 //WZ_JUPITEL#Jupiter Thunder# 9,85,10,21,1,84,5,0,0,0,0,0,0 //WZ_VERMILION#Lord of Vermilion# @@ -2263,3 +2263,671 @@ 4049,494,5,451,1,0,0,0,0,0,0,0,0 //SL_HIGH#Spirit of Rebirth# 4049,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby# 4049,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R# +//Rune Knight (non-trans) +4054,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill# +4054,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid# +4054,2,10,0,0,0,0,0,0,0,0,0,0 //SM_SWORD#Sword Mastery# +4054,3,10,2,1,0,0,0,0,0,0,0,0 //SM_TWOHAND#Two-Handed Sword Mastery# +4054,4,10,0,0,0,0,0,0,0,0,0,0 //SM_RECOVERY#Increase HP Recovery# +4054,5,10,0,0,0,0,0,0,0,0,0,0 //SM_BASH#Bash# +4054,6,10,0,0,0,0,0,0,0,0,0,0 //SM_PROVOKE#Provoke# +4054,7,10,5,5,0,0,0,0,0,0,0,0 //SM_MAGNUM#Magnum Break# +4054,8,10,6,5,0,0,0,0,0,0,0,0 //SM_ENDURE#Endure# +4054,144,1,0,0,0,0,0,0,0,0,0,0 //SM_MOVINGRECOVERY#Moving HP-Recovery# +4054,145,1,0,0,0,0,0,0,0,0,0,0 //SM_FATALBLOW#Attack Weak Point# +4054,146,1,0,0,0,0,0,0,0,0,0,0 //SM_AUTOBERSERK#Auto Berserk# +4054,55,10,0,0,0,0,0,0,0,0,0,0 //KN_SPEARMASTERY#Spear Mastery# +4054,56,10,55,1,0,0,0,0,0,0,0,0 //KN_PIERCE#Pierce# +4054,57,10,63,1,58,3,0,0,0,0,0,0 //KN_BRANDISHSPEAR#Brandish Spear# +4054,58,10,56,5,0,0,0,0,0,0,0,0 //KN_SPEARSTAB#Spear Stab# +4054,59,5,56,3,0,0,0,0,0,0,0,0 //KN_SPEARBOOMERANG#Spear Boomerang# +4054,60,10,3,1,0,0,0,0,0,0,0,0 //KN_TWOHANDQUICKEN#Twohand Quicken# +4054,61,5,3,1,0,0,0,0,0,0,0,0 //KN_AUTOCOUNTER#Counter Attack# +4054,62,10,5,10,7,3,3,5,60,10,61,5//KN_BOWLINGBASH#Bowling Bash# +4054,63,1,8,1,0,0,0,0,0,0,0,0 //KN_RIDING#Peco Peco Riding# +4054,64,5,63,1,0,0,0,0,0,0,0,0 //KN_CAVALIERMASTERY#Cavalier Mastery# +4054,1001,1,0,0,0,0,0,0,0,0,0,0 //KN_CHARGEATK#Charge Attack# +4054,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby# +4054,495,1,60,10,0,0,0,0,0,0,0,0 //KN_ONEHAND#Onehand Quicken# +4054,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R# +4054,2001,5,2010,2,0,0,0,0,0,0,0,0 //RK_ENCHANTBLADE#Enchant Blade# +4054,2002,5,2001,3,0,0,0,0,0,0,0,0 //RK_SONICWAVE#Sonic Wave# +4054,2003,10,61,1,2001,2,0,0,0,0,0,0 //RK_DEATHBOUND#Death Bound# +4054,2004,10,2020,3,0,0,0,0,0,0,0,0 //RK_HUNDREDSPEAR#Hundred Spear# +4054,2005,5,2001,5,0,0,0,0,0,0,0,0 //RK_WINDCUTTER#Wind Cutter# +4054,2006,5,2002,2,2003,5,2005,3,0,0,0,0 //RK_IGNITIONBREAK#Ignition Break# +4054,2007,5,64,1,0,0,0,0,0,0,0,0 //RK_DRAGONTRAINING#Dragon Training# +4054,2008,10,2007,2,0,0,0,0,0,0,0,0 //RK_DRAGONBREATH#Dragon Breath# +4054,2009,5,2007,2,0,0,0,0,0,0,0,0 //RK_DRAGONHOWLING#Dragon Howling# +4054,2010,10,0,0,0,0,0,0,0,0,0,0 //RK_RUNEMASTERY#Rune Mastery# +4054,2020,5,57,2,0,0,0,0,0,0,0,0 //RK_PHANTOMTHRUST#Phantom Thrust# +//Warlock (non-trans) +4055,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill# +4055,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid# +4055,9,10,0,0,0,0,0,0,0,0,0,0 //MG_SRECOVERY#Increase SP Recovery# +4055,10,1,0,0,0,0,0,0,0,0,0,0 //MG_SIGHT#Sight# +4055,11,10,0,0,0,0,0,0,0,0,0,0 //MG_NAPALMBEAT#Napalm Beat# +4055,12,10,11,7,13,5,0,0,0,0,0,0 //MG_SAFETYWALL#Safety Wall# +4055,13,10,11,4,0,0,0,0,0,0,0,0 //MG_SOULSTRIKE#Soul Strike# +4055,14,10,0,0,0,0,0,0,0,0,0,0 //MG_COLDBOLT#Cold Bolt# +4055,15,10,14,5,0,0,0,0,0,0,0,0 //MG_FROSTDIVER#Frost Diver# +4055,16,10,0,0,0,0,0,0,0,0,0,0 //MG_STONECURSE#Stone Curse# +4055,17,10,19,4,0,0,0,0,0,0,0,0 //MG_FIREBALL#Fire Ball# +4055,18,10,17,5,10,1,0,0,0,0,0,0 //MG_FIREWALL#Fire Wall# +4055,19,10,0,0,0,0,0,0,0,0,0,0 //MG_FIREBOLT#Fire Bolt# +4055,20,10,0,0,0,0,0,0,0,0,0,0 //MG_LIGHTNINGBOLT#Lightning Bolt# +4055,21,10,20,4,0,0,0,0,0,0,0,0 //MG_THUNDERSTORM#Thunderstorm# +4055,157,1,0,0,0,0,0,0,0,0,0,0 //MG_ENERGYCOAT#Energy Coat# +4055,80,10,18,1,0,0,0,0,0,0,0,0 //WZ_FIREPILLAR#Fire Pillar# +4055,81,10,20,1,10,1,0,0,0,0,0,0 //WZ_SIGHTRASHER#Sightrasher# +4055,83,10,81,2,21,1,0,0,0,0,0,0 //WZ_METEOR#Meteor Storm# +4055,84,10,11,1,20,1,0,0,0,0,0,0 //WZ_JUPITEL#Jupiter Thunder# +4055,85,10,21,1,84,5,0,0,0,0,0,0 //WZ_VERMILION#Lord of Vermilion# +4055,86,5,14,1,20,1,0,0,0,0,0,0 //WZ_WATERBALL#Water Ball# +4055,87,10,16,1,15,1,0,0,0,0,0,0 //WZ_ICEWALL#Ice Wall# +4055,88,10,87,1,0,0,0,0,0,0,0,0 //WZ_FROSTNOVA#Frost Nova# +4055,89,10,15,1,84,3,0,0,0,0,0,0 //WZ_STORMGUST#Storm Gust# +4055,90,5,16,1,0,0,0,0,0,0,0,0 //WZ_EARTHSPIKE#Earth Spike# +4055,91,5,90,3,0,0,0,0,0,0,0,0 //WZ_HEAVENDRIVE#Heaven's Drive# +4055,92,5,91,1,0,0,0,0,0,0,0,0 //WZ_QUAGMIRE#Quagmire# +4055,93,1,0,0,0,0,0,0,0,0,0,0 //WZ_ESTIMATION#Sense# +4055,1006,1,0,0,0,0,0,0,0,0,0,0 //WZ_SIGHTBLASTER#Sight Blaster# +4055,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby# +4055,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R# +4055,2201,5,2202,3,0,0,0,0,0,0,0,0 //WL_WHITEIMPRISON#White Imprison# +4055,2202,5,2210,1,0,0,0,0,0,0,0,0 //WL_SOULEXPANSION#Soul Expansion# +4055,2203,5,2224,1,0,0,0,0,0,0,0,0 //WL_FROSTMISTY#Frosty Misty# +4055,2204,5,2203,2,0,0,0,0,0,0,0,0 //WL_JACKFROST#Jack Frost# +4055,2205,5,92,1,0,0,0,0,0,0,0,0 //WL_MARSHOFABYSS#Marsh of Abyss# +4055,2206,5,2201,1,2209,1,2230,2,0,0,0,0 //WL_RECOGNIZEDSPELL#Recognized Spell# +4055,2207,5,2229,1,0,0,0,0,0,0,0,0 //WL_SIENNAEXECRATE#Sienna Execrate# +4055,2208,3,0,0,0,0,0,0,0,0,0,0 //WL_RADIUS#Radius# +4055,2209,5,2210,1,0,0,0,0,0,0,0,0 //WL_STASIS#Stasis# +4055,2210,5,2208,1,0,0,0,0,0,0,0,0 //WL_DRAINLIFE#Drain Life# +4055,2211,5,2222,1,0,0,0,0,0,0,0,0 //WL_CRIMSONROCK#Crimson Rock# +4055,2212,5,2211,2,0,0,0,0,0,0,0,0 //WL_HELLINFERNO#Hell Inferno# +4055,2213,5,2212,3,0,0,0,0,0,0,0,0 //WL_COMET#Comet# +4055,2214,5,2223,1,0,0,0,0,0,0,0,0 //WL_CHAINLIGHTNING#Chain Lightning# +4055,2216,5,2207,2,0,0,0,0,0,0,0,0 //WL_EARTHSTRAIN#Earth Strain# +4055,2217,5,2204,5,2212,5,2214,5,2216,5,0,0 //WL_TETRAVORTEX#Tetra Vortex# +4055,2222,5,83,1,0,0,0,0,0,0,0,0 //WL_SUMMONFB#Summon Fire Ball# +4055,2223,5,85,1,0,0,0,0,0,0,0,0 //WL_SUMMONBL#Summon Lightning Ball# +4055,2224,5,89,1,0,0,0,0,0,0,0,0 //WL_SUMMONWB#Summon Water Ball# +4055,2229,5,91,1,0,0,0,0,0,0,0,0 //WL_SUMMONSTONE#Summon Stone# +4055,2230,2,0,0,0,0,0,0,0,0,0,0 //WL_RELEASE#Release# +4055,2231,1,0,0,0,0,0,0,0,0,0,0 //WL_READING_SB#Reading Spellbook# +4055,2232,5,0,0,0,0,0,0,0,0,0,0 //WL_FREEZE_SP#Freeze Spell# +//Ranger (non-trans) +4056,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill# +4056,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid# +4056,43,10,0,0,0,0,0,0,0,0,0,0 //AC_OWL#Owl's Eye# +4056,44,10,43,3,0,0,0,0,0,0,0,0 //AC_VULTURE#Vulture's Eye# +4056,45,10,44,1,0,0,0,0,0,0,0,0 //AC_CONCENTRATION#Improve Concentration# +4056,46,10,0,0,0,0,0,0,0,0,0,0 //AC_DOUBLE#Double Strafe# +4056,47,10,46,5,0,0,0,0,0,0,0,0 //AC_SHOWER#Arrow Shower# +4056,147,1,0,0,0,0,0,0,0,0,0,0 //AC_MAKINGARROW#Arrow Crafting# +4056,148,1,0,0,0,0,0,0,0,0,0,0 //AC_CHARGEARROW#Arrow Repel# +4056,115,5,0,0,0,0,0,0,0,0,0,0 //HT_SKIDTRAP#Skid Trap# +4056,116,5,0,0,0,0,0,0,0,0,0,0 //HT_LANDMINE#Land Mine# +4056,117,5,115,1,0,0,0,0,0,0,0,0 //HT_ANKLESNARE#Ankle Snare# +4056,118,5,117,1,0,0,0,0,0,0,0,0 //HT_SHOCKWAVE#Shockwave Trap# +4056,119,5,120,1,0,0,0,0,0,0,0,0 //HT_SANDMAN#Sandman# +4056,120,5,115,1,0,0,0,0,0,0,0,0 //HT_FLASHER#Flasher# +4056,121,5,120,1,0,0,0,0,0,0,0,0 //HT_FREEZINGTRAP#Freezing Trap# +4056,122,5,116,1,119,1,121,1,0,0,0,0 //HT_BLASTMINE#Blast Mine# +4056,123,5,118,1,122,1,0,0,0,0,0,0 //HT_CLAYMORETRAP#Claymore Trap# +4056,124,1,116,1,0,0,0,0,0,0,0,0 //HT_REMOVETRAP#Remove Trap# +4056,125,1,118,1,124,1,0,0,0,0,0,0 //HT_TALKIEBOX#Talkie Box# +4056,126,10,0,0,0,0,0,0,0,0,0,0 //HT_BEASTBANE#Beast Bane# +4056,127,1,126,1,0,0,0,0,0,0,0,0 //HT_FALCON#Falconry Mastery# +4056,128,10,129,5,0,0,0,0,0,0,0,0 //HT_STEELCROW#Steel Crow# +4056,129,5,127,1,0,0,0,0,0,0,0,0 //HT_BLITZBEAT#Blitz Beat# +4056,130,4,45,1,127,1,0,0,0,0,0,0 //HT_DETECTING#Detect# +4056,131,5,124,1,127,1,0,0,0,0,0,0 //HT_SPRINGTRAP#Spring Trap# +4056,1009,1,0,0,0,0,0,0,0,0,0,0 //HT_PHANTASMIC#Phantasmic Arrow# +4056,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby# +4056,499,1,46,10,0,0,0,0,0,0,0,0 //HT_POWER#Beast Strafing# +4056,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R# +4056,2233,10,2236,5,0,0,0,0,0,0,0,0 //RA_ARROWSTORM#Arrow Storm# +4056,2234,5,2233,5,2247,1,0,0,0,0,0,0 //RA_FEARBREEZE#Fear Breeze# +4056,2235,10,0,0,0,0,0,0,0,0,0,0 //RA_RANGERMAIN#Ranger Main# +4056,2236,10,117,5,0,0,0,0,0,0,0,0 //RA_AIMEDBOLT#Aimed Bolt# +4056,2237,1,2239,3,0,0,0,0,0,0,0,0 //RA_DETONATOR#Detonator# +4056,2238,5,118,5,0,0,0,0,0,0,0,0 //RA_ELECTRICSHOCKER#Electric Shocker# +4056,2239,5,2248,3,0,0,0,0,0,0,0,0 //RA_CLUSTERBOMB#Cluster Bomb# +4056,2240,1,0,0,0,0,0,0,0,0,0,0 //RA_WUGMASTERY#Warg Mastery# +4056,2241,3,2240,1,0,0,0,0,0,0,0,0 //RA_WUGRIDER#Warg Rider# +4056,2242,1,2241,1,0,0,0,0,0,0,0,0 //RA_WUGDASH#Warg Dash# +4056,2243,5,2245,1,0,0,0,0,0,0,0,0 //RA_WUGSTRIKE#Warg Strike# +4056,2244,5,2240,1,0,0,0,0,0,0,0,0 //RA_WUGBITE#Warg Bite# +4056,2245,10,2240,1,0,0,0,0,0,0,0,0 //RA_TOOTHOFWUG#Tooth Of Warg# +4056,2246,5,2245,3,0,0,0,0,0,0,0,0 //RA_SENSITIVEKEEN#Sensitive Keen# +4056,2247,5,2235,1,0,0,0,0,0,0,0,0 //RA_CAMOUFLAGE#Camouflage# +4056,2248,5,123,1,124,1,0,0,0,0,0,0 //RA_RESEARCHTRAP#Research Trap# +4056,2249,1,2248,1,0,0,0,0,0,0,0,0 //RA_MAGENTATRAP#Magenta Trap# +4056,2250,1,2248,1,0,0,0,0,0,0,0,0 //RA_COBALTTRAP#Cobalt Trap# +4056,2251,1,2248,1,0,0,0,0,0,0,0,0 //RA_MAIZETRAP#Maize Trap# +4056,2252,1,2248,1,0,0,0,0,0,0,0,0 //RA_VERDURETRAP#Verdure Trap# +4056,2253,5,2237,1,0,0,0,0,0,0,0,0 //RA_FIRINGTRAP#Firing Trap# +4056,2254,5,2237,1,0,0,0,0,0,0,0,0 //RA_ICEBOUNDTRAP#Icebound Trap# +//Arch Bishop (non-trans) +4057,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill# +4057,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid# +4057,22,10,0,0,0,0,0,0,0,0,0,0 //AL_DP#Divine Protection# +4057,23,10,22,3,0,0,0,0,0,0,0,0 //AL_DEMONBANE#Demon Bane# +4057,24,1,0,0,0,0,0,0,0,0,0,0 //AL_RUWACH#Ruwach# +4057,25,1,27,4,0,0,0,0,0,0,0,0 //AL_PNEUMA#Pneuma# +4057,26,2,24,1,0,0,0,0,0,0,0,0 //AL_TELEPORT#Teleport# +4057,27,4,26,2,0,0,0,0,0,0,0,0 //AL_WARP#Warp Portal# +4057,28,10,0,0,0,0,0,0,0,0,0,0 //AL_HEAL#Heal# +4057,29,10,28,3,0,0,0,0,0,0,0,0 //AL_INCAGI#Increase AGI# +4057,30,10,29,1,0,0,0,0,0,0,0,0 //AL_DECAGI#Decrease AGI# +4057,31,1,0,0,0,0,0,0,0,0,0,0 //AL_HOLYWATER#Aqua Benedicta# +4057,32,10,23,3,0,0,0,0,0,0,0,0 //AL_CRUCIS#Signum Crusis# +4057,33,10,22,3,0,0,0,0,0,0,0,0 //AL_ANGELUS#Angelus# +4057,34,10,22,5,0,0,0,0,0,0,0,0 //AL_BLESSING#Blessing# +4057,35,1,28,2,0,0,0,0,0,0,0,0 //AL_CURE#Cure# +4057,156,1,0,0,0,0,0,0,0,0,0,0 //AL_HOLYLIGHT#Holy Light# +4057,9,10,0,0,0,0,0,0,0,0,0,0 //MG_SRECOVERY#Increase SP Recovery# +4057,12,10,68,4,70,3,0,0,0,0,0,0 //MG_SAFETYWALL#Safety Wall# +4057,54,4,72,1,9,4,0,0,0,0,0,0 //ALL_RESURRECTION#Resurrection# +4057,65,10,0,0,0,0,0,0,0,0,0,0 //PR_MACEMASTERY#Mace Mastery# +4057,66,5,0,0,0,0,0,0,0,0,0,0 //PR_IMPOSITIO#Impositio Manus# +4057,67,3,66,2,0,0,0,0,0,0,0,0 //PR_SUFFRAGIUM#Suffragium# +4057,68,5,31,1,66,3,0,0,0,0,0,0 //PR_ASPERSIO#Aspersio# +4057,69,5,75,3,68,5,0,0,0,0,0,0 //PR_BENEDICTIO#B.S Sacramenti# +4057,70,10,28,1,0,0,0,0,0,0,0,0 //PR_SANCTUARY#Sanctuary# +4057,71,4,0,0,0,0,0,0,0,0,0,0 //PR_SLOWPOISON#Slow Poison# +4057,72,1,0,0,0,0,0,0,0,0,0,0 //PR_STRECOVERY#Status Recovery# +4057,73,10,33,2,0,0,0,0,0,0,0,0 //PR_KYRIE#Kyrie Eleison# +4057,74,5,0,0,0,0,0,0,0,0,0,0 //PR_MAGNIFICAT#Magnificat# +4057,75,5,73,4,74,3,0,0,0,0,0,0 //PR_GLORIA#Gloria# +4057,76,10,24,1,0,0,0,0,0,0,0,0 //PR_LEXDIVINA#Lex Divina# +4057,77,10,54,1,76,3,0,0,0,0,0,0 //PR_TURNUNDEAD#Turn Undead# +4057,78,1,76,5,0,0,0,0,0,0,0,0 //PR_LEXAETERNA#Lex Aeterna# +4057,79,10,12,1,78,1,77,3,0,0,0,0 //PR_MAGNUS#Magnus Exorcismus# +4057,1014,1,0,0,0,0,0,0,0,0,0,0 //PR_REDEMPTIO#Redemptio# +4057,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby# +4057,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R# +4057,2038,5,77,1,0,0,0,0,0,0,0,0 //AB_JUDEX#Judex# +4057,2039,1,2041,3,0,0,0,0,0,0,0,0 //AB_ANCILLA#Ancilla# +4057,2040,10,79,1,2038,1,2039,1,0,0,0,0 //AB_ADORAMUS#Adoramus# +4057,2041,3,34,1,0,0,0,0,0,0,0,0 //AB_CLEMENTIA#Crementia# +4057,2042,3,29,1,0,0,0,0,0,0,0,0 //AB_CANTO#Canto Candidus# +4057,2043,3,28,1,0,0,0,0,0,0,0,0 //AB_CHEAL#Coluceo Heal# +4057,2044,5,2039,1,2051,1,0,0,0,0,0,0 //AB_EPICLESIS#Epiclesis# +4057,2045,10,73,1,0,0,0,0,0,0,0,0 //AB_PRAEFATIO#Praefatio# +4057,2046,10,2045,5,0,0,0,0,0,0,0,0 //AB_ORATIO#Oratio# +4057,2047,4,72,1,0,0,0,0,0,0,0,0 //AB_LAUDAAGNUS#Lauda Agnus# +4057,2048,4,2047,2,0,0,0,0,0,0,0,0 //AB_LAUDARAMUS#Lauda Ramus# +4057,2049,10,2044,1,2053,1,0,0,0,0,0,0 //AB_EUCHARISTICA#Eucharistica# +4057,2050,1,2043,3,0,0,0,0,0,0,0,0 //AB_RENOVATIO#Renovatio# +4057,2051,5,2050,1,0,0,0,0,0,0,0,0 //AB_HIGHNESSHEAL#Highness Heal# +4057,2052,5,2048,2,0,0,0,0,0,0,0,0 //AB_CLEARANCE#Clearance# +4057,2053,5,2046,5,2054,5,0,0,0,0,0,0 //AB_EXPIATIO#Expiatio# +4057,2054,10,68,1,0,0,0,0,0,0,0,0 //AB_DUPLELIGHT#Duple Light# +4057,2057,5,2052,1,0,0,0,0,0,0,0,0 //AB_SILENTIUM#Silentium# +4057,2515,5,2044,1,2053,1,0,0,0,0,0,0 //AB_SECRAMENT#Secrament# +//Mechanic (non-trans) +4058,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill# +4058,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid# +4058,36,10,0,0,0,0,0,0,0,0,0,0 //MC_INCCARRY#Enlarge Weight Limit# +4058,37,10,36,3,0,0,0,0,0,0,0,0 //MC_DISCOUNT#Discount# +4058,38,10,37,3,0,0,0,0,0,0,0,0 //MC_OVERCHARGE#Overcharge# +4058,39,10,36,5,0,0,0,0,0,0,0,0 //MC_PUSHCART#Pushcart# +4058,40,1,0,0,0,0,0,0,0,0,0,0 //MC_IDENTIFY#Item Appraisal# +4058,41,10,39,3,0,0,0,0,0,0,0,0 //MC_VENDING#Vending# +4058,42,10,0,0,0,0,0,0,0,0,0,0 //MC_MAMMONITE#Mammonite# +4058,153,1,0,0,0,0,0,0,0,0,0,0 //MC_CARTREVOLUTION#Cart Revolution# +4058,154,1,0,0,0,0,0,0,0,0,0,0 //MC_CHANGECART#Change Cart# +4058,155,1,0,0,0,0,0,0,0,0,0,0 //MC_LOUD#Crazy Uproar# +4058,94,5,0,0,0,0,0,0,0,0,0,0 //BS_IRON#Iron Tempering# +4058,95,5,94,1,0,0,0,0,0,0,0,0 //BS_STEEL#Steel Tempering# +4058,96,5,94,1,0,0,0,0,0,0,0,0 //BS_ENCHANTEDSTONE#Enchanted Stone Craft# +4058,97,5,96,1,0,0,0,0,0,0,0,0 //BS_ORIDEOCON#Oridecon Research# +4058,98,3,0,0,0,0,0,0,0,0,0,0 //BS_DAGGER#Smith Dagger# +4058,99,3,98,1,0,0,0,0,0,0,0,0 //BS_SWORD#Smith Sword# +4058,100,3,99,1,0,0,0,0,0,0,0,0 //BS_TWOHANDSWORD#Smith Two-handed Sword# +4058,101,3,99,2,0,0,0,0,0,0,0,0 //BS_AXE#Smith Axe# +4058,102,3,103,1,0,0,0,0,0,0,0,0 //BS_MACE#Smith Mace# +4058,103,3,98,1,0,0,0,0,0,0,0,0 //BS_KNUCKLE#Smith Knucklebrace# +4058,104,3,98,2,0,0,0,0,0,0,0,0 //BS_SPEAR#Smith Spear# +4058,105,1,0,0,0,0,0,0,0,0,0,0 //BS_HILTBINDING#Hilt Binding# +4058,106,1,95,1,105,1,0,0,0,0,0,0 //BS_FINDINGORE#Ore Discovery# +4058,107,10,105,1,0,0,0,0,0,0,0,0 //BS_WEAPONRESEARCH#Weaponry Research# +4058,108,1,107,1,0,0,0,0,0,0,0,0 //BS_REPAIRWEAPON#Weapon Repair# +4058,109,5,0,0,0,0,0,0,0,0,0,0 //BS_SKINTEMPER#Skin Tempering# +4058,110,5,0,0,0,0,0,0,0,0,0,0 //BS_HAMMERFALL#Hammer Fall# +4058,111,5,110,2,0,0,0,0,0,0,0,0 //BS_ADRENALINE#Adrenaline Rush# +4058,112,5,107,2,111,2,0,0,0,0,0,0 //BS_WEAPONPERFECT#Weapon Perfection# +4058,113,5,111,3,0,0,0,0,0,0,0,0 //BS_OVERTHRUST#Power-Thrust# +4058,114,5,112,3,113,2,0,0,0,0,0,0 //BS_MAXIMIZE#Maximize Power# +4058,1012,1,0,0,0,0,0,0,0,0,0,0 //BS_UNFAIRLYTRICK#Unfair Trick# +4058,1013,1,0,0,0,0,0,0,0,0,0,0 //BS_GREED#Greed# +4058,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby# +4058,459,1,111,5,0,0,0,0,0,0,0,0 //BS_ADRENALINE2#Full Adrenaline Rush# +4058,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R# +4058,2255,5,0,0,0,0,0,0,0,0,0,0 //NC_MADOLICENCE#Mado License# +4058,2256,5,2255,1,0,0,0,0,0,0,0,0 //NC_BOOSTKNUCKLE#Boost Knuckle# +4058,2257,3,2256,2,0,0,0,0,0,0,0,0 //NC_PILEBUNKER#Pile Bunker# +4058,2258,3,2256,2,0,0,0,0,0,0,0,0 //NC_VULCANARM#Vulcan Arm# +4058,2259,3,2258,3,0,0,0,0,0,0,0,0 //NC_FLAMELAUNCHER#Flame Launcher# +4058,2260,3,2258,3,0,0,0,0,0,0,0,0 //NC_COLDSLOWER#Cold Slower# +4058,2261,3,2259,2,2260,2,0,0,0,0,0,0 //NC_ARMSCANNON#Arm Cannon# +4058,2262,3,2255,1,0,0,0,0,0,0,0,0 //NC_ACCELERATION#Acceleration# +4058,2263,1,2262,1,0,0,0,0,0,0,0,0 //NC_HOVERING#Hovering# +4058,2264,1,2263,1,0,0,0,0,0,0,0,0 //NC_F_SIDESLIDE#Front-Side Slide# +4058,2265,1,2263,1,0,0,0,0,0,0,0,0 //NC_B_SIDESLIDE#Back-Side Slide# +4058,2266,4,2255,4,0,0,0,0,0,0,0,0 //NC_MAINFRAME#Mainframe Restructure# +4058,2267,3,2266,2,0,0,0,0,0,0,0,0 //NC_SELFDESTRUCTION#Self Destruction# +4058,2268,4,2266,2,0,0,0,0,0,0,0,0 //NC_SHAPESHIFT#Shape Shift# +4058,2269,1,2267,2,0,0,0,0,0,0,0,0 //NC_EMERGENCYCOOL#Emergency Cool# +4058,2270,1,2268,2,0,0,0,0,0,0,0,0 //NC_INFRAREDSCAN#Infrared Scan# +4058,2271,3,2270,1,0,0,0,0,0,0,0,0 //NC_ANALYZE#Analyze# +4058,2272,3,2269,1,0,0,0,0,0,0,0,0 //NC_MAGNETICFIELD#Magnetic Field# +4058,2273,3,2272,2,0,0,0,0,0,0,0,0 //NC_NEUTRALBARRIER#Neutral Barrier# +4058,2274,3,2271,3,2273,2,0,0,0,0,0,0 //NC_STEALTHFIELD#Stealth Field# +4058,2275,5,2255,1,0,0,0,0,0,0,0,0 //NC_REPAIR#Repair# +4058,2276,10,0,0,0,0,0,0,0,0,0,0 //NC_TRAININGAXE#Axe Training# +4058,2277,5,0,0,0,0,0,0,0,0,0,0 //NC_RESEARCHFE#Research Fire/Earth# +4058,2278,5,2276,1,0,0,0,0,0,0,0,0 //NC_AXEBOOMERANG#Axe Boomerang# +4058,2279,5,2278,3,0,0,0,0,0,0,0,0 //NC_POWERSWING#Power Swing# +4058,2280,5,2276,1,0,0,0,0,0,0,0,0 //NC_AXETORNADO#Axe Tornado# +4058,2281,5,2277,2,0,0,0,0,0,0,0,0 //NC_SILVERSNIPER#FAW - Silver Sniper# +4058,2282,5,2277,2,0,0,0,0,0,0,0,0 //NC_MAGICDECOY#FAW - Magic Decoy# +4058,2283,1,2281,1,0,0,0,0,0,0,0,0 //NC_DISJOINT#FAW Removal# +4058,2535,1,41,1,0,0,0,0,0,0,0,0 //ALL_BUYING_STORE#Open Buying Store# +//Guillotine Cross (non-trans) +4059,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill# +4059,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid# +4059,48,10,0,0,0,0,0,0,0,0,0,0 //TF_DOUBLE#Double Attack# +4059,49,10,0,0,0,0,0,0,0,0,0,0 //TF_MISS#Improve Dodge# +4059,50,10,0,0,0,0,0,0,0,0,0,0 //TF_STEAL#Steal# +4059,51,10,50,5,0,0,0,0,0,0,0,0 //TF_HIDING#Hiding# +4059,52,10,0,0,0,0,0,0,0,0,0,0 //TF_POISON#Envenom# +4059,53,1,52,3,0,0,0,0,0,0,0,0 //TF_DETOXIFY#Detoxify# +4059,149,1,0,0,0,0,0,0,0,0,0,0 //TF_SPRINKLESAND#Throw Sand# +4059,150,1,0,0,0,0,0,0,0,0,0,0 //TF_BACKSLIDING#Back Sliding# +4059,151,1,0,0,0,0,0,0,0,0,0,0 //TF_PICKSTONE#Find Stone# +4059,152,1,0,0,0,0,0,0,0,0,0,0 //TF_THROWSTONE#Stone Fling# +4059,132,5,0,0,0,0,0,0,0,0,0,0 //AS_RIGHT#Righthand Mastery# +4059,133,5,132,2,0,0,0,0,0,0,0,0 //AS_LEFT#Lefthand Mastery# +4059,134,10,0,0,0,0,0,0,0,0,0,0 //AS_KATAR#Katar Mastery# +4059,135,10,51,2,0,0,0,0,0,0,0,0 //AS_CLOAKING#Cloaking# +4059,136,10,134,4,0,0,0,0,0,0,0,0 //AS_SONICBLOW#Sonic Blow# +4059,137,5,135,2,136,5,0,0,0,0,0,0 //AS_GRIMTOOTH#Grimtooth# +4059,138,10,52,1,0,0,0,0,0,0,0,0 //AS_ENCHANTPOISON#Enchant Poison# +4059,139,10,138,3,0,0,0,0,0,0,0,0 //AS_POISONREACT#Poison React# +4059,140,10,138,5,0,0,0,0,0,0,0,0 //AS_VENOMDUST#Venom Dust# +4059,141,10,139,5,140,5,0,0,0,0,0,0 //AS_SPLASHER#Venom Splasher# +4059,1003,1,0,0,0,0,0,0,0,0,0,0 //AS_SONICACCEL#Sonic Acceleration# +4059,1004,1,0,0,0,0,0,0,0,0,0,0 //AS_VENOMKNIFE#Throw Venom Knife# +4059,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby# +4059,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R# +4059,2021,5,138,3,0,0,0,0,0,0,0,0 //GC_VENOMIMPRESS#Venom Impress# +4059,2022,5,136,10,0,0,0,0,0,0,0,0 //GC_CROSSIMPACT#Cross Impact# +4059,2023,5,2022,3,0,0,0,0,0,0,0,0 //GC_DARKILLUSION#Dark Illusion# +4059,2024,10,0,0,0,0,0,0,0,0,0,0 //GC_RESEARCHNEWPOISON#Research New Poison# +4059,2025,1,2024,1,0,0,0,0,0,0,0,0 //GC_CREATENEWPOISON#Create New Poison# +4059,2026,1,2024,5,0,0,0,0,0,0,0,0 //GC_ANTIDOTE#Antidote# +4059,2027,5,2025,1,0,0,0,0,0,0,0,0 //GC_POISONINGWEAPON#Poisoning Weapon# +4059,2028,5,133,5,0,0,0,0,0,0,0,0 //GC_WEAPONBLOCKING#Weapon Blocking# +4059,2029,5,2028,1,0,0,0,0,0,0,0,0 //GC_COUNTERSLASH#Counter Slash# +4059,2030,5,2028,1,0,0,0,0,0,0,0,0 //GC_WEAPONCRUSH#Weapon Crush# +4059,2031,5,2027,3,2028,1,0,0,0,0,0,0 //GC_VENOMPRESSURE#Venom Pressure# +4059,2032,5,2027,5,2031,5,0,0,0,0,0,0 //GC_POISONSMOKE#Poison Smoke# +4059,2033,5,135,3,0,0,0,0,0,0,0,0 //GC_CLOAKINGEXCEED#Cloaking Exceed# +4059,2034,1,2023,5,2033,5,0,0,0,0,0,0 //GC_PHANTOMMENACE#Phantom Menace# +4059,2035,5,2034,1,0,0,0,0,0,0,0,0 //GC_HALLUCINATIONWALK#Hallucination Walk# +4059,2036,5,136,10,0,0,0,0,0,0,0,0 //GC_ROLLINGCUTTER#Rolling Cutter# +4059,2037,5,2036,1,0,0,0,0,0,0,0,0 //GC_CROSSRIPPERSLASHER#Cross Ripper Slasher# +//Rune Knight (Trans) +4060,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill# +4060,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid# +4060,2,10,0,0,0,0,0,0,0,0,0,0 //SM_SWORD#Sword Mastery# +4060,3,10,2,1,0,0,0,0,0,0,0,0 //SM_TWOHAND#Two-Handed Sword Mastery# +4060,4,10,0,0,0,0,0,0,0,0,0,0 //SM_RECOVERY#Increase HP Recovery# +4060,5,10,0,0,0,0,0,0,0,0,0,0 //SM_BASH#Bash# +4060,6,10,0,0,0,0,0,0,0,0,0,0 //SM_PROVOKE#Provoke# +4060,7,10,5,5,0,0,0,0,0,0,0,0 //SM_MAGNUM#Magnum Break# +4060,8,10,6,5,0,0,0,0,0,0,0,0 //SM_ENDURE#Endure# +4060,144,1,0,0,0,0,0,0,0,0,0,0 //SM_MOVINGRECOVERY#Moving HP-Recovery# +4060,145,1,0,0,0,0,0,0,0,0,0,0 //SM_FATALBLOW#Attack Weak Point# +4060,146,1,0,0,0,0,0,0,0,0,0,0 //SM_AUTOBERSERK#Auto Berserk# +4060,55,10,0,0,0,0,0,0,0,0,0,0 //KN_SPEARMASTERY#Spear Mastery# +4060,56,10,55,1,0,0,0,0,0,0,0,0 //KN_PIERCE#Pierce# +4060,57,10,63,1,58,3,0,0,0,0,0,0 //KN_BRANDISHSPEAR#Brandish Spear# +4060,58,10,56,5,0,0,0,0,0,0,0,0 //KN_SPEARSTAB#Spear Stab# +4060,59,5,56,3,0,0,0,0,0,0,0,0 //KN_SPEARBOOMERANG#Spear Boomerang# +4060,60,10,3,1,0,0,0,0,0,0,0,0 //KN_TWOHANDQUICKEN#Twohand Quicken# +4060,61,5,3,1,0,0,0,0,0,0,0,0 //KN_AUTOCOUNTER#Counter Attack# +4060,62,10,5,10,7,3,3,5,60,10,61,5//KN_BOWLINGBASH#Bowling Bash# +4060,63,1,8,1,0,0,0,0,0,0,0,0 //KN_RIDING#Peco Peco Riding# +4060,64,5,63,1,0,0,0,0,0,0,0,0 //KN_CAVALIERMASTERY#Cavalier Mastery# +4060,1001,1,0,0,0,0,0,0,0,0,0,0 //KN_CHARGEATK#Charge Attack# +4060,355,5,5,5,7,5,3,5,0,0,0,0 //LK_AURABLADE#Aura Blade# +4060,356,10,3,10,6,5,60,3,0,0,0,0 //LK_PARRYING#Parrying# +4060,357,5,4,1,55,5,63,1,0,0,0,0 //LK_CONCENTRATION#Concentration# +4060,358,1,4,10,6,5,8,3,0,0,0,0 //LK_TENSIONRELAX#Relax# +4060,359,1,0,0,0,0,0,0,0,0,0,0 //LK_BERSERK#Frenzy# //Extra column removed. Rune Knights dont require job level 50 to use Berserk. +4060,397,5,55,10,56,5,58,5,63,1,0,0 //LK_SPIRALPIERCE#Spiral Pierce# +4060,398,5,55,9,63,1,0,0,0,0,0,0 //LK_HEADCRUSH#Traumatic Blow# +4060,399,10,55,9,64,3,398,3,0,0,0,0 //LK_JOINTBEAT#Vital Strike# +4060,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby# +4060,495,1,60,10,0,0,0,0,0,0,0,0 //KN_ONEHAND#Onehand Quicken# +4060,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R# +4060,2001,5,2010,2,0,0,0,0,0,0,0,0 //RK_ENCHANTBLADE#Enchant Blade# +4060,2002,5,2001,3,0,0,0,0,0,0,0,0 //RK_SONICWAVE#Sonic Wave# +4060,2003,10,61,1,2001,2,0,0,0,0,0,0 //RK_DEATHBOUND#Death Bound# +4060,2004,10,2020,3,0,0,0,0,0,0,0,0 //RK_HUNDREDSPEAR#Hundred Spear# +4060,2005,5,2001,5,0,0,0,0,0,0,0,0 //RK_WINDCUTTER#Wind Cutter# +4060,2006,5,2002,2,2003,5,2005,3,0,0,0,0 //RK_IGNITIONBREAK#Ignition Break# +4060,2007,5,64,1,0,0,0,0,0,0,0,0 //RK_DRAGONTRAINING#Dragon Training# +4060,2008,10,2007,2,0,0,0,0,0,0,0,0 //RK_DRAGONBREATH#Dragon Breath# +4060,2009,5,2007,2,0,0,0,0,0,0,0,0 //RK_DRAGONHOWLING#Dragon Howling# +4060,2010,10,0,0,0,0,0,0,0,0,0,0 //RK_RUNEMASTERY#Rune Mastery# +4060,2020,5,57,2,0,0,0,0,0,0,0,0 //RK_PHANTOMTHRUST#Phantom Thrust# +//Warlock (Trans) +4061,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill# +4061,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid# +4061,9,10,0,0,0,0,0,0,0,0,0,0 //MG_SRECOVERY#Increase SP Recovery# +4061,10,1,0,0,0,0,0,0,0,0,0,0 //MG_SIGHT#Sight# +4061,11,10,0,0,0,0,0,0,0,0,0,0 //MG_NAPALMBEAT#Napalm Beat# +4061,12,10,11,7,13,5,0,0,0,0,0,0 //MG_SAFETYWALL#Safety Wall# +4061,13,10,11,4,0,0,0,0,0,0,0,0 //MG_SOULSTRIKE#Soul Strike# +4061,14,10,0,0,0,0,0,0,0,0,0,0 //MG_COLDBOLT#Cold Bolt# +4061,15,10,14,5,0,0,0,0,0,0,0,0 //MG_FROSTDIVER#Frost Diver# +4061,16,10,0,0,0,0,0,0,0,0,0,0 //MG_STONECURSE#Stone Curse# +4061,17,10,19,4,0,0,0,0,0,0,0,0 //MG_FIREBALL#Fire Ball# +4061,18,10,17,5,10,1,0,0,0,0,0,0 //MG_FIREWALL#Fire Wall# +4061,19,10,0,0,0,0,0,0,0,0,0,0 //MG_FIREBOLT#Fire Bolt# +4061,20,10,0,0,0,0,0,0,0,0,0,0 //MG_LIGHTNINGBOLT#Lightning Bolt# +4061,21,10,20,4,0,0,0,0,0,0,0,0 //MG_THUNDERSTORM#Thunderstorm# +4061,157,1,0,0,0,0,0,0,0,0,0,0 //MG_ENERGYCOAT#Energy Coat# +4061,80,10,18,1,0,0,0,0,0,0,0,0 //WZ_FIREPILLAR#Fire Pillar# +4061,81,10,20,1,10,1,0,0,0,0,0,0 //WZ_SIGHTRASHER#Sightrasher# +4061,83,10,81,2,21,1,0,0,0,0,0,0 //WZ_METEOR#Meteor Storm# +4061,84,10,11,1,20,1,0,0,0,0,0,0 //WZ_JUPITEL#Jupiter Thunder# +4061,85,10,21,1,84,5,0,0,0,0,0,0 //WZ_VERMILION#Lord of Vermilion# +4061,86,5,14,1,20,1,0,0,0,0,0,0 //WZ_WATERBALL#Water Ball# +4061,87,10,16,1,15,1,0,0,0,0,0,0 //WZ_ICEWALL#Ice Wall# +4061,88,10,87,1,0,0,0,0,0,0,0,0 //WZ_FROSTNOVA#Frost Nova# +4061,89,10,15,1,84,3,0,0,0,0,0,0 //WZ_STORMGUST#Storm Gust# +4061,90,5,16,1,0,0,0,0,0,0,0,0 //WZ_EARTHSPIKE#Earth Spike# +4061,91,5,90,3,0,0,0,0,0,0,0,0 //WZ_HEAVENDRIVE#Heaven's Drive# +4061,92,5,91,1,0,0,0,0,0,0,0,0 //WZ_QUAGMIRE#Quagmire# +4061,93,1,0,0,0,0,0,0,0,0,0,0 //WZ_ESTIMATION#Sense# +4061,1006,1,0,0,0,0,0,0,0,0,0,0 //WZ_SIGHTBLASTER#Sight Blaster# +4061,364,10,9,5,13,7,0,0,0,0,0,0 //HW_SOULDRAIN#Soul Drain# +4061,365,1,9,1,0,0,0,0,0,0,0,0 //HW_MAGICCRASHER#Stave Crasher# +4061,366,10,0,0,0,0,0,0,0,0,0,0 //HW_MAGICPOWER#Mystical Amplification# +4061,400,5,11,5,0,0,0,0,0,0,0,0 //HW_NAPALMVULCAN#Napalm Vulcan# +4061,483,1,93,1,87,1,0,0,0,0,0,0 //HW_GANBANTEIN#Ganbantein# +4061,484,5,365,1,366,10,92,1,0,0,0,0 //HW_GRAVITATION#Gravitation# +4061,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby# +4061,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R# +4061,2201,5,2202,3,0,0,0,0,0,0,0,0 //WL_WHITEIMPRISON#White Imprison# +4061,2202,5,2210,1,0,0,0,0,0,0,0,0 //WL_SOULEXPANSION#Soul Expansion# +4061,2203,5,2224,1,0,0,0,0,0,0,0,0 //WL_FROSTMISTY#Frosty Misty# +4061,2204,5,2203,2,0,0,0,0,0,0,0,0 //WL_JACKFROST#Jack Frost# +4061,2205,5,92,1,0,0,0,0,0,0,0,0 //WL_MARSHOFABYSS#Marsh of Abyss# +4061,2206,5,2201,1,2209,1,2230,2,0,0,0,0 //WL_RECOGNIZEDSPELL#Recognized Spell# +4061,2207,5,2229,1,0,0,0,0,0,0,0,0 //WL_SIENNAEXECRATE#Sienna Execrate# +4061,2208,3,0,0,0,0,0,0,0,0,0,0 //WL_RADIUS#Radius# +4061,2209,5,2210,1,0,0,0,0,0,0,0,0 //WL_STASIS#Stasis# +4061,2210,5,2208,1,0,0,0,0,0,0,0,0 //WL_DRAINLIFE#Drain Life# +4061,2211,5,2222,1,0,0,0,0,0,0,0,0 //WL_CRIMSONROCK#Crimson Rock# +4061,2212,5,2211,2,0,0,0,0,0,0,0,0 //WL_HELLINFERNO#Hell Inferno# +4061,2213,5,2212,3,0,0,0,0,0,0,0,0 //WL_COMET#Comet# +4061,2214,5,2223,1,0,0,0,0,0,0,0,0 //WL_CHAINLIGHTNING#Chain Lightning# +4061,2216,5,2207,2,0,0,0,0,0,0,0,0 //WL_EARTHSTRAIN#Earth Strain# +4061,2217,5,2204,5,2212,5,2214,5,2216,5,0,0 //WL_TETRAVORTEX#Tetra Vortex# +4061,2222,5,83,1,0,0,0,0,0,0,0,0 //WL_SUMMONFB#Summon Fire Ball# +4061,2223,5,85,1,0,0,0,0,0,0,0,0 //WL_SUMMONBL#Summon Lightning Ball# +4061,2224,5,89,1,0,0,0,0,0,0,0,0 //WL_SUMMONWB#Summon Water Ball# +4061,2229,5,91,1,0,0,0,0,0,0,0,0 //WL_SUMMONSTONE#Summon Stone# +4061,2230,2,0,0,0,0,0,0,0,0,0,0 //WL_RELEASE#Release# +4061,2231,1,0,0,0,0,0,0,0,0,0,0 //WL_READING_SB#Reading Spellbook# +4061,2232,5,0,0,0,0,0,0,0,0,0,0 //WL_FREEZE_SP#Freeze Spell# +//Ranger (Trans) +4062,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill# +4062,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid# +4062,43,10,0,0,0,0,0,0,0,0,0,0 //AC_OWL#Owl's Eye# +4062,44,10,43,3,0,0,0,0,0,0,0,0 //AC_VULTURE#Vulture's Eye# +4062,45,10,44,1,0,0,0,0,0,0,0,0 //AC_CONCENTRATION#Improve Concentration# +4062,46,10,0,0,0,0,0,0,0,0,0,0 //AC_DOUBLE#Double Strafe# +4062,47,10,46,5,0,0,0,0,0,0,0,0 //AC_SHOWER#Arrow Shower# +4062,147,1,0,0,0,0,0,0,0,0,0,0 //AC_MAKINGARROW#Arrow Crafting# +4062,148,1,0,0,0,0,0,0,0,0,0,0 //AC_CHARGEARROW#Arrow Repel# +4062,115,5,0,0,0,0,0,0,0,0,0,0 //HT_SKIDTRAP#Skid Trap# +4062,116,5,0,0,0,0,0,0,0,0,0,0 //HT_LANDMINE#Land Mine# +4062,117,5,115,1,0,0,0,0,0,0,0,0 //HT_ANKLESNARE#Ankle Snare# +4062,118,5,117,1,0,0,0,0,0,0,0,0 //HT_SHOCKWAVE#Shockwave Trap# +4062,119,5,120,1,0,0,0,0,0,0,0,0 //HT_SANDMAN#Sandman# +4062,120,5,115,1,0,0,0,0,0,0,0,0 //HT_FLASHER#Flasher# +4062,121,5,120,1,0,0,0,0,0,0,0,0 //HT_FREEZINGTRAP#Freezing Trap# +4062,122,5,116,1,119,1,121,1,0,0,0,0 //HT_BLASTMINE#Blast Mine# +4062,123,5,118,1,122,1,0,0,0,0,0,0 //HT_CLAYMORETRAP#Claymore Trap# +4062,124,1,116,1,0,0,0,0,0,0,0,0 //HT_REMOVETRAP#Remove Trap# +4062,125,1,118,1,124,1,0,0,0,0,0,0 //HT_TALKIEBOX#Talkie Box# +4062,126,10,0,0,0,0,0,0,0,0,0,0 //HT_BEASTBANE#Beast Bane# +4062,127,1,126,1,0,0,0,0,0,0,0,0 //HT_FALCON#Falconry Mastery# +4062,128,10,129,5,0,0,0,0,0,0,0,0 //HT_STEELCROW#Steel Crow# +4062,129,5,127,1,0,0,0,0,0,0,0,0 //HT_BLITZBEAT#Blitz Beat# +4062,130,4,45,1,127,1,0,0,0,0,0,0 //HT_DETECTING#Detect# +4062,131,5,124,1,127,1,0,0,0,0,0,0 //HT_SPRINGTRAP#Spring Trap# +4062,1009,1,0,0,0,0,0,0,0,0,0,0 //HT_PHANTASMIC#Phantasmic Arrow# +4062,380,10,43,10,44,10,45,10,127,1,0,0 //SN_SIGHT#Falcon Eyes# +4062,381,5,128,3,44,5,129,5,127,1,0,0 //SN_FALCONASSAULT#Falcon Assault# +4062,382,5,45,10,46,5,0,0,0,0,0,0 //SN_SHARPSHOOTING#Focused Arrow Strike# +4062,383,10,45,9,0,0,0,0,0,0,0,0 //SN_WINDWALK#Wind Walker# +4062,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby# +4062,499,1,46,10,0,0,0,0,0,0,0,0 //HT_POWER#Beast Strafing# +4062,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R# +4062,2233,10,2236,5,0,0,0,0,0,0,0,0 //RA_ARROWSTORM#Arrow Storm# +4062,2234,5,2233,5,2247,1,0,0,0,0,0,0 //RA_FEARBREEZE#Fear Breeze# +4062,2235,10,0,0,0,0,0,0,0,0,0,0 //RA_RANGERMAIN#Ranger Main# +4062,2236,10,117,5,0,0,0,0,0,0,0,0 //RA_AIMEDBOLT#Aimed Bolt# +4062,2237,1,2239,3,0,0,0,0,0,0,0,0 //RA_DETONATOR#Detonator# +4062,2238,5,118,5,0,0,0,0,0,0,0,0 //RA_ELECTRICSHOCKER#Electric Shocker# +4062,2239,5,2248,3,0,0,0,0,0,0,0,0 //RA_CLUSTERBOMB#Cluster Bomb# +4062,2240,1,0,0,0,0,0,0,0,0,0,0 //RA_WUGMASTERY#Warg Mastery# +4062,2241,3,2240,1,0,0,0,0,0,0,0,0 //RA_WUGRIDER#Warg Rider# +4062,2242,1,2241,1,0,0,0,0,0,0,0,0 //RA_WUGDASH#Warg Dash# +4062,2243,5,2245,1,0,0,0,0,0,0,0,0 //RA_WUGSTRIKE#Warg Strike# +4062,2244,5,2240,1,0,0,0,0,0,0,0,0 //RA_WUGBITE#Warg Bite# +4062,2245,10,2240,1,0,0,0,0,0,0,0,0 //RA_TOOTHOFWUG#Tooth Of Warg# +4062,2246,5,2245,3,0,0,0,0,0,0,0,0 //RA_SENSITIVEKEEN#Sensitive Keen# +4062,2247,5,2235,1,0,0,0,0,0,0,0,0 //RA_CAMOUFLAGE#Camouflage# +4062,2248,5,123,1,124,1,0,0,0,0,0,0 //RA_RESEARCHTRAP#Research Trap# +4062,2249,1,2248,1,0,0,0,0,0,0,0,0 //RA_MAGENTATRAP#Magenta Trap# +4062,2250,1,2248,1,0,0,0,0,0,0,0,0 //RA_COBALTTRAP#Cobalt Trap# +4062,2251,1,2248,1,0,0,0,0,0,0,0,0 //RA_MAIZETRAP#Maize Trap# +4062,2252,1,2248,1,0,0,0,0,0,0,0,0 //RA_VERDURETRAP#Verdure Trap# +4062,2253,5,2237,1,0,0,0,0,0,0,0,0 //RA_FIRINGTRAP#Firing Trap# +4062,2254,5,2237,1,0,0,0,0,0,0,0,0 //RA_ICEBOUNDTRAP#Icebound Trap# +//Arch Bishop (Trans) +4063,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill# +4063,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid# +4063,22,10,0,0,0,0,0,0,0,0,0,0 //AL_DP#Divine Protection# +4063,23,10,22,3,0,0,0,0,0,0,0,0 //AL_DEMONBANE#Demon Bane# +4063,24,1,0,0,0,0,0,0,0,0,0,0 //AL_RUWACH#Ruwach# +4063,25,1,27,4,0,0,0,0,0,0,0,0 //AL_PNEUMA#Pneuma# +4063,26,2,24,1,0,0,0,0,0,0,0,0 //AL_TELEPORT#Teleport# +4063,27,4,26,2,0,0,0,0,0,0,0,0 //AL_WARP#Warp Portal# +4063,28,10,0,0,0,0,0,0,0,0,0,0 //AL_HEAL#Heal# +4063,29,10,28,3,0,0,0,0,0,0,0,0 //AL_INCAGI#Increase AGI# +4063,30,10,29,1,0,0,0,0,0,0,0,0 //AL_DECAGI#Decrease AGI# +4063,31,1,0,0,0,0,0,0,0,0,0,0 //AL_HOLYWATER#Aqua Benedicta# +4063,32,10,23,3,0,0,0,0,0,0,0,0 //AL_CRUCIS#Signum Crusis# +4063,33,10,22,3,0,0,0,0,0,0,0,0 //AL_ANGELUS#Angelus# +4063,34,10,22,5,0,0,0,0,0,0,0,0 //AL_BLESSING#Blessing# +4063,35,1,28,2,0,0,0,0,0,0,0,0 //AL_CURE#Cure# +4063,156,1,0,0,0,0,0,0,0,0,0,0 //AL_HOLYLIGHT#Holy Light# +4063,9,10,0,0,0,0,0,0,0,0,0,0 //MG_SRECOVERY#Increase SP Recovery# +4063,12,10,68,4,70,3,0,0,0,0,0,0 //MG_SAFETYWALL#Safety Wall# +4063,54,4,72,1,9,4,0,0,0,0,0,0 //ALL_RESURRECTION#Resurrection# +4063,65,10,0,0,0,0,0,0,0,0,0,0 //PR_MACEMASTERY#Mace Mastery# +4063,66,5,0,0,0,0,0,0,0,0,0,0 //PR_IMPOSITIO#Impositio Manus# +4063,67,3,66,2,0,0,0,0,0,0,0,0 //PR_SUFFRAGIUM#Suffragium# +4063,68,5,31,1,66,3,0,0,0,0,0,0 //PR_ASPERSIO#Aspersio# +4063,69,5,75,3,68,5,0,0,0,0,0,0 //PR_BENEDICTIO#B.S Sacramenti# +4063,70,10,28,1,0,0,0,0,0,0,0,0 //PR_SANCTUARY#Sanctuary# +4063,71,4,72,1,0,0,0,0,0,0,0,0 //PR_SLOWPOISON#Slow Poison# +4063,72,1,0,0,0,0,0,0,0,0,0,0 //PR_STRECOVERY#Status Recovery# +4063,73,10,33,2,0,0,0,0,0,0,0,0 //PR_KYRIE#Kyrie Eleison# +4063,74,5,0,0,0,0,0,0,0,0,0,0 //PR_MAGNIFICAT#Magnificat# +4063,75,5,73,4,74,3,0,0,0,0,0,0 //PR_GLORIA#Gloria# +4063,76,10,24,1,0,0,0,0,0,0,0,0 //PR_LEXDIVINA#Lex Divina# +4063,77,10,54,1,76,3,0,0,0,0,0,0 //PR_TURNUNDEAD#Turn Undead# +4063,78,1,76,5,0,0,0,0,0,0,0,0 //PR_LEXAETERNA#Lex Aeterna# +4063,79,10,12,1,78,1,77,3,0,0,0,0 //PR_MAGNUS#Magnus Exorcismus# +4063,1014,1,0,0,0,0,0,0,0,0,0,0 //PR_REDEMPTIO#Redemptio# +4063,361,5,33,1,9,3,66,3,0,0,0,0 //HP_ASSUMPTIO#Assumptio# +4063,362,5,75,2,9,1,73,3,0,0,0,0 //HP_BASILICA#Basilica# +4063,363,10,68,3,9,5,76,5,0,0,0,0 //HP_MEDITATIO#Meditatio# +4063,481,5,65,10,23,10,0,0,0,0,0,0 //HP_MANARECHARGE#Mana Recharge# +4063,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby# +4063,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R# +4063,2038,5,77,1,0,0,0,0,0,0,0,0 //AB_JUDEX#Judex# +4063,2039,1,2041,3,0,0,0,0,0,0,0,0 //AB_ANCILLA#Ancilla# +4063,2040,10,79,1,2038,1,2039,1,0,0,0,0 //AB_ADORAMUS#Adoramus# +4063,2041,3,34,1,0,0,0,0,0,0,0,0 //AB_CLEMENTIA#Crementia# +4063,2042,3,29,1,0,0,0,0,0,0,0,0 //AB_CANTO#Canto Candidus# +4063,2043,3,28,1,0,0,0,0,0,0,0,0 //AB_CHEAL#Coluceo Heal# +4063,2044,5,2039,1,2051,1,0,0,0,0,0,0 //AB_EPICLESIS#Epiclesis# +4063,2045,10,73,1,0,0,0,0,0,0,0,0 //AB_PRAEFATIO#Praefatio# +4063,2046,10,2045,5,0,0,0,0,0,0,0,0 //AB_ORATIO#Oratio# +4063,2047,4,72,1,0,0,0,0,0,0,0,0 //AB_LAUDAAGNUS#Lauda Agnus# +4063,2048,4,2047,2,0,0,0,0,0,0,0,0 //AB_LAUDARAMUS#Lauda Ramus# +4063,2049,10,2044,1,2053,1,0,0,0,0,0,0 //AB_EUCHARISTICA#Eucharistica# +4063,2050,1,2043,3,0,0,0,0,0,0,0,0 //AB_RENOVATIO#Renovatio# +4063,2051,5,2050,1,0,0,0,0,0,0,0,0 //AB_HIGHNESSHEAL#Highness Heal# +4063,2052,5,2048,2,0,0,0,0,0,0,0,0 //AB_CLEARANCE#Clearance# +4063,2053,5,2046,5,2054,5,0,0,0,0,0,0 //AB_EXPIATIO#Expiatio# +4063,2054,10,68,1,0,0,0,0,0,0,0,0 //AB_DUPLELIGHT#Duple Light# +4063,2057,5,2052,1,0,0,0,0,0,0,0,0 //AB_SILENTIUM#Silentium# +4063,2515,5,2044,1,2053,1,0,0,0,0,0,0 //AB_SECRAMENT#Secrament# +//Mechanic (Trans) +4064,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill# +4064,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid# +4064,36,10,0,0,0,0,0,0,0,0,0,0 //MC_INCCARRY#Enlarge Weight Limit# +4064,37,10,36,3,0,0,0,0,0,0,0,0 //MC_DISCOUNT#Discount# +4064,38,10,37,3,0,0,0,0,0,0,0,0 //MC_OVERCHARGE#Overcharge# +4064,39,10,36,5,0,0,0,0,0,0,0,0 //MC_PUSHCART#Pushcart# +4064,40,1,0,0,0,0,0,0,0,0,0,0 //MC_IDENTIFY#Item Appraisal# +4064,41,10,39,3,0,0,0,0,0,0,0,0 //MC_VENDING#Vending# +4064,42,10,0,0,0,0,0,0,0,0,0,0 //MC_MAMMONITE#Mammonite# +4064,153,1,0,0,0,0,0,0,0,0,0,0 //MC_CARTREVOLUTION#Cart Revolution# +4064,154,1,0,0,0,0,0,0,0,0,0,0 //MC_CHANGECART#Change Cart# +4064,155,1,0,0,0,0,0,0,0,0,0,0 //MC_LOUD#Crazy Uproar# +4064,94,5,0,0,0,0,0,0,0,0,0,0 //BS_IRON#Iron Tempering# +4064,95,5,94,1,0,0,0,0,0,0,0,0 //BS_STEEL#Steel Tempering# +4064,96,5,94,1,0,0,0,0,0,0,0,0 //BS_ENCHANTEDSTONE#Enchanted Stone Craft# +4064,97,5,96,1,0,0,0,0,0,0,0,0 //BS_ORIDEOCON#Oridecon Research# +4064,98,3,0,0,0,0,0,0,0,0,0,0 //BS_DAGGER#Smith Dagger# +4064,99,3,98,1,0,0,0,0,0,0,0,0 //BS_SWORD#Smith Sword# +4064,100,3,99,1,0,0,0,0,0,0,0,0 //BS_TWOHANDSWORD#Smith Two-handed Sword# +4064,101,3,99,2,0,0,0,0,0,0,0,0 //BS_AXE#Smith Axe# +4064,102,3,103,1,0,0,0,0,0,0,0,0 //BS_MACE#Smith Mace# +4064,103,3,98,1,0,0,0,0,0,0,0,0 //BS_KNUCKLE#Smith Knucklebrace# +4064,104,3,98,2,0,0,0,0,0,0,0,0 //BS_SPEAR#Smith Spear# +4064,105,1,0,0,0,0,0,0,0,0,0,0 //BS_HILTBINDING#Hilt Binding# +4064,106,1,95,1,105,1,0,0,0,0,0,0 //BS_FINDINGORE#Ore Discovery# +4064,107,10,105,1,0,0,0,0,0,0,0,0 //BS_WEAPONRESEARCH#Weaponry Research# +4064,108,1,107,1,0,0,0,0,0,0,0,0 //BS_REPAIRWEAPON#Weapon Repair# +4064,109,5,0,0,0,0,0,0,0,0,0,0 //BS_SKINTEMPER#Skin Tempering# +4064,110,5,0,0,0,0,0,0,0,0,0,0 //BS_HAMMERFALL#Hammer Fall# +4064,111,5,110,2,0,0,0,0,0,0,0,0 //BS_ADRENALINE#Adrenaline Rush# +4064,112,5,107,2,111,2,0,0,0,0,0,0 //BS_WEAPONPERFECT#Weapon Perfection# +4064,113,5,111,3,0,0,0,0,0,0,0,0 //BS_OVERTHRUST#Power-Thrust# +4064,114,5,112,3,113,2,0,0,0,0,0,0 //BS_MAXIMIZE#Maximize Power# +4064,1012,1,0,0,0,0,0,0,0,0,0,0 //BS_UNFAIRLYTRICK#Unfair Trick# +4064,1013,1,0,0,0,0,0,0,0,0,0,0 //BS_GREED#Greed# +4064,384,10,109,3,105,1,107,5,113,3,0,0 //WS_MELTDOWN#Shattering Strike# +4064,387,1,39,5,153,1,154,1,105,1,0,0 //WS_CARTBOOST#Cart Boost# +4064,477,10,107,10,0,0,0,0,0,0,0,0 //WS_WEAPONREFINE#Upgrade Weapon# +4064,485,10,42,10,110,5,387,1,0,0,0,0 //WS_CARTTERMINATION#Cart Termination# +4064,486,5,113,5,0,0,0,0,0,0,0,0 //WS_OVERTHRUSTMAX#Maximum Power Thrust# +4064,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby# +4064,459,1,111,5,0,0,0,0,0,0,0,0 //BS_ADRENALINE2#Full Adrenaline Rush# +4064,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R# +4064,2255,5,0,0,0,0,0,0,0,0,0,0 //NC_MADOLICENCE#Mado License# +4064,2256,5,2255,1,0,0,0,0,0,0,0,0 //NC_BOOSTKNUCKLE#Boost Knuckle# +4064,2257,3,2256,2,0,0,0,0,0,0,0,0 //NC_PILEBUNKER#Pile Bunker# +4064,2258,3,2256,2,0,0,0,0,0,0,0,0 //NC_VULCANARM#Vulcan Arm# +4064,2259,3,2258,3,0,0,0,0,0,0,0,0 //NC_FLAMELAUNCHER#Flame Launcher# +4064,2260,3,2258,3,0,0,0,0,0,0,0,0 //NC_COLDSLOWER#Cold Slower# +4064,2261,3,2259,2,2260,2,0,0,0,0,0,0 //NC_ARMSCANNON#Arm Cannon# +4064,2262,3,2255,1,0,0,0,0,0,0,0,0 //NC_ACCELERATION#Acceleration# +4064,2263,1,2262,1,0,0,0,0,0,0,0,0 //NC_HOVERING#Hovering# +4064,2264,1,2263,1,0,0,0,0,0,0,0,0 //NC_F_SIDESLIDE#Front-Side Slide# +4064,2265,1,2263,1,0,0,0,0,0,0,0,0 //NC_B_SIDESLIDE#Back-Side Slide# +4064,2266,4,2255,4,0,0,0,0,0,0,0,0 //NC_MAINFRAME#Mainframe Restructure# +4064,2267,3,2266,2,0,0,0,0,0,0,0,0 //NC_SELFDESTRUCTION#Self Destruction# +4064,2268,4,2266,2,0,0,0,0,0,0,0,0 //NC_SHAPESHIFT#Shape Shift# +4064,2269,1,2267,2,0,0,0,0,0,0,0,0 //NC_EMERGENCYCOOL#Emergency Cool# +4064,2270,1,2268,2,0,0,0,0,0,0,0,0 //NC_INFRAREDSCAN#Infrared Scan# +4064,2271,3,2270,1,0,0,0,0,0,0,0,0 //NC_ANALYZE#Analyze# +4064,2272,3,2269,1,0,0,0,0,0,0,0,0 //NC_MAGNETICFIELD#Magnetic Field# +4064,2273,3,2272,2,0,0,0,0,0,0,0,0 //NC_NEUTRALBARRIER#Neutral Barrier# +4064,2274,3,2271,3,2273,2,0,0,0,0,0,0 //NC_STEALTHFIELD#Stealth Field# +4064,2275,5,2255,1,0,0,0,0,0,0,0,0 //NC_REPAIR#Repair# +4064,2276,10,0,0,0,0,0,0,0,0,0,0 //NC_TRAININGAXE#Axe Training# +4064,2277,5,0,0,0,0,0,0,0,0,0,0 //NC_RESEARCHFE#Research Fire/Earth# +4064,2278,5,2276,1,0,0,0,0,0,0,0,0 //NC_AXEBOOMERANG#Axe Boomerang# +4064,2279,5,2278,3,0,0,0,0,0,0,0,0 //NC_POWERSWING#Power Swing# +4064,2280,5,2276,1,0,0,0,0,0,0,0,0 //NC_AXETORNADO#Axe Tornado# +4064,2281,5,2277,2,0,0,0,0,0,0,0,0 //NC_SILVERSNIPER#FAW - Silver Sniper# +4064,2282,5,2277,2,0,0,0,0,0,0,0,0 //NC_MAGICDECOY#FAW - Magic Decoy# +4064,2283,1,2281,1,0,0,0,0,0,0,0,0 //NC_DISJOINT#FAW Removal# +4064,2535,1,41,1,0,0,0,0,0,0,0,0 //ALL_BUYING_STORE#Open Buying Store# +//Guillotine Cross (Trans) +4065,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill# +4065,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid# +4065,48,10,0,0,0,0,0,0,0,0,0,0 //TF_DOUBLE#Double Attack# +4065,49,10,0,0,0,0,0,0,0,0,0,0 //TF_MISS#Improve Dodge# +4065,50,10,0,0,0,0,0,0,0,0,0,0 //TF_STEAL#Steal# +4065,51,10,50,5,0,0,0,0,0,0,0,0 //TF_HIDING#Hiding# +4065,52,10,0,0,0,0,0,0,0,0,0,0 //TF_POISON#Envenom# +4065,53,1,52,3,0,0,0,0,0,0,0,0 //TF_DETOXIFY#Detoxify# +4065,149,1,0,0,0,0,0,0,0,0,0,0 //TF_SPRINKLESAND#Throw Sand# +4065,150,1,0,0,0,0,0,0,0,0,0,0 //TF_BACKSLIDING#Back Sliding# +4065,151,1,0,0,0,0,0,0,0,0,0,0 //TF_PICKSTONE#Find Stone# +4065,152,1,0,0,0,0,0,0,0,0,0,0 //TF_THROWSTONE#Stone Fling# +4065,132,5,0,0,0,0,0,0,0,0,0,0 //AS_RIGHT#Righthand Mastery# +4065,133,5,132,2,0,0,0,0,0,0,0,0 //AS_LEFT#Lefthand Mastery# +4065,134,10,0,0,0,0,0,0,0,0,0,0 //AS_KATAR#Katar Mastery# +4065,135,10,51,2,0,0,0,0,0,0,0,0 //AS_CLOAKING#Cloaking# +4065,136,10,134,4,0,0,0,0,0,0,0,0 //AS_SONICBLOW#Sonic Blow# +4065,137,5,135,2,136,5,0,0,0,0,0,0 //AS_GRIMTOOTH#Grimtooth# +4065,138,10,52,1,0,0,0,0,0,0,0,0 //AS_ENCHANTPOISON#Enchant Poison# +4065,139,10,138,3,0,0,0,0,0,0,0,0 //AS_POISONREACT#Poison React# +4065,140,10,138,5,0,0,0,0,0,0,0,0 //AS_VENOMDUST#Venom Dust# +4065,141,10,139,5,140,5,0,0,0,0,0,0 //AS_SPLASHER#Venom Splasher# +4065,1003,1,0,0,0,0,0,0,0,0,0,0 //AS_SONICACCEL#Sonic Acceleration# +4065,1004,1,0,0,0,0,0,0,0,0,0,0 //AS_VENOMKNIFE#Throw Venom Knife# +4065,376,5,48,5,134,7,0,0,0,0,0,0 //ASC_KATAR#Advanced Katar Mastery# +4065,378,5,407,1,0,0,0,0,0,0,0,0 //ASC_EDP#Deadly Poison Enchantment# +4065,379,10,48,5,135,3,138,6,52,5,0,0 //ASC_BREAKER#Soul Destroyer# +4065,406,10,132,3,134,5,136,5,379,1,0,0 //ASC_METEORASSAULT#Meteor Assault# +4065,407,1,52,10,53,1,138,5,0,0,0,0 //ASC_CDP#Create Deadly Poison# +4065,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby# +4065,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R# +4065,2021,5,138,3,0,0,0,0,0,0,0,0 //GC_VENOMIMPRESS#Venom Impress# +4065,2022,5,136,10,0,0,0,0,0,0,0,0 //GC_CROSSIMPACT#Cross Impact# +4065,2023,5,2022,3,0,0,0,0,0,0,0,0 //GC_DARKILLUSION#Dark Illusion# +4065,2024,10,0,0,0,0,0,0,0,0,0,0 //GC_RESEARCHNEWPOISON#Research New Poison# +4065,2025,1,2024,1,0,0,0,0,0,0,0,0 //GC_CREATENEWPOISON#Create New Poison# +4065,2026,1,2024,5,0,0,0,0,0,0,0,0 //GC_ANTIDOTE#Antidote# +4065,2027,5,2025,1,0,0,0,0,0,0,0,0 //GC_POISONINGWEAPON#Poisoning Weapon# +4065,2028,5,133,5,0,0,0,0,0,0,0,0 //GC_WEAPONBLOCKING#Weapon Blocking# +4065,2029,5,2028,1,0,0,0,0,0,0,0,0 //GC_COUNTERSLASH#Counter Slash# +4065,2030,5,2028,1,0,0,0,0,0,0,0,0 //GC_WEAPONCRUSH#Weapon Crush# +4065,2031,5,2027,3,2028,1,0,0,0,0,0,0 //GC_VENOMPRESSURE#Venom Pressure# +4065,2032,5,2027,5,2031,5,0,0,0,0,0,0 //GC_POISONSMOKE#Poison Smoke# +4065,2033,5,135,3,0,0,0,0,0,0,0,0 //GC_CLOAKINGEXCEED#Cloaking Exceed# +4065,2034,1,2023,5,2033,5,0,0,0,0,0,0 //GC_PHANTOMMENACE#Phantom Menace# +4065,2035,5,2034,1,0,0,0,0,0,0,0,0 //GC_HALLUCINATIONWALK#Hallucination Walk# +4065,2036,5,136,10,0,0,0,0,0,0,0,0 //GC_ROLLINGCUTTER#Rolling Cutter# +4065,2037,5,2036,1,0,0,0,0,0,0,0,0 //GC_CROSSRIPPERSLASHER#Cross Ripper Slasher# \ No newline at end of file diff --git a/db/skill_unit_db.txt b/db/skill_unit_db.txt index 244f56ab0..45ecbc767 100644 --- a/db/skill_unit_db.txt +++ b/db/skill_unit_db.txt @@ -33,6 +33,7 @@ 70,0x83, , -1, 1,1000,all, 0x018 //PR_SANCTUARY 79,0x84, , -1, 1,3000,enemy, 0x018 //PR_MAGNUS 80,0x87,0x88, 0, 1,2000,enemy, 0x006 //WZ_FIREPILLAR + 82,0x86, , 0, 3,1000,enemy, 0x018 //WZ_FIREIVY 83,0x86, , 0, 3,1000,enemy, 0x010 //WZ_METEOR 85,0x86, , 0, 6:6:6:6:6:6:6:6:6:6:8,1250,enemy,0x018 //WZ_VERMILION 87,0x8d, , -1, 0, -1,all, 0x010 //WZ_ICEWALL @@ -95,6 +96,26 @@ 535,0xbd, , -1, 0, 20,enemy, 0x010 //NJ_KAENSIN 538,0xbb, , 1:1:1:2:2:2:3:3:3:4,0,-1,all,0x010 //NJ_SUITON 670,0xc7, , 1, 4:7:10:13:16:19:22:25:28:31,1000,all,0x008 //NPC_EVILLAND + +2044,0xca, , 0, 3,1000,all, 0x018 //AB_EPICLESIS + +2032,0xe1, , 2, 0,1000,enemy, 0x018 //GC_POISONSMOKE + +2214,0x86, , 0, 5, 100,enemy, 0x080 //WL_CHAINLIGHTNING +2216,0xcb, , -1, 2,2000,enemy, 0x018 //WL_EARTHSTRAIN + +2238,0xd8, , 0, 1,1000,enemy, 0x006 //RA_ELECTRICSHOCKER +2239,0xd9, , 0, 1,1000,enemy, 0x006 //RA_CLUSTERBOMB +2249,0xd2, , 0, 1,1000,enemy, 0x026 //RA_MAGENTATRAP +2250,0xd3, , 0, 1,1000,enemy, 0x026 //RA_COBALTTRAP +2251,0xd4, , 0, 1,1000,enemy, 0x026 //RA_MAIZETRAP +2252,0xd5, , 0, 1,1000,enemy, 0x026 //RA_VERDURETRAP +2253,0xd6, , 0, 1,1000,enemy, 0x006 //RA_FIRINGTRAP +2254,0xd7, , 0, 1,1000,enemy, 0x006 //RA_ICEBOUNDTRAP + +2273,0xe2, , 1, 0, 500,friend,0x000 //NC_NEUTRALBARRIER +2274,0xe3, , 1, 0, 500,all, 0x000 //NC_STEALTHFIELD + 8208,0x86, , 0, 2,1000,enemy, 0x080 //MA_SHOWER 8209,0x90, , 0, 1,1000,enemy, 0x006 //MA_SKIDTRAP 8210,0x93, , 0, 0,1000,enemy, 0x006 //MA_LANDMINE diff --git a/db/spellbook_db.txt b/db/spellbook_db.txt new file mode 100644 index 000000000..ee3a0c323 --- /dev/null +++ b/db/spellbook_db.txt @@ -0,0 +1,29 @@ +//============================================================ +// Preserve points database for Reading Spellbook. [LimitLine/3CeAm] +// Structure: +// SkillID,PreservePoints,Required Book +//============================================================ +//To add more entries skill.h MAX_SKILL_SPELLBOOK_DB must be increased + +//Mage +14,7,6190 //Cold Bolt +19,7,6189 //Fire Bolt +20,7,6191 //Lightning Bolt +21,9,6197 //Thunder Storm + +//Wizard +83,10,6194 //Meteor Storm +84,9,6198 //Jupitel Thunder +85,10,6193 //Lord of Vermillion +86,9,6199 //Water Ball +89,10,6192 //Storm Gust +90,8,6201 //Earth Spike +91,9,6200 //Heaven's Drive + +//Warlock +2210,8,6205 //Drain Life +2211,12,6204 //Crimson Rock +2213,22,6195 //Comet +2214,12,6203 //Chain Lightning +2216,12,6202 //Earth Strain +2217,22,6196 //Tetra Vortex diff --git a/db/statpoint_renewal.txt b/db/statpoint_renewal.txt new file mode 100644 index 000000000..cd876c4cd --- /dev/null +++ b/db/statpoint_renewal.txt @@ -0,0 +1,255 @@ +48 +51 +54 +57 +60 +64 +68 +72 +76 +80 +85 +90 +95 +100 +105 +111 +117 +123 +129 +135 +142 +149 +156 +163 +170 +178 +186 +194 +202 +210 +219 +228 +237 +246 +255 +265 +275 +285 +295 +305 +316 +327 +338 +349 +360 +372 +384 +396 +408 +420 +433 +446 +459 +472 +485 +499 +513 +527 +541 +555 +570 +585 +600 +615 +630 +646 +662 +678 +694 +710 +727 +744 +761 +778 +795 +813 +831 +849 +867 +885 +904 +923 +942 +961 +980 +1000 +1020 +1040 +1060 +1080 +1101 +1122 +1143 +1164 +1185 +1207 +1229 +1251 +1273 +1295 +1318 +1341 +1364 +1387 +1410 +1433 +1456 +1479 +1502 +1525 +1549 +1573 +1597 +1621 +1645 +1669 +1693 +1717 +1741 +1765 +1790 +1815 +1840 +1865 +1890 +1915 +1940 +1965 +1990 +2015 +2041 +2067 +2093 +2119 +2145 +2171 +2197 +2223 +2249 +2275 +2302 +2329 +2356 +2383 +2410 +2437 +2464 +2491 +2518 +2545 +2573 +2601 +2629 +2657 +2685 +2713 +2743 +2769 +2797 +2825 +2854 +2883 +2912 +2941 +2970 +2999 +3028 +3057 +3086 +3115 +3145 +3175 +3205 +3235 +3265 +3295 +3325 +3355 +3385 +3415 +3446 +3477 +3508 +3539 +3570 +3601 +3632 +3663 +3694 +3725 +3757 +3789 +3821 +3853 +3885 +3917 +3949 +3981 +4013 +4045 +4078 +4111 +4114 +4177 +4210 +4243 +4276 +4309 +4342 +4375 +4409 +4443 +4477 +4511 +4545 +4579 +4613 +4647 +4681 +4715 +4750 +4785 +4820 +4855 +4890 +4925 +4960 +5030 +5065 +5100 +5136 +5172 +5208 +5244 +5280 +5316 +5352 +5388 +5424 +5460 +5497 +5537 +5571 +5608 +5645 +5682 +5719 +5793 +5830 +5868 +5906 +5944 +5982 +6020 +6058 \ No newline at end of file diff --git a/sql-files/main.sql b/sql-files/main.sql index feafcae3e..22ccc186f 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -164,7 +164,7 @@ CREATE TABLE IF NOT EXISTS `global_reg_value` ( `char_id` int(11) unsigned NOT NULL default '0', `str` varchar(255) NOT NULL default '', `value` varchar(255) NOT NULL default '0', - `type` int(11) NOT NULL default '3', + `type` tinyint(1) NOT NULL default '3', `account_id` int(11) unsigned NOT NULL default '0', PRIMARY KEY (`char_id`,`str`,`account_id`), KEY `account_id` (`account_id`), diff --git a/sql-files/upgrade_svn15003.sql b/sql-files/upgrade_svn15003.sql new file mode 100644 index 000000000..28b4f451e --- /dev/null +++ b/sql-files/upgrade_svn15003.sql @@ -0,0 +1 @@ +ALTER TABLE `global_reg_value` MODIFY `type` TINYINT(1) UNSIGNED NOT NULL DEFAULT '3'; diff --git a/src/common/mmo.h b/src/common/mmo.h index 239e1dddd..f8ef63390 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -44,8 +44,8 @@ // 20110928 - 2011-09-28aRagexeRE+ - 0x6b, 0x6d #ifndef PACKETVER - #define PACKETVER 20081126 - //#define PACKETVER 20100707 + #define PACKETVER 20110609 + //#define PACKETVER 20100730 #endif // backward compatible PACKETVER 8 and 9 #if PACKETVER == 8 @@ -176,6 +176,7 @@ enum item_types { IT_UNKNOWN2,//9 IT_AMMO, //10 IT_DELAYCONSUME,//11 + IT_THROWWEAPON= 17,//17 IT_CASH = 18, IT_MAX }; @@ -646,6 +647,56 @@ enum { JOB_STAR_GLADIATOR, JOB_STAR_GLADIATOR2, JOB_SOUL_LINKER, + /** + * 3.1 (2.1) + **/ + JOB_RUNE_KNIGHT = 4054, + JOB_WARLOCK, + JOB_RANGER, + JOB_ARCH_BISHOP, + JOB_MECHANIC, + JOB_GUILLOTINE_CROSS, + /** + * 3.1 (2.1 Trans) + **/ + JOB_RUNE_KNIGHT_T, + JOB_WARLOCK_T, + JOB_RANGER_T, + JOB_ARCH_BISHOP_T, + JOB_MECHANIC_T, + JOB_GUILLOTINE_CROSS_T, + /** + * 3.2 (2.2) + **/ + JOB_ROYAL_GUARD, + JOB_SORCERER, + JOB_MINSTREL, + JOB_WANDERER, + JOB_SURA, + JOB_GENETIC, + JOB_SHADOW_CHASER, + /** + * 3.2 (2.2 Trans) + **/ + JOB_ROYAL_GUARD_T, + JOB_SORCERER_T, + JOB_MINSTREL_T, + JOB_WANDERER_T, + JOB_SURA_T, + JOB_GENETIC_T, + JOB_SHADOW_CHASER_T, + /** + * 3.x Mounts / Vehicles + **/ + JOB_RUNE_KNIGHT2, + JOB_RUNE_KNIGHT_T2, + JOB_ROYAL_GUARD2, + JOB_ROYAL_GUARD_T2, + JOB_RANGER2, + JOB_RANGER_T2, + JOB_MECHANIC2, + JOB_MECHANIC_T2, + JOB_MAX, }; diff --git a/src/common/showmsg.c b/src/common/showmsg.c index fc1badd26..a69c73ba2 100644 --- a/src/common/showmsg.c +++ b/src/common/showmsg.c @@ -4,6 +4,8 @@ #include "../common/cbasetypes.h" #include "../common/strlib.h" // StringBuf #include "showmsg.h" +#include "core.h" //[Ind] - For SERVER_TYPE +#include "version.h" //[Ind] - For SERVER_TYPE values #include #include @@ -51,6 +53,8 @@ int stdout_with_ansisequence = 0; int msg_silent = 0; //Specifies how silent the console is. +int console_msg_log = 0;//[Ind] msg error logging + /////////////////////////////////////////////////////////////////////////////// /// static/dynamic buffer for the messages @@ -683,6 +687,29 @@ int _vShowMessage(enum msg_type flag, const char *string, va_list ap) ShowError("Empty string passed to _vShowMessage().\n"); return 1; } + if( + ( flag == MSG_WARNING && console_msg_log&1 ) || + ( ( flag == MSG_ERROR || flag == MSG_SQL ) && console_msg_log&2 ) || + ( flag == MSG_DEBUG && console_msg_log&4 ) ) {//[Ind] + FILE *log = NULL; + if( (log = fopen(SERVER_TYPE == ATHENA_SERVER_MAP ? "./log/map-msg_log.log" : "./log/unknown.log","a+")) ) { + char timestring[255]; + time_t curtime; + time(&curtime); + strftime(timestring, 254, "%m/%d/%Y %H:%M:%S", localtime(&curtime)); + fprintf(log,"(%s) [ %s ] : ", + timestring, + flag == MSG_WARNING ? "Warning" : + flag == MSG_ERROR ? "Error" : + flag == MSG_SQL ? "SQL Error" : + flag == MSG_DEBUG ? "Debug" : + "Unknown"); + va_copy(apcopy, ap); + vfprintf(log,string,apcopy); + va_end(apcopy); + fclose(log); + } + } if( (flag == MSG_INFORMATION && msg_silent&1) || (flag == MSG_STATUS && msg_silent&2) || diff --git a/src/common/showmsg.h b/src/common/showmsg.h index 998296b66..5f80a4312 100644 --- a/src/common/showmsg.h +++ b/src/common/showmsg.h @@ -67,6 +67,7 @@ extern int stdout_with_ansisequence; //If the color ansi sequences are to be used. [flaviojs] extern int msg_silent; //Specifies how silent the console is. [Skotlex] +extern int console_msg_log; //Specifies what error messages to log. [Ind] extern char timestamp_format[20]; //For displaying Timestamps [Skotlex] enum msg_type { diff --git a/src/map/Makefile.in b/src/map/Makefile.in index 09e92dde2..60fc49f7c 100644 --- a/src/map/Makefile.in +++ b/src/map/Makefile.in @@ -34,7 +34,9 @@ MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \ storage.h skill.h atcommand.h battle.h battleground.h \ intif.h trade.h party.h vending.h guild.h pet.h \ log.h mail.h date.h unit.h homunculus.h mercenary.h quest.h instance.h mapreg.h \ - buyingstore.h searchstore.h duel.h + buyingstore.h searchstore.h duel.h \ + RRConfig/Core.h RRConfig/Renewal.h RRConfig/Secure.h RRConfig/Data/Const.h \ + RRConfig/Skills/General.h RRConfig/Skills/Mage_Classes.h RRConfig/Skills/Swordsman_Classes.h HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) diff --git a/src/map/RRConfig/Core.h b/src/map/RRConfig/Core.h new file mode 100644 index 000000000..9cb161a3f --- /dev/null +++ b/src/map/RRConfig/Core.h @@ -0,0 +1,28 @@ +#ifndef _RRCONFIGS_ +#define _RRCONFIGS_ +/** + * Ragnarok Resources Configuration File (http://ro-resources.net) + * The following settings are applied upon compiling the program, + * therefore any settings you disable will not even be added to the program + * making these settings the most performance-effiecient possible + **/ + +/** + * @INFO: RREmu Settings Core + * - For detailed guidance on these check http://trac.ro-resources.net/wiki/CoreConfiguration + **/ + +/** + * No settings past this point + **/ +#include "./Renewal.h" +#include "./Secure.h" +#include "./Skills/General.h" +/** + * Constants come last; so they process anything that could've been modified in early includes + **/ +#include "./Data/Const.h" +/** + * End of File + **/ +#endif diff --git a/src/map/RRConfig/Data/Const.h b/src/map/RRConfig/Data/Const.h new file mode 100644 index 000000000..6da8cdf13 --- /dev/null +++ b/src/map/RRConfig/Data/Const.h @@ -0,0 +1,33 @@ +#ifndef _RRCONFIGS_CONST_ +#define _RRCONFIGS_CONST_ +/** + * Ragnarok Resources Configuration File (http://ro-resources.net) + * The following settings are applied upon compiling the program, + * therefore any settings you disable will not even be added to the program + * making these settings the most performance-effiecient possible + **/ + +/** + * @INFO: This file holds constants that aims at making code smoother and more efficient + */ + +/** + * "Constants" + **/ +#define CONST_CASTRATE_SCALE ( RECASTING ? RECASTING_VMIN : battle_config.castrate_dex_scale ) +#define CONST_CASTRATE_CALC ( RECASTING ? ((status_get_dex(bl)*2)+status_get_int(bl)) : status_get_dex(bl) ) + +/** + * "Sane Checks" to save you from compiling with cool bugs + **/ +#if SECURE_NPCTIMEOUT_INTERVAL <= 0 + #error SECURE_NPCTIMEOUT_INTERVAL should be at least 1 (1s) +#endif +#if SECURE_NPCTIMEOUT < 0 + #error SECURE_NPCTIMEOUT cannot be lower than 0 +#endif + +/** + * End of File + **/ +#endif \ No newline at end of file diff --git a/src/map/RRConfig/Renewal.h b/src/map/RRConfig/Renewal.h new file mode 100644 index 000000000..db5a99008 --- /dev/null +++ b/src/map/RRConfig/Renewal.h @@ -0,0 +1,53 @@ +#ifndef _RRCONFIGS_RE_ +#define _RRCONFIGS_RE_ +/** + * Ragnarok Resources Configuration File (http://ro-resources.net) + * The following settings are applied upon compiling the program, + * therefore any settings you disable will not even be added to the program + * making these settings the most performance-effiecient possible + **/ + +/** + * @INFO: This file holds general-purpose renewal settings, for class-specific ones check /src/map/RRConfig/Skills folder + **/ + +/** + * Game Server Mode + * @values: 1 or 0 + * 1 : renewal support, such as renewal-exclusive formulas + * -> Note some features may be enabled/disabled at this file despite this setting being ON + * 0 : renewal support disabled, use original formulas + **/ +#define RRMODE 1 + +/** + * Renewal Cast Time + * @values: 1 (enabled) or 0 (disabled) + * 1 : Cast Time is decreased by DEX*2+INT, 20% of the cast time is not reduced by stats, + * - for example, on a skill whose cast time is 10s, only 8s may be reduced. other 2s are + * - part of a "fixed cast time" that is only reduced by special items and skills (such as + * - Arch Bishop's Sacrament skill). + * 0 : the old cast time method, influenced by dex, items and skills. + **/ +#define RECASTING 1 + +/** + * Renewal Cast Time : Variable-Free + * - Value required for no variable cast time with stats. + * - Formula: (casterDex x 2) + (casterInt) + * Default: 530 + **/ +#define RECASTING_VMIN 530 + +/** + * Renewal Enchant Deadly Poison Change + * - In RE EDP no longer increases final damage by 400%. + * - it increases your weapon atk and your stat atk + * - it doesn't affect grimtooth + **/ +#define RE_EDP 1 + +/** + * End of File + **/ +#endif \ No newline at end of file diff --git a/src/map/RRConfig/Secure.h b/src/map/RRConfig/Secure.h new file mode 100644 index 000000000..1288b259f --- /dev/null +++ b/src/map/RRConfig/Secure.h @@ -0,0 +1,36 @@ +#ifndef _RRCONFIGS_SECURE_ +#define _RRCONFIGS_SECURE_ +/** + * Ragnarok Resources Configuration File (http://ro-resources.net) + * The following settings are applied upon compiling the program, + * therefore any settings you disable will not even be added to the program + * making these settings the most performance-effiecient possible + **/ + +/** + * @INFO: This file holds optional security settings + **/ + +/** + * Optional NPC Dialog Timer + * When enabled all npcs dialog will 'timeout' if user is on idle for longer than the amount of seconds allowed + * - On 'timeout' the npc dialog window changes it's next/menu to a 'close' button + * @values + * - ? : Desired idle time in seconds (e.g. 10) + * - 0 : Disabled + **/ +#define SECURE_NPCTIMEOUT 0 + +/** + * (Secure) Optional NPC Dialog Timer + * @requirement : SECURE_NPCTIMEOUT must be enabled + * Minimum Interval Between timeout checks in seconds + * Default: 1s + **/ +#define SECURE_NPCTIMEOUT_INTERVAL 1 + + +/** + * End of File + **/ +#endif \ No newline at end of file diff --git a/src/map/RRConfig/Skills/General.h b/src/map/RRConfig/Skills/General.h new file mode 100644 index 000000000..5944d6844 --- /dev/null +++ b/src/map/RRConfig/Skills/General.h @@ -0,0 +1,23 @@ +#ifndef _RRCONFIGS_SKILLS_GENERAL_ +#define _RRCONFIGS_SKILLS_GENERAL_ +/** + * Ragnarok Resources Configuration File (http://ro-resources.net) + * The following settings are applied upon compiling the program, + * therefore any settings you disable will not even be added to the program + * making these settings the most performance-effiecient possible + **/ + +/** + * Default Magical Reflection Behavior + * - When reflecting, reflected damage depends on gears caster is wearing, not target + * - When disabled damage depends on gears target is wearing, not caster. + * @values 1 (enabled) or 0 (disabled) + **/ +#define RR_MAGIC_REFLECTION 1 + +/** + * No settings past this point + **/ +#include "Mage_Classes.h" +#include "Swordsman_Classes.h" +#endif diff --git a/src/map/RRConfig/Skills/Mage_Classes.h b/src/map/RRConfig/Skills/Mage_Classes.h new file mode 100644 index 000000000..cf0777787 --- /dev/null +++ b/src/map/RRConfig/Skills/Mage_Classes.h @@ -0,0 +1,19 @@ +#ifndef _RRCONFIGS_SKILLS_MAGE_ +#define _RRCONFIGS_SKILLS_MAGE_ +/** + * Ragnarok Resources Configuration File (http://ro-resources.net) + * The following settings are applied upon compiling the program, + * therefore any settings you disable will not even be added to the program + * making these settings the most performance-effiecient possible + **/ + +/** + * (Wizard/HW/Warlock) enable Fire Ivy skill? (1 OR 0) + * Default: 0 (disabled) + **/ +#define FIREIVY_ON 0 + +/** + * No settings past this point + **/ +#endif diff --git a/src/map/RRConfig/Skills/Swordsman_Classes.h b/src/map/RRConfig/Skills/Swordsman_Classes.h new file mode 100644 index 000000000..4dddeec54 --- /dev/null +++ b/src/map/RRConfig/Skills/Swordsman_Classes.h @@ -0,0 +1,19 @@ +#ifndef _RRCONFIGS_SKILLS_SWORDS_ +#define _RRCONFIGS_SKILLS_SWORDS_ +/** + * Ragnarok Resources Configuration File (http://ro-resources.net) + * The following settings are applied upon compiling the program, + * therefore any settings you disable will not even be added to the program + * making these settings the most performance-effiecient possible + **/ + +/** + * (Rune Knight) the maximum rune items a character may have of the same type + * Default: 20 + **/ +#define MAX_RUNE 20 + +/** + * No settings past this point + **/ +#endif diff --git a/src/map/atcommand.c b/src/map/atcommand.c index e98481f22..e87074883 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -1255,7 +1255,7 @@ ACMD_FUNC(jobchange) if (!message || !*message || sscanf(message, "%d %d", &job, &upper) < 1) { int i, found = 0; - const struct { char name[16]; int id; } jobs[] = { + const struct { char name[24]; int id; } jobs[] = { { "novice", 0 }, { "swordsman", 1 }, { "mage", 2 }, @@ -1330,6 +1330,32 @@ ACMD_FUNC(jobchange) { "taekwon girl", 4046 }, { "star gladiator", 4047 }, { "soul linker", 4049 }, + { "rune knight", 4054 }, + { "warlock", 4055 }, + { "ranger", 4056 }, + { "arch bishop", 4057 }, + { "mechanic", 4058 }, + { "guillotine", 4059 }, + { "rune knight (Trans)", 4060 }, + { "warlock (Trans)", 4061 }, + { "ranger (Trans)", 4062 }, + { "arch bishop (Trans)", 4063 }, + { "mechanic (Trans)", 4064 }, + { "guillotine (Trans)", 4065 }, + { "royal guard", 4066 }, + { "sorcerer", 4067 }, + { "minstrel", 4068 }, + { "wanderer", 4069 }, + { "sura", 4070 }, + { "genetic", 4071 }, + { "shadow chaser", 4072 }, + { "royal guard (Trans)", 4073 }, + { "sorcerer (Trans)", 4074 }, + { "minstrel (Trans)", 4075 }, + { "wanderer (Trans)", 4076 }, + { "sura (Trans)", 4077 }, + { "genetic (Trans)", 4078 }, + { "shadow chaser (Trans)", 4079 }, }; for (i=0; i < ARRAYLENGTH(jobs); i++) { @@ -1343,28 +1369,56 @@ ACMD_FUNC(jobchange) if (!found) { clif_displaymessage(fd, "Please, enter job ID (usage: @job/@jobchange )."); - clif_displaymessage(fd, " 0 Novice 7 Knight 14 Crusader 21 N/A"); - clif_displaymessage(fd, " 1 Swordman 8 Priest 15 Monk 22 N/A"); - clif_displaymessage(fd, " 2 Mage 9 Wizard 16 Sage 23 Super Novice"); - clif_displaymessage(fd, " 3 Archer 10 Blacksmith 17 Rogue 24 Gunslinger"); - clif_displaymessage(fd, " 4 Acolyte 11 Hunter 18 Alchemist 25 Ninja"); - clif_displaymessage(fd, " 5 Merchant 12 Assassin 19 Bard 26 N/A"); - clif_displaymessage(fd, " 6 Thief 13 N/A 20 Dancer 27 N/A"); - clif_displaymessage(fd, "4001 Novice High 4008 Lord Knight 4015 Paladin 4022 N/A"); - clif_displaymessage(fd, "4002 Swordman High 4009 High Priest 4016 Champion"); - clif_displaymessage(fd, "4003 Mage High 4010 High Wizard 4017 Professor"); - clif_displaymessage(fd, "4004 Archer High 4011 Whitesmith 4018 Stalker"); - clif_displaymessage(fd, "4005 Acolyte High 4012 Sniper 4019 Creator"); - clif_displaymessage(fd, "4006 Merchant High 4013 Assassin Cross 4020 Clown"); - clif_displaymessage(fd, "4007 Thief High 4014 N/A 4021 Gypsy"); - clif_displaymessage(fd, "4023 Baby Novice 4030 Baby Knight 4037 Baby Crusader 4044 N/A"); - clif_displaymessage(fd, "4024 Baby Swordsman 4031 Baby Priest 4038 Baby Monk 4045 Super Baby"); - clif_displaymessage(fd, "4025 Baby Mage 4032 Baby Wizard 4039 Baby Sage 4046 Taekwon Kid"); - clif_displaymessage(fd, "4026 Baby Archer 4033 Baby Blacksmith 4040 Baby Rogue 4047 Taekwon Master"); - clif_displaymessage(fd, "4027 Baby Acolyte 4034 Baby Hunter 4041 Baby Alchemist 4048 N/A"); - clif_displaymessage(fd, "4028 Baby Merchant 4035 Baby Assassin 4042 Baby Bard 4049 Soul Linker"); - clif_displaymessage(fd, "4029 Baby Thief 4036 N/A 4043 Baby Dancer"); - clif_displaymessage(fd, "[upper]: -1 (default) to automatically determine the 'level', 0 to force normal job, 1 to force high job."); + clif_displaymessage(fd, "----- Novice / 1st Class -----"); + clif_displaymessage(fd, " 0 Novice 1 Swordman 2 Mage 3 Archer"); + clif_displaymessage(fd, " 4 Acolyte 5 Merchant 6 Thief"); + clif_displaymessage(fd, "----- 2nd Class -----"); + clif_displaymessage(fd, " 7 Knight 8 Priest 9 Wizard 10 Blacksmith"); + clif_displaymessage(fd, " 11 Hunter 12 Assassin 14 Crusader 15 Monk"); + clif_displaymessage(fd, " 16 Sage 17 Rogue 18 Alchemist 19 Bard"); + clif_displaymessage(fd, " 20 Dancer"); + clif_displaymessage(fd, "----- High Novice / High 1st Class -----"); + clif_displaymessage(fd, "4001 Novice High 4002 Swordman High 4003 Mage High 4004 Archer High"); + clif_displaymessage(fd, "4005 Acolyte High 4006 Merchant High 4007 Thief High"); + clif_displaymessage(fd, "----- Transcendent 2nd Class -----"); + clif_displaymessage(fd, "4008 Lord Knight 4009 High Priest 4010 High Wizard 4011 Whitesmith"); + clif_displaymessage(fd, "4012 Sniper 4013 Assassin Cross 4015 Paladin 4016 Champion"); + clif_displaymessage(fd, "4017 Professor 4018 Stalker 4019 Creator 4020 Clown"); + clif_displaymessage(fd, "4021 Gypsy"); + clif_displaymessage(fd, "----- 3rd Class (Regular to 3rd) -----"); + clif_displaymessage(fd, "4054 Rune Knight 4055 Warlock 4056 Ranger 4057 Arch Bishop"); + clif_displaymessage(fd, "4058 Mechanic 4059 Guillotine Cross 4066 Royal Guard 4067 Sorcerer"); + clif_displaymessage(fd, "4068 Minstrel 4069 Wanderer 4070 Sura 4071 Genetic"); + clif_displaymessage(fd, "4072 Shadow Chaser"); + clif_displaymessage(fd, "----- 3rd Class (Transcendent to 3rd) -----"); + clif_displaymessage(fd, "4060 Rune Knight 4061 Warlock 4062 Ranger 4063 Arch Bishop"); + clif_displaymessage(fd, "4064 Mechanic 4065 Guillotine Cross 4073 Royal Guard 4074 Sorcerer"); + clif_displaymessage(fd, "4075 Minstrel 4076 Wanderer 4077 Sura 4078 Genetic"); + clif_displaymessage(fd, "4079 Shadow Chaser"); + clif_displaymessage(fd, "----- Expanded Class -----"); + clif_displaymessage(fd, " 23 Super Novice 24 Gunslinger 25 Ninja 26 Xmas"); + clif_displaymessage(fd, " 27 Summer 4046 Taekwon 4047 Star Gladiator 4049 Soul Linker"); + //clif_displaymessage(fd, "4050 Gangsi 4051 Death Knight 4052 Dark Collector"); + clif_displaymessage(fd, "---- 1st And 2nd Baby Class ----"); + clif_displaymessage(fd, "4023 Baby Novice 4024 Baby Swordsman 4025 Baby Mage 4026 Baby Archer"); + clif_displaymessage(fd, "4027 Baby Acolyte 4028 Baby Merchant 4029 Baby Thief 4030 Baby Knight"); + clif_displaymessage(fd, "4031 Baby Priest 4032 Baby Wizard 4033 Baby Blacksmith 4034 Baby Hunter"); + clif_displaymessage(fd, "4035 Baby Assassin 4037 Baby Crusader 4038 Baby Monk 4039 Baby Sage"); + clif_displaymessage(fd, "4040 Baby Rogue 4041 Baby Alchemist 4042 Baby Bard 4043 Baby Dancer"); + clif_displaymessage(fd, "4045 Super Baby"); + //clif_displaymessage(fd, "---- 3rd Baby Class ----"); + //clif_displaymessage(fd, "4096 Baby Rune Knight 4097 Baby Warlock 4098 Baby Ranger"); + //clif_displaymessage(fd, "4099 Baby Arch Bishop 4100 Baby Mechanic 4101 Baby Guillotine Cross"); + //clif_displaymessage(fd, "4102 Baby Royal Guard 4103 Baby Sorcerer 4104 Baby Minstrel"); + //clif_displaymessage(fd, "4105 Baby Wanderer 4106 Baby Sura 4107 Baby Genetic"); + //clif_displaymessage(fd, "4108 Baby Shadow Chaser"); + //clif_displaymessage(fd, "---- Mounts, Modes, And Others ----"); + //clif_displaymessage(fd, " 13 Knight (Peco) 21 Crusader (Peco) 22 Wedding 26 Christmas"); + //clif_displaymessage(fd, " 27 Summer 4014 Lord Knight (Peco) 4022 Paladin (Peco) 4036 Baby Knight (Peco)"); + //clif_displaymessage(fd, "4044 Baby Crusader (Peco) 4048 Star Gladiator (Union) 4080 Rune Knight (Dragon)"); + //clif_displaymessage(fd, "4081 Rune Knight Trans (Dragon) 4082 Royal Guard (Gryphon)"); + //clif_displaymessage(fd, "4083 Royal Guard Trans (Gryphon) 4084 Ranger (Warg) 4085 Ranger Trans (Warg)"); + //clif_displaymessage(fd, "4086 Mechanic (Mado) 4087 Mechanic Trans (Mado)"); return -1; } } @@ -1384,28 +1438,56 @@ ACMD_FUNC(jobchange) } } else { clif_displaymessage(fd, "Please, enter job ID (usage: @job/@jobchange )."); - clif_displaymessage(fd, " 0 Novice 7 Knight 14 Crusader 21 N/A"); - clif_displaymessage(fd, " 1 Swordman 8 Priest 15 Monk 22 N/A"); - clif_displaymessage(fd, " 2 Mage 9 Wizard 16 Sage 23 Super Novice"); - clif_displaymessage(fd, " 3 Archer 10 Blacksmith 17 Rogue 24 Gunslinger"); - clif_displaymessage(fd, " 4 Acolyte 11 Hunter 18 Alchemist 25 Ninja"); - clif_displaymessage(fd, " 5 Merchant 12 Assassin 19 Bard 26 N/A"); - clif_displaymessage(fd, " 6 Thief 13 N/A 20 Dancer 27 N/A"); - clif_displaymessage(fd, "4001 Novice High 4008 Lord Knight 4015 Paladin 4022 N/A"); - clif_displaymessage(fd, "4002 Swordman High 4009 High Priest 4016 Champion"); - clif_displaymessage(fd, "4003 Mage High 4010 High Wizard 4017 Professor"); - clif_displaymessage(fd, "4004 Archer High 4011 Whitesmith 4018 Stalker"); - clif_displaymessage(fd, "4005 Acolyte High 4012 Sniper 4019 Creator"); - clif_displaymessage(fd, "4006 Merchant High 4013 Assassin Cross 4020 Clown"); - clif_displaymessage(fd, "4007 Thief High 4014 N/A 4021 Gypsy"); - clif_displaymessage(fd, "4023 Baby Novice 4030 Baby Knight 4037 Baby Crusader 4044 N/A"); - clif_displaymessage(fd, "4024 Baby Swordsman 4031 Baby Priest 4038 Baby Monk 4045 Super Baby"); - clif_displaymessage(fd, "4025 Baby Mage 4032 Baby Wizard 4039 Baby Sage 4046 Taekwon Kid"); - clif_displaymessage(fd, "4026 Baby Archer 4033 Baby Blacksmith 4040 Baby Rogue 4047 Taekwon Master"); - clif_displaymessage(fd, "4027 Baby Acolyte 4034 Baby Hunter 4041 Baby Alchemist 4048 N/A"); - clif_displaymessage(fd, "4028 Baby Merchant 4035 Baby Assassin 4042 Baby Bard 4049 Soul Linker"); - clif_displaymessage(fd, "4029 Baby Thief 4036 N/A 4043 Baby Dancer"); - clif_displaymessage(fd, "[upper]: -1 (default) to automatically determine the 'level', 0 to force normal job, 1 to force high job."); + clif_displaymessage(fd, "----- Novice / 1st Class -----"); + clif_displaymessage(fd, " 0 Novice 1 Swordman 2 Mage 3 Archer"); + clif_displaymessage(fd, " 4 Acolyte 5 Merchant 6 Thief"); + clif_displaymessage(fd, "----- 2nd Class -----"); + clif_displaymessage(fd, " 7 Knight 8 Priest 9 Wizard 10 Blacksmith"); + clif_displaymessage(fd, " 11 Hunter 12 Assassin 14 Crusader 15 Monk"); + clif_displaymessage(fd, " 16 Sage 17 Rogue 18 Alchemist 19 Bard"); + clif_displaymessage(fd, " 20 Dancer"); + clif_displaymessage(fd, "----- High Novice / High 1st Class -----"); + clif_displaymessage(fd, "4001 Novice High 4002 Swordman High 4003 Mage High 4004 Archer High"); + clif_displaymessage(fd, "4005 Acolyte High 4006 Merchant High 4007 Thief High"); + clif_displaymessage(fd, "----- Transcendent 2nd Class -----"); + clif_displaymessage(fd, "4008 Lord Knight 4009 High Priest 4010 High Wizard 4011 Whitesmith"); + clif_displaymessage(fd, "4012 Sniper 4013 Assassin Cross 4015 Paladin 4016 Champion"); + clif_displaymessage(fd, "4017 Professor 4018 Stalker 4019 Creator 4020 Clown"); + clif_displaymessage(fd, "4021 Gypsy"); + clif_displaymessage(fd, "----- 3rd Class (Regular to 3rd) -----"); + clif_displaymessage(fd, "4054 Rune Knight 4055 Warlock 4056 Ranger 4057 Arch Bishop"); + clif_displaymessage(fd, "4058 Mechanic 4059 Guillotine Cross 4066 Royal Guard 4067 Sorcerer"); + clif_displaymessage(fd, "4068 Minstrel 4069 Wanderer 4070 Sura 4071 Genetic"); + clif_displaymessage(fd, "4072 Shadow Chaser"); + clif_displaymessage(fd, "----- 3rd Class (Transcendent to 3rd) -----"); + clif_displaymessage(fd, "4060 Rune Knight 4061 Warlock 4062 Ranger 4063 Arch Bishop"); + clif_displaymessage(fd, "4064 Mechanic 4065 Guillotine Cross 4073 Royal Guard 4074 Sorcerer"); + clif_displaymessage(fd, "4075 Minstrel 4076 Wanderer 4077 Sura 4078 Genetic"); + clif_displaymessage(fd, "4079 Shadow Chaser"); + clif_displaymessage(fd, "----- Expanded Class -----"); + clif_displaymessage(fd, " 23 Super Novice 24 Gunslinger 25 Ninja 26 Xmas"); + clif_displaymessage(fd, " 27 Summer 4046 Taekwon 4047 Star Gladiator 4049 Soul Linker"); + //clif_displaymessage(fd, "4050 Gangsi 4051 Death Knight 4052 Dark Collector"); + clif_displaymessage(fd, "---- 1st And 2nd Baby Class ----"); + clif_displaymessage(fd, "4023 Baby Novice 4024 Baby Swordsman 4025 Baby Mage 4026 Baby Archer"); + clif_displaymessage(fd, "4027 Baby Acolyte 4028 Baby Merchant 4029 Baby Thief 4030 Baby Knight"); + clif_displaymessage(fd, "4031 Baby Priest 4032 Baby Wizard 4033 Baby Blacksmith 4034 Baby Hunter"); + clif_displaymessage(fd, "4035 Baby Assassin 4037 Baby Crusader 4038 Baby Monk 4039 Baby Sage"); + clif_displaymessage(fd, "4040 Baby Rogue 4041 Baby Alchemist 4042 Baby Bard 4043 Baby Dancer"); + clif_displaymessage(fd, "4045 Super Baby"); + //clif_displaymessage(fd, "---- 3rd Baby Class ----"); + //clif_displaymessage(fd, "4096 Baby Rune Knight 4097 Baby Warlock 4098 Baby Ranger"); + //clif_displaymessage(fd, "4099 Baby Arch Bishop 4100 Baby Mechanic 4101 Baby Guillotine Cross"); + //clif_displaymessage(fd, "4102 Baby Royal Guard 4103 Baby Sorcerer 4104 Baby Minstrel"); + //clif_displaymessage(fd, "4105 Baby Wanderer 4106 Baby Sura 4107 Baby Genetic"); + //clif_displaymessage(fd, "4108 Baby Shadow Chaser"); + //clif_displaymessage(fd, "---- Mounts, Modes, And Others ----"); + //clif_displaymessage(fd, " 13 Knight (Peco) 21 Crusader (Peco) 22 Wedding 26 Christmas"); + //clif_displaymessage(fd, " 27 Summer 4014 Lord Knight (Peco) 4022 Paladin (Peco) 4036 Baby Knight (Peco)"); + //clif_displaymessage(fd, "4044 Baby Crusader (Peco) 4048 Star Gladiator (Union) 4080 Rune Knight (Dragon)"); + //clif_displaymessage(fd, "4081 Rune Knight Trans (Dragon) 4082 Royal Guard (Gryphon)"); + //clif_displaymessage(fd, "4083 Royal Guard Trans (Gryphon) 4084 Ranger (Warg) 4085 Ranger Trans (Warg)"); + //clif_displaymessage(fd, "4086 Mechanic (Mado) 4087 Mechanic Trans (Mado)"); return -1; } @@ -2842,7 +2924,7 @@ ACMD_FUNC(displaystatus) if (i < 2) flag = 1; if (i < 3) tick = 0; - clif_status_change(&sd->bl, type, flag, tick); + clif_status_change(&sd->bl, type, flag, tick, 0, 0, 0); return 0; } @@ -4395,8 +4477,11 @@ ACMD_FUNC(mapinfo) strcat(atcmd_output, "Fireworks | "); if (map[m_id].flag.leaves) strcat(atcmd_output, "Leaves | "); - if (map[m_id].flag.rain) - strcat(atcmd_output, "Rain | "); + /** + * No longer available, keeping here just in case it's back someday. [Ind] + **/ + //if (map[m_id].flag.rain) + // strcat(atcmd_output, "Rain | "); if (map[m_id].flag.nightenabled) strcat(atcmd_output, "Displays Night | "); clif_displaymessage(fd, atcmd_output); @@ -4510,7 +4595,26 @@ ACMD_FUNC(mapinfo) ACMD_FUNC(mount_peco) { nullpo_retr(-1, sd); - + if( pc_checkskill(sd,RK_DRAGONTRAINING) > 0 ) { + if( !(sd->sc.option&OPTION_DRAGON1) ) { + clif_displaymessage(sd->fd,"You have mounted your Dragon"); + pc_setoption(sd, sd->sc.option|OPTION_DRAGON1); + } else { + clif_displaymessage(sd->fd,"You have released your Dragon"); + pc_setoption(sd, sd->sc.option&~OPTION_DRAGON1); + } + return 0; + } + if( (sd->class_&MAPID_THIRDMASK) == MAPID_MECHANIC ) { + if( !(sd->sc.option&OPTION_MADOGEAR) ) { + clif_displaymessage(sd->fd,"You have mounted your Mado Gear"); + pc_setoption(sd, sd->sc.option|OPTION_MADOGEAR); + } else { + clif_displaymessage(sd->fd,"You have released your Mado Gear"); + pc_setoption(sd, sd->sc.option&~OPTION_MADOGEAR); + } + return 0; + } if (!pc_isriding(sd)) { // if actually no peco if (!pc_checkskill(sd, KN_RIDING)) { @@ -6117,24 +6221,26 @@ ACMD_FUNC(autolootitem) return 0; } - +/** + * No longer available, keeping here just in case it's back someday. [Ind] + **/ /*========================================== * It is made to rain. *------------------------------------------*/ -ACMD_FUNC(rain) -{ - nullpo_retr(-1, sd); - if (map[sd->bl.m].flag.rain) { - map[sd->bl.m].flag.rain=0; - clif_weather(sd->bl.m); - clif_displaymessage(fd, "The rain has stopped."); - } else { - map[sd->bl.m].flag.rain=1; - clif_weather(sd->bl.m); - clif_displaymessage(fd, "It is made to rain."); - } - return 0; -} +//ACMD_FUNC(rain) +//{ +// nullpo_retr(-1, sd); +// if (map[sd->bl.m].flag.rain) { +// map[sd->bl.m].flag.rain=0; +// clif_weather(sd->bl.m); +// clif_displaymessage(fd, "The rain has stopped."); +// } else { +// map[sd->bl.m].flag.rain=1; +// clif_weather(sd->bl.m); +// clif_displaymessage(fd, "It is made to rain."); +// } +// return 0; +//} /*========================================== * It is made to snow. @@ -6273,7 +6379,10 @@ ACMD_FUNC(fireworks) ACMD_FUNC(clearweather) { nullpo_retr(-1, sd); - map[sd->bl.m].flag.rain=0; + /** + * No longer available, keeping here just in case it's back someday. [Ind] + **/ + //map[sd->bl.m].flag.rain=0; map[sd->bl.m].flag.snow=0; map[sd->bl.m].flag.sakura=0; map[sd->bl.m].flag.clouds=0; @@ -7763,13 +7872,72 @@ ACMD_FUNC(fakename) } /*========================================== - * @mapflag [flag name] [1|0|on|off] [map name] by Lupus - * => Shows information about the map flags [map name] - * Also set flags + * Ragnarok Resources *------------------------------------------*/ -ACMD_FUNC(mapflag) -{ -// WIP +ACMD_FUNC(mapflag) { +#define checkflag( cmd ) if ( map[ sd->bl.m ].flag.cmd ) clif_displaymessage(sd->fd,#cmd) +#define setflag( cmd ) \ + if ( strcmp( flag_name , #cmd ) == 0 && ( flag == 0 || flag == 1 ) ){\ + map[ sd->bl.m ].flag.cmd = flag;\ + sprintf(atcmd_output,"[ @mapflag ] %s flag has been set to %s",#cmd,flag?"On":"Off");\ + clif_displaymessage(sd->fd,atcmd_output);\ + return 0;\ + } + unsigned char flag_name[100]; + int flag=9,i; + nullpo_retr(-1, sd); + memset(flag_name, '\0', sizeof(flag_name)); + + if (!message || !*message || (sscanf(message, "%99s %d", flag_name, &flag) < 1)) { + clif_displaymessage(sd->fd,"Enabled Mapflags in this map:"); + clif_displaymessage(sd->fd,"----------------------------------"); + checkflag(autotrade); checkflag(allowks); checkflag(nomemo); checkflag(noteleport); + checkflag(noreturn); checkflag(monster_noteleport); checkflag(nosave); checkflag(nobranch); + checkflag(noexppenalty); checkflag(pvp); checkflag(pvp_noparty); checkflag(pvp_noguild); + checkflag(pvp_nightmaredrop); checkflag(pvp_nocalcrank); checkflag(gvg_castle); checkflag(gvg); + checkflag(gvg_dungeon); checkflag(gvg_noparty); checkflag(battleground);checkflag(nozenypenalty); + checkflag(notrade); checkflag(noskill); checkflag(nowarp); checkflag(nowarpto); + checkflag(noicewall); checkflag(snow); checkflag(clouds); checkflag(clouds2); + checkflag(fog); checkflag(fireworks); checkflag(sakura); checkflag(leaves); + checkflag(nogo); checkflag(nobaseexp); + checkflag(nojobexp); checkflag(nomobloot); checkflag(nomvploot); checkflag(nightenabled); + checkflag(restricted); checkflag(nodrop); checkflag(novending); checkflag(loadevent); + checkflag(nochat); checkflag(partylock); checkflag(guildlock); checkflag(src4instance); + clif_displaymessage(sd->fd," "); + clif_displaymessage(sd->fd,"Usage: \"@mapflag monster_teleport 1\" (0=Off 1=On)"); + clif_displaymessage(sd->fd,"Use: \"@mapflag available\" to list the available mapflags"); + return 1; + } + for (i = 0; flag_name[i]; i++) flag_name[i] = tolower(flag_name[i]); //lowercase + + setflag(autotrade); setflag(allowks); setflag(nomemo); setflag(noteleport); + setflag(noreturn); setflag(monster_noteleport);setflag(nosave); setflag(nobranch); + setflag(noexppenalty); setflag(pvp); setflag(pvp_noparty); setflag(pvp_noguild); + setflag(pvp_nightmaredrop); setflag(pvp_nocalcrank); setflag(gvg_castle); setflag(gvg); + setflag(gvg_dungeon); setflag(gvg_noparty); setflag(battleground); setflag(nozenypenalty); + setflag(notrade); setflag(noskill); setflag(nowarp); setflag(nowarpto); + setflag(noicewall); setflag(snow); setflag(clouds); setflag(clouds2); + setflag(fog); setflag(fireworks); setflag(sakura); setflag(leaves); + setflag(nogo); setflag(nobaseexp); + setflag(nojobexp); setflag(nomobloot); setflag(nomvploot); setflag(nightenabled); + setflag(restricted); setflag(nodrop); setflag(novending); setflag(loadevent); + setflag(nochat); setflag(partylock); setflag(guildlock); setflag(src4instance); + + clif_displaymessage(sd->fd,"Invalid flag name or flag"); + clif_displaymessage(sd->fd,"Usage: \"@mapflag monster_teleport 1\" (0=Off | 1=On)"); + clif_displaymessage(sd->fd,"Available Flags:"); + clif_displaymessage(sd->fd,"----------------------------------"); + clif_displaymessage(sd->fd,"town, autotrade, allowks, nomemo, noteleport, noreturn, monster_noteleport, nosave,"); + clif_displaymessage(sd->fd,"nobranch, noexppenalty, pvp, pvp_noparty, pvp_noguild, pvp_nightmaredrop,"); + clif_displaymessage(sd->fd,"pvp_nocalcrank, gvg_castle, gvg, gvg_dungeon, gvg_noparty, battleground,"); + clif_displaymessage(sd->fd,"nozenypenalty, notrade, noskill, nowarp, nowarpto, noicewall, snow, clouds, clouds2,"); + clif_displaymessage(sd->fd,"fog, fireworks, sakura, leaves, nogo, nobaseexp, nojobexp, nomobloot,"); + clif_displaymessage(sd->fd,"nomvploot, nightenabled, restricted, nodrop, novending, loadevent, nochat, partylock,"); + clif_displaymessage(sd->fd,"guildlock, src4instance"); + +#undef checkflag +#undef setflag + return 0; } @@ -8581,8 +8749,17 @@ ACMD_FUNC(font) return 0; } - - +ACMD_FUNC(new_mount) { + clif_displaymessage(sd->fd,"NOTICE: If you crash with mount your LUA is outdated"); + if( !(sd->sc.option&OPTION_MOUNTING) ) { + clif_displaymessage(sd->fd,"You have mounted."); + pc_setoption(sd, sd->sc.option|OPTION_MOUNTING); + } else { + clif_displaymessage(sd->fd,"You have released your mount"); + pc_setoption(sd, sd->sc.option&~OPTION_MOUNTING); + } + return 0; +} /*========================================== * atcommand_info[] structure definition *------------------------------------------*/ @@ -8885,6 +9062,10 @@ AtCommandInfo atcommand_info[] = { { "delitem", 60,60, atcommand_delitem }, { "charcommands", 1,1, atcommand_commands }, { "font", 1,1, atcommand_font }, + /** + * For Testing Purposes, not going to be here after we're done. + **/ + { "newmount", 0,99, atcommand_new_mount }, }; @@ -9025,9 +9206,12 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message info = get_atcommandinfo_byname(command); if( info == NULL || info->func == NULL || ( type && ((*atcmd_msg == atcommand_symbol && pc_isGM(sd) < info->level) || (*atcmd_msg == charcommand_symbol && pc_isGM(sd) < info->level2)) ) ) { + if( pc_isGM(sd) ) { sprintf(output, msg_txt(153), command); // "%s is Unknown Command." clif_displaymessage(fd, output); return true; + } else + return false; } //Attempt to use the command diff --git a/src/map/battle.c b/src/map/battle.c index b9a408a84..556b51bbd 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -118,7 +118,7 @@ static int battle_getenemy_sub(struct block_list *bl, va_list ap) if (bl->id == target->id) return 0; - if (*c >= 24) + if (*c >= 23) return 0; if (status_isdead(bl)) return 0; @@ -136,8 +136,47 @@ struct block_list* battle_getenemy(struct block_list *target, int type, int rang int c = 0; memset(bl_list, 0, sizeof(bl_list)); map_foreachinrange(battle_getenemy_sub, target, range, type, bl_list, &c, target); - if (c == 0 || c > 24) + if (c == 0 ) + return NULL; + if( c >= 24 ) + c = 23; + return bl_list[rand()%c]; +} +static int battle_getenemyarea_sub(struct block_list *bl, va_list ap) +{ + struct block_list **bl_list, *src; + int *c, ignore_id; + + bl_list = va_arg(ap, struct block_list **); + c = va_arg(ap, int *); + src = va_arg(ap, struct block_list *); + ignore_id = va_arg(ap, int); + + if( bl->id == src->id || bl->id == ignore_id ) + return 0; // Ignores Caster and a possible pre-target + if( *c >= 23 ) + return 0; + if( status_isdead(bl) ) + return 0; + if( battle_check_target(src, bl, BCT_ENEMY) > 0 ) + { // Is Enemy!... + bl_list[(*c)++] = bl; + return 1; + } + return 0; +} + +// Pick a random enemy +struct block_list* battle_getenemyarea(struct block_list *src, int x, int y, int range, int type, int ignore_id) +{ + struct block_list *bl_list[24]; + int c = 0; + memset(bl_list, 0, sizeof(bl_list)); + map_foreachinarea(battle_getenemyarea_sub, src->m, x - range, y - range, x + range, y + range, type, bl_list, &c, src, ignore_id); + if( c == 0 ) return NULL; + if( c >= 24 ) + c = 23; return bl_list[rand()%c]; } @@ -212,7 +251,6 @@ int battle_delay_damage (unsigned int tick, int amotion, struct block_list *src, return 0; } - int battle_attr_ratio(int atk_elem,int def_type, int def_lv) { @@ -316,6 +354,20 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag d->dmg_lv = ATK_BLOCK; return 0; } + if( sc->data[SC_WHITEIMPRISON] && skill_num != HW_GRAVITATION && skill_num != PA_PRESSURE ) { // Gravitation and Pressure do damage without removing the effect + if( skill_num == MG_NAPALMBEAT || + skill_num == MG_SOULSTRIKE || + skill_num == WL_SOULEXPANSION || + (skill_num && skill_get_ele(skill_num, skill_lv) == ELE_GHOST) || + (!skill_num && (status_get_status_data(src))->rhw.ele == ELE_GHOST) + ) + status_change_end(bl,SC_WHITEIMPRISON,-1); // Those skills do damage and removes effect + else + { + d->dmg_lv = ATK_BLOCK; + return 0; + } + } if( sc->data[SC_SAFETYWALL] && (flag&(BF_SHORT|BF_MAGIC))==BF_SHORT ) { @@ -334,7 +386,13 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag d->dmg_lv = ATK_BLOCK; return 0; } - + if( sc->data[SC_WEAPONBLOCKING] && flag&(BF_SHORT|BF_WEAPON) && rand()%100 < sc->data[SC_WEAPONBLOCKING]->val2 ) + { + clif_skill_nodamage(bl,src,GC_WEAPONBLOCKING,1,1); + d->dmg_lv = ATK_NONE; + sc_start2(bl,SC_COMBO,100,GC_WEAPONBLOCKING,src->id,2000); + return 0; + } if( (sce=sc->data[SC_AUTOGUARD]) && flag&BF_WEAPON && !(skill_get_nk(skill_num)&NK_NO_CARDFIX_ATK) && rand()%100 < sce->val2 ) { int delay; @@ -487,6 +545,14 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag status_change_end(bl, SC_REJECTSWORD, INVALID_TIMER); } + //Finally added to remove the status of immobile when aimedbolt is used. [Jobbie] + if( skill_num == RA_AIMEDBOLT && (sc->data[SC_BITE] || sc->data[SC_ANKLE] || sc->data[SC_ELECTRICSHOCKER]) ) + { + status_change_end(bl, SC_BITE, -1); + status_change_end(bl, SC_ANKLE, -1); + status_change_end(bl, SC_ELECTRICSHOCKER, -1); + } + //Finally Kyrie because it may, or not, reduce damage to 0. if((sce = sc->data[SC_KYRIE]) && damage > 0){ sce->val2-=damage; @@ -539,6 +605,8 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag break; } } + if( sc->data[SC_POISONINGWEAPON] && skill_num != GC_VENOMPRESSURE && (flag&BF_WEAPON) && damage > 0 && rand()%100 < sc->data[SC_POISONINGWEAPON]->val3 ) + sc_start(bl,sc->data[SC_POISONINGWEAPON]->val2,100,sc->data[SC_POISONINGWEAPON]->val1,skill_get_time2(GC_POISONINGWEAPON,sc->data[SC_POISONINGWEAPON]->val1)); } if (battle_config.pk_mode && sd && bl->type == BL_PC && damage) @@ -720,6 +788,12 @@ int battle_addmastery(struct map_session_data *sd,struct block_list *target,int (battle_check_undead(status->race,status->def_ele) || status->race==RC_DEMON) ) damage += (skill*(int)(3+(sd->status.base_level+1)*0.05)); // submitted by orn //damage += (skill * 3); + if( (skill = pc_checkskill(sd, RA_RANGERMAIN)) > 0 && (status->race == RC_BRUTE || status->race == RC_PLANT || status->race == RC_FISH) ) + damage += (skill * 5); + if( (skill = pc_checkskill(sd,NC_RESEARCHFE)) > 0 && (status->def_ele == ELE_FIRE || status->def_ele == ELE_EARTH) ) + damage += (skill * 10); + if( (sd->sc.option&OPTION_MADOGEAR) ) + damage += 20 + 20 * pc_checkskill(sd, NC_MADOLICENCE); if((skill = pc_checkskill(sd,HT_BEASTBANE)) > 0 && (status->race==RC_BRUTE || status->race==RC_INSECT) ) { damage += (skill * 4); @@ -755,11 +829,15 @@ int battle_addmastery(struct map_session_data *sd,struct block_list *target,int case W_2HAXE: if((skill = pc_checkskill(sd,AM_AXEMASTERY)) > 0) damage += (skill * 3); + if((skill = pc_checkskill(sd,NC_TRAININGAXE)) > 0) + damage += (skill * 5); break; case W_MACE: case W_2HMACE: if((skill = pc_checkskill(sd,PR_MACEMASTERY)) > 0) damage += (skill * 3); + if((skill = pc_checkskill(sd,NC_TRAININGAXE)) > 0) + damage += (skill * 5); break; case W_FIST: if((skill = pc_checkskill(sd,TK_RUN)) > 0) @@ -1278,6 +1356,9 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo if(sd && pc_checkskill(sd,AS_SONICACCEL)>0) hitrate += hitrate * 50 / 100; break; + case GC_VENOMPRESSURE: + hitrate += 10 + 4 * skill_lv; + break; } // Weaponry Research hidden bonus @@ -1727,6 +1808,160 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo case NPC_VAMPIRE_GIFT: skillratio += ((skill_lv-1)%5+1)*100; break; + case RK_SONICWAVE: { + int level = status_get_lv(src); + skillratio += 400 + 100 * skill_lv; + if( level > 100 ) + skillratio += skillratio * (level - 100) / 200; + } + break; + case RK_HUNDREDSPEAR: { + int level = status_get_lv(src); + skillratio += 500 + 40 * skill_lv; + if( level > 100 ) + skillratio += skillratio * (level - 100) / 200; + } + break; + case RK_WINDCUTTER: { + int level = status_get_lv(src); + skillratio += 50 * skill_lv; + if( level > 100 ) + skillratio += skillratio * (level - 50) / 200; + } + break; + case RK_IGNITIONBREAK: { + int level = status_get_lv(src); + i = distance_bl(src,target); + if( i < 2 ) + skillratio = 200 + 200 * skill_lv; + else if( i < 4 ) + skillratio = 100 + 200 * skill_lv; + else + skillratio = 100 + 100 * skill_lv; + if( level > 100 ) + skillratio += skillratio * (level - 100) / 200; + if( sstatus->rhw.ele == ELE_FIRE ) + skillratio += skillratio / 2; + } + break; + case RK_CRUSHSTRIKE: + if( sd ) + { + short index = sd->equip_index[EQI_HAND_R]; + if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON ) + skillratio = sstatus->rhw.atk + 100 * sd->inventory_data[index]->wlv * (sd->status.inventory[index].refine + 6); + } + break; + case RK_STORMBLAST: + skillratio = 100 * (sd ? pc_checkskill(sd,RK_RUNEMASTERY) : 1) + 100 * (sstatus->int_ / 4); + break; + case RK_PHANTOMTHRUST: + skillratio = 50 * skill_lv + 10 * ( sd ? pc_checkskill(sd,KN_SPEARMASTERY) : 10); + //if( s_level > 100 ) skillratio += skillratio * s_level / 150; // Base level bonus. This is official, but is disabled until I can confirm something with was changed or not. [Rytech] + //if( s_level > 100 ) skillratio += skillratio * (s_level - 100) / 200; // Base level bonus. + break; + /** + * GC Guilotine Cross + **/ + case GC_CROSSIMPACT: + skillratio += 1050 + 50 * skill_lv; + break; + case GC_PHANTOMMENACE: + skillratio += 200; + break; + case GC_COUNTERSLASH: + skillratio += 200 + (100 * skill_lv) + sstatus->agi; + break; + case GC_ROLLINGCUTTER: + skillratio += 20 * skill_lv; + break; + case GC_CROSSRIPPERSLASHER: + skillratio += 60 + 40 * skill_lv; + if( sc && sc->data[SC_ROLLINGCUTTER] ) + skillratio += 25 * sc->data[SC_ROLLINGCUTTER]->val1; + break; + /** + * Arch Bishop + **/ + case AB_DUPLELIGHT_MELEE: + skillratio += 10 * skill_lv; + break; + /** + * Ranger + **/ + case RA_ARROWSTORM: + skillratio += 100 + 50 * skill_lv; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + case RA_AIMEDBOLT: + skillratio += 400 + 50 * skill_lv; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + if( tsc && (tsc->data[SC_BITE] || tsc->data[SC_ANKLE] || tsc->data[SC_ELECTRICSHOCKER]) ) + wd.div_ = tstatus->size + 2 + rand()%2; + break; + case RA_CLUSTERBOMB: + skillratio += 100 + 100 * skill_lv; + break; + case RA_WUGDASH: + skillratio = 500; + break; + case RA_WUGSTRIKE: + skillratio = 200 * skill_lv; + break; + case RA_WUGBITE: + skillratio += 300 + 200 * skill_lv; + if ( skill_lv == 5 ) skillratio += 100; + break; + case RA_SENSITIVEKEEN: + skillratio += 50 * skill_lv; + break; + /** + * Mechanic + **/ + case NC_BOOSTKNUCKLE: + skillratio += 100 + 100 * skill_lv + sstatus->dex; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + case NC_PILEBUNKER: + skillratio += 200 + 100 * skill_lv + sstatus->str; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + case NC_VULCANARM: + skillratio = 70 * skill_lv + sstatus->dex; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + case NC_FLAMELAUNCHER: + case NC_COLDSLOWER: + skillratio += 200 + 300 * skill_lv; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + case NC_ARMSCANNON: + switch( tstatus->size ) { + case 0: skillratio += 100 + 500 * skill_lv; break;// Small + case 1: skillratio += 100 + 400 * skill_lv; break;// Medium + case 2: skillratio += 100 + 300 * skill_lv; break;// Large + } + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + //NOTE: Their's some other factors that affects damage, but not sure how exactly. Will recheck one day. [Rytech] + break; + case NC_AXEBOOMERANG: + skillratio += 60 + 40 * skill_lv; + if( sd ) { + short index = sd->equip_index[EQI_HAND_R]; + if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON ) + skillratio += sd->inventory_data[index]->weight / 10;// Weight is divided by 10 since 10 weight in coding make 1 whole actural weight. [Rytech] + } + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + case NC_POWERSWING: + skillratio += 80 + 20 * skill_lv + sstatus->str + sstatus->dex; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + case NC_AXETORNADO: + skillratio += 100 + 100 * skill_lv + sstatus->vit; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + } ATK_RATE(skillratio); @@ -1755,6 +1990,16 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo case NJ_SYURIKEN: ATK_ADD(4*skill_lv); break; + /** + * Ranger + **/ + case RA_WUGDASH: + case RA_WUGSTRIKE: + case RA_WUGBITE: + if(sd) + ATK_ADD(30*pc_checkskill(sd, RA_TOOTHOFWUG)); + break; + } } //Div fix. @@ -1764,13 +2009,17 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo if (sc) { if(sc->data[SC_TRUESIGHT]) ATK_ADDRATE(2*sc->data[SC_TRUESIGHT]->val1); - + #if RE_EDP == 0 + /** + * In RE EDP doesn't affect your final damage but your atk and weapon atk + **/ if(sc->data[SC_EDP] && skill_num != ASC_BREAKER && skill_num != ASC_METEORASSAULT && skill_num != AS_SPLASHER && skill_num != AS_VENOMKNIFE) ATK_ADDRATE(sc->data[SC_EDP]->val3); + #endif } switch (skill_num) { @@ -1787,6 +2036,10 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo sc->data[SC_SPIRIT]->val2 == SL_CRUSADER) ATK_ADDRATE(100); break; + case NC_AXETORNADO: + if( (sstatus->rhw.ele) == ELE_WIND || (sstatus->lhw.ele) == ELE_WIND ) + ATK_ADDRATE(50); + break; } if( sd ) @@ -1881,6 +2134,9 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo if((battle_check_undead(sstatus->race,sstatus->def_ele) || sstatus->race==RC_DEMON) && //This bonus already doesnt work vs players src->type == BL_MOB && (skill=pc_checkskill(tsd,AL_DP)) > 0) vit_def += skill*(int)(3 +(tsd->status.base_level+1)*0.04); // submitted by orn + if( src->type == BL_MOB && (skill=pc_checkskill(tsd,RA_RANGERMAIN))>0 && + (sstatus->race == RC_BRUTE || sstatus->race == RC_FISH || sstatus->race == RC_PLANT) ) + vit_def += skill*5; } else { //Mob-Pet vit-eq //VIT + rnd(0,[VIT/20]^2-1) vit_def = (def2/20)*(def2/20); @@ -2293,20 +2549,34 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo struct Damage md = battle_calc_misc_attack(src, target, skill_num, skill_lv, wflag); wd.damage += md.damage; } - - //SG_FUSION hp penalty [Komurka] - if (sc && sc->data[SC_FUSION]) - { - int hp= sstatus->max_hp; - if (sd && tsd) { - hp = 8*hp/100; - if (100*sstatus->hp <= 20*sstatus->max_hp) - hp = sstatus->hp; - } else - hp = 2*hp/100; //2% hp loss per hit - status_zap(src, hp, 0); + if( sc ) { + //SG_FUSION hp penalty [Komurka] + if (sc->data[SC_FUSION]) + { + int hp= sstatus->max_hp; + if (sd && tsd) { + hp = 8*hp/100; + if (100*sstatus->hp <= 20*sstatus->max_hp) + hp = sstatus->hp; + } else + hp = 2*hp/100; //2% hp loss per hit + status_zap(src, hp, 0); + } + /** + * affecting non-skills + **/ + if( !skill_num ) { + /** + * RK Enchant Blade + **/ + if( sc->data[SC_ENCHANTBLADE] && sd && ( (flag.rh && sd->weapontype1) || (flag.lh && sd->weapontype2) ) ) { + struct Damage md = battle_calc_magic_attack(src, target, RK_ENCHANTBLADE, pc_checkskill(sd,RK_ENCHANTBLADE), wflag); + wd.damage += md.damage; + wd.flag |= md.flag; + } } + } return wd; } @@ -2398,6 +2668,10 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list case AL_HEAL: case PR_BENEDICTIO: case PR_SANCTUARY: + /** + * Arch Bishop + **/ + case AB_HIGHNESSHEAL: ad.damage = skill_calc_heal(src, target, skill_num, skill_lv, false); break; case PR_ASPERSIO: @@ -2417,14 +2691,31 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list case PF_SOULBURN: ad.damage = tstatus->sp * 2; break; + /** + * Arch Bishop + **/ + case AB_RENOVATIO: + //Damage calculation from iRO wiki. [Jobbie] + ad.damage = (int)((15 * status_get_lv(src)) + (1.5 * sstatus->int_)); + break; default: { + #if RRMODE //Renewal MATK Appliance according to doddler (?title=Renewal_Changes#Upgrade_MATK) + /** + * min: (weaponMATK+upgradeMATK) * 2 + 1.5 * statusMATK + * max: [weaponMATK+upgradeMATK+(wMatk*wLvl)/10] * 2 + 1.5 * statusMATK + * yes this formula MATCHES their site: matk_max already holds weaponmatk+upgradematk, and + * -> statusMATK holds the %Matk modifier stuff from earlier and lastly: + * -> the mdef part is not applied at this point, but later. + **/ + MATK_ADD(sstatus->matk_max * 2 + 15/10 * sstatus->matk_min + rand()% ( sstatus->matk_max + (sstatus->matk_max*sstatus->wlv) / 10 * 2 * 10/15 * sstatus->matk_min ) ); + #else //Ancient MATK Appliance if (sstatus->matk_max > sstatus->matk_min) { MATK_ADD(sstatus->matk_min+rand()%(1+sstatus->matk_max-sstatus->matk_min)); } else { MATK_ADD(sstatus->matk_min); } - + #endif if(nk&NK_SPLASHSPLIT){ // Divide MATK in case of multiple targets skill if(mflag>0) ad.damage/= mflag; @@ -2470,6 +2761,11 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list case WZ_SIGHTRASHER: skillratio += 20*skill_lv; break; +#if FIREIVY_ON + case WZ_FIREIVY: + skillratio += 20*skill_lv-15; + break; +#endif case WZ_VERMILION: skillratio += 20*skill_lv-20; break; @@ -2513,6 +2809,193 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list case NPC_EARTHQUAKE: skillratio += 100 +100*skill_lv +100*(skill_lv/2); break; + /** + * Arch Bishop + **/ + case AB_JUDEX: + skillratio += 180 + 20 * skill_lv; + if (skill_lv > 4) skillratio += 20; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + case AB_ADORAMUS: + skillratio += 400 + 100 * skill_lv; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + case AB_DUPLELIGHT_MAGIC: + skillratio += 100 + 20 * skill_lv; + break; + /** + * Warlock + **/ + case WL_SOULEXPANSION: + skillratio += 300 + 100 * skill_lv + sstatus->int_; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + case WL_FROSTMISTY: + skillratio += 100 + 100 * skill_lv; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + case WL_JACKFROST: + { + struct status_change *tsc = status_get_sc(target); + if( tsc && tsc->data[SC_FREEZING] ) + { + skillratio += 900 + 300 * skill_lv; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + } + else + skillratio += 400 + 100 * skill_lv; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + } + break; + case WL_DRAINLIFE: + skillratio = 200 * skill_lv + sstatus->int_; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + case WL_CRIMSONROCK: + skillratio += 1200 + 300 * skill_lv; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + case WL_HELLINFERNO: + if( status_get_element(target) == ELE_FIRE ) + skillratio = 60 * skill_lv; + else + skillratio = 240 * skill_lv; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + case WL_COMET: { + struct status_change * sc = status_get_sc(src); + if( sc ) + i = distance_xy(target->x, target->y, sc->comet_x, sc->comet_y); + else + i = 8; + if( i < 2 ) skillratio = 2500 + 500 * skill_lv; + else + if( i < 4 ) skillratio = 1600 + 400 * skill_lv; + else + if( i < 6 ) skillratio = 1200 + 300 * skill_lv; + else + skillratio = 800 + 200 * skill_lv; + } + break; + case WL_CHAINLIGHTNING_ATK: + skillratio += 100 + 300 * skill_lv; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + case WL_EARTHSTRAIN: + skillratio += 1900 + 100 * skill_lv; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + case WL_TETRAVORTEX_FIRE: + case WL_TETRAVORTEX_WATER: + case WL_TETRAVORTEX_WIND: + case WL_TETRAVORTEX_GROUND: + skillratio += 400 + 500 * skill_lv; + break; + case WL_SUMMON_ATK_FIRE: + case WL_SUMMON_ATK_WATER: + case WL_SUMMON_ATK_WIND: + case WL_SUMMON_ATK_GROUND: + skillratio = skill_lv * (status_get_lv(src) + ( sd ? sd->status.job_level : 50 ));// This is close to official, but lacking a little info to finalize. [Rytech] + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + case LG_RAYOFGENESIS: + skillratio = (skillratio + 200) * skill_lv; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + break; + case WM_METALICSOUND: + skillratio += 120 * skill_lv + 60 * ( sd? pc_checkskill(sd, WM_LESSON) : 10 ) - 100; + break; + case WM_SEVERE_RAINSTORM: + skillratio += 50 * skill_lv; + break; + case WM_REVERBERATION_MAGIC: + skillratio += 100 * (sd ? pc_checkskill(sd, WM_REVERBERATION) : 1); + break; + case SO_FIREWALK: { + struct status_change * sc = status_get_sc(src); + skillratio = 300; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + if( sc && sc->data[SC_HEATER_OPTION] ) + skillratio += skillratio * sc->data[SC_HEATER_OPTION]->val3 / 100; + } + break; + case SO_ELECTRICWALK: { + struct status_change * sc = status_get_sc(src); + skillratio = 300; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + if( sc && sc->data[SC_BLAST_OPTION] ) + skillratio += skillratio * sc->data[SC_BLAST_OPTION]->val2 / 100; + } + break; + case SO_EARTHGRAVE: { + struct status_change * sc = status_get_sc(src); + skillratio = ( 200 * ( sd ? pc_checkskill(sd, SA_SEISMICWEAPON) : 10 ) + sstatus->int_ * skill_lv ); + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + if( sc && sc->data[SC_CURSED_SOIL_OPTION] ) + skillratio += skillratio * sc->data[SC_CURSED_SOIL_OPTION]->val2 / 100; + } + break; + case SO_DIAMONDDUST: { + struct status_change * sc = status_get_sc(src); + skillratio = ( 200 * ( sd ? pc_checkskill(sd, SA_FROSTWEAPON) : 10 ) + sstatus->int_ * skill_lv ); + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + if( sc && sc->data[SC_COOLER_OPTION] ) + skillratio += skillratio * sc->data[SC_COOLER_OPTION]->val3 / 100; + } + break; + case SO_POISON_BUSTER: { + struct status_change * sc = status_get_sc(src); + skillratio += 1100 + 300 * skill_lv; + if( sc && sc->data[SC_CURSED_SOIL_OPTION] ) + skillratio += skillratio * sc->data[SC_CURSED_SOIL_OPTION]->val2 / 100; + } + break; + case SO_PSYCHIC_WAVE: { + struct status_change * sc = status_get_sc(src); + skillratio += -100 + skill_lv * 70 + (sstatus->int_ * 3); + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + if( sc ){ + if( sc->data[SC_HEATER_OPTION] ) + skillratio += skillratio * sc->data[SC_HEATER_OPTION]->val3 / 100; + else if(sc->data[SC_COOLER_OPTION] ) + skillratio += skillratio * sc->data[SC_COOLER_OPTION]->val3 / 100; + else if(sc->data[SC_BLAST_OPTION] ) + skillratio += skillratio * sc->data[SC_BLAST_OPTION]->val2 / 100; + else if(sc->data[SC_CURSED_SOIL_OPTION] ) + skillratio += skillratio * sc->data[SC_CURSED_SOIL_OPTION]->val3 / 100; + } + } + break; + case SO_VARETYR_SPEAR: { + struct status_change * sc = status_get_sc(src); + skillratio += -100 + ( 100 * ( sd ? pc_checkskill(sd, SA_LIGHTNINGLOADER) : 10 ) + sstatus->int_ * skill_lv ); + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + if( sc && sc->data[SC_BLAST_OPTION] ) + skillratio += skillratio * sc->data[SC_BLAST_OPTION]->val2 / 100; + } + break; + case SO_CLOUD_KILL: { + struct status_change * sc = status_get_sc(src); + skillratio += -100 + skill_lv * 40; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + if( sc && sc->data[SC_CURSED_SOIL_OPTION] ) + skillratio += skillratio * sc->data[SC_CURSED_SOIL_OPTION]->val2 / 100; + } + break; + case GN_DEMONIC_FIRE: + if( skill_lv > 20) + { // Fire expansion Lv.2 + skillratio += 110 + 20 * (skill_lv - 20) + status_get_int(src) * 3; // Need official INT bonus. [LimitLine] + } + else if( skill_lv > 10 ) + { // Fire expansion Lv.1 + skillratio += 110 + 20 * (skill_lv - 10) / 2; + } + else + skillratio += 110 + 20 * skill_lv; + break; + } MATK_RATE(skillratio); @@ -2550,10 +3033,19 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list //mdef2-= mdef2* i/100; } } + #if RRMODE + /** + * RE MDEF Reduction (from doddler:?title=Renewal_Changes#MDEF) + * Damage from magic = Magic Attack * 111.5/(111.5+eMDEF) + * Damage = Magic Attack * 111.5/(111.5+eMDEF) - sMDEF + **/ + ad.damage = ad.damage * ((1115/10) - mdef)/(1115/10) - mdef2; + #else if(battle_config.magic_defense_type) ad.damage = ad.damage - mdef*battle_config.magic_defense_type - mdef2; else ad.damage = ad.damage * (100-mdef)/100 - mdef2; + #endif } if (skill_num == NPC_EARTHQUAKE) @@ -2805,6 +3297,32 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * case NPC_EVILLAND: md.damage = skill_calc_heal(src,target,skill_num,skill_lv,false); break; + case RK_DRAGONBREATH: + md.damage = ((status_get_hp(src) / 50) + (status_get_max_sp(src) / 4)) * skill_lv; + if (status_get_lv(src) > 100) md.damage = md.damage * status_get_lv(src) / 150; + if (sd) md.damage = md.damage * (100 + 5 * (pc_checkskill(sd,RK_DRAGONTRAINING) - 1)) / 100; + break; + /** + * Ranger + **/ + case RA_CLUSTERBOMB: + case RA_FIRINGTRAP: + case RA_ICEBOUNDTRAP: + md.damage = (2 * skill_lv * (sstatus->dex + 100)); + if (status_get_lv(src) > 100) md.damage += md.damage * (status_get_lv(src) - 50) / 200 + 15 / 10; + md.damage = md.damage * 2;// Without BaseLv Bonus + md.damage = md.damage + (5 * sstatus->int_) + (40 * ( sd ? pc_checkskill(sd,RA_RESEARCHTRAP) : 10 ) ); + break; + /** + * Mechanic + **/ + case NC_SELFDESTRUCTION: + md.damage = (sd?pc_checkskill(sd,NC_MAINFRAME):10) * skill_lv * (status_get_sp(src) + sstatus->vit); + if (status_get_lv(src) > 100) md.damage = md.damage * status_get_lv(src) / 150;// Base level bonus. + if (sd) md.damage = md.damage + status_get_hp(src); + status_set_sp(src, 0, 0); + break; + } if (nk&NK_SPLASHSPLIT){ // Divide ATK among targets @@ -2906,11 +3424,23 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * else if( map[target->m].flag.battleground ) md.damage=battle_calc_bg_damage(src,target,md.damage,md.div_,skill_num,skill_lv,md.flag); - if (skill_num == NJ_ZENYNAGE && sd) - { //Time to Pay Up. - if ( md.damage > sd->status.zeny ) - md.damage=sd->status.zeny; - pc_payzeny(sd, md.damage); + switch( skill_num ) { + case RA_CLUSTERBOMB: + case RA_FIRINGTRAP: + case RA_ICEBOUNDTRAP: + { + struct Damage wd; + wd = battle_calc_weapon_attack(src,target,skill_num,skill_lv,mflag); + md.damage += wd.damage; + } + break; + case NJ_ZENYNAGE: + if( sd ) { + if ( md.damage > sd->status.zeny ) + md.damage = sd->status.zeny; + pc_payzeny(sd, md.damage); + } + break; } return md; @@ -2943,10 +3473,10 @@ struct Damage battle_calc_attack(int attack_type,struct block_list *bl,struct bl } //Calculates BF_WEAPON returned damage. -int battle_calc_return_damage(struct block_list* bl, int damage, int flag) +int battle_calc_return_damage(struct block_list* bl, struct block_list *src, int *dmg, int flag) { struct map_session_data* sd = NULL; - int rdamage = 0; + int rdamage = 0, damage = *dmg; sd = BL_CAST(BL_PC, bl); @@ -2959,10 +3489,24 @@ int battle_calc_return_damage(struct block_list* bl, int damage, int flag) if(rdamage < 1) rdamage = 1; } sc = status_get_sc(bl); - if (sc && sc->data[SC_REFLECTSHIELD]) - { - rdamage += damage * sc->data[SC_REFLECTSHIELD]->val2 / 100; - if (rdamage < 1) rdamage = 1; + if( sc && sc->count ) { + if (sc->data[SC_REFLECTSHIELD]) { + rdamage += damage * sc->data[SC_REFLECTSHIELD]->val2 / 100; + if (rdamage < 1) rdamage = 1; + } + if(sc->data[SC_DEATHBOUND] && !(src->type == BL_MOB && is_boss(src)) ) { + int dir = map_calc_dir(bl,src->x,src->y), + t_dir = unit_getdir(bl), rd1 = 0; + + if( distance_bl(src,bl) <= 0 || !map_check_dir(dir,t_dir) ) { + rd1 = min(damage,status_get_max_hp(bl)) * sc->data[SC_DEATHBOUND]->val2 / 100; // Amplify damage. + *dmg = rd1 * 30 / 100; // Received damge = 30% of amplifly damage. + clif_skill_damage(src,bl,gettick(), status_get_amotion(src), 0, -30000, 1, RK_DEATHBOUND, sc->data[SC_DEATHBOUND]->val1,6); + status_change_end(bl,SC_DEATHBOUND,-1); + rdamage += rd1; + if (rdamage < 1) rdamage = 1; + } + } } } else { if (sd && sd->long_weapon_damage_return) @@ -3165,7 +3709,17 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t damage = wd.damage + wd.damage2; if( damage > 0 && src != target ) { - rdamage = battle_calc_return_damage(target, damage, wd.flag); + if( sc && sc->data[SC_DUPLELIGHT] && (wd.flag&BF_SHORT) && rand()%100 <= 10+2*sc->data[SC_DUPLELIGHT]->val1 ) + { // Activates it only from melee damage + int skillid; + if( rand()%2 == 1 ) + skillid = AB_DUPLELIGHT_MELEE; + else + skillid = AB_DUPLELIGHT_MAGIC; + skill_attack(skill_get_type(skillid), src, src, target, skillid, sc->data[SC_DUPLELIGHT]->val1, tick, SD_LEVEL); + } + + rdamage = battle_calc_return_damage(target,src, &damage, wd.flag); if( rdamage > 0 ) { rdelay = clif_damage(src, src, tick, wd.amotion, sstatus->dmotion, rdamage, 1, 4, 0); @@ -3373,6 +3927,8 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f case WZ_SIGHTBLASTER: case SM_MAGNUM: case MS_MAGNUM: + case RA_DETONATOR: + case RA_SENSITIVEKEEN: state |= BCT_ENEMY; strip_enemy = 0; break; @@ -4023,6 +4579,10 @@ static const struct _battle_data { { "bg_magic_attack_damage_rate", &battle_config.bg_magic_damage_rate, 60, 0, INT_MAX, }, { "bg_misc_attack_damage_rate", &battle_config.bg_misc_damage_rate, 60, 0, INT_MAX, }, { "bg_flee_penalty", &battle_config.bg_flee_penalty, 20, 0, INT_MAX, }, + /** + * RR-Specific + **/ + { "max_third_parameter", &battle_config.max_third_parameter, 20, 0, INT_MAX, }, }; diff --git a/src/map/battle.h b/src/map/battle.h index 007499afe..a64c81041 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -35,7 +35,7 @@ struct block_list; struct Damage battle_calc_attack(int attack_type,struct block_list *bl,struct block_list *target,int skill_num,int skill_lv,int count); -int battle_calc_return_damage(struct block_list *bl, int damage, int flag); +int battle_calc_return_damage(struct block_list *bl, struct block_list *src, int *, int flag); void battle_drain(struct map_session_data *sd, struct block_list *tbl, int rdamage, int ldamage, int race, int boss); @@ -497,6 +497,8 @@ extern struct Battle_Config int bg_magic_damage_rate; int bg_misc_damage_rate; int bg_flee_penalty; + //[RR] + int max_third_parameter; } battle_config; void do_init_battle(void); @@ -507,4 +509,7 @@ extern void battle_set_defaults(void); int battle_set_value(const char* w1, const char* w2); int battle_get_value(const char* w1); +// +struct block_list* battle_getenemyarea(struct block_list *src, int x, int y, int range, int type, int ignore_id); + #endif /* _BATTLE_H_ */ diff --git a/src/map/chrif.c b/src/map/chrif.c index d1332fab2..947cb0bdc 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -505,7 +505,13 @@ void chrif_on_ready(void) ShowStatus("Map Server is now online.\n"); chrif_state = 2; chrif_check_shutdown(); - + /** + * while we're not fully ready + **/ + ShowMessage(""CL_XXBL""CL_BT_YELLOW"============= WARNING ============="CL_XXBL""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_XXBL"- "CL_BT_YELLOW"This version is under development and shouldn't be used as a real server"CL_XXBL""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_XXBL"- "CL_BT_YELLOW"For bugs, comments and suggestions: http://ro-resources.net "CL_XXBL""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_XXBL"- "CL_BT_YELLOW"Thank you for trying out"CL_XXBL""CL_CLL""CL_NORMAL"\n"); //If there are players online, send them to the char-server. [Skotlex] send_users_tochar(); diff --git a/src/map/clif.c b/src/map/clif.c index da2abe0f3..780b1af56 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -154,7 +154,8 @@ void clif_setbindip(const char* ip) } /*========================================== - * map鯖のport設定 + * Sets map port to 'port' + * is run from map.c upon loading map server configuration *------------------------------------------*/ void clif_setport(uint16 port) { @@ -162,7 +163,7 @@ void clif_setport(uint16 port) } /*========================================== - * map鯖のip読み出し + * Returns map server IP *------------------------------------------*/ uint32 clif_getip(void) { @@ -184,7 +185,7 @@ uint32 clif_refresh_ip(void) } /*========================================== - * map鯖のport読み出し + * Returns map port which is set by clif_setport() *------------------------------------------*/ uint16 clif_getport(void) { @@ -210,7 +211,14 @@ static inline unsigned char clif_bl_type(struct block_list *bl) { #endif /*========================================== - * clif_sendでAREA*指定時用 + * sub process of clif_send + * Called from a map_foreachinarea (grabs all players in specific area and subjects them to this function) + * In order to send area-wise packets, such as: + * - AREA : everyone nearby your area + * - AREA_WOSC (AREA WITHOUT SAME CHAT) : Not run for people in the same chat as yours + * - AREA_WOC (AREA WITHOUT CHAT) : Not run for people inside a chat + * - AREA_WOS (AREA WITHOUT SELF) : Not run for self + * - AREA_CHAT_WOC : Everyone in the area of your chat without a chat *------------------------------------------*/ int clif_send_sub(struct block_list *bl, va_list ap) { @@ -273,7 +281,8 @@ int clif_send_sub(struct block_list *bl, va_list ap) } /*========================================== - * + * Packet Delegation (called on all packets that require data to be sent to more than one client) + * functions that are sent solely to one use whose ID it posses use WFIFOSET *------------------------------------------*/ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target type) { @@ -554,11 +563,10 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target return 0; } -// -// パケット作って送信 -// + /*========================================== - * + * Tells client that its player is fully loaded and that it can proceed to the map screen + * Provides client with player position and facing direction *------------------------------------------*/ int clif_authok(struct map_session_data *sd) { @@ -657,7 +665,8 @@ int clif_dropflooritem(struct flooritem_data* fitem) } /*========================================== - * + * Server tells client to remove item of ID ('fitem->bl.id') from FD player area + * If FD is 0 it tells all clients nearby this item that it is gone *------------------------------------------*/ int clif_clearflooritem(struct flooritem_data *fitem, int fd) { @@ -1105,7 +1114,8 @@ static void clif_setdisguise(struct block_list *bl, unsigned char *buf,int len) } /*========================================== - * クラスチェンジ typeはMobの場合は1で他は0? + * Acronym for 'clif_mob_class_change' used to tell clients around the monster that it's identity changed + * for example, it's run when a pupa transforms into a creamy. *------------------------------------------*/ int clif_class_change(struct block_list *bl,int class_,int type) { @@ -1124,7 +1134,7 @@ int clif_class_change(struct block_list *bl,int class_,int type) } /*========================================== - * + * Server tells client to display (sd->spiritball) amount of spiritballs on target of account id (sd->bl.id) *------------------------------------------*/ static void clif_spiritball_single(int fd, struct map_session_data *sd) { @@ -1136,7 +1146,8 @@ static void clif_spiritball_single(int fd, struct map_session_data *sd) } /*========================================== - * + * Run when player changes map / refreshes + * Tells its client to display all weather settings being used by this map *------------------------------------------*/ static void clif_weather_check(struct map_session_data *sd) { @@ -1148,7 +1159,10 @@ static void clif_weather_check(struct map_session_data *sd) || map[m].flag.fireworks || map[m].flag.sakura || map[m].flag.leaves - || map[m].flag.rain + /** + * No longer available, keeping here just in case it's back someday. [Ind] + **/ + //|| map[m].flag.rain || map[m].flag.clouds2) { if (map[m].flag.snow) @@ -1168,11 +1182,16 @@ static void clif_weather_check(struct map_session_data *sd) clif_specialeffect_single(&sd->bl, 163, fd); if (map[m].flag.leaves) clif_specialeffect_single(&sd->bl, 333, fd); - if (map[m].flag.rain) - clif_specialeffect_single(&sd->bl, 161, fd); + /** + * No longer available, keeping here just in case it's back someday. [Ind] + **/ + //if (map[m].flag.rain) + // clif_specialeffect_single(&sd->bl, 161, fd); } } - +/** + * Run when the weather on a map changes, throws all players in map id 'm' to clif_weather_check function + **/ void clif_weather(int m) { struct s_mapiterator* iter; @@ -1186,7 +1205,9 @@ void clif_weather(int m) } mapit_free(iter); } - +/** + * Main function to spawn a unit on the client (player/mob/pet/etc) + **/ int clif_spawn(struct block_list *bl) { unsigned char buf[128]; @@ -1218,6 +1239,10 @@ int clif_spawn(struct block_list *bl) clif_specialeffect(bl,421,AREA); if( sd->bg_id && map[sd->bl.m].flag.battleground ) clif_sendbgemblem_area(sd); + if( sd->sc.option&OPTION_MOUNTING ) { + //New Mounts are not complaint to the original method, so we gotta tell this guy that he is mounting. + clif_status_load_notick(&sd->bl,SI_ALL_RIDING,2,1,0,0); + } } break; case BL_MOB: @@ -1873,7 +1898,7 @@ int clif_viewpoint(struct map_session_data *sd, int npc_id, int type, int x, int } /*========================================== - * + * Server tells client to display cutin of name 'image' to client, in position 'type' (255, etc) *------------------------------------------*/ int clif_cutin(struct map_session_data* sd, const char* image, int type) { @@ -1945,7 +1970,8 @@ static void clif_addcards(unsigned char* buf, struct item* item) } /*========================================== - * + * Server tells client he got item of index 'n' and amount 'amount', + * when 'fail' is 1 it tells the client it failed to receive said item *------------------------------------------*/ int clif_additem(struct map_session_data *sd, int n, int amount, int fail) { @@ -2014,7 +2040,7 @@ int clif_additem(struct map_session_data *sd, int n, int amount, int fail) } /*========================================== - * + * *------------------------------------------*/ int clif_dropitem(struct map_session_data *sd,int n,int amount) { @@ -2457,8 +2483,9 @@ int clif_guild_xy_remove(struct map_session_data *sd) } /*========================================== - * ステータスを送りつける - * 表示専用数字はこの中で計算して送る + * Server tells client that data 'type' has changed and sends it's new value + * For example, when server updates the client max weight, say, due to higher STR, + * It calls this function with SP_MAXWEIGHT type *------------------------------------------*/ int clif_updatestatus(struct map_session_data *sd,int type) { @@ -2590,7 +2617,9 @@ int clif_updatestatus(struct map_session_data *sd,int type) WFIFOL(fd,4)=pc_nextjobexp(sd); break; - // 00be 終了 + /** + * SP_U are used to update the amount of points necessary to increase that stat + **/ case SP_USTR: case SP_UAGI: case SP_UVIT: @@ -2602,14 +2631,15 @@ int clif_updatestatus(struct map_session_data *sd,int type) len=5; break; - // 013a 終了 + /** + * Tells the client how far it is allowed to attack (weapon range) + **/ case SP_ATTACKRANGE: WFIFOW(fd,0)=0x13a; WFIFOW(fd,2)=sd->battle_status.rhw.range; len=4; break; - // 0141 終了 case SP_STR: WFIFOW(fd,0)=0x141; WFIFOL(fd,2)=type; @@ -2699,7 +2729,7 @@ int clif_changestatus(struct block_list *bl,int type,int val) } /*========================================== - * + * Updates BL unit view data to nearby clients *------------------------------------------*/ void clif_changelook(struct block_list *bl,int type,int val) { @@ -2926,7 +2956,7 @@ int clif_initialstatus(struct map_session_data *sd) } /*========================================== - *矢装備 + * Server tells client item idx 'val' is meant to be shown in equipment's window arrow slot *------------------------------------------*/ int clif_arrowequip(struct map_session_data *sd,int val) { @@ -2968,7 +2998,8 @@ int clif_arrow_fail(struct map_session_data *sd,int type) } /*========================================== - * 作成可能 矢リスト送信 + * Server tells client to display a window similar to Mangifier (item) one + * Server populates the window with avilable arrow crafting options according to player's inventory *------------------------------------------*/ int clif_arrow_create_list(struct map_session_data *sd) { @@ -3004,7 +3035,7 @@ int clif_arrow_create_list(struct map_session_data *sd) } /*========================================== - * + * Server tells client his response regarding the earlier request to increase status *------------------------------------------*/ int clif_statusupack(struct map_session_data *sd,int type,int ok,int val) { @@ -3090,7 +3121,7 @@ int clif_misceffect(struct block_list* bl,int type) } /*========================================== - * 表示オプション変更 + * Server tells BL unit and all nearby clients that his unit-view options (e.g. stone curse appearance) changed *------------------------------------------*/ int clif_changeoption(struct block_list* bl) { @@ -3483,7 +3514,7 @@ void clif_tradestart(struct map_session_data* sd, uint8 type) } /*========================================== - * 相手方からのアイテム追加 + * Server tells 'tsd' player client info on the items 'sd' player just added to the trade window *------------------------------------------*/ void clif_tradeadditem(struct map_session_data* sd, struct map_session_data* tsd, int index, int amount) { @@ -3547,7 +3578,9 @@ void clif_tradeadditem(struct map_session_data* sd, struct map_session_data* tsd } /*========================================== - * アイテム追加成功/失敗 + * Server tells client on the status of it's OK request + * fail 1 : the other person did 'ok' + * fail 0 : you did 'ok' *------------------------------------------*/ void clif_tradeitemok(struct map_session_data* sd, int index, int fail) { @@ -3563,7 +3596,9 @@ void clif_tradeitemok(struct map_session_data* sd, int index, int fail) } /*========================================== - * 取り引きok押し + * Server tells client on the status of it's lock request + * fail 1 : The other trader lock request + * fail 0 : Your lock request *------------------------------------------*/ void clif_tradedeal_lock(struct map_session_data* sd, int fail) { @@ -3578,7 +3613,7 @@ void clif_tradedeal_lock(struct map_session_data* sd, int fail) } /*========================================== - * 取り引きがキャンセルされました + * Server tells client it's trade request was cancelled *------------------------------------------*/ void clif_tradecancelled(struct map_session_data* sd) { @@ -3592,7 +3627,7 @@ void clif_tradecancelled(struct map_session_data* sd) } /*========================================== - * 取り引き完了 + * Server tells client the final status on his trade request *------------------------------------------*/ void clif_tradecompleted(struct map_session_data* sd, int fail) { @@ -3607,7 +3642,7 @@ void clif_tradecompleted(struct map_session_data* sd, int fail) } /*========================================== - * カプラ倉庫のアイテム数を更新 + * Server tells client it's quantity of items in storage changed *------------------------------------------*/ void clif_updatestorageamount(struct map_session_data* sd, int amount) { @@ -3624,7 +3659,7 @@ void clif_updatestorageamount(struct map_session_data* sd, int amount) } /*========================================== - * カプラ倉庫にアイテムを追加する + * Server tells client it's status on his request to add a item to storage *------------------------------------------*/ void clif_storageitemadded(struct map_session_data* sd, struct item* i, int index, int amount) { @@ -3679,7 +3714,7 @@ void clif_updateguildstorageamount(struct map_session_data* sd, int amount) } /*========================================== - * カプラ倉庫からアイテムを取り去る + * Server tells client its status on his request to remove a item from storage *------------------------------------------*/ void clif_storageitemremoved(struct map_session_data* sd, int index, int amount) { @@ -3696,7 +3731,7 @@ void clif_storageitemremoved(struct map_session_data* sd, int index, int amount) } /*========================================== - * カプラ倉庫を閉じる + * Server tells client his storage was closed *------------------------------------------*/ void clif_storageclose(struct map_session_data* sd) { @@ -3709,9 +3744,9 @@ void clif_storageclose(struct map_session_data* sd) WFIFOW(fd,0) = 0xf8; // Storage Closed WFIFOSET(fd,packet_len(0xf8)); } - +int clif_status_load_single(int fd, int id,int type,int flag,int val1, int val2, int val3); /*========================================== - * PC表示 + * Server tells 'sd' player client the abouts of 'dstsd' player *------------------------------------------*/ static void clif_getareachar_pc(struct map_session_data* sd,struct map_session_data* dstsd) { @@ -3735,7 +3770,10 @@ static void clif_getareachar_pc(struct map_session_data* sd,struct map_session_d if(dstsd->spiritball > 0) clif_spiritball_single(sd->fd, dstsd); - + if( dstsd->sc.option&OPTION_MOUNTING ) { + //New Mounts are not complaint to the original method, so we gotta tell this guy that I'm mounting. + clif_status_load_single(sd->fd,dstsd->bl.id,SI_ALL_RIDING,2,1,0,0); + } if( (sd->status.party_id && dstsd->status.party_id == sd->status.party_id) || //Party-mate, or hpdisp setting. (sd->bg_id && sd->bg_id == dstsd->bg_id) || //BattleGround (battle_config.disp_hpmeter && (gmlvl = pc_isGM(sd)) >= battle_config.disp_hpmeter && gmlvl >= pc_isGM(dstsd)) ) @@ -4044,7 +4082,7 @@ void clif_getareachar_item(struct map_session_data* sd,struct flooritem_data* fi } /*========================================== - * 場所スキルエフェクトが視界に入る + * Server tells client 'sd' of all nearby skill units (e.g. safety wall) *------------------------------------------*/ static void clif_getareachar_skillunit(struct map_session_data *sd, struct skill_unit *unit) { @@ -4084,7 +4122,7 @@ static void clif_getareachar_skillunit(struct map_session_data *sd, struct skill } /*========================================== - * 場所スキルエフェクトが視界から消える + * Server tells client to remove unit of id 'unit->bl.id' *------------------------------------------*/ static void clif_clearchar_skillunit(struct skill_unit *unit, int fd) { @@ -4100,7 +4138,7 @@ static void clif_clearchar_skillunit(struct skill_unit *unit, int fd) } /*========================================== - * 場所スキルエフェクト削除 + * Server tells all clients in sight of 'unit->bl.id' ID to remove itself from sight (delete) *------------------------------------------*/ void clif_skill_delunit(struct skill_unit *unit) { @@ -4245,7 +4283,7 @@ int clif_insight(struct block_list *bl,va_list ap) } /*========================================== - * スキルリストを送信する + * Server tells the client information on 'sd' player's skill tree *------------------------------------------*/ int clif_skillinfoblock(struct map_session_data *sd) { @@ -4282,7 +4320,9 @@ int clif_skillinfoblock(struct map_session_data *sd) return 1; } - +/** + * Server tells client 'sd' to add skill of id 'id' to it's skill tree (e.g. with Ice Falcion item) + **/ int clif_addskill(struct map_session_data *sd, int id ) { int fd; @@ -4333,7 +4373,7 @@ int clif_deleteskill(struct map_session_data *sd, int id) } /*========================================== - * スキル割り振り通知 + * Server tells client it's skill of id 'skill_num' level changed *------------------------------------------*/ int clif_skillup(struct map_session_data *sd,int skill_num) { @@ -4668,7 +4708,7 @@ int clif_skill_damage2(struct block_list *src,struct block_list *dst,unsigned in */ /*========================================== - * 支援/回復スキルエフェクト + * Server tells client(s) that 'src' casted a skill of nodamage type (e.g. heal) on 'dst' *------------------------------------------*/ int clif_skill_nodamage(struct block_list *src,struct block_list *dst,int skill_id,int heal,int fail) { @@ -4701,7 +4741,8 @@ int clif_skill_nodamage(struct block_list *src,struct block_list *dst,int skill_ } /*========================================== - * 場所スキルエフェクト + * Server tells client 'src' to display effect of skill id 'skill_id' on location 'x' and 'y' + * 'val' is used for information that varies from skill to skill, usually it's the skill level *------------------------------------------*/ int clif_skill_poseffect(struct block_list *src,int skill_id,int val,int x,int y,int tick) { @@ -4727,7 +4768,7 @@ int clif_skill_poseffect(struct block_list *src,int skill_id,int val,int x,int y } /*========================================== - * 場所スキルエフェクト表示 + * Tells all client's nearby 'unit' sight range that it spawned *------------------------------------------*/ //FIXME: this is just an AREA version of clif_getareachar_skillunit() void clif_skill_setunit(struct skill_unit *unit) @@ -4765,7 +4806,7 @@ void clif_skill_setunit(struct skill_unit *unit) } /*========================================== - * ワープ場所選択 + * Used to display 'teleport' and 'warp portal' information on it's respective dialogs *------------------------------------------*/ void clif_skill_warppoint(struct map_session_data* sd, short skill_num, short skill_lv, unsigned short map1, unsigned short map2, unsigned short map3, unsigned short map4) { @@ -4832,7 +4873,7 @@ void clif_skill_teleportmessage(struct map_session_data *sd, int type) } /*========================================== - * モンスター情報 + * Server tells client to display 'estimation' (Sense) information for monster (bl) 'dst' *------------------------------------------*/ int clif_skill_estimation(struct map_session_data *sd,struct block_list *dst) { @@ -4868,14 +4909,15 @@ int clif_skill_estimation(struct map_session_data *sd,struct block_list *dst) return 0; } /*========================================== - * アイテム合成可能リスト + * Server tells client to display a window similar to Mangifier (item) one + * Server populates the window with avilable crafting options according to skill used to call this *------------------------------------------*/ -int clif_skill_produce_mix_list(struct map_session_data *sd, int trigger) +int clif_skill_produce_mix_list(struct map_session_data *sd, int skillid , int trigger) { int i,c,view,fd; nullpo_ret(sd); - if(sd->menuskill_id == AM_PHARMACY) + if(sd->menuskill_id == skillid) return 0; //Avoid resending the menu twice or more times... fd=sd->fd; WFIFOHEAD(fd, MAX_SKILL_PRODUCE_DB * 8 + 8); @@ -4895,7 +4937,7 @@ int clif_skill_produce_mix_list(struct map_session_data *sd, int trigger) WFIFOW(fd, 2)=c*8+8; WFIFOSET(fd,WFIFOW(fd,2)); if(c > 0) { - sd->menuskill_id = AM_PHARMACY; + sd->menuskill_id = skillid; sd->menuskill_val = trigger; return 1; } @@ -4966,9 +5008,9 @@ int clif_status_load(struct block_list *bl,int type, int flag) return 0; } /*========================================== - * 状態異常アイコン/メッセージ表示 + * Server tell's BL and nearby clients of his status change *------------------------------------------*/ -int clif_status_change(struct block_list *bl,int type,int flag,unsigned int tick) +int clif_status_change(struct block_list *bl,int type,int flag,unsigned int tick,int val1, int val2, int val3) { unsigned char buf[32]; @@ -4996,9 +5038,9 @@ int clif_status_change(struct block_list *bl,int type,int flag,unsigned int tick if( battle_config.display_status_timers && tick>0 ) { WBUFL(buf,9)=tick; - WBUFL(buf,13)=0; - WBUFL(buf,17)=0; - WBUFL(buf,21)=0; + WBUFL(buf,13) = val1; + WBUFL(buf,17) = val2; + WBUFL(buf,21) = val3; } clif_send(buf,packet_len(WBUFW(buf,0)),bl,AREA); return 0; @@ -5031,7 +5073,6 @@ int clif_displaymessage(const int fd, const char* mes) } /*========================================== - * 天の声を送信する * Send broadcast message in yellow or blue (without font formatting). * S 009A .W .?B *------------------------------------------*/ @@ -5055,7 +5096,8 @@ int clif_broadcast(struct block_list* bl, const char* mes, int len, int type, en } /*========================================== - * グローバルメッセージ + * Displays a message on a 'bl' to all it's nearby clients + * Used by npc_globalmessage *------------------------------------------*/ void clif_GlobalMessage(struct block_list* bl, const char* message) { @@ -5128,7 +5170,8 @@ int clif_broadcast2(struct block_list* bl, const char* mes, int len, unsigned lo return 0; } /*========================================== - * HPSP回復エフェクトを送信する + * Server tells self client to heal self for 'val', is either SP_HP or SP_SP + * It displays these green and blue heal numbers that show up at your body and go up until they fade away *------------------------------------------*/ int clif_heal(int fd,int type,int val) { @@ -5142,7 +5185,7 @@ int clif_heal(int fd,int type,int val) } /*========================================== - * 復活する + * Server tells nearby clients of 'bl' that it ressurected (and plays ress effect) *------------------------------------------*/ int clif_resurrection(struct block_list *bl,int type) { @@ -5190,7 +5233,8 @@ void clif_map_type(struct map_session_data* sd, enum map_type type) } /*========================================== - * PVP実装?(仮) + * Server tells client on it's pvp rank and map status, + * (it controls the counter on the bottom right of the map existent in pvp rooms) *------------------------------------------*/ int clif_pvpset(struct map_session_data *sd,int pvprank,int pvpnum,int type) { @@ -5239,7 +5283,8 @@ void clif_map_property_mapall(int map, enum map_property property) } /*========================================== - * 精錬エフェクトを送信する + * Server tells client the status on refine of item index 'index' from refine 'val' + * Message displayed depends on 'fail' (broken(red) or success(blue)) *------------------------------------------*/ void clif_refine(int fd, int fail, int index, int val) { @@ -5308,7 +5353,8 @@ int clif_wis_end(int fd, int flag) } /*========================================== - * キャラID名前引き結果を送信する + * Server tells client that char id 'charid' is to be assigned the name of 'name' + * This is used when client requests the server the name written in a item, e.g. crafted alche potions *------------------------------------------*/ int clif_solved_charname(int fd, int charid, const char* name) { @@ -5321,7 +5367,7 @@ int clif_solved_charname(int fd, int charid, const char* name) } /*========================================== - * カードの挿入可能リストを返す + * Server tells client to list all items that may be worn by card item of index 'idx' *------------------------------------------*/ int clif_use_card(struct map_session_data *sd,int idx) { @@ -5371,7 +5417,7 @@ int clif_use_card(struct map_session_data *sd,int idx) return 0; } /*========================================== - * カードの挿入終了 + * Server tells client his status on the previous clif_use_card (failed or OK) *------------------------------------------*/ int clif_insert_card(struct map_session_data *sd,int idx_equip,int idx_card,int flag) { @@ -5390,7 +5436,7 @@ int clif_insert_card(struct map_session_data *sd,int idx_equip,int idx_card,int } /*========================================== - * 鑑定可能アイテムリスト送信 + * Server tells client it's list of unidentified items *------------------------------------------*/ int clif_item_identify_list(struct map_session_data *sd) { @@ -5419,7 +5465,7 @@ int clif_item_identify_list(struct map_session_data *sd) } /*========================================== - * 鑑定結果 + * Server tells client his item of index 'idx' has been identified *------------------------------------------*/ int clif_item_identified(struct map_session_data *sd,int idx,int flag) { @@ -5437,7 +5483,7 @@ int clif_item_identified(struct map_session_data *sd,int idx,int flag) } /*========================================== - * 修理可能アイテムリスト送信 + * Server tells client the list of broken items *------------------------------------------*/ int clif_item_repair_list(struct map_session_data *sd,struct map_session_data *dstsd) { @@ -5537,7 +5583,9 @@ int clif_item_refine_list(struct map_session_data *sd) } /*========================================== - * アイテムによる一時的なスキル効果 + * Server tells client to display the 'green skill name' at the top of the screen + target cursor, + * for skill 'skillid' of 'skilllv' level + * Used for example when player uses a skill scroll (e.g. Fire Bolt Scroll) *------------------------------------------*/ int clif_item_skill(struct map_session_data *sd,int skillid,int skilllv) { @@ -5561,7 +5609,7 @@ int clif_item_skill(struct map_session_data *sd,int skillid,int skilllv) } /*========================================== - * カートにアイテム追加 + * Server tells client it's status on trying to add item of index 'n' and amount 'amount' to it's cart *------------------------------------------*/ int clif_cart_additem(struct map_session_data *sd,int n,int amount,int fail) { @@ -5611,7 +5659,7 @@ int clif_cart_additem(struct map_session_data *sd,int n,int amount,int fail) } /*========================================== - * カートからアイテム削除 + * Server tells client it's status on trying to remove item of index 'n' and amount 'amount' from it's cart to invent *------------------------------------------*/ int clif_cart_delitem(struct map_session_data *sd,int n,int amount) { @@ -5996,10 +6044,11 @@ void clif_party_inviteack(struct map_session_data* sd, const char* nick, int res /*========================================== - * パーティ設定送信 - * flag & 0x001=exp変更ミス - * 0x010=item変更ミス - * 0x100=一人にのみ送信 + * Server tells client (and it's party members) of a change in the party settings + * 'Flag' Options + * - 0x01 (exp) + * - 0x10 (item) + * - 0x100 (party member logged in / was added to party) *------------------------------------------*/ int clif_party_option(struct party_data *p,struct map_session_data *sd,int flag) { @@ -6034,7 +6083,7 @@ int clif_party_option(struct party_data *p,struct map_session_data *sd,int flag) return 0; } /*========================================== - * パーティ脱退(脱退前に呼ぶこと) + * Server tells party members of party 'p' that 'sd' player left *------------------------------------------*/ int clif_party_withdraw(struct party_data* p, struct map_session_data* sd, int account_id, const char* name, int flag) { @@ -6056,15 +6105,14 @@ int clif_party_withdraw(struct party_data* p, struct map_session_data* sd, int a WBUFL(buf,2)=account_id; memcpy(WBUFP(buf,6),name,NAME_LENGTH); WBUFB(buf,30)=flag&0x0f; - if((flag&0xf0)==0) clif_send(buf,packet_len(0x105),&sd->bl,PARTY); - else + else clif_send(buf,packet_len(0x105),&sd->bl,SELF); return 0; } /*========================================== - * パーティメッセージ送信 + * Server deploys a message to all party members, called from party.c:party_recv_message() *------------------------------------------*/ int clif_party_message(struct party_data* p, int account_id, const char* mes, int len) { @@ -6086,7 +6134,7 @@ int clif_party_message(struct party_data* p, int account_id, const char* mes, in return 0; } /*========================================== - * パーティ座標通知 + * Server tells all party members of 'sd' player that 'sd' player location changed *------------------------------------------*/ int clif_party_xy(struct map_session_data *sd) { @@ -6119,7 +6167,7 @@ int clif_party_xy_single(int fd, struct map_session_data *sd) /*========================================== - * パーティHP通知 + * Server tells nearby party members of 'sd' that his hp bar has updated *------------------------------------------*/ int clif_party_hp(struct map_session_data *sd) { @@ -6224,7 +6272,7 @@ int clif_hpmeter_sub(struct block_list *bl, va_list ap) } /*========================================== - * GMへ場所とHP通知 + * Server tells all nearby gms to 'sd' that 'sd' hp bar was updated *------------------------------------------*/ int clif_hpmeter(struct map_session_data *sd) { @@ -6237,7 +6285,7 @@ int clif_hpmeter(struct map_session_data *sd) } /*========================================== - * パーティ場所移動(未使用) + * (?) Server tells 'sd' party members that 'sd' state 'changed' *------------------------------------------*/ void clif_party_move(struct party* p, struct map_session_data* sd, int online) { @@ -6258,7 +6306,8 @@ void clif_party_move(struct party* p, struct map_session_data* sd, int online) clif_send(buf,packet_len(0x104),&sd->bl,PARTY); } /*========================================== - * 攻撃するために移動が必要 + * Server tells client to attack bl, if not in range of attack (rhw.range) it'll move to bl + * called from unit.c *------------------------------------------*/ int clif_movetoattack(struct map_session_data *sd,struct block_list *bl) { @@ -6280,7 +6329,7 @@ int clif_movetoattack(struct map_session_data *sd,struct block_list *bl) return 0; } /*========================================== - * 製造エフェクト + * Server tells client to display produce effect (refine-like), success or failure depends on 'flag' *------------------------------------------*/ int clif_produceeffect(struct map_session_data* sd,int flag,int nameid) { @@ -6331,7 +6380,7 @@ int clif_pet_roulette(struct map_session_data *sd,int data) } /*========================================== - * pet卵リスト作成 + * Server tells client to list it's eggs (used in hatching window to select a egg) *------------------------------------------*/ int clif_sendegg(struct map_session_data *sd) { @@ -6461,7 +6510,7 @@ int clif_pet_food(struct map_session_data *sd,int foodid,int fail) } /*========================================== - * オートスペル リスト送信 + * Server tells client to display autospell (Sage Skill) skill selection list *------------------------------------------*/ int clif_autospell(struct map_session_data *sd,int skilllv) { @@ -6549,7 +6598,7 @@ void clif_devotion(struct block_list *src, struct map_session_data *tsd) } /*========================================== - * 氣球 + * Server tells clients nearby 'sd' (and himself) to display 'sd->spiritball' number of spiritballs on 'sd' *------------------------------------------*/ int clif_spiritball(struct map_session_data *sd) { @@ -6581,7 +6630,8 @@ int clif_combo_delay(struct block_list *bl,int wait) return 0; } /*========================================== - *白刃取り + * Server tells client to display blade stop animation 'link' from 'src' to 'dst_id' (account id of target) + * active toggles the state *------------------------------------------*/ void clif_bladestop(struct block_list *src, int dst_id, int active) { @@ -6598,7 +6648,7 @@ void clif_bladestop(struct block_list *src, int dst_id, int active) } /*========================================== - * MVPエフェクト + * Server tells clients nearby 'sd' (and itself) to display MvP killed effect on 'sd' player *------------------------------------------*/ int clif_mvp_effect(struct map_session_data *sd) { @@ -6612,7 +6662,7 @@ int clif_mvp_effect(struct map_session_data *sd) return 0; } /*========================================== - * MVPアイテム所得 + * Server tells client to display mvp drop prize info to player 'sd' for item id 'nameid' *------------------------------------------*/ int clif_mvp_item(struct map_session_data *sd,int nameid) { @@ -6631,7 +6681,7 @@ int clif_mvp_item(struct map_session_data *sd,int nameid) return 0; } /*========================================== - * MVP経験値所得 + * Server tells client to display mvp exp prize to player 'sd' for amount 'exp' *------------------------------------------*/ int clif_mvp_exp(struct map_session_data *sd, unsigned int exp) { @@ -6693,7 +6743,7 @@ void clif_guild_belonginfo(struct map_session_data *sd, struct guild *g) /*========================================== - * ギルドメンバログイン通知 + * Server tells all members of 'g' guild that member of index 'idx' is online or offline (flag 1:0) *------------------------------------------*/ int clif_guild_memberlogin_notice(struct guild *g,int idx,int flag) { @@ -6755,7 +6805,7 @@ int clif_guild_send_onlineinfo(struct map_session_data *sd) } /*========================================== - * ギルドマスター通知(14dへの応答) + * Tells 'sd' whether he is the guild master of his guild or not (relies on sd->state.gmaster_flag) *------------------------------------------*/ int clif_guild_masterormember(struct map_session_data *sd) { @@ -6814,7 +6864,7 @@ int clif_guild_basicinfo(struct map_session_data *sd) } /*========================================== - * ギルド同盟/敵対情報 + * Server tells client 'sd' it's guild alliances *------------------------------------------*/ int clif_guild_allianceinfo(struct map_session_data *sd) { @@ -6843,7 +6893,7 @@ int clif_guild_allianceinfo(struct map_session_data *sd) } /*========================================== - * ギルドメンバーリスト + * Server tells client it's guild member list *------------------------------------------*/ int clif_guild_memberlist(struct map_session_data *sd) { @@ -6873,7 +6923,7 @@ int clif_guild_memberlist(struct map_session_data *sd) WFIFOL(fd,c*104+22)=(int)cap_value(m->exp,0,INT32_MAX); WFIFOL(fd,c*104+26)=m->online; WFIFOL(fd,c*104+30)=m->position; - memset(WFIFOP(fd,c*104+34),0,50); // メモ? + memset(WFIFOP(fd,c*104+34),0,50); //[Ind] - This is displayed in the 'note' column but being you can't edit it it's sent empty. memcpy(WFIFOP(fd,c*104+84),m->name,NAME_LENGTH); c++; } @@ -6882,7 +6932,7 @@ int clif_guild_memberlist(struct map_session_data *sd) return 0; } /*========================================== - * ギルド役職名リスト + * Server tell client it's guild position list *------------------------------------------*/ int clif_guild_positionnamelist(struct map_session_data *sd) { @@ -6905,7 +6955,7 @@ int clif_guild_positionnamelist(struct map_session_data *sd) return 0; } /*========================================== - * ギルド役職情報リスト + * Server tell client about it's guild position permissions and tax *------------------------------------------*/ int clif_guild_positioninfolist(struct map_session_data *sd) { @@ -6931,7 +6981,7 @@ int clif_guild_positioninfolist(struct map_session_data *sd) return 0; } /*========================================== - * ギルド役職変更通知 + * Server tells client about position 'idx' information, being it changed *------------------------------------------*/ int clif_guild_positionchanged(struct guild *g,int idx) { @@ -6952,7 +7002,7 @@ int clif_guild_positionchanged(struct guild *g,int idx) return 0; } /*========================================== - * ギルドメンバ変更通知 + * Server tells client about a specific guild member index that changed *------------------------------------------*/ int clif_guild_memberpositionchanged(struct guild *g,int idx) { @@ -6971,7 +7021,7 @@ int clif_guild_memberpositionchanged(struct guild *g,int idx) return 0; } /*========================================== - * ギルドエンブレム送信 + * Server tells client about this new cool emblem a specific guild got *------------------------------------------*/ int clif_guild_emblem(struct map_session_data *sd,struct guild *g) { @@ -7076,7 +7126,7 @@ int clif_guild_notice(struct map_session_data* sd, struct guild* g) } /*========================================== - * ギルドメンバ勧誘 + * Server tells client 'sd' that guild 'g' wants to invite him *------------------------------------------*/ int clif_guild_invite(struct map_session_data *sd,struct guild *g) { @@ -7116,7 +7166,7 @@ int clif_guild_inviteack(struct map_session_data *sd,int flag) } /*========================================== - * ギルドメンバ脱退通知 + * Server tells guild members of 'sd' that he left his guild for a reason *------------------------------------------*/ int clif_guild_leave(struct map_session_data *sd,const char *name,const char *mes) { @@ -7132,7 +7182,7 @@ int clif_guild_leave(struct map_session_data *sd,const char *name,const char *me } /*========================================== - * ギルドメンバ追放通知 + * Server tells guild members of 'sd' that 'name' of account id 'account_id' was expelled for reason 'mes' *------------------------------------------*/ void clif_guild_expulsion(struct map_session_data* sd, const char* name, const char* mes, int account_id) { @@ -7155,7 +7205,7 @@ void clif_guild_expulsion(struct map_session_data* sd, const char* name, const c } /*========================================== - * ギルド追放メンバリスト + * Server tells client on sd's guild expulsion records *------------------------------------------*/ void clif_guild_expulsionlist(struct map_session_data* sd) { @@ -7225,7 +7275,7 @@ void clif_guild_message(struct guild *g,int account_id,const char *mes,int len) /*========================================== - * ギルドスキル割り振り通知 + * Server tells client 'sd' that his guild skill 'skill_num' gone to level 'lv' *------------------------------------------*/ int clif_guild_skillup(struct map_session_data *sd,int skill_num,int lv) { @@ -7245,7 +7295,7 @@ int clif_guild_skillup(struct map_session_data *sd,int skill_num,int lv) return 0; } /*========================================== - * ギルド同盟要請 + * Server tells client 'sd' that 'account_id' from guild name 'name' wants to invite 'sd's guild for alliance *------------------------------------------*/ int clif_guild_reqalliance(struct map_session_data *sd,int account_id,const char *name) { @@ -7284,7 +7334,7 @@ int clif_guild_allianceack(struct map_session_data *sd,int flag) return 0; } /*========================================== - * ギルド関係解消通知 + * Server tells client 'sd' that guild_id is either in or out of it's alliance list (depend on flag) *------------------------------------------*/ int clif_guild_delalliance(struct map_session_data *sd,int guild_id,int flag) { @@ -7337,7 +7387,7 @@ int clif_guild_oppositionack(struct map_session_data *sd,int flag) }*/ /*========================================== - * ギルド解散通知 + * Server tells client 'sd' that guild broke because of 'flag' reason *------------------------------------------*/ int clif_guild_broken(struct map_session_data *sd,int flag) { @@ -7354,7 +7404,7 @@ int clif_guild_broken(struct map_session_data *sd,int flag) } /*========================================== - * エモーション + * Server tells all nearby clients of 'bl' to display emoticon number 'type' *------------------------------------------*/ void clif_emotion(struct block_list *bl,int type) { @@ -7369,7 +7419,7 @@ void clif_emotion(struct block_list *bl,int type) } /*========================================== - * トーキーボックス + * Server tells all clients nearby 'bl' that he stepped in a talkie box (and displays the message) *------------------------------------------*/ void clif_talkiebox(struct block_list* bl, const char* talkie) { @@ -7383,7 +7433,7 @@ void clif_talkiebox(struct block_list* bl, const char* talkie) } /*========================================== - * 結婚エフェクト + * Server tells bl and nearby clients to display marriage effect *------------------------------------------*/ void clif_wedding_effect(struct block_list *bl) { @@ -7396,7 +7446,7 @@ void clif_wedding_effect(struct block_list *bl) clif_send(buf, packet_len(0x1ea), bl, AREA); } /*========================================== - * ?なたに逢いたい使用時名前叫び + * Server tells client 'sd' to create a warp to call his partner (wedding skill) *------------------------------------------*/ void clif_callpartner(struct map_session_data *sd) @@ -7562,41 +7612,41 @@ void clif_GM_silence(struct map_session_data* sd, struct map_session_data* tsd, } /*========================================== - * Wis拒否許可応答 + * ? Unknown functionality : not called anywhere *------------------------------------------*/ -int clif_wisexin(struct map_session_data *sd,int type,int flag) -{ - int fd; - - nullpo_ret(sd); - - fd=sd->fd; - WFIFOHEAD(fd,packet_len(0xd1)); - WFIFOW(fd,0)=0xd1; - WFIFOB(fd,2)=type; - WFIFOB(fd,3)=flag; - WFIFOSET(fd,packet_len(0xd1)); - - return 0; -} +//int clif_wisexin(struct map_session_data *sd,int type,int flag) +//{ +// int fd; +// +// nullpo_ret(sd); +// +// fd=sd->fd; +// WFIFOHEAD(fd,packet_len(0xd1)); +// WFIFOW(fd,0)=0xd1; +// WFIFOB(fd,2)=type; +// WFIFOB(fd,3)=flag; +// WFIFOSET(fd,packet_len(0xd1)); +// +// return 0; +//} /*========================================== - * Wis全拒否許可応答 + * ? Unknown functionality : not called anywhere *------------------------------------------*/ -int clif_wisall(struct map_session_data *sd,int type,int flag) -{ - int fd; - - nullpo_ret(sd); - - fd=sd->fd; - WFIFOHEAD(fd,packet_len(0xd2)); - WFIFOW(fd,0)=0xd2; - WFIFOB(fd,2)=type; - WFIFOB(fd,3)=flag; - WFIFOSET(fd,packet_len(0xd2)); - - return 0; -} +//int clif_wisall(struct map_session_data *sd,int type,int flag) +//{ +// int fd; +// +// nullpo_ret(sd); +// +// fd=sd->fd; +// WFIFOHEAD(fd,packet_len(0xd2)); +// WFIFOW(fd,0)=0xd2; +// WFIFOB(fd,2)=type; +// WFIFOB(fd,3)=flag; +// WFIFOSET(fd,packet_len(0xd2)); +// +// return 0; +//} /*========================================== * Play a BGM! [Rikter/Yommy] @@ -7615,7 +7665,8 @@ void clif_playBGM(struct map_session_data* sd, const char* name) } /*========================================== - * サウンドエフェクト + * Server tells 'bl' to play a .wav music file in client's /wav/ folder named 'name' + * functionality of 'type' is unclear. it's normally sent as '0' *------------------------------------------*/ void clif_soundeffect(struct map_session_data* sd, struct block_list* bl, const char* name, int type) { @@ -8459,7 +8510,7 @@ static int clif_guess_PacketVer(int fd, int get_previous, int *error) // ------------ // clif_parse_* // ------------ -// パケット読み取って色々操作 +// Parses incoming (player) connection /*========================================== * *------------------------------------------*/ @@ -8548,8 +8599,9 @@ void clif_parse_WantToConnection(int fd, TBL_PC* sd) } /*========================================== - * 007d クライアント側マップ読み込み完了 - * map侵入時に必要なデータを全て送りつける + * 007d : Server/Client tells that he is able to proceed + * This is run by both server (from pc.c) and client (on map load/refresh + * (teleport/warping in same map also triggers this) *------------------------------------------*/ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) { @@ -9020,9 +9072,11 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) const char* text = (char*)RFIFOP(fd,4); int textlen = RFIFOW(fd,2) - 4; - char *name, *message; + char *name, *message, *fakename = NULL; int namelen, messagelen; + bool is_fake; + // validate packet and retrieve name and message if( !clif_process_message(sd, 0, &name, &namelen, &message, &messagelen) ) return; @@ -9039,21 +9093,35 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) return; sd->cantalk_tick = gettick() + battle_config.min_chat_delay; } - + /** + * Fake Name Design by FatalEror (bug report #9) + **/ + if( ( is_fake = ( sd->fakename[0] ) ) ) { + fakename = (char*) malloc(strlen(sd->fakename)+messagelen+3); + strcpy(fakename, sd->fakename); + strcat(fakename, " : "); + strcat(fakename, message); + textlen = strlen(fakename) + 1; + } // send message to others (using the send buffer for temp. storage) WFIFOHEAD(fd, 8 + textlen); WFIFOW(fd,0) = 0x8d; WFIFOW(fd,2) = 8 + textlen; WFIFOL(fd,4) = sd->bl.id; - safestrncpy((char*)WFIFOP(fd,8), text, textlen); + safestrncpy((char*)WFIFOP(fd,8), is_fake ? fakename : text, textlen); //FIXME: chat has range of 9 only clif_send(WFIFOP(fd,0), WFIFOW(fd,2), &sd->bl, sd->chatID ? CHAT_WOS : AREA_CHAT_WOC); // send back message to the speaker - memcpy(WFIFOP(fd,0), RFIFOP(fd,0), RFIFOW(fd,2)); - WFIFOW(fd,0) = 0x8e; + if( is_fake ) { + WFIFOW(fd,0) = 0x8e; + WFIFOW(fd,2) = textlen + 4; + safestrncpy((char*)WFIFOP(fd,4), fakename, textlen); + } else { + memcpy(WFIFOP(fd,0), RFIFOP(fd,0), RFIFOW(fd,2)); + WFIFOW(fd,0) = 0x8e; + } WFIFOSET(fd, WFIFOW(fd,2)); - #ifdef PCRE_SUPPORT // trigger listening npcs map_foreachinrange(npc_chat_sub, &sd->bl, AREA_SIZE, BL_NPC, text, textlen, &sd->bl); @@ -9837,7 +9905,7 @@ static void clif_noask_sub(struct map_session_data *src, struct map_session_data } /*========================================== - * 取引要請を相手に送る + * Client tells server to send a trade request to char id RFIFOL(fd,2) *------------------------------------------*/ void clif_parse_TradeRequest(int fd,struct map_session_data *sd) { @@ -9864,7 +9932,7 @@ void clif_parse_TradeRequest(int fd,struct map_session_data *sd) } /*========================================== - * 取引要請 + * Client tells server he replied to a trade request sent to him *------------------------------------------*/ void clif_parse_TradeAck(int fd,struct map_session_data *sd) { @@ -9872,7 +9940,7 @@ void clif_parse_TradeAck(int fd,struct map_session_data *sd) } /*========================================== - * アイテム追加 + * Client tells server to add RFIFOL(fd,4) quantity of item index RFIFOW(fd,2) *------------------------------------------*/ void clif_parse_TradeAddItem(int fd,struct map_session_data *sd) { @@ -9886,7 +9954,7 @@ void clif_parse_TradeAddItem(int fd,struct map_session_data *sd) } /*========================================== - * アイテム追加完了(ok押し) + * Client tells server player he is done adding items to his trade window *------------------------------------------*/ void clif_parse_TradeOk(int fd,struct map_session_data *sd) { @@ -9894,7 +9962,7 @@ void clif_parse_TradeOk(int fd,struct map_session_data *sd) } /*========================================== - * 取引キャンセル + * Client tells server player cancelled the trade *------------------------------------------*/ void clif_parse_TradeCancel(int fd,struct map_session_data *sd) { @@ -9902,7 +9970,7 @@ void clif_parse_TradeCancel(int fd,struct map_session_data *sd) } /*========================================== - * 取引許諾(trade押し) + * Client tells server player 'locked' the trade screen (can't add/remove items) *------------------------------------------*/ void clif_parse_TradeCommit(int fd,struct map_session_data *sd) { @@ -9918,7 +9986,7 @@ void clif_parse_StopAttack(int fd,struct map_session_data *sd) } /*========================================== - * カートへアイテムを移す + * Client tells server player dragged (RFIFOL(fd,4))x of item idx RIFOFW(fd,2)-2 to cart *------------------------------------------*/ void clif_parse_PutItemToCart(int fd,struct map_session_data *sd) { @@ -9929,7 +9997,7 @@ void clif_parse_PutItemToCart(int fd,struct map_session_data *sd) pc_putitemtocart(sd,RFIFOW(fd,2)-2,RFIFOL(fd,4)); } /*========================================== - * カートからアイテムを出す + * Client tells server to take y (RFIFOL(fd,4)) amount of item (idx:RFIFOW(fd,2)-2) from cart and add to inventory *------------------------------------------*/ void clif_parse_GetItemFromCart(int fd,struct map_session_data *sd) { @@ -9939,16 +10007,18 @@ void clif_parse_GetItemFromCart(int fd,struct map_session_data *sd) } /*========================================== - * 付属品(鷹,ペコ,カート)をはずす + * Client tells server the user hit the 'OFF' button in the equip window (appears when mounting, with falcon, etc) *------------------------------------------*/ void clif_parse_RemoveOption(int fd,struct map_session_data *sd) { - //Can only remove Cart/Riding/Falcon. - pc_setoption(sd,sd->sc.option&~(OPTION_CART|OPTION_RIDING|OPTION_FALCON)); + /** + * Attempts to remove these options when this function is called (will remove all available) + **/ + pc_setoption(sd,sd->sc.option&~(OPTION_CART|OPTION_RIDING|OPTION_FALCON|OPTION_DRAGON|OPTION_MADOGEAR)); } /*========================================== - * チェンジカート + * Client tells server the user selected cart type 'type', comes from cart selection screen (Change Cart Skill) *------------------------------------------*/ void clif_parse_ChangeCart(int fd,struct map_session_data *sd) { @@ -9968,7 +10038,7 @@ void clif_parse_ChangeCart(int fd,struct map_session_data *sd) } /*========================================== - * ステータスアップ + * Client tells Server to process a /str, /vit, etc(others) *------------------------------------------*/ void clif_parse_StatusUp(int fd,struct map_session_data *sd) { @@ -9976,7 +10046,7 @@ void clif_parse_StatusUp(int fd,struct map_session_data *sd) } /*========================================== - * スキルレベルアップ + * Client tells server to level up skill (RFIFOW(fd,2)) by 1 *------------------------------------------*/ void clif_parse_SkillUp(int fd,struct map_session_data *sd) { @@ -10056,7 +10126,7 @@ static void clif_parse_UseSkillToPos_mercenary(struct mercenary_data *md, struct } /*========================================== - * スキル使用(ID指定) + * Client tells server he'd like to use skill of id 'skillnum' and level 'skilllv' on 'target_id' *------------------------------------------*/ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) { @@ -10163,7 +10233,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) } /*========================================== - * スキル使用(場所指定) + * Client tells server he'd like to use AoE skill id 'skillnum' of level 'skilllv' on 'x','y' location *------------------------------------------*/ void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, short skilllv, short skillnum, short x, short y, int skillmoreinfo) { @@ -10273,7 +10343,7 @@ void clif_parse_UseSkillToPosMoreInfo(int fd, struct map_session_data *sd) ); } /*========================================== - * スキル使用(map指定) + * (?) I *think* this one is for skills cast on self, not entirely sure *------------------------------------------*/ void clif_parse_UseSkillMap(int fd, struct map_session_data* sd) { @@ -10294,7 +10364,7 @@ void clif_parse_UseSkillMap(int fd, struct map_session_data* sd) skill_castend_map(sd,skill_num,map_name); } /*========================================== - * メモ要求 + * Client tells server he did '/memo' *------------------------------------------*/ void clif_parse_RequestMemo(int fd,struct map_session_data *sd) { @@ -10302,13 +10372,12 @@ void clif_parse_RequestMemo(int fd,struct map_session_data *sd) pc_memo(sd,-1); } /*========================================== - * アイテム合成 + * Client tells server he selected something from a crafting window (e.g. pharmacy) *------------------------------------------*/ void clif_parse_ProduceMix(int fd,struct map_session_data *sd) { - if (sd->menuskill_id != AM_PHARMACY) + if( sd->menuskill_id != -1 && sd->menuskill_id != AM_PHARMACY && sd->menuskill_id != RK_RUNEMASTERY ) return; - if (pc_istrading(sd)) { //Make it fail to avoid shop exploits where you sell something different than you see. clif_skill_fail(sd,sd->ud.skillid,0,0); @@ -10341,7 +10410,7 @@ void clif_parse_Cooking(int fd,struct map_session_data *sd) sd->menuskill_val = sd->menuskill_id = 0; } /*========================================== - * 武器修理 + * Client tells server he selected something in his 'repair item list' *------------------------------------------*/ void clif_parse_RepairItem(int fd, struct map_session_data *sd) { @@ -10446,7 +10515,7 @@ void clif_parse_NpcCloseClicked(int fd,struct map_session_data *sd) } /*========================================== - * アイテム鑑定 + * Client tells server he selected something in his 'magnifier item list' *------------------------------------------*/ void clif_parse_ItemIdentify(int fd,struct map_session_data *sd) { @@ -10463,23 +10532,35 @@ void clif_parse_ItemIdentify(int fd,struct map_session_data *sd) sd->menuskill_val = sd->menuskill_id = 0; } /*========================================== - * 矢作成 + * Client tells server he selected something in his 'arrow crafting list' *------------------------------------------*/ void clif_parse_SelectArrow(int fd,struct map_session_data *sd) { - if (sd->menuskill_id != AC_MAKINGARROW) - return; if (pc_istrading(sd)) { //Make it fail to avoid shop exploits where you sell something different than you see. clif_skill_fail(sd,sd->ud.skillid,0,0); sd->menuskill_val = sd->menuskill_id = 0; return; } - skill_arrow_create(sd,RFIFOW(fd,2)); + switch( sd->menuskill_id ) { + case AC_MAKINGARROW: + skill_arrow_create(sd,RFIFOW(fd,2)); + break; + case WL_READING_SB: + skill_spellbook(sd,RFIFOW(fd,2)); + break; + case GC_POISONINGWEAPON: + skill_poisoningweapon(sd,RFIFOW(fd,2)); + break; + case NC_MAGICDECOY: + skill_magicdecoy(sd,RFIFOW(fd,2)); + break; + } + sd->menuskill_val = sd->menuskill_id = 0; } /*========================================== - * オートスペル受信 + * Client tells server he selected something in his 'autospell skill list' *------------------------------------------*/ void clif_parse_AutoSpell(int fd,struct map_session_data *sd) { @@ -10489,7 +10570,7 @@ void clif_parse_AutoSpell(int fd,struct map_session_data *sd) sd->menuskill_val = sd->menuskill_id = 0; } /*========================================== - * カード使用 + * Client tells server he clicked on a card item, requests the can-add-to list *------------------------------------------*/ void clif_parse_UseCard(int fd,struct map_session_data *sd) { @@ -10498,7 +10579,7 @@ void clif_parse_UseCard(int fd,struct map_session_data *sd) clif_use_card(sd,RFIFOW(fd,2)-2); } /*========================================== - * カード挿入装備選択 + * Client tells server he selected something in his 'carding list' (the one that lists all items you got that can receive that card) *------------------------------------------*/ void clif_parse_InsertCard(int fd,struct map_session_data *sd) { @@ -10508,7 +10589,7 @@ void clif_parse_InsertCard(int fd,struct map_session_data *sd) } /*========================================== - * 0193 キャラID名前引き + * 0193 : Client asks server for nick reference to a specific char id *------------------------------------------*/ void clif_parse_SolveCharName(int fd, struct map_session_data *sd) { @@ -10567,7 +10648,7 @@ void clif_parse_LocalBroadcast(int fd, struct map_session_data* sd) } /*========================================== - * カプラ倉庫へ入れる + * Client tells server to move (item_amount) quantity of item idx (item_index) from inventory to storage *------------------------------------------*/ void clif_parse_MoveToKafra(int fd, struct map_session_data *sd) { @@ -10589,7 +10670,7 @@ void clif_parse_MoveToKafra(int fd, struct map_session_data *sd) } /*========================================== - * カプラ倉庫から出す + * Client tells server to move (item_amount) quantity of item idx (item_index) from storage to inventory *------------------------------------------*/ void clif_parse_MoveFromKafra(int fd,struct map_session_data *sd) { @@ -10606,7 +10687,7 @@ void clif_parse_MoveFromKafra(int fd,struct map_session_data *sd) } /*========================================== - * カプラ倉庫へカートから入れる + * Client tells server to move RFIFOL(fd,4) quantity of item idx RFIFOW(fd,2) from cart to storage *------------------------------------------*/ void clif_parse_MoveToKafraFromCart(int fd, struct map_session_data *sd) { @@ -10623,7 +10704,7 @@ void clif_parse_MoveToKafraFromCart(int fd, struct map_session_data *sd) } /*========================================== - * カプラ倉庫から出す + * Client tells server to move RFIFOL(fd,4) quantity of item idx RFIFOW(fd,2) from storage to cart *------------------------------------------*/ void clif_parse_MoveFromKafraToCart(int fd, struct map_session_data *sd) { @@ -10640,7 +10721,7 @@ void clif_parse_MoveFromKafraToCart(int fd, struct map_session_data *sd) } /*========================================== - * カプラ倉庫を閉じる + * Client tells server to close the kafra *------------------------------------------*/ void clif_parse_CloseKafra(int fd, struct map_session_data *sd) { @@ -10771,7 +10852,7 @@ void clif_parse_ReplyPartyInvite2(int fd,struct map_session_data *sd) } /*========================================== - * パーティ脱退要求 + * Client tells server to remove itself from it's party *------------------------------------------*/ void clif_parse_LeaveParty(int fd, struct map_session_data *sd) { @@ -10784,7 +10865,7 @@ void clif_parse_LeaveParty(int fd, struct map_session_data *sd) } /*========================================== - * パーティ除名要求 + * Client tells server to remove player account id RFIFOL(fd,2) with char name RFIFOP(fd,6) from his party *------------------------------------------*/ void clif_parse_RemovePartyMember(int fd, struct map_session_data *sd) { @@ -10797,7 +10878,11 @@ void clif_parse_RemovePartyMember(int fd, struct map_session_data *sd) } /*========================================== - * パーティ設定変更要求 + * Client tells server to change it's party configuration + * - clients before 20090603 + * -- It only may toggle exp sharing + * - 20090603 or newer + * -- It may toggle exp (RFIFOW(fd,2) and item sharing options (RFIFOB(fd,6) and RFIFOB(fd,7)) *------------------------------------------*/ void clif_parse_PartyChangeOption(int fd, struct map_session_data *sd) { @@ -11251,7 +11336,7 @@ void clif_parse_GuildChangeNotice(int fd, struct map_session_data* sd) } /*========================================== - * ギルド勧誘 + * Client tells server to invite account id RFIFOL(fd,2) to his guild *------------------------------------------*/ void clif_parse_GuildInvite(int fd,struct map_session_data *sd) { @@ -11275,7 +11360,8 @@ void clif_parse_GuildInvite(int fd,struct map_session_data *sd) } /*========================================== - * ギルド勧誘返信 + * Client tells server his reply on the request from guild ID RFIFOL(fd,2), + * - based on RFIFOB(fd,6) which is either 1 (accept) or 0 (reject) *------------------------------------------*/ void clif_parse_GuildReplyInvite(int fd,struct map_session_data *sd) { @@ -11283,7 +11369,7 @@ void clif_parse_GuildReplyInvite(int fd,struct map_session_data *sd) } /*========================================== - * ギルド脱退 + * Client tells server he wants to leave his current guild *------------------------------------------*/ void clif_parse_GuildLeave(int fd,struct map_session_data *sd) { @@ -11351,7 +11437,7 @@ void clif_parse_GuildMessage(int fd, struct map_session_data* sd) } /*========================================== - * ギルド同盟要求 + * Client tells server he'd like to send a alliance request to account id RFIFOL(fd,2) *------------------------------------------*/ void clif_parse_GuildRequestAlliance(int fd, struct map_session_data *sd) { @@ -11378,7 +11464,8 @@ void clif_parse_GuildRequestAlliance(int fd, struct map_session_data *sd) } /*========================================== - * ギルド同盟要求返信 + * Client tells server his response to the alliance request from, + * Guild ID RFIFOL(fd,2) based on RFIFOL(fd,6) which is 1 (accepted) or 0 (rejected) *------------------------------------------*/ void clif_parse_GuildReplyAlliance(int fd, struct map_session_data *sd) { @@ -11386,7 +11473,8 @@ void clif_parse_GuildReplyAlliance(int fd, struct map_session_data *sd) } /*========================================== - * ギルド関係解消 + * Client tells server he'd like to delete alliance from guild ID RFIFOL(fd,2), + * RFIFOL(fd,6) returns a 1 or 0 flag but apparently it is no longer used *------------------------------------------*/ void clif_parse_GuildDelAlliance(int fd, struct map_session_data *sd) { @@ -11402,7 +11490,7 @@ void clif_parse_GuildDelAlliance(int fd, struct map_session_data *sd) } /*========================================== - * ギルド敵対 + * Client tells server he'd like his guild to be set antagonist of account id RFIFOL(fd,2)'s guild *------------------------------------------*/ void clif_parse_GuildOpposition(int fd, struct map_session_data *sd) { @@ -11429,7 +11517,7 @@ void clif_parse_GuildOpposition(int fd, struct map_session_data *sd) } /*========================================== - * ギルド解散 + * Client tells server he'd like to break (delete) his own guild *------------------------------------------*/ void clif_parse_GuildBreak(int fd, struct map_session_data *sd) { @@ -11476,7 +11564,7 @@ void clif_parse_ChangePetName(int fd, struct map_session_data *sd) } /*========================================== - * /kill + * /kill * (or right click menu for GM "(name) force to quit") * S 00cc .L *------------------------------------------*/ @@ -11997,7 +12085,7 @@ void clif_parse_PMIgnoreAll(int fd, struct map_session_data *sd) } /*========================================== - * Wis拒否リスト + * Client tells server he'd like the server to list him his ignore list *------------------------------------------*/ void clif_parse_PMIgnoreList(int fd,struct map_session_data *sd) { @@ -12015,7 +12103,7 @@ void clif_parse_PMIgnoreList(int fd,struct map_session_data *sd) } /*========================================== - * スパノビの/doridoriによるSPR2倍 + * Client tells server he did a /doridori *------------------------------------------*/ void clif_parse_NoviceDoriDori(int fd, struct map_session_data *sd) { @@ -13214,7 +13302,6 @@ void clif_parse_Auction_setitem(int fd, struct map_session_data *sd) clif_Auction_setitem(fd, idx + 2, false); } - /// Result from an auction action (ZC_AUCTION_RESULT) /// 0250 .B /// result: @@ -14329,7 +14416,7 @@ void clif_displayexp(struct map_session_data *sd, unsigned int exp, char type, b /// 0: Displays 'value' for 5 seconds. /// 1: Incremental counter (1 tick/second), negated 'value' specifies start value (e.g. using -10 lets the counter start at 10). /// 2: Decremental counter (1 tick/second), negated 'value' specifies start value (does not stop when reaching 0, but overflows). -/// 3: Decremental counter (2 ticks/second), 'value' specifies start value (stops when reaching 0, displays at most 2 digits). +/// 3: Decremental counter (1 tick/second), 'value' specifies start value (stops when reaching 0, displays at most 2 digits). /// value: /// Except for type 3 it is interpreted as seconds for displaying as DD:HH:MM:SS, HH:MM:SS, MM:SS or SS (leftmost '00' is not displayed). void clif_showdigit(struct map_session_data* sd, unsigned char type, int value) @@ -14886,6 +14973,183 @@ void clif_parse_debug(int fd,struct map_session_data *sd) ShowDump(RFIFOP(fd,0), packet_len); } +/** + * Rune Knight + **/ +void clif_millenniumshield(struct map_session_data *sd, short shields ) { +#if PACKETVER >= 20081217 + unsigned char buf[10]; + + WBUFW(buf,0) = 0x440; + WBUFL(buf,2) = sd->bl.id; + WBUFW(buf,6) = shields; + WBUFW(buf,8) = 0; + clif_send(buf,packet_len(0x440),&sd->bl,AREA); +#endif +} +/** + * Warlock + **/ +/*========================================== + * Spellbook list [LimitLine/3CeAM] + *------------------------------------------*/ +int clif_spellbook_list(struct map_session_data *sd) +{ + int i, c; + int fd; + + nullpo_ret(sd); + + fd = sd->fd; + WFIFOHEAD(fd, 8 * 8 + 8); + WFIFOW(fd,0) = 0x1ad; + + for( i = 0, c = 0; i < MAX_INVENTORY; i ++ ) + { + if( itemdb_is_spellbook(sd->status.inventory[i].nameid) ) + { + WFIFOW(fd, c * 2 + 4) = sd->status.inventory[i].nameid; + c ++; + } + } + + if( c > 0 ) + { + WFIFOW(fd,2) = c * 2 + 4; + WFIFOSET(fd, WFIFOW(fd, 2)); + sd->menuskill_id = WL_READING_SB; + sd->menuskill_val = c; + } + else + status_change_end(&sd->bl,SC_STOP,-1); + + return 1; +} +/** + * Mechanic + **/ +/*========================================== + * Magic Decoy Material List + *------------------------------------------*/ +int clif_magicdecoy_list(struct map_session_data *sd, int skill_lv, short x, short y) { + int i, c; + int fd; + + nullpo_ret(sd); + + fd = sd->fd; + WFIFOHEAD(fd, 8 * 8 + 8); + WFIFOW(fd,0) = 0x1ad; // This is the official packet. [pakpil] + + for( i = 0, c = 0; i < MAX_INVENTORY; i ++ ) { + if( itemdb_is_element(sd->status.inventory[i].nameid) ) { + WFIFOW(fd, c * 2 + 4) = sd->status.inventory[i].nameid; + c ++; + } + } + if( c > 0 ) { + sd->menuskill_id = NC_MAGICDECOY; + sd->menuskill_val = skill_lv; + sd->sc.comet_x = x; + sd->sc.comet_y = y; + WFIFOW(fd,2) = c * 2 + 4; + WFIFOSET(fd, WFIFOW(fd, 2)); + } else { + clif_skill_fail(sd,NC_MAGICDECOY,0,0); + return 0; + } + + return 1; +} +/** + * Guilotine Cross + **/ +/*========================================== + * Guillotine Cross Poisons List + *------------------------------------------*/ +int clif_poison_list(struct map_session_data *sd, int skill_lv) { + int i, c; + int fd; + + nullpo_ret(sd); + + fd = sd->fd; + WFIFOHEAD(fd, 8 * 8 + 8); + WFIFOW(fd,0) = 0x1ad; // This is the official packet. [pakpil] + + for( i = 0, c = 0; i < MAX_INVENTORY; i ++ ) { + if( itemdb_is_poison(sd->status.inventory[i].nameid) ) { + WFIFOW(fd, c * 2 + 4) = sd->status.inventory[i].nameid; + c ++; + } + } + if( c > 0 ) { + sd->menuskill_id = GC_POISONINGWEAPON; + sd->menuskill_val = skill_lv; + WFIFOW(fd,2) = c * 2 + 4; + WFIFOSET(fd, WFIFOW(fd, 2)); + } else { + clif_skill_fail(sd,GC_POISONINGWEAPON,0x2b,0); + return 0; + } + + return 1; +} +/** + * Sends a new status without a tick (currently used by the new mounts) + **/ +int clif_status_load_notick(struct block_list *bl,int type,int flag,int val1, int val2, int val3) { + unsigned char buf[32]; + + nullpo_ret(bl); + + WBUFW(buf,0)=0x043f; + WBUFW(buf,2)=type; + WBUFL(buf,4)=bl->id; + WBUFB(buf,8)=flag; + WBUFL(buf,9) = 0; + WBUFL(buf,13) = val1; + WBUFL(buf,17) = val2; + WBUFL(buf,21) = val3; + + clif_send(buf,packet_len(WBUFW(buf,0)),bl,AREA); + return 0; +} +//Notifies FD of ID's type +int clif_status_load_single(int fd, int id,int type,int flag,int val1, int val2, int val3) { + WFIFOHEAD(fd, packet_len(0x043f)); + WFIFOW(fd,0)=0x043f; + WFIFOW(fd,2)=type; + WFIFOL(fd,4)=id; + WFIFOB(fd,8)=flag; + WFIFOL(fd,9) = 0; + WFIFOL(fd,13) = val1; + WFIFOL(fd,17) = val2; + WFIFOL(fd,21) = val3; + WFIFOSET(fd, packet_len(0x043f)); + return 0; +} +// msgstringtable.txt +// 0x291 .W +void clif_msgtable(int fd, int line) { + WFIFOHEAD(fd, packet_len(0x291)); + WFIFOW(fd, 0) = 0x291; + WFIFOW(fd, 2) = line; + WFIFOSET(fd, packet_len(0x291)); +} + +// msgstringtable.txt +// 0x7e2 .W .L +void clif_msgtable_num(int fd, int line, int num) { +#if PACKETVER >= 20090805 + WFIFOHEAD(fd, packet_len(0x7e2)); + WFIFOW(fd, 0) = 0x7e2; + WFIFOW(fd, 2) = line; + WFIFOL(fd, 4) = num; + WFIFOSET(fd, packet_len(0x7e2)); +#endif +} + /*========================================== * Main client packet processing function *------------------------------------------*/ @@ -15055,7 +15319,7 @@ int clif_parse(int fd) } /*========================================== - * パケットデータベース読み込み + * Reads packet_db.txt and setups its array reference *------------------------------------------*/ static int packetdb_readdb(void) { diff --git a/src/map/clif.h b/src/map/clif.h index 783c8f4a1..8b6271075 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -343,7 +343,7 @@ int clif_skill_estimation(struct map_session_data *sd,struct block_list *dst); void clif_skill_warppoint(struct map_session_data* sd, short skill_num, short skill_lv, unsigned short map1, unsigned short map2, unsigned short map3, unsigned short map4); void clif_skill_memomessage(struct map_session_data* sd, int type); void clif_skill_teleportmessage(struct map_session_data* sd, int type); -int clif_skill_produce_mix_list(struct map_session_data *sd, int trigger); +int clif_skill_produce_mix_list(struct map_session_data *sd, int skillid, int trigger); void clif_cooking_list(struct map_session_data *sd, int trigger); int clif_produceeffect(struct map_session_data* sd,int flag,int nameid); @@ -361,7 +361,7 @@ void clif_bladestop(struct block_list* src, int dst_id, int active); void clif_changemapcell(int fd, int m, int x, int y, int type, enum send_target target); int clif_status_load(struct block_list *bl,int type, int flag); -int clif_status_change(struct block_list *bl,int type,int flag,unsigned int tick); +int clif_status_change(struct block_list *bl,int type,int flag,unsigned int tick,int val1, int val2, int val3); int clif_wis_message(int fd, const char* nick, const char* mes, int mes_len); int clif_wis_end(int fd,int flag); @@ -629,5 +629,29 @@ void clif_search_store_info_ack(struct map_session_data* sd); void clif_search_store_info_failed(struct map_session_data* sd, unsigned char reason); void clif_open_search_store_info(struct map_session_data* sd); void clif_search_store_info_click_ack(struct map_session_data* sd, short x, short y); - +/** + * 3CeAM + **/ +void clif_msgtable(int fd, int line); +void clif_msgtable_num(int fd, int line, int num); +/** + * Rune Knight + **/ +void clif_millenniumshield(struct map_session_data *sd, short shields ); +/** + * Warlock + **/ +int clif_spellbook_list(struct map_session_data *sd); +/** + * Mechanic + **/ +int clif_magicdecoy_list(struct map_session_data *sd, int skill_lv, short x, short y); +/** + * Guilotine Cross + **/ +int clif_poison_list(struct map_session_data *sd, int skill_lv); +/** + * [RRInd] for the new mounts + **/ +int clif_status_load_notick(struct block_list *bl,int type,int flag,int val1, int val2, int val3); #endif /* _CLIF_H_ */ diff --git a/src/map/itemdb.c b/src/map/itemdb.c index d8a8bb2cc..00d4176c5 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -706,7 +706,35 @@ static int itemdb_gendercheck(struct item_data *id) return (battle_config.ignore_items_gender) ? 2 : id->sex; } - +/** + * [RRInd] + * For backwards compatibility, in Renewal mode, MATK from weapons comes from the atk slot + * We use a ':' delimiter which, if not found, assumes the weapon does not provide any matk. + **/ +void itemdb_rr_split_atoi(char *str, int *atk, int *matk) { + int i, val[2]; + + for (i=0; i<2; i++) { + if (!str) break; + val[i] = atoi(str); + str = strchr(str,':'); + if (str) + *str++=0; + } + if( i == 0 ) { + *atk = *matk = 0; + return;//no data found + } + if( i == 1 ) {//Single Value, we assume it's the ATK + *atk = val[0]; + *matk = 0; + return; + } + //We assume we have 2 values. + *atk = val[0]; + *matk = val[1]; + return; +} /*========================================== * processes one itemdb entry *------------------------------------------*/ @@ -736,7 +764,7 @@ static bool itemdb_parse_dbrow(char** str, const char* source, int line, int scr id->type = atoi(str[3]); - if( id->type < 0 || id->type == IT_UNKNOWN || id->type == IT_UNKNOWN2 || ( id->type > IT_DELAYCONSUME && id->type < IT_CASH ) || id->type >= IT_MAX ) + if( id->type < 0 || id->type == IT_UNKNOWN || id->type == IT_UNKNOWN2 || ( id->type > IT_THROWWEAPON && id->type < IT_CASH ) || id->type >= IT_MAX ) {// catch invalid item types ShowWarning("itemdb_parse_dbrow: Invalid item type %d for item %d. IT_ETC will be used.\n", id->type, nameid); id->type = IT_ETC; @@ -773,7 +801,11 @@ static bool itemdb_parse_dbrow(char** str, const char* source, int line, int scr id->value_buy, id->value_sell, nameid, id->jname); id->weight = atoi(str[6]); +#if RRMODE + itemdb_rr_split_atoi(str[7],&id->atk,&id->matk); +#else id->atk = atoi(str[7]); +#endif id->def = atoi(str[8]); id->range = atoi(str[9]); id->slot = atoi(str[10]); @@ -835,7 +867,14 @@ static bool itemdb_parse_dbrow(char** str, const char* source, int line, int scr *------------------------------------------*/ static int itemdb_readdb(void) { - const char* filename[] = { "item_db.txt", "item_db2.txt" }; + /** + * ro-resources inheritance: item_db -> item_db_re -> item_db2 (user customs) + **/ +#if RRMODE + const char* filename[] = { "item_db.txt","item_db_re.txt","item_db2.txt" }; +#else + const char* filename[] = { "item_db.txt","item_db2.txt" }; +#endif int fi; for( fi = 0; fi < ARRAYLENGTH(filename); ++fi ) @@ -947,7 +986,11 @@ static int itemdb_readdb(void) *======================================*/ static int itemdb_read_sqldb(void) { +#if RRMODE + const char* item_db_name[] = { item_db_db, item_db_re_db, item_db2_db }; +#else const char* item_db_name[] = { item_db_db, item_db2_db }; +#endif int fi; for( fi = 0; fi < ARRAYLENGTH(item_db_name); ++fi ) diff --git a/src/map/itemdb.h b/src/map/itemdb.h index 5b54acd67..801b81be8 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -5,6 +5,7 @@ #define _ITEMDB_H_ #include "../common/mmo.h" // ITEM_NAME_LENGTH +#include "map.h" //RRMODE #define MAX_RANDITEM 11000 @@ -13,6 +14,11 @@ #define MAX_SEARCH 5 //Designed for search functions, species max number of matches to display. +/** + * Arch Bishop + **/ +#define ITEMID_ANCILLA 12333 + #define ITEMID_YELLOW_GEMSTONE 715 #define ITEMID_RED_GEMSTONE 716 #define ITEMID_BLUE_GEMSTONE 717 @@ -50,6 +56,9 @@ struct item_data { int equip; int weight; int atk; +#if RRMODE + int matk;//[RRInd] -- used in RE for matk +#endif int def; int range; int slot; @@ -61,7 +70,7 @@ struct item_data { //Lupus: I rearranged order of these fields due to compatibility with ITEMINFO script command // some script commands should be revised as well... unsigned int class_base[3]; //Specifies if the base can wear this item (split in 3 indexes per type: 1-1, 2-1, 2-2) - unsigned class_upper : 3; //Specifies if the upper-type can equip it (bitfield, 1: normal, 2: upper, 3: baby) + unsigned class_upper : 4; //Specifies if the upper-type can equip it (bitfield, 1: normal, 2: upper, 3: baby,4:third) struct { unsigned short chance; int id; @@ -143,4 +152,35 @@ void itemdb_reload(void); void do_final_itemdb(void); int do_init_itemdb(void); +/** + * Rune Knight + **/ +enum { + ITEMID_NAUTHIZ = 12725, + ITEMID_RAIDO, + ITEMID_BERKANA, + ITEMID_ISA, + ITEMID_OTHILA, + ITEMID_URUZ, + ITEMID_THURISAZ, + ITEMID_WYRD, + ITEMID_HAGALAZ, +} rune_list; +#define itemdb_is_rune(n) (n >= ITEMID_NAUTHIZ && n <= ITEMID_HAGALAZ) +/** + * Warlock + **/ +#define itemdb_is_spellbook(n) (n >= 6188 && n <= 6205) +/** + * Ranger + **/ +#define ITEMID_TRAP_ALLOY 7940 +/** + * Mechanic + **/ +#define itemdb_is_element(n) (n >= 990 && n <= 993) +/** + * Guilotine Cross + **/ +#define itemdb_is_poison(n) (n >= 12717 && n <= 12724) #endif /* _ITEMDB_H_ */ diff --git a/src/map/map.c b/src/map/map.c index 39077de6c..9155a11f3 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -68,6 +68,7 @@ Sql* mmysql_handle; int db_use_sqldbs = 0; char item_db_db[32] = "item_db"; char item_db2_db[32] = "item_db2"; +char item_db_re_db[32] = "item_db_re"; char mob_db_db[32] = "mob_db"; char mob_db2_db[32] = "mob_db2"; @@ -3204,6 +3205,9 @@ int map_config_read(char *cfgName) else if (strcmpi(w1, "import") == 0) map_config_read(w2); + else + if (strcmpi(w1, "console_msg_log") == 0) + console_msg_log = atoi(w2);//[Ind] else ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName); } @@ -3526,41 +3530,39 @@ void do_abort(void) /*====================================================== * Map-Server Version Screen [MC Cameri] *------------------------------------------------------*/ -void map_helpscreen(int flag) -{ - puts("Usage: map-server [options]"); - puts("Options:"); - puts(CL_WHITE" Commands\t\t\tDescription"CL_RESET); - puts("-----------------------------------------------------------------------------"); - puts(" --help, --h, --?, /? Displays this help screen"); - puts(" --map-config Load map-server configuration from "); - puts(" --battle-config Load battle configuration from "); - puts(" --atcommand-config Load atcommand configuration from "); - puts(" --script-config Load script configuration from "); - puts(" --msg-config Load message configuration from "); - puts(" --grf-path-file Load grf path file configuration from "); - puts(" --sql-config Load inter-server configuration from "); - puts(" (SQL Only)"); - puts(" --log-config Load logging configuration from "); - puts(" (SQL Only)"); - puts(" --version, --v, -v, /v Displays the server's version"); - puts("\n"); - if (flag) exit(EXIT_FAILURE); +static void map_helpscreen(bool do_exit) +{ + ShowInfo("Usage: %s [options]\n", SERVER_NAME); + ShowInfo("\n"); + ShowInfo("Options:\n"); + ShowInfo(" -?, -h [--help]\t\tDisplays this help screen.\n"); + ShowInfo(" -v [--version]\t\tDisplays the server's version.\n"); + ShowInfo(" --run-once\t\t\tCloses server after loading (testing).\n"); + ShowInfo(" --map-config \t\tAlternative map-server configuration.\n"); + ShowInfo(" --battle-config \tAlternative battle configuration.\n"); + ShowInfo(" --atcommand-config \tAlternative atcommand configuration.\n"); + ShowInfo(" --script-config \tAlternative script configuration.\n"); + ShowInfo(" --msg-config \t\tAlternative message configuration.\n"); + ShowInfo(" --grf-path \t\tAlternative GRF path configuration.\n"); + ShowInfo(" --inter-config \t\tAlternative inter-server configuration.\n"); + ShowInfo(" --log-config \t\tAlternative logging configuration.\n"); + if( do_exit ) + exit(EXIT_SUCCESS); } /*====================================================== * Map-Server Version Screen [MC Cameri] *------------------------------------------------------*/ -void map_versionscreen(int flag) +static void map_versionscreen(bool do_exit) { - ShowInfo(CL_WHITE "eAthena version %d.%02d.%02d, Athena Mod version %d" CL_RESET"\n", - ATHENA_MAJOR_VERSION, ATHENA_MINOR_VERSION, ATHENA_REVISION, - ATHENA_MOD_VERSION); - ShowInfo(CL_GREEN "Website/Forum:" CL_RESET "\thttp://eathena.deltaanime.net/\n"); - ShowInfo(CL_GREEN "IRC Channel:" CL_RESET "\tirc://irc.deltaanime.net/#athena\n"); - ShowInfo("\nOpen " CL_WHITE "readme.html" CL_RESET " for more information."); - if (ATHENA_RELEASE_FLAG) ShowNotice("This version is not for release.\n"); - if (flag) exit(EXIT_FAILURE); + ShowInfo(CL_WHITE"eAthena version %d.%02d.%02d, Athena Mod version %d" CL_RESET"\n", ATHENA_MAJOR_VERSION, ATHENA_MINOR_VERSION, ATHENA_REVISION, ATHENA_MOD_VERSION); + ShowInfo(CL_GREEN"Website/Forum:"CL_RESET"\thttp://eathena.ws/\n"); + ShowInfo(CL_GREEN"IRC Channel:"CL_RESET"\tirc://irc.deltaanime.net/#athena\n"); + ShowInfo("Open "CL_WHITE"readme.html"CL_RESET" for more information.\n"); + if(ATHENA_RELEASE_FLAG) + ShowNotice("This version is not for release.\n"); + if( do_exit ) + exit(EXIT_SUCCESS); } /*====================================================== @@ -3591,6 +3593,16 @@ void do_shutdown(void) } } +static bool map_arg_next_value(const char* option, int i, int argc) +{ + if( i >= argc-1 ) + { + ShowWarning("Missing value for option '%s'.\n", option); + return false; + } + + return true; +} int do_init(int argc, char *argv[]) { @@ -3611,31 +3623,67 @@ int do_init(int argc, char *argv[]) srand(gettick()); - for (i = 1; i < argc ; i++) { - if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "--h") == 0 || strcmp(argv[i], "--?") == 0 || strcmp(argv[i], "/?") == 0) - map_helpscreen(1); - else if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "--v") == 0 || strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "/v") == 0) - map_versionscreen(1); - else if (strcmp(argv[i], "--map_config") == 0 || strcmp(argv[i], "--map-config") == 0) - MAP_CONF_NAME=argv[i+1]; - else if (strcmp(argv[i],"--battle_config") == 0 || strcmp(argv[i],"--battle-config") == 0) - BATTLE_CONF_FILENAME = argv[i+1]; - else if (strcmp(argv[i],"--atcommand_config") == 0 || strcmp(argv[i],"--atcommand-config") == 0) - ATCOMMAND_CONF_FILENAME = argv[i+1]; - else if (strcmp(argv[i],"--script_config") == 0 || strcmp(argv[i],"--script-config") == 0) - SCRIPT_CONF_NAME = argv[i+1]; - else if (strcmp(argv[i],"--msg_config") == 0 || strcmp(argv[i],"--msg-config") == 0) - MSG_CONF_NAME = argv[i+1]; - else if (strcmp(argv[i],"--grf_path_file") == 0 || strcmp(argv[i],"--grf-path-file") == 0) - GRF_PATH_FILENAME = argv[i+1]; -#ifndef TXT_ONLY - else if (strcmp(argv[i],"--inter_config") == 0 || strcmp(argv[i],"--inter-config") == 0) - INTER_CONF_NAME = argv[i+1]; -#endif - else if (strcmp(argv[i],"--log_config") == 0 || strcmp(argv[i],"--log-config") == 0) - LOG_CONF_NAME = argv[i+1]; - else if (strcmp(argv[i],"--run_once") == 0) // close the map-server as soon as its done.. for testing [Celest] - runflag = 0; + for( i = 1; i < argc ; i++ ) + { + const char* arg = argv[i]; + + if( arg[0] != '-' && ( arg[0] != '/' || arg[1] == '-' ) ) + {// -, -- and / + ShowError("Unknown option '%s'.\n", argv[i]); + exit(EXIT_FAILURE); + } + else if( (++arg)[0] == '-' ) + {// long option + arg++; + + if( strcmp(arg, "help") == 0 ) + map_helpscreen(true); + else if( strcmp(arg, "version") == 0 ) + map_versionscreen(true); + else if( strcmp(arg, "map-config") == 0 ) { + if( map_arg_next_value(arg, i, argc) ) + MAP_CONF_NAME = argv[++i]; + } else if( strcmp(arg, "battle-config") == 0 ) { + if( map_arg_next_value(arg, i, argc) ) + BATTLE_CONF_FILENAME = argv[++i]; + } else if( strcmp(arg, "atcommand-config") == 0 ) { + if( map_arg_next_value(arg, i, argc) ) + ATCOMMAND_CONF_FILENAME = argv[++i]; + } else if( strcmp(arg, "script-config") == 0 ) { + if( map_arg_next_value(arg, i, argc) ) + SCRIPT_CONF_NAME = argv[++i]; + } else if( strcmp(arg, "msg-config") == 0 ) { + if( map_arg_next_value(arg, i, argc) ) + MSG_CONF_NAME = argv[++i]; + } else if( strcmp(arg, "grf-path-file") == 0 ) { + if( map_arg_next_value(arg, i, argc) ) + GRF_PATH_FILENAME = argv[++i]; + } else if( strcmp(arg, "inter-config") == 0 ) { + if( map_arg_next_value(arg, i, argc) ) + INTER_CONF_NAME = argv[++i]; + } else if( strcmp(arg, "log-config") == 0 ) { + if( map_arg_next_value(arg, i, argc) ) + LOG_CONF_NAME = argv[++i]; + } else if( strcmp(arg, "run-once") == 0 ) // close the map-server as soon as its done.. for testing [Celest] + runflag = CORE_ST_STOP; + else { + ShowError("Unknown option '%s'.\n", argv[i]); + exit(EXIT_FAILURE); + } + } + else switch( arg[0] ) + {// short option + case '?': + case 'h': + map_helpscreen(true); + break; + case 'v': + map_versionscreen(true); + break; + default: + ShowError("Unknown option '%s'.\n", argv[i]); + exit(EXIT_FAILURE); + } } map_config_read(MAP_CONF_NAME); diff --git a/src/map/map.h b/src/map/map.h index 8e4507599..18f5f3928 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -10,6 +10,11 @@ #include "../common/mapindex.h" #include "../common/db.h" +/** + * [ro-resources.net] + **/ +#include "./RRConfig/Core.h" + #include struct npc_data; @@ -46,7 +51,7 @@ enum E_MAPSERVER_ST #define NATURAL_HEAL_INTERVAL 500 #define MIN_FLOORITEM 2 #define MAX_FLOORITEM START_ACCOUNT_NUM -#define MAX_LEVEL 99 +#define MAX_LEVEL 150 #define MAX_DROP_PER_MAP 48 #define MAX_IGNORE_LIST 20 // official is 14 #define MAX_VENDING 12 @@ -68,10 +73,12 @@ enum E_MAPSERVER_ST #define JOBL_UPPER 0x1000 //4096 #define JOBL_BABY 0x2000 //8192 +#define JOBL_THIRD 0x4000 //16384 //for filtering and quick checking. #define MAPID_UPPERMASK 0x0fff #define MAPID_BASEMASK 0x00ff +#define MAPID_THIRDMASK (JOBL_THIRD|MAPID_UPPERMASK) //First Jobs //Note the oddity of the novice: //Super Novices are considered the 2-1 version of the novice! Novices are considered a first class type, too... @@ -154,6 +161,31 @@ enum { MAPID_BABY_ALCHEMIST, MAPID_BABY_ROGUE, MAPID_BABY_SOUL_LINKER, + MAPID_RUNE_KNIGHT = JOBL_THIRD|JOBL_2_1|0x1, + MAPID_WARLOCK, + MAPID_RANGER, + MAPID_ARCH_BISHOP, + MAPID_MECHANIC, + MAPID_GUILLOTINE_CROSS, + MAPID_ROYAL_GUARD = JOBL_THIRD|JOBL_2_2|0x1, + MAPID_SORCERER, + MAPID_MINSTRELWANDERER, + MAPID_SURA, + MAPID_GENETIC, + MAPID_SHADOW_CHASER, + MAPID_RUNE_KNIGHT_T = JOBL_THIRD|JOBL_UPPER|JOBL_2_1|0x1, + MAPID_WARLOCK_T, + MAPID_RANGER_T, + MAPID_ARCH_BISHOP_T, + MAPID_MECHANIC_T, + MAPID_GUILLOTINE_CROSS_T, + MAPID_ROYAL_GUARD_T = JOBL_THIRD|JOBL_UPPER|JOBL_2_2|0x1, + MAPID_SORCERER_T, + MAPID_MINSTRELWANDERER_T, + MAPID_SURA_T, + MAPID_GENETIC_T, + MAPID_SHADOW_CHASER_T, + }; //Max size for inputs to Graffiti, Talkie Box and Vending text prompts @@ -476,7 +508,10 @@ struct map_data { unsigned fireworks : 1; unsigned sakura : 1; // [Valaris] unsigned leaves : 1; // [Valaris] - unsigned rain : 1; // [Valaris] + /** + * No longer available, keeping here just in case it's back someday. [Ind] + **/ + //unsigned rain : 1; // [Valaris] unsigned nogo : 1; // [Valaris] unsigned nobaseexp : 1; // [Lorky] added by Lupus unsigned nojobexp : 1; // [Lorky] @@ -643,7 +678,6 @@ int map_random_dir(struct block_list *bl, short *x, short *y); // [Skotlex] int cleanup_sub(struct block_list *bl, va_list ap); -void map_helpscreen(int flag); // [Valaris] int map_delmap(char* mapname); void map_flags_init(void); @@ -667,8 +701,6 @@ extern char *SCRIPT_CONF_NAME; extern char *MSG_CONF_NAME; extern char *GRF_PATH_FILENAME; -extern char *map_server_dns; - //Useful typedefs from jA [Skotlex] typedef struct map_session_data TBL_PC; typedef struct npc_data TBL_NPC; @@ -697,6 +729,7 @@ extern Sql* logmysql_handle; extern char item_db_db[32]; extern char item_db2_db[32]; +extern char item_db_re_db[32]; extern char mob_db_db[32]; extern char mob_db2_db[32]; diff --git a/src/map/mob.c b/src/map/mob.c index 5272b17e8..8181fb5e7 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -2163,8 +2163,12 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) merc_hom_gainexp(tmpsd[i]->hd, base_exp); if(base_exp || job_exp) { - if( md->dmglog[i].flag != MDLF_PET || battle_config.pet_attack_exp_to_master ) + if( md->dmglog[i].flag != MDLF_PET || battle_config.pet_attack_exp_to_master ) { +#if RRMODE + party_renewal_exp_mod(&base_exp,&job_exp,tmpsd[i]->status.base_level,md->level); +#endif pc_gainexp(tmpsd[i], &md->bl, base_exp, job_exp, false); + } } if(zeny) // zeny from mobs [Valaris] pc_getzeny(tmpsd[i], zeny); @@ -2185,6 +2189,11 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) struct item_drop_list *dlist = ers_alloc(item_drop_list_ers, struct item_drop_list); struct item_drop *ditem; int drop_rate; +#if RRMODE + int drop_modifier = mvp_sd ? party_renewal_drop_mod(mvp_sd->status.base_level - md->level) : + second_sd ? party_renewal_drop_mod(second_sd->status.base_level - md->level) : + third_sd ? party_renewal_drop_mod(third_sd->status.base_level - md->level) : 100; +#endif dlist->m = md->bl.m; dlist->x = md->bl.x; dlist->y = md->bl.y; @@ -2226,7 +2235,10 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) // Increase drop rate if user has SC_ITEMBOOST if (sd && sd->sc.data[SC_ITEMBOOST]) // now rig the drop rate to never be over 90% unless it is originally >90%. drop_rate = max(drop_rate,cap_value((int)(0.5+drop_rate*(sd->sc.data[SC_ITEMBOOST]->val1)/100.),0,9000)); - +#if RRMODE + if( drop_modifier != 100 ) + drop_rate = drop_rate * drop_modifier / 100; +#endif // attempt to drop the item if (rand() % 10000 >= drop_rate) continue; @@ -2437,8 +2449,11 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) delete_timer(md->deletetimer,mob_timer_delete); md->deletetimer = INVALID_TIMER; } - - mob_deleteslave(md); + /** + * Only loops if necessary (e.g. a poring would never need to loop) + **/ + if( md->can_summon ) + mob_deleteslave(md); map_freeblock_unlock(); @@ -2700,6 +2715,10 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,int skill_id) if(mobdb_checkid(value[0]) == 0) return 0; + /** + * Flags this monster is able to summon; saves a worth amount of memory upon deletion + **/ + md2->can_summon = 1; while(count < 5 && mobdb_checkid(value[count])) count++; if(count < 1) return 0; diff --git a/src/map/mob.h b/src/map/mob.h index 9e86b8d63..2c6d882c9 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -161,6 +161,11 @@ struct mob_data { short skillidx; unsigned int skilldelay[MAX_MOBSKILL]; char npc_event[EVENT_NAME_LENGTH]; + /** + * Did this monster summon something? + * Used to flag summon deletions, saves a worth amount of memory + **/ + bool can_summon : 1; }; diff --git a/src/map/npc.c b/src/map/npc.c index dae395876..1762bc73b 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -199,7 +199,33 @@ struct npc_data* npc_name2id(const char* name) { return (struct npc_data *) strdb_get(npcname_db, name); } - +/** + * For the Secure NPC Timeout option (check RRConfig/Secure.h) [RR] + **/ +#if SECURE_NPCTIMEOUT +/** + * Timer to check for idle time and timeout the dialog if necessary + **/ +int npc_rr_secure_timeout_timer(int tid, unsigned int tick, int id, intptr_t data) { + struct map_session_data* sd = NULL; + if( (sd = map_id2sd(id)) == NULL || !sd->npc_id ) + return 0;//Not logged in anymore OR no longer attached to a npc + + if( DIFF_TICK(tick,sd->npc_idle_tick) > (SECURE_NPCTIMEOUT*1000) ) { + /** + * If we still have the NPC script attached, tell it to stop. + **/ + if( sd->st ) + sd->st->state = END; + /** + * This guy's been idle for longer than allowed, close him. + **/ + clif_scriptclose(sd,sd->npc_id); + } else //Create a new instance of ourselves to continue + sd->npc_idle_timer = add_timer(gettick() + (SECURE_NPCTIMEOUT_INTERVAL*1000),npc_rr_secure_timeout_timer,sd->bl.id,0); + return 0; +} +#endif /*========================================== * イベントキューのイベント処理 *------------------------------------------*/ @@ -1114,6 +1140,15 @@ int npc_scriptcont(struct map_session_data* sd, int id) return 1; } } + /** + * For the Secure NPC Timeout option (check RRConfig/Secure.h) [RR] + **/ +#if SECURE_NPCTIMEOUT + /** + * Update the last NPC iteration + **/ + sd->npc_idle_tick = gettick(); +#endif run_script_main(sd->st); return 0; @@ -3058,8 +3093,11 @@ static const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, con map[m].flag.sakura=state; else if (!strcmpi(w3,"leaves")) map[m].flag.leaves=state; - else if (!strcmpi(w3,"rain")) - map[m].flag.rain=state; + /** + * No longer available, keeping here just in case it's back someday. [Ind] + **/ + //else if (!strcmpi(w3,"rain")) + // map[m].flag.rain=state; else if (!strcmpi(w3,"nightenabled")) map[m].flag.nightenabled=state; else if (!strcmpi(w3,"nogo")) diff --git a/src/map/npc.h b/src/map/npc.h index d40fb63b4..8f8d7eca9 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -157,4 +157,11 @@ int npc_cashshop_buy(struct map_session_data *sd, int nameid, int amount, int po extern struct npc_data* fake_nd; +/** + * For the Secure NPC Timeout option (check RRConfig/Secure.h) [RR] + **/ +#if SECURE_NPCTIMEOUT +int npc_rr_secure_timeout_timer(int tid, unsigned int tick, int id, intptr_t data); +#endif + #endif /* _NPC_H_ */ diff --git a/src/map/party.c b/src/map/party.c index 9649505b4..f47f8e5c9 100644 --- a/src/map/party.c +++ b/src/map/party.c @@ -566,7 +566,7 @@ int party_member_withdraw(int party_id, int account_id, int char_id) ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == account_id && p->party.member[i].char_id == char_id ); if( i < MAX_PARTY ) { - clif_party_withdraw(p,sd,account_id,p->party.member[i].name,0x00); + clif_party_withdraw(p,sd,account_id,p->party.member[i].name,0x0); memset(&p->party.member[i], 0, sizeof(p->party.member[0])); memset(&p->data[i], 0, sizeof(p->data[0])); p->party.count--; @@ -912,13 +912,64 @@ int party_send_xy_clear(struct party_data *p) } return 0; } - +#if RRMODE +/** + * Renewal Drop Earning Modifier + **/ +int party_renewal_drop_mod(int diff) { + if( diff >= -10 && diff <= 5 ) + return 100;//no change. + if( diff > 0 ) { + if( diff > 5 && diff < 10 ) + return 90; + if( diff > 9 && diff < 15 ) + return 75; + if( diff > 14 && diff < 30 ) + return 60; + } else { + if( diff <= -10 && diff <= -14 ) + return 75;//75% + } + //other chases: 50% + return 50; +} +/** + * Renewal Experience Earning Mode + **/ +void party_renewal_exp_mod(unsigned int *base_exp, unsigned int *job_exp, int lvl, int moblvl) { + int diff = lvl - moblvl, boost = 0; + //-2 ~ +5: 100% + if( diff >= -2 && diff <= 5 ) + return;//we don't change anything, it's 100% boost + //-3 ~ -10: +5% boost for each + if( diff >= -10 && diff <= -3 ) + boost = 100 + (( -diff * 5 ) - 15 ); + // 40% boost if difference is <= -10 + else if ( diff <= -10 ) + boost = 40; + else { + boost = ( diff > 5 && diff < 11 ) ? 95 : + ( diff > 10 && diff < 16 ) ? 90 : + ( diff > 15 && diff < 21 ) ? 85 : + ( diff > 20 && diff < 26 ) ? 60 : + ( diff > 25 && diff < 31 ) ? 35 : + 10; + } + if( *base_exp ) + *base_exp = (unsigned int)cap_value(*base_exp * boost / 100, 1, UINT_MAX); + if( *job_exp ) + *job_exp = (unsigned int)cap_value(*job_exp * boost / 100, 1, UINT_MAX); + return; +} +#endif // exp share and added zeny share [Valaris] int party_exp_share(struct party_data* p, struct block_list* src, unsigned int base_exp, unsigned int job_exp, int zeny) { struct map_session_data* sd[MAX_PARTY]; unsigned int i, c; - +#if RRMODE + int src_lvl = status_get_lv(src); +#endif nullpo_ret(p); // count the number of players eligible for exp sharing @@ -945,8 +996,10 @@ int party_exp_share(struct party_data* p, struct block_list* src, unsigned int b zeny = (unsigned int) cap_value(zeny * bonus/100, INT_MIN, INT_MAX); } - for (i = 0; i < c; i++) - { + for (i = 0; i < c; i++) { +#if RRMODE + party_renewal_exp_mod(&base_exp,&job_exp,sd[i]->status.base_level,src_lvl); +#endif pc_gainexp(sd[i], src, base_exp, job_exp, false); if (zeny) // zeny from mobs [Valaris] pc_getzeny(sd[i],zeny); diff --git a/src/map/party.h b/src/map/party.h index 9fde5a6a4..4918d9a3a 100644 --- a/src/map/party.h +++ b/src/map/party.h @@ -92,4 +92,9 @@ void party_booking_update(struct map_session_data *sd, short* job); void party_booking_search(struct map_session_data *sd, short level, short mapid, short job, unsigned long lastindex, short resultcount); bool party_booking_delete(struct map_session_data *sd); +#if RRMODE +void party_renewal_exp_mod(unsigned int *base_exp, unsigned int *job_exp, int lvl, int moblvl); +int party_renewal_drop_mod(int diff); +#endif + #endif /* _PARTY_H_ */ diff --git a/src/map/pc.c b/src/map/pc.c index b93334f35..6a6c24398 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -395,7 +395,7 @@ int pc_makesavestatus(struct map_session_data *sd) //Only copy the Cart/Peco/Falcon options, the rest are handled via //status change load/saving. [Skotlex] - sd->status.option = sd->sc.option&(OPTION_CART|OPTION_FALCON|OPTION_RIDING); + sd->status.option = sd->sc.option&(OPTION_CART|OPTION_FALCON|OPTION_RIDING|OPTION_DRAGON|OPTION_WUGRIDER|OPTION_WUG|OPTION_MADOGEAR|OPTION_MOUNTING); if (sd->sc.data[SC_JAILED]) { //When Jailed, do not move last point. @@ -765,10 +765,14 @@ int pc_isequip(struct map_session_data *sd,int n) //Not equipable by class. [Skotlex] if (!(1<<(sd->class_&MAPID_BASEMASK)&item->class_base[(sd->class_&JOBL_2_1)?1:((sd->class_&JOBL_2_2)?2:0)])) return 0; - - //Not equipable by upper class. [Skotlex] - if(!(1<<((sd->class_&JOBL_UPPER)?1:((sd->class_&JOBL_BABY)?2:0))&item->class_upper)) + //Not usable by upper class. [Inkfish] + while( 1 ) { + if( item->class_upper&1 && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break; + if( item->class_upper&2 && sd->class_&(JOBL_UPPER|JOBL_THIRD) ) break; + if( item->class_upper&4 && sd->class_&JOBL_BABY ) break; + if( item->class_upper&8 && sd->class_&JOBL_THIRD ) break; return 0; + } return 1; } @@ -825,7 +829,17 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim sd->invincible_timer = INVALID_TIMER; sd->npc_timer_id = INVALID_TIMER; sd->pvp_timer = INVALID_TIMER; - + /** + * For the Secure NPC Timeout option (check RRConfig/Secure.h) [RR] + **/ +#if SECURE_NPCTIMEOUT + /** + * Initialize to defaults/expected + **/ + sd->npc_idle_timer = INVALID_TIMER; + sd->npc_idle_tick = tick; +#endif + sd->canuseitem_tick = tick; sd->canusecashfood_tick = tick; sd->canequip_tick = tick; @@ -915,7 +929,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim if (battle_config.display_version == 1){ char buf[256]; - sprintf(buf, "eAthena SVN version: %s", get_svn_revision()); + sprintf(buf, "SVN version: %s", get_svn_revision()); clif_displaymessage(sd->fd, buf); } @@ -3379,7 +3393,15 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount) w = data->weight*amount; if(sd->weight + w > sd->max_weight) return 2; - + if( itemdb_is_rune(item_data->nameid) ) { + int rune = pc_search_inventory(sd,item_data->nameid); + if( ( rune >= 0 && sd->status.inventory[rune].amount + amount > MAX_RUNE ) || + ( rune == -1 && amount > MAX_RUNE ) + ) { + clif_msgtable(sd->fd,0x61b); + return 1; + } + } i = MAX_INVENTORY; if( itemdb_isstackable2(data) && item_data->expire_time == 0 ) @@ -3662,6 +3684,17 @@ int pc_isUseitem(struct map_session_data *sd,int n) if( nameid >= 12153 && nameid <= 12182 && sd->md != NULL ) return 0; // Mercenary Scrolls + /** + * Only Rune Knights may use runes + **/ + if( itemdb_is_rune(nameid) && (sd->class_&MAPID_THIRDMASK) != MAPID_RUNE_KNIGHT ) + return 0; + /** + * Only GCross may use poisons + **/ + else if( itemdb_is_poison(nameid) && (sd->class_&MAPID_THIRDMASK) != MAPID_GUILLOTINE_CROSS ) + return 0; + //added item_noequip.txt items check by Maya&[Lupus] if ( (!map_flag_vs(sd->bl.m) && item->flag.no_equip&1) || // Normal @@ -3685,13 +3718,14 @@ int pc_isUseitem(struct map_session_data *sd,int n) (item->class_base[sd->class_&JOBL_2_1?1:(sd->class_&JOBL_2_2?2:0)]) )) return 0; - - //Not usable by upper class. [Skotlex] - if(!( - (1<<(sd->class_&JOBL_UPPER?1:(sd->class_&JOBL_BABY?2:0))) & - item->class_upper - )) + //Not usable by upper class. [Inkfish] + while( 1 ) { + if( item->class_upper&1 && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break; + if( item->class_upper&2 && sd->class_&(JOBL_UPPER|JOBL_THIRD) ) break; + if( item->class_upper&4 && sd->class_&JOBL_BABY ) break; + if( item->class_upper&8 && sd->class_&JOBL_THIRD ) break; return 0; + } //Dead Branch & Bloody Branch & Porings Box if((log_config.branch > 0) && (nameid == 604 || nameid == 12103 || nameid == 12109)) @@ -4534,6 +4568,36 @@ int pc_jobid2mapid(unsigned short b_class) case JOB_BABY_MONK: return MAPID_BABY_MONK; case JOB_BABY_ALCHEMIST: return MAPID_BABY_ALCHEMIST; case JOB_BABY_ROGUE: return MAPID_BABY_ROGUE; + //3.1 non-trans + case JOB_RUNE_KNIGHT: return MAPID_RUNE_KNIGHT; + case JOB_WARLOCK: return MAPID_WARLOCK; + case JOB_RANGER: return MAPID_RANGER; + case JOB_ARCH_BISHOP: return MAPID_ARCH_BISHOP; + case JOB_MECHANIC: return MAPID_MECHANIC; + case JOB_GUILLOTINE_CROSS: return MAPID_GUILLOTINE_CROSS; + //3.1 trans + case JOB_RUNE_KNIGHT_T: return MAPID_RUNE_KNIGHT_T; + case JOB_WARLOCK_T: return MAPID_WARLOCK_T; + case JOB_RANGER_T: return MAPID_RANGER_T; + case JOB_ARCH_BISHOP_T: return MAPID_ARCH_BISHOP_T; + case JOB_MECHANIC_T: return MAPID_MECHANIC_T; + case JOB_GUILLOTINE_CROSS_T:return MAPID_GUILLOTINE_CROSS_T; + //3.2 non-trans + case JOB_ROYAL_GUARD: return MAPID_ROYAL_GUARD; + case JOB_SORCERER: return MAPID_SORCERER; + case JOB_MINSTREL: return MAPID_MINSTRELWANDERER; + case JOB_WANDERER: return MAPID_MINSTRELWANDERER; + case JOB_SURA: return MAPID_SURA; + case JOB_GENETIC: return MAPID_GENETIC; + case JOB_SHADOW_CHASER: return MAPID_SHADOW_CHASER; + //3.2 trans + case JOB_ROYAL_GUARD_T: return MAPID_ROYAL_GUARD_T; + case JOB_SORCERER_T: return MAPID_SORCERER_T; + case JOB_MINSTREL_T: return MAPID_MINSTRELWANDERER_T; + case JOB_WANDERER_T: return MAPID_MINSTRELWANDERER_T; + case JOB_SURA_T: return MAPID_SURA_T; + case JOB_GENETIC_T: return MAPID_GENETIC_T; + case JOB_SHADOW_CHASER_T: return MAPID_SHADOW_CHASER_T; default: return -1; } @@ -4620,6 +4684,34 @@ int pc_mapid2jobid(unsigned short class_, int sex) case MAPID_BABY_MONK: return JOB_BABY_MONK; case MAPID_BABY_ALCHEMIST: return JOB_BABY_ALCHEMIST; case MAPID_BABY_ROGUE: return JOB_BABY_ROGUE; + //3.1 non-trans + case MAPID_RUNE_KNIGHT: return JOB_RUNE_KNIGHT; + case MAPID_WARLOCK: return JOB_WARLOCK; + case MAPID_RANGER: return JOB_RANGER; + case MAPID_ARCH_BISHOP: return JOB_ARCH_BISHOP; + case MAPID_MECHANIC: return JOB_MECHANIC; + case MAPID_GUILLOTINE_CROSS:return JOB_GUILLOTINE_CROSS; + //3.1 trans + case MAPID_RUNE_KNIGHT_T: return JOB_RUNE_KNIGHT_T; + case MAPID_WARLOCK_T: return JOB_WARLOCK_T; + case MAPID_RANGER_T: return JOB_RANGER_T; + case MAPID_ARCH_BISHOP_T: return JOB_ARCH_BISHOP_T; + case MAPID_MECHANIC_T: return JOB_MECHANIC_T; + case MAPID_GUILLOTINE_CROSS_T:return JOB_GUILLOTINE_CROSS_T; + //3.2 non-trans + case MAPID_ROYAL_GUARD: return JOB_ROYAL_GUARD; + case MAPID_SORCERER: return JOB_SORCERER; + case MAPID_MINSTRELWANDERER:return sex?JOB_MINSTREL:JOB_WANDERER; + case MAPID_SURA: return JOB_SURA; + case MAPID_GENETIC: return JOB_GENETIC; + case MAPID_SHADOW_CHASER: return JOB_SHADOW_CHASER; + //3.2 trans + case MAPID_ROYAL_GUARD_T: return JOB_ROYAL_GUARD_T; + case MAPID_SORCERER_T: return JOB_SORCERER_T; + case MAPID_MINSTRELWANDERER_T:return sex?JOB_MINSTREL_T:JOB_WANDERER_T; + case MAPID_SURA_T: return JOB_SURA_T; + case MAPID_GENETIC_T: return JOB_GENETIC_T; + case MAPID_SHADOW_CHASER_T: return JOB_SHADOW_CHASER_T; default: return -1; } @@ -4898,7 +4990,7 @@ int pc_checkjoblevelup(struct map_session_data *sd) status_calc_pc(sd,0); clif_misceffect(&sd->bl,1); if (pc_checkskill(sd, SG_DEVIL) && !pc_nextjobexp(sd)) - clif_status_change(&sd->bl,SI_DEVIL, 1, 0); //Permanent blind effect from SG_DEVIL. + clif_status_change(&sd->bl,SI_DEVIL, 1, 0, 0, 0, 1); //Permanent blind effect from SG_DEVIL. npc_script_event(sd, NPCE_JOBLVUP); return 1; @@ -5131,7 +5223,11 @@ int pc_need_status_point(struct map_session_data* sd, int type, int val) swap(low, high); for ( ; low < high; low++ ) +#if RRMODE //Renewal Stat Cost Formula + sp += (low < 100) ? (2 + (low - 1) / 10) : (16 + 4 * ((low - 100) / 5)); +#else sp += ( 1 + (low + 9) / 10 ); +#endif return sp; } @@ -5480,7 +5576,16 @@ int pc_resetskill(struct map_session_data* sd, int flag) i &= ~OPTION_CART; if( i&OPTION_FALCON && pc_checkskill(sd, HT_FALCON) ) i &= ~OPTION_FALCON; - + if( i&OPTION_DRAGON && pc_checkskill(sd, RK_DRAGONTRAINING) ) + i &= ~OPTION_DRAGON; + if( i&OPTION_WUG && pc_checkskill(sd, RA_WUGMASTERY) ) + i &= ~OPTION_WUG; + if( i&OPTION_WUGRIDER && pc_checkskill(sd, RA_WUGRIDER) ) + i &= ~OPTION_WUGRIDER; + if( i&OPTION_MADOGEAR && ( sd->class_&MAPID_THIRDMASK ) == MAPID_MECHANIC ) + i &= ~OPTION_MADOGEAR; + if( i&OPTION_MOUNTING ) + i &= ~OPTION_MOUNTING; if( i != sd->sc.option ) pc_setoption(sd, i); @@ -6400,7 +6505,14 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) i&=~OPTION_CART; if(i&OPTION_FALCON && !pc_checkskill(sd, HT_FALCON)) i&=~OPTION_FALCON; - + if( i&OPTION_DRAGON && !pc_checkskill(sd,RK_DRAGONTRAINING) ) + i&=~OPTION_DRAGON; + if( i&OPTION_WUGRIDER && !pc_checkskill(sd,RA_WUGMASTERY) ) + i&=~OPTION_WUGRIDER; + if( i&OPTION_WUG && !pc_checkskill(sd,RA_WUGMASTERY) ) + i&=~OPTION_WUG; + if( i&OPTION_MADOGEAR ) //You do not need a skill for this. + i&=~OPTION_MADOGEAR; if(i != sd->sc.option) pc_setoption(sd, i); @@ -6528,15 +6640,15 @@ int pc_setoption(struct map_session_data *sd,int type) sd->sc.option=type; clif_changeoption(&sd->bl); - if (type&OPTION_RIDING && !(p_type&OPTION_RIDING) && (sd->class_&MAPID_BASEMASK) == MAPID_SWORDMAN) - { //We are going to mount. [Skotlex] + if( (type&OPTION_RIDING && !(p_type&OPTION_RIDING)) || (type&OPTION_DRAGON && !(p_type&OPTION_DRAGON) && pc_checkskill(sd,RK_DRAGONTRAINING) > 0) ) + { // Mounting clif_status_load(&sd->bl,SI_RIDING,1); - status_calc_pc(sd,0); //Mounting/Umounting affects walk and attack speeds. + status_calc_pc(sd,0); } - else if (!(type&OPTION_RIDING) && p_type&OPTION_RIDING && (sd->class_&MAPID_BASEMASK) == MAPID_SWORDMAN) - { //We are going to dismount. + else if( (!(type&OPTION_RIDING) && p_type&OPTION_RIDING) || (!(type&OPTION_DRAGON) && p_type&OPTION_DRAGON && pc_checkskill(sd,RK_DRAGONTRAINING) > 0) ) + { // Dismount clif_status_load(&sd->bl,SI_RIDING,0); - status_calc_pc(sd,0); //Mounting/Umounting affects walk and attack speeds. + status_calc_pc(sd,0); } if(type&OPTION_CART && !(p_type&OPTION_CART)) @@ -6553,11 +6665,49 @@ int pc_setoption(struct map_session_data *sd,int type) status_calc_pc(sd,0); //Remove speed penalty. } + if (type&OPTION_MOUNTING && !(p_type&OPTION_MOUNTING)) { + clif_status_load_notick(&sd->bl,SI_ALL_RIDING,2,1,0,0); + status_calc_pc(sd,0); + } else if (!(type&OPTION_MOUNTING) && p_type&OPTION_MOUNTING) { + clif_status_load_notick(&sd->bl,SI_ALL_RIDING,0,0,0,0); + status_calc_pc(sd,0); + } + + if (type&OPTION_FALCON && !(p_type&OPTION_FALCON)) //Falcon ON clif_status_load(&sd->bl,SI_FALCON,1); else if (!(type&OPTION_FALCON) && p_type&OPTION_FALCON) //Falcon OFF clif_status_load(&sd->bl,SI_FALCON,0); + if( (sd->class_&MAPID_THIRDMASK) == MAPID_RANGER ) { + if( type&OPTION_WUGRIDER && !(p_type&OPTION_WUGRIDER) ) { // Mounting + clif_status_load(&sd->bl,SI_WUGRIDER,1); + status_calc_pc(sd,0); + } else if( !(type&OPTION_WUGRIDER) && p_type&OPTION_WUGRIDER ) { // Dismount + clif_status_load(&sd->bl,SI_WUGRIDER,0); + status_calc_pc(sd,0); + } + } + if( (sd->class_&MAPID_THIRDMASK) == MAPID_MECHANIC ) { + if( type&OPTION_MADOGEAR && !(p_type&OPTION_MADOGEAR) ) { + status_calc_pc(sd, 0); + status_change_end(&sd->bl,SC_MAXIMIZEPOWER,-1); + status_change_end(&sd->bl,SC_OVERTHRUST,-1); + status_change_end(&sd->bl,SC_WEAPONPERFECTION,-1); + status_change_end(&sd->bl,SC_ADRENALINE,-1); + status_change_end(&sd->bl,SC_CARTBOOST,-1); + status_change_end(&sd->bl,SC_MELTDOWN,-1); + status_change_end(&sd->bl,SC_MAXOVERTHRUST,-1); + } else if( !(type&OPTION_MADOGEAR) && p_type&OPTION_MADOGEAR ) { + status_calc_pc(sd, 0); + status_change_end(&sd->bl,SC_SHAPESHIFT,-1); + status_change_end(&sd->bl,SC_HOVERING,-1); + status_change_end(&sd->bl,SC_ACCELERATION,-1); + status_change_end(&sd->bl,SC_OVERHEAT_LIMITPOINT,-1); + status_change_end(&sd->bl,SC_OVERHEAT,-1); + } + } + if (type&OPTION_FLYING && !(p_type&OPTION_FLYING)) new_look = JOB_STAR_GLADIATOR2; else if (!(type&OPTION_FLYING) && p_type&OPTION_FLYING) @@ -6644,7 +6794,7 @@ int pc_setriding(TBL_PC* sd, int flag) if( pc_checkskill(sd,KN_RIDING) > 0 ) // ライディングスキル所持 pc_setoption(sd, sd->sc.option|OPTION_RIDING); } else if( pc_isriding(sd) ){ - pc_setoption(sd, sd->sc.option&~OPTION_RIDING); + pc_setoption(sd, sd->sc.option&~OPTION_RIDING); } return 0; @@ -7801,6 +7951,30 @@ void pc_setstand(struct map_session_data *sd){ sd->state.dead_sit = sd->vd.dead_sit = 0; } +/** + * Mechanic (MADO GEAR) + **/ +void pc_overheat(struct map_session_data *sd, int val) { + int heat = val, skill, + limit[] = { 10, 20, 28, 46, 66 }; + + if( !(sd->sc.option&OPTION_MADOGEAR) || sd->sc.data[SC_OVERHEAT] ) + return; // already burning + + skill = cap_value(pc_checkskill(sd,NC_MAINFRAME),0,4); + if( sd->sc.data[SC_OVERHEAT_LIMITPOINT] ) { + heat += sd->sc.data[SC_OVERHEAT_LIMITPOINT]->val1; + status_change_end(&sd->bl,SC_OVERHEAT_LIMITPOINT,-1); + } + + heat = max(0,heat); // Avoid negative HEAT + if( heat >= limit[skill] ) + sc_start(&sd->bl,SC_OVERHEAT,100,0,1000); + else + sc_start(&sd->bl,SC_OVERHEAT_LIMITPOINT,100,heat,30000); + + return; +} int pc_split_str(char *str,char **val,int num) { int i; @@ -8060,7 +8234,11 @@ int pc_readdb(void) // スキルツリ? memset(statp,0,sizeof(statp)); i=1; +#if RRMODE + sprintf(line, "%s/statpoint_renewal.txt", db_path); +#else sprintf(line, "%s/statpoint.txt", db_path); +#endif fp=fopen(line,"r"); if(fp == NULL){ ShowWarning("Can't read '"CL_WHITE"%s"CL_RESET"'... Generating DB.\n",line); @@ -8079,7 +8257,11 @@ int pc_readdb(void) i++; } fclose(fp); + #if RRMODE + ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n","statpoint_renewal.txt"); + #else ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n","statpoint.txt"); + #endif } // generate the remaining parts of the db if necessary k = battle_config.use_statpoint_table; //save setting diff --git a/src/map/pc.h b/src/map/pc.h index 4d1e929a0..51588c842 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -21,6 +21,9 @@ #define MAX_PC_SKILL_REQUIRE 5 #define MAX_PC_FEELHATE 3 +//For Warlock +#define MAX_SPELLBOOK 10 + struct weapon_data { int atkmods[3]; // all the variables except atkmods get zero'ed in each call of status_calc_pc @@ -405,6 +408,13 @@ struct map_session_data { bool changed; // if true, should sync with charserver on next mailbox request } mail; + // Reading SpellBook + struct { + unsigned short skillid; + unsigned char level; + unsigned char points; + } rsb[MAX_SPELLBOOK]; + //Quest log system [Kevin] [Inkfish] int num_quests; int avail_quests; @@ -420,13 +430,33 @@ struct map_session_data { unsigned int bg_id; unsigned short user_font; + /** + * For the Secure NPC Timeout option (check RRConfig/Secure.h) [RR] + **/ +#if SECURE_NPCTIMEOUT + /** + * ID of the timer + * @info + * - value is -1 (INVALID_TIMER constant) when not being used + * - timer is cancelled upon closure of the current npc's instance + **/ + int npc_idle_timer; + /** + * Tick on the last recorded NPC iteration (next/menu/whatever) + * @info + * - It is updated on every NPC iteration as mentioned above + **/ + unsigned int npc_idle_tick; +#endif + // temporary debugging of bug #3504 const char* delunit_prevfile; int delunit_prevline; }; //Update this max as necessary. 55 is the value needed for Super Baby currently -#define MAX_SKILL_TREE 55 +//Raised to 75 due to 3rds +#define MAX_SKILL_TREE 75 //Total number of classes (for data storage) #define CLASS_COUNT (JOB_MAX - JOB_NOVICE_HIGH + JOB_MAX_BASIC) @@ -538,7 +568,12 @@ enum equip_index { #define pc_isinvisible(sd) ( (sd)->sc.option&OPTION_INVISIBLE ) #define pc_is50overweight(sd) ( (sd)->weight*100 >= (sd)->max_weight*battle_config.natural_heal_weight_rate ) #define pc_is90overweight(sd) ( (sd)->weight*10 >= (sd)->max_weight*9 ) -#define pc_maxparameter(sd) ( (sd)->class_&JOBL_BABY ? battle_config.max_baby_parameter : battle_config.max_parameter ) +#define pc_maxparameter(sd) ( (sd)->class_&JOBL_THIRD ? battle_config.max_third_parameter : (sd)->class_&JOBL_BABY ? battle_config.max_baby_parameter : battle_config.max_parameter ) +/** + * Ranger + **/ +#define pc_iswug(sd) ( (sd)->sc.option&OPTION_WUG ) +#define pc_isridingwug(sd) ( (sd)->sc.option&OPTION_WUGRIDER ) #define pc_stop_walking(sd, type) unit_stop_walking(&(sd)->bl, type) #define pc_stop_attack(sd) unit_stop_attack(&(sd)->bl) @@ -550,7 +585,8 @@ enum equip_index { #define pcdb_checkid(class_) \ ( \ ( (class_) >= JOB_NOVICE && (class_) < JOB_MAX_BASIC ) \ -|| ( (class_) >= JOB_NOVICE_HIGH && (class_) < JOB_MAX ) \ +|| ( (class_) >= JOB_NOVICE_HIGH && (class_) <= JOB_SOUL_LINKER ) \ +|| ( (class_) >= JOB_RUNE_KNIGHT && (class_) < JOB_MAX ) \ ) int pc_class2idx(int class_); @@ -785,5 +821,8 @@ void pc_inventory_rental_add(struct map_session_data *sd, int seconds); int pc_read_motd(void); // [Valaris] int pc_disguise(struct map_session_data *sd, int class_); - +/** + * Mechanic (Mado Gear) + **/ +void pc_overheat(struct map_session_data *sd, int val); #endif /* _PC_H_ */ diff --git a/src/map/script.c b/src/map/script.c index 151535c2f..452212a7d 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -325,7 +325,10 @@ enum { MF_FOG, MF_SAKURA, MF_LEAVES, - MF_RAIN, //20 + /** + * No longer available, keeping here just in case it's back someday. [Ind] + **/ + //MF_RAIN, //20 // 21 free MF_NOGO = 22, MF_CLOUDS, @@ -3365,7 +3368,18 @@ static void script_detach_state(struct script_state* st, bool dequeue_event) { sd->st = st->bk_st; sd->npc_id = st->bk_npcid; - + /** + * For the Secure NPC Timeout option (check RRConfig/Secure.h) [RR] + **/ + #if SECURE_NPCTIMEOUT + /** + * We're done with this NPC session, so we cancel the timer (if existent) and move on + **/ + if( sd->npc_idle_timer != INVALID_TIMER ) { + delete_timer(sd->npc_idle_timer,npc_rr_secure_timeout_timer); + sd->npc_idle_timer = INVALID_TIMER; + } + #endif if(st->bk_st) { //Remove tag for removal. @@ -3407,6 +3421,14 @@ static void script_attach_state(struct script_state* st) } sd->st = st; sd->npc_id = st->oid; +/** + * For the Secure NPC Timeout option (check RRConfig/Secure.h) [RR] + **/ +#if SECURE_NPCTIMEOUT + if( sd->npc_idle_timer == INVALID_TIMER ) + sd->npc_idle_timer = add_timer(gettick() + (SECURE_NPCTIMEOUT_INTERVAL*1000),npc_rr_secure_timeout_timer,sd->bl.id,0); + sd->npc_idle_tick = gettick(); +#endif } } @@ -7549,7 +7571,7 @@ BUILDIN_FUNC(checkriding) if( sd == NULL ) return 0;// no player attached, report source - if( pc_isriding(sd) ) + if( pc_isriding(sd) || sd->sc.option&OPTION_MOUNTING ) script_pushint(st, 1); else script_pushint(st, 0); @@ -7771,7 +7793,7 @@ BUILDIN_FUNC(produce) return 0; trigger=script_getnum(st,2); - clif_skill_produce_mix_list(sd, trigger); + clif_skill_produce_mix_list(sd, -1, trigger); return 0; } /*========================================== @@ -9146,7 +9168,7 @@ BUILDIN_FUNC(roclass) } /*========================================== - *携帯卵孵化機使用 + * Tells client to open a hatching window, used for pet incubator *------------------------------------------*/ BUILDIN_FUNC(birthpet) { @@ -9616,7 +9638,10 @@ BUILDIN_FUNC(getmapflag) case MF_FIREWORKS: script_pushint(st,map[m].flag.fireworks); break; case MF_SAKURA: script_pushint(st,map[m].flag.sakura); break; case MF_LEAVES: script_pushint(st,map[m].flag.leaves); break; - case MF_RAIN: script_pushint(st,map[m].flag.rain); break; + /** + * No longer available, keeping here just in case it's back someday. [Ind] + **/ + //case MF_RAIN: script_pushint(st,map[m].flag.rain); break; case MF_NIGHTENABLED: script_pushint(st,map[m].flag.nightenabled); break; case MF_NOGO: script_pushint(st,map[m].flag.nogo); break; case MF_NOBASEEXP: script_pushint(st,map[m].flag.nobaseexp); break; @@ -9686,7 +9711,10 @@ BUILDIN_FUNC(setmapflag) case MF_FIREWORKS: map[m].flag.fireworks=1; break; case MF_SAKURA: map[m].flag.sakura=1; break; case MF_LEAVES: map[m].flag.leaves=1; break; - case MF_RAIN: map[m].flag.rain=1; break; + /** + * No longer available, keeping here just in case it's back someday. [Ind] + **/ + //case MF_RAIN: map[m].flag.rain=1; break; case MF_NIGHTENABLED: map[m].flag.nightenabled=1; break; case MF_NOGO: map[m].flag.nogo=1; break; case MF_NOBASEEXP: map[m].flag.nobaseexp=1; break; @@ -9753,7 +9781,10 @@ BUILDIN_FUNC(removemapflag) case MF_FIREWORKS: map[m].flag.fireworks=0; break; case MF_SAKURA: map[m].flag.sakura=0; break; case MF_LEAVES: map[m].flag.leaves=0; break; - case MF_RAIN: map[m].flag.rain=0; break; + /** + * No longer available, keeping here just in case it's back someday. [Ind] + **/ + //case MF_RAIN: map[m].flag.rain=0; break; case MF_NIGHTENABLED: map[m].flag.nightenabled=0; break; case MF_NOGO: map[m].flag.nogo=0; break; case MF_NOBASEEXP: map[m].flag.nobaseexp=0; break; @@ -14951,8 +14982,133 @@ BUILDIN_FUNC(searchstores) searchstore_open(sd, uses, effect); return 0; } +/// Displays a number as large digital clock. +/// showdigit [,]; +BUILDIN_FUNC(showdigit) +{ + unsigned int type = 0; + int value; + struct map_session_data* sd; + + if( ( sd = script_rid2sd(st) ) == NULL ) + { + return 0; + } + + value = script_getnum(st,2); + + if( script_hasdata(st,3) ) + { + type = script_getnum(st,3); + if( type > 3 ) + { + ShowError("buildin_showdigit: Invalid type %u.\n", type); + return 1; + } + } + clif_showdigit(sd, (unsigned char)type, value); + return 0; +} +/** + * Rune Knight + **/ +BUILDIN_FUNC(makerune) { + TBL_PC* sd; + if( (sd = script_rid2sd(st)) == NULL ) + return 0; + clif_skill_produce_mix_list(sd,RK_RUNEMASTERY,24); + sd->itemid = script_getnum(st,2); + return 0; +} +/** + * checkdragon() returns 1 if mounting a dragon or 0 otherwise. + **/ +BUILDIN_FUNC(checkdragon) { + TBL_PC* sd; + if( (sd = script_rid2sd(st)) == NULL ) + return 0; + if( sd->sc.option&OPTION_DRAGON ) + script_pushint(st,1); + else + script_pushint(st,0); + return 0; +} +/** + * setdragon({optional Color}) returns 1 on success or 0 otherwise + * - Toggles the dragon on a RK if he can mount; + * @param Color - when not provided uses the green dragon; + * - 1 : Green Dragon + * - 2 : Brown Dragon + * - 3 : Gray Dragon + * - 4 : Blue Dragon + * - 5 : Red Dragon + **/ +BUILDIN_FUNC(setdragon) { + TBL_PC* sd; + int color = script_hasdata(st,2) ? script_getnum(st,2) : 0; + unsigned int option = OPTION_DRAGON1; + if( (sd = script_rid2sd(st)) == NULL ) + return 0; + if( !pc_checkskill(sd,RK_DRAGONTRAINING) || (sd->class_&MAPID_THIRDMASK) != MAPID_RUNE_KNIGHT ) + script_pushint(st,0);//Doesn't have the skill or it's not a Rune Knight + else if ( sd->sc.option&OPTION_DRAGON ) {//Is mounted; release + pc_setoption(sd, sd->sc.option&~OPTION_DRAGON); + script_pushint(st,1); + } else {//Not mounted; Mount now. + if( color ) { + option = ( color == 1 ? OPTION_DRAGON1 : + color == 2 ? OPTION_DRAGON2 : + color == 3 ? OPTION_DRAGON3 : + color == 4 ? OPTION_DRAGON4 : + color == 5 ? OPTION_DRAGON5 : 0); + if( !option ) { + ShowWarning("script_setdragon: Unknown Color %d used; changing to green (1)\n",color); + option = OPTION_DRAGON1; + } + } + pc_setoption(sd, sd->sc.option|option); + script_pushint(st,1); + } + return 0; +} + +/** + * ismounting() returns 1 if mounting a new mount or 0 otherwise + **/ +BUILDIN_FUNC(ismounting) { + TBL_PC* sd; + if( (sd = script_rid2sd(st)) == NULL ) + return 0; + if( sd->sc.option&OPTION_MOUNTING ) + script_pushint(st,1); + else + script_pushint(st,0); + return 0; +} + +/** + * setmounting() returns 1 on success or 0 otherwise + * - Toggles new mounts on a player when he can mount + * - Will fail if the player is mounting a non-new mount, e.g. dragon, peco, wug, etc. + * - Will unmount the player is he is already mounting + **/ +BUILDIN_FUNC(setmounting) { + TBL_PC* sd; + if( (sd = script_rid2sd(st)) == NULL ) + return 0; + if( sd->sc.option&(OPTION_WUGRIDER|OPTION_RIDING|OPTION_DRAGON|OPTION_MADOGEAR) ) + script_pushint(st,0);//can't mount with one of these + else { + if( sd->sc.option&OPTION_MOUNTING ) + pc_setoption(sd, sd->sc.option&~OPTION_MOUNTING);//release mount + else + pc_setoption(sd, sd->sc.option|OPTION_MOUNTING);//mount + script_pushint(st,1);//in both cases, return 1. + } + return 0; +} // declarations that were supposed to be exported from npc_chat.c #ifdef PCRE_SUPPORT BUILDIN_FUNC(defpattern); @@ -15317,6 +15473,7 @@ struct script_function buildin_func[] = { BUILDIN_DEF(pushpc,"ii"), BUILDIN_DEF(buyingstore,"i"), BUILDIN_DEF(searchstores,"ii"), + BUILDIN_DEF(showdigit,"i?"), // WoE SE BUILDIN_DEF(agitstart2,""), BUILDIN_DEF(agitend2,""), @@ -15348,7 +15505,14 @@ struct script_function buildin_func[] = { BUILDIN_DEF(instance_npcname,"s?"), BUILDIN_DEF(has_instance,"s?"), BUILDIN_DEF(instance_warpall,"sii?"), - + /** + * 3rd-related + **/ + BUILDIN_DEF(makerune,"i"), + BUILDIN_DEF(checkdragon,""),//[Ind] + BUILDIN_DEF(setdragon,"?"),//[Ind] + BUILDIN_DEF(ismounting,""),//[Ind] + BUILDIN_DEF(setmounting,""),//[Ind] //Quest Log System [Inkfish] BUILDIN_DEF(setquest, "i"), BUILDIN_DEF(erasequest, "i"), diff --git a/src/map/skill.c b/src/map/skill.c index 28bb9e389..41c3580ae 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -59,11 +59,23 @@ struct s_skill_db skill_db[MAX_SKILL_DB]; struct s_skill_produce_db skill_produce_db[MAX_SKILL_PRODUCE_DB]; struct s_skill_arrow_db skill_arrow_db[MAX_SKILL_ARROW_DB]; struct s_skill_abra_db skill_abra_db[MAX_SKILL_ABRA_DB]; +//Warlock +struct s_skill_spellbook_db { + int nameid; + int skillid; + int points; +}; + +struct s_skill_spellbook_db skill_spellbook_db[MAX_SKILL_SPELLBOOK_DB]; +//Guillotine Cross +struct s_skill_magicmushroom_db skill_magicmushroom_db[MAX_SKILL_MAGICMUSHROOM_DB]; struct s_skill_unit_layout skill_unit_layout[MAX_SKILL_UNIT_LAYOUT]; int firewall_unit_pos; int icewall_unit_pos; - +int earthstrain_unit_pos; +//early declaration +int skill_stasis_check(struct block_list *bl, int src_id, int skillid); //Since only mob-casted splash skills can hit ice-walls static inline int splash_target(struct block_list* bl) { @@ -170,6 +182,7 @@ int skill_get_unit_target( int id ) { skill_get (skill_db[id].unit_target& int skill_get_unit_bl_target( int id ) { skill_get (skill_db[id].unit_target&BL_ALL, id, 1); } int skill_get_unit_flag( int id ) { skill_get (skill_db[id].unit_flag, id, 1); } int skill_get_unit_layout_type( int id ,int lv ){ skill_get (skill_db[id].unit_layout_type[lv-1], id, lv); } +int skill_get_cooldown( int id ,int lv ) { skill_get (skill_db[id].cooldown[lv-1], id, lv); } int skill_tree_get_max(int id, int b_class) { @@ -241,6 +254,12 @@ int skill_get_range2 (struct block_list *bl, int id, int lv) case MA_CHARGEARROW: case SN_FALCONASSAULT: case HT_POWER: + /** + * Ranger + **/ + case RA_ARROWSTORM: + case RA_AIMEDBOLT: + case RA_WUGBITE: if( bl->type == BL_PC ) range += pc_checkskill((TBL_PC*)bl, AC_VULTURE); else @@ -261,6 +280,36 @@ int skill_get_range2 (struct block_list *bl, int id, int lv) if (bl->type == BL_PC) range = skill_get_range(NJ_SHADOWJUMP,pc_checkskill((TBL_PC*)bl,NJ_SHADOWJUMP)); break; + /** + * Warlock + **/ + case WL_WHITEIMPRISON: + case WL_SOULEXPANSION: + case WL_FROSTMISTY: + case WL_MARSHOFABYSS: + case WL_SIENNAEXECRATE: + case WL_DRAINLIFE: + case WL_CRIMSONROCK: + case WL_HELLINFERNO: + case WL_COMET: + case WL_CHAINLIGHTNING: + case WL_TETRAVORTEX: + case WL_RELEASE: + if( bl->type == BL_PC ) + range += pc_checkskill((TBL_PC*)bl, WL_RADIUS); + break; + /** + * Ranger Bonus + **/ + case HT_LANDMINE: + case HT_FREEZINGTRAP: + case HT_BLASTMINE: + case HT_CLAYMORETRAP: + case RA_CLUSTERBOMB: + case RA_FIRINGTRAP: + case RA_ICEBOUNDTRAP: + if( bl->type == BL_PC ) + range += (1 + pc_checkskill((TBL_PC*)bl, RA_RESEARCHTRAP))/2; } if( !range && bl->type != BL_PC ) @@ -291,14 +340,25 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, int skill default: if (skill_lv >= battle_config.max_heal_lv) return battle_config.max_heal; - - hp = ( status_get_lv(src)+status_get_int(src) )/8 *(4+ skill_lv*8); + #if RRMODE + /** + * Renewal Heal Formula (from Doddler) + * TODO: whats that( 1+ %Modifier / 100 ) ? currently using 'x1' (100/100) until found out + * - Min = ( [ ( BaseLvl + INT ) / 5 ] * 30 ) * (1+( %Modifier / 100)) * (HealLvl * 0.1) + StatusMATK + EquipMATK - [(WeaponMATK * WeaponLvl) / 10] + * - Max = ( [ ( BaseLvl + INT ) / 5 ] * 30 ) * (1+( %Modifier / 100)) * (HealLvl * 0.1) + StatusMATK + EquipMATK + [(WeaponMATK * WeaponLvl) / 10] + **/ + hp = ( ( ( ( status_get_lv(src) + status_get_int(src) ) / 5 ) * 30 ) * ( skill_lv / 10 ) + status_get_matk_min(src) + status_get_matk_max(src) - ( ( status_get_matk_max(src) * status_get_wlv(src) ) / 10 ) ) + rand()%( ( ( ( status_get_lv(src) + status_get_int(src) ) / 5 ) * 30 ) * ( skill_lv / 10 ) + status_get_matk_min(src) + status_get_matk_max(src) + ( ( status_get_matk_max(src) * status_get_wlv(src) ) / 10 ) ); + #else + hp = ( status_get_lv(src) + status_get_int(src) ) / 8 * (4 + ( skill_id == AB_HIGHNESSHEAL ? ( sd ? pc_checkskill(sd,AL_HEAL) : 10 ) : skill_lv ) * 8); + #endif if( sd && ((skill = pc_checkskill(sd, HP_MEDITATIO)) > 0) ) hp += hp * skill * 2 / 100; else if( src->type == BL_HOM && (skill = merc_hom_checkskill(((TBL_HOM*)src), HLIF_BRAIN)) > 0 ) hp += hp * skill * 2 / 100; break; } + if( skill_id == AB_HIGHNESSHEAL ) + hp = (hp * (20 + 3 * (skill_lv - 1))) / 10; if( ( (target && target->type == BL_MER) || !heal ) && skill_id != NPC_EVILLAND ) hp >>= 1; @@ -378,6 +438,9 @@ int skillnotok (int skillid, struct map_session_data *sd) if(map[m].flag.restricted && map[m].zone && skill_get_nocast (skillid) & (8*map[m].zone)) return 1; + if( sd->sc.option&OPTION_MOUNTING ) + return 1;//You can't use skills while in the new mounts (The client doesn't let you, this is to make cheat-safe) + switch (skillid) { case AL_WARP: if(map[m].flag.nowarp) { @@ -410,6 +473,12 @@ int skillnotok (int skillid, struct map_session_data *sd) return 1; } break; + case GC_DARKILLUSION: + if( map_flag_gvg(m) ) { + clif_skill_fail(sd,skillid,0,0); + return 1; + } + break; case GD_EMERGENCYCALL: if ( !(battle_config.emergency_call&((agit_flag || agit2_flag)?2:1)) || @@ -420,6 +489,23 @@ int skillnotok (int skillid, struct map_session_data *sd) return 1; } break; + case BS_GREED: + case WS_CARTBOOST: + case BS_HAMMERFALL: + case BS_ADRENALINE: + case MC_CARTREVOLUTION: + case MC_MAMMONITE: + case WS_MELTDOWN: + case MG_SIGHT: + case TF_HIDING: + /** + * These skills cannot be used while in mado gear (credits to Xantara) + **/ + if(sd->sc.option&OPTION_MADOGEAR) { + clif_skill_fail(sd,skillid,0,0); + return 1; + } + break; } return (map[m].flag.noskill); } @@ -471,6 +557,8 @@ struct s_skill_unit_layout* skill_get_unit_layout (int skillid, int skilllv, str return &skill_unit_layout [firewall_unit_pos + dir]; else if (skillid == WZ_ICEWALL) return &skill_unit_layout [icewall_unit_pos + dir]; + else if( skillid == WL_EARTHSTRAIN ) //Warlock + return &skill_unit_layout [earthstrain_unit_pos + dir]; ShowError("skill_get_unit_layout: unknown unit layout for skill %d (level %d)\n", skillid, skilllv); return &skill_unit_layout[0]; // default 1x1 layout @@ -587,6 +675,9 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int rate=(sd->status.job_level+9)/10; skill_castend_damage_id(src,bl,HT_BLITZBEAT,(skillstatus.weapon == W_BOW || sd->status.weapon == W_FIST) && (skill=pc_checkskill(sd,RA_WUGSTRIKE)) > 0 && rand()%1000 <= sstatus->luk*10/3+1 ) + skill_castend_damage_id(src,bl,RA_WUGSTRIKE,skill,tick,0); // Gank if(dstmd && sd->status.weapon != W_BOW && (skill=pc_checkskill(sd,RG_SNATCHER)) > 0 && @@ -683,7 +774,14 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int case WZ_METEOR: sc_start(bl,SC_STUN,3*skilllv,skilllv,skill_get_time2(skillid,skilllv)); break; - +#if FIREIVY_ON + //case WZ_FIREIVY: + // Testing for Fire Ivy + //sc_start(bl,SC_STUN,3*skilllv,skilllv,skill_get_time2(skillid,skilllv)); + //sc_start(bl,SC_STUN,(5*skilllv+35),skilllv,skill_get_time2(skillid,skilllv)); + //sc_start(bl,SC_BURNING,(8*skilllv+35),skilllv,skill_get_time2(skillid,skilllv)); + //break; +#endif case WZ_VERMILION: sc_start(bl,SC_BLIND,4*skilllv,skilllv,skill_get_time2(skillid,skilllv)); break; @@ -929,6 +1027,104 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int case NPC_CRITICALWOUND: sc_start(bl,SC_CRITICALWOUND,100,skilllv,skill_get_time2(skillid,skilllv)); break; + /** + * Rune Knight + **/ + case RK_HUNDREDSPEAR: + if( !sd || pc_checkskill(sd,KN_SPEARBOOMERANG) == 0 ) + break; // Spear Boomerang auto cast chance only works if you have mastered Spear Boomerang. + rate = 10 + 3 * skilllv; + if( rand()%100 < rate ) + skill_castend_damage_id(src,bl,KN_SPEARBOOMERANG,1,tick,0); + break; + case RK_WINDCUTTER: + sc_start(bl,SC_FEAR,3+2*skilllv,skilllv,skill_get_time(skillid,skilllv)); + break; + case RK_DRAGONBREATH: + sc_start4(bl,SC_BURNING,5+5*skilllv,skilllv,1000,src->id,0,skill_get_time(skillid,skilllv)); + break; + /** + * Arch Bishop + **/ + case AB_ADORAMUS: + if( tsc && !tsc->data[SC_DECREASEAGI] ) //Prevent duplicate agi-down effect. + sc_start(bl, SC_ADORAMUS, 100, skilllv, skill_get_time(skillid, skilllv)); + break; + /** + * Warlock + **/ + case WL_CRIMSONROCK: + sc_start(bl, SC_STUN, 40, skilllv, skill_get_time(skillid, skilllv)); + break; + case WL_COMET: + sc_start4(bl,SC_BURNING,100,skilllv,1000,src->id,0,skill_get_time(skillid,skilllv)); + break; + case WL_EARTHSTRAIN: + { + int rate = 0, i; + const int pos[5] = { EQP_WEAPON, EQP_HELM, EQP_SHIELD, EQP_ARMOR, EQP_ACC }; + rate = 6 * skilllv + sstatus->dex / 10 + (sd? sd->status.job_level / 4 : 0) - tstatus->dex /5;// The tstatus->dex / 5 part is unofficial, but players gotta have some kind of way to have resistance. [Rytech] + //rate -= rate * tstatus->dex / 200; // Disabled until official resistance is found. + + for( i = 0; i < skilllv; i++ ) + skill_strip_equip(bl,pos[i],rate,skilllv,skill_get_time2(skillid,skilllv)); + } + break; + case WL_JACKFROST: + sc_start(bl,SC_FREEZE,100,skilllv,skill_get_time(skillid,skilllv)); + break; + /** + * Ranger + **/ + case RA_WUGBITE: + sc_start(bl, SC_BITE, 70, skilllv, skill_get_time(skillid, skilllv) + (sd ? pc_checkskill(sd,RA_TOOTHOFWUG) * 1000 : 0)); // Need official chance. + break; + case RA_SENSITIVEKEEN: + if( rand()%100 < 8 * skilllv ) + skill_castend_damage_id(src, bl, RA_WUGBITE, sd ? pc_checkskill(sd, RA_WUGBITE):skilllv, tick, SD_ANIMATION); + break; + case RA_MAGENTATRAP: + case RA_COBALTTRAP: + case RA_MAIZETRAP: + case RA_VERDURETRAP: + if( dstmd && !(dstmd->status.mode&MD_BOSS) ) + sc_start2(bl,SC_ELEMENTALCHANGE,100,skilllv,skill_get_ele(skillid,skilllv),skill_get_time2(skillid,skilllv)); + break; + case RA_FIRINGTRAP: + case RA_ICEBOUNDTRAP: + sc_start(bl, (skillid == RA_FIRINGTRAP) ? SC_BURNING:SC_FREEZING, 40 + 10 * skilllv, skilllv, skill_get_time2(skillid, skilllv)); + break; + /** + * Mechanic + **/ + case NC_PILEBUNKER: + if( rand()%100 < 5 + 15*skilllv ) + { //Deactivatable Statuses: Kyrie Eleison, Auto Guard, Steel Body, Assumptio, and Millennium Shield + status_change_end(bl, SC_KYRIE, -1); + status_change_end(bl, SC_AUTOGUARD, -1); + status_change_end(bl, SC_STEELBODY, -1); + status_change_end(bl, SC_ASSUMPTIO, -1); + status_change_end(bl, SC_MILLENNIUMSHIELD, -1); + } + break; + case NC_FLAMELAUNCHER: + sc_start4(bl, SC_BURNING, 50 + 10 * skilllv, skilllv, 1000, src->id, 0, skill_get_time2(skillid, skilllv)); + break; + case NC_COLDSLOWER: + sc_start(bl, SC_FREEZE, 10 * skilllv, skilllv, skill_get_time(skillid, skilllv)); + sc_start(bl, SC_FREEZING, 20 + 10 * skilllv, skilllv, skill_get_time2(skillid, skilllv)); + break; + case NC_POWERSWING: + sc_start(bl, SC_STUN, 5*skilllv, skilllv, skill_get_time(skillid, skilllv)); + if( rand()%100 < 5*skilllv ) + skill_castend_damage_id(src, bl, NC_AXEBOOMERANG, pc_checkskill(sd, NC_AXEBOOMERANG), tick, 1); + break; + /** + * Guilotine Cross + **/ + case GC_WEAPONCRUSH: + skill_castend_nodamage_id(src,bl,skillid,skilllv,tick,BCT_ENEMY); + break; } if (md && battle_config.summons_trigger_autospells && md->master_id && md->special_state.ai) @@ -1039,7 +1235,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int if (DIFF_TICK(ud->canact_tick, tick + rate) < 0){ ud->canact_tick = tick+rate; if ( battle_config.display_status_timers && sd ) - clif_status_change(src, SI_ACTIONDELAY, 1, rate); + clif_status_change(src, SI_ACTIONDELAY, 1, rate, 0, 0, 0); } } } @@ -1315,7 +1511,7 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * if (DIFF_TICK(ud->canact_tick, tick + rate) < 0){ ud->canact_tick = tick+rate; if ( battle_config.display_status_timers && dstsd ) - clif_status_change(bl, SI_ACTIONDELAY, 1, rate); + clif_status_change(bl, SI_ACTIONDELAY, 1, rate, 0, 0, 0); } } } @@ -1450,7 +1646,7 @@ int skill_strip_equip(struct block_list *bl, unsigned short where, int rate, int return 0; sc = status_get_sc(bl); - if (!sc) + if (!sc || sc->option&OPTION_MADOGEAR ) //Mado Gear cannot be divested [Ind] return 0; for (i = 0; i < ARRAYLENGTH(pos); i++) { @@ -1465,8 +1661,8 @@ int skill_strip_equip(struct block_list *bl, unsigned short where, int rate, int } return where?1:0; } - - +//Early declaration +static int skill_area_temp[8]; /*========================================================================= Used to knock back players, monsters, traps, etc - 'count' is the number of squares to knock back @@ -1655,8 +1851,14 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds sc->data[SC_SPIRIT]->val4 = dsrc->id; } } + /** + * Official Magic Reflection Behavior : damage reflected depends on gears caster wears, not target + **/ + #if RR_MAGIC_REFLECTION + if( dmg.dmg_lv != ATK_MISS )//Wiz SL cancelled and consumed fragment + dmg = battle_calc_attack(BF_MAGIC,bl,bl,skillid,skilllv,flag&0xFFF); + #endif } - if(sc && sc->data[SC_MAGICROD] && src == dsrc) { int sp = skill_get_sp(skillid,skilllv); dmg.damage = dmg.damage2 = 0; @@ -1678,7 +1880,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds if( damage > 0 && dmg.flag&BF_WEAPON && src != bl && ( src == dsrc || ( dsrc->type == BL_SKILL && ( skillid == SG_SUN_WARM || skillid == SG_MOON_WARM || skillid == SG_STAR_WARM ) ) ) && skillid != WS_CARTTERMINATION ) - rdamage = battle_calc_return_damage(bl, damage, dmg.flag); + rdamage = battle_calc_return_damage(bl,src, &damage, dmg.flag); //Skill hit type type=(skillid==0)?5:skill_get_hit(skillid); @@ -1804,7 +2006,31 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds else // the central target doesn't display an animation dmg.dmotion = clif_skill_damage(dsrc,bl,tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skillid, -2, 5); // needs -2(!) as skill level break; - + /** + * Warlock + **/ + case WL_HELLINFERNO: + dmg.dmotion = clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,1,skillid,-2,6); + break; + case WL_SOULEXPANSION: + case WL_COMET: + dmg.dmotion = clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,skillid,skilllv,8); + break; + case WL_CHAINLIGHTNING_ATK: + dmg.dmotion = clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,1,WL_CHAINLIGHTNING,-2,6); + break; + case WL_TETRAVORTEX_FIRE: + case WL_TETRAVORTEX_WATER: + case WL_TETRAVORTEX_WIND: + case WL_TETRAVORTEX_GROUND: + dmg.dmotion = clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,1,WL_TETRAVORTEX_FIRE,-2,type); + break; + /** + * Arch Bishop + **/ + case AB_DUPLELIGHT_MELEE: + case AB_DUPLELIGHT_MAGIC: + dmg.amotion = 300; default: if( flag&SD_ANIMATION && dmg.div_ < 2 ) //Disabling skill animation doesn't works on multi-hit. type = 5; @@ -1819,8 +2045,22 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds && (!sc || !sc->data[SC_PRESERVE]) && damage < tsd->battle_status.hp) { //Updated to not be able to copy skills if the blow will kill you. [Skotlex] - if ((tsd->status.skill[skillid].id == 0 || tsd->status.skill[skillid].flag == SKILL_FLAG_PLAGIARIZED) && - can_copy(tsd,skillid,bl)) // Split all the check into their own function [Aru] + int copy_skill = skillid; + /** + * Copy Referal: dummy skills should point to their source upon copying + **/ + switch( skillid ) { + case AB_DUPLELIGHT_MELEE: + case AB_DUPLELIGHT_MAGIC: + copy_skill = AB_DUPLELIGHT; + break; + case WL_CHAINLIGHTNING_ATK: + copy_skill = WL_CHAINLIGHTNING; + break; + } + + if ((tsd->status.skill[copy_skill].id == 0 || tsd->status.skill[copy_skill].flag == SKILL_FLAG_PLAGIARIZED) && + can_copy(tsd,copy_skill,bl)) // Split all the check into their own function [Aru] { int lv = skilllv; if (tsd->cloneskill_id && tsd->status.skill[tsd->cloneskill_id].flag == SKILL_FLAG_PLAGIARIZED){ @@ -1833,11 +2073,11 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds if ((type = pc_checkskill(tsd,RG_PLAGIARISM)) < lv) lv = type; - tsd->cloneskill_id = skillid; - pc_setglobalreg(tsd, "CLONE_SKILL", skillid); + tsd->cloneskill_id = copy_skill; + pc_setglobalreg(tsd, "CLONE_SKILL", copy_skill); pc_setglobalreg(tsd, "CLONE_SKILL_LV", lv); - tsd->status.skill[skillid].id = skillid; + tsd->status.skill[skillid].id = copy_skill; tsd->status.skill[skillid].lv = lv; tsd->status.skill[skillid].flag = SKILL_FLAG_PLAGIARIZED; clif_addskill(tsd,skillid); @@ -1871,6 +2111,12 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds if( damage > 0 ) //Counter status effects [Skotlex] skill_counter_additional_effect(src,bl,skillid,skilllv,dmg.flag,tick); } + // Hell Inferno burning status only starts if Fire part hits. + if( skillid == WL_HELLINFERNO && dmg.damage > 0 ) + sc_start4(bl,SC_BURNING,55+5*skilllv,skilllv,1000,src->id,0,skill_get_time(skillid,skilllv)); + // Apply knock back chance in SC_TRIANGLESHOT skill. + else if( skillid == SC_TRIANGLESHOT && rand()%100 > (1 + skilllv) ) + dmg.blewcount = 0; //Only knockback if it's still alive, otherwise a "ghost" is left behind. [Skotlex] //Reflected spells do not bounce back (bl == dsrc since it only happens for direct skills) @@ -1882,6 +2128,8 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds case MG_FIREWALL: direction = unit_getdir(bl); break; // backwards case WZ_STORMGUST: direction = rand()%8; break; // randomly case PR_SANCTUARY: direction = unit_getdir(bl); break; // backwards + case WL_CRIMSONROCK: direction = map_calc_dir(bl,skill_area_temp[4],skill_area_temp[5]); break; + } skill_blown(dsrc,bl,dmg.blewcount,direction,0); } @@ -1937,6 +2185,19 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds battle_drain(tsd, src, rdamage, rdamage, sstatus->race, is_boss(src)); skill_additional_effect(bl, src, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick); } + if( damage > 0 ) { + if( skillid == RK_CRUSHSTRIKE ) // Your weapon will not be broken if you miss. + skill_break_equip(src,EQP_WEAPON,10000,BCT_SELF); + + if( skillid == GC_VENOMPRESSURE ) { + struct status_change *ssc = status_get_sc(src); + if( ssc && ssc->data[SC_POISONINGWEAPON] && rand()%100 < 70 + 5*skilllv ) { + sc_start(bl,ssc->data[SC_POISONINGWEAPON]->val2,100,ssc->data[SC_POISONINGWEAPON]->val1,skill_get_time2(GC_POISONINGWEAPON,ssc->data[SC_POISONINGWEAPON]->val1)); + status_change_end(src,SC_POISONINGWEAPON,-1); + clif_skill_nodamage(src,bl,skillid,skilllv,1); + } + } + } if (!(flag&2) && ( @@ -1963,7 +2224,6 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds * ffff=自由に使用可能 * 0 =予約?B0に固定 *------------------------------------------*/ -static int skill_area_temp[8]; typedef int (*SkillFunc)(struct block_list *, struct block_list *, int, int, unsigned int, int); int skill_area_sub (struct block_list *bl, va_list ap) { @@ -2034,6 +2294,17 @@ static int skill_check_unit_range_sub (struct block_list *bl, va_list ap) case HT_CLAYMORETRAP: case HT_TALKIEBOX: case HP_BASILICA: + /** + * Ranger + **/ + case RA_ELECTRICSHOCKER: + case RA_CLUSTERBOMB: + case RA_MAGENTATRAP: + case RA_COBALTTRAP: + case RA_MAIZETRAP: + case RA_VERDURETRAP: + case RA_FIRINGTRAP: + case RA_ICEBOUNDTRAP: //Non stackable on themselves and traps (including venom dust which does not has the trap inf2 set) if (skillid != g_skillid && !(skill_get_inf2(g_skillid)&INF2_TRAP) && g_skillid != AS_VENOMDUST) return 0; @@ -2346,6 +2617,61 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) } } break; + /** + * Warlock + **/ + case WL_CHAINLIGHTNING_ATK: + { + struct block_list *nbl = NULL; // Next Target of Chain + skill_attack(BF_MAGIC,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag); // Hit a Lightning on the current Target + if( skl->type > 1 ) + { // Remaining Chains Hit + nbl = battle_getenemyarea(src,target->x,target->y,2,BL_CHAR|BL_SKILL,target->id); // Search for a new Target around current one... + if( nbl == NULL && skl->x > 1 ) + { + nbl = target; + skl->x--; + } + else skl->x = 3; + } + + if( nbl ) + skill_addtimerskill(src,tick+status_get_adelay(src),nbl->id,skl->x,0,WL_CHAINLIGHTNING_ATK,skl->skill_lv,skl->type-1,skl->flag); + } + break; + case WL_TETRAVORTEX_FIRE: + case WL_TETRAVORTEX_WATER: + case WL_TETRAVORTEX_WIND: + case WL_TETRAVORTEX_GROUND: + skill_attack(BF_MAGIC,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag); + if( skl->type >= 3 ) + { // Final Hit + status_change_end(src,SC_MAGICPOWER,-1); // Removes Magic Power + if( !status_isdead(target) ) + { // Final Status Effect + int effects[4] = { SC_BURNING, SC_FREEZING, SC_BLEEDING, SC_STUN }, + applyeffects[4] = { 0, 0, 0, 0 }, + i, j = 0, k = 0; + for( i = 1; i <= 8; i = i + i ) + { + if( skl->x&i ) + { + applyeffects[j] = effects[k]; + j++; + } + k++; + } + if( j ) + { + i = applyeffects[rand()%j]; + status_change_start(target, i, 10000, skl->skill_lv, + (i == SC_BURNING ? 1000 : 0), + (i == SC_BURNING ? src->id : 0), + 0, skill_get_time(WL_TETRAVORTEX,skl->skill_lv), 0); + } + } + } + break; default: skill_attack(skl->type,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag); break; @@ -2368,7 +2694,13 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) else if( path_search_long(NULL, src->m, src->x, src->y, skl->x, skl->y, CELL_CHKWALL) ) skill_unitsetting(src,skl->skill_id,skl->skill_lv,skl->x,skl->y,skl->flag); break; + case WL_EARTHSTRAIN: + skill_unitsetting(src,skl->skill_id,skl->skill_lv,skl->x,skl->y,(skl->type<<16)|skl->flag); + break; + } + if( skl->skill_id >= WL_TETRAVORTEX_FIRE && skl->skill_id <= WL_TETRAVORTEX_GROUND ) + status_change_end(src,SC_MAGICPOWER,-1); } } while (0); //Free skl now that it is no longer needed. @@ -2569,6 +2901,43 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int case NPC_BLEEDING: case NPC_CRITICALWOUND: case NPC_HELLPOWER: + /** + * Rune Knight + **/ + case RK_SONICWAVE: + case RK_HUNDREDSPEAR: + case RK_WINDCUTTER: + /** + * Arch Bishop + **/ + case AB_DUPLELIGHT_MELEE: + /** + * Ranger + **/ + case RA_AIMEDBOLT: + /** + * Mechanic + **/ + case NC_AXEBOOMERANG: + case NC_POWERSWING: + /** + * Guilotinne Cross + **/ + case GC_CROSSIMPACT: + case GC_VENOMPRESSURE: + + skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); + break; + + /** + * Mechanic (MADO GEAR) + **/ + case NC_BOOSTKNUCKLE: + case NC_PILEBUNKER: + case NC_VULCANARM: + case NC_COLDSLOWER: + case NC_ARMSCANNON: + if (sd) pc_overheat(sd,1); skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); break; @@ -2637,6 +3006,8 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int } break; + case NC_FLAMELAUNCHER: + if (sd) pc_overheat(sd,1); case SN_SHARPSHOOTING: case MA_SHARPSHOOTING: case NJ_KAMAITACHI: @@ -2766,6 +3137,35 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int case NPC_PULSESTRIKE: case NPC_HELLJUDGEMENT: case NPC_VAMPIRE_GIFT: + /** + * Rune Knight + **/ + case RK_IGNITIONBREAK: + /** + * Arch Bishop + **/ + case AB_JUDEX: + /** + * Warlock + **/ + case WL_SOULEXPANSION: + case WL_CRIMSONROCK: + case WL_COMET: + /** + * Ranger + **/ + case RA_ARROWSTORM: + case RA_WUGDASH: + /** + * Mechanic + **/ + case NC_SELFDESTRUCTION: + case NC_AXETORNADO: + /** + * Guilotine Cross + **/ + case GC_ROLLINGCUTTER: + case GC_COUNTERSLASH: if( flag&1 ) { //Recursive invocation // skill_area_temp[0] holds number of targets in area @@ -2792,7 +3192,10 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int skill_area_temp[0] = 0; skill_area_temp[1] = bl->id; skill_area_temp[2] = 0; - + if( skillid == WL_CRIMSONROCK ) { + skill_area_temp[4] = bl->x; + skill_area_temp[5] = bl->y; + } // if skill damage should be split among targets, count them //SD_LEVEL -> Forced splash damage for Auto Blitz-Beat -> count targets //special case: Venom Splasher uses a different range for searching than for splashing @@ -2800,7 +3203,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int skill_area_temp[0] = map_foreachinrange(skill_area_sub, bl, (skillid == AS_SPLASHER)?1:skill_get_splash(skillid, skilllv), BL_CHAR, src, skillid, skilllv, tick, BCT_ENEMY, skill_area_sub_count); // recursive invocation of skill_castend_damage_id() with flag|1 - map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), splash_target(src), src, skillid, skilllv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); + map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), (skillid == WL_CRIMSONROCK)?BL_CHAR|BL_SKILL:splash_target(src), src, skillid, skilllv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); //FIXME: Isn't EarthQuake a ground skill after all? if( skillid == NPC_EARTHQUAKE ) @@ -2920,6 +3323,20 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int case NJ_KOUENKA: case NJ_HYOUSENSOU: case NJ_HUUJIN: +#if FIREIVY_ON + case WZ_FIREIVY: +#endif + /** + * Arch Bishop + **/ + case AB_ADORAMUS: + case AB_RENOVATIO: + case AB_HIGHNESSHEAL: + case AB_DUPLELIGHT_MAGIC: + /** + * Warlock + **/ + case WL_HELLINFERNO: skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag); break; @@ -3006,6 +3423,10 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int case NPC_SMOKING: case GS_FLING: case NJ_ZENYNAGE: + /** + * Rune Knight + **/ + case RK_DRAGONBREATH: skill_attack(BF_MISC,src,src,bl,skillid,skilllv,tick,flag); break; @@ -3062,6 +3483,330 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int status_change_end(src, SC_HIDING, INVALID_TIMER); skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); break; + /** + * Rune Knight + **/ + case RK_PHANTOMTHRUST: + unit_setdir(src,map_calc_dir(src, bl->x, bl->y)); + clif_skill_nodamage(src,bl,skillid,skilllv,1); + + skill_blown(src,bl,distance_bl(src,bl)-1,unit_getdir(src),0); + if( battle_check_target(src,bl,BCT_ENEMY) ) + skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); + break; + + case RK_STORMBLAST: + case RK_CRUSHSTRIKE: + if( sd ) { + if( pc_checkskill(sd,RK_RUNEMASTERY) >= ( skillid == RK_CRUSHSTRIKE ? 7 : 3 ) ) + skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); + else + clif_skill_fail(sd,skillid,0,0); + } else //non-sd support + skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); + break; + /** + * Guilotinne Cross + **/ + case GC_DARKILLUSION: + { + short x, y; + short dir = map_calc_dir(src,bl->x,bl->y); + + if( dir > 4 ) x = -1; + else if( dir > 0 && dir < 4 ) x = 1; + else x = 0; + if( dir < 3 || dir > 5 ) y = -1; + else if( dir > 3 && dir < 5 ) y = 1; + else y = 0; + + if( unit_movepos(src, bl->x+x, bl->y+y, 1, 1) ) + { + clif_slide(src,bl->x+x,bl->y+y); + clif_fixpos(src); // the official server send these two packts. + skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); + if( rand()%100 < 4 * skilllv ) + skill_castend_damage_id(src,bl,GC_CROSSIMPACT,skilllv,tick,flag); + } + + } + break; + + case GC_WEAPONCRUSH: + if( sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == GC_WEAPONBLOCKING ) + skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); + else if( sd ) + clif_skill_fail(sd,skillid,0x1f,0); + break; + + case GC_CROSSRIPPERSLASHER: + if( sd && !(sc && sc->data[SC_ROLLINGCUTTER]) ) + clif_skill_fail(sd,skillid,0x17,0); + else + { + skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); + status_change_end(src,SC_ROLLINGCUTTER,-1); + } + break; + + case GC_PHANTOMMENACE: + if( flag&1 ) + { // Only Hits Invisible Targets + struct status_change *tsc = status_get_sc(bl); + if(tsc && (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC__INVISIBILITY]) ) + skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); + } + break; + /** + * Warlock + **/ + case WL_CHAINLIGHTNING: + clif_skill_nodamage(src,bl,skillid,skilllv,1); + skill_addtimerskill(src,tick + 150,bl->id,3,0,WL_CHAINLIGHTNING_ATK,skilllv,4+skilllv,flag); + break; + case WL_DRAINLIFE: + { + int heal = skill_attack(skill_get_type(skillid), src, src, bl, skillid, skilllv, tick, flag); + int rate = 70 + 4 * skilllv + ( sd ? sd->status.job_level : 50 ) / 5; + + heal = 8 * skilllv; + if( status_get_lv(src) > 100 ) heal = heal * status_get_lv(src) / 100; // Base level bonus. + + if( bl->type == BL_SKILL ) + heal = 0; // Don't absorb heal from Ice Walls or other skill units. + + if( heal && rand()%100 < rate ) + { + status_heal(src, heal, 0, 0); + clif_skill_nodamage(NULL, src, AL_HEAL, heal, 1); + } + } + break; + + case WL_TETRAVORTEX: + if( sd ) + { + int spheres[5] = { 0, 0, 0, 0, 0 }, + positions[5] = {-1,-1,-1,-1,-1 }, + i, j = 0, k, subskill = 0; + + for( i = SC_SPHERE_1; i <= SC_SPHERE_5; i++ ) + if( sc && sc->data[i] ) + { + spheres[j] = i; + positions[j] = sc->data[i]->val2; + j++; // + } + + if( j < 4 ) + { // Need 4 spheres minimum + clif_skill_fail(sd,skillid,0,0); + break; + } + + // Sphere Sort, this time from new to old + for( i = 0; i <= j - 2; i++ ) + for( k = i + 1; k <= j - 1; k++ ) + if( positions[i] < positions[k] ) + { + swap(positions[i],positions[k]); + swap(spheres[i],spheres[k]); + } + + k = 0; + for( i = 0; i < 4; i++ ) + { + switch( sc->data[spheres[i]]->val1 ) + { + case WLS_FIRE: subskill = WL_TETRAVORTEX_FIRE; k |= 1; break; + case WLS_WIND: subskill = WL_TETRAVORTEX_WIND; k |= 4; break; + case WLS_WATER: subskill = WL_TETRAVORTEX_WATER; k |= 2; break; + case WLS_STONE: subskill = WL_TETRAVORTEX_GROUND; k |= 8; break; + } + + skill_addtimerskill(src,tick+status_get_adelay(src)*i,bl->id,k,0,subskill,skilllv,i,flag); + status_change_end(src, spheres[i], INVALID_TIMER); + } + } + break; + + case WL_RELEASE: + if( sd ) + { + int i; + // Priority is to release SpellBook + ARR_FIND(0,MAX_SPELLBOOK,i,sd->rsb[i].skillid != 0); + if( i < MAX_SPELLBOOK ) + { // SpellBook + int rsb_skillid, rsb_skilllv; + + if( skilllv > 1 ) + { + ARR_FIND(0,MAX_SPELLBOOK,i,sd->rsb[i].skillid == 0); + i--; // At skilllvl 2, Release uses the last learned skill in spellbook + } + + rsb_skillid = sd->rsb[i].skillid; + rsb_skilllv = sd->rsb[i].level; + + if( skilllv > 1 ) + sd->rsb[i].skillid = 0; // Last position - only remove it from list + else + memmove(&sd->rsb[0],&sd->rsb[1],sizeof(sd->rsb) - sizeof(sd->rsb[0])); + + if( sd->rsb[0].skillid == 0 ) + status_change_end(src, SC_READING_SB, INVALID_TIMER); + + status_change_end(src, SC_MAGICPOWER, INVALID_TIMER); + + clif_skill_nodamage(src,bl,skillid,skilllv,1); + if( !skill_check_condition_castbegin(sd,rsb_skillid,rsb_skilllv) ) + break; + + switch( skill_get_casttype(rsb_skillid) ) + { + case CAST_GROUND: + skill_castend_pos2(src,bl->x,bl->y,rsb_skillid,rsb_skilllv,tick,0); + break; + case CAST_NODAMAGE: + skill_castend_nodamage_id(src,bl,rsb_skillid,rsb_skilllv,tick,0); + break; + case CAST_DAMAGE: + skill_castend_damage_id(src,bl,rsb_skillid,rsb_skilllv,tick,0); + break; + } + + sd->ud.canact_tick = tick + skill_delayfix(src, rsb_skillid, rsb_skilllv); + clif_status_change(src, SI_ACTIONDELAY, 1, skill_delayfix(src, rsb_skillid, rsb_skilllv), 0, 0, 0); + } + else + { // Summon Balls + int j = 0, k, skele; + int spheres[5] = { 0, 0, 0, 0, 0 }, + positions[5] = {-1,-1,-1,-1,-1 }; + + for( i = SC_SPHERE_1; i <= SC_SPHERE_5; i++ ) + if( sc && sc->data[i] ) + { + spheres[j] = i; + positions[j] = sc->data[i]->val2; + sc->data[i]->val2--; // Prepares for next position + j++; + } + + if( j == 0 ) + { // No Spheres + clif_skill_fail(sd,skillid,0,0); + break; + } + + // Sphere Sort + for( i = 0; i <= j - 2; i++ ) + for( k = i + 1; k <= j - 1; k++ ) + if( positions[i] > positions[k] ) + { + swap(positions[i],positions[k]); + swap(spheres[i],spheres[k]); + } + + status_change_end(src, SC_MAGICPOWER, INVALID_TIMER); + + if( skilllv == 1 ) j = 1; // Limit only to one ball + for( i = 0; i < j; i++ ) + { + skele = WL_RELEASE - 5 + sc->data[spheres[i]]->val1 - WLS_FIRE; // Convert Ball Element into Skill ATK for balls + // WL_SUMMON_ATK_FIRE, WL_SUMMON_ATK_WIND, WL_SUMMON_ATK_WATER, WL_SUMMON_ATK_GROUND + skill_addtimerskill(src,tick+status_get_adelay(src)*i,bl->id,0,0,skele,sc->data[spheres[i]]->val3,BF_MAGIC,flag|SD_LEVEL); + status_change_end(src, spheres[i], INVALID_TIMER); // Eliminate ball + } + clif_skill_nodamage(src,bl,skillid,0,1); + } + } + break; + case WL_FROSTMISTY: + { + struct status_change *tsc = status_get_sc(bl); + if( tsc && (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC__INVISIBILITY]) ) + break; // Doesn't hit/cause Freezing to invisible enemy + // Causes Freezing status through walls. + sc_start(bl,status_skill2sc(skillid),20+12*skilllv+(sd ? sd->status.job_level : 50)/5,skilllv,skill_get_time(skillid,skilllv)); + // Doesn't deal damage through non-shootable walls. + if( path_search(NULL,src->m,src->x,src->y,bl->x,bl->y,1,CELL_CHKWALL) ) + skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag); + } + break; + + case WL_JACKFROST: { + struct status_change *tsc = status_get_sc(bl); + if( tsc && (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC__INVISIBILITY]) ) + break; // Do not hit invisible enemy + skill_attack(skill_get_type(skillid), src, src, bl, skillid, skilllv, tick, flag); + } + break; + /** + * Ranger + **/ + case RA_WUGSTRIKE: + case RA_WUGBITE: + if( path_search(NULL,src->m,src->x,src->y,bl->x,bl->y,1,CELL_CHKNOREACH) ) { + if( skillid == RA_WUGSTRIKE ) { + if( sd && pc_isridingwug(sd) && !map_flag_gvg(src->m) && !map[src->m].flag.battleground && unit_movepos(src,bl->x,bl->y,1,1) ) + clif_slide(src, bl->x, bl->y); + } + skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); + } + break; + + case RA_SENSITIVEKEEN: + if( bl->type != BL_SKILL ) { // Only Hits Invisible Targets + struct status_change * tsc = status_get_sc(bl); + if(tsc && (tsc->option&(OPTION_HIDE|OPTION_CLOAK) || tsc->data[SC__INVISIBILITY]) ) + skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); + } + else + { + struct skill_unit *su = BL_CAST(BL_SKILL,bl); + struct skill_unit_group* sg; + + if( su && (sg=su->group) && skill_get_inf2(sg->skill_id)&INF2_TRAP && sg->src_id != src->id && + battle_check_target(src, map_id2bl(sg->src_id), BCT_ENEMY) > 0 ) + { + if( sd && !(sg->unit_id == UNT_USED_TRAPS || (sg->unit_id == UNT_ANKLESNARE && sg->val2 != 0 )) ) + { + struct item item_tmp; + memset(&item_tmp,0,sizeof(item_tmp)); + item_tmp.nameid = ( sg->unit_id >= UNT_MAGENTATRAP && sg->unit_id <= UNT_CLUSTERBOMB )?ITEMID_TRAP_ALLOY:ITEMID_TRAP; + item_tmp.identify = 1; + if( item_tmp.nameid ) + map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + } + skill_delunit(su); + } + } + break; + /** + * Mechanic + **/ + case NC_INFRAREDSCAN: + if( flag&1 ) + { //TODO: Need a confirmation if the other type of hidden status is included to be scanned. [Jobbie] + if( rand()%100 < 50 ) + sc_start(bl, SC_INFRAREDSCAN, 10000, skilllv, skill_get_time(skillid, skilllv)); + status_change_end(bl, SC_HIDING, -1); + status_change_end(bl, SC_CLOAKING, -1); + status_change_end(bl, SC_CLOAKINGEXCEED, -1); // Need confirm it. + } + else + { + map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), splash_target(src), src, skillid, skilllv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); + clif_skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6); + if( sd ) pc_overheat(sd,1); + } + break; + + case NC_MAGNETICFIELD: + sc_start2(bl,SC_MAGNETICFIELD,100,skilllv,src->id,skill_get_time(skillid,skilllv)); + break; case 0: if(sd) { if (flag & 3){ @@ -3153,6 +3898,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case AL_HEAL: case ALL_RESURRECTION: case PR_ASPERSIO: + /** + * Arch Bishop + **/ + case AB_RENOVATIO: + case AB_HIGHNESSHEAL: //Apparently only player casted skills can be offensive like this. if (sd && battle_check_undead(tstatus->race,tstatus->def_ele)) { if (battle_check_target(src, bl, BCT_ENEMY) < 1) { @@ -3186,11 +3936,17 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in { case HLIF_HEAL: //[orn] case AL_HEAL: + /** + * Arch Bishop + **/ + case AB_HIGHNESSHEAL: { int heal = skill_calc_heal(src, bl, skillid, skilllv, true); int heal_get_jobexp; - if( status_isimmune(bl) || (dstmd && (dstmd->class_ == MOBID_EMPERIUM || mob_is_battleground(dstmd))) ) + if( status_isimmune(bl) || + (dstmd && (dstmd->class_ == MOBID_EMPERIUM || mob_is_battleground(dstmd))) || + (skillid == AL_HEAL && dstsd && dstsd->sc.option&OPTION_MADOGEAR) )//Mado is immune to AL_HEAL heal=0; if( sd && dstsd && sd->status.partner_id == dstsd->status.char_id && (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.sex == 0 ) @@ -3599,7 +4355,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in sc_start4(src,SC_WATK_ELEMENT,100,3,20,0,0,skill_get_time2(skillid, skilllv)); if (sd) skill_blockpc_start (sd, skillid, skill_get_time(skillid, skilllv)); break; - + case ASC_EDP: + clif_skill_nodamage(src,bl,skillid,skilllv, + sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv) + ( sd ? 3000 * pc_checkskill(sd,GC_RESEARCHNEWPOISON) : 0 ))); + break; case AL_INCAGI: case AL_BLESSING: case MER_INCAGI: @@ -3640,7 +4399,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case HW_MAGICPOWER: case PF_MEMORIZE: case PA_SACRIFICE: - case ASC_EDP: case PF_DOUBLECASTING: case SG_SUN_COMFORT: case SG_MOON_COMFORT: @@ -3657,6 +4415,32 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case ST_PRESERVE: case NPC_INVINCIBLE: case NPC_INVINCIBLEOFF: + /** + * Rune Knight + **/ + case RK_DEATHBOUND: + /** + * Arch Bishop + **/ + case AB_RENOVATIO: + case AB_EXPIATIO: + case AB_DUPLELIGHT: + case AB_SECRAMENT: + /** + * Mechanic + **/ + case NC_ACCELERATION: + case NC_HOVERING: + case NC_SHAPESHIFT: + /** + * Warlock + **/ + case WL_RECOGNIZEDSPELL: + /** + * Guillotine Cross + **/ + case GC_VENOMIMPRESS: + clif_skill_nodamage(src,bl,skillid,skilllv, sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv))); break; @@ -3914,14 +4698,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case AM_PHARMACY: if(sd) { - clif_skill_produce_mix_list(sd,22); + clif_skill_produce_mix_list(sd,skillid,22); clif_skill_nodamage(src,bl,skillid,skilllv,1); } break; case SA_CREATECON: if(sd) { - clif_skill_produce_mix_list(sd,23); + clif_skill_produce_mix_list(sd,skillid,23); clif_skill_nodamage(src,bl,skillid,skilllv,1); } break; @@ -3942,12 +4726,32 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case ASC_METEORASSAULT: case GS_SPREADATTACK: + /** + * Rune Knight + **/ + case RK_STORMBLAST: + /** + * Mechanic + **/ + case NC_AXETORNADO: + /** + * Guilotine Cross + **/ + case GC_COUNTERSLASH: skill_area_temp[1] = 0; clif_skill_nodamage(src,bl,skillid,skilllv,1); - map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), splash_target(src), + i = map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), splash_target(src), src, skillid, skilllv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); + if( !i && skillid == NC_AXETORNADO ) + clif_skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6); break; + case NC_EMERGENCYCOOL: + clif_skill_nodamage(src,bl,skillid,skilllv,1); + status_change_end(src,SC_OVERHEAT_LIMITPOINT,-1); + status_change_end(src,SC_OVERHEAT,-1); + break; + case NC_INFRAREDSCAN: case NPC_EARTHQUAKE: case NPC_VAMPIRE_GIFT: case NPC_HELLJUDGEMENT: @@ -4091,6 +4895,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in clif_skill_nodamage(src,bl,skillid,-1,status_change_end(bl, type, INVALID_TIMER)); //Hide skill-scream animation. map_freeblock_unlock(); return 0; + } else if( tsc && tsc->option&OPTION_MADOGEAR ) { + //Mado Gear cannot hide + if( sd ) clif_skill_fail(sd,skillid,0,0); + map_freeblock_unlock(); + return 0; } clif_skill_nodamage(src,bl,skillid,-1,sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv))); break; @@ -4106,6 +4915,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in clif_walkok(sd); // So aegis has to resend the walk ok. break; case AS_CLOAKING: + case RA_CAMOUFLAGE: + /** + * Guilotine Cross + **/ + case GC_CLOAKINGEXCEED: if (tsce) { i = status_change_end(bl, type, INVALID_TIMER); @@ -4425,6 +5239,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case RG_STRIPARMOR: case RG_STRIPHELM: case ST_FULLSTRIP: + case GC_WEAPONCRUSH: { unsigned short location = 0; int d = 0; @@ -4443,6 +5258,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in switch (skillid) { case RG_STRIPWEAPON: + case GC_WEAPONCRUSH: location = EQP_WEAPON; break; case RG_STRIPSHIELD: @@ -4460,14 +5276,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in } //Special message when trying to use strip on FCP [Jobbie] - if( sd && skillid == ST_FULLSTRIP && tsc && tsc->data[SC_CP_WEAPON] && tsc->data[SC_CP_HELM] && tsc->data[SC_CP_ARMOR] && tsc->data[SC_CP_SHIELD] ) + if( sd && skillid == ST_FULLSTRIP && tsc && tsc->data[SC_CP_WEAPON] && tsc->data[SC_CP_HELM] && tsc->data[SC_CP_ARMOR] && tsc->data[SC_CP_SHIELD]) { clif_gospel_info(sd, 0x28); break; } //Attempts to strip at rate i and duration d - if( (i = skill_strip_equip(bl, location, i, skilllv, d)) || skillid != ST_FULLSTRIP ) + if( (i = skill_strip_equip(bl, location, i, skilllv, d)) || (skillid != ST_FULLSTRIP && skillid != GC_WEAPONCRUSH ) ) clif_skill_nodamage(src,bl,skillid,skilllv,i); //Nothing stripped. @@ -4631,7 +5447,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in clif_skill_nodamage(src,bl,skillid,skilllv,1); if((dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER) || (tsc && tsc->data[SC_SPIRIT] && tsc->data[SC_SPIRIT]->val2 == SL_ROGUE) //Rogue's spirit defends againt dispel. - || rand()%100 >= 50+10*skilllv) + || rand()%100 >= 50+10*skilllv + || ( tsc && tsc->option&OPTION_MADOGEAR ) )//Mado Gear is immune to dispell according to bug report 49 [Ind] { if (sd) clif_skill_fail(sd,skillid,0,0); @@ -5654,27 +6471,631 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in clif_skill_nodamage(src, bl, skillid, skilllv, buyingstore_setup(sd, MAX_BUYINGSTORE_SLOTS)); } break; - default: - ShowWarning("skill_castend_nodamage_id: Unknown skill used:%d\n",skillid); - clif_skill_nodamage(src,bl,skillid,skilllv,1); - map_freeblock_unlock(); - return 1; - } - - if (dstmd) { //Mob skill event for no damage skills (damage ones are handled in battle_calc_damage) [Skotlex] - mob_log_damage(dstmd, src, 0); //Log interaction (counts as 'attacker' for the exp bonus) - mobskill_event(dstmd, src, tick, MSC_SKILLUSED|(skillid<<16)); - } + case RK_ENCHANTBLADE: + clif_skill_nodamage(src,bl,skillid,skilllv,// formula not confirmed + sc_start2(bl,type,100,skilllv,100+20*skilllv/*+sstatus->int_/2+status_get_lv(bl)/10*/,skill_get_time(skillid,skilllv))); + break; + case RK_DRAGONHOWLING: + if( flag&1) + sc_start(bl,type,50 + 6 * skilllv,skilllv,skill_get_time(skillid,skilllv)); + else + { + skill_area_temp[2] = 0; + clif_skill_nodamage(src,bl,skillid,skilllv,1); + map_foreachinrange(skill_area_sub, src, + skill_get_splash(skillid,skilllv),BL_CHAR, + src,skillid,skilllv,tick,flag|BCT_ENEMY|SD_PREAMBLE|1, + skill_castend_nodamage_id); + } + break; + case RK_IGNITIONBREAK: + //case LG_EARTHDRIVE: + clif_skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6); + //if( skillid == LG_EARTHDRIVE ) + //{ + // int dummy = 1; + // i = skill_get_splash(skillid,skilllv); + // map_foreachinarea(skill_cell_overlap, src->m, src->x-i, src->y-i, src->x+i, src->y+i, BL_SKILL, LG_EARTHDRIVE, &dummy, src); + //} + map_foreachinrange(skill_area_sub, bl,skill_get_splash(skillid,skilllv),BL_CHAR, + src,skillid,skilllv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id); + break; + case RK_STONEHARDSKIN: + if( sd && pc_checkskill(sd,RK_RUNEMASTERY) >= 4 ) + { + int heal = sstatus->hp / 4; // 25% HP + if( status_charge(bl,heal,0) ) + clif_skill_nodamage(src,bl,skillid,skilllv,sc_start2(bl,type,100,skilllv,heal,skill_get_time(skillid,skilllv))); + else + clif_skill_fail(sd,skillid,0,0); + } + break; + case RK_REFRESH: + if( sd && pc_checkskill(sd,RK_RUNEMASTERY) >= 8 ) + { + int heal = status_get_max_hp(bl) * 25 / 100; + clif_skill_nodamage(src,bl,skillid,skilllv, + sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv))); + status_heal(bl,heal,0,1); + status_change_clear_buffs(bl,2); + } + break; - if( sd && !(flag&1) ) - { - if( sd->state.arrow_atk ) //Consume arrow on last invocation to this skill. - battle_consume_ammo(sd, skillid, skilllv); - skill_onskillusage(sd, bl, skillid, tick); - skill_consume_requirement(sd,skillid,skilllv,2); - } + case RK_MILLENNIUMSHIELD: + if( sd && pc_checkskill(sd,RK_RUNEMASTERY) >= 9 ) + { + short shields = (rand()%100<50) ? 4 : ((rand()%100<80) ? 3 : 2); + sc_start4(bl,type,100,skilllv,shields,1000,0,skill_get_time(skillid,skilllv)); + clif_millenniumshield(sd,shields); + clif_skill_nodamage(src,bl,skillid,1,1); + } + break; - map_freeblock_unlock(); + case RK_GIANTGROWTH: + case RK_VITALITYACTIVATION: + case RK_ABUNDANCE: + if( sd ) + { + int lv = 1; // RK_GIANTGROWTH + if( skillid == RK_VITALITYACTIVATION ) + lv = 2; + else if( skillid == RK_ABUNDANCE ) + lv = 6; + if( pc_checkskill(sd,RK_RUNEMASTERY) >= lv ) + clif_skill_nodamage(src,bl,skillid,skilllv,sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv))); + } + break; + + case RK_FIGHTINGSPIRIT: + if( flag&1 ) { + if( src == bl ) + sc_start2(bl,type,100,skill_area_temp[5],10*(sd?pc_checkskill(sd,RK_RUNEMASTERY):10),skill_get_time(skillid,skilllv)); + else + sc_start(bl,type,100,skill_area_temp[5]/4,skill_get_time(skillid,skilllv)); + } else if( sd && pc_checkskill(sd,RK_RUNEMASTERY) >= 5 ) { + if( sd->status.party_id ) { + i = party_foreachsamemap(skill_area_sub,sd,skill_get_splash(skillid,skilllv),src,skillid,skilllv,tick,BCT_PARTY,skill_area_sub_count); + skill_area_temp[5] = 7 * i; // ATK + party_foreachsamemap(skill_area_sub,sd,skill_get_splash(skillid,skilllv),src,skillid,skilllv,tick,flag|BCT_PARTY|1,skill_castend_nodamage_id); + } else + sc_start2(bl,type,100,7,5,skill_get_time(skillid,skilllv)); + } + clif_skill_nodamage(src,bl,skillid,1,1); + break; + /** + * Guilotine Cross + **/ + case GC_ROLLINGCUTTER: + { + short count = 1; + skill_area_temp[2] = 0; + map_foreachinrange(skill_area_sub,src,skill_get_splash(skillid,skilllv),BL_CHAR,src,skillid,skilllv,tick,flag|BCT_ENEMY|SD_PREAMBLE|SD_SPLASH|1,skill_castend_damage_id); + if( tsc && tsc->data[SC_ROLLINGCUTTER] ) + { // Every time the skill is casted the status change is reseted adding a counter. + count += (short)tsc->data[SC_ROLLINGCUTTER]->val1; + if( count > 10 ) + count = 10; // Max coounter + status_change_end(bl, SC_ROLLINGCUTTER, INVALID_TIMER); + } + sc_start(bl,SC_ROLLINGCUTTER,100,count,skill_get_time(skillid,skilllv)); + clif_skill_nodamage(src,src,skillid,skilllv,1); + } + break; + + case GC_WEAPONBLOCKING: + if( tsc && tsc->data[SC_WEAPONBLOCKING] ) + status_change_end(bl, SC_WEAPONBLOCKING, INVALID_TIMER); + else + sc_start(bl,SC_WEAPONBLOCKING,100,skilllv,skill_get_time(skillid,skilllv)); + clif_skill_nodamage(src,bl,skillid,skilllv,1); + break; + + case GC_CREATENEWPOISON: + if( sd ) + { + clif_skill_produce_mix_list(sd,skillid,25); + clif_skill_nodamage(src, bl, skillid, skilllv, 1); + } + break; + + case GC_POISONINGWEAPON: + if( sd ) { + clif_poison_list(sd,skilllv); + clif_skill_nodamage(src,bl,skillid,skilllv,1); + } + break; + + case GC_ANTIDOTE: + clif_skill_nodamage(src,bl,skillid,skilllv,1); + if( tsc ) + { + status_change_end(bl, SC_PARALYSE, INVALID_TIMER); + status_change_end(bl, SC_PYREXIA, INVALID_TIMER); + status_change_end(bl, SC_DEATHHURT, INVALID_TIMER); + status_change_end(bl, SC_LEECHESEND, INVALID_TIMER); + status_change_end(bl, SC_VENOMBLEED, INVALID_TIMER); + status_change_end(bl, SC_MAGICMUSHROOM, INVALID_TIMER); + status_change_end(bl, SC_TOXIN, INVALID_TIMER); + status_change_end(bl, SC_OBLIVIONCURSE, INVALID_TIMER); + } + break; + + case GC_PHANTOMMENACE: + clif_skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6); + clif_skill_nodamage(src,bl,skillid,skilllv,1); + map_foreachinrange(skill_area_sub,src,skill_get_splash(skillid,skilllv),BL_CHAR, + src,skillid,skilllv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id); + break; + + case GC_HALLUCINATIONWALK: + { + int heal = status_get_max_hp(bl) / 10; + if( status_get_hp(bl) < heal ) { // if you haven't enough HP skill fails. + if( sd ) clif_skill_fail(sd,skillid,0x02,0); + break; + } + if( !status_charge(bl,heal,0) ) + { + if( sd ) clif_skill_fail(sd,skillid,0x02,0); + break; + } + clif_skill_nodamage(src,bl,skillid,skilllv,sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv))); + } + break; + /** + * Arch Bishop + **/ + case AB_ANCILLA: + if( sd ) { + clif_skill_nodamage(src,bl,skillid,skilllv,1); + skill_produce_mix(sd, skillid, ITEMID_ANCILLA, 0, 0, 0, 1); + } + break; + + case AB_CLEMENTIA: + case AB_CANTO: + { + int bless_lv = pc_checkskill(sd,AL_BLESSING); + int agi_lv = pc_checkskill(sd,AL_INCAGI); + if( sd == NULL || sd->status.party_id == 0 || flag&1 ) + clif_skill_nodamage(bl, bl, skillid, skilllv, sc_start(bl,type,100, + (skillid == AB_CLEMENTIA)? bless_lv : (skillid == AB_CANTO)? agi_lv : skilllv, skill_get_time(skillid,skilllv))); + else if( sd ) + party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skillid, skilllv), src, skillid, skilllv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id); + } + break; + + case AB_PRAEFATIO: + if( sd == NULL || sd->status.party_id == 0 || flag&1 ) + clif_skill_nodamage(bl, bl, skillid, skilllv, sc_start4(bl, type, 100, skilllv, 0, 0, 1, skill_get_time(skillid, skilllv))); + else if( sd ) + party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skillid, skilllv), src, skillid, skilllv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id); + break; + + case AB_CHEAL: + if( sd == NULL || sd->status.party_id == 0 || flag&1 ) + { + if( sd && tstatus && !battle_check_undead(tstatus->race, tstatus->def_ele) ) + { + i = skill_calc_heal(src, bl, AL_HEAL, pc_checkskill(sd, AL_HEAL), true); + status_heal(bl, i, 0, 1); + clif_skill_nodamage(bl, bl, skillid, i, 1); + } + } + else if( sd ) + party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skillid, skilllv), src, skillid, skilllv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id); + break; + + case AB_ORATIO: + if( flag&1 ) + sc_start(bl, type, 40 + 5 * skilllv, skilllv, skill_get_time(skillid, skilllv)); + else + { + map_foreachinrange(skill_area_sub, src, skill_get_splash(skillid, skilllv), BL_CHAR, + src, skillid, skilllv, tick, flag|BCT_ENEMY|1, skill_castend_nodamage_id); + clif_skill_nodamage(src, bl, skillid, skilllv, 1); + } + break; + + case AB_LAUDAAGNUS: + if( flag&1 || sd == NULL ) + { + if( (tsc && (tsc->data[SC_FREEZE] || tsc->data[SC_STONE] || + tsc->data[SC_BLIND]))&& (rand()%100 < 30+5*skilllv) ) + { + status_change_end(bl, SC_FREEZE, -1); + status_change_end(bl, SC_STONE, -1); + status_change_end(bl, SC_BLIND, -1); + } + // Success rate only applies to the curing effect and not stat bonus. + clif_skill_nodamage(bl, bl, skillid, skilllv, + sc_start(bl, type, 100, skilllv, skill_get_time(skillid, skilllv))); + } + else if( sd ) + party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skillid, skilllv), + src, skillid, skilllv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id); + break; + + case AB_LAUDARAMUS: + if( flag&1 || sd == NULL ) + { + if( (tsc && (tsc->data[SC_SLEEP] || tsc->data[SC_STUN] || + tsc->data[SC_SILENCE]))&& (rand()%100 < 30+5*skilllv) ) + { + status_change_end(bl, SC_SLEEP, -1); + status_change_end(bl, SC_STUN, -1); + status_change_end(bl, SC_SILENCE, -1); + } + clif_skill_nodamage(bl, bl, skillid, skilllv, + sc_start(bl, type, 100, skilllv, skill_get_time(skillid, skilllv))); + //Success rate only applies to the curing effect and not stat bonus. + } + else if( sd ) + party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skillid, skilllv), + src, skillid, skilllv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id); + break; + + case AB_CLEARANCE: + if( flag&1 || (i = skill_get_splash(skillid, skilllv)) < 1 ) + { //As of the behavior in official server Clearance is just a super version of Dispell skill. [Jobbie] + clif_skill_nodamage(src,bl,skillid,skilllv,1); + if((dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER) || rand()%100 >= 30 + 10 * skilllv) + { + if (sd) + clif_skill_fail(sd,skillid,0,0); + break; + } + if(status_isimmune(bl) || !tsc || !tsc->count) + break; + for(i=0;idata[i]) + continue; + switch (i) { + case SC_WEIGHT50: case SC_WEIGHT90: case SC_HALLUCINATION: + case SC_STRIPWEAPON: case SC_STRIPSHIELD: case SC_STRIPARMOR: + case SC_STRIPHELM: case SC_CP_WEAPON: case SC_CP_SHIELD: + case SC_CP_ARMOR: case SC_CP_HELM: case SC_COMBO: + case SC_STRFOOD: case SC_AGIFOOD: case SC_VITFOOD: + case SC_INTFOOD: case SC_DEXFOOD: case SC_LUKFOOD: + case SC_HITFOOD: case SC_FLEEFOOD: case SC_BATKFOOD: + case SC_WATKFOOD: case SC_MATKFOOD: case SC_DANCING: + case SC_GUILDAURA: case SC_SPIRIT: case SC_AUTOBERSERK: + case SC_CARTBOOST: case SC_MELTDOWN: case SC_SAFETYWALL: + case SC_SMA: case SC_SPEEDUP0: case SC_NOCHAT: + case SC_ANKLE: case SC_SPIDERWEB: case SC_JAILED: + case SC_ITEMBOOST: case SC_EXPBOOST: case SC_LIFEINSURANCE: + case SC_BOSSMAPINFO: case SC_PNEUMA: case SC_AUTOSPELL: + case SC_INCHITRATE: case SC_INCATKRATE: case SC_NEN: + case SC_READYSTORM: case SC_READYDOWN: case SC_READYTURN: + case SC_READYCOUNTER:case SC_DODGE: case SC_WARM: + case SC_SPEEDUP1: case SC_AUTOTRADE: case SC_CRITICALWOUND: + case SC_JEXPBOOST: case SC_INVINCIBLE: case SC_INVINCIBLEOFF: + case SC_HELLPOWER: case SC_MANU_ATK: case SC_MANU_DEF: + case SC_SPL_ATK: case SC_SPL_DEF: case SC_MANU_MATK: + case SC_SPL_MATK: case SC_RICHMANKIM: case SC_ETERNALCHAOS: + case SC_DRUMBATTLE: case SC_NIBELUNGEN: case SC_ROKISWEIL: + case SC_INTOABYSS: case SC_SIEGFRIED: case SC_WHISTLE: + case SC_ASSNCROS: case SC_POEMBRAGI: case SC_APPLEIDUN: + case SC_HUMMING: case SC_DONTFORGETME: case SC_FORTUNE: + case SC_SERVICE4U: case SC_FOOD_STR_CASH: case SC_FOOD_AGI_CASH: + case SC_FOOD_VIT_CASH: case SC_FOOD_DEX_CASH: case SC_FOOD_INT_CASH: + case SC_FOOD_LUK_CASH: /* case SC_ELECTRICSHOCKER: case SC_BITE: + case SC__STRIPACCESSORY: case SC__ENERVATION: case SC__GROOMY: + case SC__IGNORANCE: case SC__LAZINESS: case SC__UNLUCKY: + case SC__WEAKNESS: case SC_SAVAGE_STEAK: case SC_COCKTAIL_WARG_BLOOD: + case SC_MAGNETICFIELD:case SC_MINOR_BBQ: case SC_SIROMA_ICE_TEA: + case SC_DROCERA_HERB_STEAMED: case SC_PUTTI_TAILS_NOODLES: + case SC_NEUTRALBARRIER_MASTER: case SC_NEUTRALBARRIER: + case SC_STEALTHFIELD_MASTER: case SC_STEALTHFIELD: */ + continue; + case SC_ASSUMPTIO: + if( bl->type == BL_MOB ) + continue; + break; + } + if(i==SC_BERSERK /*|| i==SC_SATURDAYNIGHTFEVER*/) tsc->data[i]->val2=0; //Mark a dispelled berserk to avoid setting hp to 100 by setting hp penalty to 0. + status_change_end(bl,(sc_type)i,-1); + } + break; + } + map_foreachinrange(skill_area_sub, bl, i, BL_CHAR, src, skillid, skilllv, tick, flag|1, skill_castend_damage_id); + break; + + case AB_SILENTIUM: + // Should the level of Lex Divina be equivalent to the level of Silentium or should the highest level learned be used? [LimitLine] + map_foreachinrange(skill_area_sub, src, skill_get_splash(skillid, skilllv), BL_CHAR, + src, PR_LEXDIVINA, skilllv, tick, flag|BCT_ENEMY|1, skill_castend_nodamage_id); + clif_skill_nodamage(src, bl, skillid, skilllv, 1); + break; + /** + * Warlock + **/ + case WL_STASIS: + if( flag&1 ) + sc_start2(bl,type,100,skilllv,src->id,skill_get_time(skillid,skilllv)); + else + { + map_foreachinrange(skill_area_sub,src,skill_get_splash(skillid, skilllv),BL_CHAR,src,skillid,skilllv,tick,(map_flag_vs(src->m)?BCT_ALL:BCT_ENEMY|BCT_SELF)|flag|1,skill_castend_nodamage_id); + clif_skill_nodamage(src, bl, skillid, skilllv, 1); + } + break; + + case WL_WHITEIMPRISON: + if( !(tsc && tsc->data[type]) && (src == bl || battle_check_target(src, bl, BCT_ENEMY)) ) + { + int rate = 50 + 3 * skilllv + ( sd? sd->status.job_level : 50 ) / 4; + i = sc_start2(bl,type,rate,skilllv,src->id,(src == bl)?skill_get_time2(skillid,skilllv):skill_get_time(skillid, skilllv)); + clif_skill_nodamage(src,bl,skillid,skilllv,i); + if( sd && i ) + skill_blockpc_start(sd,skillid,4000); // Reuse Delay only activated on success + } + else if( sd ) + clif_skill_fail(sd,skillid,0,0); + break; + + case WL_FROSTMISTY: + clif_skill_nodamage(src,bl,skillid,skilllv,1); + map_foreachinrange(skill_area_sub,bl,skill_get_splash(skillid,skilllv),BL_CHAR|BL_SKILL,src,skillid,skilllv,tick,flag|BCT_ENEMY,skill_castend_damage_id); + break; + + case WL_JACKFROST: + clif_skill_nodamage(src,bl,skillid,skilllv,1); + map_foreachinshootrange(skill_area_sub,bl,skill_get_splash(skillid,skilllv),BL_CHAR|BL_SKILL,src,skillid,skilllv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id); + break; + + case WL_MARSHOFABYSS: + // Should marsh of abyss still apply half reduction to players after the 28/10 patch? [LimitLine] + clif_skill_nodamage(src, bl, skillid, skilllv, + sc_start4(bl, type, 100, skilllv, status_get_int(src), sd ? sd->status.job_level : 50, 0, + skill_get_time(skillid, skilllv))); + break; + + case WL_SIENNAEXECRATE: + if( status_isimmune(bl) || !tsc ) + break; + + if( flag&1 ) + { + if( bl->id == skill_area_temp[1] ) + break; // Already work on this target + + if( tsc && tsc->data[SC_STONE] ) + status_change_end(bl,SC_STONE,-1); + else + status_change_start(bl,SC_STONE,10000,skilllv,0,0,1000,(8+2*skilllv)*1000,2); + } + else + { + int rate = 40 + 8 * skilllv + ( sd? sd->status.job_level : 50 ) / 4; + // IroWiki says Rate should be reduced by target stats, but currently unknown + if( rand()%100 < rate ) + { // Success on First Target + rate = 0; + if( !tsc->data[SC_STONE] ) + rate = status_change_start(bl,SC_STONE,10000,skilllv,0,0,1000,(8+2*skilllv)*1000,2); + else + { + rate = 1; + status_change_end(bl,SC_STONE,-1); + } + + if( rate ) + { + skill_area_temp[1] = bl->id; + map_foreachinrange(skill_area_sub,bl,skill_get_splash(skillid,skilllv),BL_CHAR,src,skillid,skilllv,tick,flag|BCT_ENEMY|1,skill_castend_nodamage_id); + } + // Doesn't send failure packet if it fails on defense. + } + else if( sd ) // Failure on Rate + clif_skill_fail(sd,skillid,0,0); + } + break; + + case WL_SUMMONFB: + case WL_SUMMONBL: + case WL_SUMMONWB: + case WL_SUMMONSTONE: + { + short element = 0, sctype = 0, pos = -1; + struct status_change *sc = status_get_sc(src); + if( !sc ) break; + + for( i = SC_SPHERE_1; i <= SC_SPHERE_5; i++ ) + { + if( !sctype && !sc->data[i] ) + sctype = i; // Take the free SC + if( sc->data[i] ) + pos = max(sc->data[i]->val2,pos); + } + + if( !sctype ) + { + if( sd ) // No free slots to put SC + clif_skill_fail(sd,skillid,0x13,0); + break; + } + + pos++; // Used in val2 for SC. Indicates the order of this ball + switch( skillid ) + { // Set val1. The SC element for this ball + case WL_SUMMONFB: element = WLS_FIRE; break; + case WL_SUMMONBL: element = WLS_WIND; break; + case WL_SUMMONWB: element = WLS_WATER; break; + case WL_SUMMONSTONE: element = WLS_STONE; break; + } + + sc_start4(src,sctype,100,element,pos,skilllv,0,skill_get_time(skillid,skilllv)); + clif_skill_nodamage(src,bl,skillid,0,0); + } + break; + + case WL_READING_SB: + if( sd ) + { + int i, preserved = 0, max_preserve = 4 * pc_checkskill(sd,WL_FREEZE_SP) + sstatus->int_ / 10 + sd->status.base_level / 10; + ARR_FIND(0, MAX_SPELLBOOK, i, sd->rsb[i].skillid == 0); // Search for a Free Slot + if( i == MAX_SPELLBOOK ) + { + clif_skill_fail(sd,skillid,0x04,0); + break; + } + for( i = 0; i < MAX_SPELLBOOK && sd->rsb[i].skillid; i++ ) + preserved += sd->rsb[i].points; + + if( preserved >= max_preserve ) + { + clif_skill_fail(sd,skillid,0x04,0); + break; + } + + sc_start(bl,SC_STOP,100,skilllv,-1); //Can't move while selecting a spellbook. + clif_spellbook_list(sd); + clif_skill_nodamage(src,bl,skillid,skilllv,1); + } + break; + /** + * Ranger + **/ + case RA_FEARBREEZE: + clif_skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6); + clif_skill_nodamage(src, bl, skillid, skilllv, sc_start(bl, type, 100, skilllv, skill_get_time(skillid, skilllv))); + break; + + case RA_WUGMASTERY: + if( sd ) + { + if( pc_isridingwug(sd) ) + clif_skill_fail(sd,skillid,0,0); + else if( !pc_iswug(sd) ) + pc_setoption(sd,sd->sc.option|OPTION_WUG); + else + pc_setoption(sd,sd->sc.option&~OPTION_WUG); + clif_skill_nodamage(src,bl,skillid,skilllv,1); + } + break; + + case RA_WUGRIDER: + if( sd ) { + if( !pc_isridingwug(sd) && pc_iswug(sd) ) { + pc_setoption(sd,sd->sc.option&~OPTION_WUG); + pc_setoption(sd,sd->sc.option|OPTION_WUGRIDER); + } else if( pc_isridingwug(sd) ) { + pc_setoption(sd,sd->sc.option&~OPTION_WUGRIDER); + pc_setoption(sd,sd->sc.option|OPTION_WUG); + } else if( sd ) { + clif_skill_fail(sd,skillid,0,0); + } + clif_skill_nodamage(src,bl,skillid,skilllv,1); + } + break; + + case RA_WUGDASH: + if( tsce ) { + clif_skill_nodamage(src,bl,skillid,skilllv,status_change_end(bl, type, -1)); + map_freeblock_unlock(); + return 0; + } + if( sd && pc_isridingwug(sd) ) { + clif_skill_nodamage(src,bl,skillid,skilllv,sc_start4(bl,type,100,skilllv,unit_getdir(bl),0,0,1)); + clif_walkok(sd); + } + break; + + case RA_SENSITIVEKEEN: + clif_skill_nodamage(src,bl,skillid,skilllv,1); + clif_skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6); + map_foreachinrange(skill_area_sub,src,skill_get_splash(skillid,skilllv),BL_CHAR|BL_SKILL,src,skillid,skilllv,tick,flag|BCT_ENEMY,skill_castend_damage_id); + break; + /** + * Mechanic + **/ + case NC_F_SIDESLIDE: + case NC_B_SIDESLIDE: + { + int dir = (skillid == NC_F_SIDESLIDE) ? (unit_getdir(src)+4)%8 : unit_getdir(src); + skill_blown(src,bl,skill_get_blewcount(skillid,skilllv),dir,0x1); + clif_slide(src,src->x,src->y); + clif_fixpos(src); //Aegis sent this packet + clif_skill_nodamage(src,bl,skillid,skilllv,1); + } + break; + + case NC_SELFDESTRUCTION: + if( sd ) { + if( sd->sc.option&OPTION_MADOGEAR ) + pc_setoption(sd, sd->sc.option&~OPTION_MADOGEAR); + clif_skill_nodamage(src, bl, skillid, skilllv, 1); + skill_castend_damage_id(src, src, skillid, skilllv, tick, flag); + } + break; + + case NC_ANALYZE: + clif_skill_damage(src, bl, tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6); + clif_skill_nodamage(src, bl, skillid, skilllv, + sc_start(bl,type, 30 + 12 * skilllv,skilllv,skill_get_time(skillid,skilllv))); + if( sd ) pc_overheat(sd,1); + break; + + case NC_MAGNETICFIELD: + if( (i = sc_start2(bl,type,100,skilllv,src->id,skill_get_time(skillid,skilllv))) ) + { + map_foreachinrange(skill_area_sub,src,skill_get_splash(skillid,skilllv),splash_target(src),src,skillid,skilllv,tick,flag|BCT_ENEMY|SD_SPLASH|1,skill_castend_damage_id);; + clif_skill_damage(src,src,tick,status_get_amotion(src),0,-30000,1,skillid,skilllv,6); + pc_overheat(sd,1); + } + clif_skill_nodamage(src,src,skillid,skilllv,i); + break; + + case NC_REPAIR: + if( sd ) + { + int heal; + if( dstsd && (dstsd->sc.option&OPTION_MADOGEAR) ) + { + heal = dstsd->status.max_hp * (3+3*skilllv) / 100; + status_heal(bl,heal,0,2); + } else { + heal = sd->status.max_hp * (3+3*skilllv) / 100; + status_heal(src,heal,0,2); + } + + clif_skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6); + clif_skill_nodamage(src, bl, skillid, skilllv, heal); + } + break; + + case NC_DISJOINT: + { + if( bl->type != BL_MOB ) break; + md = map_id2md(bl->id); + if( md && md->class_ >= 2042 && md->class_ <= 2046 ) + status_kill(bl); + clif_skill_nodamage(src, bl, skillid, skilllv, 1); + } + break; + + default: + ShowWarning("skill_castend_nodamage_id: Unknown skill used:%d\n",skillid); + clif_skill_nodamage(src,bl,skillid,skilllv,1); + map_freeblock_unlock(); + return 1; + } + + if (dstmd) { //Mob skill event for no damage skills (damage ones are handled in battle_calc_damage) [Skotlex] + mob_log_damage(dstmd, src, 0); //Log interaction (counts as 'attacker' for the exp bonus) + mobskill_event(dstmd, src, tick, MSC_SKILLUSED|(skillid<<16)); + } + + if( sd && !(flag&1) ) + { + if( sd->state.arrow_atk ) //Consume arrow on last invocation to this skill. + battle_consume_ammo(sd, skillid, skilllv); + skill_onskillusage(sd, bl, skillid, tick); + skill_consume_requirement(sd,skillid,skilllv,2); + } + + map_freeblock_unlock(); return 0; } @@ -5858,13 +7279,15 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) if (ud->state.running && ud->skillid == TK_JUMPKICK) flag = 1; - if (ud->walktimer != INVALID_TIMER && ud->skillid != TK_RUN) + if (ud->walktimer != INVALID_TIMER && ud->skillid != TK_RUN && ud->skillid != RA_WUGDASH) unit_stop_walking(src,1); if( !sd || sd->skillitem != ud->skillid || skill_get_delay(ud->skillid,ud->skilllv) ) ud->canact_tick = tick + skill_delayfix(src, ud->skillid, ud->skilllv); //Tests show wings don't overwrite the delay but skill scrolls do. [Inkfish] + if( sd && skill_get_cooldown(ud->skillid,ud->skilllv) > 0 ) + skill_blockpc_start(sd, ud->skillid, skill_get_cooldown(ud->skillid, ud->skilllv)); if( battle_config.display_status_timers && sd ) - clif_status_change(src, SI_ACTIONDELAY, 1, skill_delayfix(src, ud->skillid, ud->skilllv)); + clif_status_change(src, SI_ACTIONDELAY, 1, skill_delayfix(src, ud->skillid, ud->skilllv), 0, 0, 0); if( sd ) { switch( ud->skillid ) @@ -5900,7 +7323,7 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) sc = status_get_sc(src); if(sc && sc->count) { if(sc->data[SC_MAGICPOWER] && - ud->skillid != HW_MAGICPOWER && ud->skillid != WZ_WATERBALL) + ud->skillid != HW_MAGICPOWER && ud->skillid != WZ_WATERBALL && ud->skillid != WL_TETRAVORTEX) status_change_end(src, SC_MAGICPOWER, INVALID_TIMER); if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_WIZARD && @@ -6077,7 +7500,7 @@ int skill_castend_pos(int tid, unsigned int tick, int id, intptr_t data) if( !sd || sd->skillitem != ud->skillid || skill_get_delay(ud->skillid,ud->skilllv) ) ud->canact_tick = tick + skill_delayfix(src, ud->skillid, ud->skilllv); if( battle_config.display_status_timers && sd ) - clif_status_change(src, SI_ACTIONDELAY, 1, skill_delayfix(src, ud->skillid, ud->skilllv)); + clif_status_change(src, SI_ACTIONDELAY, 1, skill_delayfix(src, ud->skillid, ud->skilllv), 0, 0, 0); // if( sd ) // { // switch( ud->skillid ) @@ -6209,6 +7632,9 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk case MG_SAFETYWALL: case MG_FIREWALL: case MG_THUNDERSTORM: +#if FIREIVY_ON + case WZ_FIREIVY: +#endif case AL_PNEUMA: case WZ_ICEWALL: case WZ_FIREPILLAR: @@ -6271,6 +7697,17 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk case NJ_RAIGEKISAI: case NJ_KAMAITACHI: case NPC_EVILLAND: + /** + * Ranger + **/ + case RA_ELECTRICSHOCKER: + case RA_CLUSTERBOMB: + case RA_MAGENTATRAP: + case RA_COBALTTRAP: + case RA_MAIZETRAP: + case RA_VERDURETRAP: + case RA_FIRINGTRAP: + case RA_ICEBOUNDTRAP: flag|=1;//Set flag to 1 to prevent deleting ammo (it will be deleted on group-delete). case GS_GROUNDDRIFT: //Ammo should be deleted right away. skill_unitsetting(src,skillid,skilllv,x,y,0); @@ -6518,6 +7955,118 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk } } break; + /** + * Mechanic + **/ + case NC_COLDSLOWER: + case NC_ARMSCANNON: + /** + * Rune Knight + **/ + case RK_DRAGONBREATH: + case RK_WINDCUTTER: + i = skill_get_splash(skillid,skilllv); + map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,BL_CHAR, + src,skillid,skilllv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id); + break; + /** + * Guilotine Cross + **/ + case GC_POISONSMOKE: + if( !(sc && sc->data[SC_POISONINGWEAPON]) ) { + if( sd ) + clif_skill_fail(sd,skillid,0x20,0); + return 0; + } + clif_skill_damage(src,src,tick,status_get_amotion(src),0,-30000,1,skillid,skilllv,6); + skill_unitsetting(src, skillid, skilllv, x, y, flag); + status_change_end(src,SC_POISONINGWEAPON,-1); + break; + /** + * Arch Bishop + **/ + case AB_EPICLESIS: + if( (sg = skill_unitsetting(src, skillid, skilllv, x, y, 0)) ) { + i = sg->unit->range; + map_foreachinarea(skill_area_sub, src->m, x - i, y - i, x + i, y + i, BL_CHAR, src, ALL_RESURRECTION, 1, tick, flag|BCT_NOENEMY|1,skill_castend_nodamage_id); + } + break; + /** + * Warlock + **/ + case WL_COMET: + if( sc ) { + sc->comet_x = x; + sc->comet_y = y; + } + i = skill_get_splash(skillid,skilllv); + map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,BL_CHAR,src,skillid,skilllv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id); + break; + + case WL_EARTHSTRAIN: + { + int i, wave = skilllv + 4, dir = map_calc_dir(src,x,y); + int sx = x, sy = y; + + if( sc && sc->data[SC_MAGICPOWER] ) + flag = flag|2; //Store the magic power flag + + for( i = 0; i < wave; i++ ) + { + switch( dir ) + { + case 0: case 1: case 7: sy = src->y + i; break; + case 3: case 4: case 5: sy = src->y - i; break; + case 2: sx = src->x - i; break; + case 6: sx = src->x + i; break; + } + skill_addtimerskill(src,gettick() + (200 * i),0,sx,sy,skillid,skilllv,dir,flag&2); // Temp code until animation is replaced. [Rytech] + //skill_addtimerskill(src,gettick() + (150 * i),0,sx,sy,skillid,skilllv,dir,flag&2); // Official steping timer, but disabled due to too much noise. + } + } + break; + /** + * Ranger + **/ + case RA_DETONATOR: + i = skill_get_splash(skillid, skilllv); + map_foreachinarea(skill_detonator, src->m, x-i, y-i, x+i, y+i, BL_SKILL, src); + clif_skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6); + break; + /** + * Mechanic + **/ + case NC_NEUTRALBARRIER: + case NC_STEALTHFIELD: + skill_clear_unitgroup(src); // To remove previous skills - cannot used combined + if( (sg = skill_unitsetting(src,skillid,skilllv,src->x,src->y,0)) != NULL ) + { + sc_start2(src,skillid == NC_NEUTRALBARRIER ? SC_NEUTRALBARRIER_MASTER : SC_STEALTHFIELD_MASTER,100,skilllv,sg->group_id,skill_get_time(skillid,skilllv)); + if( sd ) pc_overheat(sd,1); + } + break; + + case NC_SILVERSNIPER: + { + int class_ = 2042; + struct mob_data *md; + + md = mob_once_spawn_sub(src, src->m, x, y, status_get_name(src), class_, ""); + if( md ) + { + md->master_id = src->id; + md->special_state.ai = 3; + if( md->deletetimer != INVALID_TIMER ) + delete_timer(md->deletetimer, mob_timer_delete); + md->deletetimer = add_timer (gettick() + skill_get_time(skillid, skilllv), mob_timer_delete, md->bl.id, 0); + mob_spawn( md ); + } + } + break; + + case NC_MAGICDECOY: + if( sd ) clif_magicdecoy_list(sd,skilllv,x,y); + break; default: ShowWarning("skill_castend_pos2: Unknown skill used:%d\n",skillid); @@ -6566,7 +8115,12 @@ int skill_castend_map (struct map_session_data *sd, short skill_num, const char sd->sc.data[SC_DANCING] || sd->sc.data[SC_BERSERK] || sd->sc.data[SC_BASILICA] || - sd->sc.data[SC_MARIONETTE] + sd->sc.data[SC_MARIONETTE] || + /** + * Warlock + **/ + sd->sc.data[SC_WHITEIMPRISON] || + (sd->sc.data[SC_STASIS] && skill_stasis_check(&sd->bl, sd->sc.data[SC_STASIS]->val2, skill_num)) )) { skill_failed(sd); return 0; @@ -6855,6 +8409,17 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, short skilli case HT_FREEZINGTRAP: case MA_FREEZINGTRAP: case HT_BLASTMINE: + /** + * Ranger + **/ + case RA_ELECTRICSHOCKER: + case RA_CLUSTERBOMB: + case RA_MAGENTATRAP: + case RA_COBALTTRAP: + case RA_MAIZETRAP: + case RA_VERDURETRAP: + case RA_FIRINGTRAP: + case RA_ICEBOUNDTRAP: if( map_flag_gvg(src->m) || map[src->m].flag.battleground ) limit *= 4; // longer trap times in WOE [celest] if( battle_config.vs_traps_bctall && map_flag_vs(src->m) && (src->type&battle_config.vs_traps_bctall) ) @@ -7004,6 +8569,17 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, short skilli break; } + /** + * Guilotine Cross + **/ + case GC_POISONSMOKE: + if( !(sc && sc->data[SC_POISONINGWEAPON]) ) + return NULL; + val1 = sc->data[SC_POISONINGWEAPON]->val1; // Level of Poison, to determine poisoning time + val2 = sc->data[SC_POISONINGWEAPON]->val2; // Type of Poison + limit = 4000 + 2000 * skilllv; + break; + } nullpo_retr(NULL, group=skill_initunitgroup(src,layout->count,skillid,skilllv,skill_get_unit_id(skillid,flag&1)+subunt, limit, interval)); @@ -7078,6 +8654,17 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, short skilli case HT_TALKIEBOX: case HT_SKIDTRAP: case MA_SKIDTRAP: + /** + * Ranger + **/ + case RA_ELECTRICSHOCKER: + case RA_CLUSTERBOMB: + case RA_MAGENTATRAP: + case RA_COBALTTRAP: + case RA_MAIZETRAP: + case RA_VERDURETRAP: + case RA_FIRINGTRAP: + case RA_ICEBOUNDTRAP: val1 = 3500; break; case GS_DESPERADO: @@ -7157,8 +8744,8 @@ static int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, un sc = status_get_sc(bl); - if (sc && sc->option&OPTION_HIDE && sg->skill_id != WZ_HEAVENDRIVE) - return 0; //Hidden characters are immune to AoE skills except Heaven's Drive. [Skotlex] + if (sc && sc->option&OPTION_HIDE && sg->skill_id != WZ_HEAVENDRIVE && sg->skill_id != WL_EARTHSTRAIN ) + return 0; //Hidden characters are immune to AoE skills except to these. [Skotlex] type = status_skill2sc(sg->skill_id); sce = (sc && type != -1)?sc->data[type]:NULL; @@ -7541,6 +9128,16 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns case UNT_FLASHER: case UNT_FREEZINGTRAP: case UNT_FIREPILLAR_ACTIVE: + /** + * Ranger + **/ + case UNT_CLUSTERBOMB: + case UNT_MAGENTATRAP: + case UNT_COBALTTRAP: + case UNT_MAIZETRAP: + case UNT_VERDURETRAP: + case UNT_FIRINGTRAP: + case UNT_ICEBOUNDTRAP: map_foreachinrange(skill_trap_splash,&src->bl, skill_get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &src->bl,tick); if (sg->unit_id != UNT_FIREPILLAR_ACTIVE) clif_changetraplook(&src->bl, sg->unit_id==UNT_LANDMINE?UNT_FIREPILLAR_ACTIVE:UNT_USED_TRAPS); @@ -7707,6 +9304,10 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns break; case UNT_GRAVITATION: + case UNT_EARTHSTRAIN: + case UNT_FIREWALK: + case UNT_ELECTRICWALK: + case UNT_PSYCHIC_WAVE: skill_attack(skill_get_type(sg->skill_id),ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0); break; @@ -7722,6 +9323,71 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns //clif_changetraplook(&src->bl, UNT_FIREPILLAR_ACTIVE); sg->limit=DIFF_TICK(tick,sg->tick)+1500; break; + /** + * 3rd stuff + **/ + case UNT_POISONSMOKE: + if( battle_check_target(ss,bl,BCT_ENEMY) > 0 && !(tsc && tsc->data[sg->val2]) && rand()%100 < 20 ) + sc_start(bl,sg->val2,100,sg->val1,skill_get_time2(GC_POISONINGWEAPON,sg->val1)); + break; + + case UNT_EPICLESIS: + if( bl->type == BL_PC && !battle_check_undead(tstatus->race, tstatus->def_ele) && tstatus->race != RC_DEMON ) + { + int hp, sp; + switch( sg->skill_lv ) + { + case 1: case 2: hp = 3; sp = 2; break; + case 3: case 4: hp = 4; sp = 3; break; + case 5: default: hp = 5; sp = 4; break; + } + hp = tstatus->max_hp * hp / 100; + sp = tstatus->max_sp * sp / 100; + status_heal(bl, hp, sp, 0); + if( tstatus->hp < tstatus->max_hp ) + clif_skill_nodamage(&src->bl, bl, AL_HEAL, hp, 1); + if( tstatus->sp < tstatus->max_sp ) + clif_skill_nodamage(&src->bl, bl, MG_SRECOVERY, sp, 1); + sc_start(bl, type, 100, sg->skill_lv, sg->interval + 100); + sg->val2++; + // Reveal hidden players every 5 seconds. + if( sg->val2 >= 5 ) + { + sg->val2 = 0; + // TODO: check if other hidden status can be removed. + status_change_end(bl,SC_HIDING,-1); + status_change_end(bl,SC_CLOAKING,-1); + } + } + /* Enable this if kRO fix the current skill. Currently no damage on undead and demon monster. [Jobbie] + else if( battle_check_target(ss, bl, BCT_ENEMY) > 0 && battle_check_undead(tstatus->race, tstatus->def_ele) ) + skill_castend_damage_id(&src->bl, bl, sg->skill_id, sg->skill_lv, 0, 0);*/ + break; + + case UNT_STEALTHFIELD: + if( bl->id == sg->src_id ) + break; // Dont work on Self (video shows that) + case UNT_NEUTRALBARRIER: + sc_start(bl,type,100,sg->skill_lv,sg->interval + 100); + break; + + case UNT_DIMENSIONDOOR: + if( tsd && !map[bl->m].flag.noteleport ) + pc_randomwarp(tsd,3); + else if( bl->type == BL_MOB && battle_config.mob_warp&8 ) + unit_warp(bl,-1,-1,-1,3); + break; + + case UNT_REVERBERATION: + clif_changetraplook(&src->bl,UNT_USED_TRAPS); + map_foreachinrange(skill_trap_splash,&src->bl, skill_get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &src->bl,tick); + sg->limit = DIFF_TICK(tick,sg->tick) + 1500; + break; + + case UNT_SEVERE_RAINSTORM: + if( battle_check_target(&src->bl, bl, BCT_ENEMY) ) + skill_attack(BF_WEAPON,ss,&src->bl,bl,WM_SEVERE_RAINSTORM_MELEE,sg->skill_lv,tick,0); + break; } if (sg->state.magic_power && sc && !sc->data[SC_MAGICPOWER]) @@ -7759,6 +9425,7 @@ int skill_unit_onout (struct skill_unit *src, struct block_list *bl, unsigned in switch(sg->unit_id){ case UNT_SAFETYWALL: case UNT_PNEUMA: + case UNT_EPICLESIS://Arch Bishop if (sce) status_change_end(bl, type, INVALID_TIMER); break; @@ -7767,7 +9434,6 @@ int skill_unit_onout (struct skill_unit *src, struct block_list *bl, unsigned in if( sce && sce->val4 == src->bl.id ) status_change_end(bl, type, INVALID_TIMER); break; - case UNT_HERMODE: //Clear Hermode if the owner moved. if (sce && sce->val3 == BCT_SELF && sce->val4 == sg->group_id) status_change_end(bl, type, INVALID_TIMER); @@ -8003,6 +9669,19 @@ static int skill_check_condition_char_sub (struct block_list *bl, va_list ap) p_sd[(*c)++]=tsd->bl.id; return 1; } + case AB_ADORAMUS: + { // Adoramus does not consume Blue Gemstone when there is at least 1 Priest class next to the caster + if( (tsd->class_&MAPID_UPPERMASK) == MAPID_PRIEST ) + p_sd[(*c)++] = tsd->bl.id; + return 1; + } + case WL_COMET: + { // Comet does not consume Red Gemstones when there is at least 1 Warlock class next to the caster + if( tsd->status.class_ == 4055 || tsd->status.class_ == 4061 ) + p_sd[(*c)++] = tsd->bl.id; + return 1; + } + default: //Warning: Assuming Ensemble Dance/Songs for code speed. [Skotlex] { int skilllv; @@ -8052,6 +9731,13 @@ int skill_check_pc_partner (struct map_session_data *sd, short skill_id, short* status_charge(&tsd->bl, 0, 10); } return c; + case AB_ADORAMUS: + if( c > 0 && (tsd = map_id2sd(p_sd[0])) != NULL ) + { + i = 2 * (*skill_lv); + status_charge(&tsd->bl, 0, i); + } + break; default: //Warning: Assuming Ensemble skills here (for speed) if (c > 0 && sd->sc.data[SC_DANCING] && (tsd = map_id2sd(p_sd[0])) != NULL) { @@ -8441,46 +10127,137 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh if (!sd->status.guild_id || !sd->state.gmaster_flag) return 0; break; - - case GS_GLITTERING: - if(sd->spiritball >= 10) { - clif_skill_fail(sd,skill,0,0); + + case GS_GLITTERING: + if(sd->spiritball >= 10) { + clif_skill_fail(sd,skill,0,0); + return 0; + } + break; + + case NJ_ISSEN: + if (status->hp < 2) { + clif_skill_fail(sd,skill,0,0); + return 0; + } + case NJ_BUNSINJYUTSU: + if (!(sc && sc->data[SC_NEN])) { + clif_skill_fail(sd,skill,0,0); + return 0; + } + break; + + case NJ_ZENYNAGE: + if(sd->status.zeny < require.zeny) { + clif_skill_fail(sd,skill,5,0); + return 0; + } + break; + case PF_HPCONVERSION: + if (status->sp == status->max_sp) + return 0; //Unusable when at full SP. + break; + case AM_CALLHOMUN: //Can't summon if a hom is already out + if (sd->status.hom_id && sd->hd && !sd->hd->homunculus.vaporize) { + clif_skill_fail(sd,skill,0,0); + return 0; + } + break; + case AM_REST: //Can't vapo homun if you don't have an active homunc or it's hp is < 80% + if (!merc_is_hom_active(sd->hd) || sd->hd->battle_status.hp < (sd->hd->battle_status.max_hp*80/100)) + { + clif_skill_fail(sd,skill,0,0); + return 0; + } + break; + /** + * Arch Bishop + **/ + case AB_ANCILLA: + { + int count = 0; + for( i = 0; i < MAX_INVENTORY; i ++ ) + if( sd->status.inventory[i].nameid == ITEMID_ANCILLA ) + count += sd->status.inventory[i].amount; + if( count >= 3 ) { + clif_skill_fail(sd, skill, 0x0c, 0); + return 0; + } + } + break; + /** + * Keeping as a note: + * Bug Report #17 provides a link to a sep-2011 changelog that shows this requirement was removed + **/ + //case AB_LAUDAAGNUS: + //case AB_LAUDARAMUS: + // if( !sd->status.party_id ) { + // clif_skill_fail(sd,skill,0,0); + // return 0; + // } + // break; + + case AB_ADORAMUS: + /** + * Warlock + **/ + case WL_COMET: + if( skill_check_pc_partner(sd,skill,&lv,1,0) <= 0 && ((i = pc_search_inventory(sd,require.itemid[0])) < 0 || sd->status.inventory[i].amount < require.amount[0]) ) + { + //clif_skill_fail(sd,skill,0x47,require.amount[0],require.itemid[0]); + clif_skill_fail(sd,skill,0,0); + return 0; + } + break; + case WL_SUMMONFB: + case WL_SUMMONBL: + case WL_SUMMONWB: + case WL_SUMMONSTONE: + if( sc ) + { + ARR_FIND(SC_SPHERE_1,SC_SPHERE_5+1,i,!sc->data[i]); + if( i == SC_SPHERE_5+1 ) + { // No more free slots + clif_skill_fail(sd,skill,0x13,0); + return 0; + } + } + break; + /** + * Guilotine Cross + **/ + case GC_HALLUCINATIONWALK: + if( sc && (sc->data[SC_HALLUCINATIONWALK] || sc->data[SC_HALLUCINATIONWALK_POSTDELAY]) ) { + clif_skill_fail(sd,skill,0x0,0); return 0; } break; - - case NJ_ISSEN: - if (status->hp < 2) { - clif_skill_fail(sd,skill,0,0); + case GC_COUNTERSLASH: + case GC_WEAPONCRUSH: + if( !(sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == GC_WEAPONBLOCKING) ) { + clif_skill_fail(sd, skill, 0x1f, 0); return 0; } - case NJ_BUNSINJYUTSU: - if (!(sc && sc->data[SC_NEN])) { - clif_skill_fail(sd,skill,0,0); - return 0; - } break; - - case NJ_ZENYNAGE: - if(sd->status.zeny < require.zeny) { - clif_skill_fail(sd,skill,5,0); + case GC_CROSSRIPPERSLASHER: + if( !(sc && sc->data[SC_ROLLINGCUTTER]) ) { + clif_skill_fail(sd, skill, 0x17, 0); return 0; } break; - case PF_HPCONVERSION: - if (status->sp == status->max_sp) - return 0; //Unusable when at full SP. - break; - case AM_CALLHOMUN: //Can't summon if a hom is already out - if (sd->status.hom_id && sd->hd && !sd->hd->homunculus.vaporize) { - clif_skill_fail(sd,skill,0,0); + case GC_POISONSMOKE: + case GC_VENOMPRESSURE: + if( !(sc && sc->data[SC_POISONINGWEAPON]) ) { + clif_skill_fail(sd, skill, 0x20, 0); return 0; } break; - case AM_REST: //Can't vapo homun if you don't have an active homunc or it's hp is < 80% - if (!merc_is_hom_active(sd->hd) || sd->hd->battle_status.hp < (sd->hd->battle_status.max_hp*80/100)) - { - clif_skill_fail(sd,skill,0,0); + /** + * Ranger + **/ + case RA_SENSITIVEKEEN: + if(!pc_iswug(sd)) { + clif_skill_fail(sd,skill,0x17,0); return 0; } break; @@ -8568,6 +10345,51 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh break; clif_skill_fail(sd,skill,0,0); return 0; + /** + * Rune Knight + **/ + case ST_RIDINGDRAGON: + if( !(sd->sc.option&OPTION_DRAGON)) { + clif_skill_fail(sd,skill,0,0); + return 0; + } + break; + /** + * Wug + **/ + case ST_WUG: + if( !(sd->sc.option&OPTION_WUG) ) { + clif_skill_fail(sd,skill,0,0); + return 0; + } + break; + /** + * Riding Wug + **/ + case ST_RIDINGWUG: + if( !(sd->sc.option&OPTION_WUGRIDER) ){ + clif_skill_fail(sd,skill,0,0); + return 0; + } + break; + /** + * Mechanic + **/ + case ST_MADO: + if( !(sd->sc.option&OPTION_MADOGEAR) ) { + clif_skill_fail(sd,skill,0,0); + return 0; + } + break; + /** + * Sorcerer + **/ + //case ST_ELEMENTALSPIRIT: + // if(!sd->ed) { + // clif_skill_fail(sd,skill,0x4f,0,0); + // return 0; + // } + // break; } if(require.mhp > 0 && get_percentage(status->hp, status->max_hp) > require.mhp) { @@ -8648,6 +10470,10 @@ int skill_check_condition_castend(struct map_session_data* sd, short skill, shor case PR_BENEDICTIO: skill_check_pc_partner(sd, skill, &lv, 1, 1); break; + case AB_ADORAMUS: + //if( skill_check_pc_partner(sd,skill,&lv, 1, 2) ) + // sd->state.no_gemstone = 1; // Mark this skill as it don't consume ammo because partners gives SP + break; case AM_CANNIBALIZE: case AM_SPHEREMINE: { @@ -8667,6 +10493,32 @@ int skill_check_condition_castend(struct map_session_data* sd, short skill, shor } break; } + case NC_SILVERSNIPER: + case NC_MAGICDECOY: + { + int c = 0, j; + int maxcount = skill_get_maxcount(skill,lv); + int mob_class = 2042; + if( skill == NC_MAGICDECOY ) + mob_class = 2043; + + if( battle_config.land_skill_limit && maxcount > 0 && ( battle_config.land_skill_limit&BL_PC ) ) + { + if( skill == NC_MAGICDECOY ) + { + for( j = mob_class; j <= 2046; j++ ) + i = map_foreachinmap(skill_check_condition_mob_master_sub, sd->bl.m, BL_MOB, sd->bl.id, j, skill, &c); + } + else + i = map_foreachinmap(skill_check_condition_mob_master_sub, sd->bl.m, BL_MOB, sd->bl.id, mob_class, skill, &c); + if( c >= maxcount ) + { + clif_skill_fail(sd , skill, 0, 0); + return 0; + } + } + } + break; } status = &sd->battle_status; @@ -8854,6 +10706,10 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, short if (sd->status.hom_id) //Don't delete items when hom is already out. continue; break; + case NC_SHAPESHIFT: + if( i < 4 ) + continue; + break; case WZ_FIREPILLAR: // celest if (lv <= 5) // no gems required at level 1-5 continue; @@ -8957,12 +10813,12 @@ int skill_castfix (struct block_list *bl, int skill_id, int skill_lv) sd = BL_CAST(BL_PC, bl); // calculate base cast time (reduced by dex) - if( !(skill_get_castnodex(skill_id, skill_lv)&1) ) - { - int scale = battle_config.castrate_dex_scale - status_get_dex(bl); + if( !(skill_get_castnodex(skill_id, skill_lv)&1) ) { + int scale = CONST_CASTRATE_SCALE - CONST_CASTRATE_CALC; if( scale > 0 ) // not instant cast - time = time * scale / battle_config.castrate_dex_scale; - else return 0; // instant cast + time = time * scale / CONST_CASTRATE_SCALE; + else + return 0; // instant cast } // calculate cast time reduced by item/card bonuses @@ -8980,11 +10836,9 @@ int skill_castfix (struct block_list *bl, int skill_id, int skill_lv) } } } - // config cast time multiplier if (battle_config.cast_rate != 100) time = time * battle_config.cast_rate / 100; - // return final cast time return (time > 0) ? time : 0; } @@ -8992,10 +10846,16 @@ int skill_castfix (struct block_list *bl, int skill_id, int skill_lv) /*========================================== * Does cast-time reductions based on sc data. *------------------------------------------*/ -int skill_castfix_sc (struct block_list *bl, int time) +int skill_castfix_sc (struct block_list *bl, int time, int skill_id, int skill_lv) { struct status_change *sc = status_get_sc(bl); - +#if RECASTING + int fixed = skill_get_cast(skill_id, skill_lv); + if( fixed > 1 ) + fixed = fixed * 20 / 100; + else + fixed = 0; +#endif if (sc && sc->count) { if (sc->data[SC_SLOWCAST]) time += time * sc->data[SC_SLOWCAST]->val2 / 100; @@ -9010,8 +10870,24 @@ int skill_castfix_sc (struct block_list *bl, int time) } if (sc->data[SC_POEMBRAGI]) time -= time * sc->data[SC_POEMBRAGI]->val2 / 100; - } +#if RECASTING + /** + * AB Sacrament reduces fixed cast time by (10 x Level)% (up to 50%) + **/ + if( sc->data[SC_SECRAMENT] ) + fixed -= fixed * sc->data[SC_SECRAMENT]->val2 / 100; +#endif + } +#if RECASTING + /** + * WL_RADIUS decreases 10/15/20% fixed cast time from warlock skills + **/ + if( bl->type == BL_PC && skill_id >= WL_WHITEIMPRISON && skill_id <= WL_FREEZE_SP && ( skill_lv = pc_checkskill((TBL_PC*)bl, WL_RADIUS) ) ) + fixed -= fixed * (5+(skill_lv*5)) / 100; + return (time > 0 || fixed > 0) ? cap_value( time , fixed , INT_MAX ) : 0; +#else return (time > 0) ? time : 0; +#endif } /*========================================== @@ -9572,8 +11448,8 @@ int skill_frostjoke_scream (struct block_list *bl, va_list ap) return 0; if (bl->type == BL_PC) { struct map_session_data *sd = (struct map_session_data *)bl; - if (sd && sd->sc.option&OPTION_INVISIBLE) - return 0; + if ( sd && sd->sc.option&(OPTION_INVISIBLE|OPTION_MADOGEAR) ) + return 0;//Frost Joke / Scream cannot target invisible or MADO Gear characters [Ind] } //It has been reported that Scream/Joke works the same regardless of woe-setting. [Skotlex] if(battle_check_target(src,bl,BCT_ENEMY) > 0) @@ -9731,6 +11607,48 @@ int skill_greed (struct block_list *bl, va_list ap) return 0; } +//For Ranger's Detonator [Jobbie/3CeAM] +int skill_detonator(struct block_list *bl, va_list ap) +{ + struct skill_unit *unit=NULL; + struct block_list *src; + int unit_id; + + nullpo_ret(bl); + nullpo_ret(ap); + src = va_arg(ap,struct block_list *); + + if( bl->type != BL_SKILL || (unit = (struct skill_unit *)bl) == NULL || !unit->group ) + return 0; + if( unit->group->src_id != src->id ) + return 0; + + unit_id = unit->group->unit_id; + switch( unit_id ) + { //List of Hunter and Ranger Traps that can be detonate. + case UNT_BLASTMINE: + case UNT_SANDMAN: + case UNT_CLAYMORETRAP: + case UNT_TALKIEBOX: + case UNT_CLUSTERBOMB: + case UNT_FIRINGTRAP: + case UNT_ICEBOUNDTRAP: + if( unit_id == UNT_TALKIEBOX ) + { + clif_talkiebox(bl,unit->group->valstr); + unit->group->val2 = -1; + } + else + map_foreachinrange(skill_trap_splash,bl,skill_get_splash(unit->group->skill_id,unit->group->skill_lv),unit->group->bl_flag,bl,unit->group->tick); + + clif_changetraplook(bl,unit_id == UNT_FIRINGTRAP ? UNT_DUMMYSKILL : UNT_USED_TRAPS); + unit->group->unit_id = UNT_USED_TRAPS; + unit->range = -1; + unit->group->limit = DIFF_TICK(gettick(),unit->group->tick) + (unit_id == UNT_TALKIEBOX ? 5000 : 1500); + break; + } + return 0; +} /*========================================== * @@ -9897,6 +11815,15 @@ static int skill_trap_splash (struct block_list *bl, va_list ap) if(skill_attack(BF_WEAPON,ss,src,bl,sg->skill_id,sg->skill_lv,tick,sg->val1)) skill_blown(src,bl,skill_get_blewcount(sg->skill_id,sg->skill_lv),-1,0); break; + case UNT_ELECTRICSHOCKER: + clif_skill_damage(src,bl,tick,0,0,-30000,1,sg->skill_id,sg->skill_lv,5); + break; + case UNT_FIRINGTRAP: + case UNT_ICEBOUNDTRAP: + case UNT_CLUSTERBOMB: + if(skill_attack(BF_MISC,ss,bl,bl,sg->skill_id,sg->skill_lv,tick,sg->val1)) + clif_skill_damage(bl,bl,tick,0,0,-30000,1,sg->skill_id,sg->skill_lv,5); + break; default: skill_attack(skill_get_type(sg->skill_id),ss,src,bl,sg->skill_id,sg->skill_lv,tick,0); break; @@ -9964,6 +11891,37 @@ bool skill_check_cloaking(struct block_list *bl, struct status_change_entry *sce return wall; } +bool skill_check_camouflage(struct block_list *bl, struct status_change_entry *sce) +{ + static int dx[] = { 0, 1, 0, -1, -1, 1, 1, -1}; + static int dy[] = {-1, 0, 1, 0, -1, -1, 1, 1}; + bool wall = true; + int i; + + if( bl->type == BL_PC ) + { //Check for walls. + ARR_FIND( 0, 8, i, map_getcell(bl->m, bl->x+dx[i], bl->y+dy[i], CELL_CHKNOPASS) != 0 ); + if( i == 8 ) + wall = false; + } + + if( sce ) + { + if( !wall ) + { + if( sce->val1 < 3 ) //End camouflage. + status_change_end(bl, SC_CAMOUFLAGE, -1); + else + if( sce->val3&1 ) + { //Remove wall bonus + sce->val3&=~1; + status_calc_bl(bl,SCB_SPEED); + } + } + } + + return wall; +} /*========================================== * @@ -10005,6 +11963,16 @@ struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int case HP_BASILICA: skill_unitsetmapcell(unit,HP_BASILICA,group->skill_lv,CELL_BASILICA,true); break; + /** + * Ranger + **/ + case RA_ELECTRICSHOCKER: + { + struct block_list* target = map_id2bl(group->val2); + if( target ) + status_change_end(target, SC_ELECTRICSHOCKER, -1); + } + break; default: if (group->state.song_dance&0x1) //Check for dissonance. skill_dance_overlap(unit, 1); @@ -10203,14 +12171,36 @@ int skill_delunitgroup_(struct skill_unit_group *group, const char* file, int li } } - if (group->skill_id == SG_SUN_WARM || - group->skill_id == SG_MOON_WARM || - group->skill_id == SG_STAR_WARM) { - struct status_change *sc = status_get_sc(src); - if(sc && sc->data[SC_WARM]) { - sc->data[SC_WARM]->val4 = 0; - status_change_end(src, SC_WARM, INVALID_TIMER); - } + switch( group->skill_id ) { + case SG_SUN_WARM: + case SG_MOON_WARM: + case SG_STAR_WARM: + { + struct status_change *sc = NULL; + if( (sc = status_get_sc(src)) != NULL && sc->data[SC_WARM] ) { + sc->data[SC_WARM]->val4 = 0; + status_change_end(src, SC_WARM, INVALID_TIMER); + } + } + break; + case NC_NEUTRALBARRIER: + { + struct status_change *sc = NULL; + if( (sc = status_get_sc(src)) != NULL && sc->data[SC_NEUTRALBARRIER_MASTER] ) { + sc->data[SC_NEUTRALBARRIER_MASTER]->val2 = 0; + status_change_end(src,SC_NEUTRALBARRIER_MASTER,-1); + } + } + break; + case NC_STEALTHFIELD: + { + struct status_change *sc = NULL; + if( (sc = status_get_sc(src)) != NULL && sc->data[SC_STEALTHFIELD_MASTER] ) { + sc->data[SC_STEALTHFIELD_MASTER]->val2 = 0; + status_change_end(src,SC_STEALTHFIELD_MASTER,-1); + } + } + break; } if (src->type==BL_PC && group->state.ammo_consume) @@ -10379,6 +12369,14 @@ static int skill_unit_timer_sub (DBKey key, void* data, va_list ap) case UNT_FREEZINGTRAP: case UNT_CLAYMORETRAP: case UNT_TALKIEBOX: + case UNT_CLUSTERBOMB: + case UNT_MAGENTATRAP: + case UNT_COBALTTRAP: + case UNT_MAIZETRAP: + case UNT_VERDURETRAP: + case UNT_FIRINGTRAP: + case UNT_ICEBOUNDTRAP: + { struct block_list* src; if( unit->val1 > 0 && (src = map_id2bl(group->src_id)) != NULL && src->type == BL_PC ) @@ -10445,6 +12443,11 @@ static int skill_unit_timer_sub (DBKey key, void* data, va_list ap) case UNT_FREEZINGTRAP: case UNT_TALKIEBOX: case UNT_ANKLESNARE: + /** + * Ranger + **/ + case UNT_ELECTRICSHOCKER: + case UNT_CLUSTERBOMB: if( unit->val1 <= 0 ) { if( group->unit_id == UNT_ANKLESNARE && group->val2 > 0 ) skill_delunit(unit); @@ -10817,6 +12820,9 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in if (!skill_id) //A skill can be specified for some override cases. skill_id = skill_produce_db[idx].req_skill; + if( skill_id == GC_RESEARCHNEWPOISON ) + skill_id = GC_CREATENEWPOISON; + slot[0]=slot1; slot[1]=slot2; slot[2]=slot3; @@ -10838,13 +12844,35 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in ele=ele_table[slot[i]-994]; } } + if( skill_id == RK_RUNEMASTERY ) { + int temp_qty, skill_lv = pc_checkskill(sd,skill_id); + if( skill_lv == 10 ) temp_qty = 1 + rand()%3; + else if( skill_lv > 5 ) temp_qty = 1 + rand()%2; + else temp_qty = 1; + for( i = 0; i < MAX_INVENTORY; i++ ) { + if( sd->status.inventory[i].nameid == nameid ) { + if( sd->status.inventory[i].amount >= MAX_RUNE ) { + clif_msgtable(sd->fd,0x61b); + return 0; + } else { + /** + * the amount fits, say we got temp_qty 4 and 19 runes, we trim temp_qty to 1. + **/ + if( temp_qty + sd->status.inventory[i].amount >= MAX_RUNE ) + temp_qty = MAX_RUNE - sd->status.inventory[i].amount; + } + break; + } + } + qty = temp_qty; + } for(i=0;idex + 20*status->luk); break; case AL_HOLYWATER: + /** + * Arch Bishop + **/ + case AB_ANCILLA: make_per = 100000; //100% success break; case AM_PHARMACY: // Potion Preparation - reviewed with the help of various Ragnainfo sources [DracoRPG] @@ -10939,6 +12971,19 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in case SA_CREATECON: // Elemental Converter Creation make_per = 100000; // should be 100% success rate break; + /** + * Rune Knight + **/ + case RK_RUNEMASTERY: + make_per = 5 * (sd->itemid + pc_checkskill(sd,skill_id)) * 100; + break; + /** + * Guilotine Cross + **/ + case GC_CREATENEWPOISON: + make_per = 3000 + 500 * pc_checkskill(sd,GC_RESEARCHNEWPOISON); + qty = 1+rand()%pc_checkskill(sd,GC_RESEARCHNEWPOISON); + break; default: if (sd->menuskill_id == AM_PHARMACY && sd->menuskill_val > 10 && sd->menuskill_val <= 20) @@ -11008,6 +13053,10 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in flag = battle_config.produce_item_name_input&0x2; break; case AL_HOLYWATER: + /** + * Arch Bishop + **/ + case AB_ANCILLA: flag = battle_config.produce_item_name_input&0x8; break; case ASC_CDP: @@ -11086,6 +13135,11 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in clif_produceeffect(sd,0,nameid); clif_misceffect(&sd->bl,3); break; + case RK_RUNEMASTERY: + case GC_CREATENEWPOISON: + clif_produceeffect(sd,2,nameid); + clif_misceffect(&sd->bl,5); + break; default: //Those that don't require a skill? if( skill_produce_db[idx].itemlv > 10 && skill_produce_db[idx].itemlv <= 20) { //Cooking items. @@ -11130,6 +13184,11 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in clif_produceeffect(sd,1,nameid); clif_misceffect(&sd->bl,2); break; + case RK_RUNEMASTERY: + case GC_CREATENEWPOISON: + clif_produceeffect(sd,3,nameid); + clif_misceffect(&sd->bl,6); + break; default: if( skill_produce_db[idx].itemlv > 10 && skill_produce_db[idx].itemlv <= 20 ) { //Cooking items. @@ -11183,6 +13242,125 @@ int skill_arrow_create (struct map_session_data *sd, int nameid) return 0; } +int skill_poisoningweapon( struct map_session_data *sd, int nameid) { + sc_type type; + int t_lv = 0, chance, i; + nullpo_ret(sd); + if( nameid <= 0 || (i = pc_search_inventory(sd,nameid)) < 0 || pc_delitem(sd,i,1,0,0) ) { + clif_skill_fail(sd,GC_POISONINGWEAPON,0,0); + return 0; + } + switch( nameid ) + { // t_lv used to take duration from skill_get_time2 + case PO_PARALYSE: type = SC_PARALYSE; t_lv = 1; break; + case PO_PYREXIA: type = SC_PYREXIA; t_lv = 2; break; + case PO_DEATHHURT: type = SC_DEATHHURT; t_lv = 3; break; + case PO_LEECHESEND: type = SC_LEECHESEND; t_lv = 4; break; + case PO_VENOMBLEED: type = SC_VENOMBLEED; t_lv = 6; break; + case PO_TOXIN: type = SC_TOXIN; t_lv = 7; break; + case PO_MAGICMUSHROOM: type = SC_MAGICMUSHROOM; t_lv = 8; break; + case PO_OBLIVIONCURSE: type = SC_OBLIVIONCURSE; t_lv = 9; break; + default: + clif_skill_fail(sd,GC_POISONINGWEAPON,0,0); + return 0; + } + + chance = 2 + 2 * sd->menuskill_val; // 2 + 2 * skill_lv + sc_start4(&sd->bl,SC_POISONINGWEAPON,100,t_lv,type,chance,0,skill_get_time(GC_POISONINGWEAPON,sd->menuskill_val)); + + return 0; +} +int skill_magicdecoy(struct map_session_data *sd, int nameid) { + int x, y, i, class_, skill; + struct mob_data *md; + nullpo_ret(sd); + skill = sd->menuskill_val; + + if( nameid <= 0 || !itemdb_is_element(nameid) || (i = pc_search_inventory(sd,nameid)) < 0 || !skill || pc_delitem(sd,i,1,0,0) ) + { + clif_skill_fail(sd,NC_MAGICDECOY,0,0); + return 0; + } + + // Spawn Position + pc_delitem(sd,i,1,0,0); + x = sd->sc.comet_x; + y = sd->sc.comet_y; + sd->sc.comet_x = sd->sc.comet_y = 0; + sd->menuskill_val = 0; + + class_ = (nameid == 990 || nameid == 991) ? 2043 + nameid - 990 : (nameid == 992) ? 2046 : 2045; + + + md = mob_once_spawn_sub(&sd->bl, sd->bl.m, x, y, sd->status.name, class_, ""); + if( md ) { + md->master_id = sd->bl.id; + md->special_state.ai = 3; + if( md->deletetimer != INVALID_TIMER ) + delete_timer(md->deletetimer, mob_timer_delete); + md->deletetimer = add_timer (gettick() + skill_get_time(NC_MAGICDECOY,skill), mob_timer_delete, md->bl.id, 0); + mob_spawn(md); + md->status.matk_min = md->status.matk_max = 250 + (50 * skill); + } + + return 0; +} +// Warlock Spellbooks. [LimitLine/3CeAM] +int skill_spellbook (struct map_session_data *sd, int nameid) { + int i, j, points, skillid, preserved = 0, max_preserve; + nullpo_ret(sd); + + if( sd->sc.data[SC_STOP] ) status_change_end(&sd->bl,SC_STOP,-1); + if( nameid <= 0 ) return 0; + + if( pc_search_inventory(sd,nameid) < 0 ) + { // User with no item on inventory + clif_skill_fail(sd,WL_READING_SB,0x04,0); + return 0; + } + + ARR_FIND(0,MAX_SPELLBOOK,j,sd->rsb[j].skillid == 0); // Search for a free slot + if( j == MAX_SPELLBOOK ) + { // No more free slots + clif_skill_fail(sd,WL_READING_SB,0x35,0); + return 0; + } + + ARR_FIND(0,MAX_SKILL_SPELLBOOK_DB,i,skill_spellbook_db[i].nameid == nameid); // Search for information of this item + if( i == MAX_SKILL_SPELLBOOK_DB ) + { // Fake nameid + clif_skill_fail(sd,WL_READING_SB,0x04,0); + return 0; + } + + skillid = skill_spellbook_db[i].skillid; + points = skill_spellbook_db[i].points; + + if( !pc_checkskill(sd,skillid) ) + { // User don't know the skill + sc_start(&sd->bl,SC_SLEEP,100,1,skill_get_time(WL_READING_SB,pc_checkskill(sd,WL_READING_SB))); + clif_skill_fail(sd,WL_READING_SB,0x34,0); + return 0; + } + + max_preserve = 4 * pc_checkskill(sd,WL_FREEZE_SP) + status_get_int(&sd->bl) / 10 + sd->status.base_level / 10; + for( i = 0; i < MAX_SPELLBOOK && sd->rsb[i].skillid; i++ ) + preserved += sd->rsb[i].points; + + if( preserved + points >= max_preserve ) + { // No more free points + clif_skill_fail(sd,WL_READING_SB,0x04,0); + return 0; + } + + sd->rsb[j].skillid = skillid; + sd->rsb[j].level = pc_checkskill(sd,skillid); + sd->rsb[j].points = points; + sc_start2(&sd->bl,SC_READING_SB,100,0,preserved+points,-1); + + return 1; +} + /*========================================== * @@ -11360,6 +13538,7 @@ void skill_init_unit_layout (void) switch (i) { case MG_FIREWALL: case WZ_ICEWALL: + case WL_EARTHSTRAIN://Warlock // these will be handled later break; case PR_SANCTUARY: @@ -11566,6 +13745,90 @@ void skill_init_unit_layout (void) } pos++; } + earthstrain_unit_pos = pos; + for( i = 0; i < 8; i++ ) + { // For each Direction + skill_unit_layout[pos].count = 3; // Temp code being used as the official method makes too much noise in game. [Rytech] + //skill_unit_layout[pos].count = 15; // This line is here to replace the above one once gravity changes the animation. + switch( i ) + { + case 0: case 1: case 3: case 4: case 5: case 7: + { + int dx[] = {-5, 0, 5}; + int dy[] = { 0, 0, 0}; + //int dx[] = {-7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7}; // Leave this here for future use. + //int dy[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + } + break; + case 2: + case 6: + { + int dx[] = { 0, 0, 0}; + int dy[] = {-5, 0, 5}; + //int dx[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Leave this here for future use. + //int dy[] = {-7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7}; + memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + } + break; + } + pos++; + } + +} +// Stasis skill usage check. [LimitLine/3CeAM] +int skill_stasis_check(struct block_list *bl, int src_id, int skillid) +{ + int inf = 0; + if( !bl || skillid < 1 ) + return 0; // Can do it + inf = skill_get_inf2(skillid); + if( inf == INF2_SONG_DANCE || /*skill_get_inf2(skillid) == INF2_CHORUS_SKILL ||*/ inf == INF2_SPIRIT_SKILL ) + return 1; // Can't do it. + + switch( skillid ) + { + case NV_FIRSTAID: case TF_HIDING: case AS_CLOAKING: case WZ_SIGHTRASHER: + case RG_STRIPWEAPON: case RG_STRIPSHIELD: case RG_STRIPARMOR: case WZ_METEOR: + case RG_STRIPHELM: case SC_STRIPACCESSARY: case ST_FULLSTRIP: case WZ_SIGHTBLASTER: + case ST_CHASEWALK: case SC_ENERVATION: case SC_GROOMY: case WZ_ICEWALL: + case SC_IGNORANCE: case SC_LAZINESS: case SC_UNLUCKY: case WZ_STORMGUST: + case SC_WEAKNESS: case AL_RUWACH: case AL_PNEUMA: case WZ_JUPITEL: + case AL_HEAL: case AL_BLESSING: case AL_INCAGI: case WZ_VERMILION: + case AL_TELEPORT: case AL_WARP: case AL_HOLYWATER: case WZ_EARTHSPIKE: + case AL_HOLYLIGHT: case PR_IMPOSITIO: case PR_ASPERSIO: case WZ_HEAVENDRIVE: + case PR_SANCTUARY: case PR_STRECOVERY: case PR_MAGNIFICAT: case WZ_QUAGMIRE: + case ALL_RESURRECTION: case PR_LEXDIVINA: case PR_LEXAETERNA: case HW_GRAVITATION: + case PR_MAGNUS: case PR_TURNUNDEAD: case MG_SRECOVERY: case HW_MAGICPOWER: + case MG_SIGHT: case MG_NAPALMBEAT: case MG_SAFETYWALL: case HW_GANBANTEIN: + case MG_SOULSTRIKE: case MG_COLDBOLT: case MG_FROSTDIVER: case WL_DRAINLIFE: + case MG_STONECURSE: case MG_FIREBALL: case MG_FIREWALL: case WL_SOULEXPANSION: + case MG_FIREBOLT: case MG_LIGHTNINGBOLT: case MG_THUNDERSTORM: case MG_ENERGYCOAT: + case WL_WHITEIMPRISON: case WL_SUMMONFB: case WL_SUMMONBL: case WL_SUMMONWB: + case WL_SUMMONSTONE: case WL_SIENNAEXECRATE: case WL_RELEASE: case WL_EARTHSTRAIN: + case WL_RECOGNIZEDSPELL: case WL_READING_SB: case SA_MAGICROD: case SA_SPELLBREAKER: + case SA_DISPELL: case SA_FLAMELAUNCHER: case SA_FROSTWEAPON: case SA_LIGHTNINGLOADER: + case SA_SEISMICWEAPON: case SA_VOLCANO: case SA_DELUGE: case SA_VIOLENTGALE: + case SA_LANDPROTECTOR: case PF_HPCONVERSION: case PF_SOULCHANGE: case PF_SPIDERWEB: + case PF_FOGWALL: case TK_RUN: case TK_HIGHJUMP: case TK_SEVENWIND: + case SL_KAAHI: case SL_KAUPE: case SL_KAITE: +#if FIREIVY_ON + case WZ_FIREIVY: +#endif + // Skills that need to be confirmed. + case SO_FIREWALK: case SO_ELECTRICWALK: case SO_SPELLFIST: case SO_EARTHGRAVE: + case SO_DIAMONDDUST: case SO_POISON_BUSTER: case SO_PSYCHIC_WAVE: case SO_CLOUD_KILL: + case SO_STRIKING: case SO_WARMER: case SO_VACUUM_EXTREME: case SO_VARETYR_SPEAR: + case SO_ARRULLO: + return 1; // Can't do it. + + default: + return 0; // Can do it. + } + + return 0; // Can Cast anything else like Weapon Skills } /*========================================== @@ -11596,7 +13859,10 @@ static bool skill_parse_row_skilldb(char* split[], int columns, int current) i = skill_get_index(id); if( !i ) // invalid skill id return false; - +#if FIREIVY_ON == 0 + if( i == WZ_FIREIVY ) //Disabled + return true; +#endif skill_split_atoi(split[1],skill_db[i].range); skill_db[i].hit = atoi(split[2]); skill_db[i].inf = atoi(split[3]); @@ -11638,7 +13904,10 @@ static bool skill_parse_row_requiredb(char* split[], int columns, int current) i = skill_get_index(i); if( !i ) // invalid skill id return false; - +#if FIREIVY_ON == 0 + if( i == WZ_FIREIVY ) //Disabled + return true; +#endif skill_split_atoi(split[1],skill_db[i].hp); skill_split_atoi(split[2],skill_db[i].mhp); skill_split_atoi(split[3],skill_db[i].sp); @@ -11696,6 +13965,17 @@ static bool skill_parse_row_requiredb(char* split[], int columns, int current) else if( strcmpi(split[10],"recover_weight_rate")==0 ) skill_db[i].state = ST_RECOV_WEIGHT_RATE; else if( strcmpi(split[10],"move_enable")==0 ) skill_db[i].state = ST_MOVE_ENABLE; else if( strcmpi(split[10],"water")==0 ) skill_db[i].state = ST_WATER; + /** + * New States + **/ + else if( strcmpi(split[10],"dragon")==0 ) skill_db[i].state = ST_RIDINGDRAGON; + else if( strcmpi(split[10],"warg")==0 ) skill_db[i].state = ST_WUG; + else if( strcmpi(split[10],"ridingwarg")==0 ) skill_db[i].state = ST_RIDINGWUG; + else if( strcmpi(split[10],"mado")==0 ) skill_db[i].state = ST_MADO; + else if( strcmpi(split[10],"elementalspirit")==0 ) skill_db[i].state = ST_ELEMENTALSPIRIT; + /** + * Unknown or no state + **/ else skill_db[i].state = ST_NONE; skill_split_atoi(split[11],skill_db[i].spiritball); @@ -11713,13 +13993,16 @@ static bool skill_parse_row_castdb(char* split[], int columns, int current) i = skill_get_index(i); if( !i ) // invalid skill id return false; - +#if FIREIVY_ON == 0 + if( i == WZ_FIREIVY ) //Disabled + return true; +#endif skill_split_atoi(split[1],skill_db[i].cast); skill_split_atoi(split[2],skill_db[i].delay); skill_split_atoi(split[3],skill_db[i].walkdelay); skill_split_atoi(split[4],skill_db[i].upkeep_time); skill_split_atoi(split[5],skill_db[i].upkeep_time2); - + skill_split_atoi(split[6],skill_db[i].cooldown); return true; } @@ -11729,7 +14012,10 @@ static bool skill_parse_row_castnodexdb(char* split[], int columns, int current) i = skill_get_index(i); if( !i ) // invalid skill id return false; - +#if FIREIVY_ON == 0 + if( i == WZ_FIREIVY ) //Disabled + return true; +#endif skill_split_atoi(split[1],skill_db[i].castnodex); if( split[2] ) // optional column skill_split_atoi(split[2],skill_db[i].delaynodex); @@ -11743,7 +14029,10 @@ static bool skill_parse_row_nocastdb(char* split[], int columns, int current) i = skill_get_index(i); if( !i ) // invalid skill id return false; - +#if FIREIVY_ON == 0 + if( i == WZ_FIREIVY ) //Disabled + return true; +#endif skill_db[i].nocast |= atoi(split[1]); return true; @@ -11829,6 +14118,50 @@ static bool skill_parse_row_createarrowdb(char* split[], int columns, int curren return true; } +static bool skill_parse_row_spellbookdb(char* split[], int columns, int current) +{// SkillID,PreservePoints + + int skillid = atoi(split[0]), + points = atoi(split[1]), + nameid = atoi(split[2]); + + if( !skill_get_index(skillid) || !skill_get_max(skillid) ) + ShowError("spellbook_db: Invalid skill ID %d\n", skillid); + if ( !skill_get_inf(skillid) ) + ShowError("spellbook_db: Passive skills cannot be memorized (%d/%s)\n", skillid, skill_get_name(skillid)); + if( points < 1 ) + ShowError("spellbook_db: PreservePoints have to be 1 or above! (%d/%s)\n", skillid, skill_get_name(skillid)); + else + { + skill_spellbook_db[current].skillid = skillid; + skill_spellbook_db[current].points = points; + skill_spellbook_db[current].nameid = nameid; + + return true; + } + + return false; +} +static bool skill_parse_row_magicmushroomdb(char* split[], int column, int current) +{ + int i = atoi(split[0]); + + if( !skill_get_index(i) || !skill_get_max(i) ) + { + ShowError("magicmushroom_db: Invalid skill ID %d\n", i); + return false; + } + if ( !skill_get_inf(i) ) + { + ShowError("magicmushroom_db: Passive skills cannot be casted (%d/%s)\n", i, skill_get_name(i)); + return false; + } + + skill_magicmushroom_db[current].skillid = i; + + return true; +} + static bool skill_parse_row_abradb(char* split[], int columns, int current) {// SkillID,DummyName,RequiredHocusPocusLevel,Rate @@ -11843,7 +14176,10 @@ static bool skill_parse_row_abradb(char* split[], int columns, int current) ShowError("abra_db: Passive skills cannot be casted (%d/%s)\n", i, skill_get_name(i)); return false; } - +#if FIREIVY_ON == 0 + if( i == WZ_FIREIVY ) //Disabled + return true; +#endif skill_abra_db[current].skillid = i; skill_abra_db[current].req_lv = atoi(split[2]); skill_abra_db[current].per = atoi(split[3]); @@ -11859,13 +14195,14 @@ static void skill_readdb(void) memset(skill_produce_db,0,sizeof(skill_produce_db)); memset(skill_arrow_db,0,sizeof(skill_arrow_db)); memset(skill_abra_db,0,sizeof(skill_abra_db)); - + memset(skill_spellbook_db,0,sizeof(skill_spellbook_db)); + memset(skill_magicmushroom_db,0,sizeof(skill_magicmushroom_db)); // load skill databases safestrncpy(skill_db[0].name, "UNKNOWN_SKILL", sizeof(skill_db[0].name)); safestrncpy(skill_db[0].desc, "Unknown Skill", sizeof(skill_db[0].desc)); 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_cast_db.txt" , ',', 7, 7, 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); @@ -11873,6 +14210,11 @@ static void skill_readdb(void) 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); + //Warlock + sv_readdb(db_path, "spellbook_db.txt" , ',', 3, 3, MAX_SKILL_SPELLBOOK_DB, skill_parse_row_spellbookdb); + //Guillotine Cross + sv_readdb(db_path, "magicmushroom_db.txt" , ',', 1, 1, MAX_SKILL_MAGICMUSHROOM_DB, skill_parse_row_magicmushroomdb); + } void skill_reload (void) diff --git a/src/map/skill.h b/src/map/skill.h index 1ad6ea25a..97bd54252 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -13,7 +13,7 @@ struct skill_unit_group; struct status_change_entry; #define MAX_SKILL_DB MAX_SKILL -#define MAX_SKILL_PRODUCE_DB 150 +#define MAX_SKILL_PRODUCE_DB 170 #define MAX_PRODUCE_RESOURCE 12 #define MAX_SKILL_ARROW_DB 150 #define MAX_ARROW_RESOURCE 5 @@ -91,7 +91,7 @@ struct s_skill_db { int range[MAX_SKILL_LEVEL],hit,inf,element[MAX_SKILL_LEVEL],nk,splash[MAX_SKILL_LEVEL],max; int num[MAX_SKILL_LEVEL]; int cast[MAX_SKILL_LEVEL],walkdelay[MAX_SKILL_LEVEL],delay[MAX_SKILL_LEVEL]; - int upkeep_time[MAX_SKILL_LEVEL],upkeep_time2[MAX_SKILL_LEVEL]; + int upkeep_time[MAX_SKILL_LEVEL],upkeep_time2[MAX_SKILL_LEVEL],cooldown[MAX_SKILL_LEVEL]; int castcancel,cast_def_rate; int inf2,maxcount[MAX_SKILL_LEVEL],skill_type; int blewcount[MAX_SKILL_LEVEL]; @@ -290,7 +290,7 @@ int skill_clear_group(struct block_list *bl, int flag); int skill_unit_ondamaged(struct skill_unit *src,struct block_list *bl,int damage,unsigned int tick); int skill_castfix( struct block_list *bl, int skill_id, int skill_lv); -int skill_castfix_sc( struct block_list *bl, int time); +int skill_castfix_sc( struct block_list *bl, int time, int skill_id, int skill_lv); int skill_delayfix( struct block_list *bl, int skill_id, int skill_lv); // Skill conditions check and remove [Inkfish] @@ -368,6 +368,14 @@ enum { ST_RECOV_WEIGHT_RATE, ST_MOVE_ENABLE, ST_WATER, + /** + * 3rd States + **/ + ST_RIDINGDRAGON, + ST_WUG, + ST_RIDINGWUG, + ST_MADO, + ST_ELEMENTALSPIRIT, }; enum e_skill { @@ -1310,7 +1318,7 @@ enum e_skill { GN_S_PHARMACY, GN_SLINGITEM_RANGEMELEEATK, - AB_SECRAMENT, + AB_SECRAMENT=2515, WM_SEVERE_RAINSTORM_MELEE, SR_HOWLINGOFLION, SR_RIDEINLIGHTNING, @@ -1547,5 +1555,46 @@ enum { UNT_MAX = 0x190 }; - +/** + * Warlock + **/ +#define MAX_SKILL_SPELLBOOK_DB 17 +enum wl_spheres { + WLS_FIRE = 0x44, + WLS_WIND, + WLS_WATER, + WLS_STONE, +}; +int skill_spellbook (struct map_session_data *sd, int nameid); +/** + * Guilottine Cross + **/ +#define MAX_SKILL_MAGICMUSHROOM_DB 22 +struct s_skill_magicmushroom_db { + int skillid; +}; +extern struct s_skill_magicmushroom_db skill_magicmushroom_db[MAX_SKILL_MAGICMUSHROOM_DB]; +/** + * Ranger + **/ +int skill_detonator(struct block_list *bl, va_list ap); +bool skill_check_camouflage(struct block_list *bl, struct status_change_entry *sce); +/** + * Mechanic + **/ +int skill_magicdecoy(struct map_session_data *sd, int nameid); +/** + * Guiltoine Cross + **/ +int skill_poisoningweapon( struct map_session_data *sd, int nameid); +enum gx_poison { + PO_PARALYSE = 12717, + PO_LEECHESEND, + PO_OBLIVIONCURSE, + PO_DEATHHURT, + PO_TOXIN, + PO_PYREXIA, + PO_MAGICMUSHROOM, + PO_VENOMBLEED +}; #endif /* _SKILL_H_ */ diff --git a/src/map/status.c b/src/map/status.c index 4df2c80d6..28506a4f6 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -56,7 +56,13 @@ static int refinebonus[MAX_REFINE_BONUS][3]; // int percentrefinery[5][MAX_REFINE+1]; // 精錬成功率(refine_db.txt) static int atkmods[3][MAX_WEAPON_TYPE]; // 武器ATKサイズ修正(size_fix.txt) static char job_bonus[CLASS_COUNT][MAX_LEVEL]; - +#if RRMODE +enum { + SHIELD_ASPD, + RE_JOB_DB_MAX, +} RE_JOB_DB; +static int re_job_db[CLASS_COUNT][RE_JOB_DB_MAX];//[RRInd] +#endif static struct eri *sc_data_ers; //For sc_data entries static struct status_data dummy_status; @@ -445,6 +451,162 @@ void initChangeTables(void) set_sc( GD_LEADERSHIP , SC_GUILDAURA , SI_BLANK , SCB_STR|SCB_AGI|SCB_VIT|SCB_DEX ); set_sc( GD_BATTLEORDER , SC_BATTLEORDERS , SI_BLANK , SCB_STR|SCB_INT|SCB_DEX ); set_sc( GD_REGENERATION , SC_REGENERATION , SI_BLANK , SCB_REGEN ); + + /** + * Rune Knight + **/ + set_sc( RK_ENCHANTBLADE , SC_ENCHANTBLADE , SI_ENCHANTBLADE , SCB_NONE ); + set_sc( RK_DRAGONHOWLING , SC_FEAR , SI_BLANK , SCB_FLEE|SCB_HIT ); + set_sc( RK_DEATHBOUND , SC_DEATHBOUND , SI_DEATHBOUND , SCB_NONE ); + set_sc( RK_WINDCUTTER , SC_FEAR , SI_BLANK , SCB_FLEE|SCB_HIT ); + add_sc( RK_DRAGONBREATH , SC_BURNING ); + set_sc( RK_MILLENNIUMSHIELD , SC_MILLENNIUMSHIELD , SI_REUSE_MILLENNIUMSHIELD , SCB_NONE ); + set_sc( RK_REFRESH , SC_REFRESH , SI_REFRESH , SCB_NONE ); + set_sc( RK_GIANTGROWTH , SC_GIANTGROWTH , SI_GIANTGROWTH , SCB_STR ); + set_sc( RK_STONEHARDSKIN , SC_STONEHARDSKIN , SI_STONEHARDSKIN , SCB_NONE ); + set_sc( RK_VITALITYACTIVATION, SC_VITALITYACTIVATION, SI_VITALITYACTIVATION, SCB_REGEN ); + set_sc( RK_FIGHTINGSPIRIT , SC_FIGHTINGSPIRIT , SI_FIGHTINGSPIRIT , SCB_WATK|SCB_ASPD ); + set_sc( RK_ABUNDANCE , SC_ABUNDANCE , SI_ABUNDANCE , SCB_NONE ); + /** + * GC Guillotine Cross + **/ + set_sc( GC_VENOMIMPRESS , SC_VENOMIMPRESS , SI_VENOMIMPRESS , SCB_NONE ); + set_sc( GC_POISONINGWEAPON , SC_POISONINGWEAPON , SI_POISONINGWEAPON , SCB_NONE ); + set_sc( GC_WEAPONBLOCKING , SC_WEAPONBLOCKING , SI_WEAPONBLOCKING , SCB_NONE ); + set_sc( GC_CLOAKINGEXCEED , SC_CLOAKINGEXCEED , SI_CLOAKINGEXCEED , SCB_SPEED ); + set_sc( GC_HALLUCINATIONWALK , SC_HALLUCINATIONWALK, SI_HALLUCINATIONWALK, SCB_FLEE ); + set_sc( GC_ROLLINGCUTTER , SC_ROLLINGCUTTER , SI_ROLLINGCUTTER , SCB_NONE ); + /** + * Arch Bishop + **/ + set_sc( AB_ADORAMUS , SC_ADORAMUS , SI_ADORAMUS , SCB_AGI|SCB_SPEED ); + add_sc( AB_CLEMENTIA , SC_BLESSING ); + add_sc( AB_CANTO , SC_INCREASEAGI ); + set_sc( AB_EPICLESIS , SC_EPICLESIS , SI_EPICLESIS , SCB_MAXHP ); + add_sc( AB_PRAEFATIO , SC_KYRIE ); + set_sc( AB_ORATIO , SC_ORATIO , SI_ORATIO , SCB_NONE ); + set_sc( AB_LAUDAAGNUS , SC_LAUDAAGNUS , SI_LAUDAAGNUS , SCB_VIT ); + set_sc( AB_LAUDARAMUS , SC_LAUDARAMUS , SI_LAUDARAMUS , SCB_LUK ); + set_sc( AB_RENOVATIO , SC_RENOVATIO , SI_RENOVATIO , SCB_REGEN ); + set_sc( AB_EXPIATIO , SC_EXPIATIO , SI_EXPIATIO , SCB_ATK_ELE ); + set_sc( AB_DUPLELIGHT , SC_DUPLELIGHT , SI_DUPLELIGHT , SCB_NONE ); + set_sc( AB_SECRAMENT , SC_SECRAMENT , SI_SECRAMENT , SCB_NONE ); + /** + * Warlock + **/ + add_sc( WL_WHITEIMPRISON , SC_WHITEIMPRISON ); + set_sc( WL_FROSTMISTY , SC_FREEZING , SI_FROSTMISTY , SCB_ASPD|SCB_SPEED|SCB_DEF|SCB_DEF2 ); + set_sc( WL_MARSHOFABYSS , SC_MARSHOFABYSS , SI_MARSHOFABYSS , SCB_SPEED|SCB_FLEE|SCB_DEF|SCB_MDEF ); + set_sc( WL_RECOGNIZEDSPELL , SC_RECOGNIZEDSPELL , SI_RECOGNIZEDSPELL , SCB_NONE ); + set_sc( WL_STASIS , SC_STASIS , SI_STASIS , SCB_NONE ); + /** + * Ranger + **/ + set_sc( RA_FEARBREEZE , SC_FEARBREEZE , SI_FEARBREEZE , SCB_NONE ); + set_sc( RA_ELECTRICSHOCKER , SC_ELECTRICSHOCKER , SI_ELECTRICSHOCKER , SCB_NONE ); + set_sc( RA_WUGDASH , SC_WUGDASH , SI_WUGDASH , SCB_SPEED ); + set_sc( RA_CAMOUFLAGE , SC_CAMOUFLAGE , SI_CAMOUFLAGE , SCB_CRI|SCB_SPEED ); + add_sc( RA_MAGENTATRAP , SC_ELEMENTALCHANGE ); + add_sc( RA_COBALTTRAP , SC_ELEMENTALCHANGE ); + add_sc( RA_MAIZETRAP , SC_ELEMENTALCHANGE ); + add_sc( RA_VERDURETRAP , SC_ELEMENTALCHANGE ); + add_sc( RA_FIRINGTRAP , SC_BURNING ); + set_sc( RA_ICEBOUNDTRAP , SC_FREEZING , SI_FROSTMISTY , SCB_NONE ); + /** + * Mechanic + **/ + set_sc( NC_ACCELERATION , SC_ACCELERATION , SI_ACCELERATION , SCB_SPEED ); + set_sc( NC_HOVERING , SC_HOVERING , SI_HOVERING , SCB_SPEED ); + set_sc( NC_SHAPESHIFT , SC_SHAPESHIFT , SI_SHAPESHIFT , SCB_DEF_ELE ); + set_sc( NC_INFRAREDSCAN , SC_INFRAREDSCAN , SI_INFRAREDSCAN , SCB_FLEE ); + set_sc( NC_ANALYZE , SC_ANALYZE , SI_ANALYZE , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2 ); + set_sc( NC_MAGNETICFIELD , SC_MAGNETICFIELD , SI_MAGNETICFIELD , SCB_NONE ); + set_sc( NC_NEUTRALBARRIER , SC_NEUTRALBARRIER , SI_NEUTRALBARRIER , SCB_NONE ); + set_sc( NC_STEALTHFIELD , SC_STEALTHFIELD , SI_STEALTHFIELD , SCB_NONE ); + ///** + // * Shadow Chaser + // **/ + //set_sc( SC_REPRODUCE , SC__REPRODUCE , SI_REPRODUCE , SCB_NONE ); + //set_sc( SC_AUTOSHADOWSPELL , SC__AUTOSHADOWSPELL, SI_AUTOSHADOWSPELL , SCB_NONE ); + //set_sc( SC_SHADOWFORM , SC__SHADOWFORM , SI_SHADOWFORM , SCB_NONE ); + //set_sc( SC_BODYPAINT , SC__BODYPAINT , SI_BODYPAINTING , SCB_ASPD ); + //set_sc( SC_INVISIBILITY , SC__INVISIBILITY , SI_INVISIBILITY , SCB_ASPD|SCB_CRI|SCB_ATK_ELE ); + //set_sc( SC_DEADLYINFECT , SC__DEADLYINFECT , SI_DEADLYINFECT , SCB_NONE ); + //set_sc( SC_ENERVATION , SC__ENERVATION , SI_ENERVATION , SCB_BATK ); + //set_sc( SC_GROOMY , SC__GROOMY , SI_GROOMY , SCB_ASPD|SCB_HIT|SCB_SPEED ); + //set_sc( SC_IGNORANCE , SC__IGNORANCE , SI_IGNORANCE , SCB_NONE ); + //set_sc( SC_LAZINESS , SC__LAZINESS , SI_LAZINESS , SCB_FLEE ); + //set_sc( SC_UNLUCKY , SC__UNLUCKY , SI_UNLUCKY , SCB_CRI|SCB_FLEE2 ); + //set_sc( SC_WEAKNESS , SC__WEAKNESS , SI_WEAKNESS , SCB_FLEE2|SCB_MAXHP ); + //set_sc( SC_STRIPACCESSARY , SC__STRIPACCESSORY , SI_STRIPACCESSORY , SCB_DEX|SCB_INT|SCB_LUK ); + //set_sc( SC_MANHOLE , SC__MANHOLE , SI_MANHOLE , SCB_NONE ); + //add_sc( SC_CHAOSPANIC , SC_CHAOS ); + //set_sc( SC_BLOODYLUST , SC__BLOODYLUST , SI_BLOODYLUST , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK ); + ///** + // * Royal Guard + // **/ + //set_sc( LG_REFLECTDAMAGE , SC_REFLECTDAMAGE , SI_LG_REFLECTDAMAGE, SCB_NONE ); + //set_sc( LG_FORCEOFVANGUARD , SC_FORCEOFVANGUARD , SI_FORCEOFVANGUARD , SCB_MAXHP|SCB_DEF ); + //set_sc( LG_EXEEDBREAK , SC_EXEEDBREAK , SI_EXEEDBREAK , SCB_NONE ); + //set_sc( LG_PRESTIGE , SC_PRESTIGE , SI_PRESTIGE , SCB_DEF2 ); + //set_sc( LG_BANDING , SC_BANDING , SI_BANDING , SCB_DEF2|SCB_WATK );// Renewal: atk2 & def2 + //set_sc( LG_PIETY , SC_BENEDICTIO , SI_BENEDICTIO , SCB_DEF_ELE ); + //set_sc( LG_EARTHDRIVE , SC_EARTHDRIVE , SI_EARTHDRIVE , SCB_DEF|SCB_ASPD ); + //set_sc( LG_INSPIRATION , SC_INSPIRATION , SI_INSPIRATION , SCB_MAXHP|SCB_WATK|SCB_HIT|SCB_VIT|SCB_AGI|SCB_STR|SCB_DEX|SCB_INT|SCB_LUK); + ///** + // * Sura + // **/ + //add_sc( SR_DRAGONCOMBO , SC_STUN ); + //add_sc( SR_EARTHSHAKER , SC_STUN ); + //set_sc( SR_CRESCENTELBOW , SC_CRESCENTELBOW , SI_CRESCENTELBOW , SCB_NONE ); + //set_sc( SR_CURSEDCIRCLE , SC_CURSEDCIRCLE_TARGET, SI_CURSEDCIRCLE_TARGET , SCB_NONE ); + //set_sc( SR_LIGHTNINGWALK , SC_LIGHTNINGWALK , SI_LIGHTNINGWALK , SCB_NONE ); + //set_sc( SR_RAISINGDRAGON , SC_RAISINGDRAGON , SI_RAISINGDRAGON , SCB_REGEN|SCB_MAXHP|SCB_MAXSP/*|SCB_ASPD*/ ); + //set_sc( SR_GENTLETOUCH_ENERGYGAIN, SC_GT_ENERGYGAIN , SI_GENTLETOUCH_ENERGYGAIN, SCB_NONE ); + //set_sc( SR_GENTLETOUCH_CHANGE , SC_GT_CHANGE , SI_GENTLETOUCH_CHANGE , SCB_BATK|SCB_ASPD|SCB_DEF|SCB_MDEF ); + //set_sc( SR_GENTLETOUCH_REVITALIZE, SC_GT_REVITALIZE , SI_GENTLETOUCH_REVITALIZE, SCB_MAXHP|SCB_DEF2|SCB_REGEN|SCB_ASPD|SCB_SPEED ); + ///** + // * Wanderer / Mistrel + // **/ + //set_sc( WA_SWING_DANCE , SC_SWINGDANCE , SI_SWINGDANCE , SCB_SPEED|SCB_ASPD ); + //set_sc( WA_SYMPHONY_OF_LOVER , SC_SYMPHONYOFLOVER , SI_SYMPHONYOFLOVERS , SCB_MDEF ); + //set_sc( WA_MOONLIT_SERENADE , SC_MOONLITSERENADE , SI_MOONLITSERENADE , SCB_MATK ); + //set_sc( MI_RUSH_WINDMILL , SC_RUSHWINDMILL , SI_RUSHWINDMILL , SCB_BATK ); + //set_sc( MI_ECHOSONG , SC_ECHOSONG , SI_ECHOSONG , SCB_DEF2 ); + //set_sc( MI_HARMONIZE , SC_HARMONIZE , SI_HARMONIZE , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); + //set_sc( WM_POEMOFNETHERWORLD , SC_STOP , SI_NETHERWORLD , SCB_NONE ); + //set_sc( WM_VOICEOFSIREN , SC_VOICEOFSIREN , SI_VOICEOFSIREN , SCB_NONE ); + //set_sc( WM_LULLABY_DEEPSLEEP , SC_DEEPSLEEP , SI_DEEPSLEEP , SCB_NONE ); + //set_sc( WM_SIRCLEOFNATURE , SC_SIRCLEOFNATURE , SI_SIRCLEOFNATURE , SCB_NONE ); + //set_sc( WM_GLOOMYDAY , SC_GLOOMYDAY , SI_GLOOMYDAY , SCB_FLEE|SCB_ASPD ); + //set_sc( WM_SONG_OF_MANA , SC_SONGOFMANA , SI_SONGOFMANA , SCB_NONE ); + //set_sc( WM_DANCE_WITH_WUG , SC_DANCEWITHWUG , SI_DANCEWITHWUG , SCB_ASPD ); + //set_sc( WM_SATURDAY_NIGHT_FEVER , SC_SATURDAYNIGHTFEVER , SI_SATURDAYNIGHTFEVER , SCB_BATK|SCB_DEF|SCB_FLEE|SCB_REGEN ); + //set_sc( WM_LERADS_DEW , SC_LERADSDEW , SI_LERADSDEW , SCB_MAXHP ); + //set_sc( WM_MELODYOFSINK , SC_MELODYOFSINK , SI_MELODYOFSINK , SCB_BATK|SCB_MATK ); + //set_sc( WM_BEYOND_OF_WARCRY , SC_BEYONDOFWARCRY , SI_WARCRYOFBEYOND , SCB_BATK|SCB_MATK ); + //set_sc( WM_UNLIMITED_HUMMING_VOICE, SC_UNLIMITEDHUMMINGVOICE, SI_UNLIMITEDHUMMINGVOICE, SCB_NONE ); + ///** + // * Sorcerer + // **/ + //set_sc( SO_FIREWALK , SC_PROPERTYWALK , SI_PROPERTYWALK , SCB_NONE ); + //set_sc( SO_ELECTRICWALK , SC_PROPERTYWALK , SI_PROPERTYWALK , SCB_NONE ); + //set_sc( SO_SPELLFIST , SC_SPELLFIST , SI_SPELLFIST , SCB_NONE ); + //set_sc( SO_CLOUD_KILL , SC_POISON , SI_CLOUDKILL , SCB_NONE ); + //set_sc( SO_STRIKING , SC_STRIKING , SI_STRIKING , SCB_WATK|SCB_CRI ); + //set_sc( SO_WARMER , SC_WARMER , SI_WARMER , SCB_NONE ); + //set_sc( SO_VACUUM_EXTREME , SC_VACUUM_EXTREME , SI_VACUUM_EXTREME , SCB_NONE ); + //set_sc( SO_ARRULLO , SC_DEEPSLEEP , SI_DEEPSLEEP , SCB_NONE ); + ///** + // * Genetic + // **/ + //set_sc( GN_CARTBOOST , SC_GN_CARTBOOST, SI_CARTSBOOST , SCB_SPEED ); + //set_sc( GN_THORNS_TRAP , SC_THORNSTRAP , SI_THORNTRAP , SCB_NONE ); + //set_sc( GN_BLOOD_SUCKER , SC_BLOODSUCKER , SI_BLOODSUCKER , SCB_NONE ); + //set_sc( GN_WALLOFTHORN , SC_STOP , SI_BLANK , SCB_NONE ); + //set_sc( GN_FIRE_EXPANSION_SMOKE_POWDER, SC_SMOKEPOWDER , SI_FIRE_EXPANSION_SMOKE_POWDER, SCB_NONE ); + //set_sc( GN_FIRE_EXPANSION_TEAR_GAS , SC_TEARGAS , SI_FIRE_EXPANSION_TEAR_GAS , SCB_NONE ); + //set_sc( GN_MANDRAGORA , SC_MANDRAGORA , SI_MANDRAGORA , SCB_INT ); // Storing the target job rather than simply SC_SPIRIT simplifies code later on. SkillStatusChangeTable[SL_ALCHEMIST] = (sc_type)MAPID_ALCHEMIST, @@ -516,6 +678,81 @@ void initChangeTables(void) StatusIconChangeTable[SC_MERC_HPUP] = SI_MERC_HPUP; StatusIconChangeTable[SC_MERC_SPUP] = SI_MERC_SPUP; StatusIconChangeTable[SC_MERC_HITUP] = SI_MERC_HITUP; + // Warlock Spheres + StatusIconChangeTable[SC_SPHERE_1] = SI_SPHERE_1; + StatusIconChangeTable[SC_SPHERE_2] = SI_SPHERE_2; + StatusIconChangeTable[SC_SPHERE_3] = SI_SPHERE_3; + StatusIconChangeTable[SC_SPHERE_4] = SI_SPHERE_4; + StatusIconChangeTable[SC_SPHERE_5] = SI_SPHERE_5; + + StatusIconChangeTable[SC_NEUTRALBARRIER_MASTER] = SI_NEUTRALBARRIER_MASTER; + StatusIconChangeTable[SC_STEALTHFIELD_MASTER] = SI_STEALTHFIELD_MASTER; + StatusIconChangeTable[SC_OVERHEAT] = SI_OVERHEAT; + StatusIconChangeTable[SC_OVERHEAT_LIMITPOINT] = SI_OVERHEAT_LIMITPOINT; + + StatusIconChangeTable[SC_HALLUCINATIONWALK_POSTDELAY] = SI_HALLUCINATIONWALK_POSTDELAY; + StatusIconChangeTable[SC_TOXIN] = SI_TOXIN; + StatusIconChangeTable[SC_PARALYSE] = SI_PARALYSE; + StatusIconChangeTable[SC_VENOMBLEED] = SI_VENOMBLEED; + StatusIconChangeTable[SC_MAGICMUSHROOM] = SI_MAGICMUSHROOM; + StatusIconChangeTable[SC_DEATHHURT] = SI_DEATHHURT; + StatusIconChangeTable[SC_PYREXIA] = SI_PYREXIA; + StatusIconChangeTable[SC_OBLIVIONCURSE] = SI_OBLIVIONCURSE; + StatusIconChangeTable[SC_LEECHESEND] = SI_LEECHESEND; + + StatusIconChangeTable[SC_SHIELDSPELL_DEF] = SI_SHIELDSPELL_DEF; + StatusIconChangeTable[SC_SHIELDSPELL_MDEF] = SI_SHIELDSPELL_MDEF; + StatusIconChangeTable[SC_SHIELDSPELL_REF] = SI_SHIELDSPELL_REF; + StatusIconChangeTable[SC_BANDING_DEFENCE] = SI_BANDING_DEFENCE; + + StatusIconChangeTable[SC_GLOOMYDAY_SK] = SI_GLOOMYDAY; + + StatusIconChangeTable[SC_CURSEDCIRCLE_ATKER] = SI_CURSEDCIRCLE_ATKER; + + StatusIconChangeTable[SC_STOMACHACHE] = SI_STOMACHACHE; + StatusIconChangeTable[SC_MYSTERIOUS_POWDER] = SI_MYSTERIOUS_POWDER; + StatusIconChangeTable[SC_MELON_BOMB] = SI_MELON_BOMB; + StatusIconChangeTable[SC_BANANA_BOMB] = SI_BANANA_BOMB; + StatusIconChangeTable[SC_BANANA_BOMB_SITDOWN] = SI_BANANA_BOMB_SITDOWN_POSTDELAY; + + //Genetics New Food Items Status Icons + StatusIconChangeTable[SC_SAVAGE_STEAK] = SI_SAVAGE_STEAK; + StatusIconChangeTable[SC_COCKTAIL_WARG_BLOOD] = SI_COCKTAIL_WARG_BLOOD; + StatusIconChangeTable[SC_MINOR_BBQ] = SI_MINOR_BBQ; + StatusIconChangeTable[SC_SIROMA_ICE_TEA] = SI_SIROMA_ICE_TEA; + StatusIconChangeTable[SC_DROCERA_HERB_STEAMED] = SI_DROCERA_HERB_STEAMED; + StatusIconChangeTable[SC_PUTTI_TAILS_NOODLES] = SI_PUTTI_TAILS_NOODLES; + + StatusIconChangeTable[SC_BOOST500] |= SI_BOOST500; + StatusIconChangeTable[SC_FULL_SWING_K] |= SI_FULL_SWING_K; + StatusIconChangeTable[SC_MANA_PLUS] |= SI_MANA_PLUS; + StatusIconChangeTable[SC_MUSTLE_M] |= SI_MUSTLE_M; + StatusIconChangeTable[SC_LIFE_FORCE_F] |= SI_LIFE_FORCE_F; + StatusIconChangeTable[SC_EXTRACT_WHITE_POTION_Z] |= SI_EXTRACT_WHITE_POTION_Z; + StatusIconChangeTable[SC_VITATA_500] |= SI_VITATA_500; + StatusIconChangeTable[SC_EXTRACT_SALAMINE_JUICE] |= SI_EXTRACT_SALAMINE_JUICE; + + // Elemental Spirit's 'side' status change icons. + StatusIconChangeTable[SC_CIRCLE_OF_FIRE] = SI_CIRCLE_OF_FIRE; + StatusIconChangeTable[SC_FIRE_CLOAK] = SI_FIRE_CLOAK; + StatusIconChangeTable[SC_WATER_SCREEN] = SI_WATER_SCREEN; + StatusIconChangeTable[SC_WATER_DROP] = SI_WATER_DROP; + StatusIconChangeTable[SC_WIND_STEP] = SI_WIND_STEP; + StatusIconChangeTable[SC_WIND_CURTAIN] = SI_WIND_CURTAIN; + StatusIconChangeTable[SC_SOLID_SKIN] = SI_SOLID_SKIN; + StatusIconChangeTable[SC_STONE_SHIELD] = SI_STONE_SHIELD; + StatusIconChangeTable[SC_PYROTECHNIC] = SI_PYROTECHNIC; + StatusIconChangeTable[SC_HEATER] = SI_HEATER; + StatusIconChangeTable[SC_TROPIC] = SI_TROPIC; + StatusIconChangeTable[SC_AQUAPLAY] = SI_AQUAPLAY; + StatusIconChangeTable[SC_COOLER] = SI_COOLER; + StatusIconChangeTable[SC_CHILLY_AIR] = SI_CHILLY_AIR; + StatusIconChangeTable[SC_GUST] = SI_GUST; + StatusIconChangeTable[SC_BLAST] = SI_BLAST; + StatusIconChangeTable[SC_WILD_STORM] = SI_WILD_STORM; + StatusIconChangeTable[SC_PETROLOGY] = SI_PETROLOGY; + StatusIconChangeTable[SC_CURSED_SOIL] = SI_CURSED_SOIL; + StatusIconChangeTable[SC_UPHEAVAL] = SI_UPHEAVAL; //Other SC which are not necessarily associated to skills. StatusChangeFlagTable[SC_ASPDPOTION0] = SCB_ASPD; @@ -573,7 +810,12 @@ void initChangeTables(void) StatusChangeFlagTable[SC_MERC_HPUP] |= SCB_MAXHP; StatusChangeFlagTable[SC_MERC_SPUP] |= SCB_MAXSP; StatusChangeFlagTable[SC_MERC_HITUP] |= SCB_HIT; - +#if RE_EDP + /** + * In RE EDP increases your atk and weapon atk + **/ + StatusChangeFlagTable[SC_EDP] |= SCB_BATK|SCB_WATK; +#endif if( !battle_config.display_hallucination ) //Disable Hallucination. StatusIconChangeTable[SC_HALLUCINATION] = SI_BLANK; } @@ -728,6 +970,7 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s status_change_end(target, SC_HIDING, INVALID_TIMER); status_change_end(target, SC_CLOAKING, INVALID_TIMER); status_change_end(target, SC_CHASEWALK, INVALID_TIMER); + status_change_end(target, SC_CAMOUFLAGE, INVALID_TIMER); if ((sce=sc->data[SC_ENDURE]) && !sce->val4) { //Endure count is only reduced by non-players on non-gvg maps. //val4 signals infinite endure. [Skotlex] @@ -745,6 +988,8 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s } if(sc->data[SC_DANCING] && (unsigned int)hp > status->max_hp>>2) status_change_end(target, SC_DANCING, INVALID_TIMER); + if(sc->data[SC_CLOAKINGEXCEED] && --(sc->data[SC_CLOAKINGEXCEED]->val2) <= 0) + status_change_end(target,SC_CLOAKINGEXCEED,-1); } unit_skillcastcancel(target, 2); } @@ -1176,6 +1421,8 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, int } if (sc->option&OPTION_CHASEWALK && skill_num != ST_CHASEWALK) return 0; + if(sc->option&OPTION_MOUNTING) + return 0;//New mounts can't attack nor use skills in the client; this check makes it cheat-safe [Ind] } if (target == NULL || target == src) //No further checking needed. return 1; @@ -1210,6 +1457,8 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, int if (tsc->option&hide_flag && !(status->mode&MD_BOSS) && (sd->special_state.perfect_hiding || !(status->mode&MD_DETECTOR))) return 0; + if( tsc->data[SC_CAMOUFLAGE] && !(status->mode&(MD_BOSS|MD_DETECTOR)) && !skill_num ) + return 0; } break; case BL_ITEM: //Allow targetting of items to pick'em up (or in the case of mobs, to loot them). @@ -1256,18 +1505,14 @@ int status_check_visibility(struct block_list *src, struct block_list *target) switch (target->type) { //Check for chase-walk/hiding/cloaking opponents. case BL_PC: - if(tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) && - !(status->mode&MD_BOSS) && - ( - ((TBL_PC*)target)->special_state.perfect_hiding || - !(status->mode&MD_DETECTOR) - )) + if( (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC_CAMOUFLAGE]) && !(status->mode&MD_BOSS) && + ( ((TBL_PC*)target)->special_state.perfect_hiding || !(status->mode&MD_DETECTOR) ) ) return 0; break; default: - if (tsc && tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) && - !(status->mode&(MD_BOSS|MD_DETECTOR))) - return 0; + if( tsc && (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC_CAMOUFLAGE]) && !(status->mode&(MD_BOSS|MD_DETECTOR)) ) + return 0; + } return 1; @@ -1288,7 +1533,24 @@ int status_base_amotion_pc(struct map_session_data* sd, struct status_data* stat // raw delay adjustment from bAspd bonus amotion+= sd->aspd_add; - +#if RRMODE + /** + * Bearing a shield decreases your ASPD by a fixed value depending on your class + **/ + if( sd->status.shield ) + amotion += re_job_db[pc_class2idx(sd->status.class_)][SHIELD_ASPD]; + /** + * RE Absolute aspd modifiers + **/ + if( sd->sc.count ) { + int i; + if ( sd->sc.data[i=SC_ASPDPOTION3] || + sd->sc.data[i=SC_ASPDPOTION2] || + sd->sc.data[i=SC_ASPDPOTION1] || + sd->sc.data[i=SC_ASPDPOTION0] ) + amotion -= sd->sc.data[i]->val1*10; + } +#endif return amotion; } @@ -1331,13 +1593,24 @@ static unsigned short status_base_atk(const struct block_list *bl, const struct static inline unsigned short status_base_matk_max(const struct status_data* status) { - return status->int_+(status->int_/5)*(status->int_/5); + #if RRMODE + return status->matk_max;//In RE maximum MATK signs weapon matk, which we store in this var + #else //Original Max MATK Formula + return status->int_+(status->int_/5)*(status->int_/5); + #endif } - +#if RRMODE +static inline unsigned short status_base_matk_min(const struct status_data* status, int lvl) +#else static inline unsigned short status_base_matk_min(const struct status_data* status) +#endif { - return status->int_+(status->int_/7)*(status->int_/7); + #if RRMODE //Renewal MATK Formula + return status->int_+(status->int_/2)+(status->dex/5)+(status->luk/3)+(lvl/4); + #else //Original Min MATK Formula + return status->int_+(status->int_/7)*(status->int_/7); + #endif } @@ -1350,14 +1623,31 @@ void status_calc_misc(struct block_list *bl, struct status_data *status, int lev status->hit = status->flee = status->def2 = status->mdef2 = status->cri = status->flee2 = 0; - +#if RRMODE + status->matk_min = status_base_matk_min(status, level); +#else status->matk_min = status_base_matk_min(status); +#endif status->matk_max = status_base_matk_max(status); +#if RRMODE //Renewal Formulas + status->hit += level + status->dex;//base level + ( every 1 dex = +1 hit ) + status->hit += status->luk / 3;//every 3 luk = +1 hit + status->flee += level + status->agi;//base level + ( every 1 agi = +1 flee ) + status->flee += status->luk/5;//every 5 luk = +1 flee + status->def2 += status->agi / 5;//every 5 agi = +1 def + status->def2 += status->vit / 2;//every 2 agi = +1 def + status->def2 += level / 2;//every 2 lvls = +1 def + status->mdef2 += status->int_ / 2;//every 2 int = +1 mdef + status->mdef2 += status->dex / 5;//every 5 dex = +1 mdef + status->mdef2 += level /4;//every 4 lvls = +1 mdef + //status->matk_min += level/4;//every 4 lvls = +1 matk +#else //Old Formulas status->hit += level + status->dex; status->flee += level + status->agi; status->def2 += status->vit; status->mdef2 += status->int_ + (status->vit>>1); +#endif if( bl->type&battle_config.enable_critical ) status->cri += status->luk*3 + 10; @@ -1374,6 +1664,10 @@ void status_calc_misc(struct block_list *bl, struct status_data *status, int lev status->batk = cap_value(temp, 0, USHRT_MAX); } else status->batk = status_base_atk(bl, status); +#if RRMODE //Renewal ATK Bonus Formula (after atk is calculated) + status->batk += status->luk / 3;//every 3 luk = +1ATK + status->batk += level / 4;//every 4 levels = +1 ATK +#endif if (status->cri) switch (bl->type) { case BL_MOB: @@ -1684,6 +1978,18 @@ static unsigned int status_base_pc_maxsp(struct map_session_data* sd, struct sta return val; } +#if RRMODE +/** + * Renewal Absolute Bonus to be applied after all bonuses were applied (so % bonuses on say, skills, don't affect them) + **/ +void status_renewal_postcalc(struct status_data* status, int flag) { + if( flag&SCB_FLEE ) + status->flee += 100; + if( flag&SCB_HIT ) + status->hit += 175; + return; +} +#endif //Calculates player data from scratch without counting SC adjustments. //Should be invoked whenever players raise stats, learn passive skills or change equipment. @@ -1909,7 +2215,6 @@ int status_calc_pc_(struct map_session_data* sd, bool first) int r,wlv = sd->inventory_data[index]->wlv; struct weapon_data *wd; struct weapon_atk *wa; - if (wlv >= MAX_REFINE_BONUS) wlv = MAX_REFINE_BONUS - 1; if(i == EQI_HAND_L && sd->status.inventory[index].equip == EQP_HAND_L) { @@ -1921,6 +2226,21 @@ int status_calc_pc_(struct map_session_data* sd, bool first) } wa->atk += sd->inventory_data[index]->atk; wa->atk2 = (r=sd->status.inventory[index].refine)*refinebonus[wlv][0]; + #if RRMODE + /** + * in RE matk_max is used as the weapon's matk. + * += is used so that two-wield weapons (in the case of, say, sinx) bonus stack. + **/ + status->matk_max += sd->inventory_data[index]->matk; + /** + * Refine Bonus + **/ + status->matk_max += sd->status.inventory[index].refine * refinebonus[wlv][0]; + /** + * In RE weapon level is used in several areas, this way we save performance + **/ + status->wlv = wlv; + #endif if((r-=refinebonus[wlv][2])>0) //Overrefine bonus. wd->overrefine = r*refinebonus[wlv][1]; @@ -2277,7 +2597,6 @@ int status_calc_pc_(struct map_session_data* sd, bool first) status->flee += skill*(sd->class_&JOBL_2 && (sd->class_&MAPID_BASEMASK) == MAPID_THIEF? 4 : 3); if((skill=pc_checkskill(sd,MO_DODGE))>0) status->flee += (skill*3)>>1; - // ----- EQUIPMENT-DEF CALCULATION ----- // Apply relative modifiers from equipment @@ -2429,7 +2748,6 @@ int status_calc_pc_(struct map_session_data* sd, bool first) sd->subele[ELE_WIND] += sc->data[SC_ARMOR_RESIST]->val4; } } - status_cpy(&sd->battle_status, status); // ----- CLIENT-SIDE REFRESH ----- @@ -2996,18 +3314,26 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) if(flag&SCB_MATK) { //New matk + #if RRMODE + status->matk_min = status_base_matk_min(status,status_get_lv(bl)); + #else status->matk_min = status_base_matk_min(status); + #endif status->matk_max = status_base_matk_max(status); if( bl->type&BL_PC && sd->matk_rate != 100 ) { //Bonuses from previous matk + #if RRMODE == 0 //Only changed in non-re [RRInd] status->matk_max = status->matk_max * sd->matk_rate/100; + #endif status->matk_min = status->matk_min * sd->matk_rate/100; } status->matk_min = status_calc_matk(bl, sc, status->matk_min); - status->matk_max = status_calc_matk(bl, sc, status->matk_max); + #if RRMODE == 0 //Only changed in non-re [RRInd] + status->matk_max = status_calc_matk(bl, sc, status->matk_max); + #endif if(sc->data[SC_MAGICPOWER]) { //Store current matk values sc->mp_matk_min = status->matk_min; @@ -3088,14 +3414,15 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) status->dmotion = status_calc_dmotion(bl, sc, b_status->dmotion); } } - +#if RRMODE + status_renewal_postcalc(status,flag); +#endif if(flag&(SCB_VIT|SCB_MAXHP|SCB_INT|SCB_MAXSP) && bl->type&BL_REGEN) status_calc_regen(bl, status, status_get_regen_data(bl)); if(flag&SCB_REGEN && bl->type&BL_REGEN) status_calc_regen_rate(bl, status_get_regen_data(bl), sc); } - /// Recalculates parts of an object's base status and battle status according to the specified flags. /// Also sends updates to the client wherever applicable. /// @param flag bitfield of values from enum scb_flag @@ -3265,6 +3592,11 @@ static unsigned short status_calc_str(struct block_list *bl, struct status_chang str += ((sc->data[SC_MARIONETTE2]->val3)>>16)&0xFF; if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH && str < 50) str = 50; + /** + * RK Rune Skill + **/ + if(sc->data[SC_GIANTGROWTH]) + str += 30; return (unsigned short)cap_value(str,0,USHRT_MAX); } @@ -3304,6 +3636,11 @@ static unsigned short status_calc_agi(struct block_list *bl, struct status_chang agi += ((sc->data[SC_MARIONETTE2]->val3)>>8)&0xFF; if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH && agi < 50) agi = 50; + /** + * Arch Bishop + **/ + if(sc->data[SC_ADORAMUS]) + agi -= sc->data[SC_ADORAMUS]->val2; return (unsigned short)cap_value(agi,0,USHRT_MAX); } @@ -3481,6 +3818,13 @@ static unsigned short status_calc_batk(struct block_list *bl, struct status_chan batk += sc->data[SC_GATLINGFEVER]->val3; if(sc->data[SC_MADNESSCANCEL]) batk += 100; +#if RE_EDP + /** + * in RE EDP increases your base atk by atk x Skill Level. + **/ + if( sc->data[SC_EDP] ) + batk = batk * sc->data[SC_EDP]->val1; +#endif return (unsigned short)cap_value(batk,0,USHRT_MAX); } @@ -3525,6 +3869,13 @@ static unsigned short status_calc_watk(struct block_list *bl, struct status_chan watk -= watk * sc->data[SC_STRIPWEAPON]->val2/100; if(sc->data[SC_MERC_ATKUP]) watk += sc->data[SC_MERC_ATKUP]->val2; +#if RE_EDP + /** + * in RE EDP increases your weapon atk by watk x Skill Level - 1 + **/ + if( sc->data[SC_EDP] && sc->data[SC_EDP]->val1 > 1 ) + watk = watk * (sc->data[SC_EDP]->val1 - 1); +#endif return (unsigned short)cap_value(watk,0,USHRT_MAX); } @@ -3563,6 +3914,8 @@ static signed short status_calc_critical(struct block_list *bl, struct status_ch critical += sc->data[SC_TRUESIGHT]->val2; if(sc->data[SC_CLOAKING]) critical += critical; + if(sc->data[SC_CAMOUFLAGE]) + critical += 100; return (short)cap_value(critical,10,SHRT_MAX); } @@ -3593,6 +3946,8 @@ static signed short status_calc_hit(struct block_list *bl, struct status_change hit += 20; // RockmanEXE; changed based on updated [Reddozen] if(sc->data[SC_MERC_HITUP]) hit += sc->data[SC_MERC_HITUP]->val2; + if(sc->data[SC_FEAR]) + hit -= hit * 20 / 100; return (short)cap_value(hit,1,SHRT_MAX); } @@ -3640,6 +3995,29 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change flee += 10 + sc->data[SC_SPEED]->val1 * 10; if(sc->data[SC_MERC_FLEEUP]) flee += sc->data[SC_MERC_FLEEUP]->val2; + if(sc->data[SC_FEAR]) + flee -= flee * 20 / 100; + if(sc->data[SC_PARALYSE]) + flee -= flee / 10; // 10% Flee reduction + if(sc->data[SC_INFRAREDSCAN]) + flee -= flee * 30 / 100; + if( sc->data[SC__LAZINESS] ) + flee -= flee * sc->data[SC__LAZINESS]->val3 / 100; + if( sc->data[SC_GLOOMYDAY] ) + flee -= flee * sc->data[SC_GLOOMYDAY]->val2 / 100; + if( sc->data[SC_HALLUCINATIONWALK] ) + flee += sc->data[SC_HALLUCINATIONWALK]->val2; + if( sc->data[SC_SATURDAYNIGHTFEVER] ) + flee -= flee * (40 + 10 * sc->data[SC_SATURDAYNIGHTFEVER]->val1) / 100; + if( sc->data[SC_WATER_BARRIER] ) + flee -= sc->data[SC_WATER_BARRIER]->val3; + if( sc->data[SC_WIND_STEP_OPTION] ) + flee += flee * sc->data[SC_WIND_STEP_OPTION]->val2 / 100; + if( sc->data[SC_ZEPHYR] ) + flee += flee * sc->data[SC_ZEPHYR]->val2 / 100; + if( sc->data[SC_MARSHOFABYSS] ) + flee -= (9 * sc->data[SC_MARSHOFABYSS]->val3 / 10 + sc->data[SC_MARSHOFABYSS]->val2 / 10) * (bl->type == BL_MOB ? 2 : 1); + return (short)cap_value(flee,1,SHRT_MAX); } @@ -3696,6 +4074,26 @@ static signed char status_calc_def(struct block_list *bl, struct status_change * def -= def * sc->data[SC_STRIPSHIELD]->val2/100; if (sc->data[SC_FLING]) def -= def * (sc->data[SC_FLING]->val2)/100; + if( sc->data[SC_FREEZING] ) + def -= def * 3 / 10; + if( sc->data[SC_MARSHOFABYSS] ) + def -= def * ( 6 + 6 * sc->data[SC_MARSHOFABYSS]->val3/10 + (bl->type == BL_MOB ? 5 : 3) * sc->data[SC_MARSHOFABYSS]->val2/36 ) / 100; + if( sc->data[SC_ANALYZE] ) + def -= def * ( 14 * sc->data[SC_ANALYZE]->val1 ) / 100; + if( sc->data[SC__BLOODYLUST] ) + def -= def * 55 / 100; + if( sc->data[SC_FORCEOFVANGUARD] ) + def += def * 2 * sc->data[SC_FORCEOFVANGUARD]->val1 / 100; + if(sc->data[SC_SATURDAYNIGHTFEVER]) + def -= def * (10 + 10 * sc->data[SC_SATURDAYNIGHTFEVER]->val1) / 100; + if(sc->data[SC_EARTHDRIVE]) + def -= def * 25 / 100; + if( sc->data[SC_GT_CHANGE] ) + def -= def * sc->data[SC_GT_CHANGE]->val3 / 100; + if( sc->data[SC_ROCK_CRUSHER] ) + def -= def * sc->data[SC_ROCK_CRUSHER]->val2 / 100; + if( sc->data[SC_POWER_OF_GAIA] ) + def += def * sc->data[SC_POWER_OF_GAIA]->val2 / 100; return (signed char)cap_value(def,CHAR_MIN,CHAR_MAX); } @@ -3728,6 +4126,20 @@ static signed short status_calc_def2(struct block_list *bl, struct status_change + def2 * ( sc->data[SC_JOINTBEAT]->val2&BREAK_WAIST ? 25 : 0 ) / 100; if(sc->data[SC_FLING]) def2 -= def2 * (sc->data[SC_FLING]->val3)/100; + if( sc->data[SC_FREEZING] ) + def2 -= def2 * 3 / 10; + if(sc->data[SC_ANALYZE]) + def2 -= def2 * ( 14 * sc->data[SC_ANALYZE]->val1 ) / 100; + if( sc->data[SC_ECHOSONG] ) + def2 += def2 * sc->data[SC_ECHOSONG]->val2/100; + if( sc->data[SC_PRESTIGE] ) + def2 += def2 * sc->data[SC_PRESTIGE]->val1 / 100; + if( sc->data[SC_SHIELDSPELL_REF] && sc->data[SC_SHIELDSPELL_REF]->val1 == 1 ) + def2 += sc->data[SC_SHIELDSPELL_REF]->val2; + if( sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 0 ) + def2 += (5 + sc->data[SC_BANDING]->val1) * (sc->data[SC_BANDING]->val2); + if( sc->data[SC_GT_REVITALIZE] ) + def2 += def2 * ( 50 + 10 * sc->data[SC_GT_REVITALIZE]->val1 ) / 100; return (short)cap_value(def2,1,SHRT_MAX); } @@ -3755,6 +4167,16 @@ static signed char status_calc_mdef(struct block_list *bl, struct status_change mdef += sc->data[SC_ENDURE]->val1; if(sc->data[SC_CONCENTRATION]) mdef += 1; //Skill info says it adds a fixed 1 Mdef point. + if( sc->data[SC_MARSHOFABYSS] ) + mdef -= mdef * ( 6 + 6 * sc->data[SC_MARSHOFABYSS]->val3/10 + (bl->type == BL_MOB ? 5 : 3) * sc->data[SC_MARSHOFABYSS]->val2/36 ) / 100; + if(sc->data[SC_ANALYZE]) + mdef -= mdef * ( 14 * sc->data[SC_ANALYZE]->val1 ) / 100; + if(sc->data[SC_SYMPHONYOFLOVER]) + mdef += mdef * sc->data[SC_SYMPHONYOFLOVER]->val2 / 100; + if(sc->data[SC_GT_CHANGE]) + mdef -= mdef * sc->data[SC_GT_CHANGE]->val3 / 100; + if(sc->data[SC_WATER_BARRIER]) + mdef += sc->data[SC_WATER_BARRIER]->val2; return (signed char)cap_value(mdef,CHAR_MIN,CHAR_MAX); } @@ -3768,6 +4190,8 @@ static signed short status_calc_mdef2(struct block_list *bl, struct status_chang return 0; if(sc->data[SC_MINDBREAKER]) mdef2 -= mdef2 * sc->data[SC_MINDBREAKER]->val3/100; + if(sc->data[SC_ANALYZE]) + mdef2 -= mdef2 * ( 14 * sc->data[SC_ANALYZE]->val1 ) / 100; return (short)cap_value(mdef2,1,SHRT_MAX); } @@ -3794,9 +4218,17 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha if( sc->data[SC_FUSION] ) val = 25; - else - if( sd && pc_isriding(sd) ) - val = 25; + else if( sd ) { + if( pc_isriding(sd) || sd->sc.option&(OPTION_DRAGON|OPTION_MOUNTING) ) + val = 25;//Same bonus + else if( sd->sc.option&OPTION_WUGRIDER ) + val = 15 + 5 * pc_checkskill(sd, RA_WUGRIDER); + else if( sd->sc.option&OPTION_MADOGEAR ) { + val = (- 10 * (5 - pc_checkskill(sd,NC_MADOLICENCE))); + if( sc->data[SC_ACCELERATION] ) + val += 25; + } + } speed_rate -= val; } @@ -3821,7 +4253,7 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha if( sc->data[SC_DECREASEAGI] ) val = max( val, 25 ); - if( sc->data[SC_QUAGMIRE] ) + if( sc->data[SC_QUAGMIRE] || sc->data[SC_HALLUCINATIONWALK_POSTDELAY]) val = max( val, 50 ); if( sc->data[SC_DONTFORGETME] ) val = max( val, sc->data[SC_DONTFORGETME]->val3 ); @@ -3845,6 +4277,24 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha val = max( val, sc->data[SC_SUITON]->val3 ); if( sc->data[SC_SWOO] ) val = max( val, 300 ); + if( sc->data[SC_FREEZING] ) + val = max( val, 70 ); + if( sc->data[SC_MARSHOFABYSS] ) + val = max( val, 40 + 10 * sc->data[SC_MARSHOFABYSS]->val1 ); + if( sc->data[SC_CAMOUFLAGE] && (sc->data[SC_CAMOUFLAGE]->val3&1) == 0 ) + val = max( val, sc->data[SC_CAMOUFLAGE]->val1 < 3 ? 300 : 25 * (6 - sc->data[SC_CAMOUFLAGE]->val1) ); + if( sc->data[SC__GROOMY] ) + val = max( val, sc->data[SC__GROOMY]->val2); + if( sc->data[SC_STEALTHFIELD_MASTER] ) + val = max( val, 30 ); + if( sc->data[SC_BANDING_DEFENCE] ) + val = max( val, sc->data[SC_BANDING_DEFENCE]->val1 );//+90% walking speed. + if( sc->data[SC_ROCK_CRUSHER_ATK] ) + val = max( val, sc->data[SC_ROCK_CRUSHER_ATK]->val2 ); + if( sc->data[SC_POWER_OF_GAIA] ) + val = max( val, sc->data[SC_POWER_OF_GAIA]->val2 ); + if( sc->data[SC_MELON_BOMB] ) + val = max( val, sc->data[SC_MELON_BOMB]->val1 ); if( sd && sd->speed_rate + sd->speed_add_rate > 0 ) // permanent item-based speedup val = max( val, sd->speed_rate + sd->speed_add_rate ); @@ -3912,7 +4362,12 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha /// Note that the scale of aspd_rate is 1000 = 100%. static short status_calc_aspd_rate(struct block_list *bl, struct status_change *sc, int aspd_rate) { +#if RRMODE == 0 + /** + * this variable is not used unless in non-RE + **/ int i; +#endif if(!sc || !sc->count) return cap_value(aspd_rate,0,SHRT_MAX); @@ -3981,12 +4436,16 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * else if(sc->data[SC_MADNESSCANCEL]) aspd_rate -= 200; } - +#if RRMODE == 0 + /** + * in RE they give a fixed boost -- we do so along SERVICE4U in status_base_amotion_pc + **/ if(sc->data[i=SC_ASPDPOTION3] || sc->data[i=SC_ASPDPOTION2] || sc->data[i=SC_ASPDPOTION1] || sc->data[i=SC_ASPDPOTION0]) aspd_rate -= sc->data[i]->val2; +#endif if(sc->data[SC_DONTFORGETME]) aspd_rate += 10 * sc->data[SC_DONTFORGETME]->val2; if(sc->data[SC_LONGING]) @@ -4007,6 +4466,41 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * if( sc->data[SC_JOINTBEAT]->val2&BREAK_KNEE ) aspd_rate += 100; } + if( sc->data[SC_FREEZING] ) + aspd_rate += 300; + if( sc->data[SC_HALLUCINATIONWALK_POSTDELAY] ) + aspd_rate += 500; + if( sc->data[SC_FIGHTINGSPIRIT] && sc->data[SC_FIGHTINGSPIRIT]->val2 ) + aspd_rate -= sc->data[SC_FIGHTINGSPIRIT]->val2; + if( sc->data[SC_PARALYSE] ) + aspd_rate += 100; + if( sc->data[SC__BODYPAINT] ) + aspd_rate += aspd_rate * (20 + 5 * sc->data[SC__BODYPAINT]->val1) / 100; + if( sc->data[SC__INVISIBILITY] ) + aspd_rate += aspd_rate * sc->data[SC__INVISIBILITY]->val2 / 100; + if( sc->data[SC__GROOMY] ) + aspd_rate += aspd_rate * sc->data[SC__GROOMY]->val2 / 100; + if( sc->data[SC_SWINGDANCE] ) + aspd_rate -= aspd_rate * sc->data[SC_SWINGDANCE]->val2 / 100; + if( sc->data[SC_DANCEWITHWUG] ) + aspd_rate -= aspd_rate * sc->data[SC_DANCEWITHWUG]->val3 / 100; + if( sc->data[SC_GLOOMYDAY] ) + aspd_rate += aspd_rate * sc->data[SC_GLOOMYDAY]->val3 / 100; + if( sc->data[SC_EARTHDRIVE] ) + aspd_rate += aspd_rate * 25 / 100; + /*As far I tested the skill there is no ASPD addition is applied. [Jobbie] */ + //if( sc->data[SC_RAISINGDRAGON] ) + // aspd_rate -= 100; //FIXME: Need official ASPD bonus of this status. [Jobbie] + if( sc->data[SC_GT_CHANGE] ) + aspd_rate -= aspd_rate * (sc->data[SC_GT_CHANGE]->val2/200) / 100; + if( sc->data[SC_GT_REVITALIZE] ) + aspd_rate -= aspd_rate * sc->data[SC_GT_REVITALIZE]->val2 / 100; + if( sc->data[SC_MELON_BOMB] ) + aspd_rate += aspd_rate * sc->data[SC_MELON_BOMB]->val1 / 100; + if( sc->data[SC_BOOST500] ) + aspd_rate -= aspd_rate * sc->data[SC_BOOST500]->val1/100; + if(sc->data[SC_EXTRACT_SALAMINE_JUICE]) + aspd_rate -= aspd_rate * sc->data[SC_EXTRACT_SALAMINE_JUICE]->val1/100; return (short)cap_value(aspd_rate,0,SHRT_MAX); } @@ -4020,7 +4514,7 @@ static unsigned short status_calc_dmotion(struct block_list *bl, struct status_c return 0; if( sc->data[SC_CONCENTRATION] ) return 0; - if( sc->data[SC_RUN] ) + if( sc->data[SC_RUN] || sc->data[SC_WUGDASH] ) return 0; return (unsigned short)cap_value(dmotion,0,USHRT_MAX); @@ -4045,6 +4539,12 @@ static unsigned int status_calc_maxhp(struct block_list *bl, struct status_chang if(sc->data[SC_MERC_HPUP]) maxhp += maxhp * sc->data[SC_MERC_HPUP]->val2/100; + if(sc->data[SC_EPICLESIS]) + maxhp += maxhp * 5 * sc->data[SC_EPICLESIS]->val1 / 100; + if(sc->data[SC_VENOMBLEED]) + maxhp -= maxhp * 15 / 100; + + return cap_value(maxhp,1,UINT_MAX); } @@ -4078,6 +4578,9 @@ static unsigned char status_calc_element(struct block_list *bl, struct status_ch return ELE_UNDEAD; if(sc->data[SC_ELEMENTALCHANGE]) return sc->data[SC_ELEMENTALCHANGE]->val2; + if(sc->data[SC_SHAPESHIFT]) + return sc->data[SC_SHAPESHIFT]->val2; + return (unsigned char)cap_value(element,0,UCHAR_MAX); } @@ -4096,6 +4599,8 @@ static unsigned char status_calc_element_lv(struct block_list *bl, struct status return 1; if(sc->data[SC_ELEMENTALCHANGE]) return sc->data[SC_ELEMENTALCHANGE]->val1; + if(sc->data[SC_SHAPESHIFT]) + return 1; return (unsigned char)cap_value(lv,1,4); } @@ -4567,7 +5072,7 @@ void status_change_init(struct block_list *bl) //the flag values are the same as in status_change_start. int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int tick, int flag) { - int sc_def, tick_def = 0; + int sc_def = 0, tick_def = 0; struct status_data* status; struct status_change* sc; struct map_session_data *sd; @@ -4618,6 +5123,7 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti sc_def = 3 +status->int_; break; case SC_DECREASEAGI: + case SC_ADORAMUS://Arch Bishop if (sd) tick>>=1; //Half duration for players. case SC_STONE: case SC_FREEZE: @@ -4647,6 +5153,40 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti if (sd) //Duration greatly reduced for players. tick /= 15; //No defense against it (buff). + /** + * 3rd stuff + **/ + case SC_WHITEIMPRISON: + rate -= (status_get_lv(bl) / 5 + status->vit / 4 + status->agi / 10)*100; // Lineal Reduction of Rate + //tick_def = (int)floor(log10(status_get_lv(bl)) * 10.); + break; + case SC_BURNING: + // From iROwiki : http://forums.irowiki.org/showpost.php?p=577240&postcount=583 + tick -= 50*status->luk + 60*status->int_ + 170*status->vit; + tick = max(tick,10000); // Minimum Duration 10s. + break; + case SC_FREEZING: + tick -= 1000 * ((status->vit + status->dex) / 20); + tick = max(tick,10000); // Minimum Duration 10s. + break; + case SC_OBLIVIONCURSE: + sc_def = status->int_*4/5; //FIXME: info said this is the formula of status chance. Check again pls. [Jobbie] + break; + case SC_ELECTRICSHOCKER: + case SC_BITE: + { + if( bl->type == BL_MOB ) + tick -= 1000 * (status->agi/10); + if( sd && type != SC_ELECTRICSHOCKER ) + tick >>= 1; + } + break; + case SC_CRYSTALIZE: + tick -= (1000*(status->vit/10))+(status_get_lv(bl)/50); + break; + case SC_VACUUM_EXTREME: + tick -= 50*status->str; + break; default: //Effect that cannot be reduced? Likely a buff. if (!(rand()%10000 < rate)) @@ -4749,7 +5289,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val struct status_change_entry* sce; struct status_data *status; struct view_data *vd; - int opt_flag, calc_flag, undead_flag; + int opt_flag, calc_flag, undead_flag, val_flag = 0, tick_time = 0; nullpo_ret(bl); sc = status_get_sc(bl); @@ -4787,16 +5327,27 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val //Check for inmunities / sc fails switch (type) { - case SC_FREEZE: case SC_STONE: + if(sc->data[SC_POWER_OF_GAIA]) + return 0; + case SC_FREEZE: //Undead are immune to Freeze/Stone if (undead_flag && !(flag&1)) return 0; case SC_SLEEP: case SC_STUN: + case SC_FREEZING: if (sc->opt1) return 0; //Cannot override other opt1 status changes. [Skotlex] + if((type == SC_FREEZE || type == SC_FREEZING) && sc->data[SC_WARMER]) + return 0; //Immune to Frozen and Freezing status if under Warmer status. [Jobbie] + break; + + case SC_BURNING: + if(sc->opt1 || sc->data[SC_FREEZING]) + return 0; break; + case SC_SIGNUMCRUCIS: //Only affects demons and undead element (but not players) if((!undead_flag && status->race!=RC_DEMON) || bl->type == BL_PC) @@ -4813,12 +5364,16 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_OVERTHRUST: if (sc->data[SC_MAXOVERTHRUST]) return 0; //Overthrust can't take effect if under Max Overthrust. [Skotlex] + case SC_MAXOVERTHRUST: + if( sc->option&OPTION_MADOGEAR ) + return 0;//Overthrust and Overthrust Max cannot be used on Mado Gear [Ind] break; case SC_ADRENALINE: if(sd && !pc_check_weapontype(sd,skill_get_weapontype(BS_ADRENALINE))) return 0; if (sc->data[SC_QUAGMIRE] || - sc->data[SC_DECREASEAGI] + sc->data[SC_DECREASEAGI] || + sc->option&OPTION_MADOGEAR //Adrenaline doesn't affect Mado Gear [Ind] ) return 0; break; @@ -4830,6 +5385,9 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val ) return 0; break; + case SC_MAGNIFICAT: + if( sc->option&OPTION_MADOGEAR ) //Mado is immune to magnificat + break; case SC_ONEHAND: case SC_MERC_QUICKEN: case SC_TWOHANDQUICKEN: @@ -4844,6 +5402,8 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_ASSNCROS: if (sc->data[SC_QUAGMIRE]) return 0; + if(sc->option&OPTION_MADOGEAR) + return 0;//Mado is immune to increase agi, wind walk, cart boost, etc (others above) [Ind] break; case SC_CLOAKING: //Avoid cloaking with no wall and low skill level. [Skotlex] @@ -4995,6 +5555,10 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if (sc->data[SC_LUKFOOD] && sc->data[SC_LUKFOOD]->val1 > val1) return 0; break; + case SC_CAMOUFLAGE: + if( sd && pc_checkskill(sd, RA_CAMOUFLAGE) < 3 && !skill_check_camouflage(bl,NULL) ) + return 0; + break; } //Check for BOSS resistances @@ -5003,8 +5567,6 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val return 0; switch (type) { case SC_BLESSING: - if (!undead_flag && status->race!=RC_DEMON) - break; case SC_DECREASEAGI: case SC_PROVOKE: case SC_COMA: @@ -5013,6 +5575,26 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_RICHMANKIM: case SC_ROKISWEIL: case SC_FOGWALL: + case SC_FREEZING: + case SC_BURNING: // Place here until we have info about its behavior on Boss-monsters. [pakpil] + case SC_MARSHOFABYSS: + case SC_ADORAMUS: + + // Exploid prevention - kRO Fix + case SC_PYREXIA: + case SC_DEATHHURT: + case SC_TOXIN: + case SC_PARALYSE: + case SC_VENOMBLEED: + case SC_MAGICMUSHROOM: + case SC_OBLIVIONCURSE: + case SC_LEECHESEND: + + // Ranger Effects + case SC_BITE: + case SC_ELECTRICSHOCKER: + case SC_MAGNETICFIELD: + return 0; } } @@ -5048,6 +5630,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); status_change_end(bl, SC_ONEHAND, INVALID_TIMER); status_change_end(bl, SC_MERC_QUICKEN, INVALID_TIMER); + status_change_end(bl, SC_ACCELERATION, INVALID_TIMER); break; case SC_ONEHAND: //Removes the Aspd potion effect, as reported by Vicious. [Skotlex] @@ -5286,6 +5869,8 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_EDP: // [Celest] val2 = val1 + 2; //Chance to Poison enemies. val3 = 50*(val1+1); //Damage increase (+50 +50*lv%) + if( sd )//[Ind] - iROwiki says each level increases its duration by 3 seconds + tick += pc_checkskill(sd,GC_RESEARCHNEWPOISON)*3000; break; case SC_POISONREACT: val2=(val1+1)/2 + val1/10; // Number of counters [Skotlex] @@ -5421,10 +6006,10 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val //val3 : Brings the skilllv (merged into val1 here) //val4 : Partner if (val1 == CG_MOONLIT) - clif_status_change(bl,SI_MOONLIT,1,tick); + clif_status_change(bl,SI_MOONLIT,1,tick,0, 0, 0); val1|= (val3<<16); val3 = tick/1000; //Tick duration - tick = 1000; + tick_time = 1000; // [GodLesZ] tick time break; case SC_LONGING: val2 = 500-100*val1; //Aspd penalty. @@ -5432,9 +6017,14 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_EXPLOSIONSPIRITS: val2 = 75 + 25*val1; //Cri bonus break; +#if RRMODE == 0 + /** + * Only in non-RE it's var is changed + **/ case SC_ASPDPOTION0: case SC_ASPDPOTION1: case SC_ASPDPOTION2: +#endif case SC_ASPDPOTION3: val2 = 50*(2+type-SC_ASPDPOTION0); break; @@ -5455,6 +6045,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val clif_changelook(bl,LOOK_CLOTHES_COLOR,vd->cloth_color); break; case SC_NOCHAT: + // [GodLesZ] FIXME: is this correct? a hardcoded interval of 60sec? what about configuration ?_? tick = 60000; val1 = battle_config.manner_system; //Mute filters. if (sd) @@ -5486,7 +6077,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_POISON: /* 毒 */ val3 = tick/1000; //Damage iterations if(val3 < 1) val3 = 1; - tick = 1000; + tick_time = 1000; // [GodLesZ] tick time //val4: HP damage if (bl->type == BL_PC) val4 = (type == SC_DPOISON) ? 3 + status->max_hp/50 : 3 + status->max_hp*3/200; @@ -5500,7 +6091,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_BLEEDING: val4 = tick/10000; if (!val4) val4 = 1; - tick = 10000; + tick_time = 10000; // [GodLesZ] tick time break; case SC_S_LIFEPOTION: case SC_L_LIFEPOTION: @@ -5511,7 +6102,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if( val2 < 1 ) val2 = 1; if( (val4 = tick/(val2 * 1000)) < 1 ) val4 = 1; - tick = val2 * 1000; // val2 = Seconds between heals + tick_time = val2 * 1000; // [GodLesZ] tick time break; case SC_BOSSMAPINFO: if( sd != NULL ) @@ -5525,12 +6116,12 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val1 = boss_md->bl.id; if( (val4 = tick/1000) < 1 ) val4 = 1; - tick = 1000; + tick_time = 1000; // [GodLesZ] tick time } break; case SC_HIDING: val2 = tick/1000; - tick = 1000; + tick_time = 1000; // [GodLesZ] tick time val3 = 0; // unused, previously speed adjustment val4 = val1+3; //Seconds before SP substraction happen. break; @@ -5560,7 +6151,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_SIGHTBLASTER: val3 = skill_get_splash(val2, val1); //Val2 should bring the skill-id. val2 = tick/250; - tick = 10; + tick_time = 10; // [GodLesZ] tick time break; //Permanent effects. @@ -5631,7 +6222,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val2 = 12; //SP cost val4 = 10000; //Decrease at 10secs intervals. val3 = tick/val4; - tick = val4; + tick_time = val4; // [GodLesZ] tick time break; case SC_PARRYING: val2 = 20 + val1*3; //Block Chance @@ -5654,13 +6245,13 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if (!val4) val4 = skill_get_time2(status_sc2skill(type),val1); if (!val4) val4 = 10000; //Val4 holds damage interval val3 = tick/val4; //val3 holds skill duration - tick = val4; + tick_time = val4; // [GodLesZ] tick time break; case SC_GOSPEL: if(val4 == BCT_SELF) { // self effect val2 = tick/10000; - tick = 10000; + tick_time = 10000; // [GodLesZ] tick time status_change_clear_buffs(bl,3); //Remove buffs/debuffs } break; @@ -5926,7 +6517,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_SKA: val2 = tick/1000; val3 = rand()%100; //Def changes randomly every second... - tick = 1000; + tick_time = 1000; // [GodLesZ] tick time break; case SC_JAILED: //Val1 is duration in minutes. Use INT_MAX to specify 'unlimited' time. @@ -6062,6 +6653,487 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_SPL_MATK: val2 = 2; // Splendide group break; + /** + * General + **/ + case SC_FEAR: + val2 = 2; + val4 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_BURNING: + val4 = tick / 2000; // Total Ticks to Burn!! + tick_time = 2000; // [GodLesZ] tick time + break; + /** + * Rune Knight + **/ + case SC_DEATHBOUND: + val2 = 500 + 100 * val1; + break; + case SC_FIGHTINGSPIRIT: + val_flag |= 1|2; + break; + case SC_ABUNDANCE: + val4 = tick / 10000; + tick_time = 10000; // [GodLesZ] tick time + break; + case SC_GIANTGROWTH: + val2 = 10; // Triple damage success rate. + break; + /** + * Arch Bishop + **/ + case SC_RENOVATIO: + val4 = tick / 5000; + tick_time = 5000; + break; + case SC_SECRAMENT: + val2 = 10 * val1; + break; + case SC_VENOMIMPRESS: + val2 = 10 * val1; + val_flag |= 1|2; + break; + case SC_POISONINGWEAPON: + val_flag |= 1|2|4; + break; + case SC_WEAPONBLOCKING: + val2 = 10 + 2 * val1; // Chance + val4 = tick / 3000; + tick_time = 3000; // [GodLesZ] tick time + val_flag |= 1|2; + break; + case SC_TOXIN: + val4 = tick / 10000; + tick_time = 10000; // [GodLesZ] tick time + break; + case SC_MAGICMUSHROOM: + val4 = tick / 4000; + tick_time = 4000; // [GodLesZ] tick time + break; + case SC_PYREXIA: + val4 = tick / 3000; + tick_time = 4000; // [GodLesZ] tick time + break; + case SC_LEECHESEND: + val4 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_OBLIVIONCURSE: + val4 = tick / 3000; + tick_time = 3000; // [GodLesZ] tick time + break; + case SC_ROLLINGCUTTER: + val_flag |= 1; + break; + case SC_CLOAKINGEXCEED: + val2 = ( val1 + 1 ) / 2; // Hits + val3 = ( val1 - 1 ) * 10; // Walk speed + val_flag |= 1|2|4; + if (bl->type == BL_PC) + val4 |= battle_config.pc_cloak_check_type&7; + else + val4 |= battle_config.monster_cloak_check_type&7; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_HALLUCINATIONWALK: + val2 = 50 * val1; // Evasion rate of physical attacks. Flee + val3 = 10 * val1; // Evasion rate of magical attacks. + val_flag |= 1|2|4; + break; + case SC_WHITEIMPRISON: + status_change_end(bl, SC_BURNING, -1); + status_change_end(bl, SC_FREEZING, -1); + status_change_end(bl, SC_FREEZE, -1); + status_change_end(bl, SC_STONE, -1); + break; + case SC_FREEZING: + status_change_end(bl, SC_BURNING, -1); + break; + case SC_READING_SB: + // val2 = sp reduction per second + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_SPHERE_1: + case SC_SPHERE_2: + case SC_SPHERE_3: + case SC_SPHERE_4: + case SC_SPHERE_5: + if( !sd ) + return 0; // Should only work on players. + val4 = tick / 1000; + if( val4 < 1 ) + val4 = 1; + tick_time = 1000; // [GodLesZ] tick time + val_flag |= 1; + break; + case SC_SHAPESHIFT: + switch( val1 ) + { + case 1: val2 = ELE_FIRE; break; + case 2: val2 = ELE_EARTH; break; + case 3: val2 = ELE_WIND; break; + case 4: val2 = ELE_WATER; break; + } + break; + case SC_ELECTRICSHOCKER: + case SC_CRYSTALIZE: + val4 = tick / 1000; + if( val4 < 1 ) + val4 = 1; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_CAMOUFLAGE: + //val3 |= battle_config.pc_camouflage_check_type&7; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_WUGDASH: + val4 = gettick(); //Store time at which you started running. + tick = -1; + break; + case SC__SHADOWFORM: + { + //struct map_session_data * s_sd = map_id2sd(val2); + //if( s_sd ) + // s_sd->shadowform_id = bl->id; + val4 = tick / 1000; + val_flag |= 1|2|4; + tick_time = 1000; // [GodLesZ] tick time + } + break; + case SC__STRIPACCESSORY: + if (!sd) + val2 = 20; + break; + case SC__INVISIBILITY: + val2 = 50 - 10 * val1; // ASPD + val3 = 20 * val1; // CRITICAL + val4 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + val_flag |= 1|2; + break; + case SC__ENERVATION: + val2 = 20 + 10 * val1; // ATK Reduction + val_flag |= 1|2; + if( sd ) pc_delspiritball(sd,sd->spiritball,0); + break; + case SC__GROOMY: + val2 = 20 + 10 * val1; //ASPD. Need to confirm if Movement Speed reduction is the same. [Jobbie] + val3 = 20 * val1; //HIT + val_flag |= 1|2|4; + if( sd ) + { // Removes Animals + //if( pc_isriding(sd,OPTION_RIDING|OPTION_RIDING_DRAGON|OPTION_RIDING_WUG) ) pc_setriding(sd, 0); + //if( pc_iswarg(sd) ) pc_setoption(sd, sd->sc.option&~OPTION_WUG); + if( pc_isfalcon(sd) ) pc_setoption(sd, sd->sc.option&~OPTION_FALCON); + if( sd->status.pet_id > 0 ) pet_menu(sd, 3); + if( merc_is_hom_active(sd->hd) ) merc_hom_vaporize(sd,1); + if( sd->md ) merc_delete(sd->md,3); + } + break; + case SC__LAZINESS: + val2 = 10 + 10 * val1; // Cast reduction + val3 = 10 * val1; // Flee Reduction + val_flag |= 1|2|4; + break; + case SC__UNLUCKY: + val2 = 10 * val1; // Crit and Flee2 Reduction + val_flag |= 1|2|4; + break; + case SC__WEAKNESS: + val2 = 10 * val1; + val_flag |= 1|2; + skill_strip_equip(bl,EQP_WEAPON|EQP_SHIELD,100,val1,tick); + break; + case SC__BLOODYLUST: + val_flag |= 1|2; + break; + case SC_GN_CARTBOOST: + if( val1 < 3 ) + val2 = 50; + else if( val1 < 5 ) + val2 = 75; + else + val2 = 100; + break; + case SC_PROPERTYWALK: + val_flag |= 1|2; + val3 = 0; + break; + case SC_WARMER: + status_change_end(bl, SC_FREEZE, -1); + status_change_end(bl, SC_FREEZING, -1); + status_change_end(bl, SC_CRYSTALIZE, -1); + break; + case SC_STRIKING: + val4 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_BLOODSUCKER: + val4 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_SWINGDANCE: + val2 = 4 * val1; // Walk speed and aspd reduction. + break; + case SC_SYMPHONYOFLOVER: + case SC_RUSHWINDMILL: + case SC_ECHOSONG: + val2 = 6 * val1; + val2 += val3; //Adding 1% * Lesson Bonus + val2 += (int)(val4*2/10); //Adding 0.2% per JobLevel + break; + case SC_MOONLITSERENADE: + val2 = 10 * val1; + break; + case SC_HARMONIZE: + val2 = 3 + 2 * val1; + break; + case SC_VOICEOFSIREN: + val4 = tick / 2000; + tick_time = 2000; // [GodLesZ] tick time + break; + case SC_DEEPSLEEP: + val4 = tick / 2000; + tick_time = 2000; // [GodLesZ] tick time + break; + case SC_SIRCLEOFNATURE: + val2 = 1 + val1; //SP consume + val3 = 40 * val1; //HP recovery + val4 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_SONGOFMANA: + val3 = 10 + (2 * val2); + val4 = tick/3000; + tick_time = 3000; // [GodLesZ] tick time + break; + case SC_SATURDAYNIGHTFEVER: + if (!val4) val4 = skill_get_time2(status_sc2skill(type),val1); + if (!val4) val4 = 3000; + val3 = tick/val4; + tick_time = val4; // [GodLesZ] tick time + break; + case SC_GLOOMYDAY: + val2 = 3 + 2 * val1; // Flee reduction. + val3 = 3 * val1; // ASPD reduction. + break; + case SC_SITDOWN_FORCE: + case SC_BANANA_BOMB_SITDOWN: + if( sd && !pc_issit(sd) ) + { + pc_setsit(sd); + skill_sit(sd,1); + clif_sitting(bl); + } + break; + case SC_DANCEWITHWUG: + val3 = (5 * val1) + (1 * val2); //Still need official value. + break; + case SC_LERADSDEW: + val3 = (5 * val1) + (1 * val2); + break; + case SC_MELODYOFSINK: + val3 = (5 * val1) + (1 * val2); + break; + case SC_BEYONDOFWARCRY: + val3 = (5 * val1) + (1 * val2); + break; + case SC_UNLIMITEDHUMMINGVOICE: + { + struct unit_data *ud = unit_bl2ud(bl); + if( ud == NULL ) return 0; + ud->state.skillcastcancel = 0; + val3 = 15 - (2 * val2); + } + break; + case SC_REFLECTDAMAGE: + val2 = 15 + 5 * val1; + val3 = (val1==5)?20:(val1+4)*2; // SP consumption + val4 = tick/10000; + tick_time = 10000; // [GodLesZ] tick time + break; + case SC_FORCEOFVANGUARD: // This is not the official way to handle it but I think we should use it. [pakpil] + val2 = 20 + 12 * (val1 - 1); // Chance + val3 = 5 + (2 * val1); // Max rage counters + tick_time = 6000; // [GodLesZ] tick time + val_flag |= 1|2|4; + break; + case SC_EXEEDBREAK: + val1 *= 150; // 150 * skill_lv + if( sd ) + { // Chars. + struct item_data *id = sd->inventory_data[sd->equip_index[EQI_HAND_R]]; + if( id ) val1 += (id->weight/10 * id->wlv * status_get_lv(bl) / 100); // (weapon_weight * weapon_level * base_lvl)/100 + val1 += 15 * sd->status.job_level; // 15 * job_lvl + } + else // Mobs + val1 += (400 * status_get_lv(bl) / 100) + (15 * (status_get_lv(bl) / 2)); // About 1138% at mob_lvl 99. Is an aproximation to a standard weapon. [pakpil] + break; + + case SC_PRESTIGE: // Bassed on suggested formula in iRO Wiki and some test, still need more test. [pakpil] + val2 = ((status->int_ + status->luk) / 6) + 5; // Chance to evade magic damage. + val1 *= 15; // Defence added + if( sd ) + val1 += 10 * pc_checkskill(sd,CR_DEFENDER); + val_flag |= 1|2; + break; + case SC_BANDING: + tick_time = 5000; // [GodLesZ] tick time + val_flag |= 1; + break; + case SC_SHIELDSPELL_DEF: + case SC_SHIELDSPELL_MDEF: + case SC_SHIELDSPELL_REF: + val_flag |= 1|2; + break; + case SC_MAGNETICFIELD: + val3 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + break; + case SC_INSPIRATION: + if( sd ) + { + val2 = (40 * val1) + (3 * sd->status.job_level); // ATK bonus + val3 = (sd->status.job_level / 10) * 2 + 12; // All stat bonus + } + val4 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + status_change_clear_buffs(bl,3); //Remove buffs/debuffs + break; + case SC_SPELLFIST: + case SC_CURSEDCIRCLE_ATKER: + val_flag |= 1|2|4; + break; + case SC_CRESCENTELBOW: + val2 = 94 + val1; + val_flag |= 1|2; + break; + case SC_LIGHTNINGWALK: + val1 = 88 + 2 * val1; + val_flag |= 1; + break; + case SC_RAISINGDRAGON: + val3 = tick / 5000; + tick_time = 5000; // [GodLesZ] tick time + break; + case SC_GT_CHANGE: + if( sd ) val2 = (13 * val1 / 2) * sd->status.agi; //Aspd - old formula. + val3 = 20 + 1 * val1; //Base Atk, Reduction to DEF & MDEF + break; + case SC_GT_REVITALIZE: + val2 = 5 * val1; //Custom value VIT, ASPD, SPEED bonus. + val3 = 60 + 40 * val1; //HP recovery + break; + case SC_PYROTECHNIC_OPTION: + val2 = 60; // Watk TODO: Renewal (Atk2) + val3 = 11; // % Increase damage. + val_flag |= 1|2|4; + break; + case SC_HEATER_OPTION: + val2 = 120; // Watk. TODO: Renewal (Atk2) + val3 = 33; // % Increase effects. + val4 = 3; // Change into fire element. + val_flag |= 1|2|4; + break; + case SC_TROPIC_OPTION: + val2 = 180; // Watk. TODO: Renewal (Atk2) + val3 = MG_FIREBOLT; + break; + case SC_AQUAPLAY_OPTION: + val2 = 40; // Matk. TODO: Renewal (Matk1) + val3 = 33; // % Increase effects. + val_flag |= 1|2|4; + break; + case SC_COOLER_OPTION: + val2 = 80; // % Freezing chance + val3 = 33; // % increased damage + val4 = 1; // Change into water elemet + val_flag |= 1|2|4; + break; + case SC_CHILLY_AIR_OPTION: + val2 = 120; // Matk. TODO: Renewal (Matk1) + val3 = MG_COLDBOLT; + val_flag |= 1|2; + break; + case SC_GUST_OPTION: + val2 = 33; + val_flag |= 1|2; + break; + case SC_WIND_STEP_OPTION: + val2 = 50; // % Increase speed and flee. + break; + case SC_BLAST_OPTION: + val2 = 33; + val3 = 4; + val_flag |= 1|2|4; + break; + case SC_WILD_STORM_OPTION: + val2 = MG_LIGHTNINGBOLT; + val_flag |= 1|2; + break; + case SC_PETROLOGY_OPTION: + val2 = 5; + val3 = 33; + val_flag |= 1|2|4; + break; + case SC_CURSED_SOIL_OPTION: + val2 = 10; + val3 = 33; + val4 = 2; + val_flag |= 1|2|4; + break; + case SC_UPHEAVAL_OPTION: + val2 = WZ_EARTHSPIKE; + val_flag |= 1|2; + break; + case SC_CIRCLE_OF_FIRE_OPTION: + val2 = 300; + val_flag |= 1|2; + break; + case SC_FIRE_CLOAK_OPTION: + case SC_WATER_DROP_OPTION: + case SC_WIND_CURTAIN_OPTION: + case SC_STONE_SHIELD_OPTION: + val2 = 20; // Elemental modifier. Not confirmed. + break; + case SC_CIRCLE_OF_FIRE: + case SC_FIRE_CLOAK: + case SC_WATER_DROP: + case SC_WATER_SCREEN: + case SC_WIND_CURTAIN: + case SC_WIND_STEP: + case SC_STONE_SHIELD: + case SC_SOLID_SKIN: + val2 = 10; + tick_time = 2000; // [GodLesZ] tick time + break; + case SC_WATER_BARRIER: + val2 = 40; // Increasement. Mdef1 ??? + val3 = 20; // Reductions. Atk2, Flee1, Matk1 ???? + val_flag |= 1|2|4; + break; + case SC_ZEPHYR: + val2 = 22; // Flee. + break; + case SC_TIDAL_WEAPON: + val2 = 20; // Increase Elemental's attack. + break; + case SC_ROCK_CRUSHER: + case SC_ROCK_CRUSHER_ATK: + case SC_POWER_OF_GAIA: + val2 = 33; + break; + case SC_MELON_BOMB: + case SC_BANANA_BOMB: + val1 = 15; + break; + case SC_STOMACHACHE: + val2 = 8; // SP consume. + val4 = tick / 10000; + tick_time = 10000; // [GodLesZ] tick time + break; default: if( calc_flag == SCB_NONE && StatusSkillChangeTable[type] == 0 && StatusIconChangeTable[type] == 0 ) @@ -6107,12 +7179,15 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_CLOSECONFINE2: case SC_ANKLE: case SC_SPIDERWEB: + case SC_ELECTRICSHOCKER: unit_stop_walking(bl,1); break; case SC_HIDING: case SC_CLOAKING: + case SC_CLOAKINGEXCEED: case SC_CHASEWALK: case SC_WEIGHT90: + case SC_CAMOUFLAGE: unit_stop_attack(bl); break; case SC_SILENCE: @@ -6130,6 +7205,8 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_FREEZE: sc->opt1 = OPT1_FREEZE; break; case SC_STUN: sc->opt1 = OPT1_STUN; break; case SC_SLEEP: sc->opt1 = OPT1_SLEEP; break; + case SC_BURNING: sc->opt1 = OPT1_BURNING; break; // Burning need this to be showed correctly. [pakpil] + case SC_WHITEIMPRISON: sc->opt1 = OPT1_IMPRISON; break; //OPT2 case SC_POISON: sc->opt2 |= OPT2_POISON; break; case SC_CURSE: sc->opt2 |= OPT2_CURSE; break; @@ -6234,6 +7311,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val opt_flag = 2; break; case SC_CLOAKING: + case SC_CLOAKINGEXCEED: sc->option |= OPTION_CLOAK; opt_flag = 2; break; @@ -6280,10 +7358,15 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val calc_flag&=~SCB_DYE; } - if( vd && (pcdb_checkid(vd->class_) || bl->type == BL_MER ) ) //Only for players sprites, client crashes if they receive this for a mob o.O [Skotlex] - clif_status_change(bl,StatusIconChangeTable[type],1,tick); + if( vd && (pcdb_checkid(vd->class_) || bl->type == BL_MER || bl->type == BL_MOB ) ) + clif_status_change(bl,StatusIconChangeTable[type],1,tick,(val_flag&1)?val1:1,(val_flag&2)?val2:0,(val_flag&4)?val3:0); else if( sd ) //Send packet to self otherwise (disguised player?) clif_status_load(bl,StatusIconChangeTable[type],1); + /** + * used as temporary storage for scs with interval ticks, so that the actual duration is sent to the client first. + **/ + if( tick_time ) + tick = tick_time; //Don't trust the previous sce assignment, in case the SC ended somewhere between there and here. if((sce=sc->data[type])) @@ -6337,6 +7420,16 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_MERC_SPUP: status_percent_heal(bl, 0, 100); // Recover Full SP break; + /** + * Ranger + **/ + case SC_WUGDASH: + { + struct unit_data *ud = unit_bl2ud(bl); + if( ud ) + ud->state.running = unit_wugdash(bl, sd); + } + break; case SC_COMBO: switch (sce->val1) { case TK_STORMKICK: @@ -6658,7 +7751,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const } if((sce->val1&0xFFFF) == CG_MOONLIT) - clif_status_change(bl,SI_MOONLIT,0,0); + clif_status_change(bl,SI_MOONLIT,0,0,0,0,0); status_change_end(bl, SC_LONGING, INVALID_TIMER); } @@ -6803,6 +7896,88 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const status_change_end(tbl, SC_STOP, INVALID_TIMER); } break; + /** + * 3rd Stuff + **/ + case SC_MILLENNIUMSHIELD: + clif_millenniumshield(sd,0); + break; + case SC_HALLUCINATIONWALK: + sc_start(bl,SC_HALLUCINATIONWALK_POSTDELAY,100,sce->val1,skill_get_time2(GC_HALLUCINATIONWALK,sce->val1)); + break; + case SC_WHITEIMPRISON: + if( tid == -1 ) + break; // Terminated by Damage + clif_damage(bl,bl,0,0,0,400*sce->val1,0,0,0); + status_zap(bl,400*sce->val1,0); + break; + case SC_WUGDASH: + { + struct unit_data *ud = unit_bl2ud(bl); + if (ud) { + ud->state.running = 0; + if (ud->walktimer != -1) + unit_stop_walking(bl,1); + } + } + break; + case SC_ADORAMUS: + status_change_end(bl, SC_BLIND, -1); + break; + /* + case SC__SHADOWFORM: + { + struct map_session_data *s_sd = map_id2sd(sce->val2); + if( !s_sd ) + break; + s_sd->shadowform_id = 0; + } + break; + case SC_SITDOWN_FORCE: + if( sd && pc_issit(sd) ) + { + pc_setstand(sd); + clif_standing(bl,true); + } + break; + case SC_NEUTRALBARRIER_MASTER: + case SC_STEALTHFIELD_MASTER: + if( sce->val2 ) + { + struct skill_unit_group* group = skill_id2group(sce->val2); + sce->val2 = 0; + skill_delunitgroup(group); + } + break; + case SC_BANDING: + { + struct skill_unit_group *group; + if(sce->val4) + { + group = skill_id2group(sce->val4); + sce->val4 = 0; + skill_delunitgroup(group); + } + } + break; + case SC_CURSEDCIRCLE_ATKER: + if( sce->val3 ) + map_foreachinrange(status_change_timer_sub, bl, skill_get_splash(SR_CURSEDCIRCLE, sce->val1),BL_CHAR, bl, sce, SC_CURSEDCIRCLE_TARGET, gettick()); + break; + case SC_RAISINGDRAGON: + if( sd && sce->val2 && !pc_isdead(sd) ) + { + int i; + i = min(sd->spiritball,5); + pc_delspiritball(sd, sd->spiritball, 0); + status_change_end(bl, SC_EXPLOSIONSPIRITS, -1); + while( i > 0 ) + { + pc_addspiritball(sd, skill_get_time(MO_CALLSPIRITS, pc_checkskill(sd,MO_CALLSPIRITS)), 5); + --i; + } + } + break;*/ } opt_flag = 1; @@ -6832,6 +8007,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const opt_flag|= 2|4; //Check for warp trigger + AoE trigger break; case SC_CLOAKING: + case SC_CLOAKINGEXCEED: sc->option &= ~OPTION_CLOAK; opt_flag|= 2; break; @@ -6962,7 +8138,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const //On Aegis, when turning off a status change, first goes the sc packet, then the option packet. if( vd && (pcdb_checkid(vd->class_) || bl->type == BL_MER ) ) - clif_status_change(bl,StatusIconChangeTable[type],0,0); + clif_status_change(bl,StatusIconChangeTable[type],0,0,0,0,0); else if (sd) clif_status_load(bl,StatusIconChangeTable[type],0); @@ -7354,6 +8530,461 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) return 0; } break; + case SC_ABUNDANCE: + if(--(sce->val4) > 0) + { + if( !sc->data[SC_BERSERK] ) + status_heal(bl,0,60,0); + sc_timer_next(10000+tick, status_change_timer, bl->id, data); + } + break; + + case SC_PYREXIA: + if( --(sce->val4) >= 0 ) + { + bool flag; + map_freeblock_lock(); + clif_damage(bl,bl,tick,status_get_amotion(bl),0,100,0,0,0); + status_fix_damage(NULL,bl,100,0); + flag = !sc->data[type]; + map_freeblock_unlock(); + if( !flag ) + { + if( sce->val4 == 10 ) + sc_start(bl,SC_BLIND,100,sce->val1,30000); // Blind status for the final 30 seconds + sc_timer_next(3000+tick,status_change_timer,bl->id,data); + } + return 0; + } + break; + + case SC_LEECHESEND: + if( --(sce->val4) >= 0 ) + { + bool flag; + int damage = status->max_hp/100; + if( sd && (sd->status.class_ == JOB_GUILLOTINE_CROSS || sd->status.class_ == JOB_GUILLOTINE_CROSS_T ) ) + damage += 3 * status->vit; + else + damage += 7 * status->vit; + + unit_skillcastcancel(bl,2); + + map_freeblock_lock(); + status_zap(bl,damage,0); + flag = !sc->data[type]; + map_freeblock_unlock(); + if( !flag ) { + sc_timer_next(1000 + tick, status_change_timer, bl->id, data ); + } + return 0; + } + break; + + case SC_MAGICMUSHROOM: + if( --(sce->val4) >= 0 ) + { + bool flag = 0; + int damage = status->max_hp * 3 / 100; + if( status->hp <= damage ) + damage = status->hp - 1; // Cannot Kill + + if( damage > 0 ) + { // 3% Damage each 4 seconds + map_freeblock_lock(); + status_zap(bl,damage,0); + flag = !sc->data[type]; // Killed? Should not + map_freeblock_unlock(); + } + + if( !flag ) + { // Random Skill Cast + if( sd ) + { + int mushroom_skillid = 0, i; + unit_stop_attack(bl); + unit_skillcastcancel(bl,1); + do + { + i = rand() % MAX_SKILL_MAGICMUSHROOM_DB; + mushroom_skillid = skill_magicmushroom_db[i].skillid; + } + while( mushroom_skillid == 0 ); + + switch( skill_get_casttype(mushroom_skillid) ) + { // Magic Mushroom skills are buffs or area damage + case CAST_GROUND: + skill_castend_pos2(bl,bl->x,bl->y,mushroom_skillid,1,tick,0); + break; + case CAST_NODAMAGE: + skill_castend_nodamage_id(bl,bl,mushroom_skillid,1,tick,0); + break; + case CAST_DAMAGE: + skill_castend_damage_id(bl,bl,mushroom_skillid,1,tick,0); + break; + } + } + + clif_emotion(bl,18); + sc_timer_next(4000+tick,status_change_timer,bl->id,data); + } + return 0; + } + break; + + case SC_TOXIN: + if( --(sce->val4) >= 0 ) + { //Damage is every 10 seconds including 3%sp drain. + bool flag; + map_freeblock_lock(); + clif_damage(bl,bl,tick,status_get_amotion(bl),1,1,0,0,0); + status_damage(NULL,bl,1,status->max_sp*3/100,0,16); + flag = !sc->data[type]; + map_freeblock_unlock(); + if( !flag ) { + sc_timer_next(10000 + tick, status_change_timer, bl->id, data ); + } + return 0; + } + break; + + case SC_OBLIVIONCURSE: + if( --(sce->val4) >= 0 ) + { + clif_emotion(bl,1); + sc_timer_next(3000 + tick, status_change_timer, bl->id, data ); + return 0; + } + break; + + case SC_WEAPONBLOCKING: + if( --(sce->val4) >= 0 ) + { + if( !status_charge(bl,0,3) ) + break; + sc_timer_next(3000+tick,status_change_timer,bl->id,data); + return 0; + } + break; + + case SC_CLOAKINGEXCEED: + if(!status_charge(bl,0,10-sce->val1)) + break; + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + return 0; + + case SC_RENOVATIO: + if( --(sce->val4) >= 0 ) + { + status_heal(bl, status->max_hp * 3 / 100, 0, 2); + sc_timer_next(5000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; + + case SC_BURNING: + if( --(sce->val4) >= 0 ) + { + struct block_list *src = map_id2bl(sce->val3); + int flag, damage = 3 * status_get_max_hp(bl) / 100; // Non Elemental Damage + if( status ) + damage += battle_attr_fix(NULL, bl, sce->val2, ELE_FIRE, status->def_ele, status->ele_lv); + + map_freeblock_lock(); + status_fix_damage(src,bl,damage,clif_damage(bl,bl,tick,0,0,damage,0,0,0)); + flag = !sc->data[type]; + map_freeblock_unlock(); + if( !flag ) {// Target still lives. [LimitLine] + sc_timer_next(2000 + tick, status_change_timer, bl->id, data); + } + return 0; + } + break; + + case SC_FEAR: + if( --(sce->val4) >= 0 ) + { + if( sce->val2 > 0 ) + sce->val2--; + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; + + case SC_SPHERE_1: + case SC_SPHERE_2: + case SC_SPHERE_3: + case SC_SPHERE_4: + case SC_SPHERE_5: + if( --(sce->val4) >= 0 ) + { + if( !status_charge(bl, 0, 1) ) + break; + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; + + case SC_READING_SB: + if( !status_charge(bl, 0, sce->val2) ) + break; + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + return 0; + + case SC_ELECTRICSHOCKER: + if( --(sce->val4) >= 0 ) + { + status_charge(bl, 0, status->max_sp / 100 * sce->val1 ); + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; + + case SC_CAMOUFLAGE: + if( !status_charge(bl,0,7 - sce->val1) ) + break; + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + return 0; + + case SC__REPRODUCE: + if(!status_charge(bl, 0, 1)) + break; + sc_timer_next(1000+tick, status_change_timer, bl->id, data); + return 0; + + case SC__SHADOWFORM: + if( --(sce->val4) >= 0 ) + { + if( !status_charge(bl, 0, sce->val1 - (sce->val1 - 1)) ) + break; + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; + + case SC__INVISIBILITY: + if( --(sce->val4) >= 0 ) + { + if( !status_charge(bl, 0, (status->sp * 6 - sce->val1) / 100) )// 6% - skilllv. + break; + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; + + case SC_STRIKING: + if( --(sce->val4) >= 0 ) + { + if( !status_charge(bl,0, sce->val1 ) ) + break; + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; + + case SC_BLOODSUCKER: + if( --(sce->val4) >= 0 ) + { + struct block_list *src = map_id2bl(sce->val2); + int damage; + bool flag; + if( !src || (src && (status_isdead(src) || src->m != bl->m || distance_bl(src, bl) >= 12)) ) + break; + map_freeblock_lock(); + damage = skill_attack(skill_get_type(GN_BLOOD_SUCKER), src, src, bl, GN_BLOOD_SUCKER, sce->val1, tick, 0); + flag = !sc->data[type]; + map_freeblock_unlock(); + status_heal(src, damage, 0, 0); + clif_skill_nodamage(src, bl, GN_BLOOD_SUCKER, 0, 1); + if (!flag) { + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + } + return 0; + } + break; + + case SC_VOICEOFSIREN: + if( --(sce->val4) >= 0 ) + { + clif_emotion(bl,3); + sc_timer_next(2000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; + + case SC_DEEPSLEEP: + if( --(sce->val4) >= 0 ) + { // Recovers 1% HP/SP every 2 seconds. + status_heal(bl, status->max_hp / 100, status->max_sp / 100, 2); + sc_timer_next(2000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; + + case SC_SIRCLEOFNATURE: + if( --(sce->val4) >= 0 ) + { + if( !status_charge(bl,0,sce->val2) ) + break; + status_heal(bl, sce->val3, 0, 1); + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; + + case SC_SONGOFMANA: + if( --(sce->val4) >= 0 ) + { + status_heal(bl,0,sce->val3,3); + sc_timer_next(3000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; + + + case SC_SATURDAYNIGHTFEVER: + // 1% HP/SP drain every 3 seconds [Jobbie] + if( --(sce->val3) >= 0 ) + { + int hp = status->hp / 100; + int sp = status->sp / 100; + if( !status_charge(bl, hp, sp) ) + break; + sc_timer_next(sce->val4+tick, status_change_timer, bl->id, data); + return 0; + } + break; + + case SC_CRYSTALIZE: + if( --(sce->val4) >= 0 ) + { // Drains 2% of HP and 1% of SP every seconds. + status_charge(bl, status->max_hp * 2 / 100, status->max_sp / 100); + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; + + case SC_FORCEOFVANGUARD: + if( !status_charge(bl,0,20) ) + break; + sc_timer_next(6000 + tick, status_change_timer, bl->id, data); + return 0; + + case SC_BANDING: + if( status_charge(bl, 0, 7 - sce->val1) ) + { + //if( sd ) pc_banding(sd, sce->val1); + sc_timer_next(5000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; + + case SC_REFLECTDAMAGE: + if( --(sce->val4) >= 0 ) { + if( !status_charge(bl,0,sce->val3) ) + break; + sc_timer_next(10000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; + + case SC_OVERHEAT_LIMITPOINT: + if( --(sce->val1) > 0 ) { // Cooling + sc_timer_next(30000 + tick, status_change_timer, bl->id, data); + } + break; + + case SC_OVERHEAT: + { + int flag, damage = status->max_hp / 100; // Suggestion 1% each second + if( damage >= status->hp ) damage = status->hp - 1; // Do not kill, just keep you with 1 hp minimum + map_freeblock_lock(); + status_fix_damage(NULL,bl,damage,clif_damage(bl,bl,tick,0,0,damage,0,0,0)); + flag = !sc->data[type]; + map_freeblock_unlock(); + if( !flag ) { + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + } + } + break; + + case SC_MAGNETICFIELD: + { + if( --(sce->val3) <= 0 ) + break; // Time out + if( sce->val2 == bl->id ) + { + if( !status_charge(bl,0,14 + (3 * sce->val1)) ) + break; // No more SP status should end, and in the next second will end for the other affected players + } + else + { + struct block_list *src = map_id2bl(sce->val2); + struct status_change *ssc; + if( !src || (ssc = status_get_sc(src)) == NULL || !ssc->data[SC_MAGNETICFIELD] ) + break; // Source no more under Magnetic Field + } + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + } + break; + + case SC_INSPIRATION: + if(--(sce->val4) >= 0) + { + int hp = status->max_hp * (7-sce->val1) / 100; + int sp = status->max_sp * (9-sce->val1) / 100; + + if( !status_charge(bl,hp,sp) ) break; + + sc_timer_next(1000+tick,status_change_timer,bl->id, data); + return 0; + } + break; + + case SC_RAISINGDRAGON: + // 1% every 5 seconds [Jobbie] + if( --(sce->val3)>0 && status_charge(bl, sce->val2, 0) ) + { + if( !sc->data[type] ) return 0; + sc_timer_next(5000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; + + case SC_CIRCLE_OF_FIRE: + case SC_FIRE_CLOAK: + case SC_WATER_DROP: + case SC_WATER_SCREEN: + case SC_WIND_CURTAIN: + case SC_WIND_STEP: + case SC_STONE_SHIELD: + case SC_SOLID_SKIN: + if( !status_charge(bl,0,sce->val2) ) + { + struct block_list *s_bl = battle_get_master(bl); + if( s_bl ) + status_change_end(s_bl,type+1,-1); + status_change_end(bl,type,-1); + break; + } + sc_timer_next(2000 + tick, status_change_timer, bl->id, data); + return 0; + + case SC_STOMACHACHE: + if( --(sce->val4) > 0 ) + { + status_charge(bl,0,sce->val2); // Reduce 8 every 10 seconds. + if( sd && !pc_issit(sd) ) // Force to sit every 10 seconds. + { + pc_stop_walking(sd,1|4); + pc_stop_attack(sd); + pc_setsit(sd); + clif_sitting(bl); + } + sc_timer_next(10000 + tick, status_change_timer, bl->id, data); + } + break; + } // default for all non-handled control paths is to end the status @@ -7384,11 +9015,15 @@ int status_change_timer_sub(struct block_list* bl, va_list ap) case SC_CONCENTRATE: status_change_end(bl, SC_HIDING, INVALID_TIMER); status_change_end(bl, SC_CLOAKING, INVALID_TIMER); + status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); + status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); break; case SC_RUWACH: /* ルアフ */ - if (tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING])) { + if (tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] || tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_CLOAKINGEXCEED])) { status_change_end(bl, SC_HIDING, INVALID_TIMER); status_change_end(bl, SC_CLOAKING, INVALID_TIMER); + status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); + status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); if(battle_check_target( src, bl, BCT_ENEMY ) > 0) skill_attack(BF_MAGIC,src,src,bl,AL_RUWACH,1,tick,0); } @@ -7716,6 +9351,25 @@ static int status_natural_heal_timer(int tid, unsigned int tick, int id, intptr_ * size_fix.txt - size adjustment table for weapons * refine_db.txt - refining data table *------------------------------------------*/ +#if RRMODE +static bool status_readdb_job_re(char* fields[], int columns, int current) { + int idx, class_; + unsigned int i; + + class_ = atoi(fields[0]); + + if(!pcdb_checkid(class_)) { + ShowWarning("status_readdb_job_re: Invalid job class %d specified.\n", class_); + return false; + } + idx = pc_class2idx(class_); + + for(i = 0; i < RE_JOB_DB_MAX; i++) { + re_job_db[idx][i] = atoi(fields[i+1]); + } + return true; +} +#endif static bool status_readdb_job1(char* fields[], int columns, int current) {// Job-specific values (weight, HP, SP, ASPD) int idx, class_; @@ -7801,7 +9455,9 @@ int status_readdb(void) memset(hp_coefficient2, 0, sizeof(hp_coefficient2)); memset(sp_coefficient, 0, sizeof(sp_coefficient)); memset(aspd_base, 0, sizeof(aspd_base)); - +#if RRMODE + memset(re_job_db, 0, sizeof(re_job_db)); +#endif // job_db2.txt memset(job_bonus,0,sizeof(job_bonus)); // Job-specific stats bonus @@ -7828,6 +9484,10 @@ int status_readdb(void) sv_readdb(db_path, "size_fix.txt", ',', MAX_WEAPON_TYPE, MAX_WEAPON_TYPE, ARRAYLENGTH(atkmods), &status_readdb_sizefix); sv_readdb(db_path, "refine_db.txt", ',', 3+MAX_REFINE+1, 3+MAX_REFINE+1, ARRAYLENGTH(percentrefinery), &status_readdb_refine); +#if RRMODE + sv_readdb(db_path, "re_job_db.txt", ',', 1+RE_JOB_DB_MAX, 1+RE_JOB_DB_MAX, -1, &status_readdb_job_re); +#endif + return 0; } diff --git a/src/map/status.h b/src/map/status.h index dcd532577..8572b1bbb 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -329,7 +329,248 @@ typedef enum sc_type { SC_FOOD_VIT_CASH, SC_FOOD_DEX_CASH, SC_FOOD_INT_CASH, - SC_FOOD_LUK_CASH, + SC_FOOD_LUK_CASH,//308 + /** + * 3rd + **/ + SC_FEAR,//309 + SC_BURNING,//310 + SC_FREEZING,//311 + /** + * Rune Knight + **/ + SC_ENCHANTBLADE,//312 + SC_DEATHBOUND,//313 + SC_MILLENNIUMSHIELD, + SC_CRUSHSTRIKE,//315 + SC_REFRESH, + SC_REUSE_REFRESH, + SC_GIANTGROWTH, + SC_STONEHARDSKIN, + SC_VITALITYACTIVATION,//320 + SC_STORMBLAST, + SC_FIGHTINGSPIRIT, + SC_ABUNDANCE, + /** + * Arch Bishop + **/ + SC_ADORAMUS, + SC_EPICLESIS,//325 + SC_ORATIO, + SC_LAUDAAGNUS, + SC_LAUDARAMUS, + SC_RENOVATIO, + SC_EXPIATIO,//330 + SC_DUPLELIGHT, + SC_SECRAMENT, + /** + * Warlock + **/ + SC_WHITEIMPRISON, + SC_MARSHOFABYSS, + SC_RECOGNIZEDSPELL,//335 + SC_STASIS, + SC_SPHERE_1, + SC_SPHERE_2, + SC_SPHERE_3, + SC_SPHERE_4,//340 + SC_SPHERE_5, + SC_READING_SB, + SC_FREEZINGSPELL, + /** + * Ranger + **/ + SC_FEARBREEZE, + SC_ELECTRICSHOCKER,//345 + SC_WUGDASH, + SC_BITE, + SC_CAMOUFLAGE, + /** + * Mechanic + **/ + SC_ACCELERATION, + SC_HOVERING,//350 + SC_SHAPESHIFT, + SC_INFRAREDSCAN, + SC_ANALYZE, + SC_MAGNETICFIELD, + SC_NEUTRALBARRIER,//355 + SC_NEUTRALBARRIER_MASTER, + SC_STEALTHFIELD, + SC_STEALTHFIELD_MASTER, + SC_OVERHEAT, + SC_OVERHEAT_LIMITPOINT,//360 + /** + * Guillotine Cross + **/ + SC_VENOMIMPRESS, + SC_POISONINGWEAPON, + SC_WEAPONBLOCKING, + SC_CLOAKINGEXCEED, + SC_HALLUCINATIONWALK,//365 + SC_HALLUCINATIONWALK_POSTDELAY, + SC_ROLLINGCUTTER, + SC_TOXIN, + SC_PARALYSE, + SC_VENOMBLEED,//370 + SC_MAGICMUSHROOM, + SC_DEATHHURT, + SC_PYREXIA, + SC_OBLIVIONCURSE, + SC_LEECHESEND,//375 + /** + * Royal Guard + **/ + SC_REFLECTDAMAGE, + SC_FORCEOFVANGUARD, + SC_SHIELDSPELL_DEF, + SC_SHIELDSPELL_MDEF, + SC_SHIELDSPELL_REF,//380 + SC_EXEEDBREAK, + SC_PRESTIGE, + SC_BANDING, + SC_BANDING_DEFENCE, + SC_EARTHDRIVE,//385 + SC_INSPIRATION, + /** + * Sorcerer + **/ + SC_SPELLFIST, + SC_CRYSTALIZE, + SC_STRIKING, + SC_WARMER,//390 + SC_VACUUM_EXTREME, + SC_PROPERTYWALK, + /** + * Minstrel / Wanderer + **/ + SC_SWINGDANCE, + SC_SYMPHONYOFLOVER, + SC_MOONLITSERENADE,//395 + SC_RUSHWINDMILL, + SC_ECHOSONG, + SC_HARMONIZE, + SC_VOICEOFSIREN, + SC_DEEPSLEEP,//400 + SC_SIRCLEOFNATURE, + SC_GLOOMYDAY, + SC_GLOOMYDAY_SK, + SC_SONGOFMANA, + SC_DANCEWITHWUG,//405 + SC_SATURDAYNIGHTFEVER, + SC_LERADSDEW, + SC_MELODYOFSINK, + SC_BEYONDOFWARCRY, + SC_UNLIMITEDHUMMINGVOICE,//410 + SC_SITDOWN_FORCE, + /** + * Sura + **/ + SC_CRESCENTELBOW, + SC_CURSEDCIRCLE_ATKER, + SC_CURSEDCIRCLE_TARGET, + SC_LIGHTNINGWALK,//415 + SC_RAISINGDRAGON, + SC_GT_ENERGYGAIN, + SC_GT_CHANGE, + SC_GT_REVITALIZE, + /** + * Genetic + **/ + SC_GN_CARTBOOST,//420 + SC_THORNSTRAP, + SC_BLOODSUCKER, + SC_SMOKEPOWDER, + SC_TEARGAS, + SC_MANDRAGORA,//425 + SC_STOMACHACHE, + SC_MYSTERIOUS_POWDER, + SC_MELON_BOMB, + SC_BANANA_BOMB, + SC_BANANA_BOMB_SITDOWN,//430 + SC_SAVAGE_STEAK, + SC_COCKTAIL_WARG_BLOOD, + SC_MINOR_BBQ, + SC_SIROMA_ICE_TEA, + SC_DROCERA_HERB_STEAMED,//435 + SC_PUTTI_TAILS_NOODLES, + SC_BOOST500, + SC_FULL_SWING_K, + SC_MANA_PLUS, + SC_MUSTLE_M,//440 + SC_LIFE_FORCE_F, + SC_EXTRACT_WHITE_POTION_Z, + SC_VITATA_500, + SC_EXTRACT_SALAMINE_JUICE, + /** + * Shadow Chaser + **/ + SC__REPRODUCE,//445 + SC__AUTOSHADOWSPELL, + SC__SHADOWFORM, + SC__BODYPAINT, + SC__INVISIBILITY, + SC__DEADLYINFECT,//450 + SC__ENERVATION, + SC__GROOMY, + SC__IGNORANCE, + SC__LAZINESS, + SC__UNLUCKY,//455 + SC__WEAKNESS, + SC__STRIPACCESSORY, + SC__MANHOLE, + SC_CHAOS, + SC__BLOODYLUST,//460 + /** + * Elemental Spirits + **/ + SC_CIRCLE_OF_FIRE, + SC_CIRCLE_OF_FIRE_OPTION, + SC_FIRE_CLOAK, + SC_FIRE_CLOAK_OPTION, + SC_WATER_SCREEN,//465 + SC_WATER_SCREEN_OPTION, + SC_WATER_DROP, + SC_WATER_DROP_OPTION, + SC_WATER_BARRIER, + SC_WIND_STEP,//470 + SC_WIND_STEP_OPTION, + SC_WIND_CURTAIN, + SC_WIND_CURTAIN_OPTION, + SC_ZEPHYR, + SC_SOLID_SKIN,//475 + SC_SOLID_SKIN_OPTION, + SC_STONE_SHIELD, + SC_STONE_SHIELD_OPTION, + SC_POWER_OF_GAIA, + SC_PYROTECHNIC,//480 + SC_PYROTECHNIC_OPTION, + SC_HEATER, + SC_HEATER_OPTION, + SC_TROPIC, + SC_TROPIC_OPTION,//485 + SC_AQUAPLAY, + SC_AQUAPLAY_OPTION, + SC_COOLER, + SC_COOLER_OPTION, + SC_CHILLY_AIR,//490 + SC_CHILLY_AIR_OPTION, + SC_GUST, + SC_GUST_OPTION, + SC_BLAST, + SC_BLAST_OPTION,//495 + SC_WILD_STORM, + SC_WILD_STORM_OPTION, + SC_PETROLOGY, + SC_PETROLOGY_OPTION, + SC_CURSED_SOIL,//500 + SC_CURSED_SOIL_OPTION, + SC_UPHEAVAL, + SC_UPHEAVAL_OPTION, + SC_TIDAL_WEAPON, + SC_TIDAL_WEAPON_OPTION,//505 + SC_ROCK_CRUSHER, + SC_ROCK_CRUSHER_ATK, SC_MAX, //Automatically updated max, used in for's to check we are within bounds. } sc_type; @@ -652,7 +893,7 @@ enum si_type { SI_CASH_PLUSONLYJOBEXP = 312, // SI_PARTYFLEE = 313, // SI_ANGEL_PROTECT = 314, -/* + SI_ENDURE_MDEF = 315, SI_ENCHANTBLADE = 316, SI_DEATHBOUND = 317, @@ -701,11 +942,11 @@ enum si_type { SI_CAMOUFLAGE = 360, SI_ACCELERATION = 361, SI_HOVERING = 362, - SI_SUMMON1 = 363, - SI_SUMMON2 = 364, - SI_SUMMON3 = 365, - SI_SUMMON4 = 366, - SI_SUMMON5 = 367, + SI_SPHERE_1 = 363, + SI_SPHERE_2 = 364, + SI_SPHERE_3 = 365, + SI_SPHERE_4 = 366, + SI_SPHERE_5 = 367, SI_MVPCARD_TAOGUNKA = 368, SI_MVPCARD_MISTRESS = 369, SI_MVPCARD_ORCHERO = 370, @@ -719,15 +960,15 @@ enum si_type { SI_NEUTRALBARRIER_MASTER = 378, SI_STEALTHFIELD = 379, SI_STEALTHFIELD_MASTER = 380, -*/ + SI_MANU_ATK = 381, SI_MANU_DEF = 382, SI_SPL_ATK = 383, SI_SPL_DEF = 384, -// SI_REPRODUCE = 385, + SI_REPRODUCE = 385, SI_MANU_MATK = 386, SI_SPL_MATK = 387, -/* + SI_STR_SCROLL = 388, SI_INT_SCROLL = 389, SI_LG_REFLECTDAMAGE = 390, @@ -812,7 +1053,7 @@ enum si_type { SI_BLOCKING_PLAY = 469, SI_MANDRAGORA = 470, SI_ACTIVATE = 471, - SI_AB_SECRAMENT = 472, + SI_SECRAMENT = 472, SI_ASSUMPTIO2 = 473, SI_TK_SEVENWIND = 474, SI_LIMIT_ODINS_RECALL = 475, @@ -912,7 +1153,7 @@ enum si_type { SI_WIND_INSIGNIA = 569, SI_EARTH_INSIGNIA = 570, SI_EQUIPED_FLOOR = 571, -*/ + SI_ALL_RIDING = 613,//awesome 571-613 gap, we're missing quite a few stuff here. }; // JOINTBEAT stackable ailments @@ -1033,6 +1274,7 @@ enum { OPTION_DRAGON3 = 0x01000000, OPTION_DRAGON4 = 0x02000000, OPTION_DRAGON5 = 0x04000000, + OPTION_MOUNTING = 0x08000000,//dull name (cuz ind named it :/) // compound constants OPTION_CART = OPTION_CART1|OPTION_CART2|OPTION_CART3|OPTION_CART4|OPTION_CART5, OPTION_DRAGON = OPTION_DRAGON1|OPTION_DRAGON2|OPTION_DRAGON3|OPTION_DRAGON4|OPTION_DRAGON5, @@ -1123,6 +1365,12 @@ struct status_data { aspd_rate; unsigned char def_ele, ele_lv, +#if RRMODE + /** + * in RE weapon level is used in several areas, keeping it here saves performance + **/ + wlv, +#endif size, race; signed char def, mdef; @@ -1187,7 +1435,8 @@ struct status_change { //TODO: See if it is possible to implement the following SC's without requiring extra parameters while the SC is inactive. unsigned char jb_flag; //Joint Beat type flag unsigned short mp_matk_min, mp_matk_max; //Previous matk min/max for ground spells (Amplify magic power) - int sg_id; //ID of the previous Storm gust that hit you + //int sg_id; //ID of the previous Storm gust that hit you + short comet_x, comet_y; // Point where src casted Comet - required to calculate damage from this point unsigned char sg_counter; //Storm gust counter (previous hits from storm gust) struct status_change_entry *data[SC_MAX]; }; @@ -1260,6 +1509,12 @@ unsigned char status_calc_attack_element(struct block_list *bl, struct status_ch #define status_get_race(bl) status_get_status_data(bl)->race #define status_get_size(bl) status_get_status_data(bl)->size #define status_get_mode(bl) status_get_status_data(bl)->mode +#if RRMODE + /** + * in RE weapon level is used in several areas, keeping it here saves performance + **/ + #define status_get_wlv(bl) status_get_status_data(bl)->wlv +#endif int status_get_party_id(struct block_list *bl); int status_get_guild_id(struct block_list *bl); int status_get_emblem_id(struct block_list *bl); diff --git a/src/map/unit.c b/src/map/unit.c index a11b5dc28..52b479b25 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -444,7 +444,7 @@ int unit_run(struct block_list *bl) if(to_x == bl->x && to_y == bl->y) { //If you can't run forward, you must be next to a wall, so bounce back. [Skotlex] - clif_status_change(bl, SI_BUMP, 1, 0); + clif_status_change(bl, SI_BUMP, 1, 0, 0, 0, 0); //Set running to 0 beforehand so status_change_end knows not to enable spurt [Kevin] unit_bl2ud(bl)->state.running = 0; @@ -452,7 +452,7 @@ int unit_run(struct block_list *bl) skill_blown(bl,bl,skill_get_blewcount(TK_RUN,lv),unit_getdir(bl),0); clif_fixpos(bl); //Why is a clif_slide (skill_blown) AND a fixpos needed? Ask Aegis. - clif_status_change(bl, SI_BUMP, 0, 0); + clif_status_change(bl, SI_BUMP, 0, 0, 0, 0, 0); return 0; } if (unit_walktoxy(bl, to_x, to_y, 1)) @@ -464,7 +464,7 @@ int unit_run(struct block_list *bl) } while (--i > 0 && !unit_walktoxy(bl, to_x, to_y, 1)); if (i==0) { // copy-paste from above - clif_status_change(bl, SI_BUMP, 1, 0); + clif_status_change(bl, SI_BUMP, 1, 0, 0, 0, 0); //Set running to 0 beforehand so status_change_end knows not to enable spurt [Kevin] unit_bl2ud(bl)->state.running = 0; @@ -472,7 +472,73 @@ int unit_run(struct block_list *bl) skill_blown(bl,bl,skill_get_blewcount(TK_RUN,lv),unit_getdir(bl),0); clif_fixpos(bl); - clif_status_change(bl, SI_BUMP, 0, 0); + clif_status_change(bl, SI_BUMP, 0, 0, 0, 0, 0); + return 0; + } + return 1; +} + +//Exclusive function to Wug Dash state. [Jobbie/3CeAM] +int unit_wugdash(struct block_list *bl, struct map_session_data *sd) { + struct status_change *sc = status_get_sc(bl); + short to_x,to_y,dir_x,dir_y; + int lv; + int i; + if (!(sc && sc->data[SC_WUGDASH])) + return 0; + + nullpo_ret(sd); + nullpo_ret(bl); + + if (!unit_can_move(bl)) { + status_change_end(bl,SC_WUGDASH,-1); + return 0; + } + + lv = sc->data[SC_WUGDASH]->val1; + dir_x = dirx[sc->data[SC_WUGDASH]->val2]; + dir_y = diry[sc->data[SC_WUGDASH]->val2]; + + to_x = bl->x; + to_y = bl->y; + for(i=0;im,to_x+dir_x,to_y+dir_y,CELL_CHKPASS)) + break; + + if(sc->data[SC_WUGDASH] && map_count_oncell(bl->m, to_x+dir_x, to_y+dir_y, BL_PC|BL_MOB|BL_NPC)) + break; + + to_x += dir_x; + to_y += dir_y; + } + + if(to_x == bl->x && to_y == bl->y) { + + unit_bl2ud(bl)->state.running = 0; + status_change_end(bl,SC_WUGDASH,-1); + + if( sd ){ + clif_fixpos(bl); + skill_castend_damage_id(bl, &sd->bl, RA_WUGDASH, lv, gettick(), SD_LEVEL); + } + return 0; + } + if (unit_walktoxy(bl, to_x, to_y, 1)) + return 1; + do { + to_x -= dir_x; + to_y -= dir_y; + } while (--i > 0 && !unit_walktoxy(bl, to_x, to_y, 1)); + if (i==0) { + + unit_bl2ud(bl)->state.running = 0; + status_change_end(bl,SC_WUGDASH,-1); + + if( sd ){ + clif_fixpos(bl); + skill_castend_damage_id(bl, &sd->bl, RA_WUGDASH, lv, gettick(), SD_LEVEL); + } return 0; } return 1; @@ -992,7 +1058,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh if( !target || src->m != target->m || !src->prev || !target->prev ) return 0; - if( mob_ksprotected(src, target) ) + if( battle_config.ksprotection && sd && mob_ksprotected(src, target) ) return 0; //Normally not needed because clif.c checks for it, but the at/char/script commands don't! [Skotlex] @@ -1130,7 +1196,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh // moved here to prevent Suffragium from ending if skill fails if (!(skill_get_castnodex(skill_num, skill_lv)&2)) - casttime = skill_castfix_sc(src, casttime); + casttime = skill_castfix_sc(src, casttime, skill_num, skill_lv); if( casttime > 0 || temp ) { @@ -1272,7 +1338,7 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, sh // moved here to prevent Suffragium from ending if skill fails if (!(skill_get_castnodex(skill_num, skill_lv)&2)) - casttime = skill_castfix_sc(src, casttime); + casttime = skill_castfix_sc(src, casttime, skill_num, skill_lv); ud->state.skillcastcancel = castcancel&&casttime>0?1:0; if( !sd || sd->skillitem != skill_num || skill_get_cast(skill_num,skill_lv) ) diff --git a/src/map/unit.h b/src/map/unit.h index e349a7466..f7b072739 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -126,6 +126,10 @@ int unit_changeviewsize(struct block_list *bl,short size); // 初期化ルーチン int do_init_unit(void); int do_final_unit(void); +/** + * Ranger + **/ +int unit_wugdash(struct block_list *bl, struct map_session_data *sd); extern const short dirx[8]; extern const short diry[8]; diff --git a/vcproj-10/map-server_sql.vcxproj b/vcproj-10/map-server_sql.vcxproj index 9f9664548..997854d0f 100644 --- a/vcproj-10/map-server_sql.vcxproj +++ b/vcproj-10/map-server_sql.vcxproj @@ -173,6 +173,13 @@ + + + + + + + diff --git a/vcproj-10/map-server_sql.vcxproj.filters b/vcproj-10/map-server_sql.vcxproj.filters index b290b3c95..5351488d6 100644 --- a/vcproj-10/map-server_sql.vcxproj.filters +++ b/vcproj-10/map-server_sql.vcxproj.filters @@ -115,6 +115,9 @@ common + + common + common diff --git a/vcproj-10/map-server_txt.vcxproj b/vcproj-10/map-server_txt.vcxproj index 171859e1e..a40e6f5e0 100644 --- a/vcproj-10/map-server_txt.vcxproj +++ b/vcproj-10/map-server_txt.vcxproj @@ -205,6 +205,13 @@ + + + + + + + diff --git a/vcproj-10/map-server_txt.vcxproj.filters b/vcproj-10/map-server_txt.vcxproj.filters index e157f4d40..bf2d728ae 100644 --- a/vcproj-10/map-server_txt.vcxproj.filters +++ b/vcproj-10/map-server_txt.vcxproj.filters @@ -189,6 +189,9 @@ common + + common + common diff --git a/vcproj-10/mapcache.vcxproj.filters b/vcproj-10/mapcache.vcxproj.filters index 708cab064..713cdb64b 100644 --- a/vcproj-10/mapcache.vcxproj.filters +++ b/vcproj-10/mapcache.vcxproj.filters @@ -4,6 +4,9 @@ common + + common + common @@ -30,6 +33,9 @@ common + + common + common diff --git a/vcproj-6/char-server_sql.dsp b/vcproj-6/char-server_sql.dsp deleted file mode 100644 index f64c8d67e..000000000 --- a/vcproj-6/char-server_sql.dsp +++ /dev/null @@ -1,324 +0,0 @@ -# Microsoft Developer Studio Project File - Name="char_sql" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=char_sql - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "char-server_sql.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "char-server_sql.mak" CFG="char_sql - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "char_sql - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "char_sql - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "char_sql - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir ".." -# PROP Intermediate_Dir "tmp\char_sql\Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mysql\include" /I "..\3rdparty\mt19937ar" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /FD /GF /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x405 /d "NDEBUG" -# ADD RSC /l 0x417 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib ws2_32.lib libmysql.lib /nologo /subsystem:console /debug /machine:I386 /libpath:"..\3rdparty\mysql\lib" - -!ELSEIF "$(CFG)" == "char_sql - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir ".." -# PROP Intermediate_Dir "tmp\char_sql\Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mysql\include" /I "..\3rdparty\mt19937ar" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x405 /d "_DEBUG" -# ADD RSC /l 0x417 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib ws2_32.lib libmysql.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\3rdparty\mysql\lib" - -!ENDIF - -# Begin Target - -# Name "char_sql - Win32 Release" -# Name "char_sql - Win32 Debug" -# Begin Group "3rdparty" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\3rdparty\mt19937ar\mt19937ar.c -# End Source File -# Begin Source File - -SOURCE=..\3rdparty\mt19937ar\mt19937ar.h -# End Source File -# End Group -# Begin Group "common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\common\cbasetypes.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\core.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\core.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\db.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\db.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\ers.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\ers.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\malloc.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\malloc.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\mapindex.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\mapindex.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\mmo.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\nullpo.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\nullpo.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\plugin.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\plugins.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\plugins.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\random.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\random.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\showmsg.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\showmsg.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\socket.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\socket.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\sql.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\sql.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\strlib.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\strlib.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\timer.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\timer.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\utils.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\utils.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\version.h -# End Source File -# End Group -# Begin Group "char_sql" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\char_sql\char.c -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\char.h -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_auction.c -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_auction.h -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_guild.c -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_guild.h -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_homun.c -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_homun.h -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_mail.c -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_mail.h -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_mercenary.c -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_mercenary.h -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_party.c -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_party.h -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_pet.c -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_pet.h -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_quest.c -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_quest.h -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_storage.c -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_storage.h -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\inter.c -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\inter.h -# End Source File -# End Group -# End Target -# End Project diff --git a/vcproj-6/char-server_txt.dsp b/vcproj-6/char-server_txt.dsp deleted file mode 100644 index e5d9db918..000000000 --- a/vcproj-6/char-server_txt.dsp +++ /dev/null @@ -1,300 +0,0 @@ -# Microsoft Developer Studio Project File - Name="char_txt" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=char_txt - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "char-server_txt.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "char-server_txt.mak" CFG="char_txt - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "char_txt - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "char_txt - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "char_txt - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir ".." -# PROP Intermediate_Dir "tmp\char_txt\Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mt19937ar" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "TXT_ONLY" /FD /GF /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x405 /d "NDEBUG" -# ADD RSC /l 0x417 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 - -!ELSEIF "$(CFG)" == "char_txt - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir ".." -# PROP Intermediate_Dir "tmp\char_txt\Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mt19937ar" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "TXT_ONLY" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x405 /d "_DEBUG" -# ADD RSC /l 0x417 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "char_txt - Win32 Release" -# Name "char_txt - Win32 Debug" -# Begin Group "3rdparty" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\3rdparty\mt19937ar\mt19937ar.c -# End Source File -# Begin Source File - -SOURCE=..\3rdparty\mt19937ar\mt19937ar.h -# End Source File -# End Group -# Begin Group "common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\common\cbasetypes.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\core.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\core.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\db.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\db.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\ers.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\ers.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\lock.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\lock.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\malloc.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\malloc.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\mapindex.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\mapindex.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\mmo.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\nullpo.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\nullpo.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\plugin.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\plugins.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\plugins.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\random.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\random.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\showmsg.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\showmsg.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\socket.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\socket.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\strlib.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\strlib.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\timer.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\timer.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\utils.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\utils.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\version.h -# End Source File -# End Group -# Begin Group "char_txt" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\char\char.c -# End Source File -# Begin Source File - -SOURCE=..\src\char\char.h -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_guild.c -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_guild.h -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_homun.c -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_homun.h -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_party.c -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_party.h -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_pet.c -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_pet.h -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_status.c -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_status.h -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_storage.c -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_storage.h -# End Source File -# Begin Source File - -SOURCE=..\src\char\inter.c -# End Source File -# Begin Source File - -SOURCE=..\src\char\inter.h -# End Source File -# End Group -# End Target -# End Project diff --git a/vcproj-6/login-server_sql.dsp b/vcproj-6/login-server_sql.dsp deleted file mode 100644 index 54c953466..000000000 --- a/vcproj-6/login-server_sql.dsp +++ /dev/null @@ -1,276 +0,0 @@ -# Microsoft Developer Studio Project File - Name="login_sql" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=login_sql - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "login-server_sql.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "login-server_sql.mak" CFG="login_sql - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "login_sql - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "login_sql - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "login_sql - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir ".." -# PROP Intermediate_Dir "tmp\login_sql\Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mysql\include" /I "..\3rdparty\mt19937ar" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "WITH_SQL" /FD /GF /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x405 /d "NDEBUG" -# ADD RSC /l 0x417 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib ws2_32.lib libmysql.lib /nologo /subsystem:console /debug /machine:I386 /libpath:"..\3rdparty\mysql\lib" - -!ELSEIF "$(CFG)" == "login_sql - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir ".." -# PROP Intermediate_Dir "tmp\login_sql\Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mysql\include" /I "..\3rdparty\mt19937ar" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "WITH_SQL" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x405 /d "_DEBUG" -# ADD RSC /l 0x417 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib ws2_32.lib libmysql.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\3rdparty\mysql\lib" - -!ENDIF - -# Begin Target - -# Name "login_sql - Win32 Release" -# Name "login_sql - Win32 Debug" -# Begin Group "3rdparty" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\3rdparty\mt19937ar\mt19937ar.c -# End Source File -# Begin Source File - -SOURCE=..\3rdparty\mt19937ar\mt19937ar.h -# End Source File -# End Group -# Begin Group "common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\common\cbasetypes.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\core.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\core.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\db.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\db.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\ers.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\ers.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\malloc.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\malloc.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\mapindex.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\mapindex.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\md5calc.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\md5calc.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\mmo.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\nullpo.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\nullpo.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\plugin.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\plugins.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\plugins.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\random.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\random.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\showmsg.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\showmsg.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\socket.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\socket.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\sql.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\sql.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\strlib.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\strlib.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\timer.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\timer.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\utils.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\utils.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\version.h -# End Source File -# End Group -# Begin Group "login_sql" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\login\account.h -# End Source File -# Begin Source File - -SOURCE=..\src\login\account_sql.c -# End Source File -# Begin Source File - -SOURCE=..\src\login\ipban.h -# End Source File -# Begin Source File - -SOURCE=..\src\login\ipban_sql.c -# End Source File -# Begin Source File - -SOURCE=..\src\login\login.c -# End Source File -# Begin Source File - -SOURCE=..\src\login\login.h -# End Source File -# Begin Source File - -SOURCE=..\src\login\loginlog.h -# End Source File -# Begin Source File - -SOURCE=..\src\login\loginlog_sql.c -# End Source File -# End Group -# End Target -# End Project diff --git a/vcproj-6/login-server_txt.dsp b/vcproj-6/login-server_txt.dsp deleted file mode 100644 index 642375fb7..000000000 --- a/vcproj-6/login-server_txt.dsp +++ /dev/null @@ -1,276 +0,0 @@ -# Microsoft Developer Studio Project File - Name="login_txt" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=login_txt - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "login-server_txt.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "login-server_txt.mak" CFG="login_txt - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "login_txt - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "login_txt - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "login_txt - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir ".." -# PROP Intermediate_Dir "tmp\login_txt\Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mt19937ar" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "WITH_TXT" /FD /GF /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x405 /d "NDEBUG" -# ADD RSC /l 0x417 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 - -!ELSEIF "$(CFG)" == "login_txt - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir ".." -# PROP Intermediate_Dir "tmp\login_txt\Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mt19937ar" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "WITH_TXT" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x405 /d "_DEBUG" -# ADD RSC /l 0x417 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "login_txt - Win32 Release" -# Name "login_txt - Win32 Debug" -# Begin Group "3rdparty" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\3rdparty\mt19937ar\mt19937ar.c -# End Source File -# Begin Source File - -SOURCE=..\3rdparty\mt19937ar\mt19937ar.h -# End Source File -# End Group -# Begin Group "common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\common\cbasetypes.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\core.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\core.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\db.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\db.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\ers.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\ers.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\lock.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\lock.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\malloc.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\malloc.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\mapindex.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\mapindex.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\md5calc.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\md5calc.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\mmo.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\nullpo.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\nullpo.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\plugin.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\plugins.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\plugins.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\random.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\random.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\showmsg.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\showmsg.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\socket.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\socket.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\strlib.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\strlib.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\timer.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\timer.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\utils.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\utils.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\version.h -# End Source File -# End Group -# Begin Group "login_txt" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\login\account.h -# End Source File -# Begin Source File - -SOURCE=..\src\login\account_txt.c -# End Source File -# Begin Source File - -SOURCE=..\src\login\ipban.h -# End Source File -# Begin Source File - -SOURCE=..\src\login\ipban_txt.c -# End Source File -# Begin Source File - -SOURCE=..\src\login\login.c -# End Source File -# Begin Source File - -SOURCE=..\src\login\login.h -# End Source File -# Begin Source File - -SOURCE=..\src\login\loginlog.h -# End Source File -# Begin Source File - -SOURCE=..\src\login\loginlog_txt.c -# End Source File -# End Group -# End Target -# End Project diff --git a/vcproj-6/map-server_sql.dsp b/vcproj-6/map-server_sql.dsp deleted file mode 100644 index 9246c6b17..000000000 --- a/vcproj-6/map-server_sql.dsp +++ /dev/null @@ -1,528 +0,0 @@ -# Microsoft Developer Studio Project File - Name="map_sql" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=map_sql - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "map-server_sql.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "map-server_sql.mak" CFG="map_sql - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "map_sql - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "map_sql - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "map_sql - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir ".." -# PROP Intermediate_Dir "tmp\map_sql\Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\mysql\include" /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\pcre\include" /I "..\3rdparty\zlib\include" /I "..\3rdparty\mt19937ar" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "PCRE_SUPPORT" /FD /GF /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x405 /d "NDEBUG" -# ADD RSC /l 0x417 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 libmysql.lib kernel32.lib ws2_32.lib pcre.lib zdll.lib /nologo /subsystem:console /debug /machine:I386 /libpath:"..\3rdparty\mysql\lib" /libpath:"..\3rdparty\pcre\lib" /libpath:"..\3rdparty\zlib\lib" - -!ELSEIF "$(CFG)" == "map_sql - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir ".." -# PROP Intermediate_Dir "tmp\map_sql\Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\mysql\include" /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\pcre\include" /I "..\3rdparty\zlib\include" /I "..\3rdparty\mt19937ar" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "PCRE_SUPPORT" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x405 /d "_DEBUG" -# ADD RSC /l 0x417 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 libmysql.lib kernel32.lib ws2_32.lib pcre.lib zdll.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\3rdparty\mysql\lib" /libpath:"..\3rdparty\pcre\lib" /libpath:"..\3rdparty\zlib\lib" - -!ENDIF - -# Begin Target - -# Name "map_sql - Win32 Release" -# Name "map_sql - Win32 Debug" -# Begin Group "3rdparty" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\3rdparty\mt19937ar\mt19937ar.c -# End Source File -# Begin Source File - -SOURCE=..\3rdparty\mt19937ar\mt19937ar.h -# End Source File -# End Group -# Begin Group "common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\common\cbasetypes.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\core.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\core.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\db.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\db.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\ers.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\ers.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\grfio.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\grfio.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\malloc.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\malloc.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\mapindex.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\mapindex.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\md5calc.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\md5calc.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\mmo.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\nullpo.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\nullpo.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\plugin.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\plugins.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\plugins.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\random.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\random.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\showmsg.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\showmsg.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\socket.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\socket.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\sql.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\sql.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\strlib.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\strlib.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\timer.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\timer.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\utils.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\utils.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\version.h -# End Source File -# End Group -# Begin Group "map_sql" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\map\atcommand.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\atcommand.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\battle.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\battle.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\battleground.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\battleground.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\buyingstore.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\buyingstore.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\chat.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\chat.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\chrif.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\chrif.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\clif.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\clif.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\date.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\date.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\duel.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\duel.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\guild.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\guild.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\homunculus.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\homunculus.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\instance.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\instance.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\intif.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\intif.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\itemdb.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\itemdb.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\log.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\log.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\mail.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\mail.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\map.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\map.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\mapreg.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\mapreg_sql.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\mercenary.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\mercenary.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\mob.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\mob.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\npc.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\npc.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\npc_chat.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\party.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\party.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\path.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\path.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\pc.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\pc.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\pet.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\pet.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\quest.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\quest.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\script.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\script.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\searchstore.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\searchstore.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\skill.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\skill.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\status.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\status.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\storage.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\storage.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\trade.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\trade.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\unit.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\unit.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\vending.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\vending.h -# End Source File -# End Group -# End Target -# End Project diff --git a/vcproj-6/map-server_txt.dsp b/vcproj-6/map-server_txt.dsp deleted file mode 100644 index 00e4cf716..000000000 --- a/vcproj-6/map-server_txt.dsp +++ /dev/null @@ -1,528 +0,0 @@ -# Microsoft Developer Studio Project File - Name="map_txt" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=map_txt - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "map-server_txt.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "map-server_txt.mak" CFG="map_txt - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "map_txt - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "map_txt - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "map_txt - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir ".." -# PROP Intermediate_Dir "tmp\map_txt\Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\pcre\include" /I "..\3rdparty\zlib\include" /I "..\3rdparty\mt19937ar" /D "NDEBUG" /D "TXT_ONLY" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "PCRE_SUPPORT" /FD /GF /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x405 /d "NDEBUG" -# ADD RSC /l 0x417 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib ws2_32.lib pcre.lib zdll.lib /nologo /subsystem:console /debug /machine:I386 /libpath:"..\3rdparty\pcre\lib" /libpath:"..\3rdparty\zlib\lib" - -!ELSEIF "$(CFG)" == "map_txt - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir ".." -# PROP Intermediate_Dir "tmp\map_txt\Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\pcre\include" /I "..\3rdparty\zlib\include" /I "..\3rdparty\mt19937ar" /D "_DEBUG" /D "TXT_ONLY" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "PCRE_SUPPORT" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x405 /d "_DEBUG" -# ADD RSC /l 0x417 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib ws2_32.lib pcre.lib zdll.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\3rdparty\pcre\lib" /libpath:"..\3rdparty\zlib\lib" - -!ENDIF - -# Begin Target - -# Name "map_txt - Win32 Release" -# Name "map_txt - Win32 Debug" -# Begin Group "3rdparty" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\3rdparty\mt19937ar\mt19937ar.c -# End Source File -# Begin Source File - -SOURCE=..\3rdparty\mt19937ar\mt19937ar.h -# End Source File -# End Group -# Begin Group "common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\common\cbasetypes.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\core.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\core.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\db.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\db.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\ers.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\ers.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\grfio.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\grfio.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\lock.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\lock.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\malloc.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\malloc.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\mapindex.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\mapindex.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\md5calc.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\md5calc.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\mmo.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\nullpo.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\nullpo.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\plugin.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\plugins.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\plugins.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\random.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\random.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\showmsg.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\showmsg.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\socket.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\socket.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\strlib.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\strlib.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\timer.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\timer.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\utils.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\utils.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\version.h -# End Source File -# End Group -# Begin Group "map_txt" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\map\atcommand.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\atcommand.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\battle.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\battle.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\battleground.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\battleground.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\buyingstore.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\buyingstore.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\chat.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\chat.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\chrif.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\chrif.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\clif.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\clif.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\date.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\date.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\duel.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\duel.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\guild.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\guild.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\homunculus.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\homunculus.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\instance.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\instance.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\intif.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\intif.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\itemdb.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\itemdb.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\log.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\log.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\mail.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\mail.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\map.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\map.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\mapreg.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\mapreg_txt.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\mercenary.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\mercenary.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\mob.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\mob.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\npc.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\npc.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\npc_chat.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\party.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\party.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\path.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\path.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\pc.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\pc.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\pet.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\pet.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\quest.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\quest.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\script.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\script.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\searchstore.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\searchstore.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\skill.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\skill.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\status.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\status.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\storage.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\storage.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\trade.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\trade.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\unit.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\unit.h -# End Source File -# Begin Source File - -SOURCE=..\src\map\vending.c -# End Source File -# Begin Source File - -SOURCE=..\src\map\vending.h -# End Source File -# End Group -# End Target -# End Project diff --git a/vcproj-6/mapcache.dsp b/vcproj-6/mapcache.dsp deleted file mode 100644 index 015835d2d..000000000 --- a/vcproj-6/mapcache.dsp +++ /dev/null @@ -1,160 +0,0 @@ -# Microsoft Developer Studio Project File - Name="mapcache" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=mapcache - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "mapcache.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mapcache.mak" CFG="mapcache - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mapcache - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "mapcache - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "mapcache - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir ".." -# PROP Intermediate_Dir "tmp\mapcache\Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\zlib\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D "MINICORE" /FD /GF /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x405 /d "NDEBUG" -# ADD RSC /l 0x417 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib zdll.lib /nologo /subsystem:console /debug /machine:I386 /libpath:"..\3rdparty\zlib\lib" - -!ELSEIF "$(CFG)" == "mapcache - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir ".." -# PROP Intermediate_Dir "tmp\mapcache\Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\zlib\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D "MINICORE" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x405 /d "_DEBUG" -# ADD RSC /l 0x417 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib zdll.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\3rdparty\zlib\lib" - -!ENDIF - -# Begin Target - -# Name "mapcache - Win32 Release" -# Name "mapcache - Win32 Debug" -# Begin Group "common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\common\cbasetypes.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\core.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\core.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\grfio.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\grfio.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\malloc.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\malloc.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\mmo.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\showmsg.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\showmsg.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\strlib.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\strlib.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\utils.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\utils.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\version.h -# End Source File -# End Group -# Begin Group "mapcache" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\tool\mapcache.c -# End Source File -# End Group -# End Target -# End Project diff --git a/vcproj-6/plugin-console.dsp b/vcproj-6/plugin-console.dsp deleted file mode 100644 index 3794e60ed..000000000 --- a/vcproj-6/plugin-console.dsp +++ /dev/null @@ -1,107 +0,0 @@ -# Microsoft Developer Studio Project File - Name="plugin_console" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=plugin_console - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "plugin-console.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "plugin-console.mak" CFG="plugin_console - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "plugin_console - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "plugin_console - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "plugin_console - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "..\plugins" -# PROP Intermediate_Dir "tmp\plugin_console\Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CONSOLE_EXPORTS" /YX /FD /c -# ADD CPP /nologo /MT /W3 /O2 /I "..\3rdparty\msinttypes\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_WIN32" /D "__WIN32" /FD /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /Oicf /win32 -# SUBTRACT MTL /mktyplib203 -# ADD BASE RSC /l 0x405 /d "NDEBUG" -# ADD RSC /l 0x417 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib /nologo /dll /machine:I386 /out:"..\plugins\console.dll" - -!ELSEIF "$(CFG)" == "plugin_console - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "..\plugins" -# PROP Intermediate_Dir "tmp\plugin_console\Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CONSOLE_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /I "..\3rdparty\msinttypes\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_WIN32" /D "__WIN32" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /Oicf /win32 -# SUBTRACT MTL /mktyplib203 -# ADD BASE RSC /l 0x405 /d "_DEBUG" -# ADD RSC /l 0x417 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib /nologo /dll /debug /machine:I386 /out:"..\plugins\console.dll" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "plugin_console - Win32 Release" -# Name "plugin_console - Win32 Debug" -# Begin Group "console" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\plugins\console.c -# End Source File -# Begin Source File - -SOURCE=..\src\plugins\console.def -# End Source File -# End Group -# End Target -# End Project diff --git a/vcproj-6/plugin-pid.dsp b/vcproj-6/plugin-pid.dsp deleted file mode 100644 index b9dc130e9..000000000 --- a/vcproj-6/plugin-pid.dsp +++ /dev/null @@ -1,107 +0,0 @@ -# Microsoft Developer Studio Project File - Name="plugin_pid" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=plugin_pid - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "plugin-pid.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "plugin-pid.mak" CFG="plugin_pid - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "plugin_pid - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "plugin_pid - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "plugin_pid - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "..\plugins" -# PROP Intermediate_Dir "tmp\plugin_pid\Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PID_EXPORTS" /YX /FD /c -# ADD CPP /nologo /MT /W3 /O2 /I "..\3rdparty\msinttypes\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_WIN32" /D "__WIN32" /FD /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /Oicf /win32 -# SUBTRACT MTL /mktyplib203 -# ADD BASE RSC /l 0x405 /d "NDEBUG" -# ADD RSC /l 0x417 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib /nologo /dll /machine:I386 /out:"..\plugins\pid.dll" - -!ELSEIF "$(CFG)" == "plugin_pid - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "..\plugins" -# PROP Intermediate_Dir "tmp\plugin_pid\Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PID_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /I "..\3rdparty\msinttypes\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_WIN32" /D "__WIN32" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /Oicf /win32 -# SUBTRACT MTL /mktyplib203 -# ADD BASE RSC /l 0x405 /d "_DEBUG" -# ADD RSC /l 0x417 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib /nologo /dll /debug /machine:I386 /out:"..\plugins\pid.dll" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "plugin_pid - Win32 Release" -# Name "plugin_pid - Win32 Debug" -# Begin Group "pid" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\plugins\pid.c -# End Source File -# Begin Source File - -SOURCE=..\src\plugins\pid.def -# End Source File -# End Group -# End Target -# End Project diff --git a/vcproj-6/txt-converter-char.dsp b/vcproj-6/txt-converter-char.dsp deleted file mode 100644 index 0a6684e32..000000000 --- a/vcproj-6/txt-converter-char.dsp +++ /dev/null @@ -1,576 +0,0 @@ -# Microsoft Developer Studio Project File - Name="txt_converter_char" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=txt_converter_char - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "txt-converter-char.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "txt-converter-char.mak" CFG="txt_converter_char - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "txt_converter_char - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "txt_converter_char - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir ".." -# PROP Intermediate_Dir "tmp\txt_converter_char\Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /O2 /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mysql\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D "DB_MANUAL_CAST_TO_UNION" /D "MINICORE" /D "TXT_SQL_CONVERT" /FD /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x405 /d "NDEBUG" -# ADD RSC /l 0x417 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib libmysql.lib /nologo /subsystem:console /machine:I386 /libpath:"..\3rdparty\mysql\lib" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir ".." -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /ZI /Od /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mysql\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D "DB_MANUAL_CAST_TO_UNION" /D "MINICORE" /D "TXT_SQL_CONVERT" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x405 /d "_DEBUG" -# ADD RSC /l 0x417 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib libmysql.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\3rdparty\mysql\lib" - -!ENDIF - -# Begin Target - -# Name "txt_converter_char - Win32 Release" -# Name "txt_converter_char - Win32 Debug" -# Begin Group "common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\common\cbasetypes.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\core.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\core.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\db.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\db.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\ers.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\ers.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\lock.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\lock.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\malloc.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\malloc.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\mapindex.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\mapindex.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\mmo.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\showmsg.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\showmsg.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\sql.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\sql.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\strlib.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\strlib.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\timer.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\timer.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\utils.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\utils.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\version.h -# End Source File -# End Group -# Begin Group "char_sql" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\char_sql\char.c - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_sql" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_sql" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\char.h - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_sql" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_sql" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_guild.c - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_sql" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_sql" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_guild.h - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_sql" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_sql" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_mercenary.c -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_mercenary.h -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_party.c - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_sql" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_sql" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_party.h - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_sql" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_sql" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_pet.c - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_sql" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_sql" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_pet.h - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_sql" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_sql" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_storage.c - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_sql" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_sql" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\int_storage.h - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_sql" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_sql" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\inter.c - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_sql" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_sql" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char_sql\inter.h - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_sql" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_sql" - -!ENDIF - -# End Source File -# End Group -# Begin Group "char_txt" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\char\char.c - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_txt" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_txt" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char\char.h - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_txt" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_txt" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_guild.c - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_txt" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_txt" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_guild.h - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_txt" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_txt" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_party.c - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_txt" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_txt" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_party.h - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_txt" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_txt" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_pet.c - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_txt" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_txt" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_pet.h - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_txt" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_txt" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_storage.c - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_txt" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_txt" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char\int_storage.h - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_txt" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_txt" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char\inter.c - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_txt" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_txt" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\src\char\inter.h - -!IF "$(CFG)" == "txt_converter_char - Win32 Release" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Release\char_txt" - -!ELSEIF "$(CFG)" == "txt_converter_char - Win32 Debug" - -# PROP Intermediate_Dir "tmp\txt_converter_char\Debug\char_txt" - -!ENDIF - -# End Source File -# End Group -# Begin Group "converter" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE="..\src\txt-converter\char-converter.c" -# End Source File -# End Group -# End Target -# End Project diff --git a/vcproj-6/txt-converter-login.dsp b/vcproj-6/txt-converter-login.dsp deleted file mode 100644 index a5afb569a..000000000 --- a/vcproj-6/txt-converter-login.dsp +++ /dev/null @@ -1,200 +0,0 @@ -# Microsoft Developer Studio Project File - Name="txt_converter_login" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=txt_converter_login - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "txt-converter-login.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "txt-converter-login.mak" CFG="txt_converter_login - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "txt_converter_login - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "txt_converter_login - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "txt_converter_login - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir ".." -# PROP Intermediate_Dir "tmp\txt_converter_login\Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /O2 /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mysql\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D "DB_MANUAL_CAST_TO_UNION" /D "MINICORE" /D "TXT_SQL_CONVERT" /D "WITH_SQL" /D "WITH_TXT" /FD /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x405 /d "NDEBUG" -# ADD RSC /l 0x417 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib libmysql.lib /nologo /subsystem:console /machine:I386 /libpath:"..\3rdparty\mysql\lib" - -!ELSEIF "$(CFG)" == "txt_converter_login - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir ".." -# PROP Intermediate_Dir "tmp\txt_converter_login\Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /ZI /Od /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mysql\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D "DB_MANUAL_CAST_TO_UNION" /D "MINICORE" /D "TXT_SQL_CONVERT" /D "WITH_SQL" /D "WITH_TXT" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x405 /d "_DEBUG" -# ADD RSC /l 0x417 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib libmysql.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\3rdparty\mysql\lib" - -!ENDIF - -# Begin Target - -# Name "txt_converter_login - Win32 Release" -# Name "txt_converter_login - Win32 Debug" -# Begin Group "common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\common\cbasetypes.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\core.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\core.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\db.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\db.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\ers.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\ers.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\lock.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\lock.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\malloc.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\malloc.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\mmo.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\showmsg.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\showmsg.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\sql.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\sql.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\strlib.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\timer.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\timer.h -# End Source File -# Begin Source File - -SOURCE=..\src\common\utils.c -# End Source File -# Begin Source File - -SOURCE=..\src\common\version.h -# End Source File -# End Group -# Begin Group "login" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\src\login\account.h -# End Source File -# Begin Source File - -SOURCE=..\src\login\account_sql.c -# End Source File -# Begin Source File - -SOURCE=..\src\login\account_txt.c -# End Source File -# End Group -# Begin Group "converter" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE="..\src\txt-converter\login-converter.c" -# End Source File -# End Group -# End Target -# End Project diff --git a/vcproj-7.1/char-server_sql.vcproj b/vcproj-7.1/char-server_sql.vcproj deleted file mode 100644 index 02ad69ff8..000000000 --- a/vcproj-7.1/char-server_sql.vcproj +++ /dev/null @@ -1,332 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-7.1/char-server_txt.vcproj b/vcproj-7.1/char-server_txt.vcproj deleted file mode 100644 index cf4606143..000000000 --- a/vcproj-7.1/char-server_txt.vcproj +++ /dev/null @@ -1,307 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-7.1/login-server_sql.vcproj b/vcproj-7.1/login-server_sql.vcproj deleted file mode 100644 index 6ffd56f8f..000000000 --- a/vcproj-7.1/login-server_sql.vcproj +++ /dev/null @@ -1,291 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-7.1/login-server_txt.vcproj b/vcproj-7.1/login-server_txt.vcproj deleted file mode 100644 index 624bb39d7..000000000 --- a/vcproj-7.1/login-server_txt.vcproj +++ /dev/null @@ -1,288 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-7.1/map-server_sql.vcproj b/vcproj-7.1/map-server_sql.vcproj deleted file mode 100644 index fa1b7f931..000000000 --- a/vcproj-7.1/map-server_sql.vcproj +++ /dev/null @@ -1,490 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-7.1/map-server_txt.vcproj b/vcproj-7.1/map-server_txt.vcproj deleted file mode 100644 index b78fe1759..000000000 --- a/vcproj-7.1/map-server_txt.vcproj +++ /dev/null @@ -1,484 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-7.1/mapcache.vcproj b/vcproj-7.1/mapcache.vcproj deleted file mode 100644 index af62d5194..000000000 --- a/vcproj-7.1/mapcache.vcproj +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-8/char-server_sql.vcproj b/vcproj-8/char-server_sql.vcproj deleted file mode 100644 index ecee855a8..000000000 --- a/vcproj-8/char-server_sql.vcproj +++ /dev/null @@ -1,445 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-8/char-server_txt.vcproj b/vcproj-8/char-server_txt.vcproj deleted file mode 100644 index da689efe5..000000000 --- a/vcproj-8/char-server_txt.vcproj +++ /dev/null @@ -1,411 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-8/dbghelpplug.vcproj b/vcproj-8/dbghelpplug.vcproj deleted file mode 100644 index 59d53f5c5..000000000 --- a/vcproj-8/dbghelpplug.vcproj +++ /dev/null @@ -1,211 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-8/login-server_sql.vcproj b/vcproj-8/login-server_sql.vcproj deleted file mode 100644 index bf2526125..000000000 --- a/vcproj-8/login-server_sql.vcproj +++ /dev/null @@ -1,391 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-8/login-server_txt.vcproj b/vcproj-8/login-server_txt.vcproj deleted file mode 100644 index ba298908e..000000000 --- a/vcproj-8/login-server_txt.vcproj +++ /dev/null @@ -1,374 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-8/map-server_sql.vcproj b/vcproj-8/map-server_sql.vcproj deleted file mode 100644 index 1f68af297..000000000 --- a/vcproj-8/map-server_sql.vcproj +++ /dev/null @@ -1,654 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-8/map-server_txt.vcproj b/vcproj-8/map-server_txt.vcproj deleted file mode 100644 index ab7f5ab24..000000000 --- a/vcproj-8/map-server_txt.vcproj +++ /dev/null @@ -1,645 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-8/mapcache.vcproj b/vcproj-8/mapcache.vcproj deleted file mode 100644 index 3c6585c13..000000000 --- a/vcproj-8/mapcache.vcproj +++ /dev/null @@ -1,269 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-8/plugin-console.vcproj b/vcproj-8/plugin-console.vcproj deleted file mode 100644 index ac3c6de6d..000000000 --- a/vcproj-8/plugin-console.vcproj +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-8/plugin-pid.vcproj b/vcproj-8/plugin-pid.vcproj deleted file mode 100644 index 8b24e03af..000000000 --- a/vcproj-8/plugin-pid.vcproj +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-8/txt-converter-char.vcproj b/vcproj-8/txt-converter-char.vcproj deleted file mode 100644 index 7a21cd9cf..000000000 --- a/vcproj-8/txt-converter-char.vcproj +++ /dev/null @@ -1,505 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-8/txt-converter-login.vcproj b/vcproj-8/txt-converter-login.vcproj deleted file mode 100644 index 4e43fd147..000000000 --- a/vcproj-8/txt-converter-login.vcproj +++ /dev/null @@ -1,301 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-9/char-server_sql.vcproj b/vcproj-9/char-server_sql.vcproj index 64fdf9bac..759fd4f83 100644 --- a/vcproj-9/char-server_sql.vcproj +++ b/vcproj-9/char-server_sql.vcproj @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + diff --git a/vcproj-9/map-server_txt.vcproj b/vcproj-9/map-server_txt.vcproj index 2b983df98..d4cc1b13b 100644 --- a/vcproj-9/map-server_txt.vcproj +++ b/vcproj-9/map-server_txt.vcproj @@ -414,6 +414,34 @@ RelativePath="..\src\map\quest.h" > + + + + + + + + + + + + + + diff --git a/vcproj-9/mapcache.vcproj b/vcproj-9/mapcache.vcproj index 54c2756ff..2fb78f198 100644 --- a/vcproj-9/mapcache.vcproj +++ b/vcproj-9/mapcache.vcproj @@ -1,7 +1,7 @@ Date: Sun, 15 Apr 2012 12:04:44 +0000 Subject: Fixed quite a few dozen "comparison is always true due to limited range of data type" warning with gcc on --enable-64bit mode. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@15861 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/unit.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/map/unit.h') diff --git a/src/map/unit.h b/src/map/unit.h index f7b072739..6a0bf26f6 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -46,8 +46,13 @@ struct unit_data { }; struct view_data { +#ifdef __64BIT__ + unsigned int class_; +#endif unsigned short +#ifndef __64BIT__ class_, +#endif weapon, shield, //Or left-hand weapon. robe, -- cgit v1.2.3-70-g09d2 From efc39a408c225e1f030b1d21938ad7004b65af96 Mon Sep 17 00:00:00 2001 From: epoque11 Date: Sun, 29 Apr 2012 22:52:10 +0000 Subject: - Updated the unit engine to cache attacker count rather than utilise CPU intensive block iterations - This update removes two unofficial settings, nothing that will go amiss git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@16011 54d463be-8e91-2dee-dedb-b68131a5f0ec --- conf/battle/battle.conf | 18 ----------- src/map/battle.c | 22 +++++--------- src/map/battle.h | 5 +--- src/map/mob.c | 8 ++--- src/map/unit.c | 79 ++++++++++++++++++++++++++++--------------------- src/map/unit.h | 5 +++- 6 files changed, 61 insertions(+), 76 deletions(-) (limited to 'src/map/unit.h') diff --git a/conf/battle/battle.conf b/conf/battle/battle.conf index 377ebabb2..2cbb5bb45 100644 --- a/conf/battle/battle.conf +++ b/conf/battle/battle.conf @@ -101,24 +101,6 @@ weapon_defense_type: 0 //MDEF窶嘖ame as above....(MDEF*value) magic_defense_type: 0 -// How to count the number of attackers when applying agi penalty ? (choose one) -// 1-: Count every attack attempt (even those that were dodged/lucky-dodged) -// 2 : Count every non-lucky-dodged attack attempt -// 3 : Count attacks that miss due to element/race modifier -// 4 : Count attacks whose damages are blocked by skills -// 5 : Count only attacks that actually connect -// 6+: None of the above, count will always be 0 -agi_penalty_count_lv: 2 - -// How to count the number of attackers when applying vit penalty ? (choose one) -// 1-: Count every attack attempt (even those that were dodged/lucky-dodged) -// 2 : Count every non-lucky-dodged attack attempt -// 3 : Count attacks that miss due to element/race modifier -// 4 : Count attacks whose damages are blocked by skills -// 5 : Count only attacks that actually connect -// 6+: None of the above, count will always be 0 -vit_penalty_count_lv: 3 - // Change attacker's direction to face opponent on every attack? (Note 3) attack_direction_change: 15 diff --git a/src/map/battle.c b/src/map/battle.c index 167a040ce..9ea7f5595 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -1461,13 +1461,10 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo hitrate = 80; //Default hitrate #endif - if(battle_config.agi_penalty_type && - battle_config.agi_penalty_target&target->type) - { + if(battle_config.agi_penalty_type && battle_config.agi_penalty_target&target->type) { unsigned char attacker_count; //256 max targets should be a sane max - attacker_count = unit_counttargeted(target,battle_config.agi_penalty_count_lv); - if(attacker_count >= battle_config.agi_penalty_count) - { + attacker_count = unit_counttargeted(target); + if(attacker_count >= battle_config.agi_penalty_count) { if (battle_config.agi_penalty_type == 1) flee = (flee * (100 - (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num))/100; else //asume type 2: absolute reduction @@ -2507,10 +2504,9 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo } } - if( battle_config.vit_penalty_type && battle_config.vit_penalty_target&target->type ) - { + if( battle_config.vit_penalty_type && battle_config.vit_penalty_target&target->type ) { unsigned char target_count; //256 max targets should be a sane max - target_count = unit_counttargeted(target,battle_config.vit_penalty_count_lv); + target_count = unit_counttargeted(target); if(target_count >= battle_config.vit_penalty_count) { if(battle_config.vit_penalty_type == 1) { if( !tsc || !tsc->data[SC_STEELBODY] ) @@ -3920,11 +3916,9 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * hitrate = 80; //Default hitrate #endif - if(battle_config.agi_penalty_type && - battle_config.agi_penalty_target&target->type) - { + if(battle_config.agi_penalty_type && battle_config.agi_penalty_target&target->type) { unsigned char attacker_count; //256 max targets should be a sane max - attacker_count = unit_counttargeted(target,battle_config.agi_penalty_count_lv); + attacker_count = unit_counttargeted(target); if(attacker_count >= battle_config.agi_penalty_count) { if (battle_config.agi_penalty_type == 1) @@ -5040,12 +5034,10 @@ static const struct _battle_data { { "agi_penalty_type", &battle_config.agi_penalty_type, 1, 0, 2, }, { "agi_penalty_count", &battle_config.agi_penalty_count, 3, 2, INT_MAX, }, { "agi_penalty_num", &battle_config.agi_penalty_num, 10, 0, INT_MAX, }, - { "agi_penalty_count_lv", &battle_config.agi_penalty_count_lv, ATK_FLEE, 0, INT_MAX, }, { "vit_penalty_target", &battle_config.vit_penalty_target, BL_PC, BL_NUL, BL_ALL, }, { "vit_penalty_type", &battle_config.vit_penalty_type, 1, 0, 2, }, { "vit_penalty_count", &battle_config.vit_penalty_count, 3, 2, INT_MAX, }, { "vit_penalty_num", &battle_config.vit_penalty_num, 5, 0, INT_MAX, }, - { "vit_penalty_count_lv", &battle_config.vit_penalty_count_lv, ATK_MISS, 0, INT_MAX, }, { "weapon_defense_type", &battle_config.weapon_defense_type, 0, 0, INT_MAX, }, { "magic_defense_type", &battle_config.magic_defense_type, 0, 0, INT_MAX, }, { "skill_reiteration", &battle_config.skill_reiteration, BL_NUL, BL_NUL, BL_ALL, }, diff --git a/src/map/battle.h b/src/map/battle.h index f8f0a10d7..3b42c52b7 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -312,10 +312,7 @@ extern struct Battle_Config int manner_system; // end additions [Valaris] int show_mob_info; - - int agi_penalty_count_lv; - int vit_penalty_count_lv; - + int gx_allhit; int gx_disptype; int devotion_level_difference; diff --git a/src/map/mob.c b/src/map/mob.c index 3e8df661f..8318d492f 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -1293,7 +1293,7 @@ int mob_unlocktarget(struct mob_data *md, unsigned int tick) } if (md->target_id) { md->target_id=0; - md->ud.target = 0; + unit_set_target(&md->ud, 0); } return 0; } @@ -3082,11 +3082,11 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event) case MSC_SLAVELT: // slave < num flag = (mob_countslave(&md->bl) < c2 ); break; case MSC_ATTACKPCGT: // attack pc > num - flag = (unit_counttargeted(&md->bl, 0) > c2); break; + flag = (unit_counttargeted(&md->bl) > c2); break; case MSC_SLAVELE: // slave <= num flag = (mob_countslave(&md->bl) <= c2 ); break; case MSC_ATTACKPCGE: // attack pc >= num - flag = (unit_counttargeted(&md->bl, 0) >= c2); break; + flag = (unit_counttargeted(&md->bl) >= c2); break; case MSC_AFTERSKILL: flag = (md->ud.skillid == c2); break; case MSC_RUDEATTACKED: @@ -3096,7 +3096,7 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event) case MSC_MASTERHPLTMAXRATE: flag = ((fbl = mob_getmasterhpltmaxrate(md, ms[i].cond2)) != NULL); break; case MSC_MASTERATTACKED: - flag = (md->master_id > 0 && (fbl=map_id2bl(md->master_id)) && unit_counttargeted(fbl, 0) > 0); break; + flag = (md->master_id > 0 && (fbl=map_id2bl(md->master_id)) && unit_counttargeted(fbl) > 0); break; case MSC_ALCHEMIST: flag = (md->state.alchemist); break; diff --git a/src/map/unit.c b/src/map/unit.c index e35aca262..51bf92020 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -73,7 +73,7 @@ int unit_walktoxy_sub(struct block_list *bl) memcpy(&ud->walkpath,&wpd,sizeof(wpd)); - if (ud->target && ud->chaserange>1) { + if (ud->target_to && ud->chaserange>1) { //Generally speaking, the walk path is already to an adjacent tile //so we only need to shorten the path if the range is greater than 1. int dir; @@ -234,14 +234,15 @@ static int unit_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data if ( !(unit_run(bl) || unit_wugdash(bl,sd)) ) ud->state.running = 0; } - else if (ud->target) { + else if (ud->target_to) { //Update target trajectory. - struct block_list *tbl = map_id2bl(ud->target); + struct block_list *tbl = map_id2bl(ud->target_to); if (!tbl || !status_check_visibility(bl, tbl)) { //Cancel chase. ud->to_x = bl->x; ud->to_y = bl->y; - if (tbl && bl->type == BL_MOB) //See if the mob can do a warp chase. - mob_warpchase((TBL_MOB*)bl, tbl); + if (tbl && bl->type == BL_MOB && mob_warpchase((TBL_MOB*)bl, tbl) ) + return 0; + ud->target_to = 0; return 0; } if (tbl->m == bl->m && check_distance_bl(bl, tbl, ud->chaserange)) @@ -249,6 +250,7 @@ static int unit_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data if (ud->state.attack_continue) { //Aegis uses one before every attack, we should //only need this one for syncing purposes. [Skotlex] + ud->target_to = 0; clif_fixpos(bl); unit_attack(bl, tbl->id, ud->state.attack_continue); } @@ -260,6 +262,7 @@ static int unit_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data else { //Stopped walking. Update to_x and to_y to current location [Skotlex] ud->to_x = bl->x; ud->to_y = bl->y; + ud->target_to = 0; } return 0; } @@ -300,9 +303,9 @@ int unit_walktoxy( struct block_list *bl, short x, short y, int flag) return 0; ud->state.walk_easy = flag&1; - ud->target = 0; ud->to_x = x; ud->to_y = y; + unit_set_target(ud, 0); sc = status_get_sc(bl); if (sc && sc->data[SC_CONFUSION]) //Randomize the target position @@ -368,13 +371,15 @@ int unit_walktobl(struct block_list *bl, struct block_list *tbl, int range, int if (!unit_can_reach_bl(bl, tbl, distance_bl(bl, tbl)+1, flag&1, &ud->to_x, &ud->to_y)) { ud->to_x = bl->x; ud->to_y = bl->y; + ud->target_to = 0; return 0; } ud->state.walk_easy = flag&1; - ud->target = tbl->id; + ud->target_to = tbl->id; ud->chaserange = range; //Note that if flag&2, this SHOULD be attack-range ud->state.attack_continue = flag&2?1:0; //Chase to attack. + unit_set_target(ud, 0); sc = status_get_sc(bl); if (sc && sc->data[SC_CONFUSION]) //Randomize the target position @@ -1032,7 +1037,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh target_id = ud->target; //Auto-select target. [Skotlex] temp = 1; } - + if (sd) { //Target_id checking. if(skillnotok(skill_num, sd)) // [MouseJstr] @@ -1446,6 +1451,27 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, sh return 1; } +/*======================================== + * update a block's attack target + *----------------------------------------*/ +int unit_set_target(struct unit_data* ud, int target_id) +{ + struct unit_data * ux; + struct block_list* target; + + nullpo_ret(ud); + + if( ud->target != target_id ) { + if( ud->target && (target = map_id2bl(ud->target)) && (ux = unit_bl2ud(target)) && ux->target_count > 0 ) + ux->target_count --; + if( target_id && (target = map_id2bl(target_id)) && (ux = unit_bl2ud(target)) ) + ux->target_count ++; + } + + ud->target = target_id; + return 0; +} + int unit_stop_attack(struct block_list *bl) { struct unit_data *ud = unit_bl2ud(bl); @@ -1456,7 +1482,7 @@ int unit_stop_attack(struct block_list *bl) delete_timer( ud->attacktimer, unit_attack_timer ); ud->attacktimer = INVALID_TIMER; - ud->target = 0; + unit_set_target(ud, 0); return 0; } @@ -1465,8 +1491,8 @@ int unit_unattackable(struct block_list *bl) { struct unit_data *ud = unit_bl2ud(bl); if (ud) { - ud->target = 0; ud->state.attack_continue = 0; + unit_set_target(ud, 0); } if(bl->type == BL_MOB) @@ -1515,8 +1541,9 @@ int unit_attack(struct block_list *src,int target_id,int continuous) return 1; } - ud->target = target_id; ud->state.attack_continue = continuous; + unit_set_target(ud, target_id); + if (continuous) //If you're to attack continously, set to auto-case character ud->chaserange = status_get_range(src); @@ -1889,34 +1916,16 @@ void unit_dataset(struct block_list *bl) } /*========================================== - * Returns 1 if this unit is attacking target 'id' + * Counts the number of units attacking 'bl' *------------------------------------------*/ -static int unit_counttargeted_sub(struct block_list* bl, va_list ap) +int unit_counttargeted(struct block_list* bl) { - int id = va_arg(ap, int); - int target_lv = va_arg(ap, int); // extra condition struct unit_data* ud; - - if(bl->id == id) - return 0; - - ud = unit_bl2ud(bl); - - if (ud && ud->target == id && ud->attacktimer != INVALID_TIMER && ud->attacktarget_lv >= target_lv) - return 1; - + if( bl && (ud = unit_bl2ud(bl)) ) + return ud->target_count; return 0; } -/*========================================== - * Counts the number of units attacking 'bl' - *------------------------------------------*/ -int unit_counttargeted(struct block_list* bl, int target_lv) -{ - nullpo_ret(bl); - return (map_foreachinrange(unit_counttargeted_sub, bl, AREA_SIZE, BL_CHAR, bl->id, target_lv)); -} - /*========================================== * *------------------------------------------*/ @@ -1968,13 +1977,15 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, map_freeblock_lock(); - ud->target = 0; //Unlock walk/attack target. + unit_set_target(ud, 0); + if (ud->walktimer != INVALID_TIMER) unit_stop_walking(bl,0); if (ud->attacktimer != INVALID_TIMER) unit_stop_attack(bl); if (ud->skilltimer != INVALID_TIMER) unit_skillcastcancel(bl,0); + // Do not reset can-act delay. [Skotlex] ud->attackabletime = ud->canmove_tick /*= ud->canact_tick*/ = gettick(); diff --git a/src/map/unit.h b/src/map/unit.h index 6a0bf26f6..11f5fba0e 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -27,6 +27,7 @@ struct unit_data { int skilltarget; int skilltimer; int target; + int target_to; int attacktimer; int walktimer; int chaserange; @@ -35,6 +36,7 @@ struct unit_data { unsigned int canmove_tick; uint8 dir; unsigned char walk_count; + unsigned char target_count; struct { unsigned change_walk_target : 1 ; unsigned skillcastcancel : 1 ; @@ -113,7 +115,8 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, sh // 詠唱キャンセル int unit_skillcastcancel(struct block_list *bl,int type); -int unit_counttargeted(struct block_list *bl,int target_lv); +int unit_counttargeted(struct block_list *bl); +int unit_set_target(struct unit_data* ud, int target_id); // unit_data の初期化処理 void unit_dataset(struct block_list *bl); -- cgit v1.2.3-70-g09d2 From b11bf6e1604097711291265f927e79e8f2af5c54 Mon Sep 17 00:00:00 2001 From: greenboxal2 Date: Sun, 25 Nov 2012 21:20:43 +0000 Subject: Applied AStyle code formating as discussed on tid:74602. Removed /SAFESEH option from MSVC11 projects. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@16968 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/char/char.c | 8159 +++++---- src/char/char.h | 19 +- src/char/int_auction.c | 754 +- src/char/int_elemental.c | 266 +- src/char/int_guild.c | 3072 ++-- src/char/int_guild.h | 26 +- src/char/int_homun.c | 469 +- src/char/int_homun.h | 4 +- src/char/int_mail.c | 721 +- src/char/int_mail.h | 4 +- src/char/int_mercenary.c | 266 +- src/char/int_party.c | 1367 +- src/char/int_party.h | 12 +- src/char/int_pet.c | 505 +- src/char/int_quest.c | 250 +- src/char/int_storage.c | 352 +- src/char/int_storage.h | 2 +- src/char/inter.c | 2022 ++- src/char/inter.h | 4 +- src/common/atomic.h | 139 +- src/common/cbasetypes.h | 147 +- src/common/conf.c | 147 +- src/common/core.c | 447 +- src/common/core.h | 29 +- src/common/db.c | 3246 ++-- src/common/db.h | 1041 +- src/common/des.c | 316 +- src/common/des.h | 12 +- src/common/ers.c | 316 +- src/common/ers.h | 106 +- src/common/evdp.h | 130 +- src/common/evdp_epoll.c | 356 +- src/common/grfio.c | 1205 +- src/common/grfio.h | 14 +- src/common/malloc.c | 1006 +- src/common/malloc.h | 58 +- src/common/mapindex.c | 251 +- src/common/mapindex.h | 10 +- src/common/md5calc.c | 362 +- src/common/md5calc.h | 6 +- src/common/mempool.c | 899 +- src/common/mempool.h | 62 +- src/common/mmo.h | 929 +- src/common/mutex.c | 256 +- src/common/mutex.h | 50 +- src/common/netbuffer.c | 349 +- src/common/netbuffer.h | 78 +- src/common/network.c | 1809 +- src/common/network.h | 220 +- src/common/nullpo.c | 96 +- src/common/nullpo.h | 30 +- src/common/raconf.c | 1037 +- src/common/raconf.h | 34 +- src/common/random.c | 36 +- src/common/showmsg.c | 1351 +- src/common/showmsg.h | 104 +- src/common/socket.c | 1983 +- src/common/socket.h | 75 +- src/common/spinlock.h | 108 +- src/common/sql.c | 1216 +- src/common/sql.h | 139 +- src/common/strlib.c | 1729 +- src/common/strlib.h | 119 +- src/common/thread.c | 384 +- src/common/thread.h | 62 +- src/common/timer.c | 479 +- src/common/timer.h | 32 +- src/common/utils.c | 403 +- src/common/utils.h | 8 +- src/common/winapi.h | 6 +- src/config/const.h | 74 +- src/login/account.h | 227 +- src/login/account_sql.c | 1123 +- src/login/ipban.h | 2 +- src/login/ipban_sql.c | 340 +- src/login/login.c | 3198 ++-- src/login/login.h | 123 +- src/login/loginlog.h | 4 +- src/login/loginlog_sql.c | 241 +- src/map/atcommand.c | 14212 ++++++++------- src/map/atcommand.h | 28 +- src/map/battle.c | 11244 ++++++------ src/map/battle.h | 849 +- src/map/battleground.c | 329 +- src/map/battleground.h | 26 +- src/map/buyingstore.c | 804 +- src/map/buyingstore.h | 32 +- src/map/chat.c | 570 +- src/map/chat.h | 50 +- src/map/chrif.c | 2531 +-- src/map/chrif.h | 38 +- src/map/clif.c | 21218 +++++++++++----------- src/map/clif.h | 842 +- src/map/date.c | 66 +- src/map/duel.c | 248 +- src/map/duel.h | 20 +- src/map/elemental.c | 1458 +- src/map/elemental.h | 56 +- src/map/guild.c | 2853 ++- src/map/guild.h | 26 +- src/map/homunculus.c | 2062 +-- src/map/homunculus.h | 110 +- src/map/instance.c | 631 +- src/map/instance.h | 32 +- src/map/intif.c | 3021 +-- src/map/intif.h | 20 +- src/map/itemdb.c | 2238 ++- src/map/itemdb.h | 226 +- src/map/log.c | 878 +- src/map/log.h | 107 +- src/map/mail.c | 226 +- src/map/mail.h | 2 +- src/map/map.c | 5622 +++--- src/map/map.h | 967 +- src/map/mapreg.h | 6 +- src/map/mapreg_sql.c | 311 +- src/map/mercenary.c | 640 +- src/map/mercenary.h | 58 +- src/map/mob.c | 7791 ++++---- src/map/mob.h | 359 +- src/map/npc.c | 6196 +++---- src/map/npc.h | 219 +- src/map/npc_chat.c | 568 +- src/map/party.c | 1823 +- src/map/party.h | 52 +- src/map/path.c | 686 +- src/map/path.h | 10 +- src/map/pc.c | 16188 +++++++++-------- src/map/pc.h | 1176 +- src/map/pc_groups.c | 657 +- src/map/pc_groups.h | 92 +- src/map/pet.c | 2286 ++- src/map/pet.h | 140 +- src/map/quest.c | 516 +- src/map/quest.h | 26 +- src/map/script.c | 26239 +++++++++++++------------- src/map/script.h | 238 +- src/map/searchstore.c | 593 +- src/map/searchstore.h | 77 +- src/map/skill.c | 34344 ++++++++++++++++++----------------- src/map/skill.h | 3268 ++-- src/map/status.c | 20714 +++++++++++---------- src/map/status.h | 3126 ++-- src/map/storage.c | 922 +- src/map/storage.h | 4 +- src/map/trade.c | 1014 +- src/map/trade.h | 4 +- src/map/unit.c | 4228 +++-- src/map/unit.h | 104 +- src/map/vending.c | 654 +- src/map/vending.h | 24 +- src/test/test_spinlock.c | 160 +- src/tool/mapcache.c | 484 +- vcproj-12/char-server_sql.vcxproj | 2 + vcproj-12/login-server_sql.vcxproj | 2 + vcproj-12/map-server_sql.vcxproj | 2 + vcproj-12/mapcache.vcxproj | 4 +- vcproj-12/mapcache.vcxproj.filters | 1 + 158 files changed, 128222 insertions(+), 128461 deletions(-) (limited to 'src/map/unit.h') diff --git a/src/char/char.c b/src/char/char.c index 234a91b79..0db64bf07 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -30,9 +30,9 @@ #include // private declarations -#define CHAR_CONF_NAME "conf/char_athena.conf" -#define LAN_CONF_NAME "conf/subnet_athena.conf" -#define SQL_CONF_NAME "conf/inter_athena.conf" +#define CHAR_CONF_NAME "conf/char_athena.conf" +#define LAN_CONF_NAME "conf/subnet_athena.conf" +#define SQL_CONF_NAME "conf/inter_athena.conf" char char_db[256] = "char"; char scdata_db[256] = "sc_data"; @@ -68,18 +68,18 @@ char ragsrvinfo_db[256] = "ragsrvinfo"; // show loading/saving messages int save_log = 1; -static DBMap* char_db_; // int char_id -> struct mmo_charstatus* +static DBMap *char_db_; // int char_id -> struct mmo_charstatus* char db_path[1024] = "db"; int db_use_sqldbs; struct mmo_map_server { - int fd; - uint32 ip; - uint16 port; - int users; - unsigned short map[MAX_MAP_PER_SERVER]; + int fd; + uint32 ip; + uint16 port; + int users; + unsigned short map[MAX_MAP_PER_SERVER]; } server[MAX_MAP_SERVERS]; int login_fd=-1, char_fd=-1; @@ -109,28 +109,28 @@ int char_per_account = 0; //Maximum chars per account (default unlimited) [Siriu int char_del_level = 0; //From which level u can delete character [Lupus] int char_del_delay = 86400; -int log_char = 1; // loggin char or not [devil] -int log_inter = 1; // loggin inter or not [devil] +int log_char = 1; // loggin char or not [devil] +int log_inter = 1; // loggin inter or not [devil] // Advanced subnet check [LuzZza] struct s_subnet { - uint32 mask; - uint32 char_ip; - uint32 map_ip; + uint32 mask; + uint32 char_ip; + uint32 map_ip; } subnet[16]; int subnet_count = 0; struct char_session_data { - bool auth; // whether the session is authed or not - int account_id, login_id1, login_id2, sex; - int found_char[MAX_CHARS]; // ids of chars on this account - char email[40]; // e-mail (default: a@a.com) by [Yor] - time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) - int group_id; // permission - uint32 version; - uint8 clienttype; - char new_name[NAME_LENGTH]; - char birthdate[10+1]; // YYYY-MM-DD + bool auth; // whether the session is authed or not + int account_id, login_id1, login_id2, sex; + int found_char[MAX_CHARS]; // ids of chars on this account + char email[40]; // e-mail (default: a@a.com) by [Yor] + time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) + int group_id; // permission + uint32 version; + uint8 clienttype; + char new_name[NAME_LENGTH]; + char birthdate[10+1]; // YYYY-MM-DD }; int max_connect_user = 0; @@ -167,32 +167,32 @@ int console = 0; #define AUTH_TIMEOUT 30000 struct auth_node { - int account_id; - int char_id; - uint32 login_id1; - uint32 login_id2; - uint32 ip; - int sex; - time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) - int group_id; - unsigned changing_mapservers : 1; + int account_id; + int char_id; + uint32 login_id1; + uint32 login_id2; + uint32 ip; + int sex; + time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) + int group_id; + unsigned changing_mapservers : 1; }; -static DBMap* auth_db; // int account_id -> struct auth_node* +static DBMap *auth_db; // int account_id -> struct auth_node* //----------------------------------------------------- // Online User Database //----------------------------------------------------- struct online_char_data { - int account_id; - int char_id; - int fd; - int waiting_disconnect; - short server; // -2: unknown server, -1: not connected, 0+: id of server + int account_id; + int char_id; + int fd; + int waiting_disconnect; + short server; // -2: unknown server, -1: not connected, 0+: id of server }; -static DBMap* online_char_db; // int account_id -> struct online_char_data* +static DBMap *online_char_db; // int account_id -> struct online_char_data* static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data); int delete_char_sql(int char_id); @@ -201,137 +201,129 @@ int delete_char_sql(int char_id); */ static DBData create_online_char_data(DBKey key, va_list args) { - struct online_char_data* character; - CREATE(character, struct online_char_data, 1); - character->account_id = key.i; - character->char_id = -1; - character->server = -1; - character->fd = -1; - character->waiting_disconnect = INVALID_TIMER; - return db_ptr2data(character); + struct online_char_data *character; + CREATE(character, struct online_char_data, 1); + character->account_id = key.i; + character->char_id = -1; + character->server = -1; + character->fd = -1; + character->waiting_disconnect = INVALID_TIMER; + return db_ptr2data(character); } void set_char_charselect(int account_id) { - struct online_char_data* character; + struct online_char_data *character; - character = (struct online_char_data*)idb_ensure(online_char_db, account_id, create_online_char_data); + character = (struct online_char_data *)idb_ensure(online_char_db, account_id, create_online_char_data); - if( character->server > -1 ) - if( server[character->server].users > 0 ) // Prevent this value from going negative. - server[character->server].users--; + if (character->server > -1) + if (server[character->server].users > 0) // Prevent this value from going negative. + server[character->server].users--; - character->char_id = -1; - character->server = -1; + character->char_id = -1; + character->server = -1; - if(character->waiting_disconnect != INVALID_TIMER) { - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = INVALID_TIMER; - } + if (character->waiting_disconnect != INVALID_TIMER) { + delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); + character->waiting_disconnect = INVALID_TIMER; + } - if (login_fd > 0 && !session[login_fd]->flag.eof) - { - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272b; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - } + if (login_fd > 0 && !session[login_fd]->flag.eof) { + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x272b; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + } } void set_char_online(int map_id, int char_id, int account_id) { - struct online_char_data* character; - struct mmo_charstatus *cp; - - //Update DB - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='1' WHERE `char_id`='%d' LIMIT 1", char_db, char_id) ) - Sql_ShowDebug(sql_handle); - - //Check to see for online conflicts - character = (struct online_char_data*)idb_ensure(online_char_db, account_id, create_online_char_data); - if( character->char_id != -1 && character->server > -1 && character->server != map_id ) - { - ShowNotice("set_char_online: Character %d:%d marked in map server %d, but map server %d claims to have (%d:%d) online!\n", - character->account_id, character->char_id, character->server, map_id, account_id, char_id); - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - } - - //Update state data - character->char_id = char_id; - character->server = map_id; - - if( character->server > -1 ) - server[character->server].users++; - - //Get rid of disconnect timer - if(character->waiting_disconnect != INVALID_TIMER) { - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = INVALID_TIMER; - } - - //Set char online in guild cache. If char is in memory, use the guild id on it, otherwise seek it. - cp = (struct mmo_charstatus*)idb_get(char_db_,char_id); - inter_guild_CharOnline(char_id, cp?cp->guild_id:-1); - - //Notify login server - if (login_fd > 0 && !session[login_fd]->flag.eof) - { - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272b; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - } + struct online_char_data *character; + struct mmo_charstatus *cp; + + //Update DB + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='1' WHERE `char_id`='%d' LIMIT 1", char_db, char_id)) + Sql_ShowDebug(sql_handle); + + //Check to see for online conflicts + character = (struct online_char_data *)idb_ensure(online_char_db, account_id, create_online_char_data); + if (character->char_id != -1 && character->server > -1 && character->server != map_id) { + ShowNotice("set_char_online: Character %d:%d marked in map server %d, but map server %d claims to have (%d:%d) online!\n", + character->account_id, character->char_id, character->server, map_id, account_id, char_id); + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); + } + + //Update state data + character->char_id = char_id; + character->server = map_id; + + if (character->server > -1) + server[character->server].users++; + + //Get rid of disconnect timer + if (character->waiting_disconnect != INVALID_TIMER) { + delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); + character->waiting_disconnect = INVALID_TIMER; + } + + //Set char online in guild cache. If char is in memory, use the guild id on it, otherwise seek it. + cp = (struct mmo_charstatus *)idb_get(char_db_,char_id); + inter_guild_CharOnline(char_id, cp?cp->guild_id:-1); + + //Notify login server + if (login_fd > 0 && !session[login_fd]->flag.eof) { + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x272b; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + } } void set_char_offline(int char_id, int account_id) { - struct online_char_data* character; - - if ( char_id == -1 ) - { - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `account_id`='%d'", char_db, account_id) ) - Sql_ShowDebug(sql_handle); - } - else - { - struct mmo_charstatus* cp = (struct mmo_charstatus*)idb_get(char_db_,char_id); - inter_guild_CharOffline(char_id, cp?cp->guild_id:-1); - if (cp) - idb_remove(char_db_,char_id); - - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `char_id`='%d' LIMIT 1", char_db, char_id) ) - Sql_ShowDebug(sql_handle); - } - - if ((character = (struct online_char_data*)idb_get(online_char_db, account_id)) != NULL) - { //We don't free yet to avoid aCalloc/aFree spamming during char change. [Skotlex] - if( character->server > -1 ) - if( server[character->server].users > 0 ) // Prevent this value from going negative. - server[character->server].users--; - - if(character->waiting_disconnect != INVALID_TIMER){ - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = INVALID_TIMER; - } - - if(character->char_id == char_id) - { - character->char_id = -1; - character->server = -1; - } - - //FIXME? Why Kevin free'd the online information when the char was effectively in the map-server? - } - - //Remove char if 1- Set all offline, or 2- character is no longer connected to char-server. - if (login_fd > 0 && !session[login_fd]->flag.eof && (char_id == -1 || character == NULL || character->fd == -1)) - { - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272c; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - } + struct online_char_data *character; + + if (char_id == -1) { + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `account_id`='%d'", char_db, account_id)) + Sql_ShowDebug(sql_handle); + } else { + struct mmo_charstatus *cp = (struct mmo_charstatus *)idb_get(char_db_,char_id); + inter_guild_CharOffline(char_id, cp?cp->guild_id:-1); + if (cp) + idb_remove(char_db_,char_id); + + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `char_id`='%d' LIMIT 1", char_db, char_id)) + Sql_ShowDebug(sql_handle); + } + + if ((character = (struct online_char_data *)idb_get(online_char_db, account_id)) != NULL) { + //We don't free yet to avoid aCalloc/aFree spamming during char change. [Skotlex] + if (character->server > -1) + if (server[character->server].users > 0) // Prevent this value from going negative. + server[character->server].users--; + + if (character->waiting_disconnect != INVALID_TIMER) { + delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); + character->waiting_disconnect = INVALID_TIMER; + } + + if (character->char_id == char_id) { + character->char_id = -1; + character->server = -1; + } + + //FIXME? Why Kevin free'd the online information when the char was effectively in the map-server? + } + + //Remove char if 1- Set all offline, or 2- character is no longer connected to char-server. + if (login_fd > 0 && !session[login_fd]->flag.eof && (char_id == -1 || character == NULL || character->fd == -1)) { + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x272c; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + } } /** @@ -339,18 +331,18 @@ void set_char_offline(int char_id, int account_id) */ static int char_db_setoffline(DBKey key, DBData *data, va_list ap) { - struct online_char_data* character = (struct online_char_data*)db_data2ptr(data); - int server = va_arg(ap, int); - if (server == -1) { - character->char_id = -1; - character->server = -1; - if(character->waiting_disconnect != INVALID_TIMER){ - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = INVALID_TIMER; - } - } else if (character->server == server) - character->server = -2; //In some map server that we aren't connected to. - return 0; + struct online_char_data *character = (struct online_char_data *)db_data2ptr(data); + int server = va_arg(ap, int); + if (server == -1) { + character->char_id = -1; + character->server = -1; + if (character->waiting_disconnect != INVALID_TIMER) { + delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); + character->waiting_disconnect = INVALID_TIMER; + } + } else if (character->server == server) + character->server = -2; //In some map server that we aren't connected to. + return 0; } /** @@ -358,48 +350,48 @@ static int char_db_setoffline(DBKey key, DBData *data, va_list ap) */ static int char_db_kickoffline(DBKey key, DBData *data, va_list ap) { - struct online_char_data* character = (struct online_char_data*)db_data2ptr(data); - int server_id = va_arg(ap, int); + struct online_char_data *character = (struct online_char_data *)db_data2ptr(data); + int server_id = va_arg(ap, int); - if (server_id > -1 && character->server != server_id) - return 0; + if (server_id > -1 && character->server != server_id) + return 0; - //Kick out any connected characters, and set them offline as appropriate. - if (character->server > -1) - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 1); - else if (character->waiting_disconnect == INVALID_TIMER) - set_char_offline(character->char_id, character->account_id); - else - return 0; // fail + //Kick out any connected characters, and set them offline as appropriate. + if (character->server > -1) + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 1); + else if (character->waiting_disconnect == INVALID_TIMER) + set_char_offline(character->char_id, character->account_id); + else + return 0; // fail - return 1; + return 1; } void set_all_offline(int id) { - if (id < 0) - ShowNotice("Sending all users offline.\n"); - else - ShowNotice("Sending users of map-server %d offline.\n",id); - online_char_db->foreach(online_char_db,char_db_kickoffline,id); - - if (id >= 0 || login_fd <= 0 || session[login_fd]->flag.eof) - return; - //Tell login-server to also mark all our characters as offline. - WFIFOHEAD(login_fd,2); - WFIFOW(login_fd,0) = 0x2737; - WFIFOSET(login_fd,2); + if (id < 0) + ShowNotice("Sending all users offline.\n"); + else + ShowNotice("Sending users of map-server %d offline.\n",id); + online_char_db->foreach(online_char_db,char_db_kickoffline,id); + + if (id >= 0 || login_fd <= 0 || session[login_fd]->flag.eof) + return; + //Tell login-server to also mark all our characters as offline. + WFIFOHEAD(login_fd,2); + WFIFOW(login_fd,0) = 0x2737; + WFIFOSET(login_fd,2); } void set_all_offline_sql(void) { - //Set all players to 'OFFLINE' - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", char_db) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", guild_member_db) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `connect_member` = '0'", guild_db) ) - Sql_ShowDebug(sql_handle); + //Set all players to 'OFFLINE' + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", char_db)) + Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", guild_member_db)) + Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `connect_member` = '0'", guild_db)) + Sql_ShowDebug(sql_handle); } /** @@ -407,949 +399,920 @@ void set_all_offline_sql(void) */ static DBData create_charstatus(DBKey key, va_list args) { - struct mmo_charstatus *cp; - cp = (struct mmo_charstatus *) aCalloc(1,sizeof(struct mmo_charstatus)); - cp->char_id = key.i; - return db_ptr2data(cp); + struct mmo_charstatus *cp; + cp = (struct mmo_charstatus *) aCalloc(1,sizeof(struct mmo_charstatus)); + cp->char_id = key.i; + return db_ptr2data(cp); } int inventory_to_sql(const struct item items[], int max, int id); -int mmo_char_tosql(int char_id, struct mmo_charstatus* p) +int mmo_char_tosql(int char_id, struct mmo_charstatus *p) { - int i = 0; - int count = 0; - int diff = 0; - char save_status[128]; //For displaying save information. [Skotlex] - struct mmo_charstatus *cp; - int errors = 0; //If there are any errors while saving, "cp" will not be updated at the end. - StringBuf buf; - - if (char_id!=p->char_id) return 0; - - cp = idb_ensure(char_db_, char_id, create_charstatus); - - StringBuf_Init(&buf); - memset(save_status, 0, sizeof(save_status)); - - //map inventory data - if( memcmp(p->inventory, cp->inventory, sizeof(p->inventory)) ) { - if (!inventory_to_sql(p->inventory, MAX_INVENTORY, p->char_id)) - strcat(save_status, " inventory"); - else - errors++; - } - - //map cart data - if( memcmp(p->cart, cp->cart, sizeof(p->cart)) ) { - if (!memitemdata_to_sql(p->cart, MAX_CART, p->char_id, TABLE_CART)) - strcat(save_status, " cart"); - else - errors++; - } - - //map storage data - if( memcmp(p->storage.items, cp->storage.items, sizeof(p->storage.items)) ) { - if (!memitemdata_to_sql(p->storage.items, MAX_STORAGE, p->account_id, TABLE_STORAGE)) - strcat(save_status, " storage"); - else - errors++; - } - - if ( - (p->base_exp != cp->base_exp) || (p->base_level != cp->base_level) || - (p->job_level != cp->job_level) || (p->job_exp != cp->job_exp) || - (p->zeny != cp->zeny) || - (p->last_point.map != cp->last_point.map) || - (p->last_point.x != cp->last_point.x) || (p->last_point.y != cp->last_point.y) || - (p->max_hp != cp->max_hp) || (p->hp != cp->hp) || - (p->max_sp != cp->max_sp) || (p->sp != cp->sp) || - (p->status_point != cp->status_point) || (p->skill_point != cp->skill_point) || - (p->str != cp->str) || (p->agi != cp->agi) || (p->vit != cp->vit) || - (p->int_ != cp->int_) || (p->dex != cp->dex) || (p->luk != cp->luk) || - (p->option != cp->option) || - (p->party_id != cp->party_id) || (p->guild_id != cp->guild_id) || - (p->pet_id != cp->pet_id) || (p->weapon != cp->weapon) || (p->hom_id != cp->hom_id) || - (p->ele_id != cp->ele_id) || (p->shield != cp->shield) || (p->head_top != cp->head_top) || - (p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom) || (p->delete_date != cp->delete_date) || - (p->rename != cp->rename) || (p->robe != cp->robe) - ) - { //Save status - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `base_level`='%d', `job_level`='%d'," - "`base_exp`='%u', `job_exp`='%u', `zeny`='%d'," - "`max_hp`='%d',`hp`='%d',`max_sp`='%d',`sp`='%d',`status_point`='%d',`skill_point`='%d'," - "`str`='%d',`agi`='%d',`vit`='%d',`int`='%d',`dex`='%d',`luk`='%d'," - "`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d',`elemental_id`='%d'," - "`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d'," - "`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d'," - "`delete_date`='%lu',`robe`='%d'" - " WHERE `account_id`='%d' AND `char_id` = '%d'", - char_db, p->base_level, p->job_level, - p->base_exp, p->job_exp, p->zeny, - p->max_hp, p->hp, p->max_sp, p->sp, p->status_point, p->skill_point, - p->str, p->agi, p->vit, p->int_, p->dex, p->luk, - p->option, p->party_id, p->guild_id, p->pet_id, p->hom_id, p->ele_id, - p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, - mapindex_id2name(p->last_point.map), p->last_point.x, p->last_point.y, - mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename, - (unsigned long)p->delete_date, // FIXME: platform-dependent size - p->robe, - p->account_id, p->char_id) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } else - strcat(save_status, " status"); - } - - //Values that will seldom change (to speed up saving) - if ( - (p->hair != cp->hair) || (p->hair_color != cp->hair_color) || (p->clothes_color != cp->clothes_color) || - (p->class_ != cp->class_) || - (p->partner_id != cp->partner_id) || (p->father != cp->father) || - (p->mother != cp->mother) || (p->child != cp->child) || - (p->karma != cp->karma) || (p->manner != cp->manner) || - (p->fame != cp->fame) - ) - { - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d'," - "`hair`='%d',`hair_color`='%d',`clothes_color`='%d'," - "`partner_id`='%d', `father`='%d', `mother`='%d', `child`='%d'," - "`karma`='%d',`manner`='%d', `fame`='%d'" - " WHERE `account_id`='%d' AND `char_id` = '%d'", - char_db, p->class_, - p->hair, p->hair_color, p->clothes_color, - p->partner_id, p->father, p->mother, p->child, - p->karma, p->manner, p->fame, - p->account_id, p->char_id) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } else - strcat(save_status, " status2"); - } - - /* Mercenary Owner */ - if( (p->mer_id != cp->mer_id) || - (p->arch_calls != cp->arch_calls) || (p->arch_faith != cp->arch_faith) || - (p->spear_calls != cp->spear_calls) || (p->spear_faith != cp->spear_faith) || - (p->sword_calls != cp->sword_calls) || (p->sword_faith != cp->sword_faith) ) - { - if (mercenary_owner_tosql(char_id, p)) - strcat(save_status, " mercenary"); - else - errors++; - } - - //memo points - if( memcmp(p->memo_point, cp->memo_point, sizeof(p->memo_point)) ) - { - char esc_mapname[NAME_LENGTH*2+1]; - - //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`) - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, p->char_id) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - - //insert here. - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`map`,`x`,`y`) VALUES ", memo_db); - for( i = 0, count = 0; i < MAX_MEMOPOINTS; ++i ) - { - if( p->memo_point[i].map ) - { - if( count ) - StringBuf_AppendStr(&buf, ","); - Sql_EscapeString(sql_handle, esc_mapname, mapindex_id2name(p->memo_point[i].map)); - StringBuf_Printf(&buf, "('%d', '%s', '%d', '%d')", char_id, esc_mapname, p->memo_point[i].x, p->memo_point[i].y); - ++count; - } - } - if( count ) - { - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - } - strcat(save_status, " memo"); - } - - //FIXME: is this neccessary? [ultramage] - for(i=0;iskill[i].lv != 0) && (p->skill[i].id == 0)) - p->skill[i].id = i; // Fix skill tree - - - //skills - if( memcmp(p->skill, cp->skill, sizeof(p->skill)) ) - { - //`skill` (`char_id`, `id`, `lv`) - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, p->char_id) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`id`,`lv`) VALUES ", skill_db); - //insert here. - for( i = 0, count = 0; i < MAX_SKILL; ++i ) - { - if( p->skill[i].id != 0 && p->skill[i].flag != SKILL_FLAG_TEMPORARY ) - { - if( p->skill[i].flag == SKILL_FLAG_PERMANENT && p->skill[i].lv == 0 ) - continue; - if( p->skill[i].flag != SKILL_FLAG_PERMANENT && (p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0) == 0 ) - continue; - if( count ) - StringBuf_AppendStr(&buf, ","); - StringBuf_Printf(&buf, "('%d','%d','%d')", char_id, p->skill[i].id, (p->skill[i].flag == SKILL_FLAG_PERMANENT ? p->skill[i].lv : p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0)); - ++count; - } - } - if( count ) - { - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - } - - strcat(save_status, " skills"); - } - - diff = 0; - for(i = 0; i < MAX_FRIENDS; i++){ - if(p->friends[i].char_id != cp->friends[i].char_id || - p->friends[i].account_id != cp->friends[i].account_id){ - diff = 1; - break; - } - } - - if(diff == 1) - { //Save friends - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", friend_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `friend_account`, `friend_id`) VALUES ", friend_db); - for( i = 0, count = 0; i < MAX_FRIENDS; ++i ) - { - if( p->friends[i].char_id > 0 ) - { - if( count ) - StringBuf_AppendStr(&buf, ","); - StringBuf_Printf(&buf, "('%d','%d','%d')", char_id, p->friends[i].account_id, p->friends[i].char_id); - count++; - } - } - if( count ) - { - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - } - strcat(save_status, " friends"); - } + int i = 0; + int count = 0; + int diff = 0; + char save_status[128]; //For displaying save information. [Skotlex] + struct mmo_charstatus *cp; + int errors = 0; //If there are any errors while saving, "cp" will not be updated at the end. + StringBuf buf; + + if (char_id!=p->char_id) return 0; + + cp = idb_ensure(char_db_, char_id, create_charstatus); + + StringBuf_Init(&buf); + memset(save_status, 0, sizeof(save_status)); + + //map inventory data + if (memcmp(p->inventory, cp->inventory, sizeof(p->inventory))) { + if (!inventory_to_sql(p->inventory, MAX_INVENTORY, p->char_id)) + strcat(save_status, " inventory"); + else + errors++; + } + + //map cart data + if (memcmp(p->cart, cp->cart, sizeof(p->cart))) { + if (!memitemdata_to_sql(p->cart, MAX_CART, p->char_id, TABLE_CART)) + strcat(save_status, " cart"); + else + errors++; + } + + //map storage data + if (memcmp(p->storage.items, cp->storage.items, sizeof(p->storage.items))) { + if (!memitemdata_to_sql(p->storage.items, MAX_STORAGE, p->account_id, TABLE_STORAGE)) + strcat(save_status, " storage"); + else + errors++; + } + + if ( + (p->base_exp != cp->base_exp) || (p->base_level != cp->base_level) || + (p->job_level != cp->job_level) || (p->job_exp != cp->job_exp) || + (p->zeny != cp->zeny) || + (p->last_point.map != cp->last_point.map) || + (p->last_point.x != cp->last_point.x) || (p->last_point.y != cp->last_point.y) || + (p->max_hp != cp->max_hp) || (p->hp != cp->hp) || + (p->max_sp != cp->max_sp) || (p->sp != cp->sp) || + (p->status_point != cp->status_point) || (p->skill_point != cp->skill_point) || + (p->str != cp->str) || (p->agi != cp->agi) || (p->vit != cp->vit) || + (p->int_ != cp->int_) || (p->dex != cp->dex) || (p->luk != cp->luk) || + (p->option != cp->option) || + (p->party_id != cp->party_id) || (p->guild_id != cp->guild_id) || + (p->pet_id != cp->pet_id) || (p->weapon != cp->weapon) || (p->hom_id != cp->hom_id) || + (p->ele_id != cp->ele_id) || (p->shield != cp->shield) || (p->head_top != cp->head_top) || + (p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom) || (p->delete_date != cp->delete_date) || + (p->rename != cp->rename) || (p->robe != cp->robe) + ) { + //Save status + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `base_level`='%d', `job_level`='%d'," + "`base_exp`='%u', `job_exp`='%u', `zeny`='%d'," + "`max_hp`='%d',`hp`='%d',`max_sp`='%d',`sp`='%d',`status_point`='%d',`skill_point`='%d'," + "`str`='%d',`agi`='%d',`vit`='%d',`int`='%d',`dex`='%d',`luk`='%d'," + "`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d',`elemental_id`='%d'," + "`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d'," + "`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d'," + "`delete_date`='%lu',`robe`='%d'" + " WHERE `account_id`='%d' AND `char_id` = '%d'", + char_db, p->base_level, p->job_level, + p->base_exp, p->job_exp, p->zeny, + p->max_hp, p->hp, p->max_sp, p->sp, p->status_point, p->skill_point, + p->str, p->agi, p->vit, p->int_, p->dex, p->luk, + p->option, p->party_id, p->guild_id, p->pet_id, p->hom_id, p->ele_id, + p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, + mapindex_id2name(p->last_point.map), p->last_point.x, p->last_point.y, + mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename, + (unsigned long)p->delete_date, // FIXME: platform-dependent size + p->robe, + p->account_id, p->char_id)) { + Sql_ShowDebug(sql_handle); + errors++; + } else + strcat(save_status, " status"); + } + + //Values that will seldom change (to speed up saving) + if ( + (p->hair != cp->hair) || (p->hair_color != cp->hair_color) || (p->clothes_color != cp->clothes_color) || + (p->class_ != cp->class_) || + (p->partner_id != cp->partner_id) || (p->father != cp->father) || + (p->mother != cp->mother) || (p->child != cp->child) || + (p->karma != cp->karma) || (p->manner != cp->manner) || + (p->fame != cp->fame) + ) { + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d'," + "`hair`='%d',`hair_color`='%d',`clothes_color`='%d'," + "`partner_id`='%d', `father`='%d', `mother`='%d', `child`='%d'," + "`karma`='%d',`manner`='%d', `fame`='%d'" + " WHERE `account_id`='%d' AND `char_id` = '%d'", + char_db, p->class_, + p->hair, p->hair_color, p->clothes_color, + p->partner_id, p->father, p->mother, p->child, + p->karma, p->manner, p->fame, + p->account_id, p->char_id)) { + Sql_ShowDebug(sql_handle); + errors++; + } else + strcat(save_status, " status2"); + } + + /* Mercenary Owner */ + if ((p->mer_id != cp->mer_id) || + (p->arch_calls != cp->arch_calls) || (p->arch_faith != cp->arch_faith) || + (p->spear_calls != cp->spear_calls) || (p->spear_faith != cp->spear_faith) || + (p->sword_calls != cp->sword_calls) || (p->sword_faith != cp->sword_faith)) { + if (mercenary_owner_tosql(char_id, p)) + strcat(save_status, " mercenary"); + else + errors++; + } + + //memo points + if (memcmp(p->memo_point, cp->memo_point, sizeof(p->memo_point))) { + char esc_mapname[NAME_LENGTH*2+1]; + + //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`) + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, p->char_id)) { + Sql_ShowDebug(sql_handle); + errors++; + } + + //insert here. + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`map`,`x`,`y`) VALUES ", memo_db); + for (i = 0, count = 0; i < MAX_MEMOPOINTS; ++i) { + if (p->memo_point[i].map) { + if (count) + StringBuf_AppendStr(&buf, ","); + Sql_EscapeString(sql_handle, esc_mapname, mapindex_id2name(p->memo_point[i].map)); + StringBuf_Printf(&buf, "('%d', '%s', '%d', '%d')", char_id, esc_mapname, p->memo_point[i].x, p->memo_point[i].y); + ++count; + } + } + if (count) { + if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + errors++; + } + } + strcat(save_status, " memo"); + } + + //FIXME: is this neccessary? [ultramage] + for (i=0; iskill[i].lv != 0) && (p->skill[i].id == 0)) + p->skill[i].id = i; // Fix skill tree + + + //skills + if (memcmp(p->skill, cp->skill, sizeof(p->skill))) { + //`skill` (`char_id`, `id`, `lv`) + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, p->char_id)) { + Sql_ShowDebug(sql_handle); + errors++; + } + + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`id`,`lv`) VALUES ", skill_db); + //insert here. + for (i = 0, count = 0; i < MAX_SKILL; ++i) { + if (p->skill[i].id != 0 && p->skill[i].flag != SKILL_FLAG_TEMPORARY) { + if (p->skill[i].flag == SKILL_FLAG_PERMANENT && p->skill[i].lv == 0) + continue; + if (p->skill[i].flag != SKILL_FLAG_PERMANENT && (p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0) == 0) + continue; + if (count) + StringBuf_AppendStr(&buf, ","); + StringBuf_Printf(&buf, "('%d','%d','%d')", char_id, p->skill[i].id, (p->skill[i].flag == SKILL_FLAG_PERMANENT ? p->skill[i].lv : p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0)); + ++count; + } + } + if (count) { + if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + errors++; + } + } + + strcat(save_status, " skills"); + } + + diff = 0; + for (i = 0; i < MAX_FRIENDS; i++) { + if (p->friends[i].char_id != cp->friends[i].char_id || + p->friends[i].account_id != cp->friends[i].account_id) { + diff = 1; + break; + } + } + + if (diff == 1) { + //Save friends + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", friend_db, char_id)) { + Sql_ShowDebug(sql_handle); + errors++; + } + + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `friend_account`, `friend_id`) VALUES ", friend_db); + for (i = 0, count = 0; i < MAX_FRIENDS; ++i) { + if (p->friends[i].char_id > 0) { + if (count) + StringBuf_AppendStr(&buf, ","); + StringBuf_Printf(&buf, "('%d','%d','%d')", char_id, p->friends[i].account_id, p->friends[i].char_id); + count++; + } + } + if (count) { + if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + errors++; + } + } + strcat(save_status, " friends"); + } #ifdef HOTKEY_SAVING - // hotkeys - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "REPLACE INTO `%s` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl`) VALUES ", hotkey_db); - diff = 0; - for(i = 0; i < ARRAYLENGTH(p->hotkeys); i++){ - if(memcmp(&p->hotkeys[i], &cp->hotkeys[i], sizeof(struct hotkey))) - { - if( diff ) - StringBuf_AppendStr(&buf, ",");// not the first hotkey - StringBuf_Printf(&buf, "('%d','%u','%u','%u','%u')", char_id, (unsigned int)i, (unsigned int)p->hotkeys[i].type, p->hotkeys[i].id , (unsigned int)p->hotkeys[i].lv); - diff = 1; - } - } - if(diff) { - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } else - strcat(save_status, " hotkeys"); - } + // hotkeys + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "REPLACE INTO `%s` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl`) VALUES ", hotkey_db); + diff = 0; + for (i = 0; i < ARRAYLENGTH(p->hotkeys); i++) { + if (memcmp(&p->hotkeys[i], &cp->hotkeys[i], sizeof(struct hotkey))) { + if (diff) + StringBuf_AppendStr(&buf, ",");// not the first hotkey + StringBuf_Printf(&buf, "('%d','%u','%u','%u','%u')", char_id, (unsigned int)i, (unsigned int)p->hotkeys[i].type, p->hotkeys[i].id , (unsigned int)p->hotkeys[i].lv); + diff = 1; + } + } + if (diff) { + if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + errors++; + } else + strcat(save_status, " hotkeys"); + } #endif - StringBuf_Destroy(&buf); - if (save_status[0]!='\0' && save_log) - ShowInfo("Saved char %d - %s:%s.\n", char_id, p->name, save_status); - if (!errors) - memcpy(cp, p, sizeof(struct mmo_charstatus)); - return 0; + StringBuf_Destroy(&buf); + if (save_status[0]!='\0' && save_log) + ShowInfo("Saved char %d - %s:%s.\n", char_id, p->name, save_status); + if (!errors) + memcpy(cp, p, sizeof(struct mmo_charstatus)); + return 0; } /// Saves an array of 'item' entries into the specified table. int memitemdata_to_sql(const struct item items[], int max, int id, int tableswitch) { - StringBuf buf; - SqlStmt* stmt; - int i; - int j; - const char* tablename; - const char* selectoption; - struct item item; // temp storage variable - bool* flag; // bit array for inventory matching - bool found; - int errors = 0; - - switch (tableswitch) { - case TABLE_INVENTORY: tablename = inventory_db; selectoption = "char_id"; break; - case TABLE_CART: tablename = cart_db; selectoption = "char_id"; break; - case TABLE_STORAGE: tablename = storage_db; selectoption = "account_id"; break; - case TABLE_GUILD_STORAGE: tablename = guild_storage_db; selectoption = "guild_id"; break; - default: - ShowError("Invalid table name!\n"); - return 1; - } - - - // The following code compares inventory with current database values - // and performs modification/deletion/insertion only on relevant rows. - // This approach is more complicated than a trivial delete&insert, but - // it significantly reduces cpu load on the database server. - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `%s`='%d'", tablename, selectoption, id); - - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_ERROR == SqlStmt_Execute(stmt) ) - { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); - return 1; - } - - SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); - for( j = 0; j < MAX_SLOTS; ++j ) - SqlStmt_BindColumn(stmt, 8+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); - - // bit array indicating which inventory items have already been matched - flag = (bool*) aCalloc(max, sizeof(bool)); - - while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) - { - found = false; - // search for the presence of the item in the char's inventory - for( i = 0; i < max; ++i ) - { - // skip empty and already matched entries - if( items[i].nameid == 0 || flag[i] ) - continue; - - if( items[i].nameid == item.nameid - && items[i].card[0] == item.card[0] - && items[i].card[2] == item.card[2] - && items[i].card[3] == item.card[3] - ) { //They are the same item. - ARR_FIND( 0, MAX_SLOTS, j, items[i].card[j] != item.card[j] ); - if( j == MAX_SLOTS && - items[i].amount == item.amount && - items[i].equip == item.equip && - items[i].identify == item.identify && - items[i].refine == item.refine && - items[i].attribute == item.attribute && - items[i].expire_time == item.expire_time ) - ; //Do nothing. - else - { - // update all fields. - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u'", - tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); - StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); - - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - } - - found = flag[i] = true; //Item dealt with, - break; //skip to next item in the db. - } - } - if( !found ) - {// Item not present in inventory, remove it. - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d' LIMIT 1", tablename, item.id) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - } - } - SqlStmt_Free(stmt); - - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`", tablename, selectoption); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_AppendStr(&buf, ") VALUES "); - - found = false; - // insert non-matched items into the db as new items - for( i = 0; i < max; ++i ) - { - // skip empty and already matched entries - if( items[i].nameid == 0 || flag[i] ) - continue; - - if( found ) - StringBuf_AppendStr(&buf, ","); - else - found = true; - - StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u'", - id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", '%d'", items[i].card[j]); - StringBuf_AppendStr(&buf, ")"); - } - - if( found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - - StringBuf_Destroy(&buf); - aFree(flag); - - return errors; + StringBuf buf; + SqlStmt *stmt; + int i; + int j; + const char *tablename; + const char *selectoption; + struct item item; // temp storage variable + bool *flag; // bit array for inventory matching + bool found; + int errors = 0; + + switch (tableswitch) { + case TABLE_INVENTORY: + tablename = inventory_db; + selectoption = "char_id"; + break; + case TABLE_CART: + tablename = cart_db; + selectoption = "char_id"; + break; + case TABLE_STORAGE: + tablename = storage_db; + selectoption = "account_id"; + break; + case TABLE_GUILD_STORAGE: + tablename = guild_storage_db; + selectoption = "guild_id"; + break; + default: + ShowError("Invalid table name!\n"); + return 1; + } + + + // The following code compares inventory with current database values + // and performs modification/deletion/insertion only on relevant rows. + // This approach is more complicated than a trivial delete&insert, but + // it significantly reduces cpu load on the database server. + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `%s`='%d'", tablename, selectoption, id); + + stmt = SqlStmt_Malloc(sql_handle); + if (SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_ERROR == SqlStmt_Execute(stmt)) { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); + return 1; + } + + SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); + for (j = 0; j < MAX_SLOTS; ++j) + SqlStmt_BindColumn(stmt, 8+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); + + // bit array indicating which inventory items have already been matched + flag = (bool *) aCalloc(max, sizeof(bool)); + + while (SQL_SUCCESS == SqlStmt_NextRow(stmt)) { + found = false; + // search for the presence of the item in the char's inventory + for (i = 0; i < max; ++i) { + // skip empty and already matched entries + if (items[i].nameid == 0 || flag[i]) + continue; + + if (items[i].nameid == item.nameid + && items[i].card[0] == item.card[0] + && items[i].card[2] == item.card[2] + && items[i].card[3] == item.card[3] + ) { //They are the same item. + ARR_FIND(0, MAX_SLOTS, j, items[i].card[j] != item.card[j]); + if (j == MAX_SLOTS && + items[i].amount == item.amount && + items[i].equip == item.equip && + items[i].identify == item.identify && + items[i].refine == item.refine && + items[i].attribute == item.attribute && + items[i].expire_time == item.expire_time) + ; //Do nothing. + else { + // update all fields. + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u'", + tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); + StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); + + if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + errors++; + } + } + + found = flag[i] = true; //Item dealt with, + break; //skip to next item in the db. + } + } + if (!found) { + // Item not present in inventory, remove it. + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d' LIMIT 1", tablename, item.id)) { + Sql_ShowDebug(sql_handle); + errors++; + } + } + } + SqlStmt_Free(stmt); + + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`", tablename, selectoption); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_AppendStr(&buf, ") VALUES "); + + found = false; + // insert non-matched items into the db as new items + for (i = 0; i < max; ++i) { + // skip empty and already matched entries + if (items[i].nameid == 0 || flag[i]) + continue; + + if (found) + StringBuf_AppendStr(&buf, ","); + else + found = true; + + StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u'", + id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ", '%d'", items[i].card[j]); + StringBuf_AppendStr(&buf, ")"); + } + + if (found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + errors++; + } + + StringBuf_Destroy(&buf); + aFree(flag); + + return errors; } /* pretty much a copy of memitemdata_to_sql except it handles inventory_db exclusively, * - this is required because inventory db is the only one with the 'favorite' column. */ -int inventory_to_sql(const struct item items[], int max, int id) { - StringBuf buf; - SqlStmt* stmt; - int i; - int j; - struct item item; // temp storage variable - bool* flag; // bit array for inventory matching - bool found; - int errors = 0; - - - // The following code compares inventory with current database values - // and performs modification/deletion/insertion only on relevant rows. - // This approach is more complicated than a trivial delete&insert, but - // it significantly reduces cpu load on the database server. - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`"); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d'", inventory_db, id); - - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_ERROR == SqlStmt_Execute(stmt) ) - { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); - return 1; - } - - SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR, &item.favorite, 0, NULL, NULL); - for( j = 0; j < MAX_SLOTS; ++j ) - SqlStmt_BindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); - - // bit array indicating which inventory items have already been matched - flag = (bool*) aCalloc(max, sizeof(bool)); - - while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) { - found = false; - // search for the presence of the item in the char's inventory - for( i = 0; i < max; ++i ) { - // skip empty and already matched entries - if( items[i].nameid == 0 || flag[i] ) - continue; - - if( items[i].nameid == item.nameid - && items[i].card[0] == item.card[0] - && items[i].card[2] == item.card[2] - && items[i].card[3] == item.card[3] - ) { //They are the same item. - ARR_FIND( 0, MAX_SLOTS, j, items[i].card[j] != item.card[j] ); - if( j == MAX_SLOTS && - items[i].amount == item.amount && - items[i].equip == item.equip && - items[i].identify == item.identify && - items[i].refine == item.refine && - items[i].attribute == item.attribute && - items[i].expire_time == item.expire_time && - items[i].favorite == item.favorite ) - ; //Do nothing. - else { - // update all fields. - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `favorite`='%d'", - inventory_db, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); - StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); - - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) { - Sql_ShowDebug(sql_handle); - errors++; - } - } - - found = flag[i] = true; //Item dealt with, - break; //skip to next item in the db. - } - } - if( !found ) {// Item not present in inventory, remove it. - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d' LIMIT 1", inventory_db, item.id) ) { - Sql_ShowDebug(sql_handle); - errors++; - } - } - } - SqlStmt_Free(stmt); - - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`", inventory_db); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_AppendStr(&buf, ") VALUES "); - - found = false; - // insert non-matched items into the db as new items - for( i = 0; i < max; ++i ) { - // skip empty and already matched entries - if( items[i].nameid == 0 || flag[i] ) - continue; - - if( found ) - StringBuf_AppendStr(&buf, ","); - else - found = true; - - StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%d'", - id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", '%d'", items[i].card[j]); - StringBuf_AppendStr(&buf, ")"); - } - - if( found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) { - Sql_ShowDebug(sql_handle); - errors++; - } - - StringBuf_Destroy(&buf); - aFree(flag); - - return errors; +int inventory_to_sql(const struct item items[], int max, int id) +{ + StringBuf buf; + SqlStmt *stmt; + int i; + int j; + struct item item; // temp storage variable + bool *flag; // bit array for inventory matching + bool found; + int errors = 0; + + + // The following code compares inventory with current database values + // and performs modification/deletion/insertion only on relevant rows. + // This approach is more complicated than a trivial delete&insert, but + // it significantly reduces cpu load on the database server. + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`"); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d'", inventory_db, id); + + stmt = SqlStmt_Malloc(sql_handle); + if (SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_ERROR == SqlStmt_Execute(stmt)) { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); + return 1; + } + + SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR, &item.favorite, 0, NULL, NULL); + for (j = 0; j < MAX_SLOTS; ++j) + SqlStmt_BindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); + + // bit array indicating which inventory items have already been matched + flag = (bool *) aCalloc(max, sizeof(bool)); + + while (SQL_SUCCESS == SqlStmt_NextRow(stmt)) { + found = false; + // search for the presence of the item in the char's inventory + for (i = 0; i < max; ++i) { + // skip empty and already matched entries + if (items[i].nameid == 0 || flag[i]) + continue; + + if (items[i].nameid == item.nameid + && items[i].card[0] == item.card[0] + && items[i].card[2] == item.card[2] + && items[i].card[3] == item.card[3] + ) { //They are the same item. + ARR_FIND(0, MAX_SLOTS, j, items[i].card[j] != item.card[j]); + if (j == MAX_SLOTS && + items[i].amount == item.amount && + items[i].equip == item.equip && + items[i].identify == item.identify && + items[i].refine == item.refine && + items[i].attribute == item.attribute && + items[i].expire_time == item.expire_time && + items[i].favorite == item.favorite) + ; //Do nothing. + else { + // update all fields. + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `favorite`='%d'", + inventory_db, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); + StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); + + if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + errors++; + } + } + + found = flag[i] = true; //Item dealt with, + break; //skip to next item in the db. + } + } + if (!found) { // Item not present in inventory, remove it. + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d' LIMIT 1", inventory_db, item.id)) { + Sql_ShowDebug(sql_handle); + errors++; + } + } + } + SqlStmt_Free(stmt); + + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`", inventory_db); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_AppendStr(&buf, ") VALUES "); + + found = false; + // insert non-matched items into the db as new items + for (i = 0; i < max; ++i) { + // skip empty and already matched entries + if (items[i].nameid == 0 || flag[i]) + continue; + + if (found) + StringBuf_AppendStr(&buf, ","); + else + found = true; + + StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%d'", + id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ", '%d'", items[i].card[j]); + StringBuf_AppendStr(&buf, ")"); + } + + if (found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + errors++; + } + + StringBuf_Destroy(&buf); + aFree(flag); + + return errors; } -int mmo_char_tobuf(uint8* buf, struct mmo_charstatus* p); +int mmo_char_tobuf(uint8 *buf, struct mmo_charstatus *p); //===================================================================================================== // Loads the basic character rooster for the given account. Returns total buffer used. -int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) +int mmo_chars_fromsql(struct char_session_data *sd, uint8 *buf) { - SqlStmt* stmt; - struct mmo_charstatus p; - int j = 0, i; - char last_map[MAP_NAME_LENGTH_EXT]; - - stmt = SqlStmt_Malloc(sql_handle); - if( stmt == NULL ) - { - SqlStmt_ShowDebug(stmt); - return 0; - } - memset(&p, 0, sizeof(p)); - - // read char data - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT " - "`char_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`," - "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," - "`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`," - "`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`rename`,`delete_date`," - "`robe`" - " FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", char_db, sd->account_id, MAX_CHARS) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p.char_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR, &p.slot, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &p.name, sizeof(p.name), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_SHORT, &p.class_, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_UINT, &p.base_level, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_UINT, &p.job_level, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_UINT, &p.base_exp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &p.job_exp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_INT, &p.zeny, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_SHORT, &p.str, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 10, SQLDT_SHORT, &p.agi, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 11, SQLDT_SHORT, &p.vit, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 12, SQLDT_SHORT, &p.int_, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 13, SQLDT_SHORT, &p.dex, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 14, SQLDT_SHORT, &p.luk, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 15, SQLDT_INT, &p.max_hp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 16, SQLDT_INT, &p.hp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 17, SQLDT_INT, &p.max_sp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 18, SQLDT_INT, &p.sp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 19, SQLDT_UINT, &p.status_point, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 20, SQLDT_UINT, &p.skill_point, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 21, SQLDT_UINT, &p.option, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 22, SQLDT_UCHAR, &p.karma, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 23, SQLDT_SHORT, &p.manner, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 24, SQLDT_SHORT, &p.hair, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 25, SQLDT_SHORT, &p.hair_color, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_SHORT, &p.clothes_color, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_SHORT, &p.weapon, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_SHORT, &p.shield, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_SHORT, &p.head_top, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p.head_mid, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p.head_bottom, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p.rename, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_UINT32, &p.delete_date, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p.robe, 0, NULL, NULL) - ) - { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - return 0; - } - for( i = 0; i < MAX_CHARS && SQL_SUCCESS == SqlStmt_NextRow(stmt); i++ ) - { - p.last_point.map = mapindex_name2id(last_map); - sd->found_char[i] = p.char_id; - j += mmo_char_tobuf(WBUFP(buf, j), &p); - } - for( ; i < MAX_CHARS; i++ ) - sd->found_char[i] = -1; - - memset(sd->new_name,0,sizeof(sd->new_name)); - - SqlStmt_Free(stmt); - return j; + SqlStmt *stmt; + struct mmo_charstatus p; + int j = 0, i; + char last_map[MAP_NAME_LENGTH_EXT]; + + stmt = SqlStmt_Malloc(sql_handle); + if (stmt == NULL) { + SqlStmt_ShowDebug(stmt); + return 0; + } + memset(&p, 0, sizeof(p)); + + // read char data + if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT " + "`char_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`," + "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," + "`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`," + "`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`rename`,`delete_date`," + "`robe`" + " FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", char_db, sd->account_id, MAX_CHARS) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p.char_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR, &p.slot, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &p.name, sizeof(p.name), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_SHORT, &p.class_, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_UINT, &p.base_level, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_UINT, &p.job_level, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_UINT, &p.base_exp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &p.job_exp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_INT, &p.zeny, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_SHORT, &p.str, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 10, SQLDT_SHORT, &p.agi, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 11, SQLDT_SHORT, &p.vit, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 12, SQLDT_SHORT, &p.int_, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 13, SQLDT_SHORT, &p.dex, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 14, SQLDT_SHORT, &p.luk, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 15, SQLDT_INT, &p.max_hp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 16, SQLDT_INT, &p.hp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 17, SQLDT_INT, &p.max_sp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 18, SQLDT_INT, &p.sp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 19, SQLDT_UINT, &p.status_point, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 20, SQLDT_UINT, &p.skill_point, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 21, SQLDT_UINT, &p.option, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 22, SQLDT_UCHAR, &p.karma, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 23, SQLDT_SHORT, &p.manner, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 24, SQLDT_SHORT, &p.hair, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 25, SQLDT_SHORT, &p.hair_color, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_SHORT, &p.clothes_color, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_SHORT, &p.weapon, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_SHORT, &p.shield, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_SHORT, &p.head_top, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p.head_mid, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p.head_bottom, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p.rename, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_UINT32, &p.delete_date, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p.robe, 0, NULL, NULL) + ) { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); + return 0; + } + for (i = 0; i < MAX_CHARS && SQL_SUCCESS == SqlStmt_NextRow(stmt); i++) { + p.last_point.map = mapindex_name2id(last_map); + sd->found_char[i] = p.char_id; + j += mmo_char_tobuf(WBUFP(buf, j), &p); + } + for (; i < MAX_CHARS; i++) + sd->found_char[i] = -1; + + memset(sd->new_name,0,sizeof(sd->new_name)); + + SqlStmt_Free(stmt); + return j; } //===================================================================================================== -int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything) +int mmo_char_fromsql(int char_id, struct mmo_charstatus *p, bool load_everything) { - int i,j; - char t_msg[128] = ""; - struct mmo_charstatus* cp; - StringBuf buf; - SqlStmt* stmt; - char last_map[MAP_NAME_LENGTH_EXT]; - char save_map[MAP_NAME_LENGTH_EXT]; - char point_map[MAP_NAME_LENGTH_EXT]; - struct point tmp_point; - struct item tmp_item; - struct s_skill tmp_skill; - struct s_friend tmp_friend; + int i,j; + char t_msg[128] = ""; + struct mmo_charstatus *cp; + StringBuf buf; + SqlStmt *stmt; + char last_map[MAP_NAME_LENGTH_EXT]; + char save_map[MAP_NAME_LENGTH_EXT]; + char point_map[MAP_NAME_LENGTH_EXT]; + struct point tmp_point; + struct item tmp_item; + struct s_skill tmp_skill; + struct s_friend tmp_friend; #ifdef HOTKEY_SAVING - struct hotkey tmp_hotkey; - int hotkey_num; + struct hotkey tmp_hotkey; + int hotkey_num; #endif - memset(p, 0, sizeof(struct mmo_charstatus)); - - if (save_log) ShowInfo("Char load request (%d)\n", char_id); - - stmt = SqlStmt_Malloc(sql_handle); - if( stmt == NULL ) - { - SqlStmt_ShowDebug(stmt); - return 0; - } - - // read char data - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT " - "`char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`," - "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," - "`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`," - "`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`," - "`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`" - " FROM `%s` WHERE `char_id`=? LIMIT 1", char_db) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p->char_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &p->account_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UCHAR, &p->slot, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_STRING, &p->name, sizeof(p->name), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_SHORT, &p->class_, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_UINT, &p->base_level, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_UINT, &p->job_level, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &p->base_exp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_UINT, &p->job_exp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_INT, &p->zeny, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 10, SQLDT_SHORT, &p->str, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 11, SQLDT_SHORT, &p->agi, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 12, SQLDT_SHORT, &p->vit, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 13, SQLDT_SHORT, &p->int_, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 14, SQLDT_SHORT, &p->dex, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 15, SQLDT_SHORT, &p->luk, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 16, SQLDT_INT, &p->max_hp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 17, SQLDT_INT, &p->hp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 18, SQLDT_INT, &p->max_sp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 19, SQLDT_INT, &p->sp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 20, SQLDT_UINT, &p->status_point, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 21, SQLDT_UINT, &p->skill_point, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 22, SQLDT_UINT, &p->option, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 23, SQLDT_UCHAR, &p->karma, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 24, SQLDT_SHORT, &p->manner, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 25, SQLDT_INT, &p->party_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_INT, &p->guild_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_INT, &p->pet_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_INT, &p->hom_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_INT, &p->ele_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p->hair, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p->hair_color, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_SHORT, &p->clothes_color, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p->weapon, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_SHORT, &p->shield, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p->head_top, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 36, SQLDT_SHORT, &p->head_mid, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 37, SQLDT_SHORT, &p->head_bottom, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 38, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 39, SQLDT_SHORT, &p->last_point.x, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 40, SQLDT_SHORT, &p->last_point.y, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 41, SQLDT_STRING, &save_map, sizeof(save_map), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 42, SQLDT_SHORT, &p->save_point.x, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 43, SQLDT_SHORT, &p->save_point.y, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 44, SQLDT_INT, &p->partner_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 45, SQLDT_INT, &p->father, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 46, SQLDT_INT, &p->mother, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 47, SQLDT_INT, &p->child, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 48, SQLDT_INT, &p->fame, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 49, SQLDT_SHORT, &p->rename, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 50, SQLDT_UINT32, &p->delete_date, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 51, SQLDT_SHORT, &p->robe, 0, NULL, NULL) - ) - { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - return 0; - } - if( SQL_ERROR == SqlStmt_NextRow(stmt) ) - { - ShowError("Requested non-existant character id: %d!\n", char_id); - SqlStmt_Free(stmt); - return 0; - } - p->last_point.map = mapindex_name2id(last_map); - p->save_point.map = mapindex_name2id(save_map); - - strcat(t_msg, " status"); - - if (!load_everything) // For quick selection of data when displaying the char menu - { - SqlStmt_Free(stmt); - return 1; - } - - //read memo data - //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`) - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `map`,`x`,`y` FROM `%s` WHERE `char_id`=? ORDER by `memo_id` LIMIT %d", memo_db, MAX_MEMOPOINTS) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &point_map, sizeof(point_map), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_point.x, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_point.y, 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - - for( i = 0; i < MAX_MEMOPOINTS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) - { - tmp_point.map = mapindex_name2id(point_map); - memcpy(&p->memo_point[i], &tmp_point, sizeof(tmp_point)); - } - strcat(t_msg, " memo"); - - //read inventory - //`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`) - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`"); - for( i = 0; i < MAX_SLOTS; ++i ) - StringBuf_Printf(&buf, ", `card%d`", i); - StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", inventory_db, MAX_INVENTORY); - - if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR, &tmp_item.favorite, 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - for( i = 0; i < MAX_SLOTS; ++i ) - if( SQL_ERROR == SqlStmt_BindColumn(stmt, 9+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - - for( i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) - memcpy(&p->inventory[i], &tmp_item, sizeof(tmp_item)); - - strcat(t_msg, " inventory"); - - //read cart - //`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`) - StringBuf_Clear(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", cart_db, MAX_CART); - - if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - for( i = 0; i < MAX_SLOTS; ++i ) - if( SQL_ERROR == SqlStmt_BindColumn(stmt, 8+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - - for( i = 0; i < MAX_CART && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) - memcpy(&p->cart[i], &tmp_item, sizeof(tmp_item)); - strcat(t_msg, " cart"); - - //read storage - storage_fromsql(p->account_id, &p->storage); - strcat(t_msg, " storage"); - - //read skill - //`skill` (`char_id`, `id`, `lv`) - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `id`, `lv` FROM `%s` WHERE `char_id`=? LIMIT %d", skill_db, MAX_SKILL) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_USHORT, &tmp_skill.id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_USHORT, &tmp_skill.lv, 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - tmp_skill.flag = SKILL_FLAG_PERMANENT; - - for( i = 0; i < MAX_SKILL && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) - { - if( tmp_skill.id < ARRAYLENGTH(p->skill) ) - memcpy(&p->skill[tmp_skill.id], &tmp_skill, sizeof(tmp_skill)); - else - ShowWarning("mmo_char_fromsql: ignoring invalid skill (id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", tmp_skill.id, tmp_skill.lv, p->name, p->account_id, p->char_id); - } - strcat(t_msg, " skills"); - - //read friends - //`friends` (`char_id`, `friend_account`, `friend_id`) - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT c.`account_id`, c.`char_id`, c.`name` FROM `%s` c LEFT JOIN `%s` f ON f.`friend_account` = c.`account_id` AND f.`friend_id` = c.`char_id` WHERE f.`char_id`=? LIMIT %d", char_db, friend_db, MAX_FRIENDS) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_friend.account_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_friend.char_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &tmp_friend.name, sizeof(tmp_friend.name), NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - - for( i = 0; i < MAX_FRIENDS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) - memcpy(&p->friends[i], &tmp_friend, sizeof(tmp_friend)); - strcat(t_msg, " friends"); + memset(p, 0, sizeof(struct mmo_charstatus)); + + if (save_log) ShowInfo("Char load request (%d)\n", char_id); + + stmt = SqlStmt_Malloc(sql_handle); + if (stmt == NULL) { + SqlStmt_ShowDebug(stmt); + return 0; + } + + // read char data + if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT " + "`char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`," + "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," + "`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`," + "`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`," + "`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`" + " FROM `%s` WHERE `char_id`=? LIMIT 1", char_db) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p->char_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &p->account_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UCHAR, &p->slot, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_STRING, &p->name, sizeof(p->name), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_SHORT, &p->class_, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_UINT, &p->base_level, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_UINT, &p->job_level, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &p->base_exp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_UINT, &p->job_exp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_INT, &p->zeny, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 10, SQLDT_SHORT, &p->str, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 11, SQLDT_SHORT, &p->agi, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 12, SQLDT_SHORT, &p->vit, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 13, SQLDT_SHORT, &p->int_, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 14, SQLDT_SHORT, &p->dex, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 15, SQLDT_SHORT, &p->luk, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 16, SQLDT_INT, &p->max_hp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 17, SQLDT_INT, &p->hp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 18, SQLDT_INT, &p->max_sp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 19, SQLDT_INT, &p->sp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 20, SQLDT_UINT, &p->status_point, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 21, SQLDT_UINT, &p->skill_point, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 22, SQLDT_UINT, &p->option, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 23, SQLDT_UCHAR, &p->karma, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 24, SQLDT_SHORT, &p->manner, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 25, SQLDT_INT, &p->party_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_INT, &p->guild_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_INT, &p->pet_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_INT, &p->hom_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_INT, &p->ele_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p->hair, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p->hair_color, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_SHORT, &p->clothes_color, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p->weapon, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_SHORT, &p->shield, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p->head_top, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 36, SQLDT_SHORT, &p->head_mid, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 37, SQLDT_SHORT, &p->head_bottom, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 38, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 39, SQLDT_SHORT, &p->last_point.x, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 40, SQLDT_SHORT, &p->last_point.y, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 41, SQLDT_STRING, &save_map, sizeof(save_map), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 42, SQLDT_SHORT, &p->save_point.x, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 43, SQLDT_SHORT, &p->save_point.y, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 44, SQLDT_INT, &p->partner_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 45, SQLDT_INT, &p->father, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 46, SQLDT_INT, &p->mother, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 47, SQLDT_INT, &p->child, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 48, SQLDT_INT, &p->fame, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 49, SQLDT_SHORT, &p->rename, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 50, SQLDT_UINT32, &p->delete_date, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 51, SQLDT_SHORT, &p->robe, 0, NULL, NULL) + ) { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); + return 0; + } + if (SQL_ERROR == SqlStmt_NextRow(stmt)) { + ShowError("Requested non-existant character id: %d!\n", char_id); + SqlStmt_Free(stmt); + return 0; + } + p->last_point.map = mapindex_name2id(last_map); + p->save_point.map = mapindex_name2id(save_map); + + strcat(t_msg, " status"); + + if (!load_everything) { // For quick selection of data when displaying the char menu + SqlStmt_Free(stmt); + return 1; + } + + //read memo data + //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`) + if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `map`,`x`,`y` FROM `%s` WHERE `char_id`=? ORDER by `memo_id` LIMIT %d", memo_db, MAX_MEMOPOINTS) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &point_map, sizeof(point_map), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_point.x, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_point.y, 0, NULL, NULL)) + SqlStmt_ShowDebug(stmt); + + for (i = 0; i < MAX_MEMOPOINTS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) { + tmp_point.map = mapindex_name2id(point_map); + memcpy(&p->memo_point[i], &tmp_point, sizeof(tmp_point)); + } + strcat(t_msg, " memo"); + + //read inventory + //`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`) + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`"); + for (i = 0; i < MAX_SLOTS; ++i) + StringBuf_Printf(&buf, ", `card%d`", i); + StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", inventory_db, MAX_INVENTORY); + + if (SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR, &tmp_item.favorite, 0, NULL, NULL)) + SqlStmt_ShowDebug(stmt); + for (i = 0; i < MAX_SLOTS; ++i) + if (SQL_ERROR == SqlStmt_BindColumn(stmt, 9+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL)) + SqlStmt_ShowDebug(stmt); + + for (i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) + memcpy(&p->inventory[i], &tmp_item, sizeof(tmp_item)); + + strcat(t_msg, " inventory"); + + //read cart + //`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`) + StringBuf_Clear(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", cart_db, MAX_CART); + + if (SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL)) + SqlStmt_ShowDebug(stmt); + for (i = 0; i < MAX_SLOTS; ++i) + if (SQL_ERROR == SqlStmt_BindColumn(stmt, 8+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL)) + SqlStmt_ShowDebug(stmt); + + for (i = 0; i < MAX_CART && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) + memcpy(&p->cart[i], &tmp_item, sizeof(tmp_item)); + strcat(t_msg, " cart"); + + //read storage + storage_fromsql(p->account_id, &p->storage); + strcat(t_msg, " storage"); + + //read skill + //`skill` (`char_id`, `id`, `lv`) + if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `id`, `lv` FROM `%s` WHERE `char_id`=? LIMIT %d", skill_db, MAX_SKILL) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_USHORT, &tmp_skill.id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_USHORT, &tmp_skill.lv, 0, NULL, NULL)) + SqlStmt_ShowDebug(stmt); + tmp_skill.flag = SKILL_FLAG_PERMANENT; + + for (i = 0; i < MAX_SKILL && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) { + if (tmp_skill.id < ARRAYLENGTH(p->skill)) + memcpy(&p->skill[tmp_skill.id], &tmp_skill, sizeof(tmp_skill)); + else + ShowWarning("mmo_char_fromsql: ignoring invalid skill (id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", tmp_skill.id, tmp_skill.lv, p->name, p->account_id, p->char_id); + } + strcat(t_msg, " skills"); + + //read friends + //`friends` (`char_id`, `friend_account`, `friend_id`) + if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT c.`account_id`, c.`char_id`, c.`name` FROM `%s` c LEFT JOIN `%s` f ON f.`friend_account` = c.`account_id` AND f.`friend_id` = c.`char_id` WHERE f.`char_id`=? LIMIT %d", char_db, friend_db, MAX_FRIENDS) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_friend.account_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_friend.char_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &tmp_friend.name, sizeof(tmp_friend.name), NULL, NULL)) + SqlStmt_ShowDebug(stmt); + + for (i = 0; i < MAX_FRIENDS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) + memcpy(&p->friends[i], &tmp_friend, sizeof(tmp_friend)); + strcat(t_msg, " friends"); #ifdef HOTKEY_SAVING - //read hotkeys - //`hotkey` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl` - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `hotkey`, `type`, `itemskill_id`, `skill_lvl` FROM `%s` WHERE `char_id`=?", hotkey_db) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &hotkey_num, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR, &tmp_hotkey.type, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT, &tmp_hotkey.id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_hotkey.lv, 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - - while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) - { - if( hotkey_num >= 0 && hotkey_num < MAX_HOTKEYS ) - memcpy(&p->hotkeys[hotkey_num], &tmp_hotkey, sizeof(tmp_hotkey)); - else - ShowWarning("mmo_char_fromsql: ignoring invalid hotkey (hotkey=%d,type=%u,id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", hotkey_num, tmp_hotkey.type, tmp_hotkey.id, tmp_hotkey.lv, p->name, p->account_id, p->char_id); - } - strcat(t_msg, " hotkeys"); + //read hotkeys + //`hotkey` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl` + if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `hotkey`, `type`, `itemskill_id`, `skill_lvl` FROM `%s` WHERE `char_id`=?", hotkey_db) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &hotkey_num, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR, &tmp_hotkey.type, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT, &tmp_hotkey.id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_hotkey.lv, 0, NULL, NULL)) + SqlStmt_ShowDebug(stmt); + + while (SQL_SUCCESS == SqlStmt_NextRow(stmt)) { + if (hotkey_num >= 0 && hotkey_num < MAX_HOTKEYS) + memcpy(&p->hotkeys[hotkey_num], &tmp_hotkey, sizeof(tmp_hotkey)); + else + ShowWarning("mmo_char_fromsql: ignoring invalid hotkey (hotkey=%d,type=%u,id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", hotkey_num, tmp_hotkey.type, tmp_hotkey.id, tmp_hotkey.lv, p->name, p->account_id, p->char_id); + } + strcat(t_msg, " hotkeys"); #endif - /* Mercenary Owner DataBase */ - mercenary_owner_fromsql(char_id, p); - strcat(t_msg, " mercenary"); + /* Mercenary Owner DataBase */ + mercenary_owner_fromsql(char_id, p); + strcat(t_msg, " mercenary"); - if (save_log) ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfuly! - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); + if (save_log) ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfuly! + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); - cp = idb_ensure(char_db_, char_id, create_charstatus); - memcpy(cp, p, sizeof(struct mmo_charstatus)); - return 1; + cp = idb_ensure(char_db_, char_id, create_charstatus); + memcpy(cp, p, sizeof(struct mmo_charstatus)); + return 1; } //========================================================================================================== int mmo_char_sql_init(void) { - char_db_= idb_alloc(DB_OPT_RELEASE_DATA); + char_db_= idb_alloc(DB_OPT_RELEASE_DATA); - ShowStatus("Characters per Account: '%d'.\n", char_per_account); + ShowStatus("Characters per Account: '%d'.\n", char_per_account); - //the 'set offline' part is now in check_login_conn ... - //if the server connects to loginserver - //it will dc all off players - //and send the loginserver the new state.... + //the 'set offline' part is now in check_login_conn ... + //if the server connects to loginserver + //it will dc all off players + //and send the loginserver the new state.... - // Force all users offline in sql when starting char-server - // (useful when servers crashs and don't clean the database) - set_all_offline_sql(); + // Force all users offline in sql when starting char-server + // (useful when servers crashs and don't clean the database) + set_all_offline_sql(); - return 0; + return 0; } //----------------------------------- @@ -1357,199 +1320,195 @@ int mmo_char_sql_init(void) //----------------------------------- int rename_char_sql(struct char_session_data *sd, int char_id) { - struct mmo_charstatus char_dat; - char esc_name[NAME_LENGTH*2+1]; - - if( sd->new_name[0] == 0 ) // Not ready for rename - return 2; - - if( !mmo_char_fromsql(char_id, &char_dat, false) ) // Only the short data is needed. - return 2; - - if( char_dat.rename == 0 ) - return 1; - - Sql_EscapeStringLen(sql_handle, esc_name, sd->new_name, strnlen(sd->new_name, NAME_LENGTH)); - - // check if the char exist - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` LIKE '%s' LIMIT 1", char_db, esc_name) ) - { - Sql_ShowDebug(sql_handle); - return 4; - } - - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name` = '%s', `rename` = '%d' WHERE `char_id` = '%d'", char_db, esc_name, --char_dat.rename, char_id) ) - { - Sql_ShowDebug(sql_handle); - return 3; - } - - // Change character's name into guild_db. - if( char_dat.guild_id ) - inter_guild_charname_changed(char_dat.guild_id, sd->account_id, char_id, sd->new_name); - - safestrncpy(char_dat.name, sd->new_name, NAME_LENGTH); - memset(sd->new_name,0,sizeof(sd->new_name)); - - // log change - if( log_char ) - { - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" - "VALUES (NOW(), '%s', '%d', '%d', '%s', '0', '0', '0', '0', '0', '0', '0', '0')", - charlog_db, "change char name", sd->account_id, char_dat.slot, esc_name) ) - Sql_ShowDebug(sql_handle); - } - - return 0; + struct mmo_charstatus char_dat; + char esc_name[NAME_LENGTH*2+1]; + + if (sd->new_name[0] == 0) // Not ready for rename + return 2; + + if (!mmo_char_fromsql(char_id, &char_dat, false)) // Only the short data is needed. + return 2; + + if (char_dat.rename == 0) + return 1; + + Sql_EscapeStringLen(sql_handle, esc_name, sd->new_name, strnlen(sd->new_name, NAME_LENGTH)); + + // check if the char exist + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` LIKE '%s' LIMIT 1", char_db, esc_name)) { + Sql_ShowDebug(sql_handle); + return 4; + } + + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name` = '%s', `rename` = '%d' WHERE `char_id` = '%d'", char_db, esc_name, --char_dat.rename, char_id)) { + Sql_ShowDebug(sql_handle); + return 3; + } + + // Change character's name into guild_db. + if (char_dat.guild_id) + inter_guild_charname_changed(char_dat.guild_id, sd->account_id, char_id, sd->new_name); + + safestrncpy(char_dat.name, sd->new_name, NAME_LENGTH); + memset(sd->new_name,0,sizeof(sd->new_name)); + + // log change + if (log_char) { + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" + "VALUES (NOW(), '%s', '%d', '%d', '%s', '0', '0', '0', '0', '0', '0', '0', '0')", + charlog_db, "change char name", sd->account_id, char_dat.slot, esc_name)) + Sql_ShowDebug(sql_handle); + } + + return 0; } -int check_char_name(char * name, char * esc_name) +int check_char_name(char *name, char *esc_name) { - int i; - - // check length of character name - if( name[0] == '\0' ) - return -2; // empty character name - /** - * The client does not allow you to create names with less than 4 characters, however, - * the use of WPE can bypass this, and this fixes the exploit. - **/ - if( strlen( name ) < 4 ) - return -2; - // check content of character name - if( remove_control_chars(name) ) - return -2; // control chars in name - - // check for reserved names - if( strcmpi(name, main_chat_nick) == 0 || strcmpi(name, wisp_server_name) == 0 ) - return -1; // nick reserved for internal server messages - - // Check Authorised letters/symbols in the name of the character - if( char_name_option == 1 ) - { // only letters/symbols in char_name_letters are authorised - for( i = 0; i < NAME_LENGTH && name[i]; i++ ) - if( strchr(char_name_letters, name[i]) == NULL ) - return -2; - } - else if( char_name_option == 2 ) - { // letters/symbols in char_name_letters are forbidden - for( i = 0; i < NAME_LENGTH && name[i]; i++ ) - if( strchr(char_name_letters, name[i]) != NULL ) - return -2; - } - if( name_ignoring_case ) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE BINARY `name` = '%s' LIMIT 1", char_db, esc_name) ) { - Sql_ShowDebug(sql_handle); - return -2; - } - } else { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` = '%s' LIMIT 1", char_db, esc_name) ) { - Sql_ShowDebug(sql_handle); - return -2; - } - } - if( Sql_NumRows(sql_handle) > 0 ) - return -1; // name already exists - - return 0; + int i; + + // check length of character name + if (name[0] == '\0') + return -2; // empty character name + /** + * The client does not allow you to create names with less than 4 characters, however, + * the use of WPE can bypass this, and this fixes the exploit. + **/ + if (strlen(name) < 4) + return -2; + // check content of character name + if (remove_control_chars(name)) + return -2; // control chars in name + + // check for reserved names + if (strcmpi(name, main_chat_nick) == 0 || strcmpi(name, wisp_server_name) == 0) + return -1; // nick reserved for internal server messages + + // Check Authorised letters/symbols in the name of the character + if (char_name_option == 1) { + // only letters/symbols in char_name_letters are authorised + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) == NULL) + return -2; + } else if (char_name_option == 2) { + // letters/symbols in char_name_letters are forbidden + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) != NULL) + return -2; + } + if (name_ignoring_case) { + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE BINARY `name` = '%s' LIMIT 1", char_db, esc_name)) { + Sql_ShowDebug(sql_handle); + return -2; + } + } else { + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` = '%s' LIMIT 1", char_db, esc_name)) { + Sql_ShowDebug(sql_handle); + return -2; + } + } + if (Sql_NumRows(sql_handle) > 0) + return -1; // name already exists + + return 0; } //----------------------------------- // Function to create a new character //----------------------------------- #if PACKETVER >= 20120307 -int make_new_char_sql(struct char_session_data* sd, char* name_, int slot, int hair_color, int hair_style) { - int str = 1, agi = 1, vit = 1, int_ = 1, dex = 1, luk = 1; +int make_new_char_sql(struct char_session_data *sd, char *name_, int slot, int hair_color, int hair_style) +{ + int str = 1, agi = 1, vit = 1, int_ = 1, dex = 1, luk = 1; #else -int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style) { +int make_new_char_sql(struct char_session_data *sd, char *name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style) +{ #endif - char name[NAME_LENGTH]; - char esc_name[NAME_LENGTH*2+1]; - int char_id, flag; + char name[NAME_LENGTH]; + char esc_name[NAME_LENGTH*2+1]; + int char_id, flag; - safestrncpy(name, name_, NAME_LENGTH); - normalize_name(name,TRIM_CHARS); - Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + safestrncpy(name, name_, NAME_LENGTH); + normalize_name(name,TRIM_CHARS); + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - flag = check_char_name(name,esc_name); - if( flag < 0 ) - return flag; + flag = check_char_name(name,esc_name); + if (flag < 0) + return flag; - //check other inputs + //check other inputs #if PACKETVER >= 20120307 - if(slot >= MAX_CHARS) + if (slot >= MAX_CHARS) #else - if((slot >= MAX_CHARS) // slots - || (str + agi + vit + int_ + dex + luk != 6*5 ) // stats - || (str < 1 || str > 9 || agi < 1 || agi > 9 || vit < 1 || vit > 9 || int_ < 1 || int_ > 9 || dex < 1 || dex > 9 || luk < 1 || luk > 9) // individual stat values - || (str + int_ != 10 || agi + luk != 10 || vit + dex != 10) ) // pairs + if ((slot >= MAX_CHARS) // slots + || (str + agi + vit + int_ + dex + luk != 6*5) // stats + || (str < 1 || str > 9 || agi < 1 || agi > 9 || vit < 1 || vit > 9 || int_ < 1 || int_ > 9 || dex < 1 || dex > 9 || luk < 1 || luk > 9) // individual stat values + || (str + int_ != 10 || agi + luk != 10 || vit + dex != 10)) // pairs #endif - return -2; // invalid input - - if (hair_style > 17 || hair_color > 8) - return -2; - - // check the number of already existing chars in this account - if( char_per_account != 0 ) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d'", char_db, sd->account_id) ) - Sql_ShowDebug(sql_handle); - if( Sql_NumRows(sql_handle) >= char_per_account ) - return -2; // character account limit exceeded - } - - // check char slot - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d' AND `char_num` = '%d' LIMIT 1", char_db, sd->account_id, slot) ) - Sql_ShowDebug(sql_handle); - if( Sql_NumRows(sql_handle) > 0 ) - return -2; // slot already in use - - // validation success, log result - if (log_char) { - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" - "VALUES (NOW(), '%s', '%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - charlog_db, "make new char", sd->account_id, slot, esc_name, str, agi, vit, int_, dex, luk, hair_style, hair_color) ) - Sql_ShowDebug(sql_handle); - } + return -2; // invalid input + + if (hair_style > 17 || hair_color > 8) + return -2; + + // check the number of already existing chars in this account + if (char_per_account != 0) { + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d'", char_db, sd->account_id)) + Sql_ShowDebug(sql_handle); + if (Sql_NumRows(sql_handle) >= char_per_account) + return -2; // character account limit exceeded + } + + // check char slot + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d' AND `char_num` = '%d' LIMIT 1", char_db, sd->account_id, slot)) + Sql_ShowDebug(sql_handle); + if (Sql_NumRows(sql_handle) > 0) + return -2; // slot already in use + + // validation success, log result + if (log_char) { + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" + "VALUES (NOW(), '%s', '%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", + charlog_db, "make new char", sd->account_id, slot, esc_name, str, agi, vit, int_, dex, luk, hair_style, hair_color)) + Sql_ShowDebug(sql_handle); + } #if PACKETVER >= 20120307 - //Insert the new char entry to the database - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `status_point`,`str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`," - "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES (" - "'%d', '%d', '%s', '%d', '%d','%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')", - char_db, sd->account_id , slot, esc_name, start_zeny, 48, str, agi, vit, int_, dex, luk, - (40 * (100 + vit)/100) , (40 * (100 + vit)/100 ), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color, - mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y) ) - { - Sql_ShowDebug(sql_handle); - return -2; //No, stop the procedure! - } + //Insert the new char entry to the database + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `status_point`,`str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`," + "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES (" + "'%d', '%d', '%s', '%d', '%d','%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')", + char_db, sd->account_id , slot, esc_name, start_zeny, 48, str, agi, vit, int_, dex, luk, + (40 * (100 + vit)/100) , (40 * (100 + vit)/100), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color, + mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y)) { + Sql_ShowDebug(sql_handle); + return -2; //No, stop the procedure! + } #else - //Insert the new char entry to the database - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`," - "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES (" - "'%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')", - char_db, sd->account_id , slot, esc_name, start_zeny, str, agi, vit, int_, dex, luk, - (40 * (100 + vit)/100) , (40 * (100 + vit)/100 ), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color, - mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y) ) - { - Sql_ShowDebug(sql_handle); - return -2; //No, stop the procedure! - } + //Insert the new char entry to the database + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`," + "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES (" + "'%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')", + char_db, sd->account_id , slot, esc_name, start_zeny, str, agi, vit, int_, dex, luk, + (40 * (100 + vit)/100) , (40 * (100 + vit)/100), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color, + mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y)) { + Sql_ShowDebug(sql_handle); + return -2; //No, stop the procedure! + } #endif - //Retrieve the newly auto-generated char id - char_id = (int)Sql_LastInsertId(sql_handle); - //Give the char the default items - if (start_weapon > 0) { //add Start Weapon (Knife?) - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", inventory_db, char_id, start_weapon, 1, 1) ) - Sql_ShowDebug(sql_handle); - } - if (start_armor > 0) { //Add default armor (cotton shirt?) - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", inventory_db, char_id, start_armor, 1, 1) ) - Sql_ShowDebug(sql_handle); - } - - ShowInfo("Created char: account: %d, char: %d, slot: %d, name: %s\n", sd->account_id, char_id, slot, name); - return char_id; + //Retrieve the newly auto-generated char id + char_id = (int)Sql_LastInsertId(sql_handle); + //Give the char the default items + if (start_weapon > 0) { //add Start Weapon (Knife?) + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", inventory_db, char_id, start_weapon, 1, 1)) + Sql_ShowDebug(sql_handle); + } + if (start_armor > 0) { //Add default armor (cotton shirt?) + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", inventory_db, char_id, start_armor, 1, 1)) + Sql_ShowDebug(sql_handle); + } + + ShowInfo("Created char: account: %d, char: %d, slot: %d, name: %s\n", sd->account_id, char_id, slot, name); + return char_id; } /*----------------------------------------------------------------------------------------------------------*/ @@ -1557,19 +1516,19 @@ int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int ag /*----------------------------------------------------------------------------------------------------------*/ int divorce_char_sql(int partner_id1, int partner_id2) { - unsigned char buf[64]; + unsigned char buf[64]; - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `partner_id`='0' WHERE `char_id`='%d' OR `char_id`='%d' LIMIT 2", char_db, partner_id1, partner_id2) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE (`nameid`='%d' OR `nameid`='%d') AND (`char_id`='%d' OR `char_id`='%d') LIMIT 2", inventory_db, WEDDING_RING_M, WEDDING_RING_F, partner_id1, partner_id2) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `partner_id`='0' WHERE `char_id`='%d' OR `char_id`='%d' LIMIT 2", char_db, partner_id1, partner_id2)) + Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE (`nameid`='%d' OR `nameid`='%d') AND (`char_id`='%d' OR `char_id`='%d') LIMIT 2", inventory_db, WEDDING_RING_M, WEDDING_RING_F, partner_id1, partner_id2)) + Sql_ShowDebug(sql_handle); - WBUFW(buf,0) = 0x2b12; - WBUFL(buf,2) = partner_id1; - WBUFL(buf,6) = partner_id2; - mapif_sendall(buf,10); + WBUFW(buf,0) = 0x2b12; + WBUFL(buf,2) = partner_id1; + WBUFL(buf,6) = partner_id2; + mapif_sendall(buf,10); - return 0; + return 0; } /*----------------------------------------------------------------------------------------------------------*/ @@ -1580,151 +1539,159 @@ int divorce_char_sql(int partner_id1, int partner_id2) */ int delete_char_sql(int char_id) { - char name[NAME_LENGTH]; - char esc_name[NAME_LENGTH*2+1]; //Name needs be escaped. - int account_id, party_id, guild_id, hom_id, base_level, partner_id, father_id, mother_id; - char* data; - size_t len; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name`,`account_id`,`party_id`,`guild_id`,`base_level`,`homun_id`,`partner_id`,`father`,`mother` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) ) - Sql_ShowDebug(sql_handle); - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - ShowError("delete_char_sql: Unable to fetch character data, deletion aborted.\n"); - Sql_FreeResult(sql_handle); - return -1; - } - - Sql_GetData(sql_handle, 0, &data, &len); safestrncpy(name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 1, &data, NULL); account_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); party_id = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); guild_id = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); base_level = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); hom_id = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); partner_id = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); father_id = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); mother_id = atoi(data); - - Sql_EscapeStringLen(sql_handle, esc_name, name, min(len, NAME_LENGTH)); - Sql_FreeResult(sql_handle); - - //check for config char del condition [Lupus] - // TODO: Move this out to packet processing (0x68/0x1fb). - if( ( char_del_level > 0 && base_level >= char_del_level ) - || ( char_del_level < 0 && base_level <= -char_del_level ) - ) { - ShowInfo("Char deletion aborted: %s, BaseLevel: %i\n", name, base_level); - return -1; - } - - /* Divorce [Wizputer] */ - if( partner_id ) - divorce_char_sql(char_id, partner_id); - - /* De-addopt [Zephyrus] */ - if( father_id || mother_id ) - { // Char is Baby - unsigned char buf[64]; - - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `child`='0' WHERE `char_id`='%d' OR `char_id`='%d'", char_db, father_id, mother_id) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '410'AND (`char_id`='%d' OR `char_id`='%d')", skill_db, father_id, mother_id) ) - Sql_ShowDebug(sql_handle); - - WBUFW(buf,0) = 0x2b25; - WBUFL(buf,2) = father_id; - WBUFL(buf,6) = mother_id; - WBUFL(buf,10) = char_id; // Baby - mapif_sendall(buf,14); - } - - //Make the character leave the party [Skotlex] - if (party_id) - inter_party_leave(party_id, account_id, char_id); - - /* delete char's pet */ - //Delete the hatched pet if you have one... - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `incuvate` = '0'", pet_db, char_id) ) - Sql_ShowDebug(sql_handle); - - //Delete all pets that are stored in eggs (inventory + cart) - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, inventory_db, inventory_db, char_id) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, cart_db, cart_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* remove homunculus */ - if( hom_id ) - mapif_homunculus_delete(hom_id); - - /* remove mercenary data */ - mercenary_owner_delete(char_id); - - /* delete char's friends list */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", friend_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* delete char from other's friend list */ - //NOTE: Won't this cause problems for people who are already online? [Skotlex] - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `friend_id` = '%d'", friend_db, char_id) ) - Sql_ShowDebug(sql_handle); + char name[NAME_LENGTH]; + char esc_name[NAME_LENGTH*2+1]; //Name needs be escaped. + int account_id, party_id, guild_id, hom_id, base_level, partner_id, father_id, mother_id; + char *data; + size_t len; + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `name`,`account_id`,`party_id`,`guild_id`,`base_level`,`homun_id`,`partner_id`,`father`,`mother` FROM `%s` WHERE `char_id`='%d'", char_db, char_id)) + Sql_ShowDebug(sql_handle); + + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { + ShowError("delete_char_sql: Unable to fetch character data, deletion aborted.\n"); + Sql_FreeResult(sql_handle); + return -1; + } + + Sql_GetData(sql_handle, 0, &data, &len); + safestrncpy(name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 1, &data, NULL); + account_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + party_id = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + guild_id = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + base_level = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + hom_id = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + partner_id = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); + father_id = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); + mother_id = atoi(data); + + Sql_EscapeStringLen(sql_handle, esc_name, name, min(len, NAME_LENGTH)); + Sql_FreeResult(sql_handle); + + //check for config char del condition [Lupus] + // TODO: Move this out to packet processing (0x68/0x1fb). + if ((char_del_level > 0 && base_level >= char_del_level) + || (char_del_level < 0 && base_level <= -char_del_level) + ) { + ShowInfo("Char deletion aborted: %s, BaseLevel: %i\n", name, base_level); + return -1; + } + + /* Divorce [Wizputer] */ + if (partner_id) + divorce_char_sql(char_id, partner_id); + + /* De-addopt [Zephyrus] */ + if (father_id || mother_id) { + // Char is Baby + unsigned char buf[64]; + + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `child`='0' WHERE `char_id`='%d' OR `char_id`='%d'", char_db, father_id, mother_id)) + Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '410'AND (`char_id`='%d' OR `char_id`='%d')", skill_db, father_id, mother_id)) + Sql_ShowDebug(sql_handle); + + WBUFW(buf,0) = 0x2b25; + WBUFL(buf,2) = father_id; + WBUFL(buf,6) = mother_id; + WBUFL(buf,10) = char_id; // Baby + mapif_sendall(buf,14); + } + + //Make the character leave the party [Skotlex] + if (party_id) + inter_party_leave(party_id, account_id, char_id); + + /* delete char's pet */ + //Delete the hatched pet if you have one... + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `incuvate` = '0'", pet_db, char_id)) + Sql_ShowDebug(sql_handle); + + //Delete all pets that are stored in eggs (inventory + cart) + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, inventory_db, inventory_db, char_id)) + Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, cart_db, cart_db, char_id)) + Sql_ShowDebug(sql_handle); + + /* remove homunculus */ + if (hom_id) + mapif_homunculus_delete(hom_id); + + /* remove mercenary data */ + mercenary_owner_delete(char_id); + + /* delete char's friends list */ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", friend_db, char_id)) + Sql_ShowDebug(sql_handle); + + /* delete char from other's friend list */ + //NOTE: Won't this cause problems for people who are already online? [Skotlex] + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `friend_id` = '%d'", friend_db, char_id)) + Sql_ShowDebug(sql_handle); #ifdef HOTKEY_SAVING - /* delete hotkeys */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", hotkey_db, char_id) ) - Sql_ShowDebug(sql_handle); + /* delete hotkeys */ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", hotkey_db, char_id)) + Sql_ShowDebug(sql_handle); #endif - /* delete inventory */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", inventory_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* delete cart inventory */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", cart_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* delete memo areas */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* delete character registry */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* delete skills */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, char_id) ) - Sql_ShowDebug(sql_handle); - + /* delete inventory */ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", inventory_db, char_id)) + Sql_ShowDebug(sql_handle); + + /* delete cart inventory */ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", cart_db, char_id)) + Sql_ShowDebug(sql_handle); + + /* delete memo areas */ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, char_id)) + Sql_ShowDebug(sql_handle); + + /* delete character registry */ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id)) + Sql_ShowDebug(sql_handle); + + /* delete skills */ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, char_id)) + Sql_ShowDebug(sql_handle); + #ifdef ENABLE_SC_SAVING - /* status changes */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, account_id, char_id) ) - Sql_ShowDebug(sql_handle); + /* status changes */ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, account_id, char_id)) + Sql_ShowDebug(sql_handle); #endif - if (log_char) { - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`char_msg`,`name`) VALUES (NOW(), '%d', '%d', 'Deleted char (CID %d)', '%s')", - charlog_db, account_id, 0, char_id, esc_name) ) - Sql_ShowDebug(sql_handle); - } - - /* delete character */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", char_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* No need as we used inter_guild_leave [Skotlex] - // Also delete info from guildtables. - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", guild_member_db, char_id) ) - Sql_ShowDebug(sql_handle); - */ - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `char_id` = '%d'", guild_db, char_id) ) - Sql_ShowDebug(sql_handle); - else if( Sql_NumRows(sql_handle) > 0 ) - mapif_parse_BreakGuild(0,guild_id); - else if( guild_id ) - inter_guild_leave(guild_id, account_id, char_id);// Leave your guild. - return 0; + if (log_char) { + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`char_msg`,`name`) VALUES (NOW(), '%d', '%d', 'Deleted char (CID %d)', '%s')", + charlog_db, account_id, 0, char_id, esc_name)) + Sql_ShowDebug(sql_handle); + } + + /* delete character */ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", char_db, char_id)) + Sql_ShowDebug(sql_handle); + + /* No need as we used inter_guild_leave [Skotlex] + // Also delete info from guildtables. + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", guild_member_db, char_id) ) + Sql_ShowDebug(sql_handle); + */ + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `char_id` = '%d'", guild_db, char_id)) + Sql_ShowDebug(sql_handle); + else if (Sql_NumRows(sql_handle) > 0) + mapif_parse_BreakGuild(0,guild_id); + else if (guild_id) + inter_guild_leave(guild_id, account_id, char_id);// Leave your guild. + return 0; } //--------------------------------------------------------------------- @@ -1732,190 +1699,187 @@ int delete_char_sql(int char_id) //--------------------------------------------------------------------- int count_users(void) { - int i, users; - - users = 0; - for(i = 0; i < ARRAYLENGTH(server); i++) { - if (server[i].fd > 0) { - users += server[i].users; - } - } - return users; + int i, users; + + users = 0; + for (i = 0; i < ARRAYLENGTH(server); i++) { + if (server[i].fd > 0) { + users += server[i].users; + } + } + return users; } // Writes char data to the buffer in the format used by the client. // Used in packets 0x6b (chars info) and 0x6d (new char info) // Returns the size #define MAX_CHAR_BUF 144 //Max size (for WFIFOHEAD calls) -int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p) +int mmo_char_tobuf(uint8 *buffer, struct mmo_charstatus *p) { - unsigned short offset = 0; - uint8* buf; - - if( buffer == NULL || p == NULL ) - return 0; - - buf = WBUFP(buffer,0); - WBUFL(buf,0) = p->char_id; - WBUFL(buf,4) = min(p->base_exp, INT32_MAX); - WBUFL(buf,8) = p->zeny; - WBUFL(buf,12) = min(p->job_exp, INT32_MAX); - WBUFL(buf,16) = p->job_level; - WBUFL(buf,20) = 0; // probably opt1 - WBUFL(buf,24) = 0; // probably opt2 - WBUFL(buf,28) = p->option; - WBUFL(buf,32) = p->karma; - WBUFL(buf,36) = p->manner; - WBUFW(buf,40) = min(p->status_point, INT16_MAX); - WBUFL(buf,42) = p->hp; - WBUFL(buf,46) = p->max_hp; - offset+=4; - buf = WBUFP(buffer,offset); - WBUFW(buf,46) = min(p->sp, INT16_MAX); - WBUFW(buf,48) = min(p->max_sp, INT16_MAX); - WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed; - WBUFW(buf,52) = p->class_; - WBUFW(buf,54) = p->hair; - - //When the weapon is sent and your option is riding, the client crashes on login!? - WBUFW(buf,56) = p->option&(0x20|0x80000|0x100000|0x200000|0x400000|0x800000|0x1000000|0x2000000|0x4000000|0x8000000) ? 0 : p->weapon; - - WBUFW(buf,58) = p->base_level; - WBUFW(buf,60) = min(p->skill_point, INT16_MAX); - WBUFW(buf,62) = p->head_bottom; - WBUFW(buf,64) = p->shield; - WBUFW(buf,66) = p->head_top; - WBUFW(buf,68) = p->head_mid; - WBUFW(buf,70) = p->hair_color; - WBUFW(buf,72) = p->clothes_color; - memcpy(WBUFP(buf,74), p->name, NAME_LENGTH); - WBUFB(buf,98) = min(p->str, UINT8_MAX); - WBUFB(buf,99) = min(p->agi, UINT8_MAX); - WBUFB(buf,100) = min(p->vit, UINT8_MAX); - WBUFB(buf,101) = min(p->int_, UINT8_MAX); - WBUFB(buf,102) = min(p->dex, UINT8_MAX); - WBUFB(buf,103) = min(p->luk, UINT8_MAX); - WBUFW(buf,104) = p->slot; - WBUFW(buf,106) = ( p->rename > 0 ) ? 0 : 1; - offset += 2; + unsigned short offset = 0; + uint8 *buf; + + if (buffer == NULL || p == NULL) + return 0; + + buf = WBUFP(buffer,0); + WBUFL(buf,0) = p->char_id; + WBUFL(buf,4) = min(p->base_exp, INT32_MAX); + WBUFL(buf,8) = p->zeny; + WBUFL(buf,12) = min(p->job_exp, INT32_MAX); + WBUFL(buf,16) = p->job_level; + WBUFL(buf,20) = 0; // probably opt1 + WBUFL(buf,24) = 0; // probably opt2 + WBUFL(buf,28) = p->option; + WBUFL(buf,32) = p->karma; + WBUFL(buf,36) = p->manner; + WBUFW(buf,40) = min(p->status_point, INT16_MAX); + WBUFL(buf,42) = p->hp; + WBUFL(buf,46) = p->max_hp; + offset+=4; + buf = WBUFP(buffer,offset); + WBUFW(buf,46) = min(p->sp, INT16_MAX); + WBUFW(buf,48) = min(p->max_sp, INT16_MAX); + WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed; + WBUFW(buf,52) = p->class_; + WBUFW(buf,54) = p->hair; + + //When the weapon is sent and your option is riding, the client crashes on login!? + WBUFW(buf,56) = p->option&(0x20|0x80000|0x100000|0x200000|0x400000|0x800000|0x1000000|0x2000000|0x4000000|0x8000000) ? 0 : p->weapon; + + WBUFW(buf,58) = p->base_level; + WBUFW(buf,60) = min(p->skill_point, INT16_MAX); + WBUFW(buf,62) = p->head_bottom; + WBUFW(buf,64) = p->shield; + WBUFW(buf,66) = p->head_top; + WBUFW(buf,68) = p->head_mid; + WBUFW(buf,70) = p->hair_color; + WBUFW(buf,72) = p->clothes_color; + memcpy(WBUFP(buf,74), p->name, NAME_LENGTH); + WBUFB(buf,98) = min(p->str, UINT8_MAX); + WBUFB(buf,99) = min(p->agi, UINT8_MAX); + WBUFB(buf,100) = min(p->vit, UINT8_MAX); + WBUFB(buf,101) = min(p->int_, UINT8_MAX); + WBUFB(buf,102) = min(p->dex, UINT8_MAX); + WBUFB(buf,103) = min(p->luk, UINT8_MAX); + WBUFW(buf,104) = p->slot; + WBUFW(buf,106) = (p->rename > 0) ? 0 : 1; + offset += 2; #if (PACKETVER >= 20100720 && PACKETVER <= 20100727) || PACKETVER >= 20100803 - mapindex_getmapname_ext(mapindex_id2name(p->last_point.map), (char*)WBUFP(buf,108)); - offset += MAP_NAME_LENGTH_EXT; + mapindex_getmapname_ext(mapindex_id2name(p->last_point.map), (char *)WBUFP(buf,108)); + offset += MAP_NAME_LENGTH_EXT; #endif #if PACKETVER >= 20100803 - WBUFL(buf,124) = TOL(p->delete_date); - offset += 4; + WBUFL(buf,124) = TOL(p->delete_date); + offset += 4; #endif #if PACKETVER >= 20110111 - WBUFL(buf,128) = p->robe; - offset += 4; + WBUFL(buf,128) = p->robe; + offset += 4; #endif #if PACKETVER != 20111116 //2011-11-16 wants 136, ask gravity. - #if PACKETVER >= 20110928 - WBUFL(buf,132) = 0; // change slot feature (0 = disabled, otherwise enabled) - offset += 4; - #endif - #if PACKETVER >= 20111025 - WBUFL(buf,136) = ( p->rename > 0 ) ? 1 : 0; // (0 = disabled, otherwise displays "Add-Ons" sidebar) - offset += 4; - #endif +#if PACKETVER >= 20110928 + WBUFL(buf,132) = 0; // change slot feature (0 = disabled, otherwise enabled) + offset += 4; +#endif +#if PACKETVER >= 20111025 + WBUFL(buf,136) = (p->rename > 0) ? 1 : 0; // (0 = disabled, otherwise displays "Add-Ons" sidebar) + offset += 4; +#endif #endif - return 106+offset; + return 106+offset; } //---------------------------------------- // Function to send characters to a player //---------------------------------------- -int mmo_char_send006b(int fd, struct char_session_data* sd) +int mmo_char_send006b(int fd, struct char_session_data *sd) { - int j, offset = 0; + int j, offset = 0; #if PACKETVER >= 20100413 - offset += 3; + offset += 3; #endif - if (save_log) - ShowInfo("Loading Char Data ("CL_BOLD"%d"CL_RESET")\n",sd->account_id); + if (save_log) + ShowInfo("Loading Char Data ("CL_BOLD"%d"CL_RESET")\n",sd->account_id); - j = 24 + offset; // offset - WFIFOHEAD(fd,j + MAX_CHARS*MAX_CHAR_BUF); - WFIFOW(fd,0) = 0x6b; + j = 24 + offset; // offset + WFIFOHEAD(fd,j + MAX_CHARS*MAX_CHAR_BUF); + WFIFOW(fd,0) = 0x6b; #if PACKETVER >= 20100413 - WFIFOB(fd,4) = MAX_CHARS; // Max slots. - WFIFOB(fd,5) = MAX_CHARS; // Available slots. - WFIFOB(fd,6) = MAX_CHARS; // Premium slots. + WFIFOB(fd,4) = MAX_CHARS; // Max slots. + WFIFOB(fd,5) = MAX_CHARS; // Available slots. + WFIFOB(fd,6) = MAX_CHARS; // Premium slots. #endif - memset(WFIFOP(fd,4 + offset), 0, 20); // unknown bytes - j+=mmo_chars_fromsql(sd, WFIFOP(fd,j)); - WFIFOW(fd,2) = j; // packet len - WFIFOSET(fd,j); + memset(WFIFOP(fd,4 + offset), 0, 20); // unknown bytes + j+=mmo_chars_fromsql(sd, WFIFOP(fd,j)); + WFIFOW(fd,2) = j; // packet len + WFIFOSET(fd,j); - return 0; + return 0; } int char_married(int pl1, int pl2) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `partner_id` FROM `%s` WHERE `char_id` = '%d'", char_db, pl1) ) - Sql_ShowDebug(sql_handle); - else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); - if( pl2 == atoi(data) ) - { - Sql_FreeResult(sql_handle); - return 1; - } - } - Sql_FreeResult(sql_handle); - return 0; + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `partner_id` FROM `%s` WHERE `char_id` = '%d'", char_db, pl1)) + Sql_ShowDebug(sql_handle); + else if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + char *data; + + Sql_GetData(sql_handle, 0, &data, NULL); + if (pl2 == atoi(data)) { + Sql_FreeResult(sql_handle); + return 1; + } + } + Sql_FreeResult(sql_handle); + return 0; } int char_child(int parent_id, int child_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `child` FROM `%s` WHERE `char_id` = '%d'", char_db, parent_id) ) - Sql_ShowDebug(sql_handle); - else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); - if( child_id == atoi(data) ) - { - Sql_FreeResult(sql_handle); - return 1; - } - } - Sql_FreeResult(sql_handle); - return 0; + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `child` FROM `%s` WHERE `char_id` = '%d'", char_db, parent_id)) + Sql_ShowDebug(sql_handle); + else if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + char *data; + + Sql_GetData(sql_handle, 0, &data, NULL); + if (child_id == atoi(data)) { + Sql_FreeResult(sql_handle); + return 1; + } + } + Sql_FreeResult(sql_handle); + return 0; } int char_family(int cid1, int cid2, int cid3) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`partner_id`,`child` FROM `%s` WHERE `char_id` IN ('%d','%d','%d')", char_db, cid1, cid2, cid3) ) - Sql_ShowDebug(sql_handle); - else while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - int charid; - int partnerid; - int childid; - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); charid = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); partnerid = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); childid = atoi(data); - - if( (cid1 == charid && ((cid2 == partnerid && cid3 == childid ) || (cid2 == childid && cid3 == partnerid))) || - (cid1 == partnerid && ((cid2 == charid && cid3 == childid ) || (cid2 == childid && cid3 == charid ))) || - (cid1 == childid && ((cid2 == charid && cid3 == partnerid) || (cid2 == partnerid && cid3 == charid ))) ) - { - Sql_FreeResult(sql_handle); - return childid; - } - } - Sql_FreeResult(sql_handle); - return 0; + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`partner_id`,`child` FROM `%s` WHERE `char_id` IN ('%d','%d','%d')", char_db, cid1, cid2, cid3)) + Sql_ShowDebug(sql_handle); + else while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + int charid; + int partnerid; + int childid; + char *data; + + Sql_GetData(sql_handle, 0, &data, NULL); + charid = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + partnerid = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + childid = atoi(data); + + if ((cid1 == charid && ((cid2 == partnerid && cid3 == childid) || (cid2 == childid && cid3 == partnerid))) || + (cid1 == partnerid && ((cid2 == charid && cid3 == childid) || (cid2 == childid && cid3 == charid))) || + (cid1 == childid && ((cid2 == charid && cid3 == partnerid) || (cid2 == partnerid && cid3 == charid)))) { + Sql_FreeResult(sql_handle); + return childid; + } + } + Sql_FreeResult(sql_handle); + return 0; } //---------------------------------------------------------------------- @@ -1923,58 +1887,58 @@ int char_family(int cid1, int cid2, int cid3) //---------------------------------------------------------------------- void disconnect_player(int account_id) { - int i; - struct char_session_data* sd; + int i; + struct char_session_data *sd; - // disconnect player if online on char-server - ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == account_id ); - if( i < fd_max ) - set_eof(i); + // disconnect player if online on char-server + ARR_FIND(0, fd_max, i, session[i] && (sd = (struct char_session_data *)session[i]->session_data) && sd->account_id == account_id); + if (i < fd_max) + set_eof(i); } static void char_auth_ok(int fd, struct char_session_data *sd) { - struct online_char_data* character; - - if( (character = (struct online_char_data*)idb_get(online_char_db, sd->account_id)) != NULL ) - { // check if character is not online already. [Skotlex] - if (character->server > -1) - { //Character already online. KICK KICK KICK - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - if (character->waiting_disconnect == INVALID_TIMER) - character->waiting_disconnect = add_timer(gettick()+20000, chardb_waiting_disconnect, character->account_id, 0); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 8; - WFIFOSET(fd,3); - return; - } - if (character->fd >= 0 && character->fd != fd) - { //There's already a connection from this account that hasn't picked a char yet. - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 8; - WFIFOSET(fd,3); - return; - } - character->fd = fd; - } - - if (login_fd > 0) { - // request account data - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x2716; - WFIFOL(login_fd,2) = sd->account_id; - WFIFOSET(login_fd,6); - } - - // mark session as 'authed' - sd->auth = true; - - // set char online on charserver - set_char_charselect(sd->account_id); - - // continues when account data is received... + struct online_char_data *character; + + if ((character = (struct online_char_data *)idb_get(online_char_db, sd->account_id)) != NULL) { + // check if character is not online already. [Skotlex] + if (character->server > -1) { + //Character already online. KICK KICK KICK + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); + if (character->waiting_disconnect == INVALID_TIMER) + character->waiting_disconnect = add_timer(gettick()+20000, chardb_waiting_disconnect, character->account_id, 0); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 8; + WFIFOSET(fd,3); + return; + } + if (character->fd >= 0 && character->fd != fd) { + //There's already a connection from this account that hasn't picked a char yet. + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 8; + WFIFOSET(fd,3); + return; + } + character->fd = fd; + } + + if (login_fd > 0) { + // request account data + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x2716; + WFIFOL(login_fd,2) = sd->account_id; + WFIFOSET(login_fd,6); + } + + // mark session as 'authed' + sd->auth = true; + + // set char online on charserver + set_char_charselect(sd->account_id); + + // continues when account data is received... } int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data); @@ -1984,12 +1948,12 @@ void mapif_server_reset(int id); /// Resets all the data. void loginif_reset(void) { - int id; - // TODO kick everyone out and reset everything or wait for connect and try to reaquire locks [FlavioJS] - for( id = 0; id < ARRAYLENGTH(server); ++id ) - mapif_server_reset(id); - flush_fifos(); - exit(EXIT_FAILURE); + int id; + // TODO kick everyone out and reset everything or wait for connect and try to reaquire locks [FlavioJS] + for (id = 0; id < ARRAYLENGTH(server); ++id) + mapif_server_reset(id); + flush_fifos(); + exit(EXIT_FAILURE); } @@ -1998,366 +1962,361 @@ void loginif_reset(void) /// If all the conditions are met, it stops the core loop. void loginif_check_shutdown(void) { - if( runflag != CHARSERVER_ST_SHUTDOWN ) - return; - runflag = CORE_ST_STOP; + if (runflag != CHARSERVER_ST_SHUTDOWN) + return; + runflag = CORE_ST_STOP; } /// Called when the connection to Login Server is disconnected. void loginif_on_disconnect(void) { - ShowWarning("Connection to Login Server lost.\n\n"); + ShowWarning("Connection to Login Server lost.\n\n"); } /// Called when all the connection steps are completed. void loginif_on_ready(void) { - int i; + int i; - loginif_check_shutdown(); - - //Send online accounts to login server. - send_accounts_tologin(INVALID_TIMER, gettick(), 0, 0); + loginif_check_shutdown(); - // if no map-server already connected, display a message... - ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd > 0 && server[i].map[0] ); - if( i == ARRAYLENGTH(server) ) - ShowStatus("Awaiting maps from map-server.\n"); + //Send online accounts to login server. + send_accounts_tologin(INVALID_TIMER, gettick(), 0, 0); + + // if no map-server already connected, display a message... + ARR_FIND(0, ARRAYLENGTH(server), i, server[i].fd > 0 && server[i].map[0]); + if (i == ARRAYLENGTH(server)) + ShowStatus("Awaiting maps from map-server.\n"); } -int parse_fromlogin(int fd) { - struct char_session_data* sd = NULL; - int i; - - // only process data from the login-server - if( fd != login_fd ) { - ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd); - do_close(fd); - return 0; - } - - if( session[fd]->flag.eof ) { - do_close(fd); - login_fd = -1; - loginif_on_disconnect(); - return 0; - } else if ( session[fd]->flag.ping ) {/* we've reached stall time */ - if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */ - set_eof(fd); - return 0; - } else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */ - WFIFOHEAD(fd,2);// sends a ping packet to login server (will receive pong 0x2718) - WFIFOW(fd,0) = 0x2719; - WFIFOSET(fd,2); - - session[fd]->flag.ping = 2; - } - } - - sd = (struct char_session_data*)session[fd]->session_data; - - while(RFIFOREST(fd) >= 2) { - uint16 command = RFIFOW(fd,0); - - switch( command ) - { - - // acknowledgement of connect-to-loginserver request - case 0x2711: - if (RFIFOREST(fd) < 3) - return 0; - - if (RFIFOB(fd,2)) { - //printf("connect login server error : %d\n", RFIFOB(fd,2)); - ShowError("Can not connect to login-server.\n"); - ShowError("The server communication passwords (default s1/p1) are probably invalid.\n"); - ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n"); - ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n"); - set_eof(fd); - return 0; - } else { - ShowStatus("Connected to login-server (connection #%d).\n", fd); - loginif_on_ready(); - } - RFIFOSKIP(fd,3); - break; - - // acknowledgement of account authentication request - case 0x2713: - if (RFIFOREST(fd) < 25) - return 0; - { - int account_id = RFIFOL(fd,2); - uint32 login_id1 = RFIFOL(fd,6); - uint32 login_id2 = RFIFOL(fd,10); - uint8 sex = RFIFOB(fd,14); - uint8 result = RFIFOB(fd,15); - int request_id = RFIFOL(fd,16); - uint32 version = RFIFOL(fd,20); - uint8 clienttype = RFIFOB(fd,24); - RFIFOSKIP(fd,25); - - if( session_isActive(request_id) && (sd=(struct char_session_data*)session[request_id]->session_data) && - !sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex ) - { - int client_fd = request_id; - sd->version = version; - sd->clienttype = clienttype; - switch( result ) - { - case 0:// ok - char_auth_ok(client_fd, sd); - break; - case 1:// auth failed - WFIFOHEAD(client_fd,3); - WFIFOW(client_fd,0) = 0x6c; - WFIFOB(client_fd,2) = 0;// rejected from server - WFIFOSET(client_fd,3); - break; - } - } - } - break; - - case 0x2717: // account data - if (RFIFOREST(fd) < 62) - return 0; - - // find the authenticated session with this account id - ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->auth && sd->account_id == RFIFOL(fd,2) ); - if( i < fd_max ) - { - int server_id; - memcpy(sd->email, RFIFOP(fd,6), 40); - sd->expiration_time = (time_t)RFIFOL(fd,46); - sd->group_id = RFIFOB(fd,50); - safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,51), sizeof(sd->birthdate)); - ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] ); - // continued from char_auth_ok... - if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359 - ( max_connect_user && count_users() >= max_connect_user && sd->group_id != gm_allow_group ) ) { - // refuse connection (over populated) - WFIFOHEAD(i,3); - WFIFOW(i,0) = 0x6c; - WFIFOW(i,2) = 0; - WFIFOSET(i,3); - } else { - // send characters to player - mmo_char_send006b(i, sd); +int parse_fromlogin(int fd) +{ + struct char_session_data *sd = NULL; + int i; + + // only process data from the login-server + if (fd != login_fd) { + ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd); + do_close(fd); + return 0; + } + + if (session[fd]->flag.eof) { + do_close(fd); + login_fd = -1; + loginif_on_disconnect(); + return 0; + } else if (session[fd]->flag.ping) { /* we've reached stall time */ + if (DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2)) { /* we can't wait any longer */ + set_eof(fd); + return 0; + } else if (session[fd]->flag.ping != 2) { /* we haven't sent ping out yet */ + WFIFOHEAD(fd,2);// sends a ping packet to login server (will receive pong 0x2718) + WFIFOW(fd,0) = 0x2719; + WFIFOSET(fd,2); + + session[fd]->flag.ping = 2; + } + } + + sd = (struct char_session_data *)session[fd]->session_data; + + while (RFIFOREST(fd) >= 2) { + uint16 command = RFIFOW(fd,0); + + switch (command) { + + // acknowledgement of connect-to-loginserver request + case 0x2711: + if (RFIFOREST(fd) < 3) + return 0; + + if (RFIFOB(fd,2)) { + //printf("connect login server error : %d\n", RFIFOB(fd,2)); + ShowError("Can not connect to login-server.\n"); + ShowError("The server communication passwords (default s1/p1) are probably invalid.\n"); + ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n"); + ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n"); + set_eof(fd); + return 0; + } else { + ShowStatus("Connected to login-server (connection #%d).\n", fd); + loginif_on_ready(); + } + RFIFOSKIP(fd,3); + break; + + // acknowledgement of account authentication request + case 0x2713: + if (RFIFOREST(fd) < 25) + return 0; + { + int account_id = RFIFOL(fd,2); + uint32 login_id1 = RFIFOL(fd,6); + uint32 login_id2 = RFIFOL(fd,10); + uint8 sex = RFIFOB(fd,14); + uint8 result = RFIFOB(fd,15); + int request_id = RFIFOL(fd,16); + uint32 version = RFIFOL(fd,20); + uint8 clienttype = RFIFOB(fd,24); + RFIFOSKIP(fd,25); + + if (session_isActive(request_id) && (sd=(struct char_session_data *)session[request_id]->session_data) && + !sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex) { + int client_fd = request_id; + sd->version = version; + sd->clienttype = clienttype; + switch (result) { + case 0:// ok + char_auth_ok(client_fd, sd); + break; + case 1:// auth failed + WFIFOHEAD(client_fd,3); + WFIFOW(client_fd,0) = 0x6c; + WFIFOB(client_fd,2) = 0;// rejected from server + WFIFOSET(client_fd,3); + break; + } + } + } + break; + + case 0x2717: // account data + if (RFIFOREST(fd) < 62) + return 0; + + // find the authenticated session with this account id + ARR_FIND(0, fd_max, i, session[i] && (sd = (struct char_session_data *)session[i]->session_data) && sd->auth && sd->account_id == RFIFOL(fd,2)); + if (i < fd_max) { + int server_id; + memcpy(sd->email, RFIFOP(fd,6), 40); + sd->expiration_time = (time_t)RFIFOL(fd,46); + sd->group_id = RFIFOB(fd,50); + safestrncpy(sd->birthdate, (const char *)RFIFOP(fd,51), sizeof(sd->birthdate)); + ARR_FIND(0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0]); + // continued from char_auth_ok... + if (server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359 + (max_connect_user && count_users() >= max_connect_user && sd->group_id != gm_allow_group)) { + // refuse connection (over populated) + WFIFOHEAD(i,3); + WFIFOW(i,0) = 0x6c; + WFIFOW(i,2) = 0; + WFIFOSET(i,3); + } else { + // send characters to player + mmo_char_send006b(i, sd); #if PACKETVER >= 20110309 - // PIN code system, disabled - WFIFOHEAD(i, 12); - WFIFOW(i, 0) = 0x08B9; - WFIFOW(i, 2) = 0; - WFIFOW(i, 4) = 0; - WFIFOL(i, 6) = sd->account_id; - WFIFOW(i, 10) = 0; - WFIFOSET(i, 12); + // PIN code system, disabled + WFIFOHEAD(i, 12); + WFIFOW(i, 0) = 0x08B9; + WFIFOW(i, 2) = 0; + WFIFOW(i, 4) = 0; + WFIFOL(i, 6) = sd->account_id; + WFIFOW(i, 10) = 0; + WFIFOSET(i, 12); #endif - } - } - RFIFOSKIP(fd,62); - break; - - // login-server alive packet - case 0x2718: - if (RFIFOREST(fd) < 2) - return 0; - RFIFOSKIP(fd,2); - session[fd]->flag.ping = 0; - break; - - // changesex reply - case 0x2723: - if (RFIFOREST(fd) < 7) - return 0; - { - unsigned char buf[7]; - - int acc = RFIFOL(fd,2); - int sex = RFIFOB(fd,6); - RFIFOSKIP(fd,7); - - if( acc > 0 ) - {// TODO: Is this even possible? - int char_id[MAX_CHARS]; - int class_[MAX_CHARS]; - int guild_id[MAX_CHARS]; - int num; - char* data; - - struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc); - if( node != NULL ) - node->sex = sex; - - // get characters - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc) ) - Sql_ShowDebug(sql_handle); - for( i = 0; i < MAX_CHARS && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - Sql_GetData(sql_handle, 0, &data, NULL); char_id[i] = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); class_[i] = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); guild_id[i] = atoi(data); - } - num = i; - for( i = 0; i < num; ++i ) - { - if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER || - class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY || - class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER || - class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER || - class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T || - class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER || - class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO ) - { - // job modification - if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER ) - class_[i] = (sex ? JOB_BARD : JOB_DANCER); - else if( class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY ) - class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY); - else if( class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER ) - class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER); - else if( class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER ) - class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER); - else if( class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T ) - class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T); - else if( class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER ) - class_[i] = (sex ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER); - else if( class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO ) - class_[i] = (sex ? JOB_KAGEROU : JOB_OBORO); - } - - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d', `weapon`='0', `shield`='0', `head_top`='0', `head_mid`='0', `head_bottom`='0' WHERE `char_id`='%d'", char_db, class_[i], char_id[i]) ) - Sql_ShowDebug(sql_handle); - - if( guild_id[i] )// If there is a guild, update the guild_member data [Skotlex] - inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex); - } - Sql_FreeResult(sql_handle); - - // disconnect player if online on char-server - disconnect_player(acc); - } - - // notify all mapservers about this change - WBUFW(buf,0) = 0x2b0d; - WBUFL(buf,2) = acc; - WBUFB(buf,6) = sex; - mapif_sendall(buf, 7); - } - break; - - // reply to an account_reg2 registry request - case 0x2729: - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - - { //Receive account_reg2 registry, forward to map servers. - unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)]; - memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2)); - WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex] - mapif_sendall(buf, WBUFW(buf,2)); - RFIFOSKIP(fd, RFIFOW(fd,2)); - } - break; - - // State change of account/ban notification (from login-server) - case 0x2731: - if (RFIFOREST(fd) < 11) - return 0; - - { // send to all map-servers to disconnect the player - unsigned char buf[11]; - WBUFW(buf,0) = 0x2b14; - WBUFL(buf,2) = RFIFOL(fd,2); - WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban - WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment - mapif_sendall(buf, 11); - } - // disconnect player if online on char-server - disconnect_player(RFIFOL(fd,2)); - - RFIFOSKIP(fd,11); - break; - - // Login server request to kick a character out. [Skotlex] - case 0x2734: - if (RFIFOREST(fd) < 6) - return 0; - { - int aid = RFIFOL(fd,2); - struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, aid); - RFIFOSKIP(fd,6); - if( character != NULL ) - {// account is already marked as online! - if( character->server > -1 ) - { //Kick it from the map server it is on. - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - if (character->waiting_disconnect == INVALID_TIMER) - character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0); - } - else - {// Manual kick from char server. - struct char_session_data *tsd; - int i; - ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid ); - if( i < fd_max ) - { - WFIFOHEAD(i,3); - WFIFOW(i,0) = 0x81; - WFIFOB(i,2) = 2; // "Someone has already logged in with this id" - WFIFOSET(i,3); - set_eof(i); - } - else // still moving to the map-server - set_char_offline(-1, aid); - } - } - idb_remove(auth_db, aid);// reject auth attempts from map-server - } - break; - - // ip address update signal from login server - case 0x2735: - { - unsigned char buf[2]; - uint32 new_ip = 0; - - WBUFW(buf,0) = 0x2b1e; - mapif_sendall(buf, 2); - - new_ip = host2ip(login_ip_str); - if (new_ip && new_ip != login_ip) - login_ip = new_ip; //Update login ip, too. - - new_ip = host2ip(char_ip_str); - if (new_ip && new_ip != char_ip) - { //Update ip. - char_ip = new_ip; - ShowInfo("Updating IP for [%s].\n", char_ip_str); - // notify login server about the change - WFIFOHEAD(fd,6); - WFIFOW(fd,0) = 0x2736; - WFIFOL(fd,2) = htonl(char_ip); - WFIFOSET(fd,6); - } - - RFIFOSKIP(fd,2); - } - break; - - default: - ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command); - set_eof(fd); - return 0; - } - } - - RFIFOFLUSH(fd); - return 0; + } + } + RFIFOSKIP(fd,62); + break; + + // login-server alive packet + case 0x2718: + if (RFIFOREST(fd) < 2) + return 0; + RFIFOSKIP(fd,2); + session[fd]->flag.ping = 0; + break; + + // changesex reply + case 0x2723: + if (RFIFOREST(fd) < 7) + return 0; + { + unsigned char buf[7]; + + int acc = RFIFOL(fd,2); + int sex = RFIFOB(fd,6); + RFIFOSKIP(fd,7); + + if (acc > 0) { + // TODO: Is this even possible? + int char_id[MAX_CHARS]; + int class_[MAX_CHARS]; + int guild_id[MAX_CHARS]; + int num; + char *data; + + struct auth_node *node = (struct auth_node *)idb_get(auth_db, acc); + if (node != NULL) + node->sex = sex; + + // get characters + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc)) + Sql_ShowDebug(sql_handle); + for (i = 0; i < MAX_CHARS && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + Sql_GetData(sql_handle, 0, &data, NULL); + char_id[i] = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + class_[i] = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + guild_id[i] = atoi(data); + } + num = i; + for (i = 0; i < num; ++i) { + if (class_[i] == JOB_BARD || class_[i] == JOB_DANCER || + class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY || + class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER || + class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER || + class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T || + class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER || + class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO) { + // job modification + if (class_[i] == JOB_BARD || class_[i] == JOB_DANCER) + class_[i] = (sex ? JOB_BARD : JOB_DANCER); + else if (class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY) + class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY); + else if (class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER) + class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER); + else if (class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER) + class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER); + else if (class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T) + class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T); + else if (class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER) + class_[i] = (sex ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER); + else if (class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO) + class_[i] = (sex ? JOB_KAGEROU : JOB_OBORO); + } + + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d', `weapon`='0', `shield`='0', `head_top`='0', `head_mid`='0', `head_bottom`='0' WHERE `char_id`='%d'", char_db, class_[i], char_id[i])) + Sql_ShowDebug(sql_handle); + + if (guild_id[i]) // If there is a guild, update the guild_member data [Skotlex] + inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex); + } + Sql_FreeResult(sql_handle); + + // disconnect player if online on char-server + disconnect_player(acc); + } + + // notify all mapservers about this change + WBUFW(buf,0) = 0x2b0d; + WBUFL(buf,2) = acc; + WBUFB(buf,6) = sex; + mapif_sendall(buf, 7); + } + break; + + // reply to an account_reg2 registry request + case 0x2729: + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + + { + //Receive account_reg2 registry, forward to map servers. + unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)]; + memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2)); + WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex] + mapif_sendall(buf, WBUFW(buf,2)); + RFIFOSKIP(fd, RFIFOW(fd,2)); + } + break; + + // State change of account/ban notification (from login-server) + case 0x2731: + if (RFIFOREST(fd) < 11) + return 0; + + { + // send to all map-servers to disconnect the player + unsigned char buf[11]; + WBUFW(buf,0) = 0x2b14; + WBUFL(buf,2) = RFIFOL(fd,2); + WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban + WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment + mapif_sendall(buf, 11); + } + // disconnect player if online on char-server + disconnect_player(RFIFOL(fd,2)); + + RFIFOSKIP(fd,11); + break; + + // Login server request to kick a character out. [Skotlex] + case 0x2734: + if (RFIFOREST(fd) < 6) + return 0; + { + int aid = RFIFOL(fd,2); + struct online_char_data *character = (struct online_char_data *)idb_get(online_char_db, aid); + RFIFOSKIP(fd,6); + if (character != NULL) { + // account is already marked as online! + if (character->server > -1) { + //Kick it from the map server it is on. + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); + if (character->waiting_disconnect == INVALID_TIMER) + character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0); + } else { + // Manual kick from char server. + struct char_session_data *tsd; + int i; + ARR_FIND(0, fd_max, i, session[i] && (tsd = (struct char_session_data *)session[i]->session_data) && tsd->account_id == aid); + if (i < fd_max) { + WFIFOHEAD(i,3); + WFIFOW(i,0) = 0x81; + WFIFOB(i,2) = 2; // "Someone has already logged in with this id" + WFIFOSET(i,3); + set_eof(i); + } else // still moving to the map-server + set_char_offline(-1, aid); + } + } + idb_remove(auth_db, aid);// reject auth attempts from map-server + } + break; + + // ip address update signal from login server + case 0x2735: { + unsigned char buf[2]; + uint32 new_ip = 0; + + WBUFW(buf,0) = 0x2b1e; + mapif_sendall(buf, 2); + + new_ip = host2ip(login_ip_str); + if (new_ip && new_ip != login_ip) + login_ip = new_ip; //Update login ip, too. + + new_ip = host2ip(char_ip_str); + if (new_ip && new_ip != char_ip) { + //Update ip. + char_ip = new_ip; + ShowInfo("Updating IP for [%s].\n", char_ip_str); + // notify login server about the change + WFIFOHEAD(fd,6); + WFIFOW(fd,0) = 0x2736; + WFIFOL(fd,2) = htonl(char_ip); + WFIFOSET(fd,6); + } + + RFIFOSKIP(fd,2); + } + break; + + default: + ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command); + set_eof(fd); + return 0; + } + } + + RFIFOFLUSH(fd); + return 0; } int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data); @@ -2365,176 +2324,169 @@ int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data); void do_init_loginif(void) { - // establish char-login connection if not present - add_timer_func_list(check_connect_login_server, "check_connect_login_server"); - add_timer_interval(gettick() + 1000, check_connect_login_server, 0, 0, 10 * 1000); - - // send a list of all online account IDs to login server - add_timer_func_list(send_accounts_tologin, "send_accounts_tologin"); - add_timer_interval(gettick() + 1000, send_accounts_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour + // establish char-login connection if not present + add_timer_func_list(check_connect_login_server, "check_connect_login_server"); + add_timer_interval(gettick() + 1000, check_connect_login_server, 0, 0, 10 * 1000); + + // send a list of all online account IDs to login server + add_timer_func_list(send_accounts_tologin, "send_accounts_tologin"); + add_timer_interval(gettick() + 1000, send_accounts_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour } void do_final_loginif(void) { - if( login_fd != -1 ) - { - do_close(login_fd); - login_fd = -1; - } + if (login_fd != -1) { + do_close(login_fd); + login_fd = -1; + } } int request_accreg2(int account_id, int char_id) { - if (login_fd > 0) { - WFIFOHEAD(login_fd,10); - WFIFOW(login_fd,0) = 0x272e; - WFIFOL(login_fd,2) = account_id; - WFIFOL(login_fd,6) = char_id; - WFIFOSET(login_fd,10); - return 1; - } - return 0; + if (login_fd > 0) { + WFIFOHEAD(login_fd,10); + WFIFOW(login_fd,0) = 0x272e; + WFIFOL(login_fd,2) = account_id; + WFIFOL(login_fd,6) = char_id; + WFIFOSET(login_fd,10); + return 1; + } + return 0; } //Send packet forward to login-server for account saving -int save_accreg2(unsigned char* buf, int len) +int save_accreg2(unsigned char *buf, int len) { - if (login_fd > 0) { - WFIFOHEAD(login_fd,len+4); - memcpy(WFIFOP(login_fd,4), buf, len); - WFIFOW(login_fd,0) = 0x2728; - WFIFOW(login_fd,2) = len+4; - WFIFOSET(login_fd,len+4); - return 1; - } - return 0; + if (login_fd > 0) { + WFIFOHEAD(login_fd,len+4); + memcpy(WFIFOP(login_fd,4), buf, len); + WFIFOW(login_fd,0) = 0x2728; + WFIFOW(login_fd,2) = len+4; + WFIFOSET(login_fd,len+4); + return 1; + } + return 0; } void char_read_fame_list(void) { - int i; - char* data; - size_t len; - - // Empty ranking lists - memset(smith_fame_list, 0, sizeof(smith_fame_list)); - memset(chemist_fame_list, 0, sizeof(chemist_fame_list)); - memset(taekwon_fame_list, 0, sizeof(taekwon_fame_list)); - // Build Blacksmith ranking list - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_BLACKSMITH, JOB_WHITESMITH, JOB_BABY_BLACKSMITH, JOB_MECHANIC, JOB_MECHANIC_T, JOB_BABY_MECHANIC, fame_list_size_smith) ) - Sql_ShowDebug(sql_handle); - for( i = 0; i < fame_list_size_smith && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - // char_id - Sql_GetData(sql_handle, 0, &data, NULL); - smith_fame_list[i].id = atoi(data); - // fame - Sql_GetData(sql_handle, 1, &data, &len); - smith_fame_list[i].fame = atoi(data); - // name - Sql_GetData(sql_handle, 2, &data, &len); - memcpy(smith_fame_list[i].name, data, min(len, NAME_LENGTH)); - } - // Build Alchemist ranking list - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_ALCHEMIST, JOB_CREATOR, JOB_BABY_ALCHEMIST, JOB_GENETIC, JOB_GENETIC_T, JOB_BABY_GENETIC, fame_list_size_chemist) ) - Sql_ShowDebug(sql_handle); - for( i = 0; i < fame_list_size_chemist && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - // char_id - Sql_GetData(sql_handle, 0, &data, NULL); - chemist_fame_list[i].id = atoi(data); - // fame - Sql_GetData(sql_handle, 1, &data, &len); - chemist_fame_list[i].fame = atoi(data); - // name - Sql_GetData(sql_handle, 2, &data, &len); - memcpy(chemist_fame_list[i].name, data, min(len, NAME_LENGTH)); - } - // Build Taekwon ranking list - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_TAEKWON, fame_list_size_taekwon) ) - Sql_ShowDebug(sql_handle); - for( i = 0; i < fame_list_size_taekwon && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - // char_id - Sql_GetData(sql_handle, 0, &data, NULL); - taekwon_fame_list[i].id = atoi(data); - // fame - Sql_GetData(sql_handle, 1, &data, &len); - taekwon_fame_list[i].fame = atoi(data); - // name - Sql_GetData(sql_handle, 2, &data, &len); - memcpy(taekwon_fame_list[i].name, data, min(len, NAME_LENGTH)); - } - Sql_FreeResult(sql_handle); + int i; + char *data; + size_t len; + + // Empty ranking lists + memset(smith_fame_list, 0, sizeof(smith_fame_list)); + memset(chemist_fame_list, 0, sizeof(chemist_fame_list)); + memset(taekwon_fame_list, 0, sizeof(taekwon_fame_list)); + // Build Blacksmith ranking list + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_BLACKSMITH, JOB_WHITESMITH, JOB_BABY_BLACKSMITH, JOB_MECHANIC, JOB_MECHANIC_T, JOB_BABY_MECHANIC, fame_list_size_smith)) + Sql_ShowDebug(sql_handle); + for (i = 0; i < fame_list_size_smith && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + // char_id + Sql_GetData(sql_handle, 0, &data, NULL); + smith_fame_list[i].id = atoi(data); + // fame + Sql_GetData(sql_handle, 1, &data, &len); + smith_fame_list[i].fame = atoi(data); + // name + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(smith_fame_list[i].name, data, min(len, NAME_LENGTH)); + } + // Build Alchemist ranking list + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_ALCHEMIST, JOB_CREATOR, JOB_BABY_ALCHEMIST, JOB_GENETIC, JOB_GENETIC_T, JOB_BABY_GENETIC, fame_list_size_chemist)) + Sql_ShowDebug(sql_handle); + for (i = 0; i < fame_list_size_chemist && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + // char_id + Sql_GetData(sql_handle, 0, &data, NULL); + chemist_fame_list[i].id = atoi(data); + // fame + Sql_GetData(sql_handle, 1, &data, &len); + chemist_fame_list[i].fame = atoi(data); + // name + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(chemist_fame_list[i].name, data, min(len, NAME_LENGTH)); + } + // Build Taekwon ranking list + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_TAEKWON, fame_list_size_taekwon)) + Sql_ShowDebug(sql_handle); + for (i = 0; i < fame_list_size_taekwon && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + // char_id + Sql_GetData(sql_handle, 0, &data, NULL); + taekwon_fame_list[i].id = atoi(data); + // fame + Sql_GetData(sql_handle, 1, &data, &len); + taekwon_fame_list[i].fame = atoi(data); + // name + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(taekwon_fame_list[i].name, data, min(len, NAME_LENGTH)); + } + Sql_FreeResult(sql_handle); } // Send map-servers the fame ranking lists int char_send_fame_list(int fd) { - int i, len = 8; - unsigned char buf[32000]; - - WBUFW(buf,0) = 0x2b1b; - - for(i = 0; i < fame_list_size_smith && smith_fame_list[i].id; i++) { - memcpy(WBUFP(buf, len), &smith_fame_list[i], sizeof(struct fame_list)); - len += sizeof(struct fame_list); - } - // add blacksmith's block length - WBUFW(buf, 6) = len; - - for(i = 0; i < fame_list_size_chemist && chemist_fame_list[i].id; i++) { - memcpy(WBUFP(buf, len), &chemist_fame_list[i], sizeof(struct fame_list)); - len += sizeof(struct fame_list); - } - // add alchemist's block length - WBUFW(buf, 4) = len; - - for(i = 0; i < fame_list_size_taekwon && taekwon_fame_list[i].id; i++) { - memcpy(WBUFP(buf, len), &taekwon_fame_list[i], sizeof(struct fame_list)); - len += sizeof(struct fame_list); - } - // add total packet length - WBUFW(buf, 2) = len; - - if (fd != -1) - mapif_send(fd, buf, len); - else - mapif_sendall(buf, len); - - return 0; + int i, len = 8; + unsigned char buf[32000]; + + WBUFW(buf,0) = 0x2b1b; + + for (i = 0; i < fame_list_size_smith && smith_fame_list[i].id; i++) { + memcpy(WBUFP(buf, len), &smith_fame_list[i], sizeof(struct fame_list)); + len += sizeof(struct fame_list); + } + // add blacksmith's block length + WBUFW(buf, 6) = len; + + for (i = 0; i < fame_list_size_chemist && chemist_fame_list[i].id; i++) { + memcpy(WBUFP(buf, len), &chemist_fame_list[i], sizeof(struct fame_list)); + len += sizeof(struct fame_list); + } + // add alchemist's block length + WBUFW(buf, 4) = len; + + for (i = 0; i < fame_list_size_taekwon && taekwon_fame_list[i].id; i++) { + memcpy(WBUFP(buf, len), &taekwon_fame_list[i], sizeof(struct fame_list)); + len += sizeof(struct fame_list); + } + // add total packet length + WBUFW(buf, 2) = len; + + if (fd != -1) + mapif_send(fd, buf, len); + else + mapif_sendall(buf, len); + + return 0; } void char_update_fame_list(int type, int index, int fame) { - unsigned char buf[8]; - WBUFW(buf,0) = 0x2b22; - WBUFB(buf,2) = type; - WBUFB(buf,3) = index; - WBUFL(buf,4) = fame; - mapif_sendall(buf, 8); + unsigned char buf[8]; + WBUFW(buf,0) = 0x2b22; + WBUFB(buf,2) = type; + WBUFB(buf,3) = index; + WBUFL(buf,4) = fame; + mapif_sendall(buf, 8); } //Loads a character's name and stores it in the buffer given (must be NAME_LENGTH in size) //Returns 1 on found, 0 on not found (buffer is filled with Unknown char name) -int char_loadName(int char_id, char* name) +int char_loadName(int char_id, char *name) { - char* data; - size_t len; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) ) - Sql_ShowDebug(sql_handle); - else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - Sql_GetData(sql_handle, 0, &data, &len); - safestrncpy(name, data, NAME_LENGTH); - return 1; - } - else - { - safestrncpy(name, unknown_char_name, NAME_LENGTH); - } - return 0; + char *data; + size_t len; + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `char_id`='%d'", char_db, char_id)) + Sql_ShowDebug(sql_handle); + else if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + Sql_GetData(sql_handle, 0, &data, &len); + safestrncpy(name, data, NAME_LENGTH); + return 1; + } else { + safestrncpy(name, unknown_char_name, NAME_LENGTH); + } + return 0; } int search_mapserver(unsigned short map, uint32 ip, uint16 port); @@ -2543,833 +2495,825 @@ int search_mapserver(unsigned short map, uint32 ip, uint16 port); /// Initializes a server structure. void mapif_server_init(int id) { - memset(&server[id], 0, sizeof(server[id])); - server[id].fd = -1; + memset(&server[id], 0, sizeof(server[id])); + server[id].fd = -1; } /// Destroys a server structure. void mapif_server_destroy(int id) { - if( server[id].fd == -1 ) - { - do_close(server[id].fd); - server[id].fd = -1; - } + if (server[id].fd == -1) { + do_close(server[id].fd); + server[id].fd = -1; + } } /// Resets all the data related to a server. void mapif_server_reset(int id) { - int i,j; - unsigned char buf[16384]; - int fd = server[id].fd; - //Notify other map servers that this one is gone. [Skotlex] - WBUFW(buf,0) = 0x2b20; - WBUFL(buf,4) = htonl(server[id].ip); - WBUFW(buf,8) = htons(server[id].port); - j = 0; - for(i = 0; i < MAX_MAP_PER_SERVER; i++) - if (server[id].map[i]) - WBUFW(buf,10+(j++)*4) = server[id].map[i]; - if (j > 0) { - WBUFW(buf,2) = j * 4 + 10; - mapif_sendallwos(fd, buf, WBUFW(buf,2)); - } - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `index`='%d'", ragsrvinfo_db, server[id].fd) ) - Sql_ShowDebug(sql_handle); - online_char_db->foreach(online_char_db,char_db_setoffline,id); //Tag relevant chars as 'in disconnected' server. - mapif_server_destroy(id); - mapif_server_init(id); + int i,j; + unsigned char buf[16384]; + int fd = server[id].fd; + //Notify other map servers that this one is gone. [Skotlex] + WBUFW(buf,0) = 0x2b20; + WBUFL(buf,4) = htonl(server[id].ip); + WBUFW(buf,8) = htons(server[id].port); + j = 0; + for (i = 0; i < MAX_MAP_PER_SERVER; i++) + if (server[id].map[i]) + WBUFW(buf,10+(j++)*4) = server[id].map[i]; + if (j > 0) { + WBUFW(buf,2) = j * 4 + 10; + mapif_sendallwos(fd, buf, WBUFW(buf,2)); + } + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `index`='%d'", ragsrvinfo_db, server[id].fd)) + Sql_ShowDebug(sql_handle); + online_char_db->foreach(online_char_db,char_db_setoffline,id); //Tag relevant chars as 'in disconnected' server. + mapif_server_destroy(id); + mapif_server_init(id); } /// Called when the connection to a Map Server is disconnected. void mapif_on_disconnect(int id) { - ShowStatus("Map-server #%d has disconnected.\n", id); - mapif_server_reset(id); + ShowStatus("Map-server #%d has disconnected.\n", id); + mapif_server_reset(id); } int parse_frommap(int fd) { - int i, j; - int id; - - ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd ); - if( id == ARRAYLENGTH(server) ) - {// not a map server - ShowDebug("parse_frommap: Disconnecting invalid session #%d (is not a map-server)\n", fd); - do_close(fd); - return 0; - } - if( session[fd]->flag.eof ) - { - do_close(fd); - server[id].fd = -1; - mapif_on_disconnect(id); - return 0; - } - - while(RFIFOREST(fd) >= 2) - { - switch(RFIFOW(fd,0)) - { - - case 0x2afa: // Receiving map names list from the map-server - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - - memset(server[id].map, 0, sizeof(server[id].map)); - j = 0; - for(i = 4; i < RFIFOW(fd,2); i += 4) { - server[id].map[j] = RFIFOW(fd,i); - j++; - } - - ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n", - id, j, CONVIP(server[id].ip), server[id].port); - ShowStatus("Map-server %d loading complete.\n", id); - - // send name for wisp to player - WFIFOHEAD(fd, 3 + NAME_LENGTH); - WFIFOW(fd,0) = 0x2afb; - WFIFOB(fd,2) = 0; - memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH); - WFIFOSET(fd,3+NAME_LENGTH); - - char_send_fame_list(fd); //Send fame list. - - { - unsigned char buf[16384]; - int x; - if (j == 0) { - ShowWarning("Map-server %d has NO maps.\n", id); - } else { - // Transmitting maps information to the other map-servers - WBUFW(buf,0) = 0x2b04; - WBUFW(buf,2) = j * 4 + 10; - WBUFL(buf,4) = htonl(server[id].ip); - WBUFW(buf,8) = htons(server[id].port); - memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4); - mapif_sendallwos(fd, buf, WBUFW(buf,2)); - } - // Transmitting the maps of the other map-servers to the new map-server - for(x = 0; x < ARRAYLENGTH(server); x++) { - if (server[x].fd > 0 && x != id) { - WFIFOHEAD(fd,10 +4*ARRAYLENGTH(server[x].map)); - WFIFOW(fd,0) = 0x2b04; - WFIFOL(fd,4) = htonl(server[x].ip); - WFIFOW(fd,8) = htons(server[x].port); - j = 0; - for(i = 0; i < ARRAYLENGTH(server[x].map); i++) - if (server[x].map[i]) - WFIFOW(fd,10+(j++)*4) = server[x].map[i]; - if (j > 0) { - WFIFOW(fd,2) = j * 4 + 10; - WFIFOSET(fd,WFIFOW(fd,2)); - } - } - } - } - RFIFOSKIP(fd,RFIFOW(fd,2)); - break; - - case 0x2afc: //Packet command is now used for sc_data request. [Skotlex] - if (RFIFOREST(fd) < 10) - return 0; - { + int i, j; + int id; + + ARR_FIND(0, ARRAYLENGTH(server), id, server[id].fd == fd); + if (id == ARRAYLENGTH(server)) { + // not a map server + ShowDebug("parse_frommap: Disconnecting invalid session #%d (is not a map-server)\n", fd); + do_close(fd); + return 0; + } + if (session[fd]->flag.eof) { + do_close(fd); + server[id].fd = -1; + mapif_on_disconnect(id); + return 0; + } + + while (RFIFOREST(fd) >= 2) { + switch (RFIFOW(fd,0)) { + + case 0x2afa: // Receiving map names list from the map-server + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + + memset(server[id].map, 0, sizeof(server[id].map)); + j = 0; + for (i = 4; i < RFIFOW(fd,2); i += 4) { + server[id].map[j] = RFIFOW(fd,i); + j++; + } + + ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n", + id, j, CONVIP(server[id].ip), server[id].port); + ShowStatus("Map-server %d loading complete.\n", id); + + // send name for wisp to player + WFIFOHEAD(fd, 3 + NAME_LENGTH); + WFIFOW(fd,0) = 0x2afb; + WFIFOB(fd,2) = 0; + memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH); + WFIFOSET(fd,3+NAME_LENGTH); + + char_send_fame_list(fd); //Send fame list. + + { + unsigned char buf[16384]; + int x; + if (j == 0) { + ShowWarning("Map-server %d has NO maps.\n", id); + } else { + // Transmitting maps information to the other map-servers + WBUFW(buf,0) = 0x2b04; + WBUFW(buf,2) = j * 4 + 10; + WBUFL(buf,4) = htonl(server[id].ip); + WBUFW(buf,8) = htons(server[id].port); + memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4); + mapif_sendallwos(fd, buf, WBUFW(buf,2)); + } + // Transmitting the maps of the other map-servers to the new map-server + for (x = 0; x < ARRAYLENGTH(server); x++) { + if (server[x].fd > 0 && x != id) { + WFIFOHEAD(fd,10 +4*ARRAYLENGTH(server[x].map)); + WFIFOW(fd,0) = 0x2b04; + WFIFOL(fd,4) = htonl(server[x].ip); + WFIFOW(fd,8) = htons(server[x].port); + j = 0; + for (i = 0; i < ARRAYLENGTH(server[x].map); i++) + if (server[x].map[i]) + WFIFOW(fd,10+(j++)*4) = server[x].map[i]; + if (j > 0) { + WFIFOW(fd,2) = j * 4 + 10; + WFIFOSET(fd,WFIFOW(fd,2)); + } + } + } + } + RFIFOSKIP(fd,RFIFOW(fd,2)); + break; + + case 0x2afc: //Packet command is now used for sc_data request. [Skotlex] + if (RFIFOREST(fd) < 10) + return 0; + { #ifdef ENABLE_SC_SAVING - int aid, cid; - aid = RFIFOL(fd,2); - cid = RFIFOL(fd,6); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", - scdata_db, aid, cid) ) - { - Sql_ShowDebug(sql_handle); - break; - } - if( Sql_NumRows(sql_handle) > 0 ) - { - struct status_change_data scdata; - int count; - char* data; - - WFIFOHEAD(fd,14+50*sizeof(struct status_change_data)); - WFIFOW(fd,0) = 0x2b1d; - WFIFOL(fd,4) = aid; - WFIFOL(fd,8) = cid; - for( count = 0; count < 50 && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count ) - { - Sql_GetData(sql_handle, 0, &data, NULL); scdata.type = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); scdata.tick = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); scdata.val1 = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); scdata.val2 = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); scdata.val3 = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); scdata.val4 = atoi(data); - memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data)); - } - if (count >= 50) - ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid); - if (count > 0) - { - WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data); - WFIFOW(fd,12) = count; - WFIFOSET(fd,WFIFOW(fd,2)); - - //Clear the data once loaded. - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid) ) - Sql_ShowDebug(sql_handle); - } - } - Sql_FreeResult(sql_handle); + int aid, cid; + aid = RFIFOL(fd,2); + cid = RFIFOL(fd,6); + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", + scdata_db, aid, cid)) { + Sql_ShowDebug(sql_handle); + break; + } + if (Sql_NumRows(sql_handle) > 0) { + struct status_change_data scdata; + int count; + char *data; + + WFIFOHEAD(fd,14+50*sizeof(struct status_change_data)); + WFIFOW(fd,0) = 0x2b1d; + WFIFOL(fd,4) = aid; + WFIFOL(fd,8) = cid; + for (count = 0; count < 50 && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count) { + Sql_GetData(sql_handle, 0, &data, NULL); + scdata.type = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + scdata.tick = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + scdata.val1 = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + scdata.val2 = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + scdata.val3 = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + scdata.val4 = atoi(data); + memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data)); + } + if (count >= 50) + ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid); + if (count > 0) { + WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data); + WFIFOW(fd,12) = count; + WFIFOSET(fd,WFIFOW(fd,2)); + + //Clear the data once loaded. + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid)) + Sql_ShowDebug(sql_handle); + } + } + Sql_FreeResult(sql_handle); #endif - RFIFOSKIP(fd, 10); - } - break; - - case 0x2afe: //set MAP user count - if (RFIFOREST(fd) < 4) - return 0; - if (RFIFOW(fd,2) != server[id].users) { - server[id].users = RFIFOW(fd,2); - ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id); - } - RFIFOSKIP(fd, 4); - break; - - case 0x2aff: //set MAP users - if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { - //TODO: When data mismatches memory, update guild/party online/offline states. - int aid, cid; - struct online_char_data* character; - - server[id].users = RFIFOW(fd,4); - online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown' - for(i = 0; i < server[id].users; i++) { - aid = RFIFOL(fd,6+i*8); - cid = RFIFOL(fd,6+i*8+4); - character = idb_ensure(online_char_db, aid, create_online_char_data); - if( character->server > -1 && character->server != id ) - { - ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n", - character->account_id, character->char_id, character->server, id, aid, cid); - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - } - character->server = id; - character->char_id = cid; - } - //If any chars remain in -2, they will be cleaned in the cleanup timer. - RFIFOSKIP(fd,RFIFOW(fd,2)); - } - break; - - case 0x2b01: // Receive character data from map-server for saving - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { - int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2); - struct online_char_data* character; - - if (size - 13 != sizeof(struct mmo_charstatus)) - { - ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus)); - RFIFOSKIP(fd,size); - break; - } - //Check account only if this ain't final save. Final-save goes through because of the char-map reconnect - if (RFIFOB(fd,12) || ( - (character = (struct online_char_data*)idb_get(online_char_db, aid)) != NULL && - character->char_id == cid)) - { - struct mmo_charstatus char_dat; - memcpy(&char_dat, RFIFOP(fd,13), sizeof(struct mmo_charstatus)); - mmo_char_tosql(cid, &char_dat); - } else { //This may be valid on char-server reconnection, when re-sending characters that already logged off. - ShowError("parse_from_map (save-char): Received data for non-existant/offline character (%d:%d).\n", aid, cid); - set_char_online(id, cid, aid); - } - - if (RFIFOB(fd,12)) - { //Flag, set character offline after saving. [Skotlex] - set_char_offline(cid, aid); - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save. - WFIFOL(fd,2) = aid; - WFIFOL(fd,6) = cid; - WFIFOSET(fd,10); - } - RFIFOSKIP(fd,size); - } - break; - - case 0x2b02: // req char selection - if( RFIFOREST(fd) < 18 ) - return 0; - { - struct auth_node* node; - - int account_id = RFIFOL(fd,2); - uint32 login_id1 = RFIFOL(fd,6); - uint32 login_id2 = RFIFOL(fd,10); - uint32 ip = RFIFOL(fd,14); - RFIFOSKIP(fd,18); - - if( runflag != CHARSERVER_ST_RUNNING ) - { - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x2b03; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = 0;// not ok - WFIFOSET(fd,7); - } - else - { - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = account_id; - node->char_id = 0; - node->login_id1 = login_id1; - node->login_id2 = login_id2; - //node->sex = 0; - node->ip = ntohl(ip); - //node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server) - //node->gmlevel = 0; - idb_put(auth_db, account_id, node); - - //Set char to "@ char select" in online db [Kevin] - set_char_charselect(account_id); - - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x2b03; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = 1;// ok - WFIFOSET(fd,7); - } - } - break; - - case 0x2b05: // request "change map server" - if (RFIFOREST(fd) < 39) - return 0; - { - int map_id, map_fd = -1; - struct online_char_data* data; - struct mmo_charstatus* char_data; - struct mmo_charstatus char_dat; - - map_id = search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port. - if (map_id >= 0) - map_fd = server[map_id].fd; - //Char should just had been saved before this packet, so this should be safe. [Skotlex] - char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14)); - if (char_data == NULL) { //Really shouldn't happen. - mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true); - char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14)); - } - - if( runflag == CHARSERVER_ST_RUNNING && - session_isActive(map_fd) && - char_data ) - { //Send the map server the auth of this player. - struct auth_node* node; - - //Update the "last map" as this is where the player must be spawned on the new map server. - char_data->last_point.map = RFIFOW(fd,18); - char_data->last_point.x = RFIFOW(fd,20); - char_data->last_point.y = RFIFOW(fd,22); - char_data->sex = RFIFOB(fd,30); - - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = RFIFOL(fd,2); - node->char_id = RFIFOL(fd,14); - node->login_id1 = RFIFOL(fd,6); - node->login_id2 = RFIFOL(fd,10); - node->sex = RFIFOB(fd,30); - node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing) - node->ip = ntohl(RFIFOL(fd,31)); - node->group_id = RFIFOL(fd,35); - node->changing_mapservers = 1; - idb_put(auth_db, RFIFOL(fd,2), node); - - data = idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data); - data->char_id = char_data->char_id; - data->server = map_id; //Update server where char is. - - //Reply with an ack. - WFIFOHEAD(fd,30); - WFIFOW(fd,0) = 0x2b06; - memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); - WFIFOSET(fd,30); - } else { //Reply with nak - WFIFOHEAD(fd,30); - WFIFOW(fd,0) = 0x2b06; - memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); - WFIFOL(fd,6) = 0; //Set login1 to 0. - WFIFOSET(fd,30); - } - RFIFOSKIP(fd,39); - } - break; - - case 0x2b07: // Remove RFIFOL(fd,6) (friend_id) from RFIFOL(fd,2) (char_id) friend list [Ind] - if (RFIFOREST(fd) < 10) - return 0; - { - int char_id, friend_id; - char_id = RFIFOL(fd,2); - friend_id = RFIFOL(fd,6); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `friend_id`='%d' LIMIT 1", - friend_db, char_id, friend_id) ) { - Sql_ShowDebug(sql_handle); - break; - } - RFIFOSKIP(fd,10); - } - break; - - case 0x2b08: // char name request - if (RFIFOREST(fd) < 6) - return 0; - - WFIFOHEAD(fd,30); - WFIFOW(fd,0) = 0x2b09; - WFIFOL(fd,2) = RFIFOL(fd,2); - char_loadName((int)RFIFOL(fd,2), (char*)WFIFOP(fd,6)); - WFIFOSET(fd,30); - - RFIFOSKIP(fd,6); - break; - - case 0x2b0c: // Map server send information to change an email of an account -> login-server - if (RFIFOREST(fd) < 86) - return 0; - if (login_fd > 0) { // don't send request if no login-server - WFIFOHEAD(login_fd,86); - memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0),86); // 0x2722 .L .40B .40B - WFIFOW(login_fd,0) = 0x2722; - WFIFOSET(login_fd,86); - } - RFIFOSKIP(fd, 86); - break; - - case 0x2b0e: // Request from map-server to change an account's status (will just be forwarded to login server) - if (RFIFOREST(fd) < 44) - return 0; - { - int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline - char esc_name[NAME_LENGTH*2+1]; - - int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request) - const char* name = (char*)RFIFOP(fd,6); // name of the target character - int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban - short year = RFIFOW(fd,32); - short month = RFIFOW(fd,34); - short day = RFIFOW(fd,36); - short hour = RFIFOW(fd,38); - short minute = RFIFOW(fd,40); - short second = RFIFOW(fd,42); - RFIFOSKIP(fd,44); - - Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) - Sql_ShowDebug(sql_handle); - else - if( Sql_NumRows(sql_handle) == 0 ) - { - result = 1; // 1-player not found - } - else - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - Sql_ShowDebug(sql_handle); - //FIXME: set proper result value? - else - { - char name[NAME_LENGTH]; - int account_id; - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); - - if( login_fd <= 0 ) - result = 3; // 3-login-server offline - //FIXME: need to move this check to login server [ultramage] -// else -// if( acc != -1 && isGM(acc) < isGM(account_id) ) -// result = 2; // 2-gm level too low - else - switch( type ) { - case 1: // block - WFIFOHEAD(login_fd,10); - WFIFOW(login_fd,0) = 0x2724; - WFIFOL(login_fd,2) = account_id; - WFIFOL(login_fd,6) = 5; // new account status - WFIFOSET(login_fd,10); - break; - case 2: // ban - WFIFOHEAD(login_fd,18); - WFIFOW(login_fd, 0) = 0x2725; - WFIFOL(login_fd, 2) = account_id; - WFIFOW(login_fd, 6) = year; - WFIFOW(login_fd, 8) = month; - WFIFOW(login_fd,10) = day; - WFIFOW(login_fd,12) = hour; - WFIFOW(login_fd,14) = minute; - WFIFOW(login_fd,16) = second; - WFIFOSET(login_fd,18); - break; - case 3: // unblock - WFIFOHEAD(login_fd,10); - WFIFOW(login_fd,0) = 0x2724; - WFIFOL(login_fd,2) = account_id; - WFIFOL(login_fd,6) = 0; // new account status - WFIFOSET(login_fd,10); - break; - case 4: // unban - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272a; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - break; - case 5: // changesex - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x2727; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - break; - } - } - - Sql_FreeResult(sql_handle); - - // send answer if a player ask, not if the server ask - if( acc != -1 && type != 5) { // Don't send answer for changesex - WFIFOHEAD(fd,34); - WFIFOW(fd, 0) = 0x2b0f; - WFIFOL(fd, 2) = acc; - safestrncpy((char*)WFIFOP(fd,6), name, NAME_LENGTH); - WFIFOW(fd,30) = type; - WFIFOW(fd,32) = result; - WFIFOSET(fd,34); - } - } - break; - - case 0x2b10: // Update and send fame ranking list - if (RFIFOREST(fd) < 11) - return 0; - { - int cid = RFIFOL(fd, 2); - int fame = RFIFOL(fd, 6); - char type = RFIFOB(fd, 10); - int size; - struct fame_list* list; - int player_pos; - int fame_pos; - - switch(type) - { - case 1: size = fame_list_size_smith; list = smith_fame_list; break; - case 2: size = fame_list_size_chemist; list = chemist_fame_list; break; - case 3: size = fame_list_size_taekwon; list = taekwon_fame_list; break; - default: size = 0; list = NULL; break; - } - - ARR_FIND(0, size, player_pos, list[player_pos].id == cid);// position of the player - ARR_FIND(0, size, fame_pos, list[fame_pos].fame <= fame);// where the player should be - - if( player_pos == size && fame_pos == size ) - ;// not on list and not enough fame to get on it - else if( fame_pos == player_pos ) - {// same position - list[player_pos].fame = fame; - char_update_fame_list(type, player_pos, fame); - } - else - {// move in the list - if( player_pos == size ) - {// new ranker - not in the list - ARR_MOVE(size - 1, fame_pos, list, struct fame_list); - list[fame_pos].id = cid; - list[fame_pos].fame = fame; - char_loadName(cid, list[fame_pos].name); - } - else - {// already in the list - if( fame_pos == size ) - --fame_pos;// move to the end of the list - ARR_MOVE(player_pos, fame_pos, list, struct fame_list); - list[fame_pos].fame = fame; - } - char_send_fame_list(-1); - } - - RFIFOSKIP(fd,11); - } - break; - - // Divorce chars - case 0x2b11: - if( RFIFOREST(fd) < 10 ) - return 0; - - divorce_char_sql(RFIFOL(fd,2), RFIFOL(fd,6)); - RFIFOSKIP(fd,10); - break; - - case 0x2b16: // Receive rates [Wizputer] - if( RFIFOREST(fd) < 14 ) - return 0; - { - char esc_server_name[sizeof(server_name)*2+1]; - - Sql_EscapeString(sql_handle, esc_server_name, server_name); - - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d'", - ragsrvinfo_db, fd, esc_server_name, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)) ) - Sql_ShowDebug(sql_handle); - RFIFOSKIP(fd,14); - } - break; - - case 0x2b17: // Character disconnected set online 0 [Wizputer] - if (RFIFOREST(fd) < 6) - return 0; - set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6)); - RFIFOSKIP(fd,10); - break; - - case 0x2b18: // Reset all chars to offline [Wizputer] - set_all_offline(id); - RFIFOSKIP(fd,2); - break; - - case 0x2b19: // Character set online [Wizputer] - if (RFIFOREST(fd) < 10) - return 0; - set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6)); - RFIFOSKIP(fd,10); - break; - - case 0x2b1a: // Build and send fame ranking lists [DracoRPG] - if (RFIFOREST(fd) < 2) - return 0; - char_read_fame_list(); - char_send_fame_list(-1); - RFIFOSKIP(fd,2); - break; - - case 0x2b1c: //Request to save status change data. [Skotlex] - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { + RFIFOSKIP(fd, 10); + } + break; + + case 0x2afe: //set MAP user count + if (RFIFOREST(fd) < 4) + return 0; + if (RFIFOW(fd,2) != server[id].users) { + server[id].users = RFIFOW(fd,2); + ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id); + } + RFIFOSKIP(fd, 4); + break; + + case 0x2aff: //set MAP users + if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + { + //TODO: When data mismatches memory, update guild/party online/offline states. + int aid, cid; + struct online_char_data *character; + + server[id].users = RFIFOW(fd,4); + online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown' + for (i = 0; i < server[id].users; i++) { + aid = RFIFOL(fd,6+i*8); + cid = RFIFOL(fd,6+i*8+4); + character = idb_ensure(online_char_db, aid, create_online_char_data); + if (character->server > -1 && character->server != id) { + ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n", + character->account_id, character->char_id, character->server, id, aid, cid); + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); + } + character->server = id; + character->char_id = cid; + } + //If any chars remain in -2, they will be cleaned in the cleanup timer. + RFIFOSKIP(fd,RFIFOW(fd,2)); + } + break; + + case 0x2b01: // Receive character data from map-server for saving + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + { + int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2); + struct online_char_data *character; + + if (size - 13 != sizeof(struct mmo_charstatus)) { + ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus)); + RFIFOSKIP(fd,size); + break; + } + //Check account only if this ain't final save. Final-save goes through because of the char-map reconnect + if (RFIFOB(fd,12) || ( + (character = (struct online_char_data *)idb_get(online_char_db, aid)) != NULL && + character->char_id == cid)) { + struct mmo_charstatus char_dat; + memcpy(&char_dat, RFIFOP(fd,13), sizeof(struct mmo_charstatus)); + mmo_char_tosql(cid, &char_dat); + } else { //This may be valid on char-server reconnection, when re-sending characters that already logged off. + ShowError("parse_from_map (save-char): Received data for non-existant/offline character (%d:%d).\n", aid, cid); + set_char_online(id, cid, aid); + } + + if (RFIFOB(fd,12)) { + //Flag, set character offline after saving. [Skotlex] + set_char_offline(cid, aid); + WFIFOHEAD(fd,10); + WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save. + WFIFOL(fd,2) = aid; + WFIFOL(fd,6) = cid; + WFIFOSET(fd,10); + } + RFIFOSKIP(fd,size); + } + break; + + case 0x2b02: // req char selection + if (RFIFOREST(fd) < 18) + return 0; + { + struct auth_node *node; + + int account_id = RFIFOL(fd,2); + uint32 login_id1 = RFIFOL(fd,6); + uint32 login_id2 = RFIFOL(fd,10); + uint32 ip = RFIFOL(fd,14); + RFIFOSKIP(fd,18); + + if (runflag != CHARSERVER_ST_RUNNING) { + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x2b03; + WFIFOL(fd,2) = account_id; + WFIFOB(fd,6) = 0;// not ok + WFIFOSET(fd,7); + } else { + // create temporary auth entry + CREATE(node, struct auth_node, 1); + node->account_id = account_id; + node->char_id = 0; + node->login_id1 = login_id1; + node->login_id2 = login_id2; + //node->sex = 0; + node->ip = ntohl(ip); + //node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server) + //node->gmlevel = 0; + idb_put(auth_db, account_id, node); + + //Set char to "@ char select" in online db [Kevin] + set_char_charselect(account_id); + + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x2b03; + WFIFOL(fd,2) = account_id; + WFIFOB(fd,6) = 1;// ok + WFIFOSET(fd,7); + } + } + break; + + case 0x2b05: // request "change map server" + if (RFIFOREST(fd) < 39) + return 0; + { + int map_id, map_fd = -1; + struct online_char_data *data; + struct mmo_charstatus *char_data; + struct mmo_charstatus char_dat; + + map_id = search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port. + if (map_id >= 0) + map_fd = server[map_id].fd; + //Char should just had been saved before this packet, so this should be safe. [Skotlex] + char_data = (struct mmo_charstatus *)uidb_get(char_db_,RFIFOL(fd,14)); + if (char_data == NULL) { //Really shouldn't happen. + mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true); + char_data = (struct mmo_charstatus *)uidb_get(char_db_,RFIFOL(fd,14)); + } + + if (runflag == CHARSERVER_ST_RUNNING && + session_isActive(map_fd) && + char_data) { + //Send the map server the auth of this player. + struct auth_node *node; + + //Update the "last map" as this is where the player must be spawned on the new map server. + char_data->last_point.map = RFIFOW(fd,18); + char_data->last_point.x = RFIFOW(fd,20); + char_data->last_point.y = RFIFOW(fd,22); + char_data->sex = RFIFOB(fd,30); + + // create temporary auth entry + CREATE(node, struct auth_node, 1); + node->account_id = RFIFOL(fd,2); + node->char_id = RFIFOL(fd,14); + node->login_id1 = RFIFOL(fd,6); + node->login_id2 = RFIFOL(fd,10); + node->sex = RFIFOB(fd,30); + node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing) + node->ip = ntohl(RFIFOL(fd,31)); + node->group_id = RFIFOL(fd,35); + node->changing_mapservers = 1; + idb_put(auth_db, RFIFOL(fd,2), node); + + data = idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data); + data->char_id = char_data->char_id; + data->server = map_id; //Update server where char is. + + //Reply with an ack. + WFIFOHEAD(fd,30); + WFIFOW(fd,0) = 0x2b06; + memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); + WFIFOSET(fd,30); + } else { //Reply with nak + WFIFOHEAD(fd,30); + WFIFOW(fd,0) = 0x2b06; + memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); + WFIFOL(fd,6) = 0; //Set login1 to 0. + WFIFOSET(fd,30); + } + RFIFOSKIP(fd,39); + } + break; + + case 0x2b07: // Remove RFIFOL(fd,6) (friend_id) from RFIFOL(fd,2) (char_id) friend list [Ind] + if (RFIFOREST(fd) < 10) + return 0; + { + int char_id, friend_id; + char_id = RFIFOL(fd,2); + friend_id = RFIFOL(fd,6); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `friend_id`='%d' LIMIT 1", + friend_db, char_id, friend_id)) { + Sql_ShowDebug(sql_handle); + break; + } + RFIFOSKIP(fd,10); + } + break; + + case 0x2b08: // char name request + if (RFIFOREST(fd) < 6) + return 0; + + WFIFOHEAD(fd,30); + WFIFOW(fd,0) = 0x2b09; + WFIFOL(fd,2) = RFIFOL(fd,2); + char_loadName((int)RFIFOL(fd,2), (char *)WFIFOP(fd,6)); + WFIFOSET(fd,30); + + RFIFOSKIP(fd,6); + break; + + case 0x2b0c: // Map server send information to change an email of an account -> login-server + if (RFIFOREST(fd) < 86) + return 0; + if (login_fd > 0) { // don't send request if no login-server + WFIFOHEAD(login_fd,86); + memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0),86); // 0x2722 .L .40B .40B + WFIFOW(login_fd,0) = 0x2722; + WFIFOSET(login_fd,86); + } + RFIFOSKIP(fd, 86); + break; + + case 0x2b0e: // Request from map-server to change an account's status (will just be forwarded to login server) + if (RFIFOREST(fd) < 44) + return 0; + { + int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline + char esc_name[NAME_LENGTH*2+1]; + + int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request) + const char *name = (char *)RFIFOP(fd,6); // name of the target character + int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban + short year = RFIFOW(fd,32); + short month = RFIFOW(fd,34); + short day = RFIFOW(fd,36); + short hour = RFIFOW(fd,38); + short minute = RFIFOW(fd,40); + short second = RFIFOW(fd,42); + RFIFOSKIP(fd,44); + + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name)) + Sql_ShowDebug(sql_handle); + else if (Sql_NumRows(sql_handle) == 0) { + result = 1; // 1-player not found + } else if (SQL_SUCCESS != Sql_NextRow(sql_handle)) + Sql_ShowDebug(sql_handle); + //FIXME: set proper result value? + else { + char name[NAME_LENGTH]; + int account_id; + char *data; + + Sql_GetData(sql_handle, 0, &data, NULL); + account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + safestrncpy(name, data, sizeof(name)); + + if (login_fd <= 0) + result = 3; // 3-login-server offline + //FIXME: need to move this check to login server [ultramage] + // else + // if( acc != -1 && isGM(acc) < isGM(account_id) ) + // result = 2; // 2-gm level too low + else + switch (type) { + case 1: // block + WFIFOHEAD(login_fd,10); + WFIFOW(login_fd,0) = 0x2724; + WFIFOL(login_fd,2) = account_id; + WFIFOL(login_fd,6) = 5; // new account status + WFIFOSET(login_fd,10); + break; + case 2: // ban + WFIFOHEAD(login_fd,18); + WFIFOW(login_fd, 0) = 0x2725; + WFIFOL(login_fd, 2) = account_id; + WFIFOW(login_fd, 6) = year; + WFIFOW(login_fd, 8) = month; + WFIFOW(login_fd,10) = day; + WFIFOW(login_fd,12) = hour; + WFIFOW(login_fd,14) = minute; + WFIFOW(login_fd,16) = second; + WFIFOSET(login_fd,18); + break; + case 3: // unblock + WFIFOHEAD(login_fd,10); + WFIFOW(login_fd,0) = 0x2724; + WFIFOL(login_fd,2) = account_id; + WFIFOL(login_fd,6) = 0; // new account status + WFIFOSET(login_fd,10); + break; + case 4: // unban + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x272a; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + break; + case 5: // changesex + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x2727; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + break; + } + } + + Sql_FreeResult(sql_handle); + + // send answer if a player ask, not if the server ask + if (acc != -1 && type != 5) { // Don't send answer for changesex + WFIFOHEAD(fd,34); + WFIFOW(fd, 0) = 0x2b0f; + WFIFOL(fd, 2) = acc; + safestrncpy((char *)WFIFOP(fd,6), name, NAME_LENGTH); + WFIFOW(fd,30) = type; + WFIFOW(fd,32) = result; + WFIFOSET(fd,34); + } + } + break; + + case 0x2b10: // Update and send fame ranking list + if (RFIFOREST(fd) < 11) + return 0; + { + int cid = RFIFOL(fd, 2); + int fame = RFIFOL(fd, 6); + char type = RFIFOB(fd, 10); + int size; + struct fame_list *list; + int player_pos; + int fame_pos; + + switch (type) { + case 1: + size = fame_list_size_smith; + list = smith_fame_list; + break; + case 2: + size = fame_list_size_chemist; + list = chemist_fame_list; + break; + case 3: + size = fame_list_size_taekwon; + list = taekwon_fame_list; + break; + default: + size = 0; + list = NULL; + break; + } + + ARR_FIND(0, size, player_pos, list[player_pos].id == cid);// position of the player + ARR_FIND(0, size, fame_pos, list[fame_pos].fame <= fame);// where the player should be + + if (player_pos == size && fame_pos == size) + ;// not on list and not enough fame to get on it + else if (fame_pos == player_pos) { + // same position + list[player_pos].fame = fame; + char_update_fame_list(type, player_pos, fame); + } else { + // move in the list + if (player_pos == size) { + // new ranker - not in the list + ARR_MOVE(size - 1, fame_pos, list, struct fame_list); + list[fame_pos].id = cid; + list[fame_pos].fame = fame; + char_loadName(cid, list[fame_pos].name); + } else { + // already in the list + if (fame_pos == size) + --fame_pos;// move to the end of the list + ARR_MOVE(player_pos, fame_pos, list, struct fame_list); + list[fame_pos].fame = fame; + } + char_send_fame_list(-1); + } + + RFIFOSKIP(fd,11); + } + break; + + // Divorce chars + case 0x2b11: + if (RFIFOREST(fd) < 10) + return 0; + + divorce_char_sql(RFIFOL(fd,2), RFIFOL(fd,6)); + RFIFOSKIP(fd,10); + break; + + case 0x2b16: // Receive rates [Wizputer] + if (RFIFOREST(fd) < 14) + return 0; + { + char esc_server_name[sizeof(server_name)*2+1]; + + Sql_EscapeString(sql_handle, esc_server_name, server_name); + + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d'", + ragsrvinfo_db, fd, esc_server_name, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10))) + Sql_ShowDebug(sql_handle); + RFIFOSKIP(fd,14); + } + break; + + case 0x2b17: // Character disconnected set online 0 [Wizputer] + if (RFIFOREST(fd) < 6) + return 0; + set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6)); + RFIFOSKIP(fd,10); + break; + + case 0x2b18: // Reset all chars to offline [Wizputer] + set_all_offline(id); + RFIFOSKIP(fd,2); + break; + + case 0x2b19: // Character set online [Wizputer] + if (RFIFOREST(fd) < 10) + return 0; + set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6)); + RFIFOSKIP(fd,10); + break; + + case 0x2b1a: // Build and send fame ranking lists [DracoRPG] + if (RFIFOREST(fd) < 2) + return 0; + char_read_fame_list(); + char_send_fame_list(-1); + RFIFOSKIP(fd,2); + break; + + case 0x2b1c: //Request to save status change data. [Skotlex] + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + { #ifdef ENABLE_SC_SAVING - int count, aid, cid; - - aid = RFIFOL(fd, 4); - cid = RFIFOL(fd, 8); - count = RFIFOW(fd, 12); - - if( count > 0 ) - { - struct status_change_data data; - StringBuf buf; - int i; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db); - for( i = 0; i < count; ++i ) - { - memcpy (&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data)); - if( i > 0 ) - StringBuf_AppendStr(&buf, ", "); - StringBuf_Printf(&buf, "('%d','%d','%hu','%d','%d','%d','%d','%d')", aid, cid, - data.type, data.tick, data.val1, data.val2, data.val3, data.val4); - } - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - Sql_ShowDebug(sql_handle); - StringBuf_Destroy(&buf); - } + int count, aid, cid; + + aid = RFIFOL(fd, 4); + cid = RFIFOL(fd, 8); + count = RFIFOW(fd, 12); + + if (count > 0) { + struct status_change_data data; + StringBuf buf; + int i; + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db); + for (i = 0; i < count; ++i) { + memcpy(&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data)); + if (i > 0) + StringBuf_AppendStr(&buf, ", "); + StringBuf_Printf(&buf, "('%d','%d','%hu','%d','%d','%d','%d','%d')", aid, cid, + data.type, data.tick, data.val1, data.val2, data.val3, data.val4); + } + if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) + Sql_ShowDebug(sql_handle); + StringBuf_Destroy(&buf); + } #endif - RFIFOSKIP(fd, RFIFOW(fd, 2)); - } - break; - - case 0x2b23: // map-server alive packet - WFIFOHEAD(fd,2); - WFIFOW(fd,0) = 0x2b24; - WFIFOSET(fd,2); - RFIFOSKIP(fd,2); - break; - - case 0x2b26: // auth request from map-server - if (RFIFOREST(fd) < 19) - return 0; - - { - int account_id; - int char_id; - int login_id1; - char sex; - uint32 ip; - struct auth_node* node; - struct mmo_charstatus* cd; - struct mmo_charstatus char_dat; - - account_id = RFIFOL(fd,2); - char_id = RFIFOL(fd,6); - login_id1 = RFIFOL(fd,10); - sex = RFIFOB(fd,14); - ip = ntohl(RFIFOL(fd,15)); - RFIFOSKIP(fd,19); - - node = (struct auth_node*)idb_get(auth_db, account_id); - cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id); - if( cd == NULL ) - { //Really shouldn't happen. - mmo_char_fromsql(char_id, &char_dat, true); - cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id); - } - if( runflag == CHARSERVER_ST_RUNNING && - cd != NULL && - node != NULL && - node->account_id == account_id && - node->char_id == char_id && - node->login_id1 == login_id1 && - node->sex == sex /*&& - node->ip == ip*/ ) - {// auth ok - cd->sex = sex; - - WFIFOHEAD(fd,25 + sizeof(struct mmo_charstatus)); - WFIFOW(fd,0) = 0x2afd; - WFIFOW(fd,2) = 25 + sizeof(struct mmo_charstatus); - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = node->login_id1; - WFIFOL(fd,12) = node->login_id2; - WFIFOL(fd,16) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT" - WFIFOL(fd,20) = node->group_id; - WFIFOB(fd,24) = node->changing_mapservers; - memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus)); - WFIFOSET(fd, WFIFOW(fd,2)); - - // only use the auth once and mark user online - idb_remove(auth_db, account_id); - set_char_online(id, char_id, account_id); - } - else - {// auth failed - WFIFOHEAD(fd,19); - WFIFOW(fd,0) = 0x2b27; - WFIFOL(fd,2) = account_id; - WFIFOL(fd,6) = char_id; - WFIFOL(fd,10) = login_id1; - WFIFOB(fd,14) = sex; - WFIFOL(fd,15) = htonl(ip); - WFIFOSET(fd,19); - } - } - break; - - case 0x2736: // ip address update - if (RFIFOREST(fd) < 6) return 0; - server[id].ip = ntohl(RFIFOL(fd, 2)); - ShowInfo("Updated IP address of map-server #%d to %d.%d.%d.%d.\n", id, CONVIP(server[id].ip)); - RFIFOSKIP(fd,6); - break; - - case 0x3008: - if( RFIFOREST(fd) < RFIFOW(fd,4) ) - return 0;/* packet wasn't fully received yet (still fragmented) */ - else { - int sfd;/* stat server fd */ - RFIFOSKIP(fd, 2);/* we skip first 2 bytes which are the 0x3008, so we end up with a buffer equal to the one we send */ - - if( (sfd = make_connection(host2ip("stats.rathena.org"),(uint16)25421,true) ) == -1 ) { - RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */ - break;/* connection not possible, we drop the report */ - } - - session[sfd]->flag.server = 1;/* to ensure we won't drop our own packet */ - - WFIFOHEAD(sfd, RFIFOW(fd,2) ); - - memcpy((char*)WFIFOP(sfd,0), (char*)RFIFOP(fd, 0), RFIFOW(fd,2)); - - WFIFOSET(sfd, RFIFOW(fd,2) ); - - flush_fifo(sfd); - - do_close(sfd); - - RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */ - } - break; - - - default: - { - // inter server - packet - int r = inter_parse_frommap(fd); - if (r == 1) break; // processed - if (r == 2) return 0; // need more packet - - // no inter server packet. no char server packet -> disconnect - ShowError("Unknown packet 0x%04x from map server, disconnecting.\n", RFIFOW(fd,0)); - set_eof(fd); - return 0; - } - } // switch - } // while - - return 0; + RFIFOSKIP(fd, RFIFOW(fd, 2)); + } + break; + + case 0x2b23: // map-server alive packet + WFIFOHEAD(fd,2); + WFIFOW(fd,0) = 0x2b24; + WFIFOSET(fd,2); + RFIFOSKIP(fd,2); + break; + + case 0x2b26: // auth request from map-server + if (RFIFOREST(fd) < 19) + return 0; + + { + int account_id; + int char_id; + int login_id1; + char sex; + uint32 ip; + struct auth_node *node; + struct mmo_charstatus *cd; + struct mmo_charstatus char_dat; + + account_id = RFIFOL(fd,2); + char_id = RFIFOL(fd,6); + login_id1 = RFIFOL(fd,10); + sex = RFIFOB(fd,14); + ip = ntohl(RFIFOL(fd,15)); + RFIFOSKIP(fd,19); + + node = (struct auth_node *)idb_get(auth_db, account_id); + cd = (struct mmo_charstatus *)uidb_get(char_db_,char_id); + if (cd == NULL) { + //Really shouldn't happen. + mmo_char_fromsql(char_id, &char_dat, true); + cd = (struct mmo_charstatus *)uidb_get(char_db_,char_id); + } + if (runflag == CHARSERVER_ST_RUNNING && + cd != NULL && + node != NULL && + node->account_id == account_id && + node->char_id == char_id && + node->login_id1 == login_id1 && + node->sex == sex /*&& + node->ip == ip*/) { + // auth ok + cd->sex = sex; + + WFIFOHEAD(fd,25 + sizeof(struct mmo_charstatus)); + WFIFOW(fd,0) = 0x2afd; + WFIFOW(fd,2) = 25 + sizeof(struct mmo_charstatus); + WFIFOL(fd,4) = account_id; + WFIFOL(fd,8) = node->login_id1; + WFIFOL(fd,12) = node->login_id2; + WFIFOL(fd,16) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT" + WFIFOL(fd,20) = node->group_id; + WFIFOB(fd,24) = node->changing_mapservers; + memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus)); + WFIFOSET(fd, WFIFOW(fd,2)); + + // only use the auth once and mark user online + idb_remove(auth_db, account_id); + set_char_online(id, char_id, account_id); + } else { + // auth failed + WFIFOHEAD(fd,19); + WFIFOW(fd,0) = 0x2b27; + WFIFOL(fd,2) = account_id; + WFIFOL(fd,6) = char_id; + WFIFOL(fd,10) = login_id1; + WFIFOB(fd,14) = sex; + WFIFOL(fd,15) = htonl(ip); + WFIFOSET(fd,19); + } + } + break; + + case 0x2736: // ip address update + if (RFIFOREST(fd) < 6) return 0; + server[id].ip = ntohl(RFIFOL(fd, 2)); + ShowInfo("Updated IP address of map-server #%d to %d.%d.%d.%d.\n", id, CONVIP(server[id].ip)); + RFIFOSKIP(fd,6); + break; + + case 0x3008: + if (RFIFOREST(fd) < RFIFOW(fd,4)) + return 0;/* packet wasn't fully received yet (still fragmented) */ + else { + int sfd;/* stat server fd */ + RFIFOSKIP(fd, 2);/* we skip first 2 bytes which are the 0x3008, so we end up with a buffer equal to the one we send */ + + if ((sfd = make_connection(host2ip("stats.rathena.org"),(uint16)25421,true)) == -1) { + RFIFOSKIP(fd, RFIFOW(fd,2)); /* skip this packet */ + break;/* connection not possible, we drop the report */ + } + + session[sfd]->flag.server = 1;/* to ensure we won't drop our own packet */ + + WFIFOHEAD(sfd, RFIFOW(fd,2)); + + memcpy((char *)WFIFOP(sfd,0), (char *)RFIFOP(fd, 0), RFIFOW(fd,2)); + + WFIFOSET(sfd, RFIFOW(fd,2)); + + flush_fifo(sfd); + + do_close(sfd); + + RFIFOSKIP(fd, RFIFOW(fd,2)); /* skip this packet */ + } + break; + + + default: { + // inter server - packet + int r = inter_parse_frommap(fd); + if (r == 1) break; // processed + if (r == 2) return 0; // need more packet + + // no inter server packet. no char server packet -> disconnect + ShowError("Unknown packet 0x%04x from map server, disconnecting.\n", RFIFOW(fd,0)); + set_eof(fd); + return 0; + } + } // switch + } // while + + return 0; } void do_init_mapif(void) { - int i; - for( i = 0; i < ARRAYLENGTH(server); ++i ) - mapif_server_init(i); + int i; + for (i = 0; i < ARRAYLENGTH(server); ++i) + mapif_server_init(i); } void do_final_mapif(void) { - int i; - for( i = 0; i < ARRAYLENGTH(server); ++i ) - mapif_server_destroy(i); + int i; + for (i = 0; i < ARRAYLENGTH(server); ++i) + mapif_server_destroy(i); } // Searches for the mapserver that has a given map (and optionally ip/port, if not -1). // If found, returns the server's index in the 'server' array (otherwise returns -1). int search_mapserver(unsigned short map, uint32 ip, uint16 port) { - int i, j; - - for(i = 0; i < ARRAYLENGTH(server); i++) - { - if (server[i].fd > 0 - && (ip == (uint32)-1 || server[i].ip == ip) - && (port == (uint16)-1 || server[i].port == port)) - { - for (j = 0; server[i].map[j]; j++) - if (server[i].map[j] == map) - return i; - } - } - - return -1; + int i, j; + + for (i = 0; i < ARRAYLENGTH(server); i++) { + if (server[i].fd > 0 + && (ip == (uint32)-1 || server[i].ip == ip) + && (port == (uint16)-1 || server[i].port == port)) { + for (j = 0; server[i].map[j]; j++) + if (server[i].map[j] == map) + return i; + } + } + + return -1; } // Initialization process (currently only initialization inter_mapif) static int char_mapif_init(int fd) { - return inter_mapif_init(fd); + return inter_mapif_init(fd); } //-------------------------------------------- @@ -3377,15 +3321,15 @@ static int char_mapif_init(int fd) //-------------------------------------------- int lan_subnetcheck(uint32 ip) { - int i; - ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) ); - if( i < subnet_count ) { - ShowInfo("Subnet check [%u.%u.%u.%u]: Matches "CL_CYAN"%u.%u.%u.%u/%u.%u.%u.%u"CL_RESET"\n", CONVIP(ip), CONVIP(subnet[i].char_ip & subnet[i].mask), CONVIP(subnet[i].mask)); - return subnet[i].map_ip; - } else { - ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", CONVIP(ip)); - return 0; - } + int i; + ARR_FIND(0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask)); + if (i < subnet_count) { + ShowInfo("Subnet check [%u.%u.%u.%u]: Matches "CL_CYAN"%u.%u.%u.%u/%u.%u.%u.%u"CL_RESET"\n", CONVIP(ip), CONVIP(subnet[i].char_ip & subnet[i].mask), CONVIP(subnet[i].mask)); + return subnet[i].map_ip; + } else { + ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", CONVIP(ip)); + return 0; + } } @@ -3397,13 +3341,14 @@ int lan_subnetcheck(uint32 ip) /// 5 (0x71b): To delete a character you must withdraw from the party. /// Any (0x718): An unknown error has occurred. void char_delete2_ack(int fd, int char_id, uint32 result, time_t delete_date) -{// HC: <0828>.W .L .L .L - WFIFOHEAD(fd,14); - WFIFOW(fd,0) = 0x828; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = result; - WFIFOL(fd,10) = TOL(delete_date); - WFIFOSET(fd,14); +{ + // HC: <0828>.W .L .L .L + WFIFOHEAD(fd,14); + WFIFOW(fd,0) = 0x828; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = result; + WFIFOL(fd,10) = TOL(delete_date); + WFIFOSET(fd,14); } @@ -3416,12 +3361,13 @@ void char_delete2_ack(int fd, int char_id, uint32 result, time_t delete_date) /// 5 (0x71e): Date of birth do not match. /// Any (0x718): An unknown error has occurred. void char_delete2_accept_ack(int fd, int char_id, uint32 result) -{// HC: <082a>.W .L .L - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x82a; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = result; - WFIFOSET(fd,10); +{ + // HC: <082a>.W .L .L + WFIFOHEAD(fd,10); + WFIFOW(fd,0) = 0x82a; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = result; + WFIFOSET(fd,10); } @@ -3430,804 +3376,797 @@ void char_delete2_accept_ack(int fd, int char_id, uint32 result) /// 2 (0x719): A database error occurred. /// Any (0x718): An unknown error has occurred. void char_delete2_cancel_ack(int fd, int char_id, uint32 result) -{// HC: <082c>.W .L .L - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x82c; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = result; - WFIFOSET(fd,10); +{ + // HC: <082c>.W .L .L + WFIFOHEAD(fd,10); + WFIFOW(fd,0) = 0x82c; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = result; + WFIFOSET(fd,10); } -static void char_delete2_req(int fd, struct char_session_data* sd) -{// CH: <0827>.W .L - int char_id, i; - char* data; - time_t delete_date; - - char_id = RFIFOL(fd,2); - - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id ); - if( i == MAX_CHARS ) - {// character not found - char_delete2_ack(fd, char_id, 3, 0); - return; - } - - if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_ShowDebug(sql_handle); - char_delete2_ack(fd, char_id, 3, 0); - return; - } - - Sql_GetData(sql_handle, 0, &data, NULL); delete_date = strtoul(data, NULL, 10); - - if( delete_date ) {// character already queued for deletion - char_delete2_ack(fd, char_id, 0, 0); - return; - } - -/* - // Aegis imposes these checks probably to avoid dead member - // entries in guilds/parties, otherwise they are not required. - // TODO: Figure out how these are enforced during waiting. - if( guild_id ) - {// character in guild - char_delete2_ack(fd, char_id, 4, 0); - return; - } - - if( party_id ) - {// character in party - char_delete2_ack(fd, char_id, 5, 0); - return; - } -*/ - - // success - delete_date = time(NULL)+char_del_delay; - - if( SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='%lu' WHERE `char_id`='%d'", char_db, (unsigned long)delete_date, char_id) ) - { - Sql_ShowDebug(sql_handle); - char_delete2_ack(fd, char_id, 3, 0); - return; - } - - char_delete2_ack(fd, char_id, 1, delete_date); +static void char_delete2_req(int fd, struct char_session_data *sd) +{ + // CH: <0827>.W .L + int char_id, i; + char *data; + time_t delete_date; + + char_id = RFIFOL(fd,2); + + ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == char_id); + if (i == MAX_CHARS) { + // character not found + char_delete2_ack(fd, char_id, 3, 0); + return; + } + + if (SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle)) { + Sql_ShowDebug(sql_handle); + char_delete2_ack(fd, char_id, 3, 0); + return; + } + + Sql_GetData(sql_handle, 0, &data, NULL); + delete_date = strtoul(data, NULL, 10); + + if (delete_date) { // character already queued for deletion + char_delete2_ack(fd, char_id, 0, 0); + return; + } + + /* + // Aegis imposes these checks probably to avoid dead member + // entries in guilds/parties, otherwise they are not required. + // TODO: Figure out how these are enforced during waiting. + if( guild_id ) + {// character in guild + char_delete2_ack(fd, char_id, 4, 0); + return; + } + + if( party_id ) + {// character in party + char_delete2_ack(fd, char_id, 5, 0); + return; + } + */ + + // success + delete_date = time(NULL)+char_del_delay; + + if (SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='%lu' WHERE `char_id`='%d'", char_db, (unsigned long)delete_date, char_id)) { + Sql_ShowDebug(sql_handle); + char_delete2_ack(fd, char_id, 3, 0); + return; + } + + char_delete2_ack(fd, char_id, 1, delete_date); } -static void char_delete2_accept(int fd, struct char_session_data* sd) -{// CH: <0829>.W .L .6B - char birthdate[8+1]; - int char_id, i, k; - unsigned int base_level; - char* data; - time_t delete_date; - - char_id = RFIFOL(fd,2); - - ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, char_id); - - // construct "YY-MM-DD" - birthdate[0] = RFIFOB(fd,6); - birthdate[1] = RFIFOB(fd,7); - birthdate[2] = '-'; - birthdate[3] = RFIFOB(fd,8); - birthdate[4] = RFIFOB(fd,9); - birthdate[5] = '-'; - birthdate[6] = RFIFOB(fd,10); - birthdate[7] = RFIFOB(fd,11); - birthdate[8] = 0; - - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id ); - if( i == MAX_CHARS ) - {// character not found - char_delete2_accept_ack(fd, char_id, 3); - return; - } - - if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `base_level`,`delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle) ) - {// data error - Sql_ShowDebug(sql_handle); - char_delete2_accept_ack(fd, char_id, 3); - return; - } - - Sql_GetData(sql_handle, 0, &data, NULL); base_level = (unsigned int)strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 1, &data, NULL); delete_date = strtoul(data, NULL, 10); - - if( !delete_date || delete_date>time(NULL) ) - {// not queued or delay not yet passed - char_delete2_accept_ack(fd, char_id, 4); - return; - } - - if( strcmp(sd->birthdate+2, birthdate) ) // +2 to cut off the century - {// birth date is wrong - char_delete2_accept_ack(fd, char_id, 5); - return; - } - - if( ( char_del_level > 0 && base_level >= (unsigned int)char_del_level ) || ( char_del_level < 0 && base_level <= (unsigned int)(-char_del_level) ) ) - {// character level config restriction - char_delete2_accept_ack(fd, char_id, 2); - return; - } - - // success - if( delete_char_sql(char_id) < 0 ) - { - char_delete2_accept_ack(fd, char_id, 3); - return; - } - - // refresh character list cache - for(k = i; k < MAX_CHARS-1; k++) - { - sd->found_char[k] = sd->found_char[k+1]; - } - sd->found_char[MAX_CHARS-1] = -1; - - char_delete2_accept_ack(fd, char_id, 1); +static void char_delete2_accept(int fd, struct char_session_data *sd) +{ + // CH: <0829>.W .L .6B + char birthdate[8+1]; + int char_id, i, k; + unsigned int base_level; + char *data; + time_t delete_date; + + char_id = RFIFOL(fd,2); + + ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, char_id); + + // construct "YY-MM-DD" + birthdate[0] = RFIFOB(fd,6); + birthdate[1] = RFIFOB(fd,7); + birthdate[2] = '-'; + birthdate[3] = RFIFOB(fd,8); + birthdate[4] = RFIFOB(fd,9); + birthdate[5] = '-'; + birthdate[6] = RFIFOB(fd,10); + birthdate[7] = RFIFOB(fd,11); + birthdate[8] = 0; + + ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == char_id); + if (i == MAX_CHARS) { + // character not found + char_delete2_accept_ack(fd, char_id, 3); + return; + } + + if (SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `base_level`,`delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle)) { + // data error + Sql_ShowDebug(sql_handle); + char_delete2_accept_ack(fd, char_id, 3); + return; + } + + Sql_GetData(sql_handle, 0, &data, NULL); + base_level = (unsigned int)strtoul(data, NULL, 10); + Sql_GetData(sql_handle, 1, &data, NULL); + delete_date = strtoul(data, NULL, 10); + + if (!delete_date || delete_date>time(NULL)) { + // not queued or delay not yet passed + char_delete2_accept_ack(fd, char_id, 4); + return; + } + + if (strcmp(sd->birthdate+2, birthdate)) { // +2 to cut off the century + // birth date is wrong + char_delete2_accept_ack(fd, char_id, 5); + return; + } + + if ((char_del_level > 0 && base_level >= (unsigned int)char_del_level) || (char_del_level < 0 && base_level <= (unsigned int)(-char_del_level))) { + // character level config restriction + char_delete2_accept_ack(fd, char_id, 2); + return; + } + + // success + if (delete_char_sql(char_id) < 0) { + char_delete2_accept_ack(fd, char_id, 3); + return; + } + + // refresh character list cache + for (k = i; k < MAX_CHARS-1; k++) { + sd->found_char[k] = sd->found_char[k+1]; + } + sd->found_char[MAX_CHARS-1] = -1; + + char_delete2_accept_ack(fd, char_id, 1); } -static void char_delete2_cancel(int fd, struct char_session_data* sd) -{// CH: <082b>.W .L - int char_id, i; - - char_id = RFIFOL(fd,2); - - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id ); - if( i == MAX_CHARS ) - {// character not found - char_delete2_cancel_ack(fd, char_id, 2); - return; - } - - // there is no need to check, whether or not the character was - // queued for deletion, as the client prints an error message by - // itself, if it was not the case (@see char_delete2_cancel_ack) - if( SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='0' WHERE `char_id`='%d'", char_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - char_delete2_cancel_ack(fd, char_id, 2); - return; - } - - char_delete2_cancel_ack(fd, char_id, 1); +static void char_delete2_cancel(int fd, struct char_session_data *sd) +{ + // CH: <082b>.W .L + int char_id, i; + + char_id = RFIFOL(fd,2); + + ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == char_id); + if (i == MAX_CHARS) { + // character not found + char_delete2_cancel_ack(fd, char_id, 2); + return; + } + + // there is no need to check, whether or not the character was + // queued for deletion, as the client prints an error message by + // itself, if it was not the case (@see char_delete2_cancel_ack) + if (SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='0' WHERE `char_id`='%d'", char_db, char_id)) { + Sql_ShowDebug(sql_handle); + char_delete2_cancel_ack(fd, char_id, 2); + return; + } + + char_delete2_cancel_ack(fd, char_id, 1); } int parse_char(int fd) { - int i, ch; - char email[40]; - unsigned short cmd; - int map_fd; - struct char_session_data* sd; - uint32 ipl = session[fd]->client_addr; - - sd = (struct char_session_data*)session[fd]->session_data; - - // disconnect any player if no login-server. - if(login_fd < 0) - set_eof(fd); - - if(session[fd]->flag.eof) - { - if( sd != NULL && sd->auth ) - { // already authed client - struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id); - if( data != NULL && data->fd == fd) - data->fd = -1; - if( data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex] - set_char_offline(-1,sd->account_id); - } - do_close(fd); - return 0; - } - - while( RFIFOREST(fd) >= 2 ) - { - //For use in packets that depend on an sd being present [Skotlex] - #define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } } - - cmd = RFIFOW(fd,0); - switch( cmd ) - { - - // request to connect - // 0065 .L .L .L .W .B - case 0x65: - if( RFIFOREST(fd) < 17 ) - return 0; - { - struct auth_node* node; - - int account_id = RFIFOL(fd,2); - uint32 login_id1 = RFIFOL(fd,6); - uint32 login_id2 = RFIFOL(fd,10); - int sex = RFIFOB(fd,16); - RFIFOSKIP(fd,17); - - ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2); - - if (sd) { - //Received again auth packet for already authentified account?? Discard it. - //TODO: Perhaps log this as a hack attempt? - //TODO: and perhaps send back a reply? - break; - } - - CREATE(session[fd]->session_data, struct char_session_data, 1); - sd = (struct char_session_data*)session[fd]->session_data; - sd->account_id = account_id; - sd->login_id1 = login_id1; - sd->login_id2 = login_id2; - sd->sex = sex; - sd->auth = false; // not authed yet - - // send back account_id - WFIFOHEAD(fd,4); - WFIFOL(fd,0) = account_id; - WFIFOSET(fd,4); - - if( runflag != CHARSERVER_ST_RUNNING ) - { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x6c; - WFIFOB(fd,2) = 0;// rejected from server - WFIFOSET(fd,3); - break; - } - - // search authentification - node = (struct auth_node*)idb_get(auth_db, account_id); - if( node != NULL && - node->account_id == account_id && - node->login_id1 == login_id1 && - node->login_id2 == login_id2 /*&& - node->ip == ipl*/ ) - {// authentication found (coming from map server) - idb_remove(auth_db, account_id); - char_auth_ok(fd, sd); - } - else - {// authentication not found (coming from login server) - if (login_fd > 0) { // don't send request if no login-server - WFIFOHEAD(login_fd,23); - WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account - WFIFOL(login_fd,2) = sd->account_id; - WFIFOL(login_fd,6) = sd->login_id1; - WFIFOL(login_fd,10) = sd->login_id2; - WFIFOB(login_fd,14) = sd->sex; - WFIFOL(login_fd,15) = htonl(ipl); - WFIFOL(login_fd,19) = fd; - WFIFOSET(login_fd,23); - } else { // if no login-server, we must refuse connection - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x6c; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - } - } - } - break; - - // char select - case 0x66: - FIFOSD_CHECK(3); - { - struct mmo_charstatus char_dat; - struct mmo_charstatus *cd; - char* data; - int char_id; - uint32 subnet_map_ip; - struct auth_node* node; - - int slot = RFIFOB(fd,2); - RFIFOSKIP(fd,3); - - if ( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", char_db, sd->account_id, slot) - || SQL_SUCCESS != Sql_NextRow(sql_handle) - || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) ) - { //Not found?? May be forged packet. - Sql_ShowDebug(sql_handle); - Sql_FreeResult(sql_handle); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x6c; - WFIFOB(fd,2) = 0; // rejected from server - WFIFOSET(fd,3); - break; - } - - char_id = atoi(data); - Sql_FreeResult(sql_handle); - mmo_char_fromsql(char_id, &char_dat, true); - - //Have to switch over to the DB instance otherwise data won't propagate [Kevin] - cd = (struct mmo_charstatus *)idb_get(char_db_, char_id); - cd->sex = sd->sex; - - if (log_char) { - char esc_name[NAME_LENGTH*2+1]; - - Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')", - charlog_db, sd->account_id, slot, esc_name) ) - Sql_ShowDebug(sql_handle); - } - ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name); - - // searching map server - i = search_mapserver(cd->last_point.map, -1, -1); - - // if map is not found, we check major cities - if (i < 0 || !cd->last_point.map) { - unsigned short j; - //First check that there's actually a map server online. - ARR_FIND( 0, ARRAYLENGTH(server), j, server[j].fd >= 0 && server[j].map[0] ); - if (j == ARRAYLENGTH(server)) { - ShowInfo("Connection Closed. No map servers available.\n"); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - break; - } - if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) { - cd->last_point.x = 273; - cd->last_point.y = 354; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) { - cd->last_point.x = 120; - cd->last_point.y = 100; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) { - cd->last_point.x = 160; - cd->last_point.y = 94; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) { - cd->last_point.x = 116; - cd->last_point.y = 57; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) { - cd->last_point.x = 87; - cd->last_point.y = 117; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) { - cd->last_point.x = 94; - cd->last_point.y = 103; - } else { - ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(cd->last_point.map)); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - break; - } - ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j)); - cd->last_point.map = j; - } - - //Send NEW auth packet [Kevin] - //FIXME: is this case even possible? [ultramage] - if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL) - { - ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i); - server[i].fd = -1; - memset(&server[i], 0, sizeof(struct mmo_map_server)); - //Send server closed. - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - break; - } - - //Send player to map - WFIFOHEAD(fd,28); - WFIFOW(fd,0) = 0x71; - WFIFOL(fd,2) = cd->char_id; - mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6)); - subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza] - WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip); - WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!] - WFIFOSET(fd,28); - - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = sd->account_id; - node->char_id = cd->char_id; - node->login_id1 = sd->login_id1; - node->login_id2 = sd->login_id2; - node->sex = sd->sex; - node->expiration_time = sd->expiration_time; - node->group_id = sd->group_id; - node->ip = ipl; - idb_put(auth_db, sd->account_id, node); - - set_char_online(-2,node->char_id,sd->account_id); - - } - break; - - // create new char + int i, ch; + char email[40]; + unsigned short cmd; + int map_fd; + struct char_session_data *sd; + uint32 ipl = session[fd]->client_addr; + + sd = (struct char_session_data *)session[fd]->session_data; + + // disconnect any player if no login-server. + if (login_fd < 0) + set_eof(fd); + + if (session[fd]->flag.eof) { + if (sd != NULL && sd->auth) { + // already authed client + struct online_char_data *data = (struct online_char_data *)idb_get(online_char_db, sd->account_id); + if (data != NULL && data->fd == fd) + data->fd = -1; + if (data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex] + set_char_offline(-1,sd->account_id); + } + do_close(fd); + return 0; + } + + while (RFIFOREST(fd) >= 2) { + //For use in packets that depend on an sd being present [Skotlex] +#define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } } + + cmd = RFIFOW(fd,0); + switch (cmd) { + + // request to connect + // 0065 .L .L .L .W .B + case 0x65: + if (RFIFOREST(fd) < 17) + return 0; + { + struct auth_node *node; + + int account_id = RFIFOL(fd,2); + uint32 login_id1 = RFIFOL(fd,6); + uint32 login_id2 = RFIFOL(fd,10); + int sex = RFIFOB(fd,16); + RFIFOSKIP(fd,17); + + ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2); + + if (sd) { + //Received again auth packet for already authentified account?? Discard it. + //TODO: Perhaps log this as a hack attempt? + //TODO: and perhaps send back a reply? + break; + } + + CREATE(session[fd]->session_data, struct char_session_data, 1); + sd = (struct char_session_data *)session[fd]->session_data; + sd->account_id = account_id; + sd->login_id1 = login_id1; + sd->login_id2 = login_id2; + sd->sex = sex; + sd->auth = false; // not authed yet + + // send back account_id + WFIFOHEAD(fd,4); + WFIFOL(fd,0) = account_id; + WFIFOSET(fd,4); + + if (runflag != CHARSERVER_ST_RUNNING) { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x6c; + WFIFOB(fd,2) = 0;// rejected from server + WFIFOSET(fd,3); + break; + } + + // search authentification + node = (struct auth_node *)idb_get(auth_db, account_id); + if (node != NULL && + node->account_id == account_id && + node->login_id1 == login_id1 && + node->login_id2 == login_id2 /*&& + node->ip == ipl*/) { + // authentication found (coming from map server) + idb_remove(auth_db, account_id); + char_auth_ok(fd, sd); + } else { + // authentication not found (coming from login server) + if (login_fd > 0) { // don't send request if no login-server + WFIFOHEAD(login_fd,23); + WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account + WFIFOL(login_fd,2) = sd->account_id; + WFIFOL(login_fd,6) = sd->login_id1; + WFIFOL(login_fd,10) = sd->login_id2; + WFIFOB(login_fd,14) = sd->sex; + WFIFOL(login_fd,15) = htonl(ipl); + WFIFOL(login_fd,19) = fd; + WFIFOSET(login_fd,23); + } else { // if no login-server, we must refuse connection + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x6c; + WFIFOB(fd,2) = 0; + WFIFOSET(fd,3); + } + } + } + break; + + // char select + case 0x66: + FIFOSD_CHECK(3); + { + struct mmo_charstatus char_dat; + struct mmo_charstatus *cd; + char *data; + int char_id; + uint32 subnet_map_ip; + struct auth_node *node; + + int slot = RFIFOB(fd,2); + RFIFOSKIP(fd,3); + + if (SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", char_db, sd->account_id, slot) + || SQL_SUCCESS != Sql_NextRow(sql_handle) + || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL)) { + //Not found?? May be forged packet. + Sql_ShowDebug(sql_handle); + Sql_FreeResult(sql_handle); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x6c; + WFIFOB(fd,2) = 0; // rejected from server + WFIFOSET(fd,3); + break; + } + + char_id = atoi(data); + Sql_FreeResult(sql_handle); + mmo_char_fromsql(char_id, &char_dat, true); + + //Have to switch over to the DB instance otherwise data won't propagate [Kevin] + cd = (struct mmo_charstatus *)idb_get(char_db_, char_id); + cd->sex = sd->sex; + + if (log_char) { + char esc_name[NAME_LENGTH*2+1]; + + Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH)); + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')", + charlog_db, sd->account_id, slot, esc_name)) + Sql_ShowDebug(sql_handle); + } + ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name); + + // searching map server + i = search_mapserver(cd->last_point.map, -1, -1); + + // if map is not found, we check major cities + if (i < 0 || !cd->last_point.map) { + unsigned short j; + //First check that there's actually a map server online. + ARR_FIND(0, ARRAYLENGTH(server), j, server[j].fd >= 0 && server[j].map[0]); + if (j == ARRAYLENGTH(server)) { + ShowInfo("Connection Closed. No map servers available.\n"); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + break; + } + if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) { + cd->last_point.x = 273; + cd->last_point.y = 354; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) { + cd->last_point.x = 120; + cd->last_point.y = 100; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) { + cd->last_point.x = 160; + cd->last_point.y = 94; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) { + cd->last_point.x = 116; + cd->last_point.y = 57; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) { + cd->last_point.x = 87; + cd->last_point.y = 117; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) { + cd->last_point.x = 94; + cd->last_point.y = 103; + } else { + ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(cd->last_point.map)); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + break; + } + ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j)); + cd->last_point.map = j; + } + + //Send NEW auth packet [Kevin] + //FIXME: is this case even possible? [ultramage] + if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL) { + ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i); + server[i].fd = -1; + memset(&server[i], 0, sizeof(struct mmo_map_server)); + //Send server closed. + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + break; + } + + //Send player to map + WFIFOHEAD(fd,28); + WFIFOW(fd,0) = 0x71; + WFIFOL(fd,2) = cd->char_id; + mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char *)WFIFOP(fd,6)); + subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza] + WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip); + WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!] + WFIFOSET(fd,28); + + // create temporary auth entry + CREATE(node, struct auth_node, 1); + node->account_id = sd->account_id; + node->char_id = cd->char_id; + node->login_id1 = sd->login_id1; + node->login_id2 = sd->login_id2; + node->sex = sd->sex; + node->expiration_time = sd->expiration_time; + node->group_id = sd->group_id; + node->ip = ipl; + idb_put(auth_db, sd->account_id, node); + + set_char_online(-2,node->char_id,sd->account_id); + + } + break; + + // create new char #if PACKETVER >= 20120307 - // S 0970 .24B .B .W .W - case 0x970: - FIFOSD_CHECK(31); + // S 0970 .24B .B .W .W + case 0x970: + FIFOSD_CHECK(31); #else - // S 0067 .24B .B .B .B .B .B .B .B .W .W - case 0x67: - FIFOSD_CHECK(37); + // S 0067 .24B .B .B .B .B .B .B .B .W .W + case 0x67: + FIFOSD_CHECK(37); #endif - if( !char_new ) //turn character creation on/off [Kevin] - i = -2; - else + if (!char_new) //turn character creation on/off [Kevin] + i = -2; + else #if PACKETVER >= 20120307 - i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29)); + i = make_new_char_sql(sd, (char *)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29)); #else - i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35)); + i = make_new_char_sql(sd, (char *)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35)); #endif - //'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3) - if (i < 0) - { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x6e; - switch (i) { - case -1: WFIFOB(fd,2) = 0x00; break; - case -2: WFIFOB(fd,2) = 0xFF; break; - case -3: WFIFOB(fd,2) = 0x01; break; - } - WFIFOSET(fd,3); - } - else - { - int len; - // retrieve data - struct mmo_charstatus char_dat; - mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed. - - // send to player - WFIFOHEAD(fd,2+MAX_CHAR_BUF); - WFIFOW(fd,0) = 0x6d; - len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat); - WFIFOSET(fd,len); - - // add new entry to the chars list - ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 ); - if( ch < MAX_CHARS ) - sd->found_char[ch] = i; // the char_id of the new char - } + //'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3) + if (i < 0) { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x6e; + switch (i) { + case -1: + WFIFOB(fd,2) = 0x00; + break; + case -2: + WFIFOB(fd,2) = 0xFF; + break; + case -3: + WFIFOB(fd,2) = 0x01; + break; + } + WFIFOSET(fd,3); + } else { + int len; + // retrieve data + struct mmo_charstatus char_dat; + mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed. + + // send to player + WFIFOHEAD(fd,2+MAX_CHAR_BUF); + WFIFOW(fd,0) = 0x6d; + len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat); + WFIFOSET(fd,len); + + // add new entry to the chars list + ARR_FIND(0, MAX_CHARS, ch, sd->found_char[ch] == -1); + if (ch < MAX_CHARS) + sd->found_char[ch] = i; // the char_id of the new char + } #if PACKETVER >= 20120307 - RFIFOSKIP(fd,31); + RFIFOSKIP(fd,31); #else - RFIFOSKIP(fd,37); + RFIFOSKIP(fd,37); #endif - break; - - // delete char - case 0x68: - // 2004-04-19aSakexe+ langtype 12 char deletion packet - case 0x1fb: - if (cmd == 0x68) FIFOSD_CHECK(46); - if (cmd == 0x1fb) FIFOSD_CHECK(56); - { - int cid = RFIFOL(fd,2); - - ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid); - memcpy(email, RFIFOP(fd,6), 40); - RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56); - - // Check if e-mail is correct - if(strcmpi(email, sd->email) && //email does not matches and - ( - strcmp("a@a.com", sd->email) || //it is not default email, or - (strcmp("a@a.com", email) && strcmp("", email)) //email sent does not matches default - )) { //Fail - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; // 00 = Incorrect Email address - WFIFOSET(fd,3); - break; - } - - // check if this char exists - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid ); - if( i == MAX_CHARS ) - { // Such a character does not exist in the account - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - break; - } - - // remove char from list and compact it - for(ch = i; ch < MAX_CHARS-1; ch++) - sd->found_char[ch] = sd->found_char[ch+1]; - sd->found_char[MAX_CHARS-1] = -1; - - /* Delete character */ - if(delete_char_sql(cid)<0){ - //can't delete the char - //either SQL error or can't delete by some CONFIG conditions - //del fail - WFIFOHEAD(fd,3); - WFIFOW(fd, 0) = 0x70; - WFIFOB(fd, 2) = 0; - WFIFOSET(fd, 3); - break; - } - /* Char successfully deleted.*/ - WFIFOHEAD(fd,2); - WFIFOW(fd,0) = 0x6f; - WFIFOSET(fd,2); - } - break; - - // client keep-alive packet (every 12 seconds) - // R 0187 .l - case 0x187: - if (RFIFOREST(fd) < 6) - return 0; - RFIFOSKIP(fd,6); - break; - - // char rename request - // R 028d .l .l .24B - case 0x28d: - FIFOSD_CHECK(34); - { - int i, aid = RFIFOL(fd,2), cid =RFIFOL(fd,6); - char name[NAME_LENGTH]; - char esc_name[NAME_LENGTH*2+1]; - safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH); - RFIFOSKIP(fd,34); - - if( aid != sd->account_id ) - break; - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid ); - if( i == MAX_CHARS ) - break; - - normalize_name(name,TRIM_CHARS); - Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - if( !check_char_name(name,esc_name) ) - { - i = 1; - safestrncpy(sd->new_name, name, NAME_LENGTH); - } - else - i = 0; - - WFIFOHEAD(fd, 4); - WFIFOW(fd,0) = 0x28e; - WFIFOW(fd,2) = i; - WFIFOSET(fd,4); - } - break; - //Confirm change name. - // 0x28f .L - case 0x28f: - // 0: Sucessfull - // 1: This character's name has already been changed. You cannot change a character's name more than once. - // 2: User information is not correct. - // 3: You have failed to change this character's name. - // 4: Another user is using this character name, so please select another one. - FIFOSD_CHECK(6); - { - int i; - int cid = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid ); - if( i == MAX_CHARS ) - break; - i = rename_char_sql(sd, cid); - - WFIFOHEAD(fd, 4); - WFIFOW(fd,0) = 0x290; - WFIFOW(fd,2) = i; - WFIFOSET(fd,4); - } - break; - - // captcha code request (not implemented) - // R 07e5 .w .l - case 0x7e5: - WFIFOHEAD(fd,5); - WFIFOW(fd,0) = 0x7e9; - WFIFOW(fd,2) = 5; - WFIFOB(fd,4) = 1; - WFIFOSET(fd,5); - RFIFOSKIP(fd,8); - break; - - // captcha code check (not implemented) - // R 07e7 .w .l .b10 .b14 - case 0x7e7: - WFIFOHEAD(fd,5); - WFIFOW(fd,0) = 0x7e9; - WFIFOW(fd,2) = 5; - WFIFOB(fd,4) = 1; - WFIFOSET(fd,5); - RFIFOSKIP(fd,32); - break; - - // deletion timer request - case 0x827: - FIFOSD_CHECK(6); - char_delete2_req(fd, sd); - RFIFOSKIP(fd,6); - break; - - // deletion accept request - case 0x829: - FIFOSD_CHECK(12); - char_delete2_accept(fd, sd); - RFIFOSKIP(fd,12); - break; - - // deletion cancel request - case 0x82b: - FIFOSD_CHECK(6); - char_delete2_cancel(fd, sd); - RFIFOSKIP(fd,6); - break; - - // login as map-server - case 0x2af8: - if (RFIFOREST(fd) < 60) - return 0; - { - char* l_user = (char*)RFIFOP(fd,2); - char* l_pass = (char*)RFIFOP(fd,26); - l_user[23] = '\0'; - l_pass[23] = '\0'; - ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd <= 0 ); - if( runflag != CHARSERVER_ST_RUNNING || - i == ARRAYLENGTH(server) || - strcmp(l_user, userid) != 0 || - strcmp(l_pass, passwd) != 0 ) - { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x2af9; - WFIFOB(fd,2) = 3; - WFIFOSET(fd,3); - } else { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x2af9; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - - server[i].fd = fd; - server[i].ip = ntohl(RFIFOL(fd,54)); - server[i].port = ntohs(RFIFOW(fd,58)); - server[i].users = 0; - memset(server[i].map, 0, sizeof(server[i].map)); - session[fd]->func_parse = parse_frommap; - session[fd]->flag.server = 1; - realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); - char_mapif_init(fd); - } - - RFIFOSKIP(fd,60); - } - return 0; // avoid processing of followup packets here - - // unknown packet received - default: - ShowError("parse_char: Received unknown packet "CL_WHITE"0x%x"CL_RESET" from ip '"CL_WHITE"%s"CL_RESET"'! Disconnecting!\n", RFIFOW(fd,0), ip2str(ipl, NULL)); - set_eof(fd); - return 0; - } - } - - RFIFOFLUSH(fd); - return 0; + break; + + // delete char + case 0x68: + // 2004-04-19aSakexe+ langtype 12 char deletion packet + case 0x1fb: + if (cmd == 0x68) FIFOSD_CHECK(46); + if (cmd == 0x1fb) FIFOSD_CHECK(56); + { + int cid = RFIFOL(fd,2); + + ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid); + memcpy(email, RFIFOP(fd,6), 40); + RFIFOSKIP(fd,(cmd == 0x68) ? 46 : 56); + + // Check if e-mail is correct + if (strcmpi(email, sd->email) && //email does not matches and + ( + strcmp("a@a.com", sd->email) || //it is not default email, or + (strcmp("a@a.com", email) && strcmp("", email)) //email sent does not matches default + )) { //Fail + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x70; + WFIFOB(fd,2) = 0; // 00 = Incorrect Email address + WFIFOSET(fd,3); + break; + } + + // check if this char exists + ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == cid); + if (i == MAX_CHARS) { + // Such a character does not exist in the account + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x70; + WFIFOB(fd,2) = 0; + WFIFOSET(fd,3); + break; + } + + // remove char from list and compact it + for (ch = i; ch < MAX_CHARS-1; ch++) + sd->found_char[ch] = sd->found_char[ch+1]; + sd->found_char[MAX_CHARS-1] = -1; + + /* Delete character */ + if (delete_char_sql(cid)<0) { + //can't delete the char + //either SQL error or can't delete by some CONFIG conditions + //del fail + WFIFOHEAD(fd,3); + WFIFOW(fd, 0) = 0x70; + WFIFOB(fd, 2) = 0; + WFIFOSET(fd, 3); + break; + } + /* Char successfully deleted.*/ + WFIFOHEAD(fd,2); + WFIFOW(fd,0) = 0x6f; + WFIFOSET(fd,2); + } + break; + + // client keep-alive packet (every 12 seconds) + // R 0187 .l + case 0x187: + if (RFIFOREST(fd) < 6) + return 0; + RFIFOSKIP(fd,6); + break; + + // char rename request + // R 028d .l .l .24B + case 0x28d: + FIFOSD_CHECK(34); + { + int i, aid = RFIFOL(fd,2), cid =RFIFOL(fd,6); + char name[NAME_LENGTH]; + char esc_name[NAME_LENGTH*2+1]; + safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH); + RFIFOSKIP(fd,34); + + if (aid != sd->account_id) + break; + ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == cid); + if (i == MAX_CHARS) + break; + + normalize_name(name,TRIM_CHARS); + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + if (!check_char_name(name,esc_name)) { + i = 1; + safestrncpy(sd->new_name, name, NAME_LENGTH); + } else + i = 0; + + WFIFOHEAD(fd, 4); + WFIFOW(fd,0) = 0x28e; + WFIFOW(fd,2) = i; + WFIFOSET(fd,4); + } + break; + //Confirm change name. + // 0x28f .L + case 0x28f: + // 0: Sucessfull + // 1: This character's name has already been changed. You cannot change a character's name more than once. + // 2: User information is not correct. + // 3: You have failed to change this character's name. + // 4: Another user is using this character name, so please select another one. + FIFOSD_CHECK(6); + { + int i; + int cid = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == cid); + if (i == MAX_CHARS) + break; + i = rename_char_sql(sd, cid); + + WFIFOHEAD(fd, 4); + WFIFOW(fd,0) = 0x290; + WFIFOW(fd,2) = i; + WFIFOSET(fd,4); + } + break; + + // captcha code request (not implemented) + // R 07e5 .w .l + case 0x7e5: + WFIFOHEAD(fd,5); + WFIFOW(fd,0) = 0x7e9; + WFIFOW(fd,2) = 5; + WFIFOB(fd,4) = 1; + WFIFOSET(fd,5); + RFIFOSKIP(fd,8); + break; + + // captcha code check (not implemented) + // R 07e7 .w .l .b10 .b14 + case 0x7e7: + WFIFOHEAD(fd,5); + WFIFOW(fd,0) = 0x7e9; + WFIFOW(fd,2) = 5; + WFIFOB(fd,4) = 1; + WFIFOSET(fd,5); + RFIFOSKIP(fd,32); + break; + + // deletion timer request + case 0x827: + FIFOSD_CHECK(6); + char_delete2_req(fd, sd); + RFIFOSKIP(fd,6); + break; + + // deletion accept request + case 0x829: + FIFOSD_CHECK(12); + char_delete2_accept(fd, sd); + RFIFOSKIP(fd,12); + break; + + // deletion cancel request + case 0x82b: + FIFOSD_CHECK(6); + char_delete2_cancel(fd, sd); + RFIFOSKIP(fd,6); + break; + + // login as map-server + case 0x2af8: + if (RFIFOREST(fd) < 60) + return 0; + { + char *l_user = (char *)RFIFOP(fd,2); + char *l_pass = (char *)RFIFOP(fd,26); + l_user[23] = '\0'; + l_pass[23] = '\0'; + ARR_FIND(0, ARRAYLENGTH(server), i, server[i].fd <= 0); + if (runflag != CHARSERVER_ST_RUNNING || + i == ARRAYLENGTH(server) || + strcmp(l_user, userid) != 0 || + strcmp(l_pass, passwd) != 0) { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x2af9; + WFIFOB(fd,2) = 3; + WFIFOSET(fd,3); + } else { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x2af9; + WFIFOB(fd,2) = 0; + WFIFOSET(fd,3); + + server[i].fd = fd; + server[i].ip = ntohl(RFIFOL(fd,54)); + server[i].port = ntohs(RFIFOW(fd,58)); + server[i].users = 0; + memset(server[i].map, 0, sizeof(server[i].map)); + session[fd]->func_parse = parse_frommap; + session[fd]->flag.server = 1; + realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); + char_mapif_init(fd); + } + + RFIFOSKIP(fd,60); + } + return 0; // avoid processing of followup packets here + + // unknown packet received + default: + ShowError("parse_char: Received unknown packet "CL_WHITE"0x%x"CL_RESET" from ip '"CL_WHITE"%s"CL_RESET"'! Disconnecting!\n", RFIFOW(fd,0), ip2str(ipl, NULL)); + set_eof(fd); + return 0; + } + } + + RFIFOFLUSH(fd); + return 0; } // Console Command Parser [Wizputer] -int parse_console(const char* command) +int parse_console(const char *command) { - ShowNotice("Console command: %s\n", command); - - if( strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 || strcmpi("end", command) == 0 ) - runflag = 0; - else if( strcmpi("alive", command) == 0 || strcmpi("status", command) == 0 ) - ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); - else if( strcmpi("help", command) == 0 ) - { - ShowInfo("To shutdown the server:\n"); - ShowInfo(" 'shutdown|exit|quit|end'\n"); - ShowInfo("To know if server is alive:\n"); - ShowInfo(" 'alive|status'\n"); - } - - return 0; + ShowNotice("Console command: %s\n", command); + + if (strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 || strcmpi("end", command) == 0) + runflag = 0; + else if (strcmpi("alive", command) == 0 || strcmpi("status", command) == 0) + ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); + else if (strcmpi("help", command) == 0) { + ShowInfo("To shutdown the server:\n"); + ShowInfo(" 'shutdown|exit|quit|end'\n"); + ShowInfo("To know if server is alive:\n"); + ShowInfo(" 'alive|status'\n"); + } + + return 0; } int mapif_sendall(unsigned char *buf, unsigned int len) { - int i, c; - - c = 0; - for(i = 0; i < ARRAYLENGTH(server); i++) { - int fd; - if ((fd = server[i].fd) > 0) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - c++; - } - } - - return c; + int i, c; + + c = 0; + for (i = 0; i < ARRAYLENGTH(server); i++) { + int fd; + if ((fd = server[i].fd) > 0) { + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + c++; + } + } + + return c; } int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len) { - int i, c; - - c = 0; - for(i = 0; i < ARRAYLENGTH(server); i++) { - int fd; - if ((fd = server[i].fd) > 0 && fd != sfd) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - c++; - } - } - - return c; + int i, c; + + c = 0; + for (i = 0; i < ARRAYLENGTH(server); i++) { + int fd; + if ((fd = server[i].fd) > 0 && fd != sfd) { + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + c++; + } + } + + return c; } int mapif_send(int fd, unsigned char *buf, unsigned int len) { - if (fd >= 0) { - int i; - ARR_FIND( 0, ARRAYLENGTH(server), i, fd == server[i].fd ); - if( i < ARRAYLENGTH(server) ) - { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - return 1; - } - } - return 0; + if (fd >= 0) { + int i; + ARR_FIND(0, ARRAYLENGTH(server), i, fd == server[i].fd); + if (i < ARRAYLENGTH(server)) { + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + return 1; + } + } + return 0; } int broadcast_user_count(int tid, unsigned int tick, int id, intptr_t data) { - uint8 buf[6]; - int users = count_users(); - - // only send an update when needed - static int prev_users = 0; - if( prev_users == users ) - return 0; - prev_users = users; - - if( login_fd > 0 && session[login_fd] ) - { - // send number of user to login server - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x2714; - WFIFOL(login_fd,2) = users; - WFIFOSET(login_fd,6); - } - - // send number of players to all map-servers - WBUFW(buf,0) = 0x2b00; - WBUFL(buf,2) = users; - mapif_sendall(buf,6); - - return 0; + uint8 buf[6]; + int users = count_users(); + + // only send an update when needed + static int prev_users = 0; + if (prev_users == users) + return 0; + prev_users = users; + + if (login_fd > 0 && session[login_fd]) { + // send number of user to login server + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x2714; + WFIFOL(login_fd,2) = users; + WFIFOSET(login_fd,6); + } + + // send number of players to all map-servers + WBUFW(buf,0) = 0x2b00; + WBUFL(buf,2) = users; + mapif_sendall(buf,6); + + return 0; } /** @@ -4236,66 +4175,64 @@ int broadcast_user_count(int tid, unsigned int tick, int id, intptr_t data) */ static int send_accounts_tologin_sub(DBKey key, DBData *data, va_list ap) { - struct online_char_data* character = db_data2ptr(data); - int* i = va_arg(ap, int*); - - if(character->server > -1) - { - WFIFOL(login_fd,8+(*i)*4) = character->account_id; - (*i)++; - return 1; - } - return 0; + struct online_char_data *character = db_data2ptr(data); + int *i = va_arg(ap, int *); + + if (character->server > -1) { + WFIFOL(login_fd,8+(*i)*4) = character->account_id; + (*i)++; + return 1; + } + return 0; } int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data) { - if (login_fd > 0 && session[login_fd]) - { - // send account list to login server - int users = online_char_db->size(online_char_db); - int i = 0; - - WFIFOHEAD(login_fd,8+users*4); - WFIFOW(login_fd,0) = 0x272d; - online_char_db->foreach(online_char_db, send_accounts_tologin_sub, &i, users); - WFIFOW(login_fd,2) = 8+ i*4; - WFIFOL(login_fd,4) = i; - WFIFOSET(login_fd,WFIFOW(login_fd,2)); - } - return 0; + if (login_fd > 0 && session[login_fd]) { + // send account list to login server + int users = online_char_db->size(online_char_db); + int i = 0; + + WFIFOHEAD(login_fd,8+users*4); + WFIFOW(login_fd,0) = 0x272d; + online_char_db->foreach(online_char_db, send_accounts_tologin_sub, &i, users); + WFIFOW(login_fd,2) = 8+ i*4; + WFIFOL(login_fd,4) = i; + WFIFOSET(login_fd,WFIFOW(login_fd,2)); + } + return 0; } int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data) { - if (login_fd > 0 && session[login_fd] != NULL) - return 0; - - ShowInfo("Attempt to connect to login-server...\n"); - login_fd = make_connection(login_ip, login_port, false); - if (login_fd == -1) - { //Try again later. [Skotlex] - login_fd = 0; - return 0; - } - session[login_fd]->func_parse = parse_fromlogin; - session[login_fd]->flag.server = 1; - realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); - - WFIFOHEAD(login_fd,86); - WFIFOW(login_fd,0) = 0x2710; - memcpy(WFIFOP(login_fd,2), userid, 24); - memcpy(WFIFOP(login_fd,26), passwd, 24); - WFIFOL(login_fd,50) = 0; - WFIFOL(login_fd,54) = htonl(char_ip); - WFIFOW(login_fd,58) = htons(char_port); - memcpy(WFIFOP(login_fd,60), server_name, 20); - WFIFOW(login_fd,80) = 0; - WFIFOW(login_fd,82) = char_maintenance; - WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin] - WFIFOSET(login_fd,86); - - return 1; + if (login_fd > 0 && session[login_fd] != NULL) + return 0; + + ShowInfo("Attempt to connect to login-server...\n"); + login_fd = make_connection(login_ip, login_port, false); + if (login_fd == -1) { + //Try again later. [Skotlex] + login_fd = 0; + return 0; + } + session[login_fd]->func_parse = parse_fromlogin; + session[login_fd]->flag.server = 1; + realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); + + WFIFOHEAD(login_fd,86); + WFIFOW(login_fd,0) = 0x2710; + memcpy(WFIFOP(login_fd,2), userid, 24); + memcpy(WFIFOP(login_fd,26), passwd, 24); + WFIFOL(login_fd,50) = 0; + WFIFOL(login_fd,54) = htonl(char_ip); + WFIFOW(login_fd,58) = htons(char_port); + memcpy(WFIFOP(login_fd,60), server_name, 20); + WFIFOW(login_fd,80) = 0; + WFIFOW(login_fd,82) = char_maintenance; + WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin] + WFIFOSET(login_fd,86); + + return 1; } //------------------------------------------------ @@ -4304,13 +4241,13 @@ int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data //------------------------------------------------ static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data) { - struct online_char_data* character; - if ((character = (struct online_char_data*)idb_get(online_char_db, id)) != NULL && character->waiting_disconnect == tid) - { //Mark it offline due to timeout. - character->waiting_disconnect = INVALID_TIMER; - set_char_offline(character->char_id, character->account_id); - } - return 0; + struct online_char_data *character; + if ((character = (struct online_char_data *)idb_get(online_char_db, id)) != NULL && character->waiting_disconnect == tid) { + //Mark it offline due to timeout. + character->waiting_disconnect = INVALID_TIMER; + set_char_offline(character->char_id, character->account_id); + } + return 0; } /** @@ -4318,21 +4255,21 @@ static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_ */ static int online_data_cleanup_sub(DBKey key, DBData *data, va_list ap) { - struct online_char_data *character= db_data2ptr(data); - if (character->fd != -1) - return 0; //Character still connected - if (character->server == -2) //Unknown server.. set them offline - set_char_offline(character->char_id, character->account_id); - if (character->server < 0) - //Free data from players that have not been online for a while. - db_remove(online_char_db, key); - return 0; + struct online_char_data *character= db_data2ptr(data); + if (character->fd != -1) + return 0; //Character still connected + if (character->server == -2) //Unknown server.. set them offline + set_char_offline(character->char_id, character->account_id); + if (character->server < 0) + //Free data from players that have not been online for a while. + db_remove(online_char_db, key); + return 0; } static int online_data_cleanup(int tid, unsigned int tick, int id, intptr_t data) { - online_char_db->foreach(online_char_db, online_data_cleanup_sub); - return 0; + online_char_db->foreach(online_char_db, online_data_cleanup_sub); + return 0; } //---------------------------------- @@ -4341,327 +4278,323 @@ static int online_data_cleanup(int tid, unsigned int tick, int id, intptr_t data //---------------------------------- int char_lan_config_read(const char *lancfgName) { - FILE *fp; - int line_num = 0; - char line[1024], w1[64], w2[64], w3[64], w4[64]; - - if((fp = fopen(lancfgName, "r")) == NULL) { - ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName); - return 1; - } - - while(fgets(line, sizeof(line), fp)) { - line_num++; - if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n') - continue; - - if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) { - - ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num); - continue; - } - - remove_control_chars(w1); - remove_control_chars(w2); - remove_control_chars(w3); - remove_control_chars(w4); - - if( strcmpi(w1, "subnet") == 0 ) - { - subnet[subnet_count].mask = str2ip(w2); - subnet[subnet_count].char_ip = str2ip(w3); - subnet[subnet_count].map_ip = str2ip(w4); - - if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) ) - { - ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4); - continue; - } - - subnet_count++; - } - } - - if( subnet_count > 1 ) /* only useful if there is more than 1 */ - ShowStatus("Read information about %d subnetworks.\n", subnet_count); - - fclose(fp); - return 0; + FILE *fp; + int line_num = 0; + char line[1024], w1[64], w2[64], w3[64], w4[64]; + + if ((fp = fopen(lancfgName, "r")) == NULL) { + ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName); + return 1; + } + + while (fgets(line, sizeof(line), fp)) { + line_num++; + if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n') + continue; + + if (sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) { + + ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num); + continue; + } + + remove_control_chars(w1); + remove_control_chars(w2); + remove_control_chars(w3); + remove_control_chars(w4); + + if (strcmpi(w1, "subnet") == 0) { + subnet[subnet_count].mask = str2ip(w2); + subnet[subnet_count].char_ip = str2ip(w3); + subnet[subnet_count].map_ip = str2ip(w4); + + if ((subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask)) { + ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4); + continue; + } + + subnet_count++; + } + } + + if (subnet_count > 1) /* only useful if there is more than 1 */ + ShowStatus("Read information about %d subnetworks.\n", subnet_count); + + fclose(fp); + return 0; } -void sql_config_read(const char* cfgName) +void sql_config_read(const char *cfgName) { - char line[1024], w1[1024], w2[1024]; - FILE* fp; - - if ((fp = fopen(cfgName, "r")) == NULL) { - ShowError("File not found: %s\n", cfgName); - return; - } - - while(fgets(line, sizeof(line), fp)) - { - if(line[0] == '/' && line[1] == '/') - continue; - - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - if(!strcmpi(w1,"char_db")) - safestrncpy(char_db, w2, sizeof(char_db)); - else if(!strcmpi(w1,"scdata_db")) - safestrncpy(scdata_db, w2, sizeof(scdata_db)); - else if(!strcmpi(w1,"cart_db")) - safestrncpy(cart_db, w2, sizeof(cart_db)); - else if(!strcmpi(w1,"inventory_db")) - safestrncpy(inventory_db, w2, sizeof(inventory_db)); - else if(!strcmpi(w1,"charlog_db")) - safestrncpy(charlog_db, w2, sizeof(charlog_db)); - else if(!strcmpi(w1,"storage_db")) - safestrncpy(storage_db, w2, sizeof(storage_db)); - else if(!strcmpi(w1,"reg_db")) - safestrncpy(reg_db, w2, sizeof(reg_db)); - else if(!strcmpi(w1,"skill_db")) - safestrncpy(skill_db, w2, sizeof(skill_db)); - else if(!strcmpi(w1,"interlog_db")) - safestrncpy(interlog_db, w2, sizeof(interlog_db)); - else if(!strcmpi(w1,"memo_db")) - safestrncpy(memo_db, w2, sizeof(memo_db)); - else if(!strcmpi(w1,"guild_db")) - safestrncpy(guild_db, w2, sizeof(guild_db)); - else if(!strcmpi(w1,"guild_alliance_db")) - safestrncpy(guild_alliance_db, w2, sizeof(guild_alliance_db)); - else if(!strcmpi(w1,"guild_castle_db")) - safestrncpy(guild_castle_db, w2, sizeof(guild_castle_db)); - else if(!strcmpi(w1,"guild_expulsion_db")) - safestrncpy(guild_expulsion_db, w2, sizeof(guild_expulsion_db)); - else if(!strcmpi(w1,"guild_member_db")) - safestrncpy(guild_member_db, w2, sizeof(guild_member_db)); - else if(!strcmpi(w1,"guild_skill_db")) - safestrncpy(guild_skill_db, w2, sizeof(guild_skill_db)); - else if(!strcmpi(w1,"guild_position_db")) - safestrncpy(guild_position_db, w2, sizeof(guild_position_db)); - else if(!strcmpi(w1,"guild_storage_db")) - safestrncpy(guild_storage_db, w2, sizeof(guild_storage_db)); - else if(!strcmpi(w1,"party_db")) - safestrncpy(party_db, w2, sizeof(party_db)); - else if(!strcmpi(w1,"pet_db")) - safestrncpy(pet_db, w2, sizeof(pet_db)); - else if(!strcmpi(w1,"mail_db")) - safestrncpy(mail_db, w2, sizeof(mail_db)); - else if(!strcmpi(w1,"auction_db")) - safestrncpy(auction_db, w2, sizeof(auction_db)); - else if(!strcmpi(w1,"friend_db")) - safestrncpy(friend_db, w2, sizeof(friend_db)); - else if(!strcmpi(w1,"hotkey_db")) - safestrncpy(hotkey_db, w2, sizeof(hotkey_db)); - else if(!strcmpi(w1,"quest_db")) - safestrncpy(quest_db,w2,sizeof(quest_db)); - else if(!strcmpi(w1,"homunculus_db")) - safestrncpy(homunculus_db,w2,sizeof(homunculus_db)); - else if(!strcmpi(w1,"skill_homunculus_db")) - safestrncpy(skill_homunculus_db,w2,sizeof(skill_homunculus_db)); - else if(!strcmpi(w1,"mercenary_db")) - safestrncpy(mercenary_db,w2,sizeof(mercenary_db)); - else if(!strcmpi(w1,"mercenary_owner_db")) - safestrncpy(mercenary_owner_db,w2,sizeof(mercenary_owner_db)); - //support the import command, just like any other config - else if(!strcmpi(w1,"import")) - sql_config_read(w2); - } - fclose(fp); - ShowInfo("Done reading %s.\n", cfgName); + char line[1024], w1[1024], w2[1024]; + FILE *fp; + + if ((fp = fopen(cfgName, "r")) == NULL) { + ShowError("File not found: %s\n", cfgName); + return; + } + + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') + continue; + + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + if (!strcmpi(w1,"char_db")) + safestrncpy(char_db, w2, sizeof(char_db)); + else if (!strcmpi(w1,"scdata_db")) + safestrncpy(scdata_db, w2, sizeof(scdata_db)); + else if (!strcmpi(w1,"cart_db")) + safestrncpy(cart_db, w2, sizeof(cart_db)); + else if (!strcmpi(w1,"inventory_db")) + safestrncpy(inventory_db, w2, sizeof(inventory_db)); + else if (!strcmpi(w1,"charlog_db")) + safestrncpy(charlog_db, w2, sizeof(charlog_db)); + else if (!strcmpi(w1,"storage_db")) + safestrncpy(storage_db, w2, sizeof(storage_db)); + else if (!strcmpi(w1,"reg_db")) + safestrncpy(reg_db, w2, sizeof(reg_db)); + else if (!strcmpi(w1,"skill_db")) + safestrncpy(skill_db, w2, sizeof(skill_db)); + else if (!strcmpi(w1,"interlog_db")) + safestrncpy(interlog_db, w2, sizeof(interlog_db)); + else if (!strcmpi(w1,"memo_db")) + safestrncpy(memo_db, w2, sizeof(memo_db)); + else if (!strcmpi(w1,"guild_db")) + safestrncpy(guild_db, w2, sizeof(guild_db)); + else if (!strcmpi(w1,"guild_alliance_db")) + safestrncpy(guild_alliance_db, w2, sizeof(guild_alliance_db)); + else if (!strcmpi(w1,"guild_castle_db")) + safestrncpy(guild_castle_db, w2, sizeof(guild_castle_db)); + else if (!strcmpi(w1,"guild_expulsion_db")) + safestrncpy(guild_expulsion_db, w2, sizeof(guild_expulsion_db)); + else if (!strcmpi(w1,"guild_member_db")) + safestrncpy(guild_member_db, w2, sizeof(guild_member_db)); + else if (!strcmpi(w1,"guild_skill_db")) + safestrncpy(guild_skill_db, w2, sizeof(guild_skill_db)); + else if (!strcmpi(w1,"guild_position_db")) + safestrncpy(guild_position_db, w2, sizeof(guild_position_db)); + else if (!strcmpi(w1,"guild_storage_db")) + safestrncpy(guild_storage_db, w2, sizeof(guild_storage_db)); + else if (!strcmpi(w1,"party_db")) + safestrncpy(party_db, w2, sizeof(party_db)); + else if (!strcmpi(w1,"pet_db")) + safestrncpy(pet_db, w2, sizeof(pet_db)); + else if (!strcmpi(w1,"mail_db")) + safestrncpy(mail_db, w2, sizeof(mail_db)); + else if (!strcmpi(w1,"auction_db")) + safestrncpy(auction_db, w2, sizeof(auction_db)); + else if (!strcmpi(w1,"friend_db")) + safestrncpy(friend_db, w2, sizeof(friend_db)); + else if (!strcmpi(w1,"hotkey_db")) + safestrncpy(hotkey_db, w2, sizeof(hotkey_db)); + else if (!strcmpi(w1,"quest_db")) + safestrncpy(quest_db,w2,sizeof(quest_db)); + else if (!strcmpi(w1,"homunculus_db")) + safestrncpy(homunculus_db,w2,sizeof(homunculus_db)); + else if (!strcmpi(w1,"skill_homunculus_db")) + safestrncpy(skill_homunculus_db,w2,sizeof(skill_homunculus_db)); + else if (!strcmpi(w1,"mercenary_db")) + safestrncpy(mercenary_db,w2,sizeof(mercenary_db)); + else if (!strcmpi(w1,"mercenary_owner_db")) + safestrncpy(mercenary_owner_db,w2,sizeof(mercenary_owner_db)); + //support the import command, just like any other config + else if (!strcmpi(w1,"import")) + sql_config_read(w2); + } + fclose(fp); + ShowInfo("Done reading %s.\n", cfgName); } -int char_config_read(const char* cfgName) +int char_config_read(const char *cfgName) { - char line[1024], w1[1024], w2[1024]; - FILE* fp = fopen(cfgName, "r"); - - if (fp == NULL) { - ShowError("Configuration file not found: %s.\n", cfgName); - return 1; - } - - while(fgets(line, sizeof(line), fp)) { - if (line[0] == '/' && line[1] == '/') - continue; - - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - remove_control_chars(w1); - remove_control_chars(w2); - if(strcmpi(w1,"timestamp_format") == 0) { - safestrncpy(timestamp_format, w2, sizeof(timestamp_format)); - } else if(strcmpi(w1,"console_silent")==0){ - msg_silent = atoi(w2); - if( msg_silent ) /* only bother if its actually enabled */ - ShowInfo("Console Silent Setting: %d\n", atoi(w2)); - } else if(strcmpi(w1,"stdout_with_ansisequence")==0){ - stdout_with_ansisequence = config_switch(w2); - } else if (strcmpi(w1, "userid") == 0) { - safestrncpy(userid, w2, sizeof(userid)); - } else if (strcmpi(w1, "passwd") == 0) { - safestrncpy(passwd, w2, sizeof(passwd)); - } else if (strcmpi(w1, "server_name") == 0) { - safestrncpy(server_name, w2, sizeof(server_name)); - } else if (strcmpi(w1, "wisp_server_name") == 0) { - if (strlen(w2) >= 4) { - safestrncpy(wisp_server_name, w2, sizeof(wisp_server_name)); - } - } else if (strcmpi(w1, "login_ip") == 0) { - char ip_str[16]; - login_ip = host2ip(w2); - if (login_ip) { - safestrncpy(login_ip_str, w2, sizeof(login_ip_str)); - ShowStatus("Login server IP address : %s -> %s\n", w2, ip2str(login_ip, ip_str)); - } - } else if (strcmpi(w1, "login_port") == 0) { - login_port = atoi(w2); - } else if (strcmpi(w1, "char_ip") == 0) { - char ip_str[16]; - char_ip = host2ip(w2); - if (char_ip){ - safestrncpy(char_ip_str, w2, sizeof(char_ip_str)); - ShowStatus("Character server IP address : %s -> %s\n", w2, ip2str(char_ip, ip_str)); - } - } else if (strcmpi(w1, "bind_ip") == 0) { - char ip_str[16]; - bind_ip = host2ip(w2); - if (bind_ip) { - safestrncpy(bind_ip_str, w2, sizeof(bind_ip_str)); - ShowStatus("Character server binding IP address : %s -> %s\n", w2, ip2str(bind_ip, ip_str)); - } - } else if (strcmpi(w1, "char_port") == 0) { - char_port = atoi(w2); - } else if (strcmpi(w1, "char_maintenance") == 0) { - char_maintenance = atoi(w2); - } else if (strcmpi(w1, "char_new") == 0) { - char_new = (bool)atoi(w2); - } else if (strcmpi(w1, "char_new_display") == 0) { - char_new_display = atoi(w2); - } else if (strcmpi(w1, "max_connect_user") == 0) { - max_connect_user = atoi(w2); - if (max_connect_user < 0) - max_connect_user = 0; // unlimited online players - } else if(strcmpi(w1, "gm_allow_group") == 0) { - gm_allow_group = atoi(w2); - } else if (strcmpi(w1, "autosave_time") == 0) { - autosave_interval = atoi(w2)*1000; - if (autosave_interval <= 0) - autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; - } else if (strcmpi(w1, "save_log") == 0) { - save_log = config_switch(w2); - } else if (strcmpi(w1, "start_point") == 0) { - char map[MAP_NAME_LENGTH_EXT]; - int x, y; - if (sscanf(w2, "%15[^,],%d,%d", map, &x, &y) < 3) - continue; - start_point.map = mapindex_name2id(map); - if (!start_point.map) - ShowError("Specified start_point %s not found in map-index cache.\n", map); - start_point.x = x; - start_point.y = y; - } else if (strcmpi(w1, "start_zeny") == 0) { - start_zeny = atoi(w2); - if (start_zeny < 0) - start_zeny = 0; - } else if (strcmpi(w1, "start_weapon") == 0) { - start_weapon = atoi(w2); - if (start_weapon < 0) - start_weapon = 0; - } else if (strcmpi(w1, "start_armor") == 0) { - start_armor = atoi(w2); - if (start_armor < 0) - start_armor = 0; - } else if(strcmpi(w1,"log_char")==0) { //log char or not [devil] - log_char = atoi(w2); - } else if (strcmpi(w1, "unknown_char_name") == 0) { - safestrncpy(unknown_char_name, w2, sizeof(unknown_char_name)); - unknown_char_name[NAME_LENGTH-1] = '\0'; - } else if (strcmpi(w1, "name_ignoring_case") == 0) { - name_ignoring_case = (bool)config_switch(w2); - } else if (strcmpi(w1, "char_name_option") == 0) { - char_name_option = atoi(w2); - } else if (strcmpi(w1, "char_name_letters") == 0) { - safestrncpy(char_name_letters, w2, sizeof(char_name_letters)); - } else if (strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius] - char_per_account = atoi(w2); - if( char_per_account == 0 || char_per_account > MAX_CHARS ) { - if( char_per_account > MAX_CHARS ) - ShowWarning("Max chars per account '%d' exceeded limit. Defaulting to '%d'.\n", char_per_account, MAX_CHARS); - char_per_account = MAX_CHARS; - } - } else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus] - char_del_level = atoi(w2); - } else if (strcmpi(w1, "char_del_delay") == 0) { - char_del_delay = atoi(w2); - } else if(strcmpi(w1,"db_path")==0) { - safestrncpy(db_path, w2, sizeof(db_path)); - } else if (strcmpi(w1, "console") == 0) { - console = config_switch(w2); - } else if (strcmpi(w1, "fame_list_alchemist") == 0) { - fame_list_size_chemist = atoi(w2); - if (fame_list_size_chemist > MAX_FAME_LIST) { - ShowWarning("Max fame list size is %d (fame_list_alchemist)\n", MAX_FAME_LIST); - fame_list_size_chemist = MAX_FAME_LIST; - } - } else if (strcmpi(w1, "fame_list_blacksmith") == 0) { - fame_list_size_smith = atoi(w2); - if (fame_list_size_smith > MAX_FAME_LIST) { - ShowWarning("Max fame list size is %d (fame_list_blacksmith)\n", MAX_FAME_LIST); - fame_list_size_smith = MAX_FAME_LIST; - } - } else if (strcmpi(w1, "fame_list_taekwon") == 0) { - fame_list_size_taekwon = atoi(w2); - if (fame_list_size_taekwon > MAX_FAME_LIST) { - ShowWarning("Max fame list size is %d (fame_list_taekwon)\n", MAX_FAME_LIST); - fame_list_size_taekwon = MAX_FAME_LIST; - } - } else if (strcmpi(w1, "guild_exp_rate") == 0) { - guild_exp_rate = atoi(w2); - } else if (strcmpi(w1, "import") == 0) { - char_config_read(w2); - } - } - fclose(fp); - - ShowInfo("Done reading %s.\n", cfgName); - return 0; + char line[1024], w1[1024], w2[1024]; + FILE *fp = fopen(cfgName, "r"); + + if (fp == NULL) { + ShowError("Configuration file not found: %s.\n", cfgName); + return 1; + } + + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') + continue; + + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + remove_control_chars(w1); + remove_control_chars(w2); + if (strcmpi(w1,"timestamp_format") == 0) { + safestrncpy(timestamp_format, w2, sizeof(timestamp_format)); + } else if (strcmpi(w1,"console_silent")==0) { + msg_silent = atoi(w2); + if (msg_silent) /* only bother if its actually enabled */ + ShowInfo("Console Silent Setting: %d\n", atoi(w2)); + } else if (strcmpi(w1,"stdout_with_ansisequence")==0) { + stdout_with_ansisequence = config_switch(w2); + } else if (strcmpi(w1, "userid") == 0) { + safestrncpy(userid, w2, sizeof(userid)); + } else if (strcmpi(w1, "passwd") == 0) { + safestrncpy(passwd, w2, sizeof(passwd)); + } else if (strcmpi(w1, "server_name") == 0) { + safestrncpy(server_name, w2, sizeof(server_name)); + } else if (strcmpi(w1, "wisp_server_name") == 0) { + if (strlen(w2) >= 4) { + safestrncpy(wisp_server_name, w2, sizeof(wisp_server_name)); + } + } else if (strcmpi(w1, "login_ip") == 0) { + char ip_str[16]; + login_ip = host2ip(w2); + if (login_ip) { + safestrncpy(login_ip_str, w2, sizeof(login_ip_str)); + ShowStatus("Login server IP address : %s -> %s\n", w2, ip2str(login_ip, ip_str)); + } + } else if (strcmpi(w1, "login_port") == 0) { + login_port = atoi(w2); + } else if (strcmpi(w1, "char_ip") == 0) { + char ip_str[16]; + char_ip = host2ip(w2); + if (char_ip) { + safestrncpy(char_ip_str, w2, sizeof(char_ip_str)); + ShowStatus("Character server IP address : %s -> %s\n", w2, ip2str(char_ip, ip_str)); + } + } else if (strcmpi(w1, "bind_ip") == 0) { + char ip_str[16]; + bind_ip = host2ip(w2); + if (bind_ip) { + safestrncpy(bind_ip_str, w2, sizeof(bind_ip_str)); + ShowStatus("Character server binding IP address : %s -> %s\n", w2, ip2str(bind_ip, ip_str)); + } + } else if (strcmpi(w1, "char_port") == 0) { + char_port = atoi(w2); + } else if (strcmpi(w1, "char_maintenance") == 0) { + char_maintenance = atoi(w2); + } else if (strcmpi(w1, "char_new") == 0) { + char_new = (bool)atoi(w2); + } else if (strcmpi(w1, "char_new_display") == 0) { + char_new_display = atoi(w2); + } else if (strcmpi(w1, "max_connect_user") == 0) { + max_connect_user = atoi(w2); + if (max_connect_user < 0) + max_connect_user = 0; // unlimited online players + } else if (strcmpi(w1, "gm_allow_group") == 0) { + gm_allow_group = atoi(w2); + } else if (strcmpi(w1, "autosave_time") == 0) { + autosave_interval = atoi(w2)*1000; + if (autosave_interval <= 0) + autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; + } else if (strcmpi(w1, "save_log") == 0) { + save_log = config_switch(w2); + } else if (strcmpi(w1, "start_point") == 0) { + char map[MAP_NAME_LENGTH_EXT]; + int x, y; + if (sscanf(w2, "%15[^,],%d,%d", map, &x, &y) < 3) + continue; + start_point.map = mapindex_name2id(map); + if (!start_point.map) + ShowError("Specified start_point %s not found in map-index cache.\n", map); + start_point.x = x; + start_point.y = y; + } else if (strcmpi(w1, "start_zeny") == 0) { + start_zeny = atoi(w2); + if (start_zeny < 0) + start_zeny = 0; + } else if (strcmpi(w1, "start_weapon") == 0) { + start_weapon = atoi(w2); + if (start_weapon < 0) + start_weapon = 0; + } else if (strcmpi(w1, "start_armor") == 0) { + start_armor = atoi(w2); + if (start_armor < 0) + start_armor = 0; + } else if (strcmpi(w1,"log_char")==0) { //log char or not [devil] + log_char = atoi(w2); + } else if (strcmpi(w1, "unknown_char_name") == 0) { + safestrncpy(unknown_char_name, w2, sizeof(unknown_char_name)); + unknown_char_name[NAME_LENGTH-1] = '\0'; + } else if (strcmpi(w1, "name_ignoring_case") == 0) { + name_ignoring_case = (bool)config_switch(w2); + } else if (strcmpi(w1, "char_name_option") == 0) { + char_name_option = atoi(w2); + } else if (strcmpi(w1, "char_name_letters") == 0) { + safestrncpy(char_name_letters, w2, sizeof(char_name_letters)); + } else if (strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius] + char_per_account = atoi(w2); + if (char_per_account == 0 || char_per_account > MAX_CHARS) { + if (char_per_account > MAX_CHARS) + ShowWarning("Max chars per account '%d' exceeded limit. Defaulting to '%d'.\n", char_per_account, MAX_CHARS); + char_per_account = MAX_CHARS; + } + } else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus] + char_del_level = atoi(w2); + } else if (strcmpi(w1, "char_del_delay") == 0) { + char_del_delay = atoi(w2); + } else if (strcmpi(w1,"db_path")==0) { + safestrncpy(db_path, w2, sizeof(db_path)); + } else if (strcmpi(w1, "console") == 0) { + console = config_switch(w2); + } else if (strcmpi(w1, "fame_list_alchemist") == 0) { + fame_list_size_chemist = atoi(w2); + if (fame_list_size_chemist > MAX_FAME_LIST) { + ShowWarning("Max fame list size is %d (fame_list_alchemist)\n", MAX_FAME_LIST); + fame_list_size_chemist = MAX_FAME_LIST; + } + } else if (strcmpi(w1, "fame_list_blacksmith") == 0) { + fame_list_size_smith = atoi(w2); + if (fame_list_size_smith > MAX_FAME_LIST) { + ShowWarning("Max fame list size is %d (fame_list_blacksmith)\n", MAX_FAME_LIST); + fame_list_size_smith = MAX_FAME_LIST; + } + } else if (strcmpi(w1, "fame_list_taekwon") == 0) { + fame_list_size_taekwon = atoi(w2); + if (fame_list_size_taekwon > MAX_FAME_LIST) { + ShowWarning("Max fame list size is %d (fame_list_taekwon)\n", MAX_FAME_LIST); + fame_list_size_taekwon = MAX_FAME_LIST; + } + } else if (strcmpi(w1, "guild_exp_rate") == 0) { + guild_exp_rate = atoi(w2); + } else if (strcmpi(w1, "import") == 0) { + char_config_read(w2); + } + } + fclose(fp); + + ShowInfo("Done reading %s.\n", cfgName); + return 0; } void do_final(void) { - ShowStatus("Terminating...\n"); + ShowStatus("Terminating...\n"); + + set_all_offline(-1); + set_all_offline_sql(); - set_all_offline(-1); - set_all_offline_sql(); + inter_final(); - inter_final(); + flush_fifos(); - flush_fifos(); - - do_final_mapif(); - do_final_loginif(); + do_final_mapif(); + do_final_loginif(); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s`", ragsrvinfo_db) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s`", ragsrvinfo_db)) + Sql_ShowDebug(sql_handle); - char_db_->destroy(char_db_, NULL); - online_char_db->destroy(online_char_db, NULL); - auth_db->destroy(auth_db, NULL); + char_db_->destroy(char_db_, NULL); + online_char_db->destroy(online_char_db, NULL); + auth_db->destroy(auth_db, NULL); - if( char_fd != -1 ) - { - do_close(char_fd); - char_fd = -1; - } + if (char_fd != -1) { + do_close(char_fd); + char_fd = -1; + } - Sql_Free(sql_handle); - mapindex_final(); + Sql_Free(sql_handle); + mapindex_final(); - ShowStatus("Finished.\n"); + ShowStatus("Finished.\n"); } //------------------------------ @@ -4674,111 +4607,107 @@ void do_abort(void) void set_server_type(void) { - SERVER_TYPE = ATHENA_SERVER_CHAR; + SERVER_TYPE = ATHENA_SERVER_CHAR; } /// Called when a terminate signal is received. void do_shutdown(void) { - if( runflag != CHARSERVER_ST_SHUTDOWN ) - { - int id; - runflag = CHARSERVER_ST_SHUTDOWN; - ShowStatus("Shutting down...\n"); - // TODO proper shutdown procedure; wait for acks?, kick all characters, ... [FlavoJS] - for( id = 0; id < ARRAYLENGTH(server); ++id ) - mapif_server_reset(id); - loginif_check_shutdown(); - flush_fifos(); - runflag = CORE_ST_STOP; - } + if (runflag != CHARSERVER_ST_SHUTDOWN) { + int id; + runflag = CHARSERVER_ST_SHUTDOWN; + ShowStatus("Shutting down...\n"); + // TODO proper shutdown procedure; wait for acks?, kick all characters, ... [FlavoJS] + for (id = 0; id < ARRAYLENGTH(server); ++id) + mapif_server_reset(id); + loginif_check_shutdown(); + flush_fifos(); + runflag = CORE_ST_STOP; + } } int do_init(int argc, char **argv) { - //Read map indexes - mapindex_init(); - start_point.map = mapindex_name2id("new_zone01"); - - char_config_read((argc < 2) ? CHAR_CONF_NAME : argv[1]); - char_lan_config_read((argc > 3) ? argv[3] : LAN_CONF_NAME); - sql_config_read(SQL_CONF_NAME); - - if (strcmp(userid, "s1")==0 && strcmp(passwd, "p1")==0) { - ShowWarning("Using the default user/password s1/p1 is NOT RECOMMENDED.\n"); - ShowNotice("Please edit your 'login' table to create a proper inter-server user/password (gender 'S')\n"); - ShowNotice("And then change the user/password to use in conf/char_athena.conf (or conf/import/char_conf.txt)\n"); - } - - inter_init_sql((argc > 2) ? argv[2] : inter_cfgName); // inter server configuration - - auth_db = idb_alloc(DB_OPT_RELEASE_DATA); - online_char_db = idb_alloc(DB_OPT_RELEASE_DATA); - mmo_char_sql_init(); - char_read_fame_list(); //Read fame lists. - - if ((naddr_ != 0) && (!login_ip || !char_ip)) - { - char ip_str[16]; - ip2str(addr_[0], ip_str); - - if (naddr_ > 1) - ShowStatus("Multiple interfaces detected.. using %s as our IP address\n", ip_str); - else - ShowStatus("Defaulting to %s as our IP address\n", ip_str); - if (!login_ip) { - safestrncpy(login_ip_str, ip_str, sizeof(login_ip_str)); - login_ip = str2ip(login_ip_str); - } - if (!char_ip) { - safestrncpy(char_ip_str, ip_str, sizeof(char_ip_str)); - char_ip = str2ip(char_ip_str); - } - } - - do_init_loginif(); - do_init_mapif(); - - // periodically update the overall user count on all mapservers + login server - add_timer_func_list(broadcast_user_count, "broadcast_user_count"); - add_timer_interval(gettick() + 1000, broadcast_user_count, 0, 0, 5 * 1000); - - // Timer to clear (online_char_db) - add_timer_func_list(chardb_waiting_disconnect, "chardb_waiting_disconnect"); - - // Online Data timers (checking if char still connected) - add_timer_func_list(online_data_cleanup, "online_data_cleanup"); - add_timer_interval(gettick() + 1000, online_data_cleanup, 0, 0, 600 * 1000); - - if( console ) - { - //##TODO invoke a CONSOLE_START plugin event - } - - //Cleaning the tables for NULL entrys @ startup [Sirius] - //Chardb clean - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '0'", char_db) ) - Sql_ShowDebug(sql_handle); - - //guilddb clean - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_lv` = '0' AND `max_member` = '0' AND `exp` = '0' AND `next_exp` = '0' AND `average_lv` = '0'", guild_db) ) - Sql_ShowDebug(sql_handle); - - //guildmemberdb clean - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '0' AND `account_id` = '0' AND `char_id` = '0'", guild_member_db) ) - Sql_ShowDebug(sql_handle); - - set_defaultparse(parse_char); - char_fd = make_listen_bind(bind_ip, char_port); - ShowStatus("The char-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", char_port); - - if( runflag != CORE_ST_STOP ) - { - shutdown_callback = do_shutdown; - runflag = CHARSERVER_ST_RUNNING; - } - - return 0; + //Read map indexes + mapindex_init(); + start_point.map = mapindex_name2id("new_zone01"); + + char_config_read((argc < 2) ? CHAR_CONF_NAME : argv[1]); + char_lan_config_read((argc > 3) ? argv[3] : LAN_CONF_NAME); + sql_config_read(SQL_CONF_NAME); + + if (strcmp(userid, "s1")==0 && strcmp(passwd, "p1")==0) { + ShowWarning("Using the default user/password s1/p1 is NOT RECOMMENDED.\n"); + ShowNotice("Please edit your 'login' table to create a proper inter-server user/password (gender 'S')\n"); + ShowNotice("And then change the user/password to use in conf/char_athena.conf (or conf/import/char_conf.txt)\n"); + } + + inter_init_sql((argc > 2) ? argv[2] : inter_cfgName); // inter server configuration + + auth_db = idb_alloc(DB_OPT_RELEASE_DATA); + online_char_db = idb_alloc(DB_OPT_RELEASE_DATA); + mmo_char_sql_init(); + char_read_fame_list(); //Read fame lists. + + if ((naddr_ != 0) && (!login_ip || !char_ip)) { + char ip_str[16]; + ip2str(addr_[0], ip_str); + + if (naddr_ > 1) + ShowStatus("Multiple interfaces detected.. using %s as our IP address\n", ip_str); + else + ShowStatus("Defaulting to %s as our IP address\n", ip_str); + if (!login_ip) { + safestrncpy(login_ip_str, ip_str, sizeof(login_ip_str)); + login_ip = str2ip(login_ip_str); + } + if (!char_ip) { + safestrncpy(char_ip_str, ip_str, sizeof(char_ip_str)); + char_ip = str2ip(char_ip_str); + } + } + + do_init_loginif(); + do_init_mapif(); + + // periodically update the overall user count on all mapservers + login server + add_timer_func_list(broadcast_user_count, "broadcast_user_count"); + add_timer_interval(gettick() + 1000, broadcast_user_count, 0, 0, 5 * 1000); + + // Timer to clear (online_char_db) + add_timer_func_list(chardb_waiting_disconnect, "chardb_waiting_disconnect"); + + // Online Data timers (checking if char still connected) + add_timer_func_list(online_data_cleanup, "online_data_cleanup"); + add_timer_interval(gettick() + 1000, online_data_cleanup, 0, 0, 600 * 1000); + + if (console) { + //##TODO invoke a CONSOLE_START plugin event + } + + //Cleaning the tables for NULL entrys @ startup [Sirius] + //Chardb clean + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '0'", char_db)) + Sql_ShowDebug(sql_handle); + + //guilddb clean + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_lv` = '0' AND `max_member` = '0' AND `exp` = '0' AND `next_exp` = '0' AND `average_lv` = '0'", guild_db)) + Sql_ShowDebug(sql_handle); + + //guildmemberdb clean + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '0' AND `account_id` = '0' AND `char_id` = '0'", guild_member_db)) + Sql_ShowDebug(sql_handle); + + set_defaultparse(parse_char); + char_fd = make_listen_bind(bind_ip, char_port); + ShowStatus("The char-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", char_port); + + if (runflag != CORE_ST_STOP) { + shutdown_callback = do_shutdown; + runflag = CHARSERVER_ST_RUNNING; + } + + return 0; } diff --git a/src/char/char.h b/src/char/char.h index dd1c80f9d..cdef28718 100644 --- a/src/char/char.h +++ b/src/char/char.h @@ -6,11 +6,10 @@ #include "../common/core.h" // CORE_ST_LAST -enum E_CHARSERVER_ST -{ - CHARSERVER_ST_RUNNING = CORE_ST_LAST, - CHARSERVER_ST_SHUTDOWN, - CHARSERVER_ST_LAST +enum E_CHARSERVER_ST { + CHARSERVER_ST_RUNNING = CORE_ST_LAST, + CHARSERVER_ST_SHUTDOWN, + CHARSERVER_ST_LAST }; struct mmo_charstatus; @@ -20,10 +19,10 @@ struct mmo_charstatus; #define DEFAULT_AUTOSAVE_INTERVAL 300*1000 enum { - TABLE_INVENTORY, - TABLE_CART, - TABLE_STORAGE, - TABLE_GUILD_STORAGE, + TABLE_INVENTORY, + TABLE_CART, + TABLE_STORAGE, + TABLE_GUILD_STORAGE, }; int memitemdata_to_sql(const struct item items[], int max, int id, int tableswitch); @@ -37,7 +36,7 @@ int char_child(int parent_id, int child_id); int char_family(int pl1,int pl2,int pl3); int request_accreg2(int account_id, int char_id); -int save_accreg2(unsigned char* buf, int len); +int save_accreg2(unsigned char *buf, int len); extern int char_name_option; extern char char_name_letters[]; diff --git a/src/char/int_auction.c b/src/char/int_auction.c index 4fc9215a0..4eadb4866 100644 --- a/src/char/int_auction.c +++ b/src/char/int_auction.c @@ -18,442 +18,435 @@ #include #include -static DBMap* auction_db_ = NULL; // int auction_id -> struct auction_data* +static DBMap *auction_db_ = NULL; // int auction_id -> struct auction_data* void auction_delete(struct auction_data *auction); static int auction_end_timer(int tid, unsigned int tick, int id, intptr_t data); static int auction_count(int char_id, bool buy) { - int i = 0; - struct auction_data *auction; - DBIterator *iter = db_iterator(auction_db_); - - for( auction = dbi_first(iter); dbi_exists(iter); auction = dbi_next(iter) ) - { - if( (buy && auction->buyer_id == char_id) || (!buy && auction->seller_id == char_id) ) - i++; - } - dbi_destroy(iter); - - return i; + int i = 0; + struct auction_data *auction; + DBIterator *iter = db_iterator(auction_db_); + + for (auction = dbi_first(iter); dbi_exists(iter); auction = dbi_next(iter)) { + if ((buy && auction->buyer_id == char_id) || (!buy && auction->seller_id == char_id)) + i++; + } + dbi_destroy(iter); + + return i; } void auction_save(struct auction_data *auction) { - int j; - StringBuf buf; - SqlStmt* stmt; - - if( !auction ) - return; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET `seller_id` = '%d', `seller_name` = ?, `buyer_id` = '%d', `buyer_name` = ?, `price` = '%d', `buynow` = '%d', `hours` = '%d', `timestamp` = '%lu', `nameid` = '%d', `item_name` = ?, `type` = '%d', `refine` = '%d', `attribute` = '%d'", - auction_db, auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); - for( j = 0; j < MAX_SLOTS; j++ ) - StringBuf_Printf(&buf, ", `card%d` = '%d'", j, auction->item.card[j]); - StringBuf_Printf(&buf, " WHERE `auction_id` = '%d'", auction->auction_id); - - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_Execute(stmt) ) - { - SqlStmt_ShowDebug(stmt); - } - - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); + int j; + StringBuf buf; + SqlStmt *stmt; + + if (!auction) + return; + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET `seller_id` = '%d', `seller_name` = ?, `buyer_id` = '%d', `buyer_name` = ?, `price` = '%d', `buynow` = '%d', `hours` = '%d', `timestamp` = '%lu', `nameid` = '%d', `item_name` = ?, `type` = '%d', `refine` = '%d', `attribute` = '%d'", + auction_db, auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); + for (j = 0; j < MAX_SLOTS; j++) + StringBuf_Printf(&buf, ", `card%d` = '%d'", j, auction->item.card[j]); + StringBuf_Printf(&buf, " WHERE `auction_id` = '%d'", auction->auction_id); + + stmt = SqlStmt_Malloc(sql_handle); + if (SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_Execute(stmt)) { + SqlStmt_ShowDebug(stmt); + } + + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); } unsigned int auction_create(struct auction_data *auction) { - int j; - StringBuf buf; - SqlStmt* stmt; - - if( !auction ) - return false; - - auction->timestamp = time(NULL) + (auction->hours * 3600); - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`seller_id`,`seller_name`,`buyer_id`,`buyer_name`,`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`", auction_db); - for( j = 0; j < MAX_SLOTS; j++ ) - StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, ") VALUES ('%d',?,'%d',?,'%d','%d','%d','%lu','%d',?,'%d','%d','%d'", - auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); - for( j = 0; j < MAX_SLOTS; j++ ) - StringBuf_Printf(&buf, ",'%d'", auction->item.card[j]); - StringBuf_AppendStr(&buf, ")"); - - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_Execute(stmt) ) - { - SqlStmt_ShowDebug(stmt); - auction->auction_id = 0; - } - else - { - struct auction_data *auction_; - unsigned int tick = auction->hours * 3600000; - - auction->item.amount = 1; - auction->item.identify = 1; - auction->item.expire_time = 0; - - auction->auction_id = (unsigned int)SqlStmt_LastInsertId(stmt); - auction->auction_end_timer = add_timer( gettick() + tick , auction_end_timer, auction->auction_id, 0); - ShowInfo("New Auction %u | time left %u ms | By %s.\n", auction->auction_id, tick, auction->seller_name); - - CREATE(auction_, struct auction_data, 1); - memcpy(auction_, auction, sizeof(struct auction_data)); - idb_put(auction_db_, auction_->auction_id, auction_); - } - - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); - - return auction->auction_id; + int j; + StringBuf buf; + SqlStmt *stmt; + + if (!auction) + return false; + + auction->timestamp = time(NULL) + (auction->hours * 3600); + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`seller_id`,`seller_name`,`buyer_id`,`buyer_name`,`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`", auction_db); + for (j = 0; j < MAX_SLOTS; j++) + StringBuf_Printf(&buf, ",`card%d`", j); + StringBuf_Printf(&buf, ") VALUES ('%d',?,'%d',?,'%d','%d','%d','%lu','%d',?,'%d','%d','%d'", + auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); + for (j = 0; j < MAX_SLOTS; j++) + StringBuf_Printf(&buf, ",'%d'", auction->item.card[j]); + StringBuf_AppendStr(&buf, ")"); + + stmt = SqlStmt_Malloc(sql_handle); + if (SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_Execute(stmt)) { + SqlStmt_ShowDebug(stmt); + auction->auction_id = 0; + } else { + struct auction_data *auction_; + unsigned int tick = auction->hours * 3600000; + + auction->item.amount = 1; + auction->item.identify = 1; + auction->item.expire_time = 0; + + auction->auction_id = (unsigned int)SqlStmt_LastInsertId(stmt); + auction->auction_end_timer = add_timer(gettick() + tick , auction_end_timer, auction->auction_id, 0); + ShowInfo("New Auction %u | time left %u ms | By %s.\n", auction->auction_id, tick, auction->seller_name); + + CREATE(auction_, struct auction_data, 1); + memcpy(auction_, auction, sizeof(struct auction_data)); + idb_put(auction_db_, auction_->auction_id, auction_); + } + + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); + + return auction->auction_id; } static void mapif_Auction_message(int char_id, unsigned char result) { - unsigned char buf[74]; - - WBUFW(buf,0) = 0x3854; - WBUFL(buf,2) = char_id; - WBUFL(buf,6) = result; - mapif_sendall(buf,7); + unsigned char buf[74]; + + WBUFW(buf,0) = 0x3854; + WBUFL(buf,2) = char_id; + WBUFL(buf,6) = result; + mapif_sendall(buf,7); } static int auction_end_timer(int tid, unsigned int tick, int id, intptr_t data) { - struct auction_data *auction; - if( (auction = (struct auction_data *)idb_get(auction_db_, id)) != NULL ) - { - if( auction->buyer_id ) - { - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Thanks, you won the auction!.", 0, &auction->item); - mapif_Auction_message(auction->buyer_id, 6); // You have won the auction - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Payment for your auction!.", auction->price, NULL); - } - else - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "No buyers have been found for your auction.", 0, &auction->item); - - ShowInfo("Auction End: id %u.\n", auction->auction_id); - - auction->auction_end_timer = INVALID_TIMER; - auction_delete(auction); - } - - return 0; + struct auction_data *auction; + if ((auction = (struct auction_data *)idb_get(auction_db_, id)) != NULL) { + if (auction->buyer_id) { + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Thanks, you won the auction!.", 0, &auction->item); + mapif_Auction_message(auction->buyer_id, 6); // You have won the auction + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Payment for your auction!.", auction->price, NULL); + } else + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "No buyers have been found for your auction.", 0, &auction->item); + + ShowInfo("Auction End: id %u.\n", auction->auction_id); + + auction->auction_end_timer = INVALID_TIMER; + auction_delete(auction); + } + + return 0; } void auction_delete(struct auction_data *auction) { - unsigned int auction_id = auction->auction_id; + unsigned int auction_id = auction->auction_id; - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `auction_id` = '%d'", auction_db, auction_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `auction_id` = '%d'", auction_db, auction_id)) + Sql_ShowDebug(sql_handle); - if( auction->auction_end_timer != INVALID_TIMER ) - delete_timer(auction->auction_end_timer, auction_end_timer); + if (auction->auction_end_timer != INVALID_TIMER) + delete_timer(auction->auction_end_timer, auction_end_timer); - idb_remove(auction_db_, auction_id); + idb_remove(auction_db_, auction_id); } void inter_auctions_fromsql(void) { - int i; - struct auction_data *auction; - struct item *item; - char *data; - StringBuf buf; - unsigned int tick = gettick(), endtick; - time_t now = time(NULL); - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `auction_id`,`seller_id`,`seller_name`,`buyer_id`,`buyer_name`," - "`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`"); - for( i = 0; i < MAX_SLOTS; i++ ) - StringBuf_Printf(&buf, ",`card%d`", i); - StringBuf_Printf(&buf, " FROM `%s` ORDER BY `auction_id` DESC", auction_db); - - if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) - Sql_ShowDebug(sql_handle); - - StringBuf_Destroy(&buf); - - while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - CREATE(auction, struct auction_data, 1); - Sql_GetData(sql_handle, 0, &data, NULL); auction->auction_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); auction->seller_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); safestrncpy(auction->seller_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 3, &data, NULL); auction->buyer_id = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); safestrncpy(auction->buyer_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 5, &data, NULL); auction->price = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); auction->buynow = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); auction->hours = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); auction->timestamp = atoi(data); - - item = &auction->item; - Sql_GetData(sql_handle, 9, &data, NULL); item->nameid = atoi(data); - Sql_GetData(sql_handle,10, &data, NULL); safestrncpy(auction->item_name, data, ITEM_NAME_LENGTH); - Sql_GetData(sql_handle,11, &data, NULL); auction->type = atoi(data); - - Sql_GetData(sql_handle,12, &data, NULL); item->refine = atoi(data); - Sql_GetData(sql_handle,13, &data, NULL); item->attribute = atoi(data); - - item->identify = 1; - item->amount = 1; - item->expire_time = 0; - - for( i = 0; i < MAX_SLOTS; i++ ) - { - Sql_GetData(sql_handle, 14 + i, &data, NULL); - item->card[i] = atoi(data); - } - - if( auction->timestamp > now ) - endtick = ((unsigned int)(auction->timestamp - now) * 1000) + tick; - else - endtick = tick + 10000; // 10 Second's to process ended auctions - - auction->auction_end_timer = add_timer(endtick, auction_end_timer, auction->auction_id, 0); - idb_put(auction_db_, auction->auction_id, auction); - } - - Sql_FreeResult(sql_handle); + int i; + struct auction_data *auction; + struct item *item; + char *data; + StringBuf buf; + unsigned int tick = gettick(), endtick; + time_t now = time(NULL); + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `auction_id`,`seller_id`,`seller_name`,`buyer_id`,`buyer_name`," + "`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`"); + for (i = 0; i < MAX_SLOTS; i++) + StringBuf_Printf(&buf, ",`card%d`", i); + StringBuf_Printf(&buf, " FROM `%s` ORDER BY `auction_id` DESC", auction_db); + + if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) + Sql_ShowDebug(sql_handle); + + StringBuf_Destroy(&buf); + + while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + CREATE(auction, struct auction_data, 1); + Sql_GetData(sql_handle, 0, &data, NULL); + auction->auction_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + auction->seller_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + safestrncpy(auction->seller_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 3, &data, NULL); + auction->buyer_id = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + safestrncpy(auction->buyer_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 5, &data, NULL); + auction->price = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + auction->buynow = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); + auction->hours = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); + auction->timestamp = atoi(data); + + item = &auction->item; + Sql_GetData(sql_handle, 9, &data, NULL); + item->nameid = atoi(data); + Sql_GetData(sql_handle,10, &data, NULL); + safestrncpy(auction->item_name, data, ITEM_NAME_LENGTH); + Sql_GetData(sql_handle,11, &data, NULL); + auction->type = atoi(data); + + Sql_GetData(sql_handle,12, &data, NULL); + item->refine = atoi(data); + Sql_GetData(sql_handle,13, &data, NULL); + item->attribute = atoi(data); + + item->identify = 1; + item->amount = 1; + item->expire_time = 0; + + for (i = 0; i < MAX_SLOTS; i++) { + Sql_GetData(sql_handle, 14 + i, &data, NULL); + item->card[i] = atoi(data); + } + + if (auction->timestamp > now) + endtick = ((unsigned int)(auction->timestamp - now) * 1000) + tick; + else + endtick = tick + 10000; // 10 Second's to process ended auctions + + auction->auction_end_timer = add_timer(endtick, auction_end_timer, auction->auction_id, 0); + idb_put(auction_db_, auction->auction_id, auction); + } + + Sql_FreeResult(sql_handle); } static void mapif_Auction_sendlist(int fd, int char_id, short count, short pages, unsigned char *buf) { - int len = (sizeof(struct auction_data) * count) + 12; - - WFIFOHEAD(fd, len); - WFIFOW(fd,0) = 0x3850; - WFIFOW(fd,2) = len; - WFIFOL(fd,4) = char_id; - WFIFOW(fd,8) = count; - WFIFOW(fd,10) = pages; - memcpy(WFIFOP(fd,12), buf, len - 12); - WFIFOSET(fd,len); + int len = (sizeof(struct auction_data) * count) + 12; + + WFIFOHEAD(fd, len); + WFIFOW(fd,0) = 0x3850; + WFIFOW(fd,2) = len; + WFIFOL(fd,4) = char_id; + WFIFOW(fd,8) = count; + WFIFOW(fd,10) = pages; + memcpy(WFIFOP(fd,12), buf, len - 12); + WFIFOSET(fd,len); } static void mapif_parse_Auction_requestlist(int fd) { - char searchtext[NAME_LENGTH]; - int char_id = RFIFOL(fd,4), len = sizeof(struct auction_data); - int price = RFIFOL(fd,10); - short type = RFIFOW(fd,8), page = max(1,RFIFOW(fd,14)); - unsigned char buf[5 * sizeof(struct auction_data)]; - DBIterator *iter = db_iterator(auction_db_); - struct auction_data *auction; - short i = 0, j = 0, pages = 1; - - memcpy(searchtext, RFIFOP(fd,16), NAME_LENGTH); - - for( auction = dbi_first(iter); dbi_exists(iter); auction = dbi_next(iter) ) - { - if( (type == 0 && auction->type != IT_ARMOR && auction->type != IT_PETARMOR) || - (type == 1 && auction->type != IT_WEAPON) || - (type == 2 && auction->type != IT_CARD) || - (type == 3 && auction->type != IT_ETC) || - (type == 4 && !strstr(auction->item_name, searchtext)) || - (type == 5 && auction->price > price) || - (type == 6 && auction->seller_id != char_id) || - (type == 7 && auction->buyer_id != char_id) ) - continue; - - i++; - if( i > 5 ) - { // Counting Pages of Total Results (5 Results per Page) - pages++; - i = 1; // First Result of This Page - } - - if( page != pages ) - continue; // This is not the requested Page - - memcpy(WBUFP(buf, j * len), auction, len); - j++; // Found Results - } - dbi_destroy(iter); - - mapif_Auction_sendlist(fd, char_id, j, pages, buf); + char searchtext[NAME_LENGTH]; + int char_id = RFIFOL(fd,4), len = sizeof(struct auction_data); + int price = RFIFOL(fd,10); + short type = RFIFOW(fd,8), page = max(1,RFIFOW(fd,14)); + unsigned char buf[5 * sizeof(struct auction_data)]; + DBIterator *iter = db_iterator(auction_db_); + struct auction_data *auction; + short i = 0, j = 0, pages = 1; + + memcpy(searchtext, RFIFOP(fd,16), NAME_LENGTH); + + for (auction = dbi_first(iter); dbi_exists(iter); auction = dbi_next(iter)) { + if ((type == 0 && auction->type != IT_ARMOR && auction->type != IT_PETARMOR) || + (type == 1 && auction->type != IT_WEAPON) || + (type == 2 && auction->type != IT_CARD) || + (type == 3 && auction->type != IT_ETC) || + (type == 4 && !strstr(auction->item_name, searchtext)) || + (type == 5 && auction->price > price) || + (type == 6 && auction->seller_id != char_id) || + (type == 7 && auction->buyer_id != char_id)) + continue; + + i++; + if (i > 5) { + // Counting Pages of Total Results (5 Results per Page) + pages++; + i = 1; // First Result of This Page + } + + if (page != pages) + continue; // This is not the requested Page + + memcpy(WBUFP(buf, j * len), auction, len); + j++; // Found Results + } + dbi_destroy(iter); + + mapif_Auction_sendlist(fd, char_id, j, pages, buf); } static void mapif_Auction_register(int fd, struct auction_data *auction) { - int len = sizeof(struct auction_data) + 4; + int len = sizeof(struct auction_data) + 4; - WFIFOHEAD(fd,len); - WFIFOW(fd,0) = 0x3851; - WFIFOW(fd,2) = len; - memcpy(WFIFOP(fd,4), auction, sizeof(struct auction_data)); - WFIFOSET(fd,len); + WFIFOHEAD(fd,len); + WFIFOW(fd,0) = 0x3851; + WFIFOW(fd,2) = len; + memcpy(WFIFOP(fd,4), auction, sizeof(struct auction_data)); + WFIFOSET(fd,len); } static void mapif_parse_Auction_register(int fd) { - struct auction_data auction; - if( RFIFOW(fd,2) != sizeof(struct auction_data) + 4 ) - return; + struct auction_data auction; + if (RFIFOW(fd,2) != sizeof(struct auction_data) + 4) + return; - memcpy(&auction, RFIFOP(fd,4), sizeof(struct auction_data)); - if( auction_count(auction.seller_id, false) < 5 ) - auction.auction_id = auction_create(&auction); + memcpy(&auction, RFIFOP(fd,4), sizeof(struct auction_data)); + if (auction_count(auction.seller_id, false) < 5) + auction.auction_id = auction_create(&auction); - mapif_Auction_register(fd, &auction); + mapif_Auction_register(fd, &auction); } static void mapif_Auction_cancel(int fd, int char_id, unsigned char result) { - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x3852; - WFIFOL(fd,2) = char_id; - WFIFOB(fd,6) = result; - WFIFOSET(fd,7); + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x3852; + WFIFOL(fd,2) = char_id; + WFIFOB(fd,6) = result; + WFIFOSET(fd,7); } static void mapif_parse_Auction_cancel(int fd) { - int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6); - struct auction_data *auction; - - if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL ) - { - mapif_Auction_cancel(fd, char_id, 1); // Bid Number is Incorrect - return; - } - - if( auction->seller_id != char_id ) - { - mapif_Auction_cancel(fd, char_id, 2); // You cannot end the auction - return; - } - - if( auction->buyer_id > 0 ) - { - mapif_Auction_cancel(fd, char_id, 3); // An auction with at least one bidder cannot be canceled - return; - } - - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Auction canceled.", 0, &auction->item); - auction_delete(auction); - - mapif_Auction_cancel(fd, char_id, 0); // The auction has been canceled + int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6); + struct auction_data *auction; + + if ((auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL) { + mapif_Auction_cancel(fd, char_id, 1); // Bid Number is Incorrect + return; + } + + if (auction->seller_id != char_id) { + mapif_Auction_cancel(fd, char_id, 2); // You cannot end the auction + return; + } + + if (auction->buyer_id > 0) { + mapif_Auction_cancel(fd, char_id, 3); // An auction with at least one bidder cannot be canceled + return; + } + + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Auction canceled.", 0, &auction->item); + auction_delete(auction); + + mapif_Auction_cancel(fd, char_id, 0); // The auction has been canceled } static void mapif_Auction_close(int fd, int char_id, unsigned char result) { - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x3853; - WFIFOL(fd,2) = char_id; - WFIFOB(fd,6) = result; - WFIFOSET(fd,7); + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x3853; + WFIFOL(fd,2) = char_id; + WFIFOB(fd,6) = result; + WFIFOSET(fd,7); } static void mapif_parse_Auction_close(int fd) { - int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6); - struct auction_data *auction; - - if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL ) - { - mapif_Auction_close(fd, char_id, 2); // Bid Number is Incorrect - return; - } - - if( auction->seller_id != char_id ) - { - mapif_Auction_close(fd, char_id, 1); // You cannot end the auction - return; - } - - if( auction->buyer_id == 0 ) - { - mapif_Auction_close(fd, char_id, 1); // You cannot end the auction - return; - } - - // Send Money to Seller - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Auction closed.", auction->price, NULL); - // Send Item to Buyer - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Auction winner.", 0, &auction->item); - mapif_Auction_message(auction->buyer_id, 6); // You have won the auction - auction_delete(auction); - - mapif_Auction_close(fd, char_id, 0); // You have ended the auction + int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6); + struct auction_data *auction; + + if ((auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL) { + mapif_Auction_close(fd, char_id, 2); // Bid Number is Incorrect + return; + } + + if (auction->seller_id != char_id) { + mapif_Auction_close(fd, char_id, 1); // You cannot end the auction + return; + } + + if (auction->buyer_id == 0) { + mapif_Auction_close(fd, char_id, 1); // You cannot end the auction + return; + } + + // Send Money to Seller + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Auction closed.", auction->price, NULL); + // Send Item to Buyer + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Auction winner.", 0, &auction->item); + mapif_Auction_message(auction->buyer_id, 6); // You have won the auction + auction_delete(auction); + + mapif_Auction_close(fd, char_id, 0); // You have ended the auction } static void mapif_Auction_bid(int fd, int char_id, int bid, unsigned char result) { - WFIFOHEAD(fd,11); - WFIFOW(fd,0) = 0x3855; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = bid; // To Return Zeny - WFIFOB(fd,10) = result; - WFIFOSET(fd,11); + WFIFOHEAD(fd,11); + WFIFOW(fd,0) = 0x3855; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = bid; // To Return Zeny + WFIFOB(fd,10) = result; + WFIFOSET(fd,11); } static void mapif_parse_Auction_bid(int fd) { - int char_id = RFIFOL(fd,4), bid = RFIFOL(fd,12); - unsigned int auction_id = RFIFOL(fd,8); - struct auction_data *auction; - - if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL || auction->price >= bid || auction->seller_id == char_id ) - { - mapif_Auction_bid(fd, char_id, bid, 0); // You have failed to bid in the auction - return; - } - - if( auction_count(char_id, true) > 4 && bid < auction->buynow && auction->buyer_id != char_id ) - { - mapif_Auction_bid(fd, char_id, bid, 9); // You cannot place more than 5 bids at a time - return; - } - - if( auction->buyer_id > 0 ) - { // Send Money back to the previous Buyer - if( auction->buyer_id != char_id ) - { - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Someone has placed a higher bid.", auction->price, NULL); - mapif_Auction_message(auction->buyer_id, 7); // You have failed to win the auction - } - else - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "You have placed a higher bid.", auction->price, NULL); - } - - auction->buyer_id = char_id; - safestrncpy(auction->buyer_name, (char*)RFIFOP(fd,16), NAME_LENGTH); - auction->price = bid; - - if( bid >= auction->buynow ) - { // Automatic won the auction - mapif_Auction_bid(fd, char_id, bid - auction->buynow, 1); // You have successfully bid in the auction - - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "You have won the auction.", 0, &auction->item); - mapif_Auction_message(char_id, 6); // You have won the auction - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Payment for your auction!.", auction->buynow, NULL); - - auction_delete(auction); - return; - } - - auction_save(auction); - - mapif_Auction_bid(fd, char_id, 0, 1); // You have successfully bid in the auction + int char_id = RFIFOL(fd,4), bid = RFIFOL(fd,12); + unsigned int auction_id = RFIFOL(fd,8); + struct auction_data *auction; + + if ((auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL || auction->price >= bid || auction->seller_id == char_id) { + mapif_Auction_bid(fd, char_id, bid, 0); // You have failed to bid in the auction + return; + } + + if (auction_count(char_id, true) > 4 && bid < auction->buynow && auction->buyer_id != char_id) { + mapif_Auction_bid(fd, char_id, bid, 9); // You cannot place more than 5 bids at a time + return; + } + + if (auction->buyer_id > 0) { + // Send Money back to the previous Buyer + if (auction->buyer_id != char_id) { + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Someone has placed a higher bid.", auction->price, NULL); + mapif_Auction_message(auction->buyer_id, 7); // You have failed to win the auction + } else + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "You have placed a higher bid.", auction->price, NULL); + } + + auction->buyer_id = char_id; + safestrncpy(auction->buyer_name, (char *)RFIFOP(fd,16), NAME_LENGTH); + auction->price = bid; + + if (bid >= auction->buynow) { + // Automatic won the auction + mapif_Auction_bid(fd, char_id, bid - auction->buynow, 1); // You have successfully bid in the auction + + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "You have won the auction.", 0, &auction->item); + mapif_Auction_message(char_id, 6); // You have won the auction + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Payment for your auction!.", auction->buynow, NULL); + + auction_delete(auction); + return; + } + + auction_save(auction); + + mapif_Auction_bid(fd, char_id, 0, 1); // You have successfully bid in the auction } /*========================================== @@ -461,30 +454,39 @@ static void mapif_parse_Auction_bid(int fd) *------------------------------------------*/ int inter_auction_parse_frommap(int fd) { - switch(RFIFOW(fd,0)) - { - case 0x3050: mapif_parse_Auction_requestlist(fd); break; - case 0x3051: mapif_parse_Auction_register(fd); break; - case 0x3052: mapif_parse_Auction_cancel(fd); break; - case 0x3053: mapif_parse_Auction_close(fd); break; - case 0x3055: mapif_parse_Auction_bid(fd); break; - default: - return 0; - } - return 1; + switch (RFIFOW(fd,0)) { + case 0x3050: + mapif_parse_Auction_requestlist(fd); + break; + case 0x3051: + mapif_parse_Auction_register(fd); + break; + case 0x3052: + mapif_parse_Auction_cancel(fd); + break; + case 0x3053: + mapif_parse_Auction_close(fd); + break; + case 0x3055: + mapif_parse_Auction_bid(fd); + break; + default: + return 0; + } + return 1; } int inter_auction_sql_init(void) { - auction_db_ = idb_alloc(DB_OPT_RELEASE_DATA); - inter_auctions_fromsql(); + auction_db_ = idb_alloc(DB_OPT_RELEASE_DATA); + inter_auctions_fromsql(); - return 0; + return 0; } void inter_auction_sql_final(void) { - auction_db_->destroy(auction_db_,NULL); + auction_db_->destroy(auction_db_,NULL); - return; + return; } diff --git a/src/char/int_elemental.c b/src/char/int_elemental.c index 7c76c4496..aa7ef5f65 100644 --- a/src/char/int_elemental.c +++ b/src/char/int_elemental.c @@ -15,147 +15,179 @@ #include #include -bool mapif_elemental_save(struct s_elemental* ele) { - bool flag = true; - - if( ele->elemental_id == 0 ) { // Create new DB entry - if( SQL_ERROR == Sql_Query(sql_handle, - "INSERT INTO `elemental` (`char_id`,`class`,`mode`,`hp`,`sp`,`max_hp`,`max_sp`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`life_time`)" - "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%u')", - ele->char_id, ele->class_, ele->mode, ele->hp, ele->sp, ele->max_hp, ele->max_sp, ele->str, ele->agi, ele->vit, ele->int_, ele->dex, ele->luk, ele->life_time) ) - { - Sql_ShowDebug(sql_handle); - flag = false; - } - else - ele->elemental_id = (int)Sql_LastInsertId(sql_handle); - } else if( SQL_ERROR == Sql_Query(sql_handle, - "UPDATE `elemental` SET `char_id` = '%d', `class` = '%d', `mode` = '%d', `hp` = '%d', `sp` = '%d'," - "`max_hp` = '%d', `max_sp` = '%d', `str` = '%d', `agi` = '%d', `vit` = '%d', `int` = '%d', `dex` = '%d'," - "`luk` = '%d', `life_time` = '%u' WHERE `ele_id` = '%d'", - ele->char_id, ele->class_, ele->mode, ele->hp, ele->sp, ele->max_hp, ele->max_sp, ele->str, ele->agi, - ele->vit, ele->int_, ele->dex, ele->luk, ele->life_time, ele->elemental_id) ) - { // Update DB entry - Sql_ShowDebug(sql_handle); - flag = false; - } - return flag; +bool mapif_elemental_save(struct s_elemental *ele) +{ + bool flag = true; + + if (ele->elemental_id == 0) { // Create new DB entry + if (SQL_ERROR == Sql_Query(sql_handle, + "INSERT INTO `elemental` (`char_id`,`class`,`mode`,`hp`,`sp`,`max_hp`,`max_sp`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`life_time`)" + "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%u')", + ele->char_id, ele->class_, ele->mode, ele->hp, ele->sp, ele->max_hp, ele->max_sp, ele->str, ele->agi, ele->vit, ele->int_, ele->dex, ele->luk, ele->life_time)) { + Sql_ShowDebug(sql_handle); + flag = false; + } else + ele->elemental_id = (int)Sql_LastInsertId(sql_handle); + } else if (SQL_ERROR == Sql_Query(sql_handle, + "UPDATE `elemental` SET `char_id` = '%d', `class` = '%d', `mode` = '%d', `hp` = '%d', `sp` = '%d'," + "`max_hp` = '%d', `max_sp` = '%d', `str` = '%d', `agi` = '%d', `vit` = '%d', `int` = '%d', `dex` = '%d'," + "`luk` = '%d', `life_time` = '%u' WHERE `ele_id` = '%d'", + ele->char_id, ele->class_, ele->mode, ele->hp, ele->sp, ele->max_hp, ele->max_sp, ele->str, ele->agi, + ele->vit, ele->int_, ele->dex, ele->luk, ele->life_time, ele->elemental_id)) { + // Update DB entry + Sql_ShowDebug(sql_handle); + flag = false; + } + return flag; } -bool mapif_elemental_load(int ele_id, int char_id, struct s_elemental *ele) { - char* data; - - memset(ele, 0, sizeof(struct s_elemental)); - ele->elemental_id = ele_id; - ele->char_id = char_id; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `class`, `mode`, `hp`, `sp`, `max_hp`, `max_sp`, `str`, `agi`, `vit`, `int`, `dex`," - "`luk`, `life_time` FROM `elemental` WHERE `ele_id` = '%d' AND `char_id` = '%d'", - ele_id, char_id) ) { - Sql_ShowDebug(sql_handle); - return false; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) { - Sql_FreeResult(sql_handle); - return false; - } - - Sql_GetData(sql_handle, 0, &data, NULL); ele->class_ = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); ele->mode = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); ele->hp = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); ele->sp = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); ele->max_hp = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); ele->max_sp = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); ele->str = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); ele->agi = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); ele->vit = atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); ele->int_ = atoi(data); - Sql_GetData(sql_handle, 10, &data, NULL); ele->dex = atoi(data); - Sql_GetData(sql_handle, 11, &data, NULL); ele->luk = atoi(data); - Sql_GetData(sql_handle, 12, &data, NULL); ele->life_time = atoi(data); - Sql_FreeResult(sql_handle); - if( save_log ) - ShowInfo("Elemental loaded (%d - %d).\n", ele->elemental_id, ele->char_id); - - return true; +bool mapif_elemental_load(int ele_id, int char_id, struct s_elemental *ele) +{ + char *data; + + memset(ele, 0, sizeof(struct s_elemental)); + ele->elemental_id = ele_id; + ele->char_id = char_id; + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `class`, `mode`, `hp`, `sp`, `max_hp`, `max_sp`, `str`, `agi`, `vit`, `int`, `dex`," + "`luk`, `life_time` FROM `elemental` WHERE `ele_id` = '%d' AND `char_id` = '%d'", + ele_id, char_id)) { + Sql_ShowDebug(sql_handle); + return false; + } + + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { + Sql_FreeResult(sql_handle); + return false; + } + + Sql_GetData(sql_handle, 0, &data, NULL); + ele->class_ = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + ele->mode = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + ele->hp = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + ele->sp = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + ele->max_hp = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + ele->max_sp = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + ele->str = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); + ele->agi = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); + ele->vit = atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); + ele->int_ = atoi(data); + Sql_GetData(sql_handle, 10, &data, NULL); + ele->dex = atoi(data); + Sql_GetData(sql_handle, 11, &data, NULL); + ele->luk = atoi(data); + Sql_GetData(sql_handle, 12, &data, NULL); + ele->life_time = atoi(data); + Sql_FreeResult(sql_handle); + if (save_log) + ShowInfo("Elemental loaded (%d - %d).\n", ele->elemental_id, ele->char_id); + + return true; } -bool mapif_elemental_delete(int ele_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `elemental` WHERE `ele_id` = '%d'", ele_id) ) { - Sql_ShowDebug(sql_handle); - return false; - } - - return true; +bool mapif_elemental_delete(int ele_id) +{ + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `elemental` WHERE `ele_id` = '%d'", ele_id)) { + Sql_ShowDebug(sql_handle); + return false; + } + + return true; } -static void mapif_elemental_send(int fd, struct s_elemental *ele, unsigned char flag) { - int size = sizeof(struct s_elemental) + 5; - - WFIFOHEAD(fd,size); - WFIFOW(fd,0) = 0x387c; - WFIFOW(fd,2) = size; - WFIFOB(fd,4) = flag; - memcpy(WFIFOP(fd,5),ele,sizeof(struct s_elemental)); - WFIFOSET(fd,size); +static void mapif_elemental_send(int fd, struct s_elemental *ele, unsigned char flag) +{ + int size = sizeof(struct s_elemental) + 5; + + WFIFOHEAD(fd,size); + WFIFOW(fd,0) = 0x387c; + WFIFOW(fd,2) = size; + WFIFOB(fd,4) = flag; + memcpy(WFIFOP(fd,5),ele,sizeof(struct s_elemental)); + WFIFOSET(fd,size); } -static void mapif_parse_elemental_create(int fd, struct s_elemental* ele) { - bool result = mapif_elemental_save(ele); - mapif_elemental_send(fd, ele, result); +static void mapif_parse_elemental_create(int fd, struct s_elemental *ele) +{ + bool result = mapif_elemental_save(ele); + mapif_elemental_send(fd, ele, result); } -static void mapif_parse_elemental_load(int fd, int ele_id, int char_id) { - struct s_elemental ele; - bool result = mapif_elemental_load(ele_id, char_id, &ele); - mapif_elemental_send(fd, &ele, result); +static void mapif_parse_elemental_load(int fd, int ele_id, int char_id) +{ + struct s_elemental ele; + bool result = mapif_elemental_load(ele_id, char_id, &ele); + mapif_elemental_send(fd, &ele, result); } -static void mapif_elemental_deleted(int fd, unsigned char flag) { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x387d; - WFIFOB(fd,2) = flag; - WFIFOSET(fd,3); +static void mapif_elemental_deleted(int fd, unsigned char flag) +{ + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x387d; + WFIFOB(fd,2) = flag; + WFIFOSET(fd,3); } -static void mapif_parse_elemental_delete(int fd, int ele_id) { - bool result = mapif_elemental_delete(ele_id); - mapif_elemental_deleted(fd, result); +static void mapif_parse_elemental_delete(int fd, int ele_id) +{ + bool result = mapif_elemental_delete(ele_id); + mapif_elemental_deleted(fd, result); } -static void mapif_elemental_saved(int fd, unsigned char flag) { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x387e; - WFIFOB(fd,2) = flag; - WFIFOSET(fd,3); +static void mapif_elemental_saved(int fd, unsigned char flag) +{ + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x387e; + WFIFOB(fd,2) = flag; + WFIFOSET(fd,3); } -static void mapif_parse_elemental_save(int fd, struct s_elemental* ele) { - bool result = mapif_elemental_save(ele); - mapif_elemental_saved(fd, result); +static void mapif_parse_elemental_save(int fd, struct s_elemental *ele) +{ + bool result = mapif_elemental_save(ele); + mapif_elemental_saved(fd, result); } -void inter_elemental_sql_init(void) { - return; +void inter_elemental_sql_init(void) +{ + return; } -void inter_elemental_sql_final(void) { - return; +void inter_elemental_sql_final(void) +{ + return; } /*========================================== * Inter Packets *------------------------------------------*/ -int inter_elemental_parse_frommap(int fd) { - unsigned short cmd = RFIFOW(fd,0); - - switch( cmd ) { - case 0x307c: mapif_parse_elemental_create(fd, (struct s_elemental*)RFIFOP(fd,4)); break; - case 0x307d: mapif_parse_elemental_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); break; - case 0x307e: mapif_parse_elemental_delete(fd, (int)RFIFOL(fd,2)); break; - case 0x307f: mapif_parse_elemental_save(fd, (struct s_elemental*)RFIFOP(fd,4)); break; - default: - return 0; - } - return 1; +int inter_elemental_parse_frommap(int fd) +{ + unsigned short cmd = RFIFOW(fd,0); + + switch (cmd) { + case 0x307c: + mapif_parse_elemental_create(fd, (struct s_elemental *)RFIFOP(fd,4)); + break; + case 0x307d: + mapif_parse_elemental_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); + break; + case 0x307e: + mapif_parse_elemental_delete(fd, (int)RFIFOL(fd,2)); + break; + case 0x307f: + mapif_parse_elemental_save(fd, (struct s_elemental *)RFIFOP(fd,4)); + break; + default: + return 0; + } + return 1; } diff --git a/src/char/int_guild.c b/src/char/int_guild.c index b07a1933f..2b4a9f3ac 100644 --- a/src/char/int_guild.c +++ b/src/char/int_guild.c @@ -31,7 +31,7 @@ static const char dataToHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; //Guild cache -static DBMap* guild_db_; // int guild_id -> struct guild* +static DBMap *guild_db_; // int guild_id -> struct guild* static DBMap *castle_db; static unsigned int guild_exp[100]; @@ -47,703 +47,703 @@ int inter_guild_tosql(struct guild *g,int flag); static int guild_save_timer(int tid, unsigned int tick, int id, intptr_t data) { - static int last_id = 0; //To know in which guild we were. - int state = 0; //0: Have not reached last guild. 1: Reached last guild, ready for save. 2: Some guild saved, don't do further saving. - DBIterator *iter = db_iterator(guild_db_); - DBKey key; - struct guild* g; - - if( last_id == 0 ) //Save the first guild in the list. - state = 1; - - for( g = db_data2ptr(iter->first(iter, &key)); dbi_exists(iter); g = db_data2ptr(iter->next(iter, &key)) ) - { - if( state == 0 && g->guild_id == last_id ) - state++; //Save next guild in the list. - else - if( state == 1 && g->save_flag&GS_MASK ) - { - inter_guild_tosql(g, g->save_flag&GS_MASK); - g->save_flag &= ~GS_MASK; - - //Some guild saved. - last_id = g->guild_id; - state++; - } - - if( g->save_flag == GS_REMOVE ) - {// Nothing to save, guild is ready for removal. - if (save_log) - ShowInfo("Guild Unloaded (%d - %s)\n", g->guild_id, g->name); - db_remove(guild_db_, key); - } - } - dbi_destroy(iter); - - if( state != 2 ) //Reached the end of the guild db without saving. - last_id = 0; //Reset guild saved, return to beginning. - - state = guild_db_->size(guild_db_); - if( state < 1 ) state = 1; //Calculate the time slot for the next save. - add_timer(tick + autosave_interval/state, guild_save_timer, 0, 0); - return 0; + static int last_id = 0; //To know in which guild we were. + int state = 0; //0: Have not reached last guild. 1: Reached last guild, ready for save. 2: Some guild saved, don't do further saving. + DBIterator *iter = db_iterator(guild_db_); + DBKey key; + struct guild *g; + + if (last_id == 0) //Save the first guild in the list. + state = 1; + + for (g = db_data2ptr(iter->first(iter, &key)); dbi_exists(iter); g = db_data2ptr(iter->next(iter, &key))) { + if (state == 0 && g->guild_id == last_id) + state++; //Save next guild in the list. + else if (state == 1 && g->save_flag&GS_MASK) { + inter_guild_tosql(g, g->save_flag&GS_MASK); + g->save_flag &= ~GS_MASK; + + //Some guild saved. + last_id = g->guild_id; + state++; + } + + if (g->save_flag == GS_REMOVE) { + // Nothing to save, guild is ready for removal. + if (save_log) + ShowInfo("Guild Unloaded (%d - %s)\n", g->guild_id, g->name); + db_remove(guild_db_, key); + } + } + dbi_destroy(iter); + + if (state != 2) //Reached the end of the guild db without saving. + last_id = 0; //Reset guild saved, return to beginning. + + state = guild_db_->size(guild_db_); + if (state < 1) state = 1; //Calculate the time slot for the next save. + add_timer(tick + autosave_interval/state, guild_save_timer, 0, 0); + return 0; } int inter_guild_removemember_tosql(int account_id, int char_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `account_id` = '%d' and `char_id` = '%d'", guild_member_db, account_id, char_id) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '0' WHERE `char_id` = '%d'", char_db, char_id) ) - Sql_ShowDebug(sql_handle); - return 0; + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `account_id` = '%d' and `char_id` = '%d'", guild_member_db, account_id, char_id)) + Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '0' WHERE `char_id` = '%d'", char_db, char_id)) + Sql_ShowDebug(sql_handle); + return 0; } // Save guild into sql int inter_guild_tosql(struct guild *g,int flag) { - // Table guild (GS_BASIC_MASK) - // GS_EMBLEM `emblem_len`,`emblem_id`,`emblem_data` - // GS_CONNECT `connect_member`,`average_lv` - // GS_MES `mes1`,`mes2` - // GS_LEVEL `guild_lv`,`max_member`,`exp`,`next_exp`,`skill_point` - // GS_BASIC `name`,`master`,`char_id` - - // GS_MEMBER `guild_member` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) - // GS_POSITION `guild_position` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) - // GS_ALLIANCE `guild_alliance` (`guild_id`,`opposition`,`alliance_id`,`name`) - // GS_EXPULSION `guild_expulsion` (`guild_id`,`account_id`,`name`,`mes`) - // GS_SKILL `guild_skill` (`guild_id`,`id`,`lv`) - - // temporary storage for str convertion. They must be twice the size of the - // original string to ensure no overflows will occur. [Skotlex] - char t_info[256]; - char esc_name[NAME_LENGTH*2+1]; - char esc_master[NAME_LENGTH*2+1]; - char new_guild = 0; - int i=0; - - if (g->guild_id<=0 && g->guild_id != -1) return 0; - + // Table guild (GS_BASIC_MASK) + // GS_EMBLEM `emblem_len`,`emblem_id`,`emblem_data` + // GS_CONNECT `connect_member`,`average_lv` + // GS_MES `mes1`,`mes2` + // GS_LEVEL `guild_lv`,`max_member`,`exp`,`next_exp`,`skill_point` + // GS_BASIC `name`,`master`,`char_id` + + // GS_MEMBER `guild_member` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) + // GS_POSITION `guild_position` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) + // GS_ALLIANCE `guild_alliance` (`guild_id`,`opposition`,`alliance_id`,`name`) + // GS_EXPULSION `guild_expulsion` (`guild_id`,`account_id`,`name`,`mes`) + // GS_SKILL `guild_skill` (`guild_id`,`id`,`lv`) + + // temporary storage for str convertion. They must be twice the size of the + // original string to ensure no overflows will occur. [Skotlex] + char t_info[256]; + char esc_name[NAME_LENGTH*2+1]; + char esc_master[NAME_LENGTH*2+1]; + char new_guild = 0; + int i=0; + + if (g->guild_id<=0 && g->guild_id != -1) return 0; + #ifdef NOISY - ShowInfo("Save guild request ("CL_BOLD"%d"CL_RESET" - flag 0x%x).",g->guild_id, flag); + ShowInfo("Save guild request ("CL_BOLD"%d"CL_RESET" - flag 0x%x).",g->guild_id, flag); #endif - Sql_EscapeStringLen(sql_handle, esc_name, g->name, strnlen(g->name, NAME_LENGTH)); - Sql_EscapeStringLen(sql_handle, esc_master, g->master, strnlen(g->master, NAME_LENGTH)); - *t_info = '\0'; - - // Insert a new guild the guild - if (flag&GS_BASIC && g->guild_id == -1) - { - strcat(t_info, " guild_create"); - - // Create a new guild - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " - "(`name`,`master`,`guild_lv`,`max_member`,`average_lv`,`char_id`) " - "VALUES ('%s', '%s', '%d', '%d', '%d', '%d')", - guild_db, esc_name, esc_master, g->guild_lv, g->max_member, g->average_lv, g->member[0].char_id) ) - { - Sql_ShowDebug(sql_handle); - if (g->guild_id == -1) - return 0; //Failed to create guild! - } - else - { - g->guild_id = (int)Sql_LastInsertId(sql_handle); - new_guild = 1; - } - } - - // If we need an update on an existing guild or more update on the new guild - if (((flag & GS_BASIC_MASK) && !new_guild) || ((flag & (GS_BASIC_MASK & ~GS_BASIC)) && new_guild)) - { - StringBuf buf; - bool add_comma = false; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET ", guild_db); - - if (flag & GS_EMBLEM) - { - char emblem_data[sizeof(g->emblem_data)*2+1]; - char* pData = emblem_data; - - strcat(t_info, " emblem"); - // Convert emblem_data to hex - //TODO: why not use binary directly? [ultramage] - for(i=0; iemblem_len; i++){ - *pData++ = dataToHex[(g->emblem_data[i] >> 4) & 0x0F]; - *pData++ = dataToHex[g->emblem_data[i] & 0x0F]; - } - *pData = 0; - StringBuf_Printf(&buf, "`emblem_len`=%d, `emblem_id`=%d, `emblem_data`='%s'", g->emblem_len, g->emblem_id, emblem_data); - add_comma = true; - } - if (flag & GS_BASIC) - { - strcat(t_info, " basic"); - if( add_comma ) - StringBuf_AppendStr(&buf, ", "); - else - add_comma = true; - StringBuf_Printf(&buf, "`name`='%s', `master`='%s', `char_id`=%d", esc_name, esc_master, g->member[0].char_id); - } - if (flag & GS_CONNECT) - { - strcat(t_info, " connect"); - if( add_comma ) - StringBuf_AppendStr(&buf, ", "); - else - add_comma = true; - StringBuf_Printf(&buf, "`connect_member`=%d, `average_lv`=%d", g->connect_member, g->average_lv); - } - if (flag & GS_MES) - { - char esc_mes1[sizeof(g->mes1)*2+1]; - char esc_mes2[sizeof(g->mes2)*2+1]; - - strcat(t_info, " mes"); - if( add_comma ) - StringBuf_AppendStr(&buf, ", "); - else - add_comma = true; - Sql_EscapeStringLen(sql_handle, esc_mes1, g->mes1, strnlen(g->mes1, sizeof(g->mes1))); - Sql_EscapeStringLen(sql_handle, esc_mes2, g->mes2, strnlen(g->mes2, sizeof(g->mes2))); - StringBuf_Printf(&buf, "`mes1`='%s', `mes2`='%s'", esc_mes1, esc_mes2); - } - if (flag & GS_LEVEL) - { - strcat(t_info, " level"); - if( add_comma ) - StringBuf_AppendStr(&buf, ", "); - else - add_comma = true; - StringBuf_Printf(&buf, "`guild_lv`=%d, `skill_point`=%d, `exp`=%"PRIu64", `next_exp`=%u, `max_member`=%d", g->guild_lv, g->skill_point, g->exp, g->next_exp, g->max_member); - } - StringBuf_Printf(&buf, " WHERE `guild_id`=%d", g->guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "%s", StringBuf_Value(&buf)) ) - Sql_ShowDebug(sql_handle); - StringBuf_Destroy(&buf); - } - - if (flag&GS_MEMBER) - { - struct guild_member *m; - - strcat(t_info, " members"); - // Update only needed players - for(i=0;imax_member;i++){ - m = &g->member[i]; - if (!m->modified) - continue; - if(m->account_id) { - //Since nothing references guild member table as foreign keys, it's safe to use REPLACE INTO - Sql_EscapeStringLen(sql_handle, esc_name, m->name, strnlen(m->name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) " - "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%"PRIu64"','%d','%d','%d','%s')", - guild_member_db, g->guild_id, m->account_id, m->char_id, - m->hair, m->hair_color, m->gender, - m->class_, m->lv, m->exp, m->exp_payper, m->online, m->position, esc_name) ) - Sql_ShowDebug(sql_handle); - if (m->modified & GS_MEMBER_NEW) - { - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '%d' WHERE `char_id` = '%d'", - char_db, g->guild_id, m->char_id) ) - Sql_ShowDebug(sql_handle); - } - m->modified = GS_MEMBER_UNMODIFIED; - } - } - } - - if (flag&GS_POSITION){ - strcat(t_info, " positions"); - //printf("- Insert guild %d to guild_position\n",g->guild_id); - for(i=0;iposition[i]; - if (!p->modified) - continue; - Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) VALUES ('%d','%d','%s','%d','%d')", - guild_position_db, g->guild_id, i, esc_name, p->mode, p->exp_mode) ) - Sql_ShowDebug(sql_handle); - p->modified = GS_POSITION_UNMODIFIED; - } - } - - if (flag&GS_ALLIANCE) - { - // Delete current alliances - // NOTE: no need to do it on both sides since both guilds in memory had - // their info changed, not to mention this would also mess up oppositions! - // [Skotlex] - //if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d' OR `alliance_id`='%d'", guild_alliance_db, g->guild_id, g->guild_id) ) - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", guild_alliance_db, g->guild_id) ) - { - Sql_ShowDebug(sql_handle); - } - else - { - //printf("- Insert guild %d to guild_alliance\n",g->guild_id); - for(i=0;ialliance[i]; - if(a->guild_id>0) - { - Sql_EscapeStringLen(sql_handle, esc_name, a->name, strnlen(a->name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`opposition`,`alliance_id`,`name`) " - "VALUES ('%d','%d','%d','%s')", - guild_alliance_db, g->guild_id, a->opposition, a->guild_id, esc_name) ) - Sql_ShowDebug(sql_handle); - } - } - } - } - - if (flag&GS_EXPULSION){ - strcat(t_info, " expulsions"); - //printf("- Insert guild %d to guild_expulsion\n",g->guild_id); - for(i=0;iexpulsion[i]; - if(e->account_id>0){ - char esc_mes[sizeof(e->mes)*2+1]; - - Sql_EscapeStringLen(sql_handle, esc_name, e->name, strnlen(e->name, NAME_LENGTH)); - Sql_EscapeStringLen(sql_handle, esc_mes, e->mes, strnlen(e->mes, sizeof(e->mes))); - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`account_id`,`name`,`mes`) " - "VALUES ('%d','%d','%s','%s')", guild_expulsion_db, g->guild_id, e->account_id, esc_name, esc_mes) ) - Sql_ShowDebug(sql_handle); - } - } - } - - if (flag&GS_SKILL){ - strcat(t_info, " skills"); - //printf("- Insert guild %d to guild_skill\n",g->guild_id); - for(i=0;iskill[i].id>0 && g->skill[i].lv>0){ - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`id`,`lv`) VALUES ('%d','%d','%d')", - guild_skill_db, g->guild_id, g->skill[i].id, g->skill[i].lv) ) - Sql_ShowDebug(sql_handle); - } - } - } - - if (save_log) - ShowInfo("Saved guild (%d - %s):%s\n",g->guild_id,g->name,t_info); - return 1; + Sql_EscapeStringLen(sql_handle, esc_name, g->name, strnlen(g->name, NAME_LENGTH)); + Sql_EscapeStringLen(sql_handle, esc_master, g->master, strnlen(g->master, NAME_LENGTH)); + *t_info = '\0'; + + // Insert a new guild the guild + if (flag&GS_BASIC && g->guild_id == -1) { + strcat(t_info, " guild_create"); + + // Create a new guild + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " + "(`name`,`master`,`guild_lv`,`max_member`,`average_lv`,`char_id`) " + "VALUES ('%s', '%s', '%d', '%d', '%d', '%d')", + guild_db, esc_name, esc_master, g->guild_lv, g->max_member, g->average_lv, g->member[0].char_id)) { + Sql_ShowDebug(sql_handle); + if (g->guild_id == -1) + return 0; //Failed to create guild! + } else { + g->guild_id = (int)Sql_LastInsertId(sql_handle); + new_guild = 1; + } + } + + // If we need an update on an existing guild or more update on the new guild + if (((flag & GS_BASIC_MASK) && !new_guild) || ((flag & (GS_BASIC_MASK & ~GS_BASIC)) && new_guild)) { + StringBuf buf; + bool add_comma = false; + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET ", guild_db); + + if (flag & GS_EMBLEM) { + char emblem_data[sizeof(g->emblem_data)*2+1]; + char *pData = emblem_data; + + strcat(t_info, " emblem"); + // Convert emblem_data to hex + //TODO: why not use binary directly? [ultramage] + for (i=0; iemblem_len; i++) { + *pData++ = dataToHex[(g->emblem_data[i] >> 4) & 0x0F]; + *pData++ = dataToHex[g->emblem_data[i] & 0x0F]; + } + *pData = 0; + StringBuf_Printf(&buf, "`emblem_len`=%d, `emblem_id`=%d, `emblem_data`='%s'", g->emblem_len, g->emblem_id, emblem_data); + add_comma = true; + } + if (flag & GS_BASIC) { + strcat(t_info, " basic"); + if (add_comma) + StringBuf_AppendStr(&buf, ", "); + else + add_comma = true; + StringBuf_Printf(&buf, "`name`='%s', `master`='%s', `char_id`=%d", esc_name, esc_master, g->member[0].char_id); + } + if (flag & GS_CONNECT) { + strcat(t_info, " connect"); + if (add_comma) + StringBuf_AppendStr(&buf, ", "); + else + add_comma = true; + StringBuf_Printf(&buf, "`connect_member`=%d, `average_lv`=%d", g->connect_member, g->average_lv); + } + if (flag & GS_MES) { + char esc_mes1[sizeof(g->mes1)*2+1]; + char esc_mes2[sizeof(g->mes2)*2+1]; + + strcat(t_info, " mes"); + if (add_comma) + StringBuf_AppendStr(&buf, ", "); + else + add_comma = true; + Sql_EscapeStringLen(sql_handle, esc_mes1, g->mes1, strnlen(g->mes1, sizeof(g->mes1))); + Sql_EscapeStringLen(sql_handle, esc_mes2, g->mes2, strnlen(g->mes2, sizeof(g->mes2))); + StringBuf_Printf(&buf, "`mes1`='%s', `mes2`='%s'", esc_mes1, esc_mes2); + } + if (flag & GS_LEVEL) { + strcat(t_info, " level"); + if (add_comma) + StringBuf_AppendStr(&buf, ", "); + else + add_comma = true; + StringBuf_Printf(&buf, "`guild_lv`=%d, `skill_point`=%d, `exp`=%"PRIu64", `next_exp`=%u, `max_member`=%d", g->guild_lv, g->skill_point, g->exp, g->next_exp, g->max_member); + } + StringBuf_Printf(&buf, " WHERE `guild_id`=%d", g->guild_id); + if (SQL_ERROR == Sql_Query(sql_handle, "%s", StringBuf_Value(&buf))) + Sql_ShowDebug(sql_handle); + StringBuf_Destroy(&buf); + } + + if (flag&GS_MEMBER) { + struct guild_member *m; + + strcat(t_info, " members"); + // Update only needed players + for (i=0; imax_member; i++) { + m = &g->member[i]; + if (!m->modified) + continue; + if (m->account_id) { + //Since nothing references guild member table as foreign keys, it's safe to use REPLACE INTO + Sql_EscapeStringLen(sql_handle, esc_name, m->name, strnlen(m->name, NAME_LENGTH)); + if (SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) " + "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%"PRIu64"','%d','%d','%d','%s')", + guild_member_db, g->guild_id, m->account_id, m->char_id, + m->hair, m->hair_color, m->gender, + m->class_, m->lv, m->exp, m->exp_payper, m->online, m->position, esc_name)) + Sql_ShowDebug(sql_handle); + if (m->modified & GS_MEMBER_NEW) { + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '%d' WHERE `char_id` = '%d'", + char_db, g->guild_id, m->char_id)) + Sql_ShowDebug(sql_handle); + } + m->modified = GS_MEMBER_UNMODIFIED; + } + } + } + + if (flag&GS_POSITION) { + strcat(t_info, " positions"); + //printf("- Insert guild %d to guild_position\n",g->guild_id); + for (i=0; iposition[i]; + if (!p->modified) + continue; + Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); + if (SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) VALUES ('%d','%d','%s','%d','%d')", + guild_position_db, g->guild_id, i, esc_name, p->mode, p->exp_mode)) + Sql_ShowDebug(sql_handle); + p->modified = GS_POSITION_UNMODIFIED; + } + } + + if (flag&GS_ALLIANCE) { + // Delete current alliances + // NOTE: no need to do it on both sides since both guilds in memory had + // their info changed, not to mention this would also mess up oppositions! + // [Skotlex] + //if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d' OR `alliance_id`='%d'", guild_alliance_db, g->guild_id, g->guild_id) ) + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", guild_alliance_db, g->guild_id)) { + Sql_ShowDebug(sql_handle); + } else { + //printf("- Insert guild %d to guild_alliance\n",g->guild_id); + for (i=0; ialliance[i]; + if (a->guild_id>0) { + Sql_EscapeStringLen(sql_handle, esc_name, a->name, strnlen(a->name, NAME_LENGTH)); + if (SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`opposition`,`alliance_id`,`name`) " + "VALUES ('%d','%d','%d','%s')", + guild_alliance_db, g->guild_id, a->opposition, a->guild_id, esc_name)) + Sql_ShowDebug(sql_handle); + } + } + } + } + + if (flag&GS_EXPULSION) { + strcat(t_info, " expulsions"); + //printf("- Insert guild %d to guild_expulsion\n",g->guild_id); + for (i=0; iexpulsion[i]; + if (e->account_id>0) { + char esc_mes[sizeof(e->mes)*2+1]; + + Sql_EscapeStringLen(sql_handle, esc_name, e->name, strnlen(e->name, NAME_LENGTH)); + Sql_EscapeStringLen(sql_handle, esc_mes, e->mes, strnlen(e->mes, sizeof(e->mes))); + if (SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`account_id`,`name`,`mes`) " + "VALUES ('%d','%d','%s','%s')", guild_expulsion_db, g->guild_id, e->account_id, esc_name, esc_mes)) + Sql_ShowDebug(sql_handle); + } + } + } + + if (flag&GS_SKILL) { + strcat(t_info, " skills"); + //printf("- Insert guild %d to guild_skill\n",g->guild_id); + for (i=0; iskill[i].id>0 && g->skill[i].lv>0) { + if (SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`id`,`lv`) VALUES ('%d','%d','%d')", + guild_skill_db, g->guild_id, g->skill[i].id, g->skill[i].lv)) + Sql_ShowDebug(sql_handle); + } + } + } + + if (save_log) + ShowInfo("Saved guild (%d - %s):%s\n",g->guild_id,g->name,t_info); + return 1; } // Read guild from sql -struct guild * inter_guild_fromsql(int guild_id) -{ - struct guild *g; - char* data; - size_t len; - char* p; - int i; +struct guild *inter_guild_fromsql(int guild_id) { + struct guild *g; + char *data; + size_t len; + char *p; + int i; - if( guild_id <= 0 ) - return NULL; + if (guild_id <= 0) + return NULL; - g = (struct guild*)idb_get(guild_db_, guild_id); - if( g ) - return g; + g = (struct guild *)idb_get(guild_db_, guild_id); + if (g) + return g; #ifdef NOISY - ShowInfo("Guild load request (%d)...\n", guild_id); + ShowInfo("Guild load request (%d)...\n", guild_id); #endif - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT g.`name`,c.`name`,g.`guild_lv`,g.`connect_member`,g.`max_member`,g.`average_lv`,g.`exp`,g.`next_exp`,g.`skill_point`,g.`mes1`,g.`mes2`,g.`emblem_len`,g.`emblem_id`,g.`emblem_data` " - "FROM `%s` g LEFT JOIN `%s` c ON c.`char_id` = g.`char_id` WHERE g.`guild_id`='%d'", guild_db, char_db, guild_id) ) - { - Sql_ShowDebug(sql_handle); - return NULL; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - return NULL;// Guild does not exists. - - CREATE(g, struct guild, 1); - - g->guild_id = guild_id; - Sql_GetData(sql_handle, 0, &data, &len); memcpy(g->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 1, &data, &len); memcpy(g->master, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 2, &data, NULL); g->guild_lv = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); g->connect_member = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); g->max_member = atoi(data); - if( g->max_member > MAX_GUILD ) - { // Fix reduction of MAX_GUILD [PoW] - ShowWarning("Guild %d:%s specifies higher capacity (%d) than MAX_GUILD (%d)\n", guild_id, g->name, g->max_member, MAX_GUILD); - g->max_member = MAX_GUILD; - } - Sql_GetData(sql_handle, 5, &data, NULL); g->average_lv = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); g->exp = strtoull(data, NULL, 10); - Sql_GetData(sql_handle, 7, &data, NULL); g->next_exp = (unsigned int)strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 8, &data, NULL); g->skill_point = atoi(data); - Sql_GetData(sql_handle, 9, &data, &len); memcpy(g->mes1, data, min(len, sizeof(g->mes1))); - Sql_GetData(sql_handle, 10, &data, &len); memcpy(g->mes2, data, min(len, sizeof(g->mes2))); - Sql_GetData(sql_handle, 11, &data, &len); g->emblem_len = atoi(data); - Sql_GetData(sql_handle, 12, &data, &len); g->emblem_id = atoi(data); - Sql_GetData(sql_handle, 13, &data, &len); - // convert emblem data from hexadecimal to binary - //TODO: why not store it in the db as binary directly? [ultramage] - for( i = 0, p = g->emblem_data; i < g->emblem_len; ++i, ++p ) - { - if( *data >= '0' && *data <= '9' ) - *p = *data - '0'; - else if( *data >= 'a' && *data <= 'f' ) - *p = *data - 'a' + 10; - else if( *data >= 'A' && *data <= 'F' ) - *p = *data - 'A' + 10; - *p <<= 4; - ++data; - - if( *data >= '0' && *data <= '9' ) - *p |= *data - '0'; - else if( *data >= 'a' && *data <= 'f' ) - *p |= *data - 'a' + 10; - else if( *data >= 'A' && *data <= 'F' ) - *p |= *data - 'A' + 10; - ++data; - } - - // load guild member info - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name` " - "FROM `%s` WHERE `guild_id`='%d' ORDER BY `position`", guild_member_db, guild_id) ) - { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - for( i = 0; i < g->max_member && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - struct guild_member* m = &g->member[i]; - - Sql_GetData(sql_handle, 0, &data, NULL); m->account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); m->char_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); m->hair = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); m->hair_color = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); m->gender = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); m->class_ = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); m->lv = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); m->exp = strtoull(data, NULL, 10); - Sql_GetData(sql_handle, 8, &data, NULL); m->exp_payper = (unsigned int)atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); m->online = atoi(data); - Sql_GetData(sql_handle, 10, &data, NULL); m->position = atoi(data); - if( m->position >= MAX_GUILDPOSITION ) // Fix reduction of MAX_GUILDPOSITION [PoW] - m->position = MAX_GUILDPOSITION - 1; - Sql_GetData(sql_handle, 11, &data, &len); memcpy(m->name, data, min(len, NAME_LENGTH)); - m->modified = GS_MEMBER_UNMODIFIED; - } - - //printf("- Read guild_position %d from sql \n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `position`,`name`,`mode`,`exp_mode` FROM `%s` WHERE `guild_id`='%d'", guild_position_db, guild_id) ) - { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - int position; - struct guild_position* p; - - Sql_GetData(sql_handle, 0, &data, NULL); position = atoi(data); - if( position < 0 || position >= MAX_GUILDPOSITION ) - continue;// invalid position - p = &g->position[position]; - Sql_GetData(sql_handle, 1, &data, &len); memcpy(p->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 2, &data, NULL); p->mode = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); p->exp_mode = atoi(data); - p->modified = GS_POSITION_UNMODIFIED; - } - - //printf("- Read guild_alliance %d from sql \n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `opposition`,`alliance_id`,`name` FROM `%s` WHERE `guild_id`='%d'", guild_alliance_db, guild_id) ) - { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - for( i = 0; i < MAX_GUILDALLIANCE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - struct guild_alliance* a = &g->alliance[i]; - - Sql_GetData(sql_handle, 0, &data, NULL); a->opposition = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); a->guild_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, &len); memcpy(a->name, data, min(len, NAME_LENGTH)); - } - - //printf("- Read guild_expulsion %d from sql \n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name`,`mes` FROM `%s` WHERE `guild_id`='%d'", guild_expulsion_db, guild_id) ) - { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - for( i = 0; i < MAX_GUILDEXPULSION && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - struct guild_expulsion *e = &g->expulsion[i]; - - Sql_GetData(sql_handle, 0, &data, NULL); e->account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, &len); memcpy(e->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 2, &data, &len); memcpy(e->mes, data, min(len, sizeof(e->mes))); - } - - //printf("- Read guild_skill %d from sql \n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `%s` WHERE `guild_id`='%d' ORDER BY `id`", guild_skill_db, guild_id) ) - { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - - for(i = 0; i < MAX_GUILDSKILL; i++) - { //Skill IDs must always be initialized. [Skotlex] - g->skill[i].id = i + GD_SKILLBASE; - } - - while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - int id; - Sql_GetData(sql_handle, 0, &data, NULL); id = atoi(data) - GD_SKILLBASE; - if( id < 0 && id >= MAX_GUILDSKILL ) - continue;// invalid guild skill - Sql_GetData(sql_handle, 1, &data, NULL); g->skill[id].lv = atoi(data); - } - Sql_FreeResult(sql_handle); - - idb_put(guild_db_, guild_id, g); //Add to cache - g->save_flag |= GS_REMOVE; //But set it to be removed, in case it is not needed for long. - - if (save_log) - ShowInfo("Guild loaded (%d - %s)\n", guild_id, g->name); - - return g; + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT g.`name`,c.`name`,g.`guild_lv`,g.`connect_member`,g.`max_member`,g.`average_lv`,g.`exp`,g.`next_exp`,g.`skill_point`,g.`mes1`,g.`mes2`,g.`emblem_len`,g.`emblem_id`,g.`emblem_data` " + "FROM `%s` g LEFT JOIN `%s` c ON c.`char_id` = g.`char_id` WHERE g.`guild_id`='%d'", guild_db, char_db, guild_id)) { + Sql_ShowDebug(sql_handle); + return NULL; + } + + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) + return NULL;// Guild does not exists. + + CREATE(g, struct guild, 1); + + g->guild_id = guild_id; + Sql_GetData(sql_handle, 0, &data, &len); + memcpy(g->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 1, &data, &len); + memcpy(g->master, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 2, &data, NULL); + g->guild_lv = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + g->connect_member = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + g->max_member = atoi(data); + if (g->max_member > MAX_GUILD) { + // Fix reduction of MAX_GUILD [PoW] + ShowWarning("Guild %d:%s specifies higher capacity (%d) than MAX_GUILD (%d)\n", guild_id, g->name, g->max_member, MAX_GUILD); + g->max_member = MAX_GUILD; + } + Sql_GetData(sql_handle, 5, &data, NULL); + g->average_lv = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + g->exp = strtoull(data, NULL, 10); + Sql_GetData(sql_handle, 7, &data, NULL); + g->next_exp = (unsigned int)strtoul(data, NULL, 10); + Sql_GetData(sql_handle, 8, &data, NULL); + g->skill_point = atoi(data); + Sql_GetData(sql_handle, 9, &data, &len); + memcpy(g->mes1, data, min(len, sizeof(g->mes1))); + Sql_GetData(sql_handle, 10, &data, &len); + memcpy(g->mes2, data, min(len, sizeof(g->mes2))); + Sql_GetData(sql_handle, 11, &data, &len); + g->emblem_len = atoi(data); + Sql_GetData(sql_handle, 12, &data, &len); + g->emblem_id = atoi(data); + Sql_GetData(sql_handle, 13, &data, &len); + // convert emblem data from hexadecimal to binary + //TODO: why not store it in the db as binary directly? [ultramage] + for (i = 0, p = g->emblem_data; i < g->emblem_len; ++i, ++p) { + if (*data >= '0' && *data <= '9') + *p = *data - '0'; + else if (*data >= 'a' && *data <= 'f') + *p = *data - 'a' + 10; + else if (*data >= 'A' && *data <= 'F') + *p = *data - 'A' + 10; + *p <<= 4; + ++data; + + if (*data >= '0' && *data <= '9') + *p |= *data - '0'; + else if (*data >= 'a' && *data <= 'f') + *p |= *data - 'a' + 10; + else if (*data >= 'A' && *data <= 'F') + *p |= *data - 'A' + 10; + ++data; + } + + // load guild member info + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name` " + "FROM `%s` WHERE `guild_id`='%d' ORDER BY `position`", guild_member_db, guild_id)) { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } + for (i = 0; i < g->max_member && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + struct guild_member *m = &g->member[i]; + + Sql_GetData(sql_handle, 0, &data, NULL); + m->account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + m->char_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + m->hair = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + m->hair_color = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + m->gender = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + m->class_ = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + m->lv = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); + m->exp = strtoull(data, NULL, 10); + Sql_GetData(sql_handle, 8, &data, NULL); + m->exp_payper = (unsigned int)atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); + m->online = atoi(data); + Sql_GetData(sql_handle, 10, &data, NULL); + m->position = atoi(data); + if (m->position >= MAX_GUILDPOSITION) // Fix reduction of MAX_GUILDPOSITION [PoW] + m->position = MAX_GUILDPOSITION - 1; + Sql_GetData(sql_handle, 11, &data, &len); + memcpy(m->name, data, min(len, NAME_LENGTH)); + m->modified = GS_MEMBER_UNMODIFIED; + } + + //printf("- Read guild_position %d from sql \n",guild_id); + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `position`,`name`,`mode`,`exp_mode` FROM `%s` WHERE `guild_id`='%d'", guild_position_db, guild_id)) { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } + while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + int position; + struct guild_position *p; + + Sql_GetData(sql_handle, 0, &data, NULL); + position = atoi(data); + if (position < 0 || position >= MAX_GUILDPOSITION) + continue;// invalid position + p = &g->position[position]; + Sql_GetData(sql_handle, 1, &data, &len); + memcpy(p->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 2, &data, NULL); + p->mode = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + p->exp_mode = atoi(data); + p->modified = GS_POSITION_UNMODIFIED; + } + + //printf("- Read guild_alliance %d from sql \n",guild_id); + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `opposition`,`alliance_id`,`name` FROM `%s` WHERE `guild_id`='%d'", guild_alliance_db, guild_id)) { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } + for (i = 0; i < MAX_GUILDALLIANCE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + struct guild_alliance *a = &g->alliance[i]; + + Sql_GetData(sql_handle, 0, &data, NULL); + a->opposition = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + a->guild_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(a->name, data, min(len, NAME_LENGTH)); + } + + //printf("- Read guild_expulsion %d from sql \n",guild_id); + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name`,`mes` FROM `%s` WHERE `guild_id`='%d'", guild_expulsion_db, guild_id)) { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } + for (i = 0; i < MAX_GUILDEXPULSION && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + struct guild_expulsion *e = &g->expulsion[i]; + + Sql_GetData(sql_handle, 0, &data, NULL); + e->account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, &len); + memcpy(e->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(e->mes, data, min(len, sizeof(e->mes))); + } + + //printf("- Read guild_skill %d from sql \n",guild_id); + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `%s` WHERE `guild_id`='%d' ORDER BY `id`", guild_skill_db, guild_id)) { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } + + for (i = 0; i < MAX_GUILDSKILL; i++) { + //Skill IDs must always be initialized. [Skotlex] + g->skill[i].id = i + GD_SKILLBASE; + } + + while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + int id; + Sql_GetData(sql_handle, 0, &data, NULL); + id = atoi(data) - GD_SKILLBASE; + if (id < 0 && id >= MAX_GUILDSKILL) + continue;// invalid guild skill + Sql_GetData(sql_handle, 1, &data, NULL); + g->skill[id].lv = atoi(data); + } + Sql_FreeResult(sql_handle); + + idb_put(guild_db_, guild_id, g); //Add to cache + g->save_flag |= GS_REMOVE; //But set it to be removed, in case it is not needed for long. + + if (save_log) + ShowInfo("Guild loaded (%d - %s)\n", guild_id, g->name); + + return g; } // `guild_castle` (`castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, `triggerD`, `nextTime`, `payTime`, `createTime`, `visibleC`, `visibleG0`, `visibleG1`, `visibleG2`, `visibleG3`, `visibleG4`, `visibleG5`, `visibleG6`, `visibleG7`) int inter_guildcastle_tosql(struct guild_castle *gc) { - StringBuf buf; - int i; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "REPLACE INTO `%s` SET `castle_id`='%d', `guild_id`='%d', `economy`='%d', `defense`='%d', " - "`triggerE`='%d', `triggerD`='%d', `nextTime`='%d', `payTime`='%d', `createTime`='%d', `visibleC`='%d'", - guild_castle_db, gc->castle_id, gc->guild_id, gc->economy, gc->defense, - gc->triggerE, gc->triggerD, gc->nextTime, gc->payTime, gc->createTime, gc->visibleC); - for (i = 0; i < MAX_GUARDIANS; ++i) - StringBuf_Printf(&buf, ", `visibleG%d`='%d'", i, gc->guardian[i].visible); - - if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) - Sql_ShowDebug(sql_handle); - else if(save_log) - ShowInfo("Saved guild castle (%d)\n", gc->castle_id); - - StringBuf_Destroy(&buf); - return 0; + StringBuf buf; + int i; + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "REPLACE INTO `%s` SET `castle_id`='%d', `guild_id`='%d', `economy`='%d', `defense`='%d', " + "`triggerE`='%d', `triggerD`='%d', `nextTime`='%d', `payTime`='%d', `createTime`='%d', `visibleC`='%d'", + guild_castle_db, gc->castle_id, gc->guild_id, gc->economy, gc->defense, + gc->triggerE, gc->triggerD, gc->nextTime, gc->payTime, gc->createTime, gc->visibleC); + for (i = 0; i < MAX_GUARDIANS; ++i) + StringBuf_Printf(&buf, ", `visibleG%d`='%d'", i, gc->guardian[i].visible); + + if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) + Sql_ShowDebug(sql_handle); + else if (save_log) + ShowInfo("Saved guild castle (%d)\n", gc->castle_id); + + StringBuf_Destroy(&buf); + return 0; } // Read guild_castle from SQL -static struct guild_castle* inter_guildcastle_fromsql(int castle_id) -{ - char *data; - int i; - StringBuf buf; - struct guild_castle *gc = idb_get(castle_db, castle_id); - - if (gc != NULL) - return gc; - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, " - "`triggerD`, `nextTime`, `payTime`, `createTime`, `visibleC`"); - for (i = 0; i < MAX_GUARDIANS; ++i) - StringBuf_Printf(&buf, ", `visibleG%d`", i); - StringBuf_Printf(&buf, " FROM `%s` WHERE `castle_id`='%d'", guild_castle_db, castle_id); - if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) { - Sql_ShowDebug(sql_handle); - StringBuf_Destroy(&buf); - return NULL; - } - StringBuf_Destroy(&buf); - - CREATE(gc, struct guild_castle, 1); - gc->castle_id = castle_id; - - if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { - Sql_GetData(sql_handle, 1, &data, NULL); gc->guild_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); gc->economy = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); gc->defense = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); gc->triggerE = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); gc->triggerD = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); gc->nextTime = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); gc->payTime = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); gc->createTime = atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); gc->visibleC = atoi(data); - for (i = 10; i < 10+MAX_GUARDIANS; i++) { - Sql_GetData(sql_handle, i, &data, NULL); gc->guardian[i-10].visible = atoi(data); - } - } - Sql_FreeResult(sql_handle); - - idb_put(castle_db, castle_id, gc); - - if (save_log) - ShowInfo("Loaded guild castle (%d - guild %d)\n", castle_id, gc->guild_id); - - return gc; +static struct guild_castle *inter_guildcastle_fromsql(int castle_id) { + char *data; + int i; + StringBuf buf; + struct guild_castle *gc = idb_get(castle_db, castle_id); + + if (gc != NULL) + return gc; + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, " + "`triggerD`, `nextTime`, `payTime`, `createTime`, `visibleC`"); + for (i = 0; i < MAX_GUARDIANS; ++i) + StringBuf_Printf(&buf, ", `visibleG%d`", i); + StringBuf_Printf(&buf, " FROM `%s` WHERE `castle_id`='%d'", guild_castle_db, castle_id); + if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + StringBuf_Destroy(&buf); + return NULL; + } + StringBuf_Destroy(&buf); + + CREATE(gc, struct guild_castle, 1); + gc->castle_id = castle_id; + + if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + Sql_GetData(sql_handle, 1, &data, NULL); + gc->guild_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + gc->economy = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + gc->defense = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + gc->triggerE = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + gc->triggerD = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + gc->nextTime = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); + gc->payTime = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); + gc->createTime = atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); + gc->visibleC = atoi(data); + for (i = 10; i < 10+MAX_GUARDIANS; i++) { + Sql_GetData(sql_handle, i, &data, NULL); + gc->guardian[i-10].visible = atoi(data); + } + } + Sql_FreeResult(sql_handle); + + idb_put(castle_db, castle_id, gc); + + if (save_log) + ShowInfo("Loaded guild castle (%d - guild %d)\n", castle_id, gc->guild_id); + + return gc; } // Read exp_guild.txt int inter_guild_ReadEXP(void) { - int i; - FILE *fp; - char line[1024]; - for (i=0;i<100;i++) guild_exp[i]=0; - //this is going to be discussed, temp fix - sprintf(line, "%s/pre-re/exp_guild.txt", db_path); - fp=fopen(line,"r"); - if(fp==NULL){ - ShowError("can't read %s\n", line); - return 1; - } - i=0; - while(fgets(line, sizeof(line), fp) && i < 100) - { - if(line[0]=='/' && line[1]=='/') - continue; - guild_exp[i]=(unsigned int)atof(line); - i++; - } - fclose(fp); - - return 0; + int i; + FILE *fp; + char line[1024]; + for (i=0; i<100; i++) guild_exp[i]=0; + //this is going to be discussed, temp fix + sprintf(line, "%s/pre-re/exp_guild.txt", db_path); + fp=fopen(line,"r"); + if (fp==NULL) { + ShowError("can't read %s\n", line); + return 1; + } + i=0; + while (fgets(line, sizeof(line), fp) && i < 100) { + if (line[0]=='/' && line[1]=='/') + continue; + guild_exp[i]=(unsigned int)atof(line); + i++; + } + fclose(fp); + + return 0; } int inter_guild_CharOnline(int char_id, int guild_id) { - struct guild *g; - int i; - - if (guild_id == -1) { - //Get guild_id from the database - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - - if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); - guild_id = atoi(data); - } - else - { - guild_id = 0; - } - Sql_FreeResult(sql_handle); - } - if (guild_id == 0) - return 0; //No guild... - - g = inter_guild_fromsql(guild_id); - if(!g) { - ShowError("Character %d's guild %d not found!\n", char_id, guild_id); - return 0; - } - - //Member has logged in before saving, tell saver not to delete - if(g->save_flag & GS_REMOVE) - g->save_flag &= ~GS_REMOVE; - - //Set member online - ARR_FIND( 0, g->max_member, i, g->member[i].char_id == char_id ); - if( i < g->max_member ) - { - g->member[i].online = 1; - g->member[i].modified = GS_MEMBER_MODIFIED; - } - - return 1; + struct guild *g; + int i; + + if (guild_id == -1) { + //Get guild_id from the database + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", char_db, char_id)) { + Sql_ShowDebug(sql_handle); + return 0; + } + + if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + char *data; + + Sql_GetData(sql_handle, 0, &data, NULL); + guild_id = atoi(data); + } else { + guild_id = 0; + } + Sql_FreeResult(sql_handle); + } + if (guild_id == 0) + return 0; //No guild... + + g = inter_guild_fromsql(guild_id); + if (!g) { + ShowError("Character %d's guild %d not found!\n", char_id, guild_id); + return 0; + } + + //Member has logged in before saving, tell saver not to delete + if (g->save_flag & GS_REMOVE) + g->save_flag &= ~GS_REMOVE; + + //Set member online + ARR_FIND(0, g->max_member, i, g->member[i].char_id == char_id); + if (i < g->max_member) { + g->member[i].online = 1; + g->member[i].modified = GS_MEMBER_MODIFIED; + } + + return 1; } int inter_guild_CharOffline(int char_id, int guild_id) { - struct guild *g=NULL; - int online_count, i; - - if (guild_id == -1) - { - //Get guild_id from the database - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - - if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); - guild_id = atoi(data); - } - else - { - guild_id = 0; - } - Sql_FreeResult(sql_handle); - } - if (guild_id == 0) - return 0; //No guild... - - //Character has a guild, set character offline and check if they were the only member online - g = inter_guild_fromsql(guild_id); - if (g == NULL) //Guild not found? - return 0; - - //Set member offline - ARR_FIND( 0, g->max_member, i, g->member[i].char_id == char_id ); - if( i < g->max_member ) - { - g->member[i].online = 0; - g->member[i].modified = GS_MEMBER_MODIFIED; - } - - online_count = 0; - for( i = 0; i < g->max_member; i++ ) - if( g->member[i].online ) - online_count++; - - // Remove guild from memory if no players online - if( online_count == 0 ) - g->save_flag |= GS_REMOVE; - - return 1; + struct guild *g=NULL; + int online_count, i; + + if (guild_id == -1) { + //Get guild_id from the database + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", char_db, char_id)) { + Sql_ShowDebug(sql_handle); + return 0; + } + + if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + char *data; + + Sql_GetData(sql_handle, 0, &data, NULL); + guild_id = atoi(data); + } else { + guild_id = 0; + } + Sql_FreeResult(sql_handle); + } + if (guild_id == 0) + return 0; //No guild... + + //Character has a guild, set character offline and check if they were the only member online + g = inter_guild_fromsql(guild_id); + if (g == NULL) //Guild not found? + return 0; + + //Set member offline + ARR_FIND(0, g->max_member, i, g->member[i].char_id == char_id); + if (i < g->max_member) { + g->member[i].online = 0; + g->member[i].modified = GS_MEMBER_MODIFIED; + } + + online_count = 0; + for (i = 0; i < g->max_member; i++) + if (g->member[i].online) + online_count++; + + // Remove guild from memory if no players online + if (online_count == 0) + g->save_flag |= GS_REMOVE; + + return 1; } // Initialize guild sql int inter_guild_sql_init(void) { - //Initialize the guild cache - guild_db_= idb_alloc(DB_OPT_RELEASE_DATA); - castle_db = idb_alloc(DB_OPT_RELEASE_DATA); - - //Read exp file - inter_guild_ReadEXP(); - - add_timer_func_list(guild_save_timer, "guild_save_timer"); - add_timer(gettick() + 10000, guild_save_timer, 0, 0); - return 0; + //Initialize the guild cache + guild_db_= idb_alloc(DB_OPT_RELEASE_DATA); + castle_db = idb_alloc(DB_OPT_RELEASE_DATA); + + //Read exp file + inter_guild_ReadEXP(); + + add_timer_func_list(guild_save_timer, "guild_save_timer"); + add_timer(gettick() + 10000, guild_save_timer, 0, 0); + return 0; } /** @@ -751,145 +751,134 @@ int inter_guild_sql_init(void) */ static int guild_db_final(DBKey key, DBData *data, va_list ap) { - struct guild *g = db_data2ptr(data); - if (g->save_flag&GS_MASK) { - inter_guild_tosql(g, g->save_flag&GS_MASK); - return 1; - } - return 0; + struct guild *g = db_data2ptr(data); + if (g->save_flag&GS_MASK) { + inter_guild_tosql(g, g->save_flag&GS_MASK); + return 1; + } + return 0; } void inter_guild_sql_final(void) { - guild_db_->destroy(guild_db_, guild_db_final); - db_destroy(castle_db); - return; + guild_db_->destroy(guild_db_, guild_db_final); + db_destroy(castle_db); + return; } // Get guild_id by its name. Returns 0 if not found, -1 on error. int search_guildname(char *str) { - int guild_id; - char esc_name[NAME_LENGTH*2+1]; - - Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH)); - //Lookup guilds with the same name - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE name='%s'", guild_db, esc_name) ) - { - Sql_ShowDebug(sql_handle); - return -1; - } - - if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); - guild_id = atoi(data); - } - else - { - guild_id = 0; - } - Sql_FreeResult(sql_handle); - return guild_id; + int guild_id; + char esc_name[NAME_LENGTH*2+1]; + + Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH)); + //Lookup guilds with the same name + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE name='%s'", guild_db, esc_name)) { + Sql_ShowDebug(sql_handle); + return -1; + } + + if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + char *data; + + Sql_GetData(sql_handle, 0, &data, NULL); + guild_id = atoi(data); + } else { + guild_id = 0; + } + Sql_FreeResult(sql_handle); + return guild_id; } // Check if guild is empty static bool guild_check_empty(struct guild *g) { - int i; - ARR_FIND( 0, g->max_member, i, g->member[i].account_id > 0 ); - if( i < g->max_member) - return false; // not empty - - //Let the calling function handle the guild removal in case they need - //to do something else with it before freeing the data. [Skotlex] - return true; + int i; + ARR_FIND(0, g->max_member, i, g->member[i].account_id > 0); + if (i < g->max_member) + return false; // not empty + + //Let the calling function handle the guild removal in case they need + //to do something else with it before freeing the data. [Skotlex] + return true; } unsigned int guild_nextexp(int level) { - if (level == 0) - return 1; - if (level < 100 && level > 0) // Change by hack - return guild_exp[level-1]; + if (level == 0) + return 1; + if (level < 100 && level > 0) // Change by hack + return guild_exp[level-1]; - return 0; + return 0; } int guild_checkskill(struct guild *g,int id) { - int idx = id - GD_SKILLBASE; + int idx = id - GD_SKILLBASE; - if(idx < 0 || idx >= MAX_GUILDSKILL) - return 0; + if (idx < 0 || idx >= MAX_GUILDSKILL) + return 0; - return g->skill[idx].lv; + return g->skill[idx].lv; } int guild_calcinfo(struct guild *g) { - int i,c; - unsigned int nextexp; - struct guild before = *g; // Save guild current values - - if(g->guild_lv<=0) - g->guild_lv = 1; - nextexp = guild_nextexp(g->guild_lv); - - // Consume guild exp and increase guild level - while(g->exp >= nextexp && nextexp > 0){ //fixed guild exp overflow [Kevin] - g->exp-=nextexp; - g->guild_lv++; - g->skill_point++; - nextexp = guild_nextexp(g->guild_lv); - } - - // Save next exp step - g->next_exp = nextexp; - - // Set the max number of members, Guild Extention skill - currently adds 6 to max per skill lv. - g->max_member = 16 + guild_checkskill(g, GD_EXTENSION) * 6; - if(g->max_member > MAX_GUILD) - { - ShowError("Guild %d:%s has capacity for too many guild members (%d), max supported is %d\n", g->guild_id, g->name, g->max_member, MAX_GUILD); - g->max_member = MAX_GUILD; - } - - // Compute the guild average level level - g->average_lv=0; - g->connect_member=0; - for(i=c=0;imax_member;i++) - { - if(g->member[i].account_id>0) - { - if (g->member[i].lv >= 0) - { - g->average_lv+=g->member[i].lv; - c++; - } - else - { - ShowWarning("Guild %d:%s, member %d:%s has an invalid level %d\n", g->guild_id, g->name, g->member[i].char_id, g->member[i].name, g->member[i].lv); - } - - if(g->member[i].online) - g->connect_member++; - } - } - if(c) - g->average_lv /= c; - - // Check if guild stats has change - if(g->max_member != before.max_member || g->guild_lv != before.guild_lv || g->skill_point != before.skill_point ) - { - g->save_flag |= GS_LEVEL; - mapif_guild_info(-1,g); - return 1; - } - - return 0; + int i,c; + unsigned int nextexp; + struct guild before = *g; // Save guild current values + + if (g->guild_lv<=0) + g->guild_lv = 1; + nextexp = guild_nextexp(g->guild_lv); + + // Consume guild exp and increase guild level + while (g->exp >= nextexp && nextexp > 0) { //fixed guild exp overflow [Kevin] + g->exp-=nextexp; + g->guild_lv++; + g->skill_point++; + nextexp = guild_nextexp(g->guild_lv); + } + + // Save next exp step + g->next_exp = nextexp; + + // Set the max number of members, Guild Extention skill - currently adds 6 to max per skill lv. + g->max_member = 16 + guild_checkskill(g, GD_EXTENSION) * 6; + if (g->max_member > MAX_GUILD) { + ShowError("Guild %d:%s has capacity for too many guild members (%d), max supported is %d\n", g->guild_id, g->name, g->max_member, MAX_GUILD); + g->max_member = MAX_GUILD; + } + + // Compute the guild average level level + g->average_lv=0; + g->connect_member=0; + for (i=c=0; imax_member; i++) { + if (g->member[i].account_id>0) { + if (g->member[i].lv >= 0) { + g->average_lv+=g->member[i].lv; + c++; + } else { + ShowWarning("Guild %d:%s, member %d:%s has an invalid level %d\n", g->guild_id, g->name, g->member[i].char_id, g->member[i].name, g->member[i].lv); + } + + if (g->member[i].online) + g->connect_member++; + } + } + if (c) + g->average_lv /= c; + + // Check if guild stats has change + if (g->max_member != before.max_member || g->guild_lv != before.guild_lv || g->skill_point != before.skill_point) { + g->save_flag |= GS_LEVEL; + mapif_guild_info(-1,g); + return 1; + } + + return 0; } //------------------------------------------------------------------- @@ -897,245 +886,244 @@ int guild_calcinfo(struct guild *g) int mapif_guild_created(int fd,int account_id,struct guild *g) { - WFIFOHEAD(fd, 10); - WFIFOW(fd,0)=0x3830; - WFIFOL(fd,2)=account_id; - if(g != NULL) - { - WFIFOL(fd,6)=g->guild_id; - ShowInfo("int_guild: Guild created (%d - %s)\n",g->guild_id,g->name); - } else - WFIFOL(fd,6)=0; - - WFIFOSET(fd,10); - return 0; + WFIFOHEAD(fd, 10); + WFIFOW(fd,0)=0x3830; + WFIFOL(fd,2)=account_id; + if (g != NULL) { + WFIFOL(fd,6)=g->guild_id; + ShowInfo("int_guild: Guild created (%d - %s)\n",g->guild_id,g->name); + } else + WFIFOL(fd,6)=0; + + WFIFOSET(fd,10); + return 0; } // Guild not found int mapif_guild_noinfo(int fd,int guild_id) { - unsigned char buf[12]; - WBUFW(buf,0)=0x3831; - WBUFW(buf,2)=8; - WBUFL(buf,4)=guild_id; - ShowWarning("int_guild: info not found %d\n",guild_id); - if(fd<0) - mapif_sendall(buf,8); - else - mapif_send(fd,buf,8); - return 0; + unsigned char buf[12]; + WBUFW(buf,0)=0x3831; + WBUFW(buf,2)=8; + WBUFL(buf,4)=guild_id; + ShowWarning("int_guild: info not found %d\n",guild_id); + if (fd<0) + mapif_sendall(buf,8); + else + mapif_send(fd,buf,8); + return 0; } // Send guild info int mapif_guild_info(int fd,struct guild *g) { - unsigned char buf[8+sizeof(struct guild)]; - WBUFW(buf,0)=0x3831; - WBUFW(buf,2)=4+sizeof(struct guild); - memcpy(buf+4,g,sizeof(struct guild)); - if(fd<0) - mapif_sendall(buf,WBUFW(buf,2)); - else - mapif_send(fd,buf,WBUFW(buf,2)); - return 0; + unsigned char buf[8+sizeof(struct guild)]; + WBUFW(buf,0)=0x3831; + WBUFW(buf,2)=4+sizeof(struct guild); + memcpy(buf+4,g,sizeof(struct guild)); + if (fd<0) + mapif_sendall(buf,WBUFW(buf,2)); + else + mapif_send(fd,buf,WBUFW(buf,2)); + return 0; } // ACK member add int mapif_guild_memberadded(int fd,int guild_id,int account_id,int char_id,int flag) { - WFIFOHEAD(fd, 15); - WFIFOW(fd,0)=0x3832; - WFIFOL(fd,2)=guild_id; - WFIFOL(fd,6)=account_id; - WFIFOL(fd,10)=char_id; - WFIFOB(fd,14)=flag; - WFIFOSET(fd,15); - return 0; + WFIFOHEAD(fd, 15); + WFIFOW(fd,0)=0x3832; + WFIFOL(fd,2)=guild_id; + WFIFOL(fd,6)=account_id; + WFIFOL(fd,10)=char_id; + WFIFOB(fd,14)=flag; + WFIFOSET(fd,15); + return 0; } // ACK member leave int mapif_guild_withdraw(int guild_id,int account_id,int char_id,int flag, const char *name, const char *mes) { - unsigned char buf[55+NAME_LENGTH]; - WBUFW(buf, 0)=0x3834; - WBUFL(buf, 2)=guild_id; - WBUFL(buf, 6)=account_id; - WBUFL(buf,10)=char_id; - WBUFB(buf,14)=flag; - memcpy(WBUFP(buf,15),mes,40); - memcpy(WBUFP(buf,55),name,NAME_LENGTH); - mapif_sendall(buf,55+NAME_LENGTH); - ShowInfo("int_guild: guild withdraw (%d - %d: %s - %s)\n",guild_id,account_id,name,mes); - return 0; + unsigned char buf[55+NAME_LENGTH]; + WBUFW(buf, 0)=0x3834; + WBUFL(buf, 2)=guild_id; + WBUFL(buf, 6)=account_id; + WBUFL(buf,10)=char_id; + WBUFB(buf,14)=flag; + memcpy(WBUFP(buf,15),mes,40); + memcpy(WBUFP(buf,55),name,NAME_LENGTH); + mapif_sendall(buf,55+NAME_LENGTH); + ShowInfo("int_guild: guild withdraw (%d - %d: %s - %s)\n",guild_id,account_id,name,mes); + return 0; } // Send short member's info int mapif_guild_memberinfoshort(struct guild *g,int idx) { - unsigned char buf[19]; - WBUFW(buf, 0)=0x3835; - WBUFL(buf, 2)=g->guild_id; - WBUFL(buf, 6)=g->member[idx].account_id; - WBUFL(buf,10)=g->member[idx].char_id; - WBUFB(buf,14)=(unsigned char)g->member[idx].online; - WBUFW(buf,15)=g->member[idx].lv; - WBUFW(buf,17)=g->member[idx].class_; - mapif_sendall(buf,19); - return 0; + unsigned char buf[19]; + WBUFW(buf, 0)=0x3835; + WBUFL(buf, 2)=g->guild_id; + WBUFL(buf, 6)=g->member[idx].account_id; + WBUFL(buf,10)=g->member[idx].char_id; + WBUFB(buf,14)=(unsigned char)g->member[idx].online; + WBUFW(buf,15)=g->member[idx].lv; + WBUFW(buf,17)=g->member[idx].class_; + mapif_sendall(buf,19); + return 0; } // Send guild broken int mapif_guild_broken(int guild_id,int flag) { - unsigned char buf[7]; - WBUFW(buf,0)=0x3836; - WBUFL(buf,2)=guild_id; - WBUFB(buf,6)=flag; - mapif_sendall(buf,7); - ShowInfo("int_guild: Guild broken (%d)\n",guild_id); - return 0; + unsigned char buf[7]; + WBUFW(buf,0)=0x3836; + WBUFL(buf,2)=guild_id; + WBUFB(buf,6)=flag; + mapif_sendall(buf,7); + ShowInfo("int_guild: Guild broken (%d)\n",guild_id); + return 0; } // Send guild message int mapif_guild_message(int guild_id,int account_id,char *mes,int len, int sfd) { - unsigned char buf[512]; - if (len > 500) - len = 500; - WBUFW(buf,0)=0x3837; - WBUFW(buf,2)=len+12; - WBUFL(buf,4)=guild_id; - WBUFL(buf,8)=account_id; - memcpy(WBUFP(buf,12),mes,len); - mapif_sendallwos(sfd, buf,len+12); - return 0; + unsigned char buf[512]; + if (len > 500) + len = 500; + WBUFW(buf,0)=0x3837; + WBUFW(buf,2)=len+12; + WBUFL(buf,4)=guild_id; + WBUFL(buf,8)=account_id; + memcpy(WBUFP(buf,12),mes,len); + mapif_sendallwos(sfd, buf,len+12); + return 0; } // Send basic info int mapif_guild_basicinfochanged(int guild_id,int type,const void *data,int len) { - unsigned char buf[2048]; - if (len > 2038) - len = 2038; - WBUFW(buf, 0)=0x3839; - WBUFW(buf, 2)=len+10; - WBUFL(buf, 4)=guild_id; - WBUFW(buf, 8)=type; - memcpy(WBUFP(buf,10),data,len); - mapif_sendall(buf,len+10); - return 0; + unsigned char buf[2048]; + if (len > 2038) + len = 2038; + WBUFW(buf, 0)=0x3839; + WBUFW(buf, 2)=len+10; + WBUFL(buf, 4)=guild_id; + WBUFW(buf, 8)=type; + memcpy(WBUFP(buf,10),data,len); + mapif_sendall(buf,len+10); + return 0; } // Send member info int mapif_guild_memberinfochanged(int guild_id,int account_id,int char_id, int type,const void *data,int len) { - unsigned char buf[2048]; - if (len > 2030) - len = 2030; - WBUFW(buf, 0)=0x383a; - WBUFW(buf, 2)=len+18; - WBUFL(buf, 4)=guild_id; - WBUFL(buf, 8)=account_id; - WBUFL(buf,12)=char_id; - WBUFW(buf,16)=type; - memcpy(WBUFP(buf,18),data,len); - mapif_sendall(buf,len+18); - return 0; + unsigned char buf[2048]; + if (len > 2030) + len = 2030; + WBUFW(buf, 0)=0x383a; + WBUFW(buf, 2)=len+18; + WBUFL(buf, 4)=guild_id; + WBUFL(buf, 8)=account_id; + WBUFL(buf,12)=char_id; + WBUFW(buf,16)=type; + memcpy(WBUFP(buf,18),data,len); + mapif_sendall(buf,len+18); + return 0; } // ACK guild skill up int mapif_guild_skillupack(int guild_id,int skill_num,int account_id) { - unsigned char buf[14]; - WBUFW(buf, 0)=0x383c; - WBUFL(buf, 2)=guild_id; - WBUFL(buf, 6)=skill_num; - WBUFL(buf,10)=account_id; - mapif_sendall(buf,14); - return 0; + unsigned char buf[14]; + WBUFW(buf, 0)=0x383c; + WBUFL(buf, 2)=guild_id; + WBUFL(buf, 6)=skill_num; + WBUFL(buf,10)=account_id; + mapif_sendall(buf,14); + return 0; } // ACK guild alliance int mapif_guild_alliance(int guild_id1,int guild_id2,int account_id1,int account_id2,int flag,const char *name1,const char *name2) { - unsigned char buf[19+2*NAME_LENGTH]; - WBUFW(buf, 0)=0x383d; - WBUFL(buf, 2)=guild_id1; - WBUFL(buf, 6)=guild_id2; - WBUFL(buf,10)=account_id1; - WBUFL(buf,14)=account_id2; - WBUFB(buf,18)=flag; - memcpy(WBUFP(buf,19),name1,NAME_LENGTH); - memcpy(WBUFP(buf,19+NAME_LENGTH),name2,NAME_LENGTH); - mapif_sendall(buf,19+2*NAME_LENGTH); - return 0; + unsigned char buf[19+2*NAME_LENGTH]; + WBUFW(buf, 0)=0x383d; + WBUFL(buf, 2)=guild_id1; + WBUFL(buf, 6)=guild_id2; + WBUFL(buf,10)=account_id1; + WBUFL(buf,14)=account_id2; + WBUFB(buf,18)=flag; + memcpy(WBUFP(buf,19),name1,NAME_LENGTH); + memcpy(WBUFP(buf,19+NAME_LENGTH),name2,NAME_LENGTH); + mapif_sendall(buf,19+2*NAME_LENGTH); + return 0; } // Send a guild position desc int mapif_guild_position(struct guild *g,int idx) { - unsigned char buf[12 + sizeof(struct guild_position)]; - WBUFW(buf,0)=0x383b; - WBUFW(buf,2)=sizeof(struct guild_position)+12; - WBUFL(buf,4)=g->guild_id; - WBUFL(buf,8)=idx; - memcpy(WBUFP(buf,12),&g->position[idx],sizeof(struct guild_position)); - mapif_sendall(buf,WBUFW(buf,2)); - return 0; + unsigned char buf[12 + sizeof(struct guild_position)]; + WBUFW(buf,0)=0x383b; + WBUFW(buf,2)=sizeof(struct guild_position)+12; + WBUFL(buf,4)=g->guild_id; + WBUFL(buf,8)=idx; + memcpy(WBUFP(buf,12),&g->position[idx],sizeof(struct guild_position)); + mapif_sendall(buf,WBUFW(buf,2)); + return 0; } // Send the guild notice int mapif_guild_notice(struct guild *g) { - unsigned char buf[256]; - WBUFW(buf,0)=0x383e; - WBUFL(buf,2)=g->guild_id; - memcpy(WBUFP(buf,6),g->mes1,MAX_GUILDMES1); - memcpy(WBUFP(buf,66),g->mes2,MAX_GUILDMES2); - mapif_sendall(buf,186); - return 0; + unsigned char buf[256]; + WBUFW(buf,0)=0x383e; + WBUFL(buf,2)=g->guild_id; + memcpy(WBUFP(buf,6),g->mes1,MAX_GUILDMES1); + memcpy(WBUFP(buf,66),g->mes2,MAX_GUILDMES2); + mapif_sendall(buf,186); + return 0; } // Send emblem data int mapif_guild_emblem(struct guild *g) { - unsigned char buf[12 + sizeof(g->emblem_data)]; - WBUFW(buf,0)=0x383f; - WBUFW(buf,2)=g->emblem_len+12; - WBUFL(buf,4)=g->guild_id; - WBUFL(buf,8)=g->emblem_id; - memcpy(WBUFP(buf,12),g->emblem_data,g->emblem_len); - mapif_sendall(buf,WBUFW(buf,2)); - return 0; + unsigned char buf[12 + sizeof(g->emblem_data)]; + WBUFW(buf,0)=0x383f; + WBUFW(buf,2)=g->emblem_len+12; + WBUFL(buf,4)=g->guild_id; + WBUFL(buf,8)=g->emblem_id; + memcpy(WBUFP(buf,12),g->emblem_data,g->emblem_len); + mapif_sendall(buf,WBUFW(buf,2)); + return 0; } int mapif_guild_master_changed(struct guild *g, int aid, int cid) { - unsigned char buf[14]; - WBUFW(buf,0)=0x3843; - WBUFL(buf,2)=g->guild_id; - WBUFL(buf,6)=aid; - WBUFL(buf,10)=cid; - mapif_sendall(buf,14); - return 0; + unsigned char buf[14]; + WBUFW(buf,0)=0x3843; + WBUFL(buf,2)=g->guild_id; + WBUFL(buf,6)=aid; + WBUFL(buf,10)=cid; + mapif_sendall(buf,14); + return 0; } int mapif_guild_castle_dataload(int fd, int sz, int *castle_ids) { - struct guild_castle *gc = NULL; - int num = (sz - 4) / sizeof(int); - int len = 4 + num * sizeof(*gc); - int i; - - WFIFOHEAD(fd, len); - WFIFOW(fd, 0) = 0x3840; - WFIFOW(fd, 2) = len; - for (i = 0; i < num; i++) { - gc = inter_guildcastle_fromsql(*(castle_ids++)); - memcpy(WFIFOP(fd, 4 + i * sizeof(*gc)), gc, sizeof(*gc)); - } - WFIFOSET(fd, len); - return 0; + struct guild_castle *gc = NULL; + int num = (sz - 4) / sizeof(int); + int len = 4 + num * sizeof(*gc); + int i; + + WFIFOHEAD(fd, len); + WFIFOW(fd, 0) = 0x3840; + WFIFOW(fd, 2) = len; + for (i = 0; i < num; i++) { + gc = inter_guildcastle_fromsql(*(castle_ids++)); + memcpy(WFIFOP(fd, 4 + i * sizeof(*gc)), gc, sizeof(*gc)); + } + WFIFOSET(fd, len); + return 0; } //------------------------------------------------------------------- @@ -1145,696 +1133,680 @@ int mapif_guild_castle_dataload(int fd, int sz, int *castle_ids) // Guild creation request int mapif_parse_CreateGuild(int fd,int account_id,char *name,struct guild_member *master) { - struct guild *g; - int i=0; + struct guild *g; + int i=0; #ifdef NOISY - ShowInfo("Creating Guild (%s)\n", name); + ShowInfo("Creating Guild (%s)\n", name); #endif - if(search_guildname(name) != 0){ - ShowInfo("int_guild: guild with same name exists [%s]\n",name); - mapif_guild_created(fd,account_id,NULL); - return 0; - } - // Check Authorised letters/symbols in the name of the character - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { - mapif_guild_created(fd,account_id,NULL); - return 0; - } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { - mapif_guild_created(fd,account_id,NULL); - return 0; - } - } - - g = (struct guild *)aMalloc(sizeof(struct guild)); - memset(g,0,sizeof(struct guild)); - - memcpy(g->name,name,NAME_LENGTH); - memcpy(g->master,master->name,NAME_LENGTH); - memcpy(&g->member[0],master,sizeof(struct guild_member)); - g->member[0].modified = GS_MEMBER_MODIFIED; - - // Set default positions - g->position[0].mode=0x11; - strcpy(g->position[0].name,"GuildMaster"); - strcpy(g->position[MAX_GUILDPOSITION-1].name,"Newbie"); - g->position[0].modified = g->position[MAX_GUILDPOSITION-1].modified = GS_POSITION_MODIFIED; - for(i=1;iposition[i].name,"Position %d",i+1); - g->position[i].modified = GS_POSITION_MODIFIED; - } - - // Initialize guild property - g->max_member=16; - g->average_lv=master->lv; - g->connect_member=1; - - for(i=0;iskill[i].id=i + GD_SKILLBASE; - g->guild_id= -1; //Request to create guild. - - // Create the guild - if (!inter_guild_tosql(g,GS_BASIC|GS_POSITION|GS_SKILL)) { - //Failed to Create guild.... - ShowError("Failed to create Guild %s (Guild Master: %s)\n", g->name, g->master); - mapif_guild_created(fd,account_id,NULL); - aFree(g); - return 0; - } - ShowInfo("Created Guild %d - %s (Guild Master: %s)\n", g->guild_id, g->name, g->master); - - //Add to cache - idb_put(guild_db_, g->guild_id, g); - - // Report to client - mapif_guild_created(fd,account_id,g); - mapif_guild_info(fd,g); - - if(log_inter) - inter_log("guild %s (id=%d) created by master %s (id=%d)\n", - name, g->guild_id, master->name, master->account_id ); - - return 0; + if (search_guildname(name) != 0) { + ShowInfo("int_guild: guild with same name exists [%s]\n",name); + mapif_guild_created(fd,account_id,NULL); + return 0; + } + // Check Authorised letters/symbols in the name of the character + if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) == NULL) { + mapif_guild_created(fd,account_id,NULL); + return 0; + } + } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) != NULL) { + mapif_guild_created(fd,account_id,NULL); + return 0; + } + } + + g = (struct guild *)aMalloc(sizeof(struct guild)); + memset(g,0,sizeof(struct guild)); + + memcpy(g->name,name,NAME_LENGTH); + memcpy(g->master,master->name,NAME_LENGTH); + memcpy(&g->member[0],master,sizeof(struct guild_member)); + g->member[0].modified = GS_MEMBER_MODIFIED; + + // Set default positions + g->position[0].mode=0x11; + strcpy(g->position[0].name,"GuildMaster"); + strcpy(g->position[MAX_GUILDPOSITION-1].name,"Newbie"); + g->position[0].modified = g->position[MAX_GUILDPOSITION-1].modified = GS_POSITION_MODIFIED; + for (i=1; iposition[i].name,"Position %d",i+1); + g->position[i].modified = GS_POSITION_MODIFIED; + } + + // Initialize guild property + g->max_member=16; + g->average_lv=master->lv; + g->connect_member=1; + + for (i=0; iskill[i].id=i + GD_SKILLBASE; + g->guild_id= -1; //Request to create guild. + + // Create the guild + if (!inter_guild_tosql(g,GS_BASIC|GS_POSITION|GS_SKILL)) { + //Failed to Create guild.... + ShowError("Failed to create Guild %s (Guild Master: %s)\n", g->name, g->master); + mapif_guild_created(fd,account_id,NULL); + aFree(g); + return 0; + } + ShowInfo("Created Guild %d - %s (Guild Master: %s)\n", g->guild_id, g->name, g->master); + + //Add to cache + idb_put(guild_db_, g->guild_id, g); + + // Report to client + mapif_guild_created(fd,account_id,g); + mapif_guild_info(fd,g); + + if (log_inter) + inter_log("guild %s (id=%d) created by master %s (id=%d)\n", + name, g->guild_id, master->name, master->account_id); + + return 0; } // Return guild info to client int mapif_parse_GuildInfo(int fd,int guild_id) { - struct guild * g = inter_guild_fromsql(guild_id); //We use this because on start-up the info of castle-owned guilds is requied. [Skotlex] - if(g) - { - if (!guild_calcinfo(g)) - mapif_guild_info(fd,g); - } - else - mapif_guild_noinfo(fd,guild_id); // Failed to load info - return 0; + struct guild *g = inter_guild_fromsql(guild_id); //We use this because on start-up the info of castle-owned guilds is requied. [Skotlex] + if (g) { + if (!guild_calcinfo(g)) + mapif_guild_info(fd,g); + } else + mapif_guild_noinfo(fd,guild_id); // Failed to load info + return 0; } // Add member to guild int mapif_parse_GuildAddMember(int fd,int guild_id,struct guild_member *m) { - struct guild * g; - int i; - - g = inter_guild_fromsql(guild_id); - if(g==NULL){ - // Failed to add - mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1); - return 0; - } - - // Find an empty slot - for(i=0;imax_member;i++) - { - if(g->member[i].account_id==0) - { - memcpy(&g->member[i],m,sizeof(struct guild_member)); - g->member[i].modified = (GS_MEMBER_NEW | GS_MEMBER_MODIFIED); - mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,0); - if (!guild_calcinfo(g)) //Send members if it was not invoked. - mapif_guild_info(-1,g); - - g->save_flag |= GS_MEMBER; - if (g->save_flag&GS_REMOVE) - g->save_flag&=~GS_REMOVE; - return 0; - } - } - - // Failed to add - mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1); - return 0; + struct guild *g; + int i; + + g = inter_guild_fromsql(guild_id); + if (g==NULL) { + // Failed to add + mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1); + return 0; + } + + // Find an empty slot + for (i=0; imax_member; i++) { + if (g->member[i].account_id==0) { + memcpy(&g->member[i],m,sizeof(struct guild_member)); + g->member[i].modified = (GS_MEMBER_NEW | GS_MEMBER_MODIFIED); + mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,0); + if (!guild_calcinfo(g)) //Send members if it was not invoked. + mapif_guild_info(-1,g); + + g->save_flag |= GS_MEMBER; + if (g->save_flag&GS_REMOVE) + g->save_flag&=~GS_REMOVE; + return 0; + } + } + + // Failed to add + mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1); + return 0; } // Delete member from guild int mapif_parse_GuildLeave(int fd, int guild_id, int account_id, int char_id, int flag, const char *mes) { - int i, j; - - struct guild* g = inter_guild_fromsql(guild_id); - if( g == NULL ) - { - // Unknown guild, just update the player - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `account_id`='%d' AND `char_id`='%d'", char_db, account_id, char_id) ) - Sql_ShowDebug(sql_handle); - // mapif_guild_withdraw(guild_id,account_id,char_id,flag,g->member[i].name,mes); - return 0; - } - - // Find the member - ARR_FIND( 0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id ); - if( i == g->max_member ) - { - //TODO - return 0; - } - - if( flag ) - { // Write expulsion reason - // Find an empty slot - ARR_FIND( 0, MAX_GUILDEXPULSION, j, g->expulsion[j].account_id == 0 ); - if( j == MAX_GUILDEXPULSION ) - { - // Expulsion list is full, flush the oldest one - for( j = 0; j < MAX_GUILDEXPULSION - 1; j++ ) - g->expulsion[j] = g->expulsion[j+1]; - j = MAX_GUILDEXPULSION-1; - } - // Save the expulsion entry - g->expulsion[j].account_id = account_id; - safestrncpy(g->expulsion[j].name, g->member[i].name, NAME_LENGTH); - safestrncpy(g->expulsion[j].mes, mes, 40); - } - - mapif_guild_withdraw(guild_id,account_id,char_id,flag,g->member[i].name,mes); - inter_guild_removemember_tosql(g->member[i].account_id,g->member[i].char_id); - - memset(&g->member[i],0,sizeof(struct guild_member)); - - if( guild_check_empty(g) ) - mapif_parse_BreakGuild(-1,guild_id); //Break the guild. - else { - //Update member info. - if (!guild_calcinfo(g)) - mapif_guild_info(fd,g); - g->save_flag |= GS_EXPULSION; - } - - return 0; + int i, j; + + struct guild *g = inter_guild_fromsql(guild_id); + if (g == NULL) { + // Unknown guild, just update the player + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `account_id`='%d' AND `char_id`='%d'", char_db, account_id, char_id)) + Sql_ShowDebug(sql_handle); + // mapif_guild_withdraw(guild_id,account_id,char_id,flag,g->member[i].name,mes); + return 0; + } + + // Find the member + ARR_FIND(0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id); + if (i == g->max_member) { + //TODO + return 0; + } + + if (flag) { + // Write expulsion reason + // Find an empty slot + ARR_FIND(0, MAX_GUILDEXPULSION, j, g->expulsion[j].account_id == 0); + if (j == MAX_GUILDEXPULSION) { + // Expulsion list is full, flush the oldest one + for (j = 0; j < MAX_GUILDEXPULSION - 1; j++) + g->expulsion[j] = g->expulsion[j+1]; + j = MAX_GUILDEXPULSION-1; + } + // Save the expulsion entry + g->expulsion[j].account_id = account_id; + safestrncpy(g->expulsion[j].name, g->member[i].name, NAME_LENGTH); + safestrncpy(g->expulsion[j].mes, mes, 40); + } + + mapif_guild_withdraw(guild_id,account_id,char_id,flag,g->member[i].name,mes); + inter_guild_removemember_tosql(g->member[i].account_id,g->member[i].char_id); + + memset(&g->member[i],0,sizeof(struct guild_member)); + + if (guild_check_empty(g)) + mapif_parse_BreakGuild(-1,guild_id); //Break the guild. + else { + //Update member info. + if (!guild_calcinfo(g)) + mapif_guild_info(fd,g); + g->save_flag |= GS_EXPULSION; + } + + return 0; } // Change member info int mapif_parse_GuildChangeMemberInfoShort(int fd,int guild_id,int account_id,int char_id,int online,int lv,int class_) { - // Could speed up by manipulating only guild_member - struct guild * g; - int i,sum,c; - int prev_count, prev_alv; - - g = inter_guild_fromsql(guild_id); - if(g==NULL) - return 0; - - ARR_FIND( 0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id ); - if( i < g->max_member ) - { - g->member[i].online = online; - g->member[i].lv = lv; - g->member[i].class_ = class_; - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfoshort(g,i); - } - - prev_count = g->connect_member; - prev_alv = g->average_lv; - - g->average_lv = 0; - g->connect_member = 0; - c = 0; - sum = 0; - - for( i = 0; i < g->max_member; i++ ) - { - if( g->member[i].account_id > 0 ) - { - sum += g->member[i].lv; - c++; - } - if( g->member[i].online ) - g->connect_member++; - } - - if( c ) // this check should always succeed... - { - g->average_lv = sum / c; - if( g->connect_member != prev_count || g->average_lv != prev_alv ) - g->save_flag |= GS_CONNECT; - if( g->save_flag & GS_REMOVE ) - g->save_flag &= ~GS_REMOVE; - } - g->save_flag |= GS_MEMBER; //Update guild member data - return 0; + // Could speed up by manipulating only guild_member + struct guild *g; + int i,sum,c; + int prev_count, prev_alv; + + g = inter_guild_fromsql(guild_id); + if (g==NULL) + return 0; + + ARR_FIND(0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id); + if (i < g->max_member) { + g->member[i].online = online; + g->member[i].lv = lv; + g->member[i].class_ = class_; + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfoshort(g,i); + } + + prev_count = g->connect_member; + prev_alv = g->average_lv; + + g->average_lv = 0; + g->connect_member = 0; + c = 0; + sum = 0; + + for (i = 0; i < g->max_member; i++) { + if (g->member[i].account_id > 0) { + sum += g->member[i].lv; + c++; + } + if (g->member[i].online) + g->connect_member++; + } + + if (c) { // this check should always succeed... + g->average_lv = sum / c; + if (g->connect_member != prev_count || g->average_lv != prev_alv) + g->save_flag |= GS_CONNECT; + if (g->save_flag & GS_REMOVE) + g->save_flag &= ~GS_REMOVE; + } + g->save_flag |= GS_MEMBER; //Update guild member data + return 0; } // BreakGuild int mapif_parse_BreakGuild(int fd,int guild_id) { - struct guild * g; - - g = inter_guild_fromsql(guild_id); - if(g==NULL) - return 0; + struct guild *g; - // Delete guild from sql - //printf("- Delete guild %d from guild\n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_db, guild_id) ) - Sql_ShowDebug(sql_handle); + g = inter_guild_fromsql(guild_id); + if (g==NULL) + return 0; - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_member_db, guild_id) ) - Sql_ShowDebug(sql_handle); + // Delete guild from sql + //printf("- Delete guild %d from guild\n",guild_id); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_db, guild_id)) + Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_castle_db, guild_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_member_db, guild_id)) + Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_storage_db, guild_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_castle_db, guild_id)) + Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d' OR `alliance_id` = '%d'", guild_alliance_db, guild_id, guild_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_storage_db, guild_id)) + Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_position_db, guild_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d' OR `alliance_id` = '%d'", guild_alliance_db, guild_id, guild_id)) + Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_skill_db, guild_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_position_db, guild_id)) + Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_expulsion_db, guild_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_skill_db, guild_id)) + Sql_ShowDebug(sql_handle); - //printf("- Update guild %d of char\n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `guild_id`='%d'", char_db, guild_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_expulsion_db, guild_id)) + Sql_ShowDebug(sql_handle); - mapif_guild_broken(guild_id,0); + //printf("- Update guild %d of char\n",guild_id); + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `guild_id`='%d'", char_db, guild_id)) + Sql_ShowDebug(sql_handle); - if(log_inter) - inter_log("guild %s (id=%d) broken\n",g->name,guild_id); + mapif_guild_broken(guild_id,0); - //Remove the guild from memory. [Skotlex] - idb_remove(guild_db_, guild_id); - return 0; + if (log_inter) + inter_log("guild %s (id=%d) broken\n",g->name,guild_id); + + //Remove the guild from memory. [Skotlex] + idb_remove(guild_db_, guild_id); + return 0; } // Forward Guild message to others map servers int mapif_parse_GuildMessage(int fd,int guild_id,int account_id,char *mes,int len) { - return mapif_guild_message(guild_id,account_id,mes,len, fd); + return mapif_guild_message(guild_id,account_id,mes,len, fd); } -// Modification of the guild +// Modification of the guild int mapif_parse_GuildBasicInfoChange(int fd,int guild_id,int type,const char *data,int len) { - struct guild * g; - short dw=*((short *)data); - g = inter_guild_fromsql(guild_id); - if(g==NULL) - return 0; - - switch(type) - { - case GBI_GUILDLV: - if(dw>0 && g->guild_lv+dw<=50) - { - g->guild_lv+=dw; - g->skill_point+=dw; - } - else if(dw<0 && g->guild_lv+dw>=1) - g->guild_lv+=dw; - mapif_guild_info(-1,g); - g->save_flag |= GS_LEVEL; - return 0; - default: - ShowError("int_guild: GuildBasicInfoChange: Unknown type %d\n",type); - break; - } - mapif_guild_basicinfochanged(guild_id,type,data,len); - return 0; + struct guild *g; + short dw=*((short *)data); + g = inter_guild_fromsql(guild_id); + if (g==NULL) + return 0; + + switch (type) { + case GBI_GUILDLV: + if (dw>0 && g->guild_lv+dw<=50) { + g->guild_lv+=dw; + g->skill_point+=dw; + } else if (dw<0 && g->guild_lv+dw>=1) + g->guild_lv+=dw; + mapif_guild_info(-1,g); + g->save_flag |= GS_LEVEL; + return 0; + default: + ShowError("int_guild: GuildBasicInfoChange: Unknown type %d\n",type); + break; + } + mapif_guild_basicinfochanged(guild_id,type,data,len); + return 0; } -// Modification of the guild +// Modification of the guild int mapif_parse_GuildMemberInfoChange(int fd,int guild_id,int account_id,int char_id,int type,const char *data,int len) { - // Could make some improvement in speed, because only change guild_member - int i; - struct guild * g; - - g = inter_guild_fromsql(guild_id); - if(g==NULL) - return 0; - - // Search the member - for(i=0;imax_member;i++) - if( g->member[i].account_id==account_id && - g->member[i].char_id==char_id ) - break; - - // Not Found - if(i==g->max_member){ - ShowWarning("int_guild: GuildMemberChange: Not found %d,%d in guild (%d - %s)\n", - account_id,char_id,guild_id,g->name); - return 0; - } - - switch(type) - { - case GMI_POSITION: - { - g->member[i].position=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; - break; - } - case GMI_EXP: - { // EXP - uint64 exp, old_exp=g->member[i].exp; - g->member[i].exp=*((uint64 *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - if (g->member[i].exp > old_exp) - { - exp = g->member[i].exp - old_exp; - - // Compute gained exp - if (guild_exp_rate != 100) - exp = exp*guild_exp_rate/100; - - // Update guild exp - if (exp > UINT64_MAX - g->exp) - g->exp = UINT64_MAX; - else - g->exp+=exp; - - guild_calcinfo(g); - mapif_guild_basicinfochanged(guild_id,GBI_EXP,&g->exp,sizeof(g->exp)); - g->save_flag |= GS_LEVEL; - } - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; - break; - } - case GMI_HAIR: - { - g->member[i].hair=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - case GMI_HAIR_COLOR: - { - g->member[i].hair_color=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - case GMI_GENDER: - { - g->member[i].gender=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - case GMI_CLASS: - { - g->member[i].class_=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - case GMI_LEVEL: - { - g->member[i].lv=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - default: - ShowError("int_guild: GuildMemberInfoChange: Unknown type %d\n",type); - break; - } - return 0; + // Could make some improvement in speed, because only change guild_member + int i; + struct guild *g; + + g = inter_guild_fromsql(guild_id); + if (g==NULL) + return 0; + + // Search the member + for (i=0; imax_member; i++) + if (g->member[i].account_id==account_id && + g->member[i].char_id==char_id) + break; + + // Not Found + if (i==g->max_member) { + ShowWarning("int_guild: GuildMemberChange: Not found %d,%d in guild (%d - %s)\n", + account_id,char_id,guild_id,g->name); + return 0; + } + + switch (type) { + case GMI_POSITION: { + g->member[i].position=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; + break; + } + case GMI_EXP: { + // EXP + uint64 exp, old_exp=g->member[i].exp; + g->member[i].exp=*((uint64 *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + if (g->member[i].exp > old_exp) { + exp = g->member[i].exp - old_exp; + + // Compute gained exp + if (guild_exp_rate != 100) + exp = exp*guild_exp_rate/100; + + // Update guild exp + if (exp > UINT64_MAX - g->exp) + g->exp = UINT64_MAX; + else + g->exp+=exp; + + guild_calcinfo(g); + mapif_guild_basicinfochanged(guild_id,GBI_EXP,&g->exp,sizeof(g->exp)); + g->save_flag |= GS_LEVEL; + } + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; + break; + } + case GMI_HAIR: { + g->member[i].hair=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + case GMI_HAIR_COLOR: { + g->member[i].hair_color=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + case GMI_GENDER: { + g->member[i].gender=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + case GMI_CLASS: { + g->member[i].class_=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + case GMI_LEVEL: { + g->member[i].lv=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + default: + ShowError("int_guild: GuildMemberInfoChange: Unknown type %d\n",type); + break; + } + return 0; } int inter_guild_sex_changed(int guild_id,int account_id,int char_id, short gender) { - return mapif_parse_GuildMemberInfoChange(0, guild_id, account_id, char_id, GMI_GENDER, (const char*)&gender, sizeof(gender)); + return mapif_parse_GuildMemberInfoChange(0, guild_id, account_id, char_id, GMI_GENDER, (const char *)&gender, sizeof(gender)); } int inter_guild_charname_changed(int guild_id,int account_id, int char_id, char *name) { - struct guild *g; - int i, flag = 0; - - g = inter_guild_fromsql(guild_id); - if( g == NULL ) - { - ShowError("inter_guild_charrenamed: Can't find guild %d.\n", guild_id); - return 0; - } - - ARR_FIND(0, g->max_member, i, g->member[i].char_id == char_id); - if( i == g->max_member ) - { - ShowError("inter_guild_charrenamed: Can't find character %d in the guild\n", char_id); - return 0; - } - - if( !strcmp(g->member[i].name, g->master) ) - { - safestrncpy(g->master, name, NAME_LENGTH); - flag |= GS_BASIC; - } - safestrncpy(g->member[i].name, name, NAME_LENGTH); - g->member[i].modified = GS_MEMBER_MODIFIED; - flag |= GS_MEMBER; - - if( !inter_guild_tosql(g, flag) ) - return 0; - - mapif_guild_info(-1,g); - - return 0; + struct guild *g; + int i, flag = 0; + + g = inter_guild_fromsql(guild_id); + if (g == NULL) { + ShowError("inter_guild_charrenamed: Can't find guild %d.\n", guild_id); + return 0; + } + + ARR_FIND(0, g->max_member, i, g->member[i].char_id == char_id); + if (i == g->max_member) { + ShowError("inter_guild_charrenamed: Can't find character %d in the guild\n", char_id); + return 0; + } + + if (!strcmp(g->member[i].name, g->master)) { + safestrncpy(g->master, name, NAME_LENGTH); + flag |= GS_BASIC; + } + safestrncpy(g->member[i].name, name, NAME_LENGTH); + g->member[i].modified = GS_MEMBER_MODIFIED; + flag |= GS_MEMBER; + + if (!inter_guild_tosql(g, flag)) + return 0; + + mapif_guild_info(-1,g); + + return 0; } // Change a position desc int mapif_parse_GuildPosition(int fd,int guild_id,int idx,struct guild_position *p) { - // Could make some improvement in speed, because only change guild_position - struct guild * g; - - g = inter_guild_fromsql(guild_id); - if(g==NULL || idx<0 || idx>=MAX_GUILDPOSITION) - return 0; - - memcpy(&g->position[idx],p,sizeof(struct guild_position)); - mapif_guild_position(g,idx); - g->position[idx].modified = GS_POSITION_MODIFIED; - g->save_flag |= GS_POSITION; // Change guild_position - return 0; + // Could make some improvement in speed, because only change guild_position + struct guild *g; + + g = inter_guild_fromsql(guild_id); + if (g==NULL || idx<0 || idx>=MAX_GUILDPOSITION) + return 0; + + memcpy(&g->position[idx],p,sizeof(struct guild_position)); + mapif_guild_position(g,idx); + g->position[idx].modified = GS_POSITION_MODIFIED; + g->save_flag |= GS_POSITION; // Change guild_position + return 0; } // Guild Skill UP int mapif_parse_GuildSkillUp(int fd,int guild_id,int skill_num,int account_id,int max) { - struct guild * g; - int idx = skill_num - GD_SKILLBASE; - - g = inter_guild_fromsql(guild_id); - if(g == NULL || idx < 0 || idx >= MAX_GUILDSKILL) - return 0; - - if(g->skill_point>0 && g->skill[idx].id>0 && g->skill[idx].lvskill[idx].lv++; - g->skill_point--; - if (!guild_calcinfo(g)) - mapif_guild_info(-1,g); - mapif_guild_skillupack(guild_id,skill_num,account_id); - g->save_flag |= (GS_LEVEL|GS_SKILL); // Change guild & guild_skill - } - return 0; + struct guild *g; + int idx = skill_num - GD_SKILLBASE; + + g = inter_guild_fromsql(guild_id); + if (g == NULL || idx < 0 || idx >= MAX_GUILDSKILL) + return 0; + + if (g->skill_point>0 && g->skill[idx].id>0 && g->skill[idx].lvskill[idx].lv++; + g->skill_point--; + if (!guild_calcinfo(g)) + mapif_guild_info(-1,g); + mapif_guild_skillupack(guild_id,skill_num,account_id); + g->save_flag |= (GS_LEVEL|GS_SKILL); // Change guild & guild_skill + } + return 0; } //Manual deletion of an alliance when partnering guild does not exists. [Skotlex] static int mapif_parse_GuildDeleteAlliance(struct guild *g, int guild_id, int account_id1, int account_id2, int flag) { - int i; - char name[NAME_LENGTH]; - - ARR_FIND( 0, MAX_GUILDALLIANCE, i, g->alliance[i].guild_id == guild_id ); - if( i == MAX_GUILDALLIANCE ) - return -1; - - strcpy(name, g->alliance[i].name); - g->alliance[i].guild_id=0; - - mapif_guild_alliance(g->guild_id,guild_id,account_id1,account_id2,flag,g->name,name); - g->save_flag |= GS_ALLIANCE; - return 0; + int i; + char name[NAME_LENGTH]; + + ARR_FIND(0, MAX_GUILDALLIANCE, i, g->alliance[i].guild_id == guild_id); + if (i == MAX_GUILDALLIANCE) + return -1; + + strcpy(name, g->alliance[i].name); + g->alliance[i].guild_id=0; + + mapif_guild_alliance(g->guild_id,guild_id,account_id1,account_id2,flag,g->name,name); + g->save_flag |= GS_ALLIANCE; + return 0; } // Alliance modification int mapif_parse_GuildAlliance(int fd,int guild_id1,int guild_id2,int account_id1,int account_id2,int flag) { - // Could speed up - struct guild *g[2]; - int j,i; - g[0] = inter_guild_fromsql(guild_id1); - g[1] = inter_guild_fromsql(guild_id2); - - if(g[0] && g[1]==NULL && (flag & GUILD_ALLIANCE_REMOVE)) //Requested to remove an alliance with a not found guild. - return mapif_parse_GuildDeleteAlliance(g[0], guild_id2, account_id1, account_id2, flag); //Try to do a manual removal of said guild. - - if(g[0]==NULL || g[1]==NULL) - return 0; - - if(flag&GUILD_ALLIANCE_REMOVE) - { - // Remove alliance/opposition, in case of alliance, remove on both side - for(i=0;i<2-(flag&GUILD_ALLIANCE_TYPE_MASK);i++) - { - ARR_FIND( 0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == g[1-i]->guild_id && g[i]->alliance[j].opposition == (flag&GUILD_ALLIANCE_TYPE_MASK) ); - if( j < MAX_GUILDALLIANCE ) - g[i]->alliance[j].guild_id = 0; - } - } - else - { - // Add alliance, in case of alliance, add on both side - for(i=0;i<2-(flag&GUILD_ALLIANCE_TYPE_MASK);i++) - { - // Search an empty slot - ARR_FIND( 0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == 0 ); - if( j < MAX_GUILDALLIANCE ) - { - g[i]->alliance[j].guild_id=g[1-i]->guild_id; - memcpy(g[i]->alliance[j].name,g[1-i]->name,NAME_LENGTH); - // Set alliance type - g[i]->alliance[j].opposition = flag&GUILD_ALLIANCE_TYPE_MASK; - } - } - } - - // Send on all map the new alliance/opposition - mapif_guild_alliance(guild_id1,guild_id2,account_id1,account_id2,flag,g[0]->name,g[1]->name); - - // Mark the two guild to be saved - g[0]->save_flag |= GS_ALLIANCE; - g[1]->save_flag |= GS_ALLIANCE; - return 0; + // Could speed up + struct guild *g[2]; + int j,i; + g[0] = inter_guild_fromsql(guild_id1); + g[1] = inter_guild_fromsql(guild_id2); + + if (g[0] && g[1]==NULL && (flag & GUILD_ALLIANCE_REMOVE)) //Requested to remove an alliance with a not found guild. + return mapif_parse_GuildDeleteAlliance(g[0], guild_id2, account_id1, account_id2, flag); //Try to do a manual removal of said guild. + + if (g[0]==NULL || g[1]==NULL) + return 0; + + if (flag&GUILD_ALLIANCE_REMOVE) { + // Remove alliance/opposition, in case of alliance, remove on both side + for (i=0; i<2-(flag&GUILD_ALLIANCE_TYPE_MASK); i++) { + ARR_FIND(0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == g[1-i]->guild_id && g[i]->alliance[j].opposition == (flag&GUILD_ALLIANCE_TYPE_MASK)); + if (j < MAX_GUILDALLIANCE) + g[i]->alliance[j].guild_id = 0; + } + } else { + // Add alliance, in case of alliance, add on both side + for (i=0; i<2-(flag&GUILD_ALLIANCE_TYPE_MASK); i++) { + // Search an empty slot + ARR_FIND(0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == 0); + if (j < MAX_GUILDALLIANCE) { + g[i]->alliance[j].guild_id=g[1-i]->guild_id; + memcpy(g[i]->alliance[j].name,g[1-i]->name,NAME_LENGTH); + // Set alliance type + g[i]->alliance[j].opposition = flag&GUILD_ALLIANCE_TYPE_MASK; + } + } + } + + // Send on all map the new alliance/opposition + mapif_guild_alliance(guild_id1,guild_id2,account_id1,account_id2,flag,g[0]->name,g[1]->name); + + // Mark the two guild to be saved + g[0]->save_flag |= GS_ALLIANCE; + g[1]->save_flag |= GS_ALLIANCE; + return 0; } // Change guild message int mapif_parse_GuildNotice(int fd,int guild_id,const char *mes1,const char *mes2) { - struct guild *g; + struct guild *g; - g = inter_guild_fromsql(guild_id); - if(g==NULL) - return 0; + g = inter_guild_fromsql(guild_id); + if (g==NULL) + return 0; - memcpy(g->mes1,mes1,MAX_GUILDMES1); - memcpy(g->mes2,mes2,MAX_GUILDMES2); - g->save_flag |= GS_MES; //Change mes of guild - return mapif_guild_notice(g); + memcpy(g->mes1,mes1,MAX_GUILDMES1); + memcpy(g->mes2,mes2,MAX_GUILDMES2); + g->save_flag |= GS_MES; //Change mes of guild + return mapif_guild_notice(g); } int mapif_parse_GuildEmblem(int fd,int len,int guild_id,int dummy,const char *data) { - struct guild * g; + struct guild *g; - g = inter_guild_fromsql(guild_id); - if(g==NULL) - return 0; + g = inter_guild_fromsql(guild_id); + if (g==NULL) + return 0; - if (len > sizeof(g->emblem_data)) - len = sizeof(g->emblem_data); + if (len > sizeof(g->emblem_data)) + len = sizeof(g->emblem_data); - memcpy(g->emblem_data,data,len); - g->emblem_len=len; - g->emblem_id++; - g->save_flag |= GS_EMBLEM; //Change guild - return mapif_guild_emblem(g); + memcpy(g->emblem_data,data,len); + g->emblem_len=len; + g->emblem_id++; + g->save_flag |= GS_EMBLEM; //Change guild + return mapif_guild_emblem(g); } int mapif_parse_GuildCastleDataLoad(int fd, int len, int *castle_ids) { - return mapif_guild_castle_dataload(fd, len, castle_ids); + return mapif_guild_castle_dataload(fd, len, castle_ids); } int mapif_parse_GuildCastleDataSave(int fd, int castle_id, int index, int value) { - struct guild_castle *gc = inter_guildcastle_fromsql(castle_id); - - if (gc == NULL) { - ShowError("mapif_parse_GuildCastleDataSave: castle id=%d not found\n", castle_id); - return 0; - } - - switch (index) { - case 1: - if (log_inter && gc->guild_id != value) { - int gid = (value) ? value : gc->guild_id; - struct guild *g = idb_get(guild_db_, gid); - inter_log("guild %s (id=%d) %s castle id=%d\n", - (g) ? g->name : "??", gid, (value) ? "occupy" : "abandon", castle_id); - } - gc->guild_id = value; - break; - case 2: gc->economy = value; break; - case 3: gc->defense = value; break; - case 4: gc->triggerE = value; break; - case 5: gc->triggerD = value; break; - case 6: gc->nextTime = value; break; - case 7: gc->payTime = value; break; - case 8: gc->createTime = value; break; - case 9: gc->visibleC = value; break; - default: - if (index > 9 && index <= 9+MAX_GUARDIANS) { - gc->guardian[index-10].visible = value; - break; - } - ShowError("mapif_parse_GuildCastleDataSave: not found index=%d\n", index); - return 0; - } - inter_guildcastle_tosql(gc); - return 0; + struct guild_castle *gc = inter_guildcastle_fromsql(castle_id); + + if (gc == NULL) { + ShowError("mapif_parse_GuildCastleDataSave: castle id=%d not found\n", castle_id); + return 0; + } + + switch (index) { + case 1: + if (log_inter && gc->guild_id != value) { + int gid = (value) ? value : gc->guild_id; + struct guild *g = idb_get(guild_db_, gid); + inter_log("guild %s (id=%d) %s castle id=%d\n", + (g) ? g->name : "??", gid, (value) ? "occupy" : "abandon", castle_id); + } + gc->guild_id = value; + break; + case 2: + gc->economy = value; + break; + case 3: + gc->defense = value; + break; + case 4: + gc->triggerE = value; + break; + case 5: + gc->triggerD = value; + break; + case 6: + gc->nextTime = value; + break; + case 7: + gc->payTime = value; + break; + case 8: + gc->createTime = value; + break; + case 9: + gc->visibleC = value; + break; + default: + if (index > 9 && index <= 9+MAX_GUARDIANS) { + gc->guardian[index-10].visible = value; + break; + } + ShowError("mapif_parse_GuildCastleDataSave: not found index=%d\n", index); + return 0; + } + inter_guildcastle_tosql(gc); + return 0; } -int mapif_parse_GuildMasterChange(int fd, int guild_id, const char* name, int len) +int mapif_parse_GuildMasterChange(int fd, int guild_id, const char *name, int len) { - struct guild * g; - struct guild_member gm; - int pos; - - g = inter_guild_fromsql(guild_id); - - if(g==NULL || len > NAME_LENGTH) - return 0; - - // Find member (name) - for (pos = 0; pos < g->max_member && strncmp(g->member[pos].name, name, len); pos++); - - if (pos == g->max_member) - return 0; //Character not found?? - - // Switch current and old GM - memcpy(&gm, &g->member[pos], sizeof (struct guild_member)); - memcpy(&g->member[pos], &g->member[0], sizeof(struct guild_member)); - memcpy(&g->member[0], &gm, sizeof(struct guild_member)); - - // Switch positions - g->member[pos].position = g->member[0].position; - g->member[pos].modified = GS_MEMBER_MODIFIED; - g->member[0].position = 0; //Position 0: guild Master. - g->member[0].modified = GS_MEMBER_MODIFIED; - - strncpy(g->master, name, len); - if (len < NAME_LENGTH) - g->master[len] = '\0'; - - ShowInfo("int_guild: Guildmaster Changed to %s (Guild %d - %s)\n",g->master, guild_id, g->name); - g->save_flag |= (GS_BASIC|GS_MEMBER); //Save main data and member data. - return mapif_guild_master_changed(g, g->member[0].account_id, g->member[0].char_id); + struct guild *g; + struct guild_member gm; + int pos; + + g = inter_guild_fromsql(guild_id); + + if (g==NULL || len > NAME_LENGTH) + return 0; + + // Find member (name) + for (pos = 0; pos < g->max_member && strncmp(g->member[pos].name, name, len); pos++); + + if (pos == g->max_member) + return 0; //Character not found?? + + // Switch current and old GM + memcpy(&gm, &g->member[pos], sizeof(struct guild_member)); + memcpy(&g->member[pos], &g->member[0], sizeof(struct guild_member)); + memcpy(&g->member[0], &gm, sizeof(struct guild_member)); + + // Switch positions + g->member[pos].position = g->member[0].position; + g->member[pos].modified = GS_MEMBER_MODIFIED; + g->member[0].position = 0; //Position 0: guild Master. + g->member[0].modified = GS_MEMBER_MODIFIED; + + strncpy(g->master, name, len); + if (len < NAME_LENGTH) + g->master[len] = '\0'; + + ShowInfo("int_guild: Guildmaster Changed to %s (Guild %d - %s)\n",g->master, guild_id, g->name); + g->save_flag |= (GS_BASIC|GS_MEMBER); //Save main data and member data. + return mapif_guild_master_changed(g, g->member[0].account_id, g->member[0].char_id); } // Communication from the map server @@ -1842,44 +1814,78 @@ int mapif_parse_GuildMasterChange(int fd, int guild_id, const char* name, int le // Data packet length that you set to inter.c //- Shouldn't do checking and packet length, RFIFOSKIP is done by the caller // Must Return -// 1 : ok +// 1 : ok // 0 : error int inter_guild_parse_frommap(int fd) { - RFIFOHEAD(fd); - switch(RFIFOW(fd,0)) { - case 0x3030: mapif_parse_CreateGuild(fd,RFIFOL(fd,4),(char*)RFIFOP(fd,8),(struct guild_member *)RFIFOP(fd,32)); break; - case 0x3031: mapif_parse_GuildInfo(fd,RFIFOL(fd,2)); break; - case 0x3032: mapif_parse_GuildAddMember(fd,RFIFOL(fd,4),(struct guild_member *)RFIFOP(fd,8)); break; - case 0x3033: mapif_parse_GuildMasterChange(fd,RFIFOL(fd,4),(const char*)RFIFOP(fd,8),RFIFOW(fd,2)-8); break; - case 0x3034: mapif_parse_GuildLeave(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),(const char*)RFIFOP(fd,15)); break; - case 0x3035: mapif_parse_GuildChangeMemberInfoShort(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),RFIFOW(fd,15),RFIFOW(fd,17)); break; - case 0x3036: mapif_parse_BreakGuild(fd,RFIFOL(fd,2)); break; - case 0x3037: mapif_parse_GuildMessage(fd,RFIFOL(fd,4),RFIFOL(fd,8),(char*)RFIFOP(fd,12),RFIFOW(fd,2)-12); break; - case 0x3039: mapif_parse_GuildBasicInfoChange(fd,RFIFOL(fd,4),RFIFOW(fd,8),(const char*)RFIFOP(fd,10),RFIFOW(fd,2)-10); break; - case 0x303A: mapif_parse_GuildMemberInfoChange(fd,RFIFOL(fd,4),RFIFOL(fd,8),RFIFOL(fd,12),RFIFOW(fd,16),(const char*)RFIFOP(fd,18),RFIFOW(fd,2)-18); break; - case 0x303B: mapif_parse_GuildPosition(fd,RFIFOL(fd,4),RFIFOL(fd,8),(struct guild_position *)RFIFOP(fd,12)); break; - case 0x303C: mapif_parse_GuildSkillUp(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14)); break; - case 0x303D: mapif_parse_GuildAlliance(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14),RFIFOB(fd,18)); break; - case 0x303E: mapif_parse_GuildNotice(fd,RFIFOL(fd,2),(const char*)RFIFOP(fd,6),(const char*)RFIFOP(fd,66)); break; - case 0x303F: mapif_parse_GuildEmblem(fd,RFIFOW(fd,2)-12,RFIFOL(fd,4),RFIFOL(fd,8),(const char*)RFIFOP(fd,12)); break; - case 0x3040: mapif_parse_GuildCastleDataLoad(fd,RFIFOW(fd,2),(int *)RFIFOP(fd,4)); break; - case 0x3041: mapif_parse_GuildCastleDataSave(fd,RFIFOW(fd,2),RFIFOB(fd,4),RFIFOL(fd,5)); break; - - default: - return 0; - } - - return 1; + RFIFOHEAD(fd); + switch (RFIFOW(fd,0)) { + case 0x3030: + mapif_parse_CreateGuild(fd,RFIFOL(fd,4),(char *)RFIFOP(fd,8),(struct guild_member *)RFIFOP(fd,32)); + break; + case 0x3031: + mapif_parse_GuildInfo(fd,RFIFOL(fd,2)); + break; + case 0x3032: + mapif_parse_GuildAddMember(fd,RFIFOL(fd,4),(struct guild_member *)RFIFOP(fd,8)); + break; + case 0x3033: + mapif_parse_GuildMasterChange(fd,RFIFOL(fd,4),(const char *)RFIFOP(fd,8),RFIFOW(fd,2)-8); + break; + case 0x3034: + mapif_parse_GuildLeave(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),(const char *)RFIFOP(fd,15)); + break; + case 0x3035: + mapif_parse_GuildChangeMemberInfoShort(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),RFIFOW(fd,15),RFIFOW(fd,17)); + break; + case 0x3036: + mapif_parse_BreakGuild(fd,RFIFOL(fd,2)); + break; + case 0x3037: + mapif_parse_GuildMessage(fd,RFIFOL(fd,4),RFIFOL(fd,8),(char *)RFIFOP(fd,12),RFIFOW(fd,2)-12); + break; + case 0x3039: + mapif_parse_GuildBasicInfoChange(fd,RFIFOL(fd,4),RFIFOW(fd,8),(const char *)RFIFOP(fd,10),RFIFOW(fd,2)-10); + break; + case 0x303A: + mapif_parse_GuildMemberInfoChange(fd,RFIFOL(fd,4),RFIFOL(fd,8),RFIFOL(fd,12),RFIFOW(fd,16),(const char *)RFIFOP(fd,18),RFIFOW(fd,2)-18); + break; + case 0x303B: + mapif_parse_GuildPosition(fd,RFIFOL(fd,4),RFIFOL(fd,8),(struct guild_position *)RFIFOP(fd,12)); + break; + case 0x303C: + mapif_parse_GuildSkillUp(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14)); + break; + case 0x303D: + mapif_parse_GuildAlliance(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14),RFIFOB(fd,18)); + break; + case 0x303E: + mapif_parse_GuildNotice(fd,RFIFOL(fd,2),(const char *)RFIFOP(fd,6),(const char *)RFIFOP(fd,66)); + break; + case 0x303F: + mapif_parse_GuildEmblem(fd,RFIFOW(fd,2)-12,RFIFOL(fd,4),RFIFOL(fd,8),(const char *)RFIFOP(fd,12)); + break; + case 0x3040: + mapif_parse_GuildCastleDataLoad(fd,RFIFOW(fd,2),(int *)RFIFOP(fd,4)); + break; + case 0x3041: + mapif_parse_GuildCastleDataSave(fd,RFIFOW(fd,2),RFIFOB(fd,4),RFIFOL(fd,5)); + break; + + default: + return 0; + } + + return 1; } //Leave request from the server (for deleting character from guild) int inter_guild_leave(int guild_id, int account_id, int char_id) { - return mapif_parse_GuildLeave(-1, guild_id, account_id, char_id, 0, "** Character Deleted **"); + return mapif_parse_GuildLeave(-1, guild_id, account_id, char_id, 0, "** Character Deleted **"); } int inter_guild_broken(int guild_id) { - return mapif_guild_broken(guild_id, 0); + return mapif_guild_broken(guild_id, 0); } diff --git a/src/char/int_guild.h b/src/char/int_guild.h index 47c42dcc5..5bc3c2fe3 100644 --- a/src/char/int_guild.h +++ b/src/char/int_guild.h @@ -5,19 +5,19 @@ #define _INT_GUILD_SQL_H_ enum { - GS_BASIC = 0x0001, - GS_MEMBER = 0x0002, - GS_POSITION = 0x0004, - GS_ALLIANCE = 0x0008, - GS_EXPULSION = 0x0010, - GS_SKILL = 0x0020, - GS_EMBLEM = 0x0040, - GS_CONNECT = 0x0080, - GS_LEVEL = 0x0100, - GS_MES = 0x0200, - GS_MASK = 0x03FF, - GS_BASIC_MASK = (GS_BASIC | GS_EMBLEM | GS_CONNECT | GS_LEVEL | GS_MES), - GS_REMOVE = 0x8000, + GS_BASIC = 0x0001, + GS_MEMBER = 0x0002, + GS_POSITION = 0x0004, + GS_ALLIANCE = 0x0008, + GS_EXPULSION = 0x0010, + GS_SKILL = 0x0020, + GS_EMBLEM = 0x0040, + GS_CONNECT = 0x0080, + GS_LEVEL = 0x0100, + GS_MES = 0x0200, + GS_MASK = 0x03FF, + GS_BASIC_MASK = (GS_BASIC | GS_EMBLEM | GS_CONNECT | GS_LEVEL | GS_MES), + GS_REMOVE = 0x8000, }; struct guild; diff --git a/src/char/int_homun.c b/src/char/int_homun.c index 933661954..5676556f4 100644 --- a/src/char/int_homun.c +++ b/src/char/int_homun.c @@ -18,279 +18,281 @@ int inter_homunculus_sql_init(void) { - return 0; + return 0; } void inter_homunculus_sql_final(void) { - return; + return; } static void mapif_homunculus_created(int fd, int account_id, struct s_homunculus *sh, unsigned char flag) { - WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); - WFIFOW(fd,0) = 0x3890; - WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; - WFIFOL(fd,4) = account_id; - WFIFOB(fd,8)= flag; - memcpy(WFIFOP(fd,9),sh,sizeof(struct s_homunculus)); - WFIFOSET(fd, WFIFOW(fd,2)); + WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); + WFIFOW(fd,0) = 0x3890; + WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; + WFIFOL(fd,4) = account_id; + WFIFOB(fd,8)= flag; + memcpy(WFIFOP(fd,9),sh,sizeof(struct s_homunculus)); + WFIFOSET(fd, WFIFOW(fd,2)); } static void mapif_homunculus_deleted(int fd, int flag) { - WFIFOHEAD(fd, 3); - WFIFOW(fd, 0) = 0x3893; - WFIFOB(fd,2) = flag; //Flag 1 = success - WFIFOSET(fd, 3); + WFIFOHEAD(fd, 3); + WFIFOW(fd, 0) = 0x3893; + WFIFOB(fd,2) = flag; //Flag 1 = success + WFIFOSET(fd, 3); } static void mapif_homunculus_loaded(int fd, int account_id, struct s_homunculus *hd) { - WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); - WFIFOW(fd,0) = 0x3891; - WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; - WFIFOL(fd,4) = account_id; - if( hd != NULL ) - { - WFIFOB(fd,8) = 1; // success - memcpy(WFIFOP(fd,9), hd, sizeof(struct s_homunculus)); - } - else - { - WFIFOB(fd,8) = 0; // not found. - memset(WFIFOP(fd,9), 0, sizeof(struct s_homunculus)); - } - WFIFOSET(fd, sizeof(struct s_homunculus)+9); + WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); + WFIFOW(fd,0) = 0x3891; + WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; + WFIFOL(fd,4) = account_id; + if (hd != NULL) { + WFIFOB(fd,8) = 1; // success + memcpy(WFIFOP(fd,9), hd, sizeof(struct s_homunculus)); + } else { + WFIFOB(fd,8) = 0; // not found. + memset(WFIFOP(fd,9), 0, sizeof(struct s_homunculus)); + } + WFIFOSET(fd, sizeof(struct s_homunculus)+9); } static void mapif_homunculus_saved(int fd, int account_id, bool flag) { - WFIFOHEAD(fd, 7); - WFIFOW(fd,0) = 0x3892; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = flag; // 1:success, 0:failure - WFIFOSET(fd, 7); + WFIFOHEAD(fd, 7); + WFIFOW(fd,0) = 0x3892; + WFIFOL(fd,2) = account_id; + WFIFOB(fd,6) = flag; // 1:success, 0:failure + WFIFOSET(fd, 7); } -static void mapif_homunculus_renamed(int fd, int account_id, int char_id, unsigned char flag, char* name) +static void mapif_homunculus_renamed(int fd, int account_id, int char_id, unsigned char flag, char *name) { - WFIFOHEAD(fd, NAME_LENGTH+12); - WFIFOW(fd, 0) = 0x3894; - WFIFOL(fd, 2) = account_id; - WFIFOL(fd, 6) = char_id; - WFIFOB(fd,10) = flag; - safestrncpy((char*)WFIFOP(fd,11), name, NAME_LENGTH); - WFIFOSET(fd, NAME_LENGTH+12); + WFIFOHEAD(fd, NAME_LENGTH+12); + WFIFOW(fd, 0) = 0x3894; + WFIFOL(fd, 2) = account_id; + WFIFOL(fd, 6) = char_id; + WFIFOB(fd,10) = flag; + safestrncpy((char *)WFIFOP(fd,11), name, NAME_LENGTH); + WFIFOSET(fd, NAME_LENGTH+12); } -bool mapif_homunculus_save(struct s_homunculus* hd) +bool mapif_homunculus_save(struct s_homunculus *hd) { - bool flag = true; - char esc_name[NAME_LENGTH*2+1]; - - Sql_EscapeStringLen(sql_handle, esc_name, hd->name, strnlen(hd->name, NAME_LENGTH)); - - if( hd->hom_id == 0 ) - {// new homunculus - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " - "(`char_id`, `class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`, `rename_flag`, `vaporize`) " - "VALUES ('%d', '%d', '%d', '%s', '%d', '%u', '%u', '%d', '%d', %d, '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - homunculus_db, hd->char_id, hd->class_, hd->prev_class, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, - hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize) ) - { - Sql_ShowDebug(sql_handle); - flag = false; - } - else - { - hd->hom_id = (int)Sql_LastInsertId(sql_handle); - } - } - else - { - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_id`='%d', `class`='%d',`prev_class`='%d',`name`='%s',`level`='%d',`exp`='%u',`intimacy`='%u',`hunger`='%d', `str`='%d', `agi`='%d', `vit`='%d', `int`='%d', `dex`='%d', `luk`='%d', `hp`='%d',`max_hp`='%d',`sp`='%d',`max_sp`='%d',`skill_point`='%d', `rename_flag`='%d', `vaporize`='%d' WHERE `homun_id`='%d'", - homunculus_db, hd->char_id, hd->class_, hd->prev_class, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, - hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize, hd->hom_id) ) - { - Sql_ShowDebug(sql_handle); - flag = false; - } - else - { - SqlStmt* stmt; - int i; - - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_ERROR == SqlStmt_Prepare(stmt, "REPLACE INTO `%s` (`homun_id`, `id`, `lv`) VALUES (%d, ?, ?)", skill_homunculus_db, hd->hom_id) ) - SqlStmt_ShowDebug(stmt); - for( i = 0; i < MAX_HOMUNSKILL; ++i ) - { - if( hd->hskill[i].id > 0 && hd->hskill[i].lv != 0 ) - { - SqlStmt_BindParam(stmt, 0, SQLDT_USHORT, &hd->hskill[i].id, 0); - SqlStmt_BindParam(stmt, 1, SQLDT_USHORT, &hd->hskill[i].lv, 0); - if( SQL_ERROR == SqlStmt_Execute(stmt) ) - { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - flag = false; - break; - } - } - } - SqlStmt_Free(stmt); - } - } - - return flag; + bool flag = true; + char esc_name[NAME_LENGTH*2+1]; + + Sql_EscapeStringLen(sql_handle, esc_name, hd->name, strnlen(hd->name, NAME_LENGTH)); + + if (hd->hom_id == 0) { + // new homunculus + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " + "(`char_id`, `class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`, `rename_flag`, `vaporize`) " + "VALUES ('%d', '%d', '%d', '%s', '%d', '%u', '%u', '%d', '%d', %d, '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", + homunculus_db, hd->char_id, hd->class_, hd->prev_class, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, + hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize)) { + Sql_ShowDebug(sql_handle); + flag = false; + } else { + hd->hom_id = (int)Sql_LastInsertId(sql_handle); + } + } else { + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_id`='%d', `class`='%d',`prev_class`='%d',`name`='%s',`level`='%d',`exp`='%u',`intimacy`='%u',`hunger`='%d', `str`='%d', `agi`='%d', `vit`='%d', `int`='%d', `dex`='%d', `luk`='%d', `hp`='%d',`max_hp`='%d',`sp`='%d',`max_sp`='%d',`skill_point`='%d', `rename_flag`='%d', `vaporize`='%d' WHERE `homun_id`='%d'", + homunculus_db, hd->char_id, hd->class_, hd->prev_class, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, + hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize, hd->hom_id)) { + Sql_ShowDebug(sql_handle); + flag = false; + } else { + SqlStmt *stmt; + int i; + + stmt = SqlStmt_Malloc(sql_handle); + if (SQL_ERROR == SqlStmt_Prepare(stmt, "REPLACE INTO `%s` (`homun_id`, `id`, `lv`) VALUES (%d, ?, ?)", skill_homunculus_db, hd->hom_id)) + SqlStmt_ShowDebug(stmt); + for (i = 0; i < MAX_HOMUNSKILL; ++i) { + if (hd->hskill[i].id > 0 && hd->hskill[i].lv != 0) { + SqlStmt_BindParam(stmt, 0, SQLDT_USHORT, &hd->hskill[i].id, 0); + SqlStmt_BindParam(stmt, 1, SQLDT_USHORT, &hd->hskill[i].lv, 0); + if (SQL_ERROR == SqlStmt_Execute(stmt)) { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); + flag = false; + break; + } + } + } + SqlStmt_Free(stmt); + } + } + + return flag; } // Load an homunculus -bool mapif_homunculus_load(int homun_id, struct s_homunculus* hd) +bool mapif_homunculus_load(int homun_id, struct s_homunculus *hd) { - int i; - char* data; - size_t len; - - memset(hd, 0, sizeof(*hd)); - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `homun_id`,`char_id`,`class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`,`rename_flag`, `vaporize` FROM `%s` WHERE `homun_id`='%u'", homunculus_db, homun_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - if( !Sql_NumRows(sql_handle) ) - { //No homunculus found. - Sql_FreeResult(sql_handle); - return false; - } - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_ShowDebug(sql_handle); - Sql_FreeResult(sql_handle); - return false; - } - - hd->hom_id = homun_id; - Sql_GetData(sql_handle, 1, &data, NULL); hd->char_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); hd->class_ = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); hd->prev_class = atoi(data); - Sql_GetData(sql_handle, 4, &data, &len); safestrncpy(hd->name, data, sizeof(hd->name)); - Sql_GetData(sql_handle, 5, &data, NULL); hd->level = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); hd->exp = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); hd->intimacy = (unsigned int)strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 8, &data, NULL); hd->hunger = atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); hd->str = atoi(data); - Sql_GetData(sql_handle, 10, &data, NULL); hd->agi = atoi(data); - Sql_GetData(sql_handle, 11, &data, NULL); hd->vit = atoi(data); - Sql_GetData(sql_handle, 12, &data, NULL); hd->int_ = atoi(data); - Sql_GetData(sql_handle, 13, &data, NULL); hd->dex = atoi(data); - Sql_GetData(sql_handle, 14, &data, NULL); hd->luk = atoi(data); - Sql_GetData(sql_handle, 15, &data, NULL); hd->hp = atoi(data); - Sql_GetData(sql_handle, 16, &data, NULL); hd->max_hp = atoi(data); - Sql_GetData(sql_handle, 17, &data, NULL); hd->sp = atoi(data); - Sql_GetData(sql_handle, 18, &data, NULL); hd->max_sp = atoi(data); - Sql_GetData(sql_handle, 19, &data, NULL); hd->skillpts = atoi(data); - Sql_GetData(sql_handle, 20, &data, NULL); hd->rename_flag = atoi(data); - Sql_GetData(sql_handle, 21, &data, NULL); hd->vaporize = atoi(data); - Sql_FreeResult(sql_handle); - - hd->intimacy = cap_value(hd->intimacy, 0, 100000); - hd->hunger = cap_value(hd->hunger, 0, 100); - - // Load Homunculus Skill - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `%s` WHERE `homun_id`=%d", skill_homunculus_db, homun_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - // id - Sql_GetData(sql_handle, 0, &data, NULL); - i = atoi(data); - if( i < HM_SKILLBASE || i >= HM_SKILLBASE + MAX_HOMUNSKILL ) - continue;// invalid skill id - i = i - HM_SKILLBASE; - hd->hskill[i].id = (unsigned short)atoi(data); - - // lv - Sql_GetData(sql_handle, 1, &data, NULL); - hd->hskill[i].lv = (unsigned char)atoi(data); - } - Sql_FreeResult(sql_handle); - - if( save_log ) - ShowInfo("Homunculus loaded (%d - %s).\n", hd->hom_id, hd->name); - - return true; + int i; + char *data; + size_t len; + + memset(hd, 0, sizeof(*hd)); + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `homun_id`,`char_id`,`class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`,`rename_flag`, `vaporize` FROM `%s` WHERE `homun_id`='%u'", homunculus_db, homun_id)) { + Sql_ShowDebug(sql_handle); + return false; + } + + if (!Sql_NumRows(sql_handle)) { + //No homunculus found. + Sql_FreeResult(sql_handle); + return false; + } + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { + Sql_ShowDebug(sql_handle); + Sql_FreeResult(sql_handle); + return false; + } + + hd->hom_id = homun_id; + Sql_GetData(sql_handle, 1, &data, NULL); + hd->char_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + hd->class_ = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + hd->prev_class = atoi(data); + Sql_GetData(sql_handle, 4, &data, &len); + safestrncpy(hd->name, data, sizeof(hd->name)); + Sql_GetData(sql_handle, 5, &data, NULL); + hd->level = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + hd->exp = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); + hd->intimacy = (unsigned int)strtoul(data, NULL, 10); + Sql_GetData(sql_handle, 8, &data, NULL); + hd->hunger = atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); + hd->str = atoi(data); + Sql_GetData(sql_handle, 10, &data, NULL); + hd->agi = atoi(data); + Sql_GetData(sql_handle, 11, &data, NULL); + hd->vit = atoi(data); + Sql_GetData(sql_handle, 12, &data, NULL); + hd->int_ = atoi(data); + Sql_GetData(sql_handle, 13, &data, NULL); + hd->dex = atoi(data); + Sql_GetData(sql_handle, 14, &data, NULL); + hd->luk = atoi(data); + Sql_GetData(sql_handle, 15, &data, NULL); + hd->hp = atoi(data); + Sql_GetData(sql_handle, 16, &data, NULL); + hd->max_hp = atoi(data); + Sql_GetData(sql_handle, 17, &data, NULL); + hd->sp = atoi(data); + Sql_GetData(sql_handle, 18, &data, NULL); + hd->max_sp = atoi(data); + Sql_GetData(sql_handle, 19, &data, NULL); + hd->skillpts = atoi(data); + Sql_GetData(sql_handle, 20, &data, NULL); + hd->rename_flag = atoi(data); + Sql_GetData(sql_handle, 21, &data, NULL); + hd->vaporize = atoi(data); + Sql_FreeResult(sql_handle); + + hd->intimacy = cap_value(hd->intimacy, 0, 100000); + hd->hunger = cap_value(hd->hunger, 0, 100); + + // Load Homunculus Skill + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `%s` WHERE `homun_id`=%d", skill_homunculus_db, homun_id)) { + Sql_ShowDebug(sql_handle); + return false; + } + while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + // id + Sql_GetData(sql_handle, 0, &data, NULL); + i = atoi(data); + if (i < HM_SKILLBASE || i >= HM_SKILLBASE + MAX_HOMUNSKILL) + continue;// invalid skill id + i = i - HM_SKILLBASE; + hd->hskill[i].id = (unsigned short)atoi(data); + + // lv + Sql_GetData(sql_handle, 1, &data, NULL); + hd->hskill[i].lv = (unsigned char)atoi(data); + } + Sql_FreeResult(sql_handle); + + if (save_log) + ShowInfo("Homunculus loaded (%d - %s).\n", hd->hom_id, hd->name); + + return true; } bool mapif_homunculus_delete(int homun_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `homun_id` = '%u'", homunculus_db, homun_id) - || SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `homun_id` = '%u'", skill_homunculus_db, homun_id) - ) { - Sql_ShowDebug(sql_handle); - return false; - } - return true; + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `homun_id` = '%u'", homunculus_db, homun_id) + || SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `homun_id` = '%u'", skill_homunculus_db, homun_id) + ) { + Sql_ShowDebug(sql_handle); + return false; + } + return true; } bool mapif_homunculus_rename(char *name) { - int i; - - // Check Authorised letters/symbols in the name of the homun - if( char_name_option == 1 ) - {// only letters/symbols in char_name_letters are authorised - for( i = 0; i < NAME_LENGTH && name[i]; i++ ) - if( strchr(char_name_letters, name[i]) == NULL ) - return false; - } else - if( char_name_option == 2 ) - {// letters/symbols in char_name_letters are forbidden - for( i = 0; i < NAME_LENGTH && name[i]; i++ ) - if( strchr(char_name_letters, name[i]) != NULL ) - return false; - } - - return true; + int i; + + // Check Authorised letters/symbols in the name of the homun + if (char_name_option == 1) { + // only letters/symbols in char_name_letters are authorised + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) == NULL) + return false; + } else if (char_name_option == 2) { + // letters/symbols in char_name_letters are forbidden + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) != NULL) + return false; + } + + return true; } -static void mapif_parse_homunculus_create(int fd, int len, int account_id, struct s_homunculus* phd) +static void mapif_parse_homunculus_create(int fd, int len, int account_id, struct s_homunculus *phd) { - bool result = mapif_homunculus_save(phd); - mapif_homunculus_created(fd, account_id, phd, result); + bool result = mapif_homunculus_save(phd); + mapif_homunculus_created(fd, account_id, phd, result); } static void mapif_parse_homunculus_delete(int fd, int homun_id) { - bool result = mapif_homunculus_delete(homun_id); - mapif_homunculus_deleted(fd, result); + bool result = mapif_homunculus_delete(homun_id); + mapif_homunculus_deleted(fd, result); } static void mapif_parse_homunculus_load(int fd, int account_id, int homun_id) { - struct s_homunculus hd; - bool result = mapif_homunculus_load(homun_id, &hd); - mapif_homunculus_loaded(fd, account_id, ( result ? &hd : NULL )); + struct s_homunculus hd; + bool result = mapif_homunculus_load(homun_id, &hd); + mapif_homunculus_loaded(fd, account_id, (result ? &hd : NULL)); } -static void mapif_parse_homunculus_save(int fd, int len, int account_id, struct s_homunculus* phd) +static void mapif_parse_homunculus_save(int fd, int len, int account_id, struct s_homunculus *phd) { - bool result = mapif_homunculus_save(phd); - mapif_homunculus_saved(fd, account_id, result); + bool result = mapif_homunculus_save(phd); + mapif_homunculus_saved(fd, account_id, result); } -static void mapif_parse_homunculus_rename(int fd, int account_id, int char_id, char* name) +static void mapif_parse_homunculus_rename(int fd, int account_id, int char_id, char *name) { - bool result = mapif_homunculus_rename(name); - mapif_homunculus_renamed(fd, account_id, char_id, result, name); + bool result = mapif_homunculus_rename(name); + mapif_homunculus_renamed(fd, account_id, char_id, result, name); } /*========================================== @@ -298,17 +300,26 @@ static void mapif_parse_homunculus_rename(int fd, int account_id, int char_id, c *------------------------------------------*/ int inter_homunculus_parse_frommap(int fd) { - unsigned short cmd = RFIFOW(fd,0); - - switch( cmd ) - { - case 0x3090: mapif_parse_homunculus_create(fd, (int)RFIFOW(fd,2), (int)RFIFOL(fd,4), (struct s_homunculus*)RFIFOP(fd,8)); break; - case 0x3091: mapif_parse_homunculus_load (fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); break; - case 0x3092: mapif_parse_homunculus_save (fd, (int)RFIFOW(fd,2), (int)RFIFOL(fd,4), (struct s_homunculus*)RFIFOP(fd,8)); break; - case 0x3093: mapif_parse_homunculus_delete(fd, (int)RFIFOL(fd,2)); break; - case 0x3094: mapif_parse_homunculus_rename(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6), (char*)RFIFOP(fd,10)); break; - default: - return 0; - } - return 1; + unsigned short cmd = RFIFOW(fd,0); + + switch (cmd) { + case 0x3090: + mapif_parse_homunculus_create(fd, (int)RFIFOW(fd,2), (int)RFIFOL(fd,4), (struct s_homunculus *)RFIFOP(fd,8)); + break; + case 0x3091: + mapif_parse_homunculus_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); + break; + case 0x3092: + mapif_parse_homunculus_save(fd, (int)RFIFOW(fd,2), (int)RFIFOL(fd,4), (struct s_homunculus *)RFIFOP(fd,8)); + break; + case 0x3093: + mapif_parse_homunculus_delete(fd, (int)RFIFOL(fd,2)); + break; + case 0x3094: + mapif_parse_homunculus_rename(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6), (char *)RFIFOP(fd,10)); + break; + default: + return 0; + } + return 1; } diff --git a/src/char/int_homun.h b/src/char/int_homun.h index 1c0d76269..e7976d51a 100644 --- a/src/char/int_homun.h +++ b/src/char/int_homun.h @@ -10,8 +10,8 @@ int inter_homunculus_sql_init(void); void inter_homunculus_sql_final(void); int inter_homunculus_parse_frommap(int fd); -bool mapif_homunculus_save(struct s_homunculus* hd); -bool mapif_homunculus_load(int homun_id, struct s_homunculus* hd); +bool mapif_homunculus_save(struct s_homunculus *hd); +bool mapif_homunculus_load(int homun_id, struct s_homunculus *hd); bool mapif_homunculus_delete(int homun_id); bool mapif_homunculus_rename(char *name); diff --git a/src/char/int_mail.c b/src/char/int_mail.c index 98da43aeb..2e34d9014 100644 --- a/src/char/int_mail.c +++ b/src/char/int_mail.c @@ -15,180 +15,200 @@ #include #include -static int mail_fromsql(int char_id, struct mail_data* md) +static int mail_fromsql(int char_id, struct mail_data *md) { - int i, j; - struct mail_message *msg; - struct item *item; - char *data; - StringBuf buf; - - memset(md, 0, sizeof(struct mail_data)); - md->amount = 0; - md->full = false; - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`," - "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`"); - for (i = 0; i < MAX_SLOTS; i++) - StringBuf_Printf(&buf, ",`card%d`", i); - - // I keep the `status` < 3 just in case someone forget to apply the sqlfix - StringBuf_Printf(&buf, " FROM `%s` WHERE `dest_id`='%d' AND `status` < 3 ORDER BY `id` LIMIT %d", - mail_db, char_id, MAIL_MAX_INBOX + 1); - - if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) - Sql_ShowDebug(sql_handle); - - StringBuf_Destroy(&buf); - - for (i = 0; i < MAIL_MAX_INBOX && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - msg = &md->msg[i]; - Sql_GetData(sql_handle, 0, &data, NULL); msg->id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(msg->send_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 2, &data, NULL); msg->send_id = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); safestrncpy(msg->dest_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 4, &data, NULL); msg->dest_id = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); safestrncpy(msg->title, data, MAIL_TITLE_LENGTH); - Sql_GetData(sql_handle, 6, &data, NULL); safestrncpy(msg->body, data, MAIL_BODY_LENGTH); - Sql_GetData(sql_handle, 7, &data, NULL); msg->timestamp = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); msg->status = (mail_status)atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); msg->zeny = atoi(data); - item = &msg->item; - Sql_GetData(sql_handle,10, &data, NULL); item->amount = (short)atoi(data); - Sql_GetData(sql_handle,11, &data, NULL); item->nameid = atoi(data); - Sql_GetData(sql_handle,12, &data, NULL); item->refine = atoi(data); - Sql_GetData(sql_handle,13, &data, NULL); item->attribute = atoi(data); - Sql_GetData(sql_handle,14, &data, NULL); item->identify = atoi(data); - item->expire_time = 0; - - for (j = 0; j < MAX_SLOTS; j++) - { - Sql_GetData(sql_handle, 15 + j, &data, NULL); - item->card[j] = atoi(data); - } - } - - md->full = ( Sql_NumRows(sql_handle) > MAIL_MAX_INBOX ); - - md->amount = i; - Sql_FreeResult(sql_handle); - - md->unchecked = 0; - md->unread = 0; - for (i = 0; i < md->amount; i++) - { - msg = &md->msg[i]; - if( msg->status == MAIL_NEW ) - { - if ( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_UNREAD, msg->id) ) - Sql_ShowDebug(sql_handle); - - msg->status = MAIL_UNREAD; - md->unchecked++; - } - else if ( msg->status == MAIL_UNREAD ) - md->unread++; - } - - ShowInfo("mail load complete from DB - id: %d (total: %d)\n", char_id, md->amount); - return 1; + int i, j; + struct mail_message *msg; + struct item *item; + char *data; + StringBuf buf; + + memset(md, 0, sizeof(struct mail_data)); + md->amount = 0; + md->full = false; + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`," + "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`"); + for (i = 0; i < MAX_SLOTS; i++) + StringBuf_Printf(&buf, ",`card%d`", i); + + // I keep the `status` < 3 just in case someone forget to apply the sqlfix + StringBuf_Printf(&buf, " FROM `%s` WHERE `dest_id`='%d' AND `status` < 3 ORDER BY `id` LIMIT %d", + mail_db, char_id, MAIL_MAX_INBOX + 1); + + if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) + Sql_ShowDebug(sql_handle); + + StringBuf_Destroy(&buf); + + for (i = 0; i < MAIL_MAX_INBOX && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + msg = &md->msg[i]; + Sql_GetData(sql_handle, 0, &data, NULL); + msg->id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + safestrncpy(msg->send_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 2, &data, NULL); + msg->send_id = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + safestrncpy(msg->dest_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 4, &data, NULL); + msg->dest_id = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + safestrncpy(msg->title, data, MAIL_TITLE_LENGTH); + Sql_GetData(sql_handle, 6, &data, NULL); + safestrncpy(msg->body, data, MAIL_BODY_LENGTH); + Sql_GetData(sql_handle, 7, &data, NULL); + msg->timestamp = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); + msg->status = (mail_status)atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); + msg->zeny = atoi(data); + item = &msg->item; + Sql_GetData(sql_handle,10, &data, NULL); + item->amount = (short)atoi(data); + Sql_GetData(sql_handle,11, &data, NULL); + item->nameid = atoi(data); + Sql_GetData(sql_handle,12, &data, NULL); + item->refine = atoi(data); + Sql_GetData(sql_handle,13, &data, NULL); + item->attribute = atoi(data); + Sql_GetData(sql_handle,14, &data, NULL); + item->identify = atoi(data); + item->expire_time = 0; + + for (j = 0; j < MAX_SLOTS; j++) { + Sql_GetData(sql_handle, 15 + j, &data, NULL); + item->card[j] = atoi(data); + } + } + + md->full = (Sql_NumRows(sql_handle) > MAIL_MAX_INBOX); + + md->amount = i; + Sql_FreeResult(sql_handle); + + md->unchecked = 0; + md->unread = 0; + for (i = 0; i < md->amount; i++) { + msg = &md->msg[i]; + if (msg->status == MAIL_NEW) { + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_UNREAD, msg->id)) + Sql_ShowDebug(sql_handle); + + msg->status = MAIL_UNREAD; + md->unchecked++; + } else if (msg->status == MAIL_UNREAD) + md->unread++; + } + + ShowInfo("mail load complete from DB - id: %d (total: %d)\n", char_id, md->amount); + return 1; } /// Stores a single message in the database. /// Returns the message's ID if successful (or 0 if it fails). -int mail_savemessage(struct mail_message* msg) +int mail_savemessage(struct mail_message *msg) { - StringBuf buf; - SqlStmt* stmt; - int j; - - // build message save query - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`send_name`, `send_id`, `dest_name`, `dest_id`, `title`, `message`, `time`, `status`, `zeny`, `amount`, `nameid`, `refine`, `attribute`, `identify`", mail_db); - for (j = 0; j < MAX_SLOTS; j++) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_Printf(&buf, ") VALUES (?, '%d', ?, '%d', ?, ?, '%lu', '%d', '%d', '%d', '%d', '%d', '%d', '%d'", - msg->send_id, msg->dest_id, (unsigned long)msg->timestamp, msg->status, msg->zeny, msg->item.amount, msg->item.nameid, msg->item.refine, msg->item.attribute, msg->item.identify); - for (j = 0; j < MAX_SLOTS; j++) - StringBuf_Printf(&buf, ", '%d'", msg->item.card[j]); - StringBuf_AppendStr(&buf, ")"); - - // prepare and execute query - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, msg->send_name, strnlen(msg->send_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, msg->dest_name, strnlen(msg->dest_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, msg->title, strnlen(msg->title, MAIL_TITLE_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, msg->body, strnlen(msg->body, MAIL_BODY_LENGTH)) - || SQL_SUCCESS != SqlStmt_Execute(stmt) ) - { - SqlStmt_ShowDebug(stmt); - msg->id = 0; - } else - msg->id = (int)SqlStmt_LastInsertId(stmt); - - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); - - return msg->id; + StringBuf buf; + SqlStmt *stmt; + int j; + + // build message save query + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`send_name`, `send_id`, `dest_name`, `dest_id`, `title`, `message`, `time`, `status`, `zeny`, `amount`, `nameid`, `refine`, `attribute`, `identify`", mail_db); + for (j = 0; j < MAX_SLOTS; j++) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_Printf(&buf, ") VALUES (?, '%d', ?, '%d', ?, ?, '%lu', '%d', '%d', '%d', '%d', '%d', '%d', '%d'", + msg->send_id, msg->dest_id, (unsigned long)msg->timestamp, msg->status, msg->zeny, msg->item.amount, msg->item.nameid, msg->item.refine, msg->item.attribute, msg->item.identify); + for (j = 0; j < MAX_SLOTS; j++) + StringBuf_Printf(&buf, ", '%d'", msg->item.card[j]); + StringBuf_AppendStr(&buf, ")"); + + // prepare and execute query + stmt = SqlStmt_Malloc(sql_handle); + if (SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, msg->send_name, strnlen(msg->send_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, msg->dest_name, strnlen(msg->dest_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, msg->title, strnlen(msg->title, MAIL_TITLE_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, msg->body, strnlen(msg->body, MAIL_BODY_LENGTH)) + || SQL_SUCCESS != SqlStmt_Execute(stmt)) { + SqlStmt_ShowDebug(stmt); + msg->id = 0; + } else + msg->id = (int)SqlStmt_LastInsertId(stmt); + + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); + + return msg->id; } /// Retrieves a single message from the database. /// Returns true if the operation succeeds (or false if it fails). -static bool mail_loadmessage(int mail_id, struct mail_message* msg) +static bool mail_loadmessage(int mail_id, struct mail_message *msg) { - int j; - StringBuf buf; - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`," - "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`"); - for( j = 0; j < MAX_SLOTS; j++ ) - StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `id` = '%d'", mail_db, mail_id); - - if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) - || SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_ShowDebug(sql_handle); - Sql_FreeResult(sql_handle); - StringBuf_Destroy(&buf); - return false; - } - else - { - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); msg->id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(msg->send_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 2, &data, NULL); msg->send_id = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); safestrncpy(msg->dest_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 4, &data, NULL); msg->dest_id = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); safestrncpy(msg->title, data, MAIL_TITLE_LENGTH); - Sql_GetData(sql_handle, 6, &data, NULL); safestrncpy(msg->body, data, MAIL_BODY_LENGTH); - Sql_GetData(sql_handle, 7, &data, NULL); msg->timestamp = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); msg->status = (mail_status)atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); msg->zeny = atoi(data); - Sql_GetData(sql_handle,10, &data, NULL); msg->item.amount = (short)atoi(data); - Sql_GetData(sql_handle,11, &data, NULL); msg->item.nameid = atoi(data); - Sql_GetData(sql_handle,12, &data, NULL); msg->item.refine = atoi(data); - Sql_GetData(sql_handle,13, &data, NULL); msg->item.attribute = atoi(data); - Sql_GetData(sql_handle,14, &data, NULL); msg->item.identify = atoi(data); - msg->item.expire_time = 0; - - for( j = 0; j < MAX_SLOTS; j++ ) - { - Sql_GetData(sql_handle,15 + j, &data, NULL); - msg->item.card[j] = atoi(data); - } - } - - StringBuf_Destroy(&buf); - Sql_FreeResult(sql_handle); - - return true; + int j; + StringBuf buf; + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`," + "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`"); + for (j = 0; j < MAX_SLOTS; j++) + StringBuf_Printf(&buf, ",`card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `id` = '%d'", mail_db, mail_id); + + if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) + || SQL_SUCCESS != Sql_NextRow(sql_handle)) { + Sql_ShowDebug(sql_handle); + Sql_FreeResult(sql_handle); + StringBuf_Destroy(&buf); + return false; + } else { + char *data; + + Sql_GetData(sql_handle, 0, &data, NULL); + msg->id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + safestrncpy(msg->send_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 2, &data, NULL); + msg->send_id = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + safestrncpy(msg->dest_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 4, &data, NULL); + msg->dest_id = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + safestrncpy(msg->title, data, MAIL_TITLE_LENGTH); + Sql_GetData(sql_handle, 6, &data, NULL); + safestrncpy(msg->body, data, MAIL_BODY_LENGTH); + Sql_GetData(sql_handle, 7, &data, NULL); + msg->timestamp = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); + msg->status = (mail_status)atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); + msg->zeny = atoi(data); + Sql_GetData(sql_handle,10, &data, NULL); + msg->item.amount = (short)atoi(data); + Sql_GetData(sql_handle,11, &data, NULL); + msg->item.nameid = atoi(data); + Sql_GetData(sql_handle,12, &data, NULL); + msg->item.refine = atoi(data); + Sql_GetData(sql_handle,13, &data, NULL); + msg->item.attribute = atoi(data); + Sql_GetData(sql_handle,14, &data, NULL); + msg->item.identify = atoi(data); + msg->item.expire_time = 0; + + for (j = 0; j < MAX_SLOTS; j++) { + Sql_GetData(sql_handle,15 + j, &data, NULL); + msg->item.card[j] = atoi(data); + } + } + + StringBuf_Destroy(&buf); + Sql_FreeResult(sql_handle); + + return true; } /*========================================== @@ -196,22 +216,22 @@ static bool mail_loadmessage(int mail_id, struct mail_message* msg) *------------------------------------------*/ static void mapif_Mail_sendinbox(int fd, int char_id, unsigned char flag) { - struct mail_data md; - mail_fromsql(char_id, &md); - - //FIXME: dumping the whole structure like this is unsafe [ultramage] - WFIFOHEAD(fd, sizeof(md) + 9); - WFIFOW(fd,0) = 0x3848; - WFIFOW(fd,2) = sizeof(md) + 9; - WFIFOL(fd,4) = char_id; - WFIFOB(fd,8) = flag; - memcpy(WFIFOP(fd,9),&md,sizeof(md)); - WFIFOSET(fd,WFIFOW(fd,2)); + struct mail_data md; + mail_fromsql(char_id, &md); + + //FIXME: dumping the whole structure like this is unsafe [ultramage] + WFIFOHEAD(fd, sizeof(md) + 9); + WFIFOW(fd,0) = 0x3848; + WFIFOW(fd,2) = sizeof(md) + 9; + WFIFOL(fd,4) = char_id; + WFIFOB(fd,8) = flag; + memcpy(WFIFOP(fd,9),&md,sizeof(md)); + WFIFOSET(fd,WFIFOW(fd,2)); } static void mapif_parse_Mail_requestinbox(int fd) { - mapif_Mail_sendinbox(fd, RFIFOL(fd,2), RFIFOB(fd,6)); + mapif_Mail_sendinbox(fd, RFIFOL(fd,2), RFIFOB(fd,6)); } /*========================================== @@ -219,9 +239,9 @@ static void mapif_parse_Mail_requestinbox(int fd) *------------------------------------------*/ static void mapif_parse_Mail_read(int fd) { - int mail_id = RFIFOL(fd,2); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_READ, mail_id) ) - Sql_ShowDebug(sql_handle); + int mail_id = RFIFOL(fd,2); + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_READ, mail_id)) + Sql_ShowDebug(sql_handle); } /*========================================== @@ -229,58 +249,57 @@ static void mapif_parse_Mail_read(int fd) *------------------------------------------*/ static bool mail_DeleteAttach(int mail_id) { - StringBuf buf; - int i; + StringBuf buf; + int i; - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET `zeny` = '0', `nameid` = '0', `amount` = '0', `refine` = '0', `attribute` = '0', `identify` = '0'", mail_db); - for (i = 0; i < MAX_SLOTS; i++) - StringBuf_Printf(&buf, ", `card%d` = '0'", i); - StringBuf_Printf(&buf, " WHERE `id` = '%d'", mail_id); + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET `zeny` = '0', `nameid` = '0', `amount` = '0', `refine` = '0', `attribute` = '0', `identify` = '0'", mail_db); + for (i = 0; i < MAX_SLOTS; i++) + StringBuf_Printf(&buf, ", `card%d` = '0'", i); + StringBuf_Printf(&buf, " WHERE `id` = '%d'", mail_id); - if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - StringBuf_Destroy(&buf); + if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + StringBuf_Destroy(&buf); - return false; - } + return false; + } - StringBuf_Destroy(&buf); - return true; + StringBuf_Destroy(&buf); + return true; } static void mapif_Mail_getattach(int fd, int char_id, int mail_id) { - struct mail_message msg; + struct mail_message msg; - if( !mail_loadmessage(mail_id, &msg) ) - return; + if (!mail_loadmessage(mail_id, &msg)) + return; - if( msg.dest_id != char_id ) - return; + if (msg.dest_id != char_id) + return; - if( msg.status != MAIL_READ ) - return; + if (msg.status != MAIL_READ) + return; - if( (msg.item.nameid < 1 || msg.item.amount < 1) && msg.zeny < 1 ) - return; // No Attachment + if ((msg.item.nameid < 1 || msg.item.amount < 1) && msg.zeny < 1) + return; // No Attachment - if( !mail_DeleteAttach(mail_id) ) - return; + if (!mail_DeleteAttach(mail_id)) + return; - WFIFOHEAD(fd, sizeof(struct item) + 12); - WFIFOW(fd,0) = 0x384a; - WFIFOW(fd,2) = sizeof(struct item) + 12; - WFIFOL(fd,4) = char_id; - WFIFOL(fd,8) = (msg.zeny > 0)?msg.zeny:0; - memcpy(WFIFOP(fd,12), &msg.item, sizeof(struct item)); - WFIFOSET(fd,WFIFOW(fd,2)); + WFIFOHEAD(fd, sizeof(struct item) + 12); + WFIFOW(fd,0) = 0x384a; + WFIFOW(fd,2) = sizeof(struct item) + 12; + WFIFOL(fd,4) = char_id; + WFIFOL(fd,8) = (msg.zeny > 0)?msg.zeny:0; + memcpy(WFIFOP(fd,12), &msg.item, sizeof(struct item)); + WFIFOSET(fd,WFIFOW(fd,2)); } static void mapif_parse_Mail_getattach(int fd) { - mapif_Mail_getattach(fd, RFIFOL(fd,2), RFIFOL(fd,6)); + mapif_Mail_getattach(fd, RFIFOL(fd,2), RFIFOL(fd,6)); } /*========================================== @@ -288,24 +307,23 @@ static void mapif_parse_Mail_getattach(int fd) *------------------------------------------*/ static void mapif_Mail_delete(int fd, int char_id, int mail_id) { - bool failed = false; - if ( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id) ) - { - Sql_ShowDebug(sql_handle); - failed = true; - } - - WFIFOHEAD(fd,11); - WFIFOW(fd,0) = 0x384b; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = mail_id; - WFIFOB(fd,10) = failed; - WFIFOSET(fd,11); + bool failed = false; + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id)) { + Sql_ShowDebug(sql_handle); + failed = true; + } + + WFIFOHEAD(fd,11); + WFIFOW(fd,0) = 0x384b; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = mail_id; + WFIFOB(fd,10) = failed; + WFIFOSET(fd,11); } static void mapif_parse_Mail_delete(int fd) { - mapif_Mail_delete(fd, RFIFOL(fd,2), RFIFOL(fd,6)); + mapif_Mail_delete(fd, RFIFOL(fd,2), RFIFOL(fd,6)); } /*========================================== @@ -313,17 +331,17 @@ static void mapif_parse_Mail_delete(int fd) *------------------------------------------*/ void mapif_Mail_new(struct mail_message *msg) { - unsigned char buf[74]; - - if( !msg || !msg->id ) - return; - - WBUFW(buf,0) = 0x3849; - WBUFL(buf,2) = msg->dest_id; - WBUFL(buf,6) = msg->id; - memcpy(WBUFP(buf,10), msg->send_name, NAME_LENGTH); - memcpy(WBUFP(buf,34), msg->title, MAIL_TITLE_LENGTH); - mapif_sendall(buf, 74); + unsigned char buf[74]; + + if (!msg || !msg->id) + return; + + WBUFW(buf,0) = 0x3849; + WBUFL(buf,2) = msg->dest_id; + WBUFL(buf,6) = msg->id; + memcpy(WBUFP(buf,10), msg->send_name, NAME_LENGTH); + memcpy(WBUFP(buf,34), msg->title, MAIL_TITLE_LENGTH); + mapif_sendall(buf, 74); } /*========================================== @@ -331,120 +349,116 @@ void mapif_Mail_new(struct mail_message *msg) *------------------------------------------*/ static void mapif_Mail_return(int fd, int char_id, int mail_id) { - struct mail_message msg; - int new_mail = 0; - - if( mail_loadmessage(mail_id, &msg) ) - { - if( msg.dest_id != char_id) - return; - else if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id) ) - Sql_ShowDebug(sql_handle); - else - { - char temp_[MAIL_TITLE_LENGTH]; - - // swap sender and receiver - swap(msg.send_id, msg.dest_id); - safestrncpy(temp_, msg.send_name, NAME_LENGTH); - safestrncpy(msg.send_name, msg.dest_name, NAME_LENGTH); - safestrncpy(msg.dest_name, temp_, NAME_LENGTH); - - // set reply message title - snprintf(temp_, MAIL_TITLE_LENGTH, "RE:%s", msg.title); - safestrncpy(msg.title, temp_, MAIL_TITLE_LENGTH); - - msg.status = MAIL_NEW; - msg.timestamp = time(NULL); - - new_mail = mail_savemessage(&msg); - mapif_Mail_new(&msg); - } - } - - WFIFOHEAD(fd,11); - WFIFOW(fd,0) = 0x384c; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = mail_id; - WFIFOB(fd,10) = (new_mail == 0); - WFIFOSET(fd,11); + struct mail_message msg; + int new_mail = 0; + + if (mail_loadmessage(mail_id, &msg)) { + if (msg.dest_id != char_id) + return; + else if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id)) + Sql_ShowDebug(sql_handle); + else { + char temp_[MAIL_TITLE_LENGTH]; + + // swap sender and receiver + swap(msg.send_id, msg.dest_id); + safestrncpy(temp_, msg.send_name, NAME_LENGTH); + safestrncpy(msg.send_name, msg.dest_name, NAME_LENGTH); + safestrncpy(msg.dest_name, temp_, NAME_LENGTH); + + // set reply message title + snprintf(temp_, MAIL_TITLE_LENGTH, "RE:%s", msg.title); + safestrncpy(msg.title, temp_, MAIL_TITLE_LENGTH); + + msg.status = MAIL_NEW; + msg.timestamp = time(NULL); + + new_mail = mail_savemessage(&msg); + mapif_Mail_new(&msg); + } + } + + WFIFOHEAD(fd,11); + WFIFOW(fd,0) = 0x384c; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = mail_id; + WFIFOB(fd,10) = (new_mail == 0); + WFIFOSET(fd,11); } static void mapif_parse_Mail_return(int fd) { - mapif_Mail_return(fd, RFIFOL(fd,2), RFIFOL(fd,6)); + mapif_Mail_return(fd, RFIFOL(fd,2), RFIFOL(fd,6)); } /*========================================== * Send Mail *------------------------------------------*/ -static void mapif_Mail_send(int fd, struct mail_message* msg) +static void mapif_Mail_send(int fd, struct mail_message *msg) { - int len = sizeof(struct mail_message) + 4; - - WFIFOHEAD(fd,len); - WFIFOW(fd,0) = 0x384d; - WFIFOW(fd,2) = len; - memcpy(WFIFOP(fd,4), msg, sizeof(struct mail_message)); - WFIFOSET(fd,len); + int len = sizeof(struct mail_message) + 4; + + WFIFOHEAD(fd,len); + WFIFOW(fd,0) = 0x384d; + WFIFOW(fd,2) = len; + memcpy(WFIFOP(fd,4), msg, sizeof(struct mail_message)); + WFIFOSET(fd,len); } static void mapif_parse_Mail_send(int fd) { - struct mail_message msg; - char esc_name[NAME_LENGTH*2+1]; - int account_id = 0; - - if(RFIFOW(fd,2) != 8 + sizeof(struct mail_message)) - return; - - account_id = RFIFOL(fd,4); - memcpy(&msg, RFIFOP(fd,8), sizeof(struct mail_message)); - - // Try to find the Dest Char by Name - Sql_EscapeStringLen(sql_handle, esc_name, msg.dest_name, strnlen(msg.dest_name, NAME_LENGTH)); - if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`, `char_id` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) - Sql_ShowDebug(sql_handle); - else - if ( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char *data; - Sql_GetData(sql_handle, 0, &data, NULL); - if (atoi(data) != account_id) - { // Cannot send mail to char in the same account - Sql_GetData(sql_handle, 1, &data, NULL); - msg.dest_id = atoi(data); - } - } - Sql_FreeResult(sql_handle); - msg.status = MAIL_NEW; - - if( msg.dest_id > 0 ) - msg.id = mail_savemessage(&msg); - - mapif_Mail_send(fd, &msg); // notify sender - mapif_Mail_new(&msg); // notify recipient + struct mail_message msg; + char esc_name[NAME_LENGTH*2+1]; + int account_id = 0; + + if (RFIFOW(fd,2) != 8 + sizeof(struct mail_message)) + return; + + account_id = RFIFOL(fd,4); + memcpy(&msg, RFIFOP(fd,8), sizeof(struct mail_message)); + + // Try to find the Dest Char by Name + Sql_EscapeStringLen(sql_handle, esc_name, msg.dest_name, strnlen(msg.dest_name, NAME_LENGTH)); + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`, `char_id` FROM `%s` WHERE `name` = '%s'", char_db, esc_name)) + Sql_ShowDebug(sql_handle); + else if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + char *data; + Sql_GetData(sql_handle, 0, &data, NULL); + if (atoi(data) != account_id) { + // Cannot send mail to char in the same account + Sql_GetData(sql_handle, 1, &data, NULL); + msg.dest_id = atoi(data); + } + } + Sql_FreeResult(sql_handle); + msg.status = MAIL_NEW; + + if (msg.dest_id > 0) + msg.id = mail_savemessage(&msg); + + mapif_Mail_send(fd, &msg); // notify sender + mapif_Mail_new(&msg); // notify recipient } -void mail_sendmail(int send_id, const char* send_name, int dest_id, const char* dest_name, const char* title, const char* body, int zeny, struct item *item) +void mail_sendmail(int send_id, const char *send_name, int dest_id, const char *dest_name, const char *title, const char *body, int zeny, struct item *item) { - struct mail_message msg; - memset(&msg, 0, sizeof(struct mail_message)); - - msg.send_id = send_id; - safestrncpy(msg.send_name, send_name, NAME_LENGTH); - msg.dest_id = dest_id; - safestrncpy(msg.dest_name, dest_name, NAME_LENGTH); - safestrncpy(msg.title, title, MAIL_TITLE_LENGTH); - safestrncpy(msg.body, body, MAIL_BODY_LENGTH); - msg.zeny = zeny; - if( item != NULL ) - memcpy(&msg.item, item, sizeof(struct item)); - - msg.timestamp = time(NULL); - - mail_savemessage(&msg); - mapif_Mail_new(&msg); + struct mail_message msg; + memset(&msg, 0, sizeof(struct mail_message)); + + msg.send_id = send_id; + safestrncpy(msg.send_name, send_name, NAME_LENGTH); + msg.dest_id = dest_id; + safestrncpy(msg.dest_name, dest_name, NAME_LENGTH); + safestrncpy(msg.title, title, MAIL_TITLE_LENGTH); + safestrncpy(msg.body, body, MAIL_BODY_LENGTH); + msg.zeny = zeny; + if (item != NULL) + memcpy(&msg.item, item, sizeof(struct item)); + + msg.timestamp = time(NULL); + + mail_savemessage(&msg); + mapif_Mail_new(&msg); } /*========================================== @@ -452,26 +466,37 @@ void mail_sendmail(int send_id, const char* send_name, int dest_id, const char* *------------------------------------------*/ int inter_mail_parse_frommap(int fd) { - switch(RFIFOW(fd,0)) - { - case 0x3048: mapif_parse_Mail_requestinbox(fd); break; - case 0x3049: mapif_parse_Mail_read(fd); break; - case 0x304a: mapif_parse_Mail_getattach(fd); break; - case 0x304b: mapif_parse_Mail_delete(fd); break; - case 0x304c: mapif_parse_Mail_return(fd); break; - case 0x304d: mapif_parse_Mail_send(fd); break; - default: - return 0; - } - return 1; + switch (RFIFOW(fd,0)) { + case 0x3048: + mapif_parse_Mail_requestinbox(fd); + break; + case 0x3049: + mapif_parse_Mail_read(fd); + break; + case 0x304a: + mapif_parse_Mail_getattach(fd); + break; + case 0x304b: + mapif_parse_Mail_delete(fd); + break; + case 0x304c: + mapif_parse_Mail_return(fd); + break; + case 0x304d: + mapif_parse_Mail_send(fd); + break; + default: + return 0; + } + return 1; } int inter_mail_sql_init(void) { - return 1; + return 1; } void inter_mail_sql_final(void) { - return; + return; } diff --git a/src/char/int_mail.h b/src/char/int_mail.h index 77db51e5b..0fef3d4ab 100644 --- a/src/char/int_mail.h +++ b/src/char/int_mail.h @@ -5,12 +5,12 @@ #define _INT_MAIL_SQL_H_ int inter_mail_parse_frommap(int fd); -void mail_sendmail(int send_id, const char* send_name, int dest_id, const char* dest_name, const char* title, const char* body, int zeny, struct item *item); +void mail_sendmail(int send_id, const char *send_name, int dest_id, const char *dest_name, const char *title, const char *body, int zeny, struct item *item); int inter_mail_sql_init(void); void inter_mail_sql_final(void); -int mail_savemessage(struct mail_message* msg); +int mail_savemessage(struct mail_message *msg); void mapif_Mail_new(struct mail_message *msg); #endif /* _INT_MAIL_SQL_H_ */ diff --git a/src/char/int_mercenary.c b/src/char/int_mercenary.c index 3b3714416..528f05524 100644 --- a/src/char/int_mercenary.c +++ b/src/char/int_mercenary.c @@ -17,185 +17,188 @@ bool mercenary_owner_fromsql(int char_id, struct mmo_charstatus *status) { - char* data; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith` FROM `%s` WHERE `char_id` = '%d'", mercenary_owner_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_FreeResult(sql_handle); - return false; - } - - Sql_GetData(sql_handle, 0, &data, NULL); status->mer_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); status->arch_calls = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); status->arch_faith = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); status->spear_calls = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); status->spear_faith = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); status->sword_calls = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); status->sword_faith = atoi(data); - Sql_FreeResult(sql_handle); - - return true; + char *data; + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith` FROM `%s` WHERE `char_id` = '%d'", mercenary_owner_db, char_id)) { + Sql_ShowDebug(sql_handle); + return false; + } + + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { + Sql_FreeResult(sql_handle); + return false; + } + + Sql_GetData(sql_handle, 0, &data, NULL); + status->mer_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + status->arch_calls = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + status->arch_faith = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + status->spear_calls = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + status->spear_faith = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + status->sword_calls = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + status->sword_faith = atoi(data); + Sql_FreeResult(sql_handle); + + return true; } bool mercenary_owner_tosql(int char_id, struct mmo_charstatus *status) { - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`char_id`, `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith`) VALUES ('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - mercenary_owner_db, char_id, status->mer_id, status->arch_calls, status->arch_faith, status->spear_calls, status->spear_faith, status->sword_calls, status->sword_faith) ) - { - Sql_ShowDebug(sql_handle); - return false; - } + if (SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`char_id`, `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith`) VALUES ('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", + mercenary_owner_db, char_id, status->mer_id, status->arch_calls, status->arch_faith, status->spear_calls, status->spear_faith, status->sword_calls, status->sword_faith)) { + Sql_ShowDebug(sql_handle); + return false; + } - return true; + return true; } bool mercenary_owner_delete(int char_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", mercenary_owner_db, char_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", mercenary_owner_db, char_id)) + Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", mercenary_db, char_id) ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", mercenary_db, char_id)) + Sql_ShowDebug(sql_handle); - return true; + return true; } -bool mapif_mercenary_save(struct s_mercenary* merc) +bool mapif_mercenary_save(struct s_mercenary *merc) { - bool flag = true; + bool flag = true; - if( merc->mercenary_id == 0 ) - { // Create new DB entry - if( SQL_ERROR == Sql_Query(sql_handle, - "INSERT INTO `%s` (`char_id`,`class`,`hp`,`sp`,`kill_counter`,`life_time`) VALUES ('%d','%d','%d','%d','%u','%u')", - mercenary_db, merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time) ) - { - Sql_ShowDebug(sql_handle); - flag = false; - } - else - merc->mercenary_id = (int)Sql_LastInsertId(sql_handle); - } - else if( SQL_ERROR == Sql_Query(sql_handle, - "UPDATE `%s` SET `char_id` = '%d', `class` = '%d', `hp` = '%d', `sp` = '%d', `kill_counter` = '%u', `life_time` = '%u' WHERE `mer_id` = '%d'", - mercenary_db, merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time, merc->mercenary_id) ) - { // Update DB entry - Sql_ShowDebug(sql_handle); - flag = false; - } + if (merc->mercenary_id == 0) { + // Create new DB entry + if (SQL_ERROR == Sql_Query(sql_handle, + "INSERT INTO `%s` (`char_id`,`class`,`hp`,`sp`,`kill_counter`,`life_time`) VALUES ('%d','%d','%d','%d','%u','%u')", + mercenary_db, merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time)) { + Sql_ShowDebug(sql_handle); + flag = false; + } else + merc->mercenary_id = (int)Sql_LastInsertId(sql_handle); + } else if (SQL_ERROR == Sql_Query(sql_handle, + "UPDATE `%s` SET `char_id` = '%d', `class` = '%d', `hp` = '%d', `sp` = '%d', `kill_counter` = '%u', `life_time` = '%u' WHERE `mer_id` = '%d'", + mercenary_db, merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time, merc->mercenary_id)) { + // Update DB entry + Sql_ShowDebug(sql_handle); + flag = false; + } - return flag; + return flag; } bool mapif_mercenary_load(int merc_id, int char_id, struct s_mercenary *merc) { - char* data; + char *data; + + memset(merc, 0, sizeof(struct s_mercenary)); + merc->mercenary_id = merc_id; + merc->char_id = char_id; - memset(merc, 0, sizeof(struct s_mercenary)); - merc->mercenary_id = merc_id; - merc->char_id = char_id; + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `class`, `hp`, `sp`, `kill_counter`, `life_time` FROM `%s` WHERE `mer_id` = '%d' AND `char_id` = '%d'", mercenary_db, merc_id, char_id)) { + Sql_ShowDebug(sql_handle); + return false; + } - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `class`, `hp`, `sp`, `kill_counter`, `life_time` FROM `%s` WHERE `mer_id` = '%d' AND `char_id` = '%d'", mercenary_db, merc_id, char_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { + Sql_FreeResult(sql_handle); + return false; + } - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_FreeResult(sql_handle); - return false; - } + Sql_GetData(sql_handle, 0, &data, NULL); + merc->class_ = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + merc->hp = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + merc->sp = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + merc->kill_count = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + merc->life_time = atoi(data); + Sql_FreeResult(sql_handle); + if (save_log) + ShowInfo("Mercenary loaded (%d - %d).\n", merc->mercenary_id, merc->char_id); - Sql_GetData(sql_handle, 0, &data, NULL); merc->class_ = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); merc->hp = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); merc->sp = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); merc->kill_count = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); merc->life_time = atoi(data); - Sql_FreeResult(sql_handle); - if( save_log ) - ShowInfo("Mercenary loaded (%d - %d).\n", merc->mercenary_id, merc->char_id); - - return true; + return true; } bool mapif_mercenary_delete(int merc_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `mer_id` = '%d'", mercenary_db, merc_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `mer_id` = '%d'", mercenary_db, merc_id)) { + Sql_ShowDebug(sql_handle); + return false; + } - return true; + return true; } static void mapif_mercenary_send(int fd, struct s_mercenary *merc, unsigned char flag) { - int size = sizeof(struct s_mercenary) + 5; + int size = sizeof(struct s_mercenary) + 5; - WFIFOHEAD(fd,size); - WFIFOW(fd,0) = 0x3870; - WFIFOW(fd,2) = size; - WFIFOB(fd,4) = flag; - memcpy(WFIFOP(fd,5),merc,sizeof(struct s_mercenary)); - WFIFOSET(fd,size); + WFIFOHEAD(fd,size); + WFIFOW(fd,0) = 0x3870; + WFIFOW(fd,2) = size; + WFIFOB(fd,4) = flag; + memcpy(WFIFOP(fd,5),merc,sizeof(struct s_mercenary)); + WFIFOSET(fd,size); } -static void mapif_parse_mercenary_create(int fd, struct s_mercenary* merc) +static void mapif_parse_mercenary_create(int fd, struct s_mercenary *merc) { - bool result = mapif_mercenary_save(merc); - mapif_mercenary_send(fd, merc, result); + bool result = mapif_mercenary_save(merc); + mapif_mercenary_send(fd, merc, result); } static void mapif_parse_mercenary_load(int fd, int merc_id, int char_id) { - struct s_mercenary merc; - bool result = mapif_mercenary_load(merc_id, char_id, &merc); - mapif_mercenary_send(fd, &merc, result); + struct s_mercenary merc; + bool result = mapif_mercenary_load(merc_id, char_id, &merc); + mapif_mercenary_send(fd, &merc, result); } static void mapif_mercenary_deleted(int fd, unsigned char flag) { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x3871; - WFIFOB(fd,2) = flag; - WFIFOSET(fd,3); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x3871; + WFIFOB(fd,2) = flag; + WFIFOSET(fd,3); } static void mapif_parse_mercenary_delete(int fd, int merc_id) { - bool result = mapif_mercenary_delete(merc_id); - mapif_mercenary_deleted(fd, result); + bool result = mapif_mercenary_delete(merc_id); + mapif_mercenary_deleted(fd, result); } static void mapif_mercenary_saved(int fd, unsigned char flag) { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x3872; - WFIFOB(fd,2) = flag; - WFIFOSET(fd,3); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x3872; + WFIFOB(fd,2) = flag; + WFIFOSET(fd,3); } -static void mapif_parse_mercenary_save(int fd, struct s_mercenary* merc) +static void mapif_parse_mercenary_save(int fd, struct s_mercenary *merc) { - bool result = mapif_mercenary_save(merc); - mapif_mercenary_saved(fd, result); + bool result = mapif_mercenary_save(merc); + mapif_mercenary_saved(fd, result); } int inter_mercenary_sql_init(void) { - return 0; + return 0; } void inter_mercenary_sql_final(void) { - return; + return; } /*========================================== @@ -203,16 +206,23 @@ void inter_mercenary_sql_final(void) *------------------------------------------*/ int inter_mercenary_parse_frommap(int fd) { - unsigned short cmd = RFIFOW(fd,0); - - switch( cmd ) - { - case 0x3070: mapif_parse_mercenary_create(fd, (struct s_mercenary*)RFIFOP(fd,4)); break; - case 0x3071: mapif_parse_mercenary_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); break; - case 0x3072: mapif_parse_mercenary_delete(fd, (int)RFIFOL(fd,2)); break; - case 0x3073: mapif_parse_mercenary_save(fd, (struct s_mercenary*)RFIFOP(fd,4)); break; - default: - return 0; - } - return 1; + unsigned short cmd = RFIFOW(fd,0); + + switch (cmd) { + case 0x3070: + mapif_parse_mercenary_create(fd, (struct s_mercenary *)RFIFOP(fd,4)); + break; + case 0x3071: + mapif_parse_mercenary_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); + break; + case 0x3072: + mapif_parse_mercenary_delete(fd, (int)RFIFOL(fd,2)); + break; + case 0x3073: + mapif_parse_mercenary_save(fd, (struct s_mercenary *)RFIFOP(fd,4)); + break; + default: + return 0; + } + return 1; } diff --git a/src/char/int_party.c b/src/char/int_party.c index a88e5c586..862a943f1 100644 --- a/src/char/int_party.c +++ b/src/char/int_party.c @@ -19,14 +19,14 @@ #include struct party_data { - struct party party; - unsigned int min_lv, max_lv; - int family; //Is this party a family? if so, this holds the child id. - unsigned char size; //Total size of party. + struct party party; + unsigned int min_lv, max_lv; + int family; //Is this party a family? if so, this holds the child id. + unsigned char size; //Total size of party. }; static struct party_data *party_pt; -static DBMap* party_db_; // int party_id -> struct party_data* +static DBMap *party_db_; // int party_id -> struct party_data* int mapif_party_broken(int party_id,int flag); int party_check_empty(struct party_data *p); @@ -35,292 +35,297 @@ int party_check_exp_share(struct party_data *p); int mapif_party_optionchanged(int fd,struct party *p, int account_id, int flag); //Updates party's level range and unsets even share if broken. -static int int_party_check_lv(struct party_data *p) { - int i; - unsigned int lv; - p->min_lv = UINT_MAX; - p->max_lv = 0; - for(i=0;iparty.member[i].online || p->party.member[i].char_id == p->family ) - continue; - - lv=p->party.member[i].lv; - if (lv < p->min_lv) p->min_lv = lv; - if (lv > p->max_lv) p->max_lv = lv; - } - - if (p->party.exp && !party_check_exp_share(p)) { - p->party.exp = 0; - mapif_party_optionchanged(0, &p->party, 0, 0); - return 0; - } - return 1; +static int int_party_check_lv(struct party_data *p) +{ + int i; + unsigned int lv; + p->min_lv = UINT_MAX; + p->max_lv = 0; + for (i=0; iparty.member[i].online || p->party.member[i].char_id == p->family) + continue; + + lv=p->party.member[i].lv; + if (lv < p->min_lv) p->min_lv = lv; + if (lv > p->max_lv) p->max_lv = lv; + } + + if (p->party.exp && !party_check_exp_share(p)) { + p->party.exp = 0; + mapif_party_optionchanged(0, &p->party, 0, 0); + return 0; + } + return 1; } //Calculates the state of a party. static void int_party_calc_state(struct party_data *p) { - int i; - unsigned int lv; - p->min_lv = UINT_MAX; - p->max_lv = 0; - p->party.count = - p->size = - p->family = 0; - - //Check party size - for(i=0;iparty.member[i].lv) continue; - p->size++; - if(p->party.member[i].online) - p->party.count++; - } - if( p->size == 2 && ( char_child(p->party.member[0].char_id,p->party.member[1].char_id) || char_child(p->party.member[1].char_id,p->party.member[0].char_id) ) ) { - //Child should be able to share with either of their parents [RoM] - if(p->party.member[0].class_&0x2000) //first slot is the child? - p->family = p->party.member[0].char_id; - else - p->family = p->party.member[1].char_id; - } else if( p->size == 3 ) { - //Check Family State. - p->family = char_family( - p->party.member[0].char_id, - p->party.member[1].char_id, - p->party.member[2].char_id - ); - } - //max/min levels. - for(i=0;iparty.member[i].lv; - if (!lv) continue; - if(p->party.member[i].online && - //On families, the kid is not counted towards exp share rules. - p->party.member[i].char_id != p->family) - { - if( lv < p->min_lv ) p->min_lv=lv; - if( p->max_lv < lv ) p->max_lv=lv; - } - } - - if (p->party.exp && !party_check_exp_share(p)) { - p->party.exp = 0; //Set off even share. - mapif_party_optionchanged(0, &p->party, 0, 0); - } - return; + int i; + unsigned int lv; + p->min_lv = UINT_MAX; + p->max_lv = 0; + p->party.count = + p->size = + p->family = 0; + + //Check party size + for (i=0; iparty.member[i].lv) continue; + p->size++; + if (p->party.member[i].online) + p->party.count++; + } + if (p->size == 2 && (char_child(p->party.member[0].char_id,p->party.member[1].char_id) || char_child(p->party.member[1].char_id,p->party.member[0].char_id))) { + //Child should be able to share with either of their parents [RoM] + if (p->party.member[0].class_&0x2000) //first slot is the child? + p->family = p->party.member[0].char_id; + else + p->family = p->party.member[1].char_id; + } else if (p->size == 3) { + //Check Family State. + p->family = char_family( + p->party.member[0].char_id, + p->party.member[1].char_id, + p->party.member[2].char_id + ); + } + //max/min levels. + for (i=0; iparty.member[i].lv; + if (!lv) continue; + if (p->party.member[i].online && + //On families, the kid is not counted towards exp share rules. + p->party.member[i].char_id != p->family) { + if (lv < p->min_lv) p->min_lv=lv; + if (p->max_lv < lv) p->max_lv=lv; + } + } + + if (p->party.exp && !party_check_exp_share(p)) { + p->party.exp = 0; //Set off even share. + mapif_party_optionchanged(0, &p->party, 0, 0); + } + return; } // Save party to mysql int inter_party_tosql(struct party *p, int flag, int index) { - // 'party' ('party_id','name','exp','item','leader_id','leader_char') - char esc_name[NAME_LENGTH*2+1];// escaped party name - int party_id; + // 'party' ('party_id','name','exp','item','leader_id','leader_char') + char esc_name[NAME_LENGTH*2+1];// escaped party name + int party_id; - if( p == NULL || p->party_id == 0 ) - return 0; - party_id = p->party_id; + if (p == NULL || p->party_id == 0) + return 0; + party_id = p->party_id; #ifdef NOISY - ShowInfo("Save party request ("CL_BOLD"%d"CL_RESET" - %s).\n", party_id, p->name); + ShowInfo("Save party request ("CL_BOLD"%d"CL_RESET" - %s).\n", party_id, p->name); #endif - Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); - - if( flag & PS_BREAK ) - {// Break the party - // we'll skip name-checking and just reset everyone with the same party id [celest] - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `party_id`='%d'", party_db, party_id) ) - Sql_ShowDebug(sql_handle); - //Remove from memory - idb_remove(party_db_, party_id); - return 1; - } - - if( flag & PS_CREATE ) - {// Create party - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " - "(`name`, `exp`, `item`, `leader_id`, `leader_char`) " - "VALUES ('%s', '%d', '%d', '%d', '%d')", - party_db, esc_name, p->exp, p->item, p->member[index].account_id, p->member[index].char_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - party_id = p->party_id = (int)Sql_LastInsertId(sql_handle); - } - - if( flag & PS_BASIC ) - {// Update party info. - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name`='%s', `exp`='%d', `item`='%d' WHERE `party_id`='%d'", - party_db, esc_name, p->exp, p->item, party_id) ) - Sql_ShowDebug(sql_handle); - } - - if( flag & PS_LEADER ) - {// Update leader - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `leader_id`='%d', `leader_char`='%d' WHERE `party_id`='%d'", - party_db, p->member[index].account_id, p->member[index].char_id, party_id) ) - Sql_ShowDebug(sql_handle); - } - - if( flag & PS_ADDMEMBER ) - {// Add one party member. - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='%d' WHERE `account_id`='%d' AND `char_id`='%d'", - char_db, party_id, p->member[index].account_id, p->member[index].char_id) ) - Sql_ShowDebug(sql_handle); - } - - if( flag & PS_DELMEMBER ) - {// Remove one party member. - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d' AND `account_id`='%d' AND `char_id`='%d'", - char_db, party_id, p->member[index].account_id, p->member[index].char_id) ) - Sql_ShowDebug(sql_handle); - } - - if( save_log ) - ShowInfo("Party Saved (%d - %s)\n", party_id, p->name); - return 1; + Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); + + if (flag & PS_BREAK) { + // Break the party + // we'll skip name-checking and just reset everyone with the same party id [celest] + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id)) + Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `party_id`='%d'", party_db, party_id)) + Sql_ShowDebug(sql_handle); + //Remove from memory + idb_remove(party_db_, party_id); + return 1; + } + + if (flag & PS_CREATE) { + // Create party + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " + "(`name`, `exp`, `item`, `leader_id`, `leader_char`) " + "VALUES ('%s', '%d', '%d', '%d', '%d')", + party_db, esc_name, p->exp, p->item, p->member[index].account_id, p->member[index].char_id)) { + Sql_ShowDebug(sql_handle); + return 0; + } + party_id = p->party_id = (int)Sql_LastInsertId(sql_handle); + } + + if (flag & PS_BASIC) { + // Update party info. + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name`='%s', `exp`='%d', `item`='%d' WHERE `party_id`='%d'", + party_db, esc_name, p->exp, p->item, party_id)) + Sql_ShowDebug(sql_handle); + } + + if (flag & PS_LEADER) { + // Update leader + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `leader_id`='%d', `leader_char`='%d' WHERE `party_id`='%d'", + party_db, p->member[index].account_id, p->member[index].char_id, party_id)) + Sql_ShowDebug(sql_handle); + } + + if (flag & PS_ADDMEMBER) { + // Add one party member. + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='%d' WHERE `account_id`='%d' AND `char_id`='%d'", + char_db, party_id, p->member[index].account_id, p->member[index].char_id)) + Sql_ShowDebug(sql_handle); + } + + if (flag & PS_DELMEMBER) { + // Remove one party member. + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d' AND `account_id`='%d' AND `char_id`='%d'", + char_db, party_id, p->member[index].account_id, p->member[index].char_id)) + Sql_ShowDebug(sql_handle); + } + + if (save_log) + ShowInfo("Party Saved (%d - %s)\n", party_id, p->name); + return 1; } // Read party from mysql -struct party_data *inter_party_fromsql(int party_id) -{ - int leader_id = 0; - int leader_char = 0; - struct party_data* p; - struct party_member* m; - char* data; - size_t len; - int i; +struct party_data *inter_party_fromsql(int party_id) { + int leader_id = 0; + int leader_char = 0; + struct party_data *p; + struct party_member *m; + char *data; + size_t len; + int i; #ifdef NOISY - ShowInfo("Load party request ("CL_BOLD"%d"CL_RESET")\n", party_id); + ShowInfo("Load party request ("CL_BOLD"%d"CL_RESET")\n", party_id); #endif - if( party_id <= 0 ) - return NULL; - - //Load from memory - p = (struct party_data*)idb_get(party_db_, party_id); - if( p != NULL ) - return p; - - p = party_pt; - memset(p, 0, sizeof(struct party_data)); - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id`, `name`,`exp`,`item`, `leader_id`, `leader_char` FROM `%s` WHERE `party_id`='%d'", party_db, party_id) ) - { - Sql_ShowDebug(sql_handle); - return NULL; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - return NULL; - - p->party.party_id = party_id; - Sql_GetData(sql_handle, 1, &data, &len); memcpy(p->party.name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 2, &data, NULL); p->party.exp = (atoi(data) ? 1 : 0); - Sql_GetData(sql_handle, 3, &data, NULL); p->party.item = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); leader_id = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); leader_char = atoi(data); - Sql_FreeResult(sql_handle); - - // Load members - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`name`,`base_level`,`last_map`,`online`,`class` FROM `%s` WHERE `party_id`='%d'", char_db, party_id) ) - { - Sql_ShowDebug(sql_handle); - return NULL; - } - for( i = 0; i < MAX_PARTY && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - m = &p->party.member[i]; - Sql_GetData(sql_handle, 0, &data, NULL); m->account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); m->char_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, &len); memcpy(m->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 3, &data, NULL); m->lv = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); m->map = mapindex_name2id(data); - Sql_GetData(sql_handle, 5, &data, NULL); m->online = (atoi(data) ? 1 : 0); - Sql_GetData(sql_handle, 6, &data, NULL); m->class_ = atoi(data); - m->leader = (m->account_id == leader_id && m->char_id == leader_char ? 1 : 0); - } - Sql_FreeResult(sql_handle); - - if( save_log ) - ShowInfo("Party loaded (%d - %s).\n", party_id, p->party.name); - //Add party to memory. - CREATE(p, struct party_data, 1); - memcpy(p, party_pt, sizeof(struct party_data)); - //init state - int_party_calc_state(p); - idb_put(party_db_, party_id, p); - return p; + if (party_id <= 0) + return NULL; + + //Load from memory + p = (struct party_data *)idb_get(party_db_, party_id); + if (p != NULL) + return p; + + p = party_pt; + memset(p, 0, sizeof(struct party_data)); + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id`, `name`,`exp`,`item`, `leader_id`, `leader_char` FROM `%s` WHERE `party_id`='%d'", party_db, party_id)) { + Sql_ShowDebug(sql_handle); + return NULL; + } + + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) + return NULL; + + p->party.party_id = party_id; + Sql_GetData(sql_handle, 1, &data, &len); + memcpy(p->party.name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 2, &data, NULL); + p->party.exp = (atoi(data) ? 1 : 0); + Sql_GetData(sql_handle, 3, &data, NULL); + p->party.item = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + leader_id = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + leader_char = atoi(data); + Sql_FreeResult(sql_handle); + + // Load members + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`name`,`base_level`,`last_map`,`online`,`class` FROM `%s` WHERE `party_id`='%d'", char_db, party_id)) { + Sql_ShowDebug(sql_handle); + return NULL; + } + for (i = 0; i < MAX_PARTY && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + m = &p->party.member[i]; + Sql_GetData(sql_handle, 0, &data, NULL); + m->account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + m->char_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(m->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 3, &data, NULL); + m->lv = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + m->map = mapindex_name2id(data); + Sql_GetData(sql_handle, 5, &data, NULL); + m->online = (atoi(data) ? 1 : 0); + Sql_GetData(sql_handle, 6, &data, NULL); + m->class_ = atoi(data); + m->leader = (m->account_id == leader_id && m->char_id == leader_char ? 1 : 0); + } + Sql_FreeResult(sql_handle); + + if (save_log) + ShowInfo("Party loaded (%d - %s).\n", party_id, p->party.name); + //Add party to memory. + CREATE(p, struct party_data, 1); + memcpy(p, party_pt, sizeof(struct party_data)); + //init state + int_party_calc_state(p); + idb_put(party_db_, party_id, p); + return p; } int inter_party_sql_init(void) { - //memory alloc - party_db_ = idb_alloc(DB_OPT_RELEASE_DATA); - party_pt = (struct party_data*)aCalloc(sizeof(struct party_data), 1); - if (!party_pt) { - ShowFatalError("inter_party_sql_init: Out of Memory!\n"); - exit(EXIT_FAILURE); - } - - /* Uncomment the following if you want to do a party_db cleanup (remove parties with no members) on startup.[Skotlex] - ShowStatus("cleaning party table...\n"); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` LEFT JOIN `%s` ON `%s`.leader_id =`%s`.account_id AND `%s`.leader_char = `%s`.char_id WHERE `%s`.account_id IS NULL", - party_db, party_db, char_db, party_db, char_db, party_db, char_db, char_db) ) - Sql_ShowDebug(sql_handle); - */ - return 0; + //memory alloc + party_db_ = idb_alloc(DB_OPT_RELEASE_DATA); + party_pt = (struct party_data *)aCalloc(sizeof(struct party_data), 1); + if (!party_pt) { + ShowFatalError("inter_party_sql_init: Out of Memory!\n"); + exit(EXIT_FAILURE); + } + + /* Uncomment the following if you want to do a party_db cleanup (remove parties with no members) on startup.[Skotlex] + ShowStatus("cleaning party table...\n"); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` LEFT JOIN `%s` ON `%s`.leader_id =`%s`.account_id AND `%s`.leader_char = `%s`.char_id WHERE `%s`.account_id IS NULL", + party_db, party_db, char_db, party_db, char_db, party_db, char_db, char_db) ) + Sql_ShowDebug(sql_handle); + */ + return 0; } void inter_party_sql_final(void) { - party_db_->destroy(party_db_, NULL); - aFree(party_pt); - return; + party_db_->destroy(party_db_, NULL); + aFree(party_pt); + return; } // Search for the party according to its name -struct party_data* search_partyname(char* str) -{ - char esc_name[NAME_LENGTH*2+1]; - char* data; - struct party_data* p = NULL; - - Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id` FROM `%s` WHERE `name`='%s'", party_db, esc_name) ) - Sql_ShowDebug(sql_handle); - else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - Sql_GetData(sql_handle, 0, &data, NULL); - p = inter_party_fromsql(atoi(data)); - } - Sql_FreeResult(sql_handle); - - return p; +struct party_data *search_partyname(char *str) { + char esc_name[NAME_LENGTH*2+1]; + char *data; + struct party_data *p = NULL; + + Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH)); + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id` FROM `%s` WHERE `name`='%s'", party_db, esc_name)) + Sql_ShowDebug(sql_handle); + else if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + Sql_GetData(sql_handle, 0, &data, NULL); + p = inter_party_fromsql(atoi(data)); + } + Sql_FreeResult(sql_handle); + + return p; } // Returns whether this party can keep having exp share or not. int party_check_exp_share(struct party_data *p) { - return (p->party.count < 2 || p->max_lv - p->min_lv <= party_share_level); + return (p->party.count < 2 || p->max_lv - p->min_lv <= party_share_level); } // Is there any member in the party? int party_check_empty(struct party_data *p) { - int i; - if (p==NULL||p->party.party_id==0) return 1; - for(i=0;iparty.member[i].account_id;i++); - if (i < MAX_PARTY) return 0; - // If there is no member, then break the party - mapif_party_broken(p->party.party_id,0); - inter_party_tosql(&p->party, PS_BREAK, 0); - return 1; + int i; + if (p==NULL||p->party.party_id==0) return 1; + for (i=0; iparty.member[i].account_id; i++); + if (i < MAX_PARTY) return 0; + // If there is no member, then break the party + mapif_party_broken(p->party.party_id,0); + inter_party_tosql(&p->party, PS_BREAK, 0); + return 1; } //------------------------------------------------------------------- @@ -330,133 +335,135 @@ int party_check_empty(struct party_data *p) // Create a party whether or not int mapif_party_created(int fd,int account_id,int char_id,struct party *p) { - WFIFOHEAD(fd, 39); - WFIFOW(fd,0)=0x3820; - WFIFOL(fd,2)=account_id; - WFIFOL(fd,6)=char_id; - if(p!=NULL){ - WFIFOB(fd,10)=0; - WFIFOL(fd,11)=p->party_id; - memcpy(WFIFOP(fd,15),p->name,NAME_LENGTH); - ShowInfo("int_party: Party created (%d - %s)\n",p->party_id,p->name); - }else{ - WFIFOB(fd,10)=1; - WFIFOL(fd,11)=0; - memset(WFIFOP(fd,15),0,NAME_LENGTH); - } - WFIFOSET(fd,39); - - return 0; + WFIFOHEAD(fd, 39); + WFIFOW(fd,0)=0x3820; + WFIFOL(fd,2)=account_id; + WFIFOL(fd,6)=char_id; + if (p!=NULL) { + WFIFOB(fd,10)=0; + WFIFOL(fd,11)=p->party_id; + memcpy(WFIFOP(fd,15),p->name,NAME_LENGTH); + ShowInfo("int_party: Party created (%d - %s)\n",p->party_id,p->name); + } else { + WFIFOB(fd,10)=1; + WFIFOL(fd,11)=0; + memset(WFIFOP(fd,15),0,NAME_LENGTH); + } + WFIFOSET(fd,39); + + return 0; } //Party information not found static void mapif_party_noinfo(int fd, int party_id, int char_id) { - WFIFOHEAD(fd, 12); - WFIFOW(fd,0) = 0x3821; - WFIFOW(fd,2) = 12; - WFIFOL(fd,4) = char_id; - WFIFOL(fd,8) = party_id; - WFIFOSET(fd,12); - ShowWarning("int_party: info not found (party_id=%d char_id=%d)\n", party_id, char_id); + WFIFOHEAD(fd, 12); + WFIFOW(fd,0) = 0x3821; + WFIFOW(fd,2) = 12; + WFIFOL(fd,4) = char_id; + WFIFOL(fd,8) = party_id; + WFIFOSET(fd,12); + ShowWarning("int_party: info not found (party_id=%d char_id=%d)\n", party_id, char_id); } //Digest party information -static void mapif_party_info(int fd, struct party* p, int char_id) +static void mapif_party_info(int fd, struct party *p, int char_id) { - unsigned char buf[8 + sizeof(struct party)]; - WBUFW(buf,0) = 0x3821; - WBUFW(buf,2) = 8 + sizeof(struct party); - WBUFL(buf,4) = char_id; - memcpy(WBUFP(buf,8), p, sizeof(struct party)); - - if(fd<0) - mapif_sendall(buf,WBUFW(buf,2)); - else - mapif_send(fd,buf,WBUFW(buf,2)); + unsigned char buf[8 + sizeof(struct party)]; + WBUFW(buf,0) = 0x3821; + WBUFW(buf,2) = 8 + sizeof(struct party); + WBUFL(buf,4) = char_id; + memcpy(WBUFP(buf,8), p, sizeof(struct party)); + + if (fd<0) + mapif_sendall(buf,WBUFW(buf,2)); + else + mapif_send(fd,buf,WBUFW(buf,2)); } //Whether or not additional party members -int mapif_party_memberadded(int fd, int party_id, int account_id, int char_id, int flag) { - WFIFOHEAD(fd, 15); - WFIFOW(fd,0) = 0x3822; - WFIFOL(fd,2) = party_id; - WFIFOL(fd,6) = account_id; - WFIFOL(fd,10) = char_id; - WFIFOB(fd,14) = flag; - WFIFOSET(fd,15); - - return 0; +int mapif_party_memberadded(int fd, int party_id, int account_id, int char_id, int flag) +{ + WFIFOHEAD(fd, 15); + WFIFOW(fd,0) = 0x3822; + WFIFOL(fd,2) = party_id; + WFIFOL(fd,6) = account_id; + WFIFOL(fd,10) = char_id; + WFIFOB(fd,14) = flag; + WFIFOSET(fd,15); + + return 0; } // Party setting change notification int mapif_party_optionchanged(int fd,struct party *p,int account_id,int flag) { - unsigned char buf[16]; - WBUFW(buf,0)=0x3823; - WBUFL(buf,2)=p->party_id; - WBUFL(buf,6)=account_id; - WBUFW(buf,10)=p->exp; - WBUFW(buf,12)=p->item; - WBUFB(buf,14)=flag; - if(flag==0) - mapif_sendall(buf,15); - else - mapif_send(fd,buf,15); - return 0; + unsigned char buf[16]; + WBUFW(buf,0)=0x3823; + WBUFL(buf,2)=p->party_id; + WBUFL(buf,6)=account_id; + WBUFW(buf,10)=p->exp; + WBUFW(buf,12)=p->item; + WBUFB(buf,14)=flag; + if (flag==0) + mapif_sendall(buf,15); + else + mapif_send(fd,buf,15); + return 0; } //Withdrawal notification party -int mapif_party_withdraw(int party_id,int account_id, int char_id) { - unsigned char buf[16]; - - WBUFW(buf,0) = 0x3824; - WBUFL(buf,2) = party_id; - WBUFL(buf,6) = account_id; - WBUFL(buf,10) = char_id; - mapif_sendall(buf, 14); - return 0; +int mapif_party_withdraw(int party_id,int account_id, int char_id) +{ + unsigned char buf[16]; + + WBUFW(buf,0) = 0x3824; + WBUFL(buf,2) = party_id; + WBUFL(buf,6) = account_id; + WBUFL(buf,10) = char_id; + mapif_sendall(buf, 14); + return 0; } //Party map update notification int mapif_party_membermoved(struct party *p,int idx) { - unsigned char buf[20]; - - WBUFW(buf,0) = 0x3825; - WBUFL(buf,2) = p->party_id; - WBUFL(buf,6) = p->member[idx].account_id; - WBUFL(buf,10) = p->member[idx].char_id; - WBUFW(buf,14) = p->member[idx].map; - WBUFB(buf,16) = p->member[idx].online; - WBUFW(buf,17) = p->member[idx].lv; - mapif_sendall(buf, 19); - return 0; + unsigned char buf[20]; + + WBUFW(buf,0) = 0x3825; + WBUFL(buf,2) = p->party_id; + WBUFL(buf,6) = p->member[idx].account_id; + WBUFL(buf,10) = p->member[idx].char_id; + WBUFW(buf,14) = p->member[idx].map; + WBUFB(buf,16) = p->member[idx].online; + WBUFW(buf,17) = p->member[idx].lv; + mapif_sendall(buf, 19); + return 0; } //Dissolution party notification int mapif_party_broken(int party_id,int flag) { - unsigned char buf[16]; - WBUFW(buf,0)=0x3826; - WBUFL(buf,2)=party_id; - WBUFB(buf,6)=flag; - mapif_sendall(buf,7); - //printf("int_party: broken %d\n",party_id); - return 0; + unsigned char buf[16]; + WBUFW(buf,0)=0x3826; + WBUFL(buf,2)=party_id; + WBUFB(buf,6)=flag; + mapif_sendall(buf,7); + //printf("int_party: broken %d\n",party_id); + return 0; } //Remarks in the party int mapif_party_message(int party_id,int account_id,char *mes,int len, int sfd) { - unsigned char buf[512]; - WBUFW(buf,0)=0x3827; - WBUFW(buf,2)=len+12; - WBUFL(buf,4)=party_id; - WBUFL(buf,8)=account_id; - memcpy(WBUFP(buf,12),mes,len); - mapif_sendallwos(sfd, buf,len+12); - return 0; + unsigned char buf[512]; + WBUFW(buf,0)=0x3827; + WBUFW(buf,2)=len+12; + WBUFL(buf,4)=party_id; + WBUFL(buf,8)=account_id; + memcpy(WBUFP(buf,12),mes,len); + mapif_sendallwos(sfd, buf,len+12); + return 0; } //------------------------------------------------------------------- @@ -466,273 +473,267 @@ int mapif_party_message(int party_id,int account_id,char *mes,int len, int sfd) // Create Party int mapif_parse_CreateParty(int fd, char *name, int item, int item2, struct party_member *leader) { - struct party_data *p; - int i; - if( (p=search_partyname(name))!=NULL){ - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - return 0; - } - // Check Authorised letters/symbols in the name of the character - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - return 0; - } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - return 0; - } - } - - p = (struct party_data*)aCalloc(1, sizeof(struct party_data)); - - memcpy(p->party.name,name,NAME_LENGTH); - p->party.exp=0; - p->party.item=(item?1:0)|(item2?2:0); - - memcpy(&p->party.member[0], leader, sizeof(struct party_member)); - p->party.member[0].leader=1; - p->party.member[0].online=1; - - p->party.party_id=-1;//New party. - if (inter_party_tosql(&p->party,PS_CREATE|PS_ADDMEMBER,0)) { - //Add party to db - int_party_calc_state(p); - idb_put(party_db_, p->party.party_id, p); - mapif_party_info(fd, &p->party, 0); - mapif_party_created(fd,leader->account_id,leader->char_id,&p->party); - } else { //Failed to create party. - aFree(p); - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - } - - return 0; + struct party_data *p; + int i; + if ((p=search_partyname(name))!=NULL) { + mapif_party_created(fd,leader->account_id,leader->char_id,NULL); + return 0; + } + // Check Authorised letters/symbols in the name of the character + if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) == NULL) { + mapif_party_created(fd,leader->account_id,leader->char_id,NULL); + return 0; + } + } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) != NULL) { + mapif_party_created(fd,leader->account_id,leader->char_id,NULL); + return 0; + } + } + + p = (struct party_data *)aCalloc(1, sizeof(struct party_data)); + + memcpy(p->party.name,name,NAME_LENGTH); + p->party.exp=0; + p->party.item=(item?1:0)|(item2?2:0); + + memcpy(&p->party.member[0], leader, sizeof(struct party_member)); + p->party.member[0].leader=1; + p->party.member[0].online=1; + + p->party.party_id=-1;//New party. + if (inter_party_tosql(&p->party,PS_CREATE|PS_ADDMEMBER,0)) { + //Add party to db + int_party_calc_state(p); + idb_put(party_db_, p->party.party_id, p); + mapif_party_info(fd, &p->party, 0); + mapif_party_created(fd,leader->account_id,leader->char_id,&p->party); + } else { //Failed to create party. + aFree(p); + mapif_party_created(fd,leader->account_id,leader->char_id,NULL); + } + + return 0; } // Party information request static void mapif_parse_PartyInfo(int fd, int party_id, int char_id) { - struct party_data *p; - p = inter_party_fromsql(party_id); + struct party_data *p; + p = inter_party_fromsql(party_id); - if (p) - mapif_party_info(fd, &p->party, char_id); - else - mapif_party_noinfo(fd, party_id, char_id); + if (p) + mapif_party_info(fd, &p->party, char_id); + else + mapif_party_noinfo(fd, party_id, char_id); } // Add a player to party request int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member) { - struct party_data *p; - int i; - - p = inter_party_fromsql(party_id); - if( p == NULL || p->size == MAX_PARTY ) { - mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); - return 0; - } - - ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == 0 ); - if( i == MAX_PARTY ) - {// Party full - mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); - return 0; - } - - memcpy(&p->party.member[i], member, sizeof(struct party_member)); - p->party.member[i].leader = 0; - if (p->party.member[i].online) p->party.count++; - p->size++; - if (p->size == 2 || p->size == 3) // Check family state. And also accept either of their Parents. [RoM] - int_party_calc_state(p); - else //Check even share range. - if (member->lv < p->min_lv || member->lv > p->max_lv || p->family) { - if (p->family) p->family = 0; //Family state broken. - int_party_check_lv(p); - } - - mapif_party_info(-1, &p->party, 0); - mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 0); - inter_party_tosql(&p->party, PS_ADDMEMBER, i); - - return 0; + struct party_data *p; + int i; + + p = inter_party_fromsql(party_id); + if (p == NULL || p->size == MAX_PARTY) { + mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); + return 0; + } + + ARR_FIND(0, MAX_PARTY, i, p->party.member[i].account_id == 0); + if (i == MAX_PARTY) { + // Party full + mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); + return 0; + } + + memcpy(&p->party.member[i], member, sizeof(struct party_member)); + p->party.member[i].leader = 0; + if (p->party.member[i].online) p->party.count++; + p->size++; + if (p->size == 2 || p->size == 3) // Check family state. And also accept either of their Parents. [RoM] + int_party_calc_state(p); + else //Check even share range. + if (member->lv < p->min_lv || member->lv > p->max_lv || p->family) { + if (p->family) p->family = 0; //Family state broken. + int_party_check_lv(p); + } + + mapif_party_info(-1, &p->party, 0); + mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 0); + inter_party_tosql(&p->party, PS_ADDMEMBER, i); + + return 0; } //Party setting change request int mapif_parse_PartyChangeOption(int fd,int party_id,int account_id,int exp,int item) { - struct party_data *p; - int flag = 0; - p = inter_party_fromsql(party_id); - - if(!p) - return 0; - - p->party.exp=exp; - if( exp && !party_check_exp_share(p) ){ - flag|=0x01; - p->party.exp=0; - } - p->party.item = item&0x3; //Filter out invalid values. - mapif_party_optionchanged(fd,&p->party,account_id,flag); - inter_party_tosql(&p->party, PS_BASIC, 0); - return 0; + struct party_data *p; + int flag = 0; + p = inter_party_fromsql(party_id); + + if (!p) + return 0; + + p->party.exp=exp; + if (exp && !party_check_exp_share(p)) { + flag|=0x01; + p->party.exp=0; + } + p->party.item = item&0x3; //Filter out invalid values. + mapif_party_optionchanged(fd,&p->party,account_id,flag); + inter_party_tosql(&p->party, PS_BASIC, 0); + return 0; } //Request leave party int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id) { - struct party_data *p; - int i,j=-1; - - p = inter_party_fromsql(party_id); - if( p == NULL ) - {// Party does not exists? - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id) ) - Sql_ShowDebug(sql_handle); - return 0; - } - - for (i = 0; i < MAX_PARTY; i++) { - if(p->party.member[i].account_id == account_id && - p->party.member[i].char_id == char_id) { - break; - } - } - if (i >= MAX_PARTY) - return 0; //Member not found? - - mapif_party_withdraw(party_id, account_id, char_id); - - if (p->party.member[i].leader){ - p->party.member[i].account_id = 0; - for (j = 0; j < MAX_PARTY; j++) { - if (!p->party.member[j].account_id) - continue; - mapif_party_withdraw(party_id, p->party.member[j].account_id, p->party.member[j].char_id); - p->party.member[j].account_id = 0; - } - //Party gets deleted on the check_empty call below. - } else { - inter_party_tosql(&p->party,PS_DELMEMBER,i); - j = p->party.member[i].lv; - if(p->party.member[i].online) p->party.count--; - memset(&p->party.member[i], 0, sizeof(struct party_member)); - p->size--; - if (j == p->min_lv || j == p->max_lv || p->family) - { - if(p->family) p->family = 0; //Family state broken. - int_party_check_lv(p); - } - } - - if (party_check_empty(p) == 0) - mapif_party_info(-1, &p->party, 0); - return 0; + struct party_data *p; + int i,j=-1; + + p = inter_party_fromsql(party_id); + if (p == NULL) { + // Party does not exists? + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id)) + Sql_ShowDebug(sql_handle); + return 0; + } + + for (i = 0; i < MAX_PARTY; i++) { + if (p->party.member[i].account_id == account_id && + p->party.member[i].char_id == char_id) { + break; + } + } + if (i >= MAX_PARTY) + return 0; //Member not found? + + mapif_party_withdraw(party_id, account_id, char_id); + + if (p->party.member[i].leader) { + p->party.member[i].account_id = 0; + for (j = 0; j < MAX_PARTY; j++) { + if (!p->party.member[j].account_id) + continue; + mapif_party_withdraw(party_id, p->party.member[j].account_id, p->party.member[j].char_id); + p->party.member[j].account_id = 0; + } + //Party gets deleted on the check_empty call below. + } else { + inter_party_tosql(&p->party,PS_DELMEMBER,i); + j = p->party.member[i].lv; + if (p->party.member[i].online) p->party.count--; + memset(&p->party.member[i], 0, sizeof(struct party_member)); + p->size--; + if (j == p->min_lv || j == p->max_lv || p->family) { + if (p->family) p->family = 0; //Family state broken. + int_party_check_lv(p); + } + } + + if (party_check_empty(p) == 0) + mapif_party_info(-1, &p->party, 0); + return 0; } // When member goes to other map or levels up. int mapif_parse_PartyChangeMap(int fd, int party_id, int account_id, int char_id, unsigned short map, int online, unsigned int lv) { - struct party_data *p; - int i; - - p = inter_party_fromsql(party_id); - if (p == NULL) - return 0; - - for(i = 0; i < MAX_PARTY && - (p->party.member[i].account_id != account_id || - p->party.member[i].char_id != char_id); i++); - - if (i == MAX_PARTY) return 0; - - if (p->party.member[i].online != online) - { - p->party.member[i].online = online; - if (online) - p->party.count++; - else - p->party.count--; - // Even share check situations: Family state (always breaks) - // character logging on/off is max/min level (update level range) - // or character logging on/off has a different level (update level range using new level) - if (p->family || - (p->party.member[i].lv <= p->min_lv || p->party.member[i].lv >= p->max_lv) || - (p->party.member[i].lv != lv && (lv <= p->min_lv || lv >= p->max_lv)) - ) - { - p->party.member[i].lv = lv; - int_party_check_lv(p); - } - //Send online/offline update. - mapif_party_membermoved(&p->party, i); - } - - if (p->party.member[i].lv != lv) { - if(p->party.member[i].lv == p->min_lv || - p->party.member[i].lv == p->max_lv) - { - p->party.member[i].lv = lv; - int_party_check_lv(p); - } else - p->party.member[i].lv = lv; - //There is no need to send level update to map servers - //since they do nothing with it. - } - - if (p->party.member[i].map != map) { - p->party.member[i].map = map; - mapif_party_membermoved(&p->party, i); - } - return 0; + struct party_data *p; + int i; + + p = inter_party_fromsql(party_id); + if (p == NULL) + return 0; + + for (i = 0; i < MAX_PARTY && + (p->party.member[i].account_id != account_id || + p->party.member[i].char_id != char_id); i++); + + if (i == MAX_PARTY) return 0; + + if (p->party.member[i].online != online) { + p->party.member[i].online = online; + if (online) + p->party.count++; + else + p->party.count--; + // Even share check situations: Family state (always breaks) + // character logging on/off is max/min level (update level range) + // or character logging on/off has a different level (update level range using new level) + if (p->family || + (p->party.member[i].lv <= p->min_lv || p->party.member[i].lv >= p->max_lv) || + (p->party.member[i].lv != lv && (lv <= p->min_lv || lv >= p->max_lv)) + ) { + p->party.member[i].lv = lv; + int_party_check_lv(p); + } + //Send online/offline update. + mapif_party_membermoved(&p->party, i); + } + + if (p->party.member[i].lv != lv) { + if (p->party.member[i].lv == p->min_lv || + p->party.member[i].lv == p->max_lv) { + p->party.member[i].lv = lv; + int_party_check_lv(p); + } else + p->party.member[i].lv = lv; + //There is no need to send level update to map servers + //since they do nothing with it. + } + + if (p->party.member[i].map != map) { + p->party.member[i].map = map; + mapif_party_membermoved(&p->party, i); + } + return 0; } //Request party dissolution int mapif_parse_BreakParty(int fd,int party_id) { - struct party_data *p; + struct party_data *p; - p = inter_party_fromsql(party_id); + p = inter_party_fromsql(party_id); - if(!p) - return 0; - inter_party_tosql(&p->party,PS_BREAK,0); - mapif_party_broken(fd,party_id); - return 0; + if (!p) + return 0; + inter_party_tosql(&p->party,PS_BREAK,0); + mapif_party_broken(fd,party_id); + return 0; } //Party sending the message int mapif_parse_PartyMessage(int fd,int party_id,int account_id,char *mes,int len) { - return mapif_party_message(party_id,account_id,mes,len, fd); + return mapif_party_message(party_id,account_id,mes,len, fd); } int mapif_parse_PartyLeaderChange(int fd,int party_id,int account_id,int char_id) { - struct party_data *p; - int i; - - p = inter_party_fromsql(party_id); - - if(!p) - return 0; - - for (i = 0; i < MAX_PARTY; i++) - { - if(p->party.member[i].leader) - p->party.member[i].leader = 0; - if(p->party.member[i].account_id == account_id && - p->party.member[i].char_id == char_id) - { - p->party.member[i].leader = 1; - inter_party_tosql(&p->party,PS_LEADER, i); - } - } - return 1; + struct party_data *p; + int i; + + p = inter_party_fromsql(party_id); + + if (!p) + return 0; + + for (i = 0; i < MAX_PARTY; i++) { + if (p->party.member[i].leader) + p->party.member[i].leader = 0; + if (p->party.member[i].account_id == account_id && + p->party.member[i].char_id == char_id) { + p->party.member[i].leader = 1; + inter_party_tosql(&p->party,PS_LEADER, i); + } + } + return 1; } @@ -741,123 +742,139 @@ int mapif_parse_PartyLeaderChange(int fd,int party_id,int account_id,int char_id // Data packet length is set to inter.c that you // Do NOT go and check the packet length, RFIFOSKIP is done by the caller // Return : -// 0 : error -// 1 : ok +// 0 : error +// 1 : ok int inter_party_parse_frommap(int fd) { - RFIFOHEAD(fd); - switch(RFIFOW(fd,0)) { - case 0x3020: mapif_parse_CreateParty(fd, (char*)RFIFOP(fd,4), RFIFOB(fd,28), RFIFOB(fd,29), (struct party_member*)RFIFOP(fd,30)); break; - case 0x3021: mapif_parse_PartyInfo(fd, RFIFOL(fd,2), RFIFOL(fd,6)); break; - case 0x3022: mapif_parse_PartyAddMember(fd, RFIFOL(fd,4), (struct party_member*)RFIFOP(fd,8)); break; - case 0x3023: mapif_parse_PartyChangeOption(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOW(fd,10), RFIFOW(fd,12)); break; - case 0x3024: mapif_parse_PartyLeave(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; - case 0x3025: mapif_parse_PartyChangeMap(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOW(fd,14), RFIFOB(fd,16), RFIFOW(fd,17)); break; - case 0x3026: mapif_parse_BreakParty(fd, RFIFOL(fd,2)); break; - case 0x3027: mapif_parse_PartyMessage(fd, RFIFOL(fd,4), RFIFOL(fd,8), (char*)RFIFOP(fd,12), RFIFOW(fd,2)-12); break; - case 0x3029: mapif_parse_PartyLeaderChange(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; - default: - return 0; - } - return 1; + RFIFOHEAD(fd); + switch (RFIFOW(fd,0)) { + case 0x3020: + mapif_parse_CreateParty(fd, (char *)RFIFOP(fd,4), RFIFOB(fd,28), RFIFOB(fd,29), (struct party_member *)RFIFOP(fd,30)); + break; + case 0x3021: + mapif_parse_PartyInfo(fd, RFIFOL(fd,2), RFIFOL(fd,6)); + break; + case 0x3022: + mapif_parse_PartyAddMember(fd, RFIFOL(fd,4), (struct party_member *)RFIFOP(fd,8)); + break; + case 0x3023: + mapif_parse_PartyChangeOption(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOW(fd,10), RFIFOW(fd,12)); + break; + case 0x3024: + mapif_parse_PartyLeave(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); + break; + case 0x3025: + mapif_parse_PartyChangeMap(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOW(fd,14), RFIFOB(fd,16), RFIFOW(fd,17)); + break; + case 0x3026: + mapif_parse_BreakParty(fd, RFIFOL(fd,2)); + break; + case 0x3027: + mapif_parse_PartyMessage(fd, RFIFOL(fd,4), RFIFOL(fd,8), (char *)RFIFOP(fd,12), RFIFOW(fd,2)-12); + break; + case 0x3029: + mapif_parse_PartyLeaderChange(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); + break; + default: + return 0; + } + return 1; } //Leave request from the server (for delete character) int inter_party_leave(int party_id,int account_id, int char_id) { - return mapif_parse_PartyLeave(-1,party_id,account_id, char_id); + return mapif_parse_PartyLeave(-1,party_id,account_id, char_id); } int inter_party_CharOnline(int char_id, int party_id) { - struct party_data* p; - int i; - - if( party_id == -1 ) - {// Get party_id from the database - char* data; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - return 0; //Eh? No party? - - Sql_GetData(sql_handle, 0, &data, NULL); - party_id = atoi(data); - Sql_FreeResult(sql_handle); - } - if (party_id == 0) - return 0; //No party... - - p = inter_party_fromsql(party_id); - if(!p) { - ShowError("Character %d's party %d not found!\n", char_id, party_id); - return 0; - } - - //Set member online - for(i=0; iparty.member[i].char_id == char_id) { - if (!p->party.member[i].online) { - p->party.member[i].online = 1; - p->party.count++; - if (p->party.member[i].lv < p->min_lv || - p->party.member[i].lv > p->max_lv) - int_party_check_lv(p); - } - break; - } - } - return 1; + struct party_data *p; + int i; + + if (party_id == -1) { + // Get party_id from the database + char *data; + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id)) { + Sql_ShowDebug(sql_handle); + return 0; + } + + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) + return 0; //Eh? No party? + + Sql_GetData(sql_handle, 0, &data, NULL); + party_id = atoi(data); + Sql_FreeResult(sql_handle); + } + if (party_id == 0) + return 0; //No party... + + p = inter_party_fromsql(party_id); + if (!p) { + ShowError("Character %d's party %d not found!\n", char_id, party_id); + return 0; + } + + //Set member online + for (i=0; iparty.member[i].char_id == char_id) { + if (!p->party.member[i].online) { + p->party.member[i].online = 1; + p->party.count++; + if (p->party.member[i].lv < p->min_lv || + p->party.member[i].lv > p->max_lv) + int_party_check_lv(p); + } + break; + } + } + return 1; } -int inter_party_CharOffline(int char_id, int party_id) { - struct party_data *p=NULL; - int i; - - if( party_id == -1 ) - {// Get guild_id from the database - char* data; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - return 0; //Eh? No party? - - Sql_GetData(sql_handle, 0, &data, NULL); - party_id = atoi(data); - Sql_FreeResult(sql_handle); - } - if (party_id == 0) - return 0; //No party... - - //Character has a party, set character offline and check if they were the only member online - if ((p = inter_party_fromsql(party_id)) == NULL) - return 0; - - //Set member offline - for(i=0; i< MAX_PARTY; i++) { - if(p->party.member[i].char_id == char_id) - { - p->party.member[i].online = 0; - p->party.count--; - if(p->party.member[i].lv == p->min_lv || - p->party.member[i].lv == p->max_lv) - int_party_check_lv(p); - break; - } - } - - if(!p->party.count) - //Parties don't have any data that needs be saved at this point... so just remove it from memory. - idb_remove(party_db_, party_id); - return 1; +int inter_party_CharOffline(int char_id, int party_id) +{ + struct party_data *p=NULL; + int i; + + if (party_id == -1) { + // Get guild_id from the database + char *data; + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id)) { + Sql_ShowDebug(sql_handle); + return 0; + } + + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) + return 0; //Eh? No party? + + Sql_GetData(sql_handle, 0, &data, NULL); + party_id = atoi(data); + Sql_FreeResult(sql_handle); + } + if (party_id == 0) + return 0; //No party... + + //Character has a party, set character offline and check if they were the only member online + if ((p = inter_party_fromsql(party_id)) == NULL) + return 0; + + //Set member offline + for (i=0; i< MAX_PARTY; i++) { + if (p->party.member[i].char_id == char_id) { + p->party.member[i].online = 0; + p->party.count--; + if (p->party.member[i].lv == p->min_lv || + p->party.member[i].lv == p->max_lv) + int_party_check_lv(p); + break; + } + } + + if (!p->party.count) + //Parties don't have any data that needs be saved at this point... so just remove it from memory. + idb_remove(party_db_, party_id); + return 1; } diff --git a/src/char/int_party.h b/src/char/int_party.h index d8cdcdc6a..27df25f15 100644 --- a/src/char/int_party.h +++ b/src/char/int_party.h @@ -6,12 +6,12 @@ //Party Flags on what to save/delete. enum { - PS_CREATE = 0x01, //Create a new party entry (index holds leader's info) - PS_BASIC = 0x02, //Update basic party info. - PS_LEADER = 0x04, //Update party's leader - PS_ADDMEMBER = 0x08, //Specify new party member (index specifies which party member) - PS_DELMEMBER = 0x10, //Specify member that left (index specifies which party member) - PS_BREAK = 0x20, //Specify that this party must be deleted. + PS_CREATE = 0x01, //Create a new party entry (index holds leader's info) + PS_BASIC = 0x02, //Update basic party info. + PS_LEADER = 0x04, //Update party's leader + PS_ADDMEMBER = 0x08, //Specify new party member (index specifies which party member) + PS_DELMEMBER = 0x10, //Specify member that left (index specifies which party member) + PS_BREAK = 0x20, //Specify that this party must be deleted. }; struct party; diff --git a/src/char/int_pet.c b/src/char/int_pet.c index 114398290..e04138c0a 100644 --- a/src/char/int_pet.c +++ b/src/char/int_pet.c @@ -18,292 +18,319 @@ struct s_pet *pet_pt; //--------------------------------------------------------- -int inter_pet_tosql(int pet_id, struct s_pet* p) +int inter_pet_tosql(int pet_id, struct s_pet *p) { - //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) - char esc_name[NAME_LENGTH*2+1];// escaped pet name - - Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); - p->hungry = cap_value(p->hungry, 0, 100); - p->intimate = cap_value(p->intimate, 0, 1000); - - if( pet_id == -1 ) - {// New pet. - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " - "(`class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) " - "VALUES ('%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, - p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - p->pet_id = (int)Sql_LastInsertId(sql_handle); - } - else - {// Update pet. - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d',`name`='%s',`account_id`='%d',`char_id`='%d',`level`='%d',`egg_id`='%d',`equip`='%d',`intimate`='%d',`hungry`='%d',`rename_flag`='%d',`incuvate`='%d' WHERE `pet_id`='%d'", - pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, - p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate, p->pet_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - } - - if (save_log) - ShowInfo("Pet saved %d - %s.\n", pet_id, p->name); - return 1; + //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) + char esc_name[NAME_LENGTH*2+1];// escaped pet name + + Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); + p->hungry = cap_value(p->hungry, 0, 100); + p->intimate = cap_value(p->intimate, 0, 1000); + + if (pet_id == -1) { + // New pet. + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " + "(`class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) " + "VALUES ('%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", + pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, + p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate)) { + Sql_ShowDebug(sql_handle); + return 0; + } + p->pet_id = (int)Sql_LastInsertId(sql_handle); + } else { + // Update pet. + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d',`name`='%s',`account_id`='%d',`char_id`='%d',`level`='%d',`egg_id`='%d',`equip`='%d',`intimate`='%d',`hungry`='%d',`rename_flag`='%d',`incuvate`='%d' WHERE `pet_id`='%d'", + pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, + p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate, p->pet_id)) { + Sql_ShowDebug(sql_handle); + return 0; + } + } + + if (save_log) + ShowInfo("Pet saved %d - %s.\n", pet_id, p->name); + return 1; } -int inter_pet_fromsql(int pet_id, struct s_pet* p) +int inter_pet_fromsql(int pet_id, struct s_pet *p) { - char* data; - size_t len; + char *data; + size_t len; #ifdef NOISY - ShowInfo("Loading pet (%d)...\n",pet_id); + ShowInfo("Loading pet (%d)...\n",pet_id); #endif - memset(p, 0, sizeof(struct s_pet)); - - //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate` FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - - if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - p->pet_id = pet_id; - Sql_GetData(sql_handle, 1, &data, NULL); p->class_ = atoi(data); - Sql_GetData(sql_handle, 2, &data, &len); memcpy(p->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 3, &data, NULL); p->account_id = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); p->char_id = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); p->level = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); p->egg_id = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); p->equip = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); p->intimate = atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); p->hungry = atoi(data); - Sql_GetData(sql_handle, 10, &data, NULL); p->rename_flag = atoi(data); - Sql_GetData(sql_handle, 11, &data, NULL); p->incuvate = atoi(data); - - Sql_FreeResult(sql_handle); - - p->hungry = cap_value(p->hungry, 0, 100); - p->intimate = cap_value(p->intimate, 0, 1000); - - if( save_log ) - ShowInfo("Pet loaded (%d - %s).\n", pet_id, p->name); - } - return 0; + memset(p, 0, sizeof(struct s_pet)); + + //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate` FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id)) { + Sql_ShowDebug(sql_handle); + return 0; + } + + if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + p->pet_id = pet_id; + Sql_GetData(sql_handle, 1, &data, NULL); + p->class_ = atoi(data); + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(p->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 3, &data, NULL); + p->account_id = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + p->char_id = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + p->level = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + p->egg_id = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); + p->equip = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); + p->intimate = atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); + p->hungry = atoi(data); + Sql_GetData(sql_handle, 10, &data, NULL); + p->rename_flag = atoi(data); + Sql_GetData(sql_handle, 11, &data, NULL); + p->incuvate = atoi(data); + + Sql_FreeResult(sql_handle); + + p->hungry = cap_value(p->hungry, 0, 100); + p->intimate = cap_value(p->intimate, 0, 1000); + + if (save_log) + ShowInfo("Pet loaded (%d - %s).\n", pet_id, p->name); + } + return 0; } //---------------------------------------------- -int inter_pet_sql_init(void){ - //memory alloc - pet_pt = (struct s_pet*)aCalloc(sizeof(struct s_pet), 1); - return 0; +int inter_pet_sql_init(void) +{ + //memory alloc + pet_pt = (struct s_pet *)aCalloc(sizeof(struct s_pet), 1); + return 0; } -void inter_pet_sql_final(void){ - if (pet_pt) aFree(pet_pt); - return; +void inter_pet_sql_final(void) +{ + if (pet_pt) aFree(pet_pt); + return; } //---------------------------------- -int inter_pet_delete(int pet_id){ - ShowInfo("delete pet request: %d...\n",pet_id); +int inter_pet_delete(int pet_id) +{ + ShowInfo("delete pet request: %d...\n",pet_id); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id) ) - Sql_ShowDebug(sql_handle); - return 0; + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id)) + Sql_ShowDebug(sql_handle); + return 0; } //------------------------------------------------------ int mapif_pet_created(int fd, int account_id, struct s_pet *p) { - WFIFOHEAD(fd, 11); - WFIFOW(fd, 0) =0x3880; - WFIFOL(fd, 2) =account_id; - if(p!=NULL){ - WFIFOB(fd, 6)=0; - WFIFOL(fd, 7) =p->pet_id; - ShowInfo("int_pet: created pet %d - %s\n", p->pet_id, p->name); - }else{ - WFIFOB(fd, 6)=1; - WFIFOL(fd, 7)=0; - } - WFIFOSET(fd, 11); - - return 0; + WFIFOHEAD(fd, 11); + WFIFOW(fd, 0) =0x3880; + WFIFOL(fd, 2) =account_id; + if (p!=NULL) { + WFIFOB(fd, 6)=0; + WFIFOL(fd, 7) =p->pet_id; + ShowInfo("int_pet: created pet %d - %s\n", p->pet_id, p->name); + } else { + WFIFOB(fd, 6)=1; + WFIFOL(fd, 7)=0; + } + WFIFOSET(fd, 11); + + return 0; } -int mapif_pet_info(int fd, int account_id, struct s_pet *p){ - WFIFOHEAD(fd, sizeof(struct s_pet) + 9); - WFIFOW(fd, 0) =0x3881; - WFIFOW(fd, 2) =sizeof(struct s_pet) + 9; - WFIFOL(fd, 4) =account_id; - WFIFOB(fd, 8)=0; - memcpy(WFIFOP(fd, 9), p, sizeof(struct s_pet)); - WFIFOSET(fd, WFIFOW(fd, 2)); - - return 0; +int mapif_pet_info(int fd, int account_id, struct s_pet *p) +{ + WFIFOHEAD(fd, sizeof(struct s_pet) + 9); + WFIFOW(fd, 0) =0x3881; + WFIFOW(fd, 2) =sizeof(struct s_pet) + 9; + WFIFOL(fd, 4) =account_id; + WFIFOB(fd, 8)=0; + memcpy(WFIFOP(fd, 9), p, sizeof(struct s_pet)); + WFIFOSET(fd, WFIFOW(fd, 2)); + + return 0; } -int mapif_pet_noinfo(int fd, int account_id){ - WFIFOHEAD(fd, sizeof(struct s_pet) + 9); - WFIFOW(fd, 0) =0x3881; - WFIFOW(fd, 2) =sizeof(struct s_pet) + 9; - WFIFOL(fd, 4) =account_id; - WFIFOB(fd, 8)=1; - memset(WFIFOP(fd, 9), 0, sizeof(struct s_pet)); - WFIFOSET(fd, WFIFOW(fd, 2)); - - return 0; +int mapif_pet_noinfo(int fd, int account_id) +{ + WFIFOHEAD(fd, sizeof(struct s_pet) + 9); + WFIFOW(fd, 0) =0x3881; + WFIFOW(fd, 2) =sizeof(struct s_pet) + 9; + WFIFOL(fd, 4) =account_id; + WFIFOB(fd, 8)=1; + memset(WFIFOP(fd, 9), 0, sizeof(struct s_pet)); + WFIFOSET(fd, WFIFOW(fd, 2)); + + return 0; } -int mapif_save_pet_ack(int fd, int account_id, int flag){ - WFIFOHEAD(fd, 7); - WFIFOW(fd, 0) =0x3882; - WFIFOL(fd, 2) =account_id; - WFIFOB(fd, 6) =flag; - WFIFOSET(fd, 7); +int mapif_save_pet_ack(int fd, int account_id, int flag) +{ + WFIFOHEAD(fd, 7); + WFIFOW(fd, 0) =0x3882; + WFIFOL(fd, 2) =account_id; + WFIFOB(fd, 6) =flag; + WFIFOSET(fd, 7); - return 0; + return 0; } -int mapif_delete_pet_ack(int fd, int flag){ - WFIFOHEAD(fd, 3); - WFIFOW(fd, 0) =0x3883; - WFIFOB(fd, 2) =flag; - WFIFOSET(fd, 3); +int mapif_delete_pet_ack(int fd, int flag) +{ + WFIFOHEAD(fd, 3); + WFIFOW(fd, 0) =0x3883; + WFIFOB(fd, 2) =flag; + WFIFOSET(fd, 3); - return 0; + return 0; } int mapif_create_pet(int fd, int account_id, int char_id, short pet_class, short pet_lv, short pet_egg_id, - short pet_equip, short intimate, short hungry, char rename_flag, char incuvate, char *pet_name) + short pet_equip, short intimate, short hungry, char rename_flag, char incuvate, char *pet_name) { - memset(pet_pt, 0, sizeof(struct s_pet)); - strncpy(pet_pt->name, pet_name, NAME_LENGTH); - if(incuvate == 1) - pet_pt->account_id = pet_pt->char_id = 0; - else { - pet_pt->account_id = account_id; - pet_pt->char_id = char_id; - } - pet_pt->class_ = pet_class; - pet_pt->level = pet_lv; - pet_pt->egg_id = pet_egg_id; - pet_pt->equip = pet_equip; - pet_pt->intimate = intimate; - pet_pt->hungry = hungry; - pet_pt->rename_flag = rename_flag; - pet_pt->incuvate = incuvate; - - if(pet_pt->hungry < 0) - pet_pt->hungry = 0; - else if(pet_pt->hungry > 100) - pet_pt->hungry = 100; - if(pet_pt->intimate < 0) - pet_pt->intimate = 0; - else if(pet_pt->intimate > 1000) - pet_pt->intimate = 1000; - - pet_pt->pet_id = -1; //Signal NEW pet. - if (inter_pet_tosql(pet_pt->pet_id,pet_pt)) - mapif_pet_created(fd, account_id, pet_pt); - else //Failed... - mapif_pet_created(fd, account_id, NULL); - - return 0; + memset(pet_pt, 0, sizeof(struct s_pet)); + strncpy(pet_pt->name, pet_name, NAME_LENGTH); + if (incuvate == 1) + pet_pt->account_id = pet_pt->char_id = 0; + else { + pet_pt->account_id = account_id; + pet_pt->char_id = char_id; + } + pet_pt->class_ = pet_class; + pet_pt->level = pet_lv; + pet_pt->egg_id = pet_egg_id; + pet_pt->equip = pet_equip; + pet_pt->intimate = intimate; + pet_pt->hungry = hungry; + pet_pt->rename_flag = rename_flag; + pet_pt->incuvate = incuvate; + + if (pet_pt->hungry < 0) + pet_pt->hungry = 0; + else if (pet_pt->hungry > 100) + pet_pt->hungry = 100; + if (pet_pt->intimate < 0) + pet_pt->intimate = 0; + else if (pet_pt->intimate > 1000) + pet_pt->intimate = 1000; + + pet_pt->pet_id = -1; //Signal NEW pet. + if (inter_pet_tosql(pet_pt->pet_id,pet_pt)) + mapif_pet_created(fd, account_id, pet_pt); + else //Failed... + mapif_pet_created(fd, account_id, NULL); + + return 0; } -int mapif_load_pet(int fd, int account_id, int char_id, int pet_id){ - memset(pet_pt, 0, sizeof(struct s_pet)); - - inter_pet_fromsql(pet_id, pet_pt); - - if(pet_pt!=NULL) { - if(pet_pt->incuvate == 1) { - pet_pt->account_id = pet_pt->char_id = 0; - mapif_pet_info(fd, account_id, pet_pt); - } - else if(account_id == pet_pt->account_id && char_id == pet_pt->char_id) - mapif_pet_info(fd, account_id, pet_pt); - else - mapif_pet_noinfo(fd, account_id); - } - else - mapif_pet_noinfo(fd, account_id); - - return 0; +int mapif_load_pet(int fd, int account_id, int char_id, int pet_id) +{ + memset(pet_pt, 0, sizeof(struct s_pet)); + + inter_pet_fromsql(pet_id, pet_pt); + + if (pet_pt!=NULL) { + if (pet_pt->incuvate == 1) { + pet_pt->account_id = pet_pt->char_id = 0; + mapif_pet_info(fd, account_id, pet_pt); + } else if (account_id == pet_pt->account_id && char_id == pet_pt->char_id) + mapif_pet_info(fd, account_id, pet_pt); + else + mapif_pet_noinfo(fd, account_id); + } else + mapif_pet_noinfo(fd, account_id); + + return 0; } -int mapif_save_pet(int fd, int account_id, struct s_pet *data) { - //here process pet save request. - int len; - RFIFOHEAD(fd); - len=RFIFOW(fd, 2); - if(sizeof(struct s_pet)!=len-8) { - ShowError("inter pet: data size error %d %d\n", sizeof(struct s_pet), len-8); - } - - else{ - if(data->hungry < 0) - data->hungry = 0; - else if(data->hungry > 100) - data->hungry = 100; - if(data->intimate < 0) - data->intimate = 0; - else if(data->intimate > 1000) - data->intimate = 1000; - inter_pet_tosql(data->pet_id,data); - mapif_save_pet_ack(fd, account_id, 0); - } - - return 0; +int mapif_save_pet(int fd, int account_id, struct s_pet *data) +{ + //here process pet save request. + int len; + RFIFOHEAD(fd); + len=RFIFOW(fd, 2); + if (sizeof(struct s_pet)!=len-8) { + ShowError("inter pet: data size error %d %d\n", sizeof(struct s_pet), len-8); + } + + else { + if (data->hungry < 0) + data->hungry = 0; + else if (data->hungry > 100) + data->hungry = 100; + if (data->intimate < 0) + data->intimate = 0; + else if (data->intimate > 1000) + data->intimate = 1000; + inter_pet_tosql(data->pet_id,data); + mapif_save_pet_ack(fd, account_id, 0); + } + + return 0; } -int mapif_delete_pet(int fd, int pet_id){ - mapif_delete_pet_ack(fd, inter_pet_delete(pet_id)); +int mapif_delete_pet(int fd, int pet_id) +{ + mapif_delete_pet_ack(fd, inter_pet_delete(pet_id)); - return 0; + return 0; } -int mapif_parse_CreatePet(int fd){ - RFIFOHEAD(fd); - mapif_create_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOW(fd, 10), RFIFOW(fd, 12), RFIFOW(fd, 14), RFIFOW(fd, 16), RFIFOW(fd, 18), - RFIFOW(fd, 20), RFIFOB(fd, 22), RFIFOB(fd, 23), (char*)RFIFOP(fd, 24)); - return 0; +int mapif_parse_CreatePet(int fd) +{ + RFIFOHEAD(fd); + mapif_create_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOW(fd, 10), RFIFOW(fd, 12), RFIFOW(fd, 14), RFIFOW(fd, 16), RFIFOW(fd, 18), + RFIFOW(fd, 20), RFIFOB(fd, 22), RFIFOB(fd, 23), (char *)RFIFOP(fd, 24)); + return 0; } -int mapif_parse_LoadPet(int fd){ - RFIFOHEAD(fd); - mapif_load_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOL(fd, 10)); - return 0; +int mapif_parse_LoadPet(int fd) +{ + RFIFOHEAD(fd); + mapif_load_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOL(fd, 10)); + return 0; } -int mapif_parse_SavePet(int fd){ - RFIFOHEAD(fd); - mapif_save_pet(fd, RFIFOL(fd, 4), (struct s_pet *) RFIFOP(fd, 8)); - return 0; +int mapif_parse_SavePet(int fd) +{ + RFIFOHEAD(fd); + mapif_save_pet(fd, RFIFOL(fd, 4), (struct s_pet *) RFIFOP(fd, 8)); + return 0; } -int mapif_parse_DeletePet(int fd){ - RFIFOHEAD(fd); - mapif_delete_pet(fd, RFIFOL(fd, 2)); - return 0; +int mapif_parse_DeletePet(int fd) +{ + RFIFOHEAD(fd); + mapif_delete_pet(fd, RFIFOL(fd, 2)); + return 0; } -int inter_pet_parse_frommap(int fd){ - RFIFOHEAD(fd); - switch(RFIFOW(fd, 0)){ - case 0x3080: mapif_parse_CreatePet(fd); break; - case 0x3081: mapif_parse_LoadPet(fd); break; - case 0x3082: mapif_parse_SavePet(fd); break; - case 0x3083: mapif_parse_DeletePet(fd); break; - default: - return 0; - } - return 1; +int inter_pet_parse_frommap(int fd) +{ + RFIFOHEAD(fd); + switch (RFIFOW(fd, 0)) { + case 0x3080: + mapif_parse_CreatePet(fd); + break; + case 0x3081: + mapif_parse_LoadPet(fd); + break; + case 0x3082: + mapif_parse_SavePet(fd); + break; + case 0x3083: + mapif_parse_DeletePet(fd); + break; + default: + return 0; + } + return 1; } diff --git a/src/char/int_quest.c b/src/char/int_quest.c index 224205412..8ba6ef95a 100644 --- a/src/char/int_quest.c +++ b/src/char/int_quest.c @@ -21,164 +21,158 @@ //Load entire questlog for a character int mapif_quests_fromsql(int char_id, struct quest questlog[]) { - int i; - struct quest tmp_quest; - SqlStmt * stmt; - - stmt = SqlStmt_Malloc(sql_handle); - if( stmt == NULL ) - { - SqlStmt_ShowDebug(stmt); - return 0; - } - - memset(&tmp_quest, 0, sizeof(struct quest)); - - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `quest_id`, `state`, `time`, `count1`, `count2`, `count3` FROM `%s` WHERE `char_id`=? LIMIT %d", quest_db, MAX_QUEST_DB) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_quest.quest_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_quest.state, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT, &tmp_quest.time, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_INT, &tmp_quest.count[0], 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_INT, &tmp_quest.count[1], 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_INT, &tmp_quest.count[2], 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - - for( i = 0; i < MAX_QUEST_DB && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) - memcpy(&questlog[i], &tmp_quest, sizeof(tmp_quest)); - - SqlStmt_Free(stmt); - return i; + int i; + struct quest tmp_quest; + SqlStmt *stmt; + + stmt = SqlStmt_Malloc(sql_handle); + if (stmt == NULL) { + SqlStmt_ShowDebug(stmt); + return 0; + } + + memset(&tmp_quest, 0, sizeof(struct quest)); + + if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `quest_id`, `state`, `time`, `count1`, `count2`, `count3` FROM `%s` WHERE `char_id`=? LIMIT %d", quest_db, MAX_QUEST_DB) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_quest.quest_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_quest.state, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT, &tmp_quest.time, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_INT, &tmp_quest.count[0], 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_INT, &tmp_quest.count[1], 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_INT, &tmp_quest.count[2], 0, NULL, NULL)) + SqlStmt_ShowDebug(stmt); + + for (i = 0; i < MAX_QUEST_DB && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) + memcpy(&questlog[i], &tmp_quest, sizeof(tmp_quest)); + + SqlStmt_Free(stmt); + return i; } //Delete a quest bool mapif_quest_delete(int char_id, int quest_id) { - if ( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, quest_id, char_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, quest_id, char_id)) { + Sql_ShowDebug(sql_handle); + return false; + } - return true; + return true; } //Add a quest to a questlog bool mapif_quest_add(int char_id, struct quest qd) { - if ( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`quest_id`, `char_id`, `state`, `time`, `count1`, `count2`, `count3`) VALUES ('%d', '%d', '%d','%d', '%d', '%d', '%d')", quest_db, qd.quest_id, char_id, qd.state, qd.time, qd.count[0], qd.count[1], qd.count[2]) ) - { - Sql_ShowDebug(sql_handle); - return false; - } + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`quest_id`, `char_id`, `state`, `time`, `count1`, `count2`, `count3`) VALUES ('%d', '%d', '%d','%d', '%d', '%d', '%d')", quest_db, qd.quest_id, char_id, qd.state, qd.time, qd.count[0], qd.count[1], qd.count[2])) { + Sql_ShowDebug(sql_handle); + return false; + } - return true; + return true; } //Update a questlog bool mapif_quest_update(int char_id, struct quest qd) { - if ( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `state`='%d', `count1`='%d', `count2`='%d', `count3`='%d' WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, qd.state, qd.count[0], qd.count[1], qd.count[2], qd.quest_id, char_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } + if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `state`='%d', `count1`='%d', `count2`='%d', `count3`='%d' WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, qd.state, qd.count[0], qd.count[1], qd.count[2], qd.quest_id, char_id)) { + Sql_ShowDebug(sql_handle); + return false; + } - return true; + return true; } //Save quests int mapif_parse_quest_save(int fd) { - int i, j, k, num2, num1 = (RFIFOW(fd,2)-8)/sizeof(struct quest); - int char_id = RFIFOL(fd,4); - struct quest qd1[MAX_QUEST_DB],qd2[MAX_QUEST_DB]; - bool success = true; - - memset(qd1, 0, sizeof(qd1)); - memset(qd2, 0, sizeof(qd2)); - if( num1 ) memcpy(&qd1, RFIFOP(fd,8), RFIFOW(fd,2)-8); - num2 = mapif_quests_fromsql(char_id, qd2); - - for( i = 0; i < num1; i++ ) - { - ARR_FIND( 0, num2, j, qd1[i].quest_id == qd2[j].quest_id ); - if( j < num2 ) // Update existed quests - { // Only states and counts are changable. - ARR_FIND( 0, MAX_QUEST_OBJECTIVES, k, qd1[i].count[k] != qd2[j].count[k] ); - if( k != MAX_QUEST_OBJECTIVES || qd1[i].state != qd2[j].state ) - success &= mapif_quest_update(char_id, qd1[i]); - - if( j < (--num2) ) - { - memmove(&qd2[j],&qd2[j+1],sizeof(struct quest)*(num2-j)); - memset(&qd2[num2], 0, sizeof(struct quest)); - } - - } - else // Add new quests - success &= mapif_quest_add(char_id, qd1[i]); - } - - for( i = 0; i < num2; i++ ) // Quests not in qd1 but in qd2 are to be erased. - success &= mapif_quest_delete(char_id, qd2[i].quest_id); - - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x3861; - WFIFOL(fd,2) = char_id; - WFIFOB(fd,6) = success?1:0; - WFIFOSET(fd,7); - - return 0; + int i, j, k, num2, num1 = (RFIFOW(fd,2)-8)/sizeof(struct quest); + int char_id = RFIFOL(fd,4); + struct quest qd1[MAX_QUEST_DB],qd2[MAX_QUEST_DB]; + bool success = true; + + memset(qd1, 0, sizeof(qd1)); + memset(qd2, 0, sizeof(qd2)); + if (num1) memcpy(&qd1, RFIFOP(fd,8), RFIFOW(fd,2)-8); + num2 = mapif_quests_fromsql(char_id, qd2); + + for (i = 0; i < num1; i++) { + ARR_FIND(0, num2, j, qd1[i].quest_id == qd2[j].quest_id); + if (j < num2) { // Update existed quests + // Only states and counts are changable. + ARR_FIND(0, MAX_QUEST_OBJECTIVES, k, qd1[i].count[k] != qd2[j].count[k]); + if (k != MAX_QUEST_OBJECTIVES || qd1[i].state != qd2[j].state) + success &= mapif_quest_update(char_id, qd1[i]); + + if (j < (--num2)) { + memmove(&qd2[j],&qd2[j+1],sizeof(struct quest)*(num2-j)); + memset(&qd2[num2], 0, sizeof(struct quest)); + } + + } else // Add new quests + success &= mapif_quest_add(char_id, qd1[i]); + } + + for (i = 0; i < num2; i++) // Quests not in qd1 but in qd2 are to be erased. + success &= mapif_quest_delete(char_id, qd2[i].quest_id); + + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x3861; + WFIFOL(fd,2) = char_id; + WFIFOB(fd,6) = success?1:0; + WFIFOSET(fd,7); + + return 0; } //Send questlog to map server int mapif_parse_quest_load(int fd) { - int char_id = RFIFOL(fd,2); - struct quest tmp_questlog[MAX_QUEST_DB]; - int num_quests, i, num_complete = 0; - int complete[MAX_QUEST_DB]; - - memset(tmp_questlog, 0, sizeof(tmp_questlog)); - memset(complete, 0, sizeof(complete)); - - num_quests = mapif_quests_fromsql(char_id, tmp_questlog); - - WFIFOHEAD(fd,num_quests*sizeof(struct quest)+8); - WFIFOW(fd,0) = 0x3860; - WFIFOW(fd,2) = num_quests*sizeof(struct quest)+8; - WFIFOL(fd,4) = char_id; - - //Active and inactive quests - for( i = 0; i < num_quests; i++ ) - { - if( tmp_questlog[i].state == Q_COMPLETE ) - { - complete[num_complete++] = i; - continue; - } - memcpy(WFIFOP(fd,(i-num_complete)*sizeof(struct quest)+8), &tmp_questlog[i], sizeof(struct quest)); - } - - // Completed quests - for( i = num_quests - num_complete; i < num_quests; i++ ) - memcpy(WFIFOP(fd,i*sizeof(struct quest)+8), &tmp_questlog[complete[i-num_quests+num_complete]], sizeof(struct quest)); - - WFIFOSET(fd,num_quests*sizeof(struct quest)+8); - - return 0; + int char_id = RFIFOL(fd,2); + struct quest tmp_questlog[MAX_QUEST_DB]; + int num_quests, i, num_complete = 0; + int complete[MAX_QUEST_DB]; + + memset(tmp_questlog, 0, sizeof(tmp_questlog)); + memset(complete, 0, sizeof(complete)); + + num_quests = mapif_quests_fromsql(char_id, tmp_questlog); + + WFIFOHEAD(fd,num_quests*sizeof(struct quest)+8); + WFIFOW(fd,0) = 0x3860; + WFIFOW(fd,2) = num_quests*sizeof(struct quest)+8; + WFIFOL(fd,4) = char_id; + + //Active and inactive quests + for (i = 0; i < num_quests; i++) { + if (tmp_questlog[i].state == Q_COMPLETE) { + complete[num_complete++] = i; + continue; + } + memcpy(WFIFOP(fd,(i-num_complete)*sizeof(struct quest)+8), &tmp_questlog[i], sizeof(struct quest)); + } + + // Completed quests + for (i = num_quests - num_complete; i < num_quests; i++) + memcpy(WFIFOP(fd,i*sizeof(struct quest)+8), &tmp_questlog[complete[i-num_quests+num_complete]], sizeof(struct quest)); + + WFIFOSET(fd,num_quests*sizeof(struct quest)+8); + + return 0; } int inter_quest_parse_frommap(int fd) { - switch(RFIFOW(fd,0)) - { - case 0x3060: mapif_parse_quest_load(fd); break; - case 0x3061: mapif_parse_quest_save(fd); break; - default: - return 0; - } - return 1; + switch (RFIFOW(fd,0)) { + case 0x3060: + mapif_parse_quest_load(fd); + break; + case 0x3061: + mapif_parse_quest_save(fd); + break; + default: + return 0; + } + return 1; } diff --git a/src/char/int_storage.c b/src/char/int_storage.c index 248a4521f..6f94ecc32 100644 --- a/src/char/int_storage.c +++ b/src/char/int_storage.c @@ -15,142 +15,155 @@ #include -#define STORAGE_MEMINC 16 +#define STORAGE_MEMINC 16 /// Save storage data to sql -int storage_tosql(int account_id, struct storage_data* p) +int storage_tosql(int account_id, struct storage_data *p) { - memitemdata_to_sql(p->items, MAX_STORAGE, account_id, TABLE_STORAGE); - return 0; + memitemdata_to_sql(p->items, MAX_STORAGE, account_id, TABLE_STORAGE); + return 0; } /// Load storage data to mem -int storage_fromsql(int account_id, struct storage_data* p) +int storage_fromsql(int account_id, struct storage_data *p) { - StringBuf buf; - struct item* item; - char* data; - int i; - int j; - - memset(p, 0, sizeof(struct storage_data)); //clean up memory - p->storage_amount = 0; - - // storage {`account_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`"); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", storage_db, account_id); - - if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) - Sql_ShowDebug(sql_handle); - - StringBuf_Destroy(&buf); - - for( i = 0; i < MAX_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - item = &p->items[i]; - Sql_GetData(sql_handle, 0, &data, NULL); item->id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); item->nameid = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); item->amount = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); item->equip = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); item->identify = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); item->refine = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); item->attribute = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); item->expire_time = (unsigned int)atoi(data); - for( j = 0; j < MAX_SLOTS; ++j ) - { - Sql_GetData(sql_handle, 8+j, &data, NULL); item->card[j] = atoi(data); - } - } - p->storage_amount = i; - Sql_FreeResult(sql_handle); - - ShowInfo("storage load complete from DB - id: %d (total: %d)\n", account_id, p->storage_amount); - return 1; + StringBuf buf; + struct item *item; + char *data; + int i; + int j; + + memset(p, 0, sizeof(struct storage_data)); //clean up memory + p->storage_amount = 0; + + // storage {`account_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`"); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ",`card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", storage_db, account_id); + + if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) + Sql_ShowDebug(sql_handle); + + StringBuf_Destroy(&buf); + + for (i = 0; i < MAX_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + item = &p->items[i]; + Sql_GetData(sql_handle, 0, &data, NULL); + item->id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + item->nameid = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + item->amount = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + item->equip = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + item->identify = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + item->refine = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + item->attribute = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); + item->expire_time = (unsigned int)atoi(data); + for (j = 0; j < MAX_SLOTS; ++j) { + Sql_GetData(sql_handle, 8+j, &data, NULL); + item->card[j] = atoi(data); + } + } + p->storage_amount = i; + Sql_FreeResult(sql_handle); + + ShowInfo("storage load complete from DB - id: %d (total: %d)\n", account_id, p->storage_amount); + return 1; } /// Save guild_storage data to sql -int guild_storage_tosql(int guild_id, struct guild_storage* p) +int guild_storage_tosql(int guild_id, struct guild_storage *p) { - memitemdata_to_sql(p->items, MAX_GUILD_STORAGE, guild_id, TABLE_GUILD_STORAGE); - ShowInfo ("guild storage save to DB - guild: %d\n", guild_id); - return 0; + memitemdata_to_sql(p->items, MAX_GUILD_STORAGE, guild_id, TABLE_GUILD_STORAGE); + ShowInfo("guild storage save to DB - guild: %d\n", guild_id); + return 0; } /// Load guild_storage data to mem -int guild_storage_fromsql(int guild_id, struct guild_storage* p) +int guild_storage_fromsql(int guild_id, struct guild_storage *p) { - StringBuf buf; - struct item* item; - char* data; - int i; - int j; - - memset(p, 0, sizeof(struct guild_storage)); //clean up memory - p->storage_amount = 0; - p->guild_id = guild_id; - - // storage {`guild_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`"); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", guild_storage_db, guild_id); - - if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) - Sql_ShowDebug(sql_handle); - - StringBuf_Destroy(&buf); - - for( i = 0; i < MAX_GUILD_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - item = &p->items[i]; - Sql_GetData(sql_handle, 0, &data, NULL); item->id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); item->nameid = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); item->amount = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); item->equip = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); item->identify = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); item->refine = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); item->attribute = atoi(data); - item->expire_time = 0; - for( j = 0; j < MAX_SLOTS; ++j ) - { - Sql_GetData(sql_handle, 7+j, &data, NULL); item->card[j] = atoi(data); - } - } - p->storage_amount = i; - Sql_FreeResult(sql_handle); - - ShowInfo("guild storage load complete from DB - id: %d (total: %d)\n", guild_id, p->storage_amount); - return 0; + StringBuf buf; + struct item *item; + char *data; + int i; + int j; + + memset(p, 0, sizeof(struct guild_storage)); //clean up memory + p->storage_amount = 0; + p->guild_id = guild_id; + + // storage {`guild_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`"); + for (j = 0; j < MAX_SLOTS; ++j) + StringBuf_Printf(&buf, ",`card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", guild_storage_db, guild_id); + + if (SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))) + Sql_ShowDebug(sql_handle); + + StringBuf_Destroy(&buf); + + for (i = 0; i < MAX_GUILD_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + item = &p->items[i]; + Sql_GetData(sql_handle, 0, &data, NULL); + item->id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + item->nameid = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); + item->amount = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + item->equip = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + item->identify = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + item->refine = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + item->attribute = atoi(data); + item->expire_time = 0; + for (j = 0; j < MAX_SLOTS; ++j) { + Sql_GetData(sql_handle, 7+j, &data, NULL); + item->card[j] = atoi(data); + } + } + p->storage_amount = i; + Sql_FreeResult(sql_handle); + + ShowInfo("guild storage load complete from DB - id: %d (total: %d)\n", guild_id, p->storage_amount); + return 0; } //--------------------------------------------------------- // storage data initialize int inter_storage_sql_init(void) { - return 1; + return 1; } // storage data finalize void inter_storage_sql_final(void) { - return; + return; } // q?f[^? int inter_storage_delete(int account_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id`='%d'", storage_db, account_id) ) - Sql_ShowDebug(sql_handle); - return 0; + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id`='%d'", storage_db, account_id)) + Sql_ShowDebug(sql_handle); + return 0; } int inter_guild_storage_delete(int guild_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", guild_storage_db, guild_id) ) - Sql_ShowDebug(sql_handle); - return 0; + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", guild_storage_db, guild_id)) + Sql_ShowDebug(sql_handle); + return 0; } //--------------------------------------------------------- @@ -158,38 +171,38 @@ int inter_guild_storage_delete(int guild_id) int mapif_load_guild_storage(int fd,int account_id,int guild_id) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id) ) - Sql_ShowDebug(sql_handle); - else if( Sql_NumRows(sql_handle) > 0 ) - {// guild exists - WFIFOHEAD(fd, sizeof(struct guild_storage)+12); - WFIFOW(fd,0) = 0x3818; - WFIFOW(fd,2) = sizeof(struct guild_storage)+12; - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = guild_id; - guild_storage_fromsql(guild_id, (struct guild_storage*)WFIFOP(fd,12)); - WFIFOSET(fd, WFIFOW(fd,2)); - return 0; - } - // guild does not exist - Sql_FreeResult(sql_handle); - WFIFOHEAD(fd, 12); - WFIFOW(fd,0) = 0x3818; - WFIFOW(fd,2) = 12; - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = 0; - WFIFOSET(fd, 12); - return 0; + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id)) + Sql_ShowDebug(sql_handle); + else if (Sql_NumRows(sql_handle) > 0) { + // guild exists + WFIFOHEAD(fd, sizeof(struct guild_storage)+12); + WFIFOW(fd,0) = 0x3818; + WFIFOW(fd,2) = sizeof(struct guild_storage)+12; + WFIFOL(fd,4) = account_id; + WFIFOL(fd,8) = guild_id; + guild_storage_fromsql(guild_id, (struct guild_storage *)WFIFOP(fd,12)); + WFIFOSET(fd, WFIFOW(fd,2)); + return 0; + } + // guild does not exist + Sql_FreeResult(sql_handle); + WFIFOHEAD(fd, 12); + WFIFOW(fd,0) = 0x3818; + WFIFOW(fd,2) = 12; + WFIFOL(fd,4) = account_id; + WFIFOL(fd,8) = 0; + WFIFOSET(fd, 12); + return 0; } int mapif_save_guild_storage_ack(int fd,int account_id,int guild_id,int fail) { - WFIFOHEAD(fd,11); - WFIFOW(fd,0)=0x3819; - WFIFOL(fd,2)=account_id; - WFIFOL(fd,6)=guild_id; - WFIFOB(fd,10)=fail; - WFIFOSET(fd,11); - return 0; + WFIFOHEAD(fd,11); + WFIFOW(fd,0)=0x3819; + WFIFOL(fd,2)=account_id; + WFIFOL(fd,6)=guild_id; + WFIFOB(fd,10)=fail; + WFIFOSET(fd,11); + return 0; } //--------------------------------------------------------- @@ -197,50 +210,51 @@ int mapif_save_guild_storage_ack(int fd,int account_id,int guild_id,int fail) int mapif_parse_LoadGuildStorage(int fd) { - RFIFOHEAD(fd); - mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6)); - return 0; + RFIFOHEAD(fd); + mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6)); + return 0; } int mapif_parse_SaveGuildStorage(int fd) { - int guild_id; - int len; - - RFIFOHEAD(fd); - guild_id = RFIFOL(fd,8); - len = RFIFOW(fd,2); - - if( sizeof(struct guild_storage) != len - 12 ) - { - ShowError("inter storage: data size error %d != %d\n", sizeof(struct guild_storage), len - 12); - } - else - { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id) ) - Sql_ShowDebug(sql_handle); - else if( Sql_NumRows(sql_handle) > 0 ) - {// guild exists - Sql_FreeResult(sql_handle); - guild_storage_tosql(guild_id, (struct guild_storage*)RFIFOP(fd,12)); - mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 0); - return 0; - } - Sql_FreeResult(sql_handle); - } - mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 1); - return 0; + int guild_id; + int len; + + RFIFOHEAD(fd); + guild_id = RFIFOL(fd,8); + len = RFIFOW(fd,2); + + if (sizeof(struct guild_storage) != len - 12) { + ShowError("inter storage: data size error %d != %d\n", sizeof(struct guild_storage), len - 12); + } else { + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id)) + Sql_ShowDebug(sql_handle); + else if (Sql_NumRows(sql_handle) > 0) { + // guild exists + Sql_FreeResult(sql_handle); + guild_storage_tosql(guild_id, (struct guild_storage *)RFIFOP(fd,12)); + mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 0); + return 0; + } + Sql_FreeResult(sql_handle); + } + mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 1); + return 0; } int inter_storage_parse_frommap(int fd) { - RFIFOHEAD(fd); - switch(RFIFOW(fd,0)){ - case 0x3018: mapif_parse_LoadGuildStorage(fd); break; - case 0x3019: mapif_parse_SaveGuildStorage(fd); break; - default: - return 0; - } - return 1; + RFIFOHEAD(fd); + switch (RFIFOW(fd,0)) { + case 0x3018: + mapif_parse_LoadGuildStorage(fd); + break; + case 0x3019: + mapif_parse_SaveGuildStorage(fd); + break; + default: + return 0; + } + return 1; } diff --git a/src/char/int_storage.h b/src/char/int_storage.h index 811608f82..6285a8d21 100644 --- a/src/char/int_storage.h +++ b/src/char/int_storage.h @@ -15,7 +15,7 @@ int inter_guild_storage_delete(int guild_id); int inter_storage_parse_frommap(int fd); //Exported for use in the TXT-SQL converter. -int storage_fromsql(int account_id, struct storage_data* p); +int storage_fromsql(int account_id, struct storage_data *p); int storage_tosql(int account_id,struct storage_data *p); int guild_storage_tosql(int guild_id, struct guild_storage *p); diff --git a/src/char/inter.c b/src/char/inter.c index 8863b41d8..9b33d271e 100644 --- a/src/char/inter.c +++ b/src/char/inter.c @@ -28,11 +28,11 @@ #include // for stat/lstat/fstat - [Dekamaster/Ultimate GM Tool] -#define WISDATA_TTL (60*1000) //Wis data Time To Live (60 seconds) -#define WISDELLIST_MAX 256 // Number of elements in the list Delete data Wis +#define WISDATA_TTL (60*1000) //Wis data Time To Live (60 seconds) +#define WISDELLIST_MAX 256 // Number of elements in the list Delete data Wis -Sql* sql_handle = NULL; +Sql *sql_handle = NULL; int char_server_port = 3306; char char_server_ip[32] = "127.0.0.1"; @@ -47,778 +47,800 @@ char main_chat_nick[16] = "Main"; // recv. packet list int inter_recv_packet_length[] = { - -1,-1, 7,-1, -1,13,36, (2 + 4 + 4 + 4 + NAME_LENGTH), 0, 0, 0, 0, 0, 0, 0, 0, // 3000- - 6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, // 3010- - -1,10,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, // 3020- Party - -1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1, // 3030- - -1, 9, 0, 0, 0, 0, 0, 0, 7, 6,10,10, 10,-1, 0, 0, // 3040- - -1,-1,10,10, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3050- Auction System [Zephyrus] - 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3060- Quest system [Kevin] [Inkfish] - -1,10, 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, -1,10, 6,-1, // 3070- Mercenary packets [Zephyrus], Elemental packets [pakpil] - 48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3080- - -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3090- Homunculus packets [albator] + -1,-1, 7,-1, -1,13,36, (2 + 4 + 4 + 4 + NAME_LENGTH), 0, 0, 0, 0, 0, 0, 0, 0, // 3000- + 6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, // 3010- + -1,10,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, // 3020- Party + -1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1, // 3030- + -1, 9, 0, 0, 0, 0, 0, 0, 7, 6,10,10, 10,-1, 0, 0, // 3040- + -1,-1,10,10, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3050- Auction System [Zephyrus] + 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3060- Quest system [Kevin] [Inkfish] + -1,10, 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, -1,10, 6,-1, // 3070- Mercenary packets [Zephyrus], Elemental packets [pakpil] + 48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3080- + -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3090- Homunculus packets [albator] }; struct WisData { - int id, fd, count, len; - unsigned long tick; - unsigned char src[24], dst[24], msg[512]; + int id, fd, count, len; + unsigned long tick; + unsigned char src[24], dst[24], msg[512]; }; -static DBMap* wis_db = NULL; // int wis_id -> struct WisData* +static DBMap *wis_db = NULL; // int wis_id -> struct WisData* static int wis_dellist[WISDELLIST_MAX], wis_delnum; #define MAX_JOB_NAMES 106 -static char* msg_table[MAX_JOB_NAMES]; // messages 550 ~ 655 are job names +static char *msg_table[MAX_JOB_NAMES]; // messages 550 ~ 655 are job names -const char* msg_txt(int msg_number) { - msg_number -= 550; - if (msg_number >= 0 && msg_number < MAX_JOB_NAMES && - msg_table[msg_number] != NULL && msg_table[msg_number][0] != '\0') - return msg_table[msg_number]; +const char *msg_txt(int msg_number) +{ + msg_number -= 550; + if (msg_number >= 0 && msg_number < MAX_JOB_NAMES && + msg_table[msg_number] != NULL && msg_table[msg_number][0] != '\0') + return msg_table[msg_number]; - return "Unknown"; + return "Unknown"; } /*========================================== * Read Message Data -- at char server we only keep job names. *------------------------------------------*/ -int msg_config_read(const char* cfgName) { - int msg_number; - char line[1024], w1[1024], w2[1024]; - FILE *fp; - static int called = 1; - - if ((fp = fopen(cfgName, "r")) == NULL) { - ShowError("Messages file not found: %s\n", cfgName); - return 1; - } - - if ((--called) == 0) - memset(msg_table, 0, sizeof(msg_table[0]) * MAX_JOB_NAMES); - - while(fgets(line, sizeof(line), fp) ) { - if (line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - if (strcmpi(w1, "import") == 0) - msg_config_read(w2); - else { - msg_number = atoi(w1); - if( msg_number < 550 || msg_number > (550+MAX_JOB_NAMES) ) - continue; - msg_number -= 550; - if (msg_number >= 0 && msg_number < MAX_JOB_NAMES) { - if (msg_table[msg_number] != NULL) - aFree(msg_table[msg_number]); - msg_table[msg_number] = (char *)aMalloc((strlen(w2) + 1)*sizeof (char)); - strcpy(msg_table[msg_number],w2); - } - } - } - - fclose(fp); - - return 0; +int msg_config_read(const char *cfgName) +{ + int msg_number; + char line[1024], w1[1024], w2[1024]; + FILE *fp; + static int called = 1; + + if ((fp = fopen(cfgName, "r")) == NULL) { + ShowError("Messages file not found: %s\n", cfgName); + return 1; + } + + if ((--called) == 0) + memset(msg_table, 0, sizeof(msg_table[0]) * MAX_JOB_NAMES); + + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') + continue; + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + if (strcmpi(w1, "import") == 0) + msg_config_read(w2); + else { + msg_number = atoi(w1); + if (msg_number < 550 || msg_number > (550+MAX_JOB_NAMES)) + continue; + msg_number -= 550; + if (msg_number >= 0 && msg_number < MAX_JOB_NAMES) { + if (msg_table[msg_number] != NULL) + aFree(msg_table[msg_number]); + msg_table[msg_number] = (char *)aMalloc((strlen(w2) + 1)*sizeof(char)); + strcpy(msg_table[msg_number],w2); + } + } + } + + fclose(fp); + + return 0; } /*========================================== * Cleanup Message Data *------------------------------------------*/ -void do_final_msg(void) { - int i; - for (i = 0; i < MAX_JOB_NAMES; i++) - aFree(msg_table[i]); +void do_final_msg(void) +{ + int i; + for (i = 0; i < MAX_JOB_NAMES; i++) + aFree(msg_table[i]); } /* from pc.c due to @accinfo. any ideas to replace this crap are more than welcome. */ -const char* job_name(int class_) { - switch (class_) { - case JOB_NOVICE: - case JOB_SWORDMAN: - case JOB_MAGE: - case JOB_ARCHER: - case JOB_ACOLYTE: - case JOB_MERCHANT: - case JOB_THIEF: - return msg_txt(550 - JOB_NOVICE+class_); - - case JOB_KNIGHT: - case JOB_PRIEST: - case JOB_WIZARD: - case JOB_BLACKSMITH: - case JOB_HUNTER: - case JOB_ASSASSIN: - return msg_txt(557 - JOB_KNIGHT+class_); - - case JOB_KNIGHT2: - return msg_txt(557); - - case JOB_CRUSADER: - case JOB_MONK: - case JOB_SAGE: - case JOB_ROGUE: - case JOB_ALCHEMIST: - case JOB_BARD: - case JOB_DANCER: - return msg_txt(563 - JOB_CRUSADER+class_); - - case JOB_CRUSADER2: - return msg_txt(563); - - case JOB_WEDDING: - case JOB_SUPER_NOVICE: - case JOB_GUNSLINGER: - case JOB_NINJA: - case JOB_XMAS: - return msg_txt(570 - JOB_WEDDING+class_); - - case JOB_SUMMER: - return msg_txt(621); - - case JOB_NOVICE_HIGH: - case JOB_SWORDMAN_HIGH: - case JOB_MAGE_HIGH: - case JOB_ARCHER_HIGH: - case JOB_ACOLYTE_HIGH: - case JOB_MERCHANT_HIGH: - case JOB_THIEF_HIGH: - return msg_txt(575 - JOB_NOVICE_HIGH+class_); - - case JOB_LORD_KNIGHT: - case JOB_HIGH_PRIEST: - case JOB_HIGH_WIZARD: - case JOB_WHITESMITH: - case JOB_SNIPER: - case JOB_ASSASSIN_CROSS: - return msg_txt(582 - JOB_LORD_KNIGHT+class_); - - case JOB_LORD_KNIGHT2: - return msg_txt(582); - - case JOB_PALADIN: - case JOB_CHAMPION: - case JOB_PROFESSOR: - case JOB_STALKER: - case JOB_CREATOR: - case JOB_CLOWN: - case JOB_GYPSY: - return msg_txt(588 - JOB_PALADIN + class_); - - case JOB_PALADIN2: - return msg_txt(588); - - case JOB_BABY: - case JOB_BABY_SWORDMAN: - case JOB_BABY_MAGE: - case JOB_BABY_ARCHER: - case JOB_BABY_ACOLYTE: - case JOB_BABY_MERCHANT: - case JOB_BABY_THIEF: - return msg_txt(595 - JOB_BABY + class_); - - case JOB_BABY_KNIGHT: - case JOB_BABY_PRIEST: - case JOB_BABY_WIZARD: - case JOB_BABY_BLACKSMITH: - case JOB_BABY_HUNTER: - case JOB_BABY_ASSASSIN: - return msg_txt(602 - JOB_BABY_KNIGHT + class_); - - case JOB_BABY_KNIGHT2: - return msg_txt(602); - - case JOB_BABY_CRUSADER: - case JOB_BABY_MONK: - case JOB_BABY_SAGE: - case JOB_BABY_ROGUE: - case JOB_BABY_ALCHEMIST: - case JOB_BABY_BARD: - case JOB_BABY_DANCER: - return msg_txt(608 - JOB_BABY_CRUSADER + class_); - - case JOB_BABY_CRUSADER2: - return msg_txt(608); - - case JOB_SUPER_BABY: - return msg_txt(615); - - case JOB_TAEKWON: - return msg_txt(616); - case JOB_STAR_GLADIATOR: - case JOB_STAR_GLADIATOR2: - return msg_txt(617); - case JOB_SOUL_LINKER: - return msg_txt(618); - - case JOB_GANGSI: - case JOB_DEATH_KNIGHT: - case JOB_DARK_COLLECTOR: - return msg_txt(622 - JOB_GANGSI+class_); - - case JOB_RUNE_KNIGHT: - case JOB_WARLOCK: - case JOB_RANGER: - case JOB_ARCH_BISHOP: - case JOB_MECHANIC: - case JOB_GUILLOTINE_CROSS: - return msg_txt(625 - JOB_RUNE_KNIGHT+class_); - - case JOB_RUNE_KNIGHT_T: - case JOB_WARLOCK_T: - case JOB_RANGER_T: - case JOB_ARCH_BISHOP_T: - case JOB_MECHANIC_T: - case JOB_GUILLOTINE_CROSS_T: - return msg_txt(625 - JOB_RUNE_KNIGHT_T+class_); - - case JOB_ROYAL_GUARD: - case JOB_SORCERER: - case JOB_MINSTREL: - case JOB_WANDERER: - case JOB_SURA: - case JOB_GENETIC: - case JOB_SHADOW_CHASER: - return msg_txt(631 - JOB_ROYAL_GUARD+class_); - - case JOB_ROYAL_GUARD_T: - case JOB_SORCERER_T: - case JOB_MINSTREL_T: - case JOB_WANDERER_T: - case JOB_SURA_T: - case JOB_GENETIC_T: - case JOB_SHADOW_CHASER_T: - return msg_txt(631 - JOB_ROYAL_GUARD_T+class_); - - case JOB_RUNE_KNIGHT2: - case JOB_RUNE_KNIGHT_T2: - return msg_txt(625); - - case JOB_ROYAL_GUARD2: - case JOB_ROYAL_GUARD_T2: - return msg_txt(631); - - case JOB_RANGER2: - case JOB_RANGER_T2: - return msg_txt(627); - - case JOB_MECHANIC2: - case JOB_MECHANIC_T2: - return msg_txt(629); - - case JOB_BABY_RUNE: - case JOB_BABY_WARLOCK: - case JOB_BABY_RANGER: - case JOB_BABY_BISHOP: - case JOB_BABY_MECHANIC: - case JOB_BABY_CROSS: - case JOB_BABY_GUARD: - case JOB_BABY_SORCERER: - case JOB_BABY_MINSTREL: - case JOB_BABY_WANDERER: - case JOB_BABY_SURA: - case JOB_BABY_GENETIC: - case JOB_BABY_CHASER: - return msg_txt(638 - JOB_BABY_RUNE+class_); - - case JOB_BABY_RUNE2: - return msg_txt(638); - - case JOB_BABY_GUARD2: - return msg_txt(644); - - case JOB_BABY_RANGER2: - return msg_txt(640); - - case JOB_BABY_MECHANIC2: - return msg_txt(642); - - case JOB_SUPER_NOVICE_E: - case JOB_SUPER_BABY_E: - return msg_txt(651 - JOB_SUPER_NOVICE_E+class_); - - case JOB_KAGEROU: - case JOB_OBORO: - return msg_txt(653 - JOB_KAGEROU+class_); - - default: - return msg_txt(655); - } +const char *job_name(int class_) +{ + switch (class_) { + case JOB_NOVICE: + case JOB_SWORDMAN: + case JOB_MAGE: + case JOB_ARCHER: + case JOB_ACOLYTE: + case JOB_MERCHANT: + case JOB_THIEF: + return msg_txt(550 - JOB_NOVICE+class_); + + case JOB_KNIGHT: + case JOB_PRIEST: + case JOB_WIZARD: + case JOB_BLACKSMITH: + case JOB_HUNTER: + case JOB_ASSASSIN: + return msg_txt(557 - JOB_KNIGHT+class_); + + case JOB_KNIGHT2: + return msg_txt(557); + + case JOB_CRUSADER: + case JOB_MONK: + case JOB_SAGE: + case JOB_ROGUE: + case JOB_ALCHEMIST: + case JOB_BARD: + case JOB_DANCER: + return msg_txt(563 - JOB_CRUSADER+class_); + + case JOB_CRUSADER2: + return msg_txt(563); + + case JOB_WEDDING: + case JOB_SUPER_NOVICE: + case JOB_GUNSLINGER: + case JOB_NINJA: + case JOB_XMAS: + return msg_txt(570 - JOB_WEDDING+class_); + + case JOB_SUMMER: + return msg_txt(621); + + case JOB_NOVICE_HIGH: + case JOB_SWORDMAN_HIGH: + case JOB_MAGE_HIGH: + case JOB_ARCHER_HIGH: + case JOB_ACOLYTE_HIGH: + case JOB_MERCHANT_HIGH: + case JOB_THIEF_HIGH: + return msg_txt(575 - JOB_NOVICE_HIGH+class_); + + case JOB_LORD_KNIGHT: + case JOB_HIGH_PRIEST: + case JOB_HIGH_WIZARD: + case JOB_WHITESMITH: + case JOB_SNIPER: + case JOB_ASSASSIN_CROSS: + return msg_txt(582 - JOB_LORD_KNIGHT+class_); + + case JOB_LORD_KNIGHT2: + return msg_txt(582); + + case JOB_PALADIN: + case JOB_CHAMPION: + case JOB_PROFESSOR: + case JOB_STALKER: + case JOB_CREATOR: + case JOB_CLOWN: + case JOB_GYPSY: + return msg_txt(588 - JOB_PALADIN + class_); + + case JOB_PALADIN2: + return msg_txt(588); + + case JOB_BABY: + case JOB_BABY_SWORDMAN: + case JOB_BABY_MAGE: + case JOB_BABY_ARCHER: + case JOB_BABY_ACOLYTE: + case JOB_BABY_MERCHANT: + case JOB_BABY_THIEF: + return msg_txt(595 - JOB_BABY + class_); + + case JOB_BABY_KNIGHT: + case JOB_BABY_PRIEST: + case JOB_BABY_WIZARD: + case JOB_BABY_BLACKSMITH: + case JOB_BABY_HUNTER: + case JOB_BABY_ASSASSIN: + return msg_txt(602 - JOB_BABY_KNIGHT + class_); + + case JOB_BABY_KNIGHT2: + return msg_txt(602); + + case JOB_BABY_CRUSADER: + case JOB_BABY_MONK: + case JOB_BABY_SAGE: + case JOB_BABY_ROGUE: + case JOB_BABY_ALCHEMIST: + case JOB_BABY_BARD: + case JOB_BABY_DANCER: + return msg_txt(608 - JOB_BABY_CRUSADER + class_); + + case JOB_BABY_CRUSADER2: + return msg_txt(608); + + case JOB_SUPER_BABY: + return msg_txt(615); + + case JOB_TAEKWON: + return msg_txt(616); + case JOB_STAR_GLADIATOR: + case JOB_STAR_GLADIATOR2: + return msg_txt(617); + case JOB_SOUL_LINKER: + return msg_txt(618); + + case JOB_GANGSI: + case JOB_DEATH_KNIGHT: + case JOB_DARK_COLLECTOR: + return msg_txt(622 - JOB_GANGSI+class_); + + case JOB_RUNE_KNIGHT: + case JOB_WARLOCK: + case JOB_RANGER: + case JOB_ARCH_BISHOP: + case JOB_MECHANIC: + case JOB_GUILLOTINE_CROSS: + return msg_txt(625 - JOB_RUNE_KNIGHT+class_); + + case JOB_RUNE_KNIGHT_T: + case JOB_WARLOCK_T: + case JOB_RANGER_T: + case JOB_ARCH_BISHOP_T: + case JOB_MECHANIC_T: + case JOB_GUILLOTINE_CROSS_T: + return msg_txt(625 - JOB_RUNE_KNIGHT_T+class_); + + case JOB_ROYAL_GUARD: + case JOB_SORCERER: + case JOB_MINSTREL: + case JOB_WANDERER: + case JOB_SURA: + case JOB_GENETIC: + case JOB_SHADOW_CHASER: + return msg_txt(631 - JOB_ROYAL_GUARD+class_); + + case JOB_ROYAL_GUARD_T: + case JOB_SORCERER_T: + case JOB_MINSTREL_T: + case JOB_WANDERER_T: + case JOB_SURA_T: + case JOB_GENETIC_T: + case JOB_SHADOW_CHASER_T: + return msg_txt(631 - JOB_ROYAL_GUARD_T+class_); + + case JOB_RUNE_KNIGHT2: + case JOB_RUNE_KNIGHT_T2: + return msg_txt(625); + + case JOB_ROYAL_GUARD2: + case JOB_ROYAL_GUARD_T2: + return msg_txt(631); + + case JOB_RANGER2: + case JOB_RANGER_T2: + return msg_txt(627); + + case JOB_MECHANIC2: + case JOB_MECHANIC_T2: + return msg_txt(629); + + case JOB_BABY_RUNE: + case JOB_BABY_WARLOCK: + case JOB_BABY_RANGER: + case JOB_BABY_BISHOP: + case JOB_BABY_MECHANIC: + case JOB_BABY_CROSS: + case JOB_BABY_GUARD: + case JOB_BABY_SORCERER: + case JOB_BABY_MINSTREL: + case JOB_BABY_WANDERER: + case JOB_BABY_SURA: + case JOB_BABY_GENETIC: + case JOB_BABY_CHASER: + return msg_txt(638 - JOB_BABY_RUNE+class_); + + case JOB_BABY_RUNE2: + return msg_txt(638); + + case JOB_BABY_GUARD2: + return msg_txt(644); + + case JOB_BABY_RANGER2: + return msg_txt(640); + + case JOB_BABY_MECHANIC2: + return msg_txt(642); + + case JOB_SUPER_NOVICE_E: + case JOB_SUPER_BABY_E: + return msg_txt(651 - JOB_SUPER_NOVICE_E+class_); + + case JOB_KAGEROU: + case JOB_OBORO: + return msg_txt(653 - JOB_KAGEROU+class_); + + default: + return msg_txt(655); + } } /** * [Dekamaster/Nightroad] **/ -const char * geoip_countryname[253] = {"Unknown","Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles", - "Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados", - "Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia", - "Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the", - "Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica", - "Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic", - "Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji", - "Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana", - "Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala", - "Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia", - "Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan", - "Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait", - "Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania", - "Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali", - "Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives", - "Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua", - "Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia", - "Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau", - "Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan", - "Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname", - "Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand", - "Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan", - "Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines","Venezuela", - "Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa", - "Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey", - "Saint Barthelemy","Saint Martin"}; +const char *geoip_countryname[253] = {"Unknown","Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles", + "Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados", + "Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia", + "Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the", + "Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica", + "Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic", + "Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji", + "Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana", + "Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala", + "Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia", + "Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan", + "Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait", + "Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania", + "Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali", + "Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives", + "Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua", + "Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia", + "Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau", + "Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan", + "Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname", + "Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand", + "Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan", + "Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines","Venezuela", + "Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa", + "Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey", + "Saint Barthelemy","Saint Martin" + }; unsigned char *geoip_cache; -void geoip_readdb(void){ - struct stat bufa; - FILE *db=fopen("./db/GeoIP.dat","rb"); - fstat(fileno(db), &bufa); - geoip_cache = (unsigned char *) malloc(sizeof(unsigned char) * bufa.st_size); - if(fread(geoip_cache, sizeof(unsigned char), bufa.st_size, db) != bufa.st_size) { ShowError("geoip_cache reading didn't read all elements \n"); } - fclose(db); - ShowStatus("Finished Reading "CL_GREEN"GeoIP"CL_RESET" Database.\n"); +void geoip_readdb(void) +{ + struct stat bufa; + FILE *db=fopen("./db/GeoIP.dat","rb"); + fstat(fileno(db), &bufa); + geoip_cache = (unsigned char *) malloc(sizeof(unsigned char) * bufa.st_size); + if (fread(geoip_cache, sizeof(unsigned char), bufa.st_size, db) != bufa.st_size) { + ShowError("geoip_cache reading didn't read all elements \n"); + } + fclose(db); + ShowStatus("Finished Reading "CL_GREEN"GeoIP"CL_RESET" Database.\n"); } /* [Dekamaster/Nightroad] */ /* WHY NOT A DBMAP: There are millions of entries in GeoIP and it has its own algorithm to go quickly through them, a DBMap wouldn't be efficient */ -const char* geoip_getcountry(uint32 ipnum){ - int depth; - unsigned int x; - const unsigned char *buf; - unsigned int offset = 0; - - for (depth = 31; depth >= 0; depth--) { - buf = geoip_cache + (long)6 *offset; - if (ipnum & (1 << depth)) { - /* Take the right-hand branch */ - x = (buf[3*1 + 0] << (0*8)) - + (buf[3*1 + 1] << (1*8)) - + (buf[3*1 + 2] << (2*8)); - } else { - /* Take the left-hand branch */ - x = (buf[3*0 + 0] << (0*8)) - + (buf[3*0 + 1] << (1*8)) - + (buf[3*0 + 2] << (2*8)); - } - if (x >= 16776960) { - x=x-16776960; - return geoip_countryname[x]; - } - offset = x; - } - return geoip_countryname[0]; +const char *geoip_getcountry(uint32 ipnum) +{ + int depth; + unsigned int x; + const unsigned char *buf; + unsigned int offset = 0; + + for (depth = 31; depth >= 0; depth--) { + buf = geoip_cache + (long)6 *offset; + if (ipnum & (1 << depth)) { + /* Take the right-hand branch */ + x = (buf[3*1 + 0] << (0*8)) + + (buf[3*1 + 1] << (1*8)) + + (buf[3*1 + 2] << (2*8)); + } else { + /* Take the left-hand branch */ + x = (buf[3*0 + 0] << (0*8)) + + (buf[3*0 + 1] << (1*8)) + + (buf[3*0 + 2] << (2*8)); + } + if (x >= 16776960) { + x=x-16776960; + return geoip_countryname[x]; + } + offset = x; + } + return geoip_countryname[0]; } /* sends a mesasge to map server (fd) to a user (u_fd) although we use fd we keep aid for safe-check */ /* extremely handy I believe it will serve other uses in the near future */ -void inter_to_fd(int fd, int u_fd, int aid, char* msg, ...) { - char msg_out[512]; - va_list ap; - int len = 1;/* yes we start at 1 */ +void inter_to_fd(int fd, int u_fd, int aid, char *msg, ...) +{ + char msg_out[512]; + va_list ap; + int len = 1;/* yes we start at 1 */ - va_start(ap,msg); - len += vsnprintf(msg_out, 512, msg, ap); - va_end(ap); + va_start(ap,msg); + len += vsnprintf(msg_out, 512, msg, ap); + va_end(ap); - WFIFOHEAD(fd,12 + len); + WFIFOHEAD(fd,12 + len); - WFIFOW(fd,0) = 0x3807; - WFIFOW(fd,2) = 12 + (unsigned short)len; - WFIFOL(fd,4) = u_fd; - WFIFOL(fd,8) = aid; - safestrncpy((char*)WFIFOP(fd,12), msg_out, len); + WFIFOW(fd,0) = 0x3807; + WFIFOW(fd,2) = 12 + (unsigned short)len; + WFIFOL(fd,4) = u_fd; + WFIFOL(fd,8) = aid; + safestrncpy((char *)WFIFOP(fd,12), msg_out, len); - WFIFOSET(fd,12 + len); + WFIFOSET(fd,12 + len); - return; + return; } /* [Dekamaster/Nightroad] */ -void mapif_parse_accinfo(int fd) { - int u_fd = RFIFOL(fd,2), aid = RFIFOL(fd,6), castergroup = RFIFOL(fd,10); - char query[NAME_LENGTH], query_esq[NAME_LENGTH*2+1]; - int account_id; - char *data; - - safestrncpy(query, (char*) RFIFOP(fd,14), NAME_LENGTH); - - Sql_EscapeString(sql_handle, query_esq, query); - - account_id = atoi(query); - - if (account_id < START_ACCOUNT_NUM) { // is string - if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name`,`class`,`base_level`,`job_level`,`online` FROM `char` WHERE `name` LIKE '%s' LIMIT 10", query_esq) - || Sql_NumRows(sql_handle) == 0 ) { - if( Sql_NumRows(sql_handle) == 0 ) { - inter_to_fd(fd, u_fd, aid, "No matches were found for your criteria, '%s'",query); - } else { - Sql_ShowDebug(sql_handle); - inter_to_fd(fd, u_fd, aid, "An error occured, bother your admin about it."); - } - Sql_FreeResult(sql_handle); - return; - } else { - if( Sql_NumRows(sql_handle) == 1 ) {//we found a perfect match - Sql_NextRow(sql_handle); - Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data); - Sql_FreeResult(sql_handle); - } else {// more than one, listing... [Dekamaster/Nightroad] - inter_to_fd(fd, u_fd, aid, "Your query returned the following %d results, please be more specific...",(int)Sql_NumRows(sql_handle)); - while ( SQL_SUCCESS == Sql_NextRow(sql_handle) ) { - int class_; - short base_level, job_level, online; - char name[NAME_LENGTH]; - - Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); - Sql_GetData(sql_handle, 2, &data, NULL); class_ = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); base_level = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); job_level = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); online = atoi(data); - - inter_to_fd(fd, u_fd, aid, "[AID: %d] %s | %s | Level: %d/%d | %s", account_id, name, job_name(class_), base_level, job_level, online?"Online":"Offline"); - } - Sql_FreeResult(sql_handle); - return; - } - } - } - - /* it will only get here if we have a single match */ - if( account_id ) { - char userid[NAME_LENGTH], user_pass[NAME_LENGTH], email[40], last_ip[20], lastlogin[30]; - short level = -1; - int logincount = 0,state = 0; - if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `userid`, `user_pass`, `email`, `last_ip`, `group_id`, `lastlogin`, `logincount`, `state` FROM `login` WHERE `account_id` = '%d' LIMIT 1", account_id) - || Sql_NumRows(sql_handle) == 0 ) { - if( Sql_NumRows(sql_handle) == 0 ) { - inter_to_fd(fd, u_fd, aid, "No account with ID '%d' was found.", account_id ); - } else { - inter_to_fd(fd, u_fd, aid, "An error occured, bother your admin about it."); - Sql_ShowDebug(sql_handle); - } - } else { - Sql_NextRow(sql_handle); - Sql_GetData(sql_handle, 0, &data, NULL); safestrncpy(userid, data, sizeof(userid)); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(user_pass, data, sizeof(user_pass)); - Sql_GetData(sql_handle, 2, &data, NULL); safestrncpy(email, data, sizeof(email)); - Sql_GetData(sql_handle, 3, &data, NULL); safestrncpy(last_ip, data, sizeof(last_ip)); - Sql_GetData(sql_handle, 4, &data, NULL); level = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); safestrncpy(lastlogin, data, sizeof(lastlogin)); - Sql_GetData(sql_handle, 6, &data, NULL); logincount = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); state = atoi(data); - } - - Sql_FreeResult(sql_handle); - - if (level == -1) - return; - - inter_to_fd(fd, u_fd, aid, "-- Account %d --", account_id ); - inter_to_fd(fd, u_fd, aid, "User: %s | GM Group: %d | State: %d", userid, level, state ); - - if (level < castergroup) /* only show pass if your gm level is greater than the one you're searching for */ - inter_to_fd(fd, u_fd, aid, "Password: %s", user_pass ); - - inter_to_fd(fd, u_fd, aid, "Account e-mail: %s", email); - inter_to_fd(fd, u_fd, aid, "Last IP: %s (%s)", last_ip, geoip_getcountry(str2ip(last_ip)) ); - inter_to_fd(fd, u_fd, aid, "This user has logged %d times, the last time were at %s", logincount, lastlogin ); - inter_to_fd(fd, u_fd, aid, "-- Character Details --" ); - - - if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`, `name`, `char_num`, `class`, `base_level`, `job_level`, `online` FROM `char` WHERE `account_id` = '%d' ORDER BY `char_num` LIMIT %d", account_id, MAX_CHARS) - || Sql_NumRows(sql_handle) == 0 ) { - - if( Sql_NumRows(sql_handle) == 0 ) - inter_to_fd(fd, u_fd, aid,"This account doesn't have characters."); - else { - inter_to_fd(fd, u_fd, aid,"An error occured, bother your admin about it."); - Sql_ShowDebug(sql_handle); - } - - } else { - while ( SQL_SUCCESS == Sql_NextRow(sql_handle) ) { - int char_id, class_; - short char_num, base_level, job_level, online; - char name[NAME_LENGTH]; - - Sql_GetData(sql_handle, 0, &data, NULL); char_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); - Sql_GetData(sql_handle, 2, &data, NULL); char_num = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); class_ = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); base_level = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); job_level = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); online = atoi(data); - - inter_to_fd(fd, u_fd, aid, "[Slot/CID: %d/%d] %s | %s | Level: %d/%d | %s", char_num, char_id, name, job_name(class_), base_level, job_level, online?"On":"Off"); - } - } - Sql_FreeResult(sql_handle); - } - - return; +void mapif_parse_accinfo(int fd) +{ + int u_fd = RFIFOL(fd,2), aid = RFIFOL(fd,6), castergroup = RFIFOL(fd,10); + char query[NAME_LENGTH], query_esq[NAME_LENGTH*2+1]; + int account_id; + char *data; + + safestrncpy(query, (char *) RFIFOP(fd,14), NAME_LENGTH); + + Sql_EscapeString(sql_handle, query_esq, query); + + account_id = atoi(query); + + if (account_id < START_ACCOUNT_NUM) { // is string + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name`,`class`,`base_level`,`job_level`,`online` FROM `char` WHERE `name` LIKE '%s' LIMIT 10", query_esq) + || Sql_NumRows(sql_handle) == 0) { + if (Sql_NumRows(sql_handle) == 0) { + inter_to_fd(fd, u_fd, aid, "No matches were found for your criteria, '%s'",query); + } else { + Sql_ShowDebug(sql_handle); + inter_to_fd(fd, u_fd, aid, "An error occured, bother your admin about it."); + } + Sql_FreeResult(sql_handle); + return; + } else { + if (Sql_NumRows(sql_handle) == 1) { //we found a perfect match + Sql_NextRow(sql_handle); + Sql_GetData(sql_handle, 0, &data, NULL); + account_id = atoi(data); + Sql_FreeResult(sql_handle); + } else {// more than one, listing... [Dekamaster/Nightroad] + inter_to_fd(fd, u_fd, aid, "Your query returned the following %d results, please be more specific...",(int)Sql_NumRows(sql_handle)); + while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + int class_; + short base_level, job_level, online; + char name[NAME_LENGTH]; + + Sql_GetData(sql_handle, 0, &data, NULL); + account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + safestrncpy(name, data, sizeof(name)); + Sql_GetData(sql_handle, 2, &data, NULL); + class_ = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + base_level = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + job_level = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + online = atoi(data); + + inter_to_fd(fd, u_fd, aid, "[AID: %d] %s | %s | Level: %d/%d | %s", account_id, name, job_name(class_), base_level, job_level, online?"Online":"Offline"); + } + Sql_FreeResult(sql_handle); + return; + } + } + } + + /* it will only get here if we have a single match */ + if (account_id) { + char userid[NAME_LENGTH], user_pass[NAME_LENGTH], email[40], last_ip[20], lastlogin[30]; + short level = -1; + int logincount = 0,state = 0; + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `userid`, `user_pass`, `email`, `last_ip`, `group_id`, `lastlogin`, `logincount`, `state` FROM `login` WHERE `account_id` = '%d' LIMIT 1", account_id) + || Sql_NumRows(sql_handle) == 0) { + if (Sql_NumRows(sql_handle) == 0) { + inter_to_fd(fd, u_fd, aid, "No account with ID '%d' was found.", account_id); + } else { + inter_to_fd(fd, u_fd, aid, "An error occured, bother your admin about it."); + Sql_ShowDebug(sql_handle); + } + } else { + Sql_NextRow(sql_handle); + Sql_GetData(sql_handle, 0, &data, NULL); + safestrncpy(userid, data, sizeof(userid)); + Sql_GetData(sql_handle, 1, &data, NULL); + safestrncpy(user_pass, data, sizeof(user_pass)); + Sql_GetData(sql_handle, 2, &data, NULL); + safestrncpy(email, data, sizeof(email)); + Sql_GetData(sql_handle, 3, &data, NULL); + safestrncpy(last_ip, data, sizeof(last_ip)); + Sql_GetData(sql_handle, 4, &data, NULL); + level = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + safestrncpy(lastlogin, data, sizeof(lastlogin)); + Sql_GetData(sql_handle, 6, &data, NULL); + logincount = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); + state = atoi(data); + } + + Sql_FreeResult(sql_handle); + + if (level == -1) + return; + + inter_to_fd(fd, u_fd, aid, "-- Account %d --", account_id); + inter_to_fd(fd, u_fd, aid, "User: %s | GM Group: %d | State: %d", userid, level, state); + + if (level < castergroup) /* only show pass if your gm level is greater than the one you're searching for */ + inter_to_fd(fd, u_fd, aid, "Password: %s", user_pass); + + inter_to_fd(fd, u_fd, aid, "Account e-mail: %s", email); + inter_to_fd(fd, u_fd, aid, "Last IP: %s (%s)", last_ip, geoip_getcountry(str2ip(last_ip))); + inter_to_fd(fd, u_fd, aid, "This user has logged %d times, the last time were at %s", logincount, lastlogin); + inter_to_fd(fd, u_fd, aid, "-- Character Details --"); + + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`, `name`, `char_num`, `class`, `base_level`, `job_level`, `online` FROM `char` WHERE `account_id` = '%d' ORDER BY `char_num` LIMIT %d", account_id, MAX_CHARS) + || Sql_NumRows(sql_handle) == 0) { + + if (Sql_NumRows(sql_handle) == 0) + inter_to_fd(fd, u_fd, aid,"This account doesn't have characters."); + else { + inter_to_fd(fd, u_fd, aid,"An error occured, bother your admin about it."); + Sql_ShowDebug(sql_handle); + } + + } else { + while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + int char_id, class_; + short char_num, base_level, job_level, online; + char name[NAME_LENGTH]; + + Sql_GetData(sql_handle, 0, &data, NULL); + char_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + safestrncpy(name, data, sizeof(name)); + Sql_GetData(sql_handle, 2, &data, NULL); + char_num = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); + class_ = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); + base_level = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); + job_level = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + online = atoi(data); + + inter_to_fd(fd, u_fd, aid, "[Slot/CID: %d/%d] %s | %s | Level: %d/%d | %s", char_num, char_id, name, job_name(class_), base_level, job_level, online?"On":"Off"); + } + } + Sql_FreeResult(sql_handle); + } + + return; } //-------------------------------------------------------- // Save registry to sql -int inter_accreg_tosql(int account_id, int char_id, struct accreg* reg, int type) +int inter_accreg_tosql(int account_id, int char_id, struct accreg *reg, int type) { - struct global_reg* r; - StringBuf buf; - int i; - - if( account_id <= 0 ) - return 0; - reg->account_id = account_id; - reg->char_id = char_id; - - //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`) - switch( type ) - { - case 3: //Char Reg - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) ) - Sql_ShowDebug(sql_handle); - account_id = 0; - break; - case 2: //Account Reg - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id) ) - Sql_ShowDebug(sql_handle); - char_id = 0; - break; - case 1: //Account2 Reg - ShowError("inter_accreg_tosql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n"); - return 0; - default: - ShowError("inter_accreg_tosql: Invalid type %d\n", type); - return 0; - } - - if( reg->reg_num <= 0 ) - return 0; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`type`,`account_id`,`char_id`,`str`,`value`) VALUES ", reg_db); - - for( i = 0; i < reg->reg_num; ++i ) { - r = ®->reg[i]; - if( r->str[0] != '\0' && r->value[0] != '\0' ) { - char str[32]; - char val[256]; - - if( i > 0 ) - StringBuf_AppendStr(&buf, ","); - - Sql_EscapeString(sql_handle, str, r->str); - Sql_EscapeString(sql_handle, val, r->value); - - StringBuf_Printf(&buf, "('%d','%d','%d','%s','%s')", type, account_id, char_id, str, val); - } - } - - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) { - Sql_ShowDebug(sql_handle); - } - - StringBuf_Destroy(&buf); - - return 1; + struct global_reg *r; + StringBuf buf; + int i; + + if (account_id <= 0) + return 0; + reg->account_id = account_id; + reg->char_id = char_id; + + //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`) + switch (type) { + case 3: //Char Reg + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id)) + Sql_ShowDebug(sql_handle); + account_id = 0; + break; + case 2: //Account Reg + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id)) + Sql_ShowDebug(sql_handle); + char_id = 0; + break; + case 1: //Account2 Reg + ShowError("inter_accreg_tosql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n"); + return 0; + default: + ShowError("inter_accreg_tosql: Invalid type %d\n", type); + return 0; + } + + if (reg->reg_num <= 0) + return 0; + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`type`,`account_id`,`char_id`,`str`,`value`) VALUES ", reg_db); + + for (i = 0; i < reg->reg_num; ++i) { + r = ®->reg[i]; + if (r->str[0] != '\0' && r->value[0] != '\0') { + char str[32]; + char val[256]; + + if (i > 0) + StringBuf_AppendStr(&buf, ","); + + Sql_EscapeString(sql_handle, str, r->str); + Sql_EscapeString(sql_handle, val, r->value); + + StringBuf_Printf(&buf, "('%d','%d','%d','%s','%s')", type, account_id, char_id, str, val); + } + } + + if (SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf))) { + Sql_ShowDebug(sql_handle); + } + + StringBuf_Destroy(&buf); + + return 1; } // Load account_reg from sql (type=2) int inter_accreg_fromsql(int account_id,int char_id, struct accreg *reg, int type) { - struct global_reg* r; - char* data; - size_t len; - int i; - - if( reg == NULL) - return 0; - - memset(reg, 0, sizeof(struct accreg)); - reg->account_id = account_id; - reg->char_id = char_id; - - //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`) - switch( type ) - { - case 3: //char reg - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) ) - Sql_ShowDebug(sql_handle); - break; - case 2: //account reg - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id) ) - Sql_ShowDebug(sql_handle); - break; - case 1: //account2 reg - ShowError("inter_accreg_fromsql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n"); - return 0; - default: - ShowError("inter_accreg_fromsql: Invalid type %d\n", type); - return 0; - } - for( i = 0; i < MAX_REG_NUM && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - r = ®->reg[i]; - // str - Sql_GetData(sql_handle, 0, &data, &len); - memcpy(r->str, data, min(len, sizeof(r->str))); - // value - Sql_GetData(sql_handle, 1, &data, &len); - memcpy(r->value, data, min(len, sizeof(r->value))); - } - reg->reg_num = i; - Sql_FreeResult(sql_handle); - return 1; + struct global_reg *r; + char *data; + size_t len; + int i; + + if (reg == NULL) + return 0; + + memset(reg, 0, sizeof(struct accreg)); + reg->account_id = account_id; + reg->char_id = char_id; + + //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`) + switch (type) { + case 3: //char reg + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id)) + Sql_ShowDebug(sql_handle); + break; + case 2: //account reg + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id)) + Sql_ShowDebug(sql_handle); + break; + case 1: //account2 reg + ShowError("inter_accreg_fromsql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n"); + return 0; + default: + ShowError("inter_accreg_fromsql: Invalid type %d\n", type); + return 0; + } + for (i = 0; i < MAX_REG_NUM && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i) { + r = ®->reg[i]; + // str + Sql_GetData(sql_handle, 0, &data, &len); + memcpy(r->str, data, min(len, sizeof(r->str))); + // value + Sql_GetData(sql_handle, 1, &data, &len); + memcpy(r->value, data, min(len, sizeof(r->value))); + } + reg->reg_num = i; + Sql_FreeResult(sql_handle); + return 1; } // Initialize int inter_accreg_sql_init(void) { - CREATE(accreg_pt, struct accreg, 1); - return 0; + CREATE(accreg_pt, struct accreg, 1); + return 0; } /*========================================== * read config file *------------------------------------------*/ -static int inter_config_read(const char* cfgName) +static int inter_config_read(const char *cfgName) { - int i; - char line[1024], w1[1024], w2[1024]; - FILE* fp; - - fp = fopen(cfgName, "r"); - if(fp == NULL) { - ShowError("File not found: %s\n", cfgName); - return 1; - } - - while(fgets(line, sizeof(line), fp)) - { - i = sscanf(line, "%[^:]: %[^\r\n]", w1, w2); - if(i != 2) - continue; - - if(!strcmpi(w1,"char_server_ip")) { - strcpy(char_server_ip,w2); - } else - if(!strcmpi(w1,"char_server_port")) { - char_server_port = atoi(w2); - } else - if(!strcmpi(w1,"char_server_id")) { - strcpy(char_server_id,w2); - } else - if(!strcmpi(w1,"char_server_pw")) { - strcpy(char_server_pw,w2); - } else - if(!strcmpi(w1,"char_server_db")) { - strcpy(char_server_db,w2); - } else - if(!strcmpi(w1,"default_codepage")) { - strcpy(default_codepage,w2); - } - else if(!strcmpi(w1,"party_share_level")) - party_share_level = atoi(w2); - else if(!strcmpi(w1,"log_inter")) - log_inter = atoi(w2); - else if(!strcmpi(w1,"main_chat_nick")) - safestrncpy(main_chat_nick, w2, sizeof(main_chat_nick)); - else if(!strcmpi(w1,"import")) - inter_config_read(w2); - } - fclose(fp); - - ShowInfo ("Done reading %s.\n", cfgName); - - return 0; + int i; + char line[1024], w1[1024], w2[1024]; + FILE *fp; + + fp = fopen(cfgName, "r"); + if (fp == NULL) { + ShowError("File not found: %s\n", cfgName); + return 1; + } + + while (fgets(line, sizeof(line), fp)) { + i = sscanf(line, "%[^:]: %[^\r\n]", w1, w2); + if (i != 2) + continue; + + if (!strcmpi(w1,"char_server_ip")) { + strcpy(char_server_ip,w2); + } else if (!strcmpi(w1,"char_server_port")) { + char_server_port = atoi(w2); + } else if (!strcmpi(w1,"char_server_id")) { + strcpy(char_server_id,w2); + } else if (!strcmpi(w1,"char_server_pw")) { + strcpy(char_server_pw,w2); + } else if (!strcmpi(w1,"char_server_db")) { + strcpy(char_server_db,w2); + } else if (!strcmpi(w1,"default_codepage")) { + strcpy(default_codepage,w2); + } else if (!strcmpi(w1,"party_share_level")) + party_share_level = atoi(w2); + else if (!strcmpi(w1,"log_inter")) + log_inter = atoi(w2); + else if (!strcmpi(w1,"main_chat_nick")) + safestrncpy(main_chat_nick, w2, sizeof(main_chat_nick)); + else if (!strcmpi(w1,"import")) + inter_config_read(w2); + } + fclose(fp); + + ShowInfo("Done reading %s.\n", cfgName); + + return 0; } // Save interlog into sql -int inter_log(char* fmt, ...) +int inter_log(char *fmt, ...) { - char str[255]; - char esc_str[sizeof(str)*2+1];// escaped str - va_list ap; + char str[255]; + char esc_str[sizeof(str)*2+1];// escaped str + va_list ap; - va_start(ap,fmt); - vsnprintf(str, sizeof(str), fmt, ap); - va_end(ap); + va_start(ap,fmt); + vsnprintf(str, sizeof(str), fmt, ap); + va_end(ap); - Sql_EscapeStringLen(sql_handle, esc_str, str, strnlen(str, sizeof(str))); - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `log`) VALUES (NOW(), '%s')", interlog_db, esc_str) ) - Sql_ShowDebug(sql_handle); + Sql_EscapeStringLen(sql_handle, esc_str, str, strnlen(str, sizeof(str))); + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `log`) VALUES (NOW(), '%s')", interlog_db, esc_str)) + Sql_ShowDebug(sql_handle); - return 0; + return 0; } // initialize int inter_init_sql(const char *file) { - //int i; - - inter_config_read(file); - - //DB connection initialized - sql_handle = Sql_Malloc(); - ShowInfo("Connect Character DB server.... (Character Server)\n"); - if( SQL_ERROR == Sql_Connect(sql_handle, char_server_id, char_server_pw, char_server_ip, (uint16)char_server_port, char_server_db) ) - { - Sql_ShowDebug(sql_handle); - Sql_Free(sql_handle); - exit(EXIT_FAILURE); - } - - if( *default_codepage ) { - if( SQL_ERROR == Sql_SetEncoding(sql_handle, default_codepage) ) - Sql_ShowDebug(sql_handle); - } - - wis_db = idb_alloc(DB_OPT_RELEASE_DATA); - inter_guild_sql_init(); - inter_storage_sql_init(); - inter_party_sql_init(); - inter_pet_sql_init(); - inter_homunculus_sql_init(); - inter_mercenary_sql_init(); - inter_elemental_sql_init(); - inter_accreg_sql_init(); - inter_mail_sql_init(); - inter_auction_sql_init(); - - geoip_readdb(); - msg_config_read("conf/msg_athena.conf"); - return 0; + //int i; + + inter_config_read(file); + + //DB connection initialized + sql_handle = Sql_Malloc(); + ShowInfo("Connect Character DB server.... (Character Server)\n"); + if (SQL_ERROR == Sql_Connect(sql_handle, char_server_id, char_server_pw, char_server_ip, (uint16)char_server_port, char_server_db)) { + Sql_ShowDebug(sql_handle); + Sql_Free(sql_handle); + exit(EXIT_FAILURE); + } + + if (*default_codepage) { + if (SQL_ERROR == Sql_SetEncoding(sql_handle, default_codepage)) + Sql_ShowDebug(sql_handle); + } + + wis_db = idb_alloc(DB_OPT_RELEASE_DATA); + inter_guild_sql_init(); + inter_storage_sql_init(); + inter_party_sql_init(); + inter_pet_sql_init(); + inter_homunculus_sql_init(); + inter_mercenary_sql_init(); + inter_elemental_sql_init(); + inter_accreg_sql_init(); + inter_mail_sql_init(); + inter_auction_sql_init(); + + geoip_readdb(); + msg_config_read("conf/msg_athena.conf"); + return 0; } // finalize void inter_final(void) { - wis_db->destroy(wis_db, NULL); - - inter_guild_sql_final(); - inter_storage_sql_final(); - inter_party_sql_final(); - inter_pet_sql_final(); - inter_homunculus_sql_final(); - inter_mercenary_sql_final(); - inter_elemental_sql_final(); - inter_mail_sql_final(); - inter_auction_sql_final(); - - if (accreg_pt) aFree(accreg_pt); - - do_final_msg(); - return; + wis_db->destroy(wis_db, NULL); + + inter_guild_sql_final(); + inter_storage_sql_final(); + inter_party_sql_final(); + inter_pet_sql_final(); + inter_homunculus_sql_final(); + inter_mercenary_sql_final(); + inter_elemental_sql_final(); + inter_mail_sql_final(); + inter_auction_sql_final(); + + if (accreg_pt) aFree(accreg_pt); + + do_final_msg(); + return; } int inter_mapif_init(int fd) { - return 0; + return 0; } @@ -827,99 +849,98 @@ int inter_mapif_init(int fd) // broadcast sending int mapif_broadcast(unsigned char *mes, int len, unsigned long fontColor, short fontType, short fontSize, short fontAlign, short fontY, int sfd) { - unsigned char *buf = (unsigned char*)aMalloc((len)*sizeof(unsigned char)); - - WBUFW(buf,0) = 0x3800; - WBUFW(buf,2) = len; - WBUFL(buf,4) = fontColor; - WBUFW(buf,8) = fontType; - WBUFW(buf,10) = fontSize; - WBUFW(buf,12) = fontAlign; - WBUFW(buf,14) = fontY; - memcpy(WBUFP(buf,16), mes, len - 16); - mapif_sendallwos(sfd, buf, len); - - if (buf) - aFree(buf); - return 0; + unsigned char *buf = (unsigned char *)aMalloc((len)*sizeof(unsigned char)); + + WBUFW(buf,0) = 0x3800; + WBUFW(buf,2) = len; + WBUFL(buf,4) = fontColor; + WBUFW(buf,8) = fontType; + WBUFW(buf,10) = fontSize; + WBUFW(buf,12) = fontAlign; + WBUFW(buf,14) = fontY; + memcpy(WBUFP(buf,16), mes, len - 16); + mapif_sendallwos(sfd, buf, len); + + if (buf) + aFree(buf); + return 0; } // Wis sending int mapif_wis_message(struct WisData *wd) { - unsigned char buf[2048]; - if (wd->len > 2047-56) wd->len = 2047-56; //Force it to fit to avoid crashes. [Skotlex] - - WBUFW(buf, 0) = 0x3801; - WBUFW(buf, 2) = 56 +wd->len; - WBUFL(buf, 4) = wd->id; - memcpy(WBUFP(buf, 8), wd->src, NAME_LENGTH); - memcpy(WBUFP(buf,32), wd->dst, NAME_LENGTH); - memcpy(WBUFP(buf,56), wd->msg, wd->len); - wd->count = mapif_sendall(buf,WBUFW(buf,2)); - - return 0; + unsigned char buf[2048]; + if (wd->len > 2047-56) wd->len = 2047-56; //Force it to fit to avoid crashes. [Skotlex] + + WBUFW(buf, 0) = 0x3801; + WBUFW(buf, 2) = 56 +wd->len; + WBUFL(buf, 4) = wd->id; + memcpy(WBUFP(buf, 8), wd->src, NAME_LENGTH); + memcpy(WBUFP(buf,32), wd->dst, NAME_LENGTH); + memcpy(WBUFP(buf,56), wd->msg, wd->len); + wd->count = mapif_sendall(buf,WBUFW(buf,2)); + + return 0; } // Wis sending result int mapif_wis_end(struct WisData *wd, int flag) { - unsigned char buf[27]; + unsigned char buf[27]; - WBUFW(buf, 0)=0x3802; - memcpy(WBUFP(buf, 2),wd->src,24); - WBUFB(buf,26)=flag; - mapif_send(wd->fd,buf,27); - return 0; + WBUFW(buf, 0)=0x3802; + memcpy(WBUFP(buf, 2),wd->src,24); + WBUFB(buf,26)=flag; + mapif_send(wd->fd,buf,27); + return 0; } // Account registry transfer to map-server static void mapif_account_reg(int fd, unsigned char *src) { - WBUFW(src,0)=0x3804; //NOTE: writing to RFIFO - mapif_sendallwos(fd, src, WBUFW(src,2)); + WBUFW(src,0)=0x3804; //NOTE: writing to RFIFO + mapif_sendallwos(fd, src, WBUFW(src,2)); } // Send the requested account_reg int mapif_account_reg_reply(int fd,int account_id,int char_id, int type) { - struct accreg *reg=accreg_pt; - WFIFOHEAD(fd, 13 + 5000); - inter_accreg_fromsql(account_id,char_id,reg,type); - - WFIFOW(fd,0)=0x3804; - WFIFOL(fd,4)=account_id; - WFIFOL(fd,8)=char_id; - WFIFOB(fd,12)=type; - if(reg->reg_num==0){ - WFIFOW(fd,2)=13; - }else{ - int i,p; - for (p=13,i = 0; i < reg->reg_num && p < 5000; i++) { - p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].str)+1; //We add 1 to consider the '\0' in place. - p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].value)+1; - } - WFIFOW(fd,2)=p; - if (p>= 5000) - ShowWarning("Too many acc regs for %d:%d, not all values were loaded.\n", account_id, char_id); - } - WFIFOSET(fd,WFIFOW(fd,2)); - return 0; + struct accreg *reg=accreg_pt; + WFIFOHEAD(fd, 13 + 5000); + inter_accreg_fromsql(account_id,char_id,reg,type); + + WFIFOW(fd,0)=0x3804; + WFIFOL(fd,4)=account_id; + WFIFOL(fd,8)=char_id; + WFIFOB(fd,12)=type; + if (reg->reg_num==0) { + WFIFOW(fd,2)=13; + } else { + int i,p; + for (p=13,i = 0; i < reg->reg_num && p < 5000; i++) { + p+= sprintf((char *)WFIFOP(fd,p), "%s", reg->reg[i].str)+1; //We add 1 to consider the '\0' in place. + p+= sprintf((char *)WFIFOP(fd,p), "%s", reg->reg[i].value)+1; + } + WFIFOW(fd,2)=p; + if (p>= 5000) + ShowWarning("Too many acc regs for %d:%d, not all values were loaded.\n", account_id, char_id); + } + WFIFOSET(fd,WFIFOW(fd,2)); + return 0; } //Request to kick char from a certain map server. [Skotlex] int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason) { - if (fd >= 0) - { - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x2b1f; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = reason; - WFIFOSET(fd,7); - return 0; - } - return -1; + if (fd >= 0) { + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x2b1f; + WFIFOL(fd,2) = account_id; + WFIFOB(fd,6) = reason; + WFIFOSET(fd,7); + return 0; + } + return -1; } //-------------------------------------------------------- @@ -930,34 +951,34 @@ int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason) */ int check_ttl_wisdata_sub(DBKey key, DBData *data, va_list ap) { - unsigned long tick; - struct WisData *wd = db_data2ptr(data); - tick = va_arg(ap, unsigned long); + unsigned long tick; + struct WisData *wd = db_data2ptr(data); + tick = va_arg(ap, unsigned long); - if (DIFF_TICK(tick, wd->tick) > WISDATA_TTL && wis_delnum < WISDELLIST_MAX) - wis_dellist[wis_delnum++] = wd->id; + if (DIFF_TICK(tick, wd->tick) > WISDATA_TTL && wis_delnum < WISDELLIST_MAX) + wis_dellist[wis_delnum++] = wd->id; - return 0; + return 0; } int check_ttl_wisdata(void) { - unsigned long tick = gettick(); - int i; - - do { - wis_delnum = 0; - wis_db->foreach(wis_db, check_ttl_wisdata_sub, tick); - for(i = 0; i < wis_delnum; i++) { - struct WisData *wd = (struct WisData*)idb_get(wis_db, wis_dellist[i]); - ShowWarning("inter: wis data id=%d time out : from %s to %s\n", wd->id, wd->src, wd->dst); - // removed. not send information after a timeout. Just no answer for the player - //mapif_wis_end(wd, 1); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - idb_remove(wis_db, wd->id); - } - } while(wis_delnum >= WISDELLIST_MAX); - - return 0; + unsigned long tick = gettick(); + int i; + + do { + wis_delnum = 0; + wis_db->foreach(wis_db, check_ttl_wisdata_sub, tick); + for (i = 0; i < wis_delnum; i++) { + struct WisData *wd = (struct WisData *)idb_get(wis_db, wis_dellist[i]); + ShowWarning("inter: wis data id=%d time out : from %s to %s\n", wd->id, wd->src, wd->dst); + // removed. not send information after a timeout. Just no answer for the player + //mapif_wis_end(wd, 1); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + idb_remove(wis_db, wd->id); + } + } while (wis_delnum >= WISDELLIST_MAX); + + return 0; } //-------------------------------------------------------- @@ -965,209 +986,206 @@ int check_ttl_wisdata(void) // broadcast sending int mapif_parse_broadcast(int fd) { - mapif_broadcast(RFIFOP(fd,16), RFIFOW(fd,2), RFIFOL(fd,4), RFIFOW(fd,8), RFIFOW(fd,10), RFIFOW(fd,12), RFIFOW(fd,14), fd); - return 0; + mapif_broadcast(RFIFOP(fd,16), RFIFOW(fd,2), RFIFOL(fd,4), RFIFOW(fd,8), RFIFOW(fd,10), RFIFOW(fd,12), RFIFOW(fd,14), fd); + return 0; } // Wisp/page request to send int mapif_parse_WisRequest(int fd) { - struct WisData* wd; - static int wisid = 0; - char name[NAME_LENGTH]; - char esc_name[NAME_LENGTH*2+1];// escaped name - char* data; - size_t len; - - - if ( fd <= 0 ) {return 0;} // check if we have a valid fd - - if (RFIFOW(fd,2)-52 >= sizeof(wd->msg)) { - ShowWarning("inter: Wis message size too long.\n"); - return 0; - } else if (RFIFOW(fd,2)-52 <= 0) { // normaly, impossible, but who knows... - ShowError("inter: Wis message doesn't exist.\n"); - return 0; - } - - safestrncpy(name, (char*)RFIFOP(fd,28), NAME_LENGTH); //Received name may be too large and not contain \0! [Skotlex] - - Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `name`='%s'", char_db, esc_name) ) - Sql_ShowDebug(sql_handle); - - // search if character exists before to ask all map-servers - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - unsigned char buf[27]; - WBUFW(buf, 0) = 0x3802; - memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); - WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - mapif_send(fd, buf, 27); - } - else - {// Character exists. So, ask all map-servers - // to be sure of the correct name, rewrite it - Sql_GetData(sql_handle, 0, &data, &len); - memset(name, 0, NAME_LENGTH); - memcpy(name, data, min(len, NAME_LENGTH)); - // if source is destination, don't ask other servers. - if( strncmp((const char*)RFIFOP(fd,4), name, NAME_LENGTH) == 0 ) - { - uint8 buf[27]; - WBUFW(buf, 0) = 0x3802; - memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); - WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - mapif_send(fd, buf, 27); - } - else - { - - CREATE(wd, struct WisData, 1); - - // Whether the failure of previous wisp/page transmission (timeout) - check_ttl_wisdata(); - - wd->id = ++wisid; - wd->fd = fd; - wd->len= RFIFOW(fd,2)-52; - memcpy(wd->src, RFIFOP(fd, 4), NAME_LENGTH); - memcpy(wd->dst, RFIFOP(fd,28), NAME_LENGTH); - memcpy(wd->msg, RFIFOP(fd,52), wd->len); - wd->tick = gettick(); - idb_put(wis_db, wd->id, wd); - mapif_wis_message(wd); - } - } - - Sql_FreeResult(sql_handle); - return 0; + struct WisData *wd; + static int wisid = 0; + char name[NAME_LENGTH]; + char esc_name[NAME_LENGTH*2+1];// escaped name + char *data; + size_t len; + + + if (fd <= 0) { + return 0; // check if we have a valid fd + } + + if (RFIFOW(fd,2)-52 >= sizeof(wd->msg)) { + ShowWarning("inter: Wis message size too long.\n"); + return 0; + } else if (RFIFOW(fd,2)-52 <= 0) { // normaly, impossible, but who knows... + ShowError("inter: Wis message doesn't exist.\n"); + return 0; + } + + safestrncpy(name, (char *)RFIFOP(fd,28), NAME_LENGTH); //Received name may be too large and not contain \0! [Skotlex] + + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `name`='%s'", char_db, esc_name)) + Sql_ShowDebug(sql_handle); + + // search if character exists before to ask all map-servers + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { + unsigned char buf[27]; + WBUFW(buf, 0) = 0x3802; + memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); + WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + mapif_send(fd, buf, 27); + } else { + // Character exists. So, ask all map-servers + // to be sure of the correct name, rewrite it + Sql_GetData(sql_handle, 0, &data, &len); + memset(name, 0, NAME_LENGTH); + memcpy(name, data, min(len, NAME_LENGTH)); + // if source is destination, don't ask other servers. + if (strncmp((const char *)RFIFOP(fd,4), name, NAME_LENGTH) == 0) { + uint8 buf[27]; + WBUFW(buf, 0) = 0x3802; + memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); + WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + mapif_send(fd, buf, 27); + } else { + + CREATE(wd, struct WisData, 1); + + // Whether the failure of previous wisp/page transmission (timeout) + check_ttl_wisdata(); + + wd->id = ++wisid; + wd->fd = fd; + wd->len= RFIFOW(fd,2)-52; + memcpy(wd->src, RFIFOP(fd, 4), NAME_LENGTH); + memcpy(wd->dst, RFIFOP(fd,28), NAME_LENGTH); + memcpy(wd->msg, RFIFOP(fd,52), wd->len); + wd->tick = gettick(); + idb_put(wis_db, wd->id, wd); + mapif_wis_message(wd); + } + } + + Sql_FreeResult(sql_handle); + return 0; } // Wisp/page transmission result int mapif_parse_WisReply(int fd) { - int id, flag; - struct WisData *wd; + int id, flag; + struct WisData *wd; - id = RFIFOL(fd,2); - flag = RFIFOB(fd,6); - wd = (struct WisData*)idb_get(wis_db, id); - if (wd == NULL) - return 0; // This wisp was probably suppress before, because it was timeout of because of target was found on another map-server + id = RFIFOL(fd,2); + flag = RFIFOB(fd,6); + wd = (struct WisData *)idb_get(wis_db, id); + if (wd == NULL) + return 0; // This wisp was probably suppress before, because it was timeout of because of target was found on another map-server - if ((--wd->count) <= 0 || flag != 1) { - mapif_wis_end(wd, flag); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - idb_remove(wis_db, id); - } + if ((--wd->count) <= 0 || flag != 1) { + mapif_wis_end(wd, flag); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + idb_remove(wis_db, id); + } - return 0; + return 0; } // Received wisp message from map-server for ALL gm (just copy the message and resends it to ALL map-servers) int mapif_parse_WisToGM(int fd) { - unsigned char buf[2048]; // 0x3003/0x3803 .w .24B .w .?B + unsigned char buf[2048]; // 0x3003/0x3803 .w .24B .w .?B - memcpy(WBUFP(buf,0), RFIFOP(fd,0), RFIFOW(fd,2)); - WBUFW(buf, 0) = 0x3803; - mapif_sendall(buf, RFIFOW(fd,2)); + memcpy(WBUFP(buf,0), RFIFOP(fd,0), RFIFOW(fd,2)); + WBUFW(buf, 0) = 0x3803; + mapif_sendall(buf, RFIFOW(fd,2)); - return 0; + return 0; } // Save account_reg into sql (type=2) int mapif_parse_Registry(int fd) { - int j,p,len, max; - struct accreg *reg=accreg_pt; - - memset(accreg_pt,0,sizeof(struct accreg)); - switch (RFIFOB(fd, 12)) { - case 3: //Character registry - max = GLOBAL_REG_NUM; - break; - case 2: //Account Registry - max = ACCOUNT_REG_NUM; - break; - case 1: //Account2 registry, must be sent over to login server. - return save_accreg2(RFIFOP(fd,4), RFIFOW(fd,2)-4); - default: - return 1; - } - for(j=0,p=13;jreg[j].str,&len); - reg->reg[j].str[len]='\0'; - p +=len+1; //+1 to skip the '\0' between strings. - sscanf((char*)RFIFOP(fd,p), "%255c%n",reg->reg[j].value,&len); - reg->reg[j].value[len]='\0'; - p +=len+1; - } - reg->reg_num=j; - - inter_accreg_tosql(RFIFOL(fd,4),RFIFOL(fd,8),reg, RFIFOB(fd,12)); - mapif_account_reg(fd,RFIFOP(fd,0)); // Send updated accounts to other map servers. - return 0; + int j,p,len, max; + struct accreg *reg=accreg_pt; + + memset(accreg_pt,0,sizeof(struct accreg)); + switch (RFIFOB(fd, 12)) { + case 3: //Character registry + max = GLOBAL_REG_NUM; + break; + case 2: //Account Registry + max = ACCOUNT_REG_NUM; + break; + case 1: //Account2 registry, must be sent over to login server. + return save_accreg2(RFIFOP(fd,4), RFIFOW(fd,2)-4); + default: + return 1; + } + for (j=0,p=13; jreg[j].str,&len); + reg->reg[j].str[len]='\0'; + p +=len+1; //+1 to skip the '\0' between strings. + sscanf((char *)RFIFOP(fd,p), "%255c%n",reg->reg[j].value,&len); + reg->reg[j].value[len]='\0'; + p +=len+1; + } + reg->reg_num=j; + + inter_accreg_tosql(RFIFOL(fd,4),RFIFOL(fd,8),reg, RFIFOB(fd,12)); + mapif_account_reg(fd,RFIFOP(fd,0)); // Send updated accounts to other map servers. + return 0; } // Request the value of all registries. int mapif_parse_RegistryRequest(int fd) { - //Load Char Registry - if (RFIFOB(fd,12)) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),3); - //Load Account Registry - if (RFIFOB(fd,11)) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),2); - //Ask Login Server for Account2 values. - if (RFIFOB(fd,10)) request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)); - return 1; + //Load Char Registry + if (RFIFOB(fd,12)) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),3); + //Load Account Registry + if (RFIFOB(fd,11)) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),2); + //Ask Login Server for Account2 values. + if (RFIFOB(fd,10)) request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)); + return 1; } static void mapif_namechange_ack(int fd, int account_id, int char_id, int type, int flag, char *name) { - WFIFOHEAD(fd, NAME_LENGTH+13); - WFIFOW(fd, 0) = 0x3806; - WFIFOL(fd, 2) = account_id; - WFIFOL(fd, 6) = char_id; - WFIFOB(fd,10) = type; - WFIFOB(fd,11) = flag; - memcpy(WFIFOP(fd, 12), name, NAME_LENGTH); - WFIFOSET(fd, NAME_LENGTH+13); + WFIFOHEAD(fd, NAME_LENGTH+13); + WFIFOW(fd, 0) = 0x3806; + WFIFOL(fd, 2) = account_id; + WFIFOL(fd, 6) = char_id; + WFIFOB(fd,10) = type; + WFIFOB(fd,11) = flag; + memcpy(WFIFOP(fd, 12), name, NAME_LENGTH); + WFIFOSET(fd, NAME_LENGTH+13); } int mapif_parse_NameChangeRequest(int fd) { - int account_id, char_id, type; - char* name; - int i; - - account_id = RFIFOL(fd,2); - char_id = RFIFOL(fd,6); - type = RFIFOB(fd,10); - name = (char*)RFIFOP(fd,11); - - // Check Authorised letters/symbols in the name - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { - mapif_namechange_ack(fd, account_id, char_id, type, 0, name); - return 0; - } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { - mapif_namechange_ack(fd, account_id, char_id, type, 0, name); - return 0; - } - } - //TODO: type holds the type of object to rename. - //If it were a player, it needs to have the guild information and db information - //updated here, because changing it on the map won't make it be saved [Skotlex] - - //name allowed. - mapif_namechange_ack(fd, account_id, char_id, type, 1, name); - return 0; + int account_id, char_id, type; + char *name; + int i; + + account_id = RFIFOL(fd,2); + char_id = RFIFOL(fd,6); + type = RFIFOB(fd,10); + name = (char *)RFIFOP(fd,11); + + // Check Authorised letters/symbols in the name + if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) == NULL) { + mapif_namechange_ack(fd, account_id, char_id, type, 0, name); + return 0; + } + } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) != NULL) { + mapif_namechange_ack(fd, account_id, char_id, type, 0, name); + return 0; + } + } + //TODO: type holds the type of object to rename. + //If it were a player, it needs to have the guild information and db information + //updated here, because changing it on the map won't make it be saved [Skotlex] + + //name allowed. + mapif_namechange_ack(fd, account_id, char_id, type, 1, name); + return 0; } //-------------------------------------------------------- @@ -1178,59 +1196,75 @@ int mapif_parse_NameChangeRequest(int fd) /// @param length The minimum allowed length, or -1 for dynamic lookup int inter_check_length(int fd, int length) { - if( length == -1 ) - {// variable-length packet - if( RFIFOREST(fd) < 4 ) - return 0; - length = RFIFOW(fd,2); - } + if (length == -1) { + // variable-length packet + if (RFIFOREST(fd) < 4) + return 0; + length = RFIFOW(fd,2); + } - if( (int)RFIFOREST(fd) < length ) - return 0; + if ((int)RFIFOREST(fd) < length) + return 0; - return length; + return length; } int inter_parse_frommap(int fd) { - int cmd; - int len = 0; - cmd = RFIFOW(fd,0); - // Check is valid packet entry - if(cmd < 0x3000 || cmd >= 0x3000 + ARRAYLENGTH(inter_recv_packet_length) || inter_recv_packet_length[cmd - 0x3000] == 0) - return 0; - - // Check packet length - if((len = inter_check_length(fd, inter_recv_packet_length[cmd - 0x3000])) == 0) - return 2; - - switch(cmd) { - case 0x3000: mapif_parse_broadcast(fd); break; - case 0x3001: mapif_parse_WisRequest(fd); break; - case 0x3002: mapif_parse_WisReply(fd); break; - case 0x3003: mapif_parse_WisToGM(fd); break; - case 0x3004: mapif_parse_Registry(fd); break; - case 0x3005: mapif_parse_RegistryRequest(fd); break; - case 0x3006: mapif_parse_NameChangeRequest(fd); break; - case 0x3007: mapif_parse_accinfo(fd); break; - /* 0x3008 is used by the report stuff */ - default: - if( inter_party_parse_frommap(fd) - || inter_guild_parse_frommap(fd) - || inter_storage_parse_frommap(fd) - || inter_pet_parse_frommap(fd) - || inter_homunculus_parse_frommap(fd) - || inter_mercenary_parse_frommap(fd) - || inter_elemental_parse_frommap(fd) - || inter_mail_parse_frommap(fd) - || inter_auction_parse_frommap(fd) - || inter_quest_parse_frommap(fd) - ) - break; - else - return 0; - } - - RFIFOSKIP(fd, len); - return 1; + int cmd; + int len = 0; + cmd = RFIFOW(fd,0); + // Check is valid packet entry + if (cmd < 0x3000 || cmd >= 0x3000 + ARRAYLENGTH(inter_recv_packet_length) || inter_recv_packet_length[cmd - 0x3000] == 0) + return 0; + + // Check packet length + if ((len = inter_check_length(fd, inter_recv_packet_length[cmd - 0x3000])) == 0) + return 2; + + switch (cmd) { + case 0x3000: + mapif_parse_broadcast(fd); + break; + case 0x3001: + mapif_parse_WisRequest(fd); + break; + case 0x3002: + mapif_parse_WisReply(fd); + break; + case 0x3003: + mapif_parse_WisToGM(fd); + break; + case 0x3004: + mapif_parse_Registry(fd); + break; + case 0x3005: + mapif_parse_RegistryRequest(fd); + break; + case 0x3006: + mapif_parse_NameChangeRequest(fd); + break; + case 0x3007: + mapif_parse_accinfo(fd); + break; + /* 0x3008 is used by the report stuff */ + default: + if (inter_party_parse_frommap(fd) + || inter_guild_parse_frommap(fd) + || inter_storage_parse_frommap(fd) + || inter_pet_parse_frommap(fd) + || inter_homunculus_parse_frommap(fd) + || inter_mercenary_parse_frommap(fd) + || inter_elemental_parse_frommap(fd) + || inter_mail_parse_frommap(fd) + || inter_auction_parse_frommap(fd) + || inter_quest_parse_frommap(fd) + ) + break; + else + return 0; + } + + RFIFOSKIP(fd, len); + return 1; } diff --git a/src/char/inter.h b/src/char/inter.h index ac2e1785f..199d70bb4 100644 --- a/src/char/inter.h +++ b/src/char/inter.h @@ -20,8 +20,8 @@ int inter_log(char *fmt,...); extern unsigned int party_share_level; -extern Sql* sql_handle; -extern Sql* lsql_handle; +extern Sql *sql_handle; +extern Sql *lsql_handle; extern char main_chat_nick[16]; diff --git a/src/common/atomic.h b/src/common/atomic.h index b1a4bda92..a7e953db2 100644 --- a/src/common/atomic.h +++ b/src/common/atomic.h @@ -4,16 +4,16 @@ #ifndef _rA_ATOMIC_H_ #define _rA_ATOMIC_H_ -// Atomic Operations +// Atomic Operations // (Interlocked CompareExchange, Add .. and so on ..) -// +// // Implementation varies / depends on: -// - Architecture -// - Compiler -// - Operating System +// - Architecture +// - Compiler +// - Operating System // // our Abstraction is fully API-Compatible to Microsofts implementation @ NT5.0+ -// +// #include "../common/cbasetypes.h" #if defined(_MSC_VER) @@ -22,60 +22,65 @@ #if !defined(_M_X64) // When compiling for windows 32bit, the 8byte interlocked operations are not provided by microsoft // (because they need at least i586 so its not generic enough.. ... ) -forceinline int64 InterlockedCompareExchange64(volatile int64 *dest, int64 exch, int64 _cmp){ - _asm{ - lea esi,_cmp; - lea edi,exch; - - mov eax,[esi]; - mov edx,4[esi]; - mov ebx,[edi]; - mov ecx,4[edi]; - mov esi,dest; - - lock CMPXCHG8B [esi]; - } +forceinline int64 InterlockedCompareExchange64(volatile int64 *dest, int64 exch, int64 _cmp) +{ + _asm { + lea esi,_cmp; + lea edi,exch; + + mov eax,[esi]; + mov edx,4[esi]; + mov ebx,[edi]; + mov ecx,4[edi]; + mov esi,dest; + + lock CMPXCHG8B [esi]; + } } -forceinline volatile int64 InterlockedIncrement64(volatile int64 *addend){ - __int64 old; - do{ - old = *addend; - }while(InterlockedCompareExchange64(addend, (old+1), old) != old); +forceinline volatile int64 InterlockedIncrement64(volatile int64 *addend) +{ + __int64 old; + do { + old = *addend; + } while (InterlockedCompareExchange64(addend, (old+1), old) != old); - return (old + 1); + return (old + 1); } -forceinline volatile int64 InterlockedDecrement64(volatile int64 *addend){ - __int64 old; +forceinline volatile int64 InterlockedDecrement64(volatile int64 *addend) +{ + __int64 old; - do{ - old = *addend; - }while(InterlockedCompareExchange64(addend, (old-1), old) != old); + do { + old = *addend; + } while (InterlockedCompareExchange64(addend, (old-1), old) != old); - return (old - 1); + return (old - 1); } -forceinline volatile int64 InterlockedExchangeAdd64(volatile int64 *addend, int64 increment){ - __int64 old; +forceinline volatile int64 InterlockedExchangeAdd64(volatile int64 *addend, int64 increment) +{ + __int64 old; - do{ - old = *addend; - }while(InterlockedCompareExchange64(addend, (old + increment), old) != old); + do { + old = *addend; + } while (InterlockedCompareExchange64(addend, (old + increment), old) != old); - return old; + return old; } -forceinline volatile int64 InterlockedExchange64(volatile int64 *target, int64 val){ - __int64 old; - do{ - old = *target; - }while(InterlockedCompareExchange64(target, val, old) != old); +forceinline volatile int64 InterlockedExchange64(volatile int64 *target, int64 val) +{ + __int64 old; + do { + old = *target; + } while (InterlockedCompareExchange64(target, val, old) != old); - return old; + return old; } #endif //endif 32bit windows @@ -86,52 +91,62 @@ forceinline volatile int64 InterlockedExchange64(volatile int64 *target, int64 v #error Your Target Platfrom is not supported #endif -static forceinline int64 InterlockedExchangeAdd64(volatile int64 *addend, int64 increment){ - return __sync_fetch_and_add(addend, increment); +static forceinline int64 InterlockedExchangeAdd64(volatile int64 *addend, int64 increment) +{ + return __sync_fetch_and_add(addend, increment); }//end: InterlockedExchangeAdd64() -static forceinline int32 InterlockedExchangeAdd(volatile int32 *addend, int32 increment){ - return __sync_fetch_and_add(addend, increment); +static forceinline int32 InterlockedExchangeAdd(volatile int32 *addend, int32 increment) +{ + return __sync_fetch_and_add(addend, increment); }//end: InterlockedExchangeAdd() -static forceinline int64 InterlockedIncrement64(volatile int64 *addend){ - return __sync_add_and_fetch(addend, 1); +static forceinline int64 InterlockedIncrement64(volatile int64 *addend) +{ + return __sync_add_and_fetch(addend, 1); }//end: InterlockedIncrement64() -static forceinline int32 InterlockedIncrement(volatile int32 *addend){ - return __sync_add_and_fetch(addend, 1); +static forceinline int32 InterlockedIncrement(volatile int32 *addend) +{ + return __sync_add_and_fetch(addend, 1); }//end: InterlockedIncrement() -static forceinline int64 InterlockedDecrement64(volatile int64 *addend){ - return __sync_sub_and_fetch(addend, 1); +static forceinline int64 InterlockedDecrement64(volatile int64 *addend) +{ + return __sync_sub_and_fetch(addend, 1); }//end: InterlockedDecrement64() -static forceinline int32 InterlockedDecrement(volatile int32 *addend){ - return __sync_sub_and_fetch(addend, 1); +static forceinline int32 InterlockedDecrement(volatile int32 *addend) +{ + return __sync_sub_and_fetch(addend, 1); }//end: InterlockedDecrement() -static forceinline int64 InterlockedCompareExchange64(volatile int64 *dest, int64 exch, int64 cmp){ - return __sync_val_compare_and_swap(dest, cmp, exch); +static forceinline int64 InterlockedCompareExchange64(volatile int64 *dest, int64 exch, int64 cmp) +{ + return __sync_val_compare_and_swap(dest, cmp, exch); }//end: InterlockedCompareExchange64() -static forceinline int32 InterlockedCompareExchange(volatile int32 *dest, int32 exch, int32 cmp){ - return __sync_val_compare_and_swap(dest, cmp, exch); +static forceinline int32 InterlockedCompareExchange(volatile int32 *dest, int32 exch, int32 cmp) +{ + return __sync_val_compare_and_swap(dest, cmp, exch); }//end: InterlockedCompareExchnage() -static forceinline int64 InterlockedExchange64(volatile int64 *target, int64 val){ - return __sync_lock_test_and_set(target, val); +static forceinline int64 InterlockedExchange64(volatile int64 *target, int64 val) +{ + return __sync_lock_test_and_set(target, val); }//end: InterlockedExchange64() -static forceinline int32 InterlockedExchange(volatile int32 *target, int32 val){ +static forceinline int32 InterlockedExchange(volatile int32 *target, int32 val) +{ return __sync_lock_test_and_set(target, val); }//end: InterlockedExchange() diff --git a/src/common/cbasetypes.h b/src/common/cbasetypes.h index 731a8b578..a47a7434f 100644 --- a/src/common/cbasetypes.h +++ b/src/common/cbasetypes.h @@ -59,11 +59,11 @@ // debug function name #ifndef __NETBSD__ #if __STDC_VERSION__ < 199901L -# if __GNUC__ >= 2 -# define __func__ __FUNCTION__ -# else -# define __func__ "" -# endif +# if __GNUC__ >= 2 +# define __func__ __FUNCTION__ +# else +# define __func__ "" +# endif #endif #endif @@ -106,56 +106,56 @@ // Integers with guaranteed _exact_ size. ////////////////////////////////////////////////////////////////////////// -typedef int8_t int8; -typedef int16_t int16; -typedef int32_t int32; -typedef int64_t int64; +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; -typedef int8_t sint8; -typedef int16_t sint16; -typedef int32_t sint32; -typedef int64_t sint64; +typedef int8_t sint8; +typedef int16_t sint16; +typedef int32_t sint32; +typedef int64_t sint64; -typedef uint8_t uint8; -typedef uint16_t uint16; -typedef uint32_t uint32; -typedef uint64_t uint64; +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; #undef UINT8_MIN #undef UINT16_MIN #undef UINT32_MIN #undef UINT64_MIN -#define UINT8_MIN ((uint8) UINT8_C(0x00)) -#define UINT16_MIN ((uint16)UINT16_C(0x0000)) -#define UINT32_MIN ((uint32)UINT32_C(0x00000000)) -#define UINT64_MIN ((uint64)UINT64_C(0x0000000000000000)) +#define UINT8_MIN ((uint8) UINT8_C(0x00)) +#define UINT16_MIN ((uint16)UINT16_C(0x0000)) +#define UINT32_MIN ((uint32)UINT32_C(0x00000000)) +#define UINT64_MIN ((uint64)UINT64_C(0x0000000000000000)) #undef UINT8_MAX #undef UINT16_MAX #undef UINT32_MAX #undef UINT64_MAX -#define UINT8_MAX ((uint8) UINT8_C(0xFF)) -#define UINT16_MAX ((uint16)UINT16_C(0xFFFF)) -#define UINT32_MAX ((uint32)UINT32_C(0xFFFFFFFF)) -#define UINT64_MAX ((uint64)UINT64_C(0xFFFFFFFFFFFFFFFF)) +#define UINT8_MAX ((uint8) UINT8_C(0xFF)) +#define UINT16_MAX ((uint16)UINT16_C(0xFFFF)) +#define UINT32_MAX ((uint32)UINT32_C(0xFFFFFFFF)) +#define UINT64_MAX ((uint64)UINT64_C(0xFFFFFFFFFFFFFFFF)) #undef SINT8_MIN #undef SINT16_MIN #undef SINT32_MIN #undef SINT64_MIN -#define SINT8_MIN ((sint8) INT8_C(0x80)) -#define SINT16_MIN ((sint16)INT16_C(0x8000)) -#define SINT32_MIN ((sint32)INT32_C(0x80000000)) -#define SINT64_MIN ((sint32)INT64_C(0x8000000000000000)) +#define SINT8_MIN ((sint8) INT8_C(0x80)) +#define SINT16_MIN ((sint16)INT16_C(0x8000)) +#define SINT32_MIN ((sint32)INT32_C(0x80000000)) +#define SINT64_MIN ((sint32)INT64_C(0x8000000000000000)) #undef SINT8_MAX #undef SINT16_MAX #undef SINT32_MAX #undef SINT64_MAX -#define SINT8_MAX ((sint8) INT8_C(0x7F)) -#define SINT16_MAX ((sint16)INT16_C(0x7FFF)) -#define SINT32_MAX ((sint32)INT32_C(0x7FFFFFFF)) -#define SINT64_MAX ((sint64)INT64_C(0x7FFFFFFFFFFFFFFF)) +#define SINT8_MAX ((sint8) INT8_C(0x7F)) +#define SINT16_MAX ((sint16)INT16_C(0x7FFF)) +#define SINT32_MAX ((sint32)INT32_C(0x7FFFFFFF)) +#define SINT64_MAX ((sint64)INT64_C(0x7FFFFFFFFFFFFFFF)) ////////////////////////////////////////////////////////////////////////// // Integers with guaranteed _minimum_ size. @@ -180,10 +180,10 @@ typedef unsigned long int ppuint32; #if defined(WIN32) && !defined(MINGW) // does not have a signed size_t ////////////////////////////// -#if defined(_WIN64) // naive 64bit windows platform -typedef __int64 ssize_t; +#if defined(_WIN64) // naive 64bit windows platform +typedef __int64 ssize_t; #else -typedef int ssize_t; +typedef int ssize_t; #endif ////////////////////////////// #endif @@ -201,23 +201,23 @@ typedef uintptr_t uintptr; // Add a 'sysint' Type which has the width of the platform we're compiled for. ////////////////////////////////////////////////////////////////////////// #if defined(__GNUC__) - #if defined(__x86_64__) - typedef int64 sysint; - typedef uint64 usysint; - #else - typedef int32 sysint; - typedef uint32 usysint; - #endif +#if defined(__x86_64__) +typedef int64 sysint; +typedef uint64 usysint; +#else +typedef int32 sysint; +typedef uint32 usysint; +#endif #elif defined(_MSC_VER) - #if defined(_M_X64) - typedef int64 sysint; - typedef uint64 usysint; - #else - typedef int32 sysint; - typedef uint32 usysint; - #endif +#if defined(_M_X64) +typedef int64 sysint; +typedef uint64 usysint; +#else +typedef int32 sysint; +typedef uint32 usysint; +#endif #else - #error Compiler / Platform is unsupported. +#error Compiler / Platform is unsupported. #endif @@ -225,21 +225,21 @@ typedef uintptr_t uintptr; // some redefine of function redefines for some Compilers ////////////////////////////////////////////////////////////////////////// #if defined(_MSC_VER) || defined(__BORLANDC__) -#define strcasecmp stricmp -#define strncasecmp strnicmp -#define strncmpi strnicmp -#define snprintf _snprintf +#define strcasecmp stricmp +#define strncasecmp strnicmp +#define strncmpi strnicmp +#define snprintf _snprintf #if defined(_MSC_VER) && _MSC_VER < 1400 -#define vsnprintf _vsnprintf +#define vsnprintf _vsnprintf #endif #else -#define strcmpi strcasecmp -#define stricmp strcasecmp -#define strncmpi strncasecmp -#define strnicmp strncasecmp +#define strcmpi strcasecmp +#define stricmp strcasecmp +#define strncmpi strncasecmp +#define strnicmp strncasecmp #endif #if defined(_MSC_VER) && _MSC_VER > 1200 -#define strtoull _strtoui64 +#define strtoull _strtoui64 #endif // keyword replacement @@ -262,8 +262,8 @@ typedef uintptr_t uintptr; // boolean types for C typedef char bool; -#define false (1==0) -#define true (1==1) +#define false (1==0) +#define true (1==1) ////////////////////////////// #endif // not __cplusplus @@ -276,7 +276,7 @@ typedef char bool; #undef swap #endif // hmm only ints? -//#define swap(a,b) { int temp=a; a=b; b=temp;} +//#define swap(a,b) { int temp=a; a=b; b=temp;} // if using macros then something that is type independent //#define swap(a,b) ((a == b) || ((a ^= b), (b ^= a), (a ^= b))) // Avoid "value computed is not used" warning and generates the same assembly code @@ -299,7 +299,7 @@ typedef char bool; ////////////////////////////////////////////////////////////////////////// // number of bits in a byte #ifndef NBBY -#define NBBY 8 +#define NBBY 8 #endif ////////////////////////////////////////////////////////////////////////// @@ -383,17 +383,20 @@ typedef char bool; // Set a pointer variable to a pointer value. #ifdef __cplusplus template -void SET_POINTER(T1*&var, T2* p) +void SET_POINTER(T1 *&var, T2 *p) { - var = static_cast(p); + var = static_cast(p); } template -void SET_FUNCPOINTER(T1& var, T2 p) +void SET_FUNCPOINTER(T1 &var, T2 p) { - char ASSERT_POINTERSIZE[sizeof(T1) == sizeof(void*) && sizeof(T2) == sizeof(void*)?1:-1];// 1 if true, -1 if false - union{ T1 out; T2 in; } tmp;// /!\ WARNING casting a pointer to a function pointer is against the C++ standard - tmp.in = p; - var = tmp.out; + char ASSERT_POINTERSIZE[sizeof(T1) == sizeof(void *) && sizeof(T2) == sizeof(void *)?1:-1]; // 1 if true, -1 if false + union { + T1 out; + T2 in; + } tmp;// /!\ WARNING casting a pointer to a function pointer is against the C++ standard + tmp.in = p; + var = tmp.out; } #else #define SET_POINTER(var,p) (var) = (p) diff --git a/src/common/conf.c b/src/common/conf.c index 3057bd4dc..2027b4b09 100644 --- a/src/common/conf.c +++ b/src/common/conf.c @@ -8,14 +8,14 @@ int conf_read_file(config_t *config, const char *config_filename) { - config_init(config); - if (!config_read_file(config, config_filename)) { - ShowError("%s:%d - %s\n", config_error_file(config), - config_error_line(config), config_error_text(config)); - config_destroy(config); - return 1; - } - return 0; + config_init(config); + if (!config_read_file(config, config_filename)) { + ShowError("%s:%d - %s\n", config_error_file(config), + config_error_line(config), config_error_text(config)); + config_destroy(config); + return 1; + } + return 0; } // @@ -28,82 +28,81 @@ int config_setting_copy(config_setting_t *parent, const config_setting_t *src); void config_setting_copy_simple(config_setting_t *parent, const config_setting_t *src) { - if (config_setting_is_aggregate(src)) { - config_setting_copy_aggregate(parent, src); - } - else { - config_setting_t *set = config_setting_add(parent, config_setting_name(src), config_setting_type(src)); - - if (set == NULL) - return; - - if (CONFIG_TYPE_INT == config_setting_type(src)) { - config_setting_set_int(set, config_setting_get_int(src)); - config_setting_set_format(set, src->format); - } else if (CONFIG_TYPE_INT64 == config_setting_type(src)) { - config_setting_set_int64(set, config_setting_get_int64(src)); - config_setting_set_format(set, src->format); - } else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) { - config_setting_set_float(set, config_setting_get_float(src)); - } else if (CONFIG_TYPE_STRING == config_setting_type(src)) { - config_setting_set_string(set, config_setting_get_string(src)); - } else if (CONFIG_TYPE_BOOL == config_setting_type(src)) { - config_setting_set_bool(set, config_setting_get_bool(src)); - } - } + if (config_setting_is_aggregate(src)) { + config_setting_copy_aggregate(parent, src); + } else { + config_setting_t *set = config_setting_add(parent, config_setting_name(src), config_setting_type(src)); + + if (set == NULL) + return; + + if (CONFIG_TYPE_INT == config_setting_type(src)) { + config_setting_set_int(set, config_setting_get_int(src)); + config_setting_set_format(set, src->format); + } else if (CONFIG_TYPE_INT64 == config_setting_type(src)) { + config_setting_set_int64(set, config_setting_get_int64(src)); + config_setting_set_format(set, src->format); + } else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) { + config_setting_set_float(set, config_setting_get_float(src)); + } else if (CONFIG_TYPE_STRING == config_setting_type(src)) { + config_setting_set_string(set, config_setting_get_string(src)); + } else if (CONFIG_TYPE_BOOL == config_setting_type(src)) { + config_setting_set_bool(set, config_setting_get_bool(src)); + } + } } void config_setting_copy_elem(config_setting_t *parent, const config_setting_t *src) { - config_setting_t *set = NULL; - - if (config_setting_is_aggregate(src)) - config_setting_copy_aggregate(parent, src); - else if (CONFIG_TYPE_INT == config_setting_type(src)) { - set = config_setting_set_int_elem(parent, -1, config_setting_get_int(src)); - config_setting_set_format(set, src->format); - } else if (CONFIG_TYPE_INT64 == config_setting_type(src)) { - set = config_setting_set_int64_elem(parent, -1, config_setting_get_int64(src)); - config_setting_set_format(set, src->format); - } else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) { - config_setting_set_float_elem(parent, -1, config_setting_get_float(src)); - } else if (CONFIG_TYPE_STRING == config_setting_type(src)) { - config_setting_set_string_elem(parent, -1, config_setting_get_string(src)); - } else if (CONFIG_TYPE_BOOL == config_setting_type(src)) { - config_setting_set_bool_elem(parent, -1, config_setting_get_bool(src)); - } + config_setting_t *set = NULL; + + if (config_setting_is_aggregate(src)) + config_setting_copy_aggregate(parent, src); + else if (CONFIG_TYPE_INT == config_setting_type(src)) { + set = config_setting_set_int_elem(parent, -1, config_setting_get_int(src)); + config_setting_set_format(set, src->format); + } else if (CONFIG_TYPE_INT64 == config_setting_type(src)) { + set = config_setting_set_int64_elem(parent, -1, config_setting_get_int64(src)); + config_setting_set_format(set, src->format); + } else if (CONFIG_TYPE_FLOAT == config_setting_type(src)) { + config_setting_set_float_elem(parent, -1, config_setting_get_float(src)); + } else if (CONFIG_TYPE_STRING == config_setting_type(src)) { + config_setting_set_string_elem(parent, -1, config_setting_get_string(src)); + } else if (CONFIG_TYPE_BOOL == config_setting_type(src)) { + config_setting_set_bool_elem(parent, -1, config_setting_get_bool(src)); + } } void config_setting_copy_aggregate(config_setting_t *parent, const config_setting_t *src) { - config_setting_t *newAgg; - int i, n; - - newAgg = config_setting_add(parent, config_setting_name(src), config_setting_type(src)); - - if (newAgg == NULL) - return; - - n = config_setting_length(src); - - for (i = 0; i < n; i++) { - if (config_setting_is_group(src)) { - config_setting_copy_simple(newAgg, config_setting_get_elem(src, i)); - } else { - config_setting_copy_elem(newAgg, config_setting_get_elem(src, i)); - } - } + config_setting_t *newAgg; + int i, n; + + newAgg = config_setting_add(parent, config_setting_name(src), config_setting_type(src)); + + if (newAgg == NULL) + return; + + n = config_setting_length(src); + + for (i = 0; i < n; i++) { + if (config_setting_is_group(src)) { + config_setting_copy_simple(newAgg, config_setting_get_elem(src, i)); + } else { + config_setting_copy_elem(newAgg, config_setting_get_elem(src, i)); + } + } } int config_setting_copy(config_setting_t *parent, const config_setting_t *src) { - if (!config_setting_is_group(parent) && !config_setting_is_list(parent)) - return CONFIG_FALSE; - - if (config_setting_is_aggregate(src)) { - config_setting_copy_aggregate(parent, src); - } else { - config_setting_copy_simple(parent, src); - } - return CONFIG_TRUE; + if (!config_setting_is_group(parent) && !config_setting_is_list(parent)) + return CONFIG_FALSE; + + if (config_setting_is_aggregate(src)) { + config_setting_copy_aggregate(parent, src); + } else { + config_setting_copy_simple(parent, src); + } + return CONFIG_TRUE; } diff --git a/src/common/core.c b/src/common/core.c index e1f99885b..efab15dcb 100644 --- a/src/common/core.c +++ b/src/common/core.c @@ -28,7 +28,7 @@ void (*shutdown_callback)(void) = NULL; #if defined(BUILDBOT) - int buildbotflag = 0; +int buildbotflag = 0; #endif int runflag = CORE_ST_RUN; @@ -38,14 +38,14 @@ char **arg_v = NULL; char *SERVER_NAME = NULL; char SERVER_TYPE = ATHENA_SERVER_NONE; -#ifndef MINICORE // minimalist Core +#ifndef MINICORE // minimalist Core // Added by Gabuzomeu // // This is an implementation of signal() using sigaction() for portability. // (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced // Programming in the UNIX Environment_. // -#ifdef WIN32 // windows don't have SIGPIPE +#ifdef WIN32 // windows don't have SIGPIPE #define SIGPIPE SIGINT #endif @@ -54,229 +54,225 @@ char SERVER_TYPE = ATHENA_SERVER_NONE; #else sigfunc *compat_signal(int signo, sigfunc *func) { - struct sigaction sact, oact; + struct sigaction sact, oact; - sact.sa_handler = func; - sigemptyset(&sact.sa_mask); - sact.sa_flags = 0; + sact.sa_handler = func; + sigemptyset(&sact.sa_mask); + sact.sa_flags = 0; #ifdef SA_INTERRUPT - sact.sa_flags |= SA_INTERRUPT; /* SunOS */ + sact.sa_flags |= SA_INTERRUPT; /* SunOS */ #endif - if (sigaction(signo, &sact, &oact) < 0) - return (SIG_ERR); + if (sigaction(signo, &sact, &oact) < 0) + return (SIG_ERR); - return (oact.sa_handler); + return (oact.sa_handler); } #endif /*====================================== - * CORE : Console events for Windows + * CORE : Console events for Windows *--------------------------------------*/ #ifdef _WIN32 static BOOL WINAPI console_handler(DWORD c_event) { - switch(c_event) - { - case CTRL_CLOSE_EVENT: - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - if( shutdown_callback != NULL ) - shutdown_callback(); - else - runflag = CORE_ST_STOP;// auto-shutdown - break; - default: - return FALSE; + switch (c_event) { + case CTRL_CLOSE_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + if (shutdown_callback != NULL) + shutdown_callback(); + else + runflag = CORE_ST_STOP;// auto-shutdown + break; + default: + return FALSE; } return TRUE; } static void cevents_init() { - if (SetConsoleCtrlHandler(console_handler,TRUE)==FALSE) - ShowWarning ("Unable to install the console handler!\n"); + if (SetConsoleCtrlHandler(console_handler,TRUE)==FALSE) + ShowWarning("Unable to install the console handler!\n"); } #endif /*====================================== - * CORE : Signal Sub Function + * CORE : Signal Sub Function *--------------------------------------*/ static void sig_proc(int sn) { - static int is_called = 0; - - switch (sn) { - case SIGINT: - case SIGTERM: - if (++is_called > 3) - exit(EXIT_SUCCESS); - if( shutdown_callback != NULL ) - shutdown_callback(); - else - runflag = CORE_ST_STOP;// auto-shutdown - break; - case SIGSEGV: - case SIGFPE: - do_abort(); - // Pass the signal to the system's default handler - compat_signal(sn, SIG_DFL); - raise(sn); - break; + static int is_called = 0; + + switch (sn) { + case SIGINT: + case SIGTERM: + if (++is_called > 3) + exit(EXIT_SUCCESS); + if (shutdown_callback != NULL) + shutdown_callback(); + else + runflag = CORE_ST_STOP;// auto-shutdown + break; + case SIGSEGV: + case SIGFPE: + do_abort(); + // Pass the signal to the system's default handler + compat_signal(sn, SIG_DFL); + raise(sn); + break; #ifndef _WIN32 - case SIGXFSZ: - // ignore and allow it to set errno to EFBIG - ShowWarning ("Max file size reached!\n"); - //run_flag = 0; // should we quit? - break; - case SIGPIPE: - //ShowInfo ("Broken pipe found... closing socket\n"); // set to eof in socket.c - break; // does nothing here + case SIGXFSZ: + // ignore and allow it to set errno to EFBIG + ShowWarning("Max file size reached!\n"); + //run_flag = 0; // should we quit? + break; + case SIGPIPE: + //ShowInfo ("Broken pipe found... closing socket\n"); // set to eof in socket.c + break; // does nothing here #endif - } + } } -void signals_init (void) +void signals_init(void) { - compat_signal(SIGTERM, sig_proc); - compat_signal(SIGINT, sig_proc); + compat_signal(SIGTERM, sig_proc); + compat_signal(SIGINT, sig_proc); #ifndef _DEBUG // need unhandled exceptions to debug on Windows - compat_signal(SIGSEGV, sig_proc); - compat_signal(SIGFPE, sig_proc); + compat_signal(SIGSEGV, sig_proc); + compat_signal(SIGFPE, sig_proc); #endif #ifndef _WIN32 - compat_signal(SIGILL, SIG_DFL); - compat_signal(SIGXFSZ, sig_proc); - compat_signal(SIGPIPE, sig_proc); - compat_signal(SIGBUS, SIG_DFL); - compat_signal(SIGTRAP, SIG_DFL); + compat_signal(SIGILL, SIG_DFL); + compat_signal(SIGXFSZ, sig_proc); + compat_signal(SIGPIPE, sig_proc); + compat_signal(SIGBUS, SIG_DFL); + compat_signal(SIGTRAP, SIG_DFL); #endif } #endif #ifdef SVNVERSION - const char *get_svn_revision(void) - { - return EXPAND_AND_QUOTE(SVNVERSION); - } +const char *get_svn_revision(void) +{ + return EXPAND_AND_QUOTE(SVNVERSION); +} #else// not SVNVERSION -const char* get_svn_revision(void) +const char *get_svn_revision(void) { - static char svn_version_buffer[16] = ""; - FILE *fp; - - if( svn_version_buffer[0] != '\0' ) - return svn_version_buffer; - - // subversion 1.7 uses a sqlite3 database - // FIXME this is hackish at best... - // - ignores database file structure - // - assumes the data in NODES.dav_cache column ends with "!svn/ver//)" - // - since it's a cache column, the data might not even exist - if( (fp = fopen(".svn"PATHSEP_STR"wc.db", "rb")) != NULL || (fp = fopen(".."PATHSEP_STR".svn"PATHSEP_STR"wc.db", "rb")) != NULL ) - { - #ifndef SVNNODEPATH - //not sure how to handle branches, so i'll leave this overridable define until a better solution comes up - #define SVNNODEPATH trunk - #endif - const char* prefix = "!svn/ver/"; - const char* postfix = "/"EXPAND_AND_QUOTE(SVNNODEPATH)")"; // there should exist only 1 entry like this - size_t prefix_len = strlen(prefix); - size_t postfix_len = strlen(postfix); - size_t i,j,len; - char* buffer; - - // read file to buffer - fseek(fp, 0, SEEK_END); - len = ftell(fp); - buffer = (char*)aMalloc(len + 1); - fseek(fp, 0, SEEK_SET); - len = fread(buffer, 1, len, fp); - buffer[len] = '\0'; - fclose(fp); - - // parse buffer - for( i = prefix_len + 1; i + postfix_len <= len; ++i ) - { - if( buffer[i] != postfix[0] || memcmp(buffer + i, postfix, postfix_len) != 0 ) - continue; // postfix missmatch - for( j = i; j > 0; --j ) - {// skip digits - if( !ISDIGIT(buffer[j - 1]) ) - break; - } - if( memcmp(buffer + j - prefix_len, prefix, prefix_len) != 0 ) - continue; // prefix missmatch - // done - snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(buffer + j)); - break; - } - aFree(buffer); - - if( svn_version_buffer[0] != '\0' ) - return svn_version_buffer; - } - - // subversion 1.6 and older? - if ((fp = fopen(".svn/entries", "r")) != NULL) - { - char line[1024]; - int rev; - // Check the version - if (fgets(line, sizeof(line), fp)) - { - if(!ISDIGIT(line[0])) - { - // XML File format - while (fgets(line,sizeof(line),fp)) - if (strstr(line,"revision=")) break; - if (sscanf(line," %*[^\"]\"%d%*[^\n]", &rev) == 1) { - snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", rev); - } - } - else - { - // Bin File format - if ( fgets(line, sizeof(line), fp) == NULL ) { printf("Can't get bin name\n"); } // Get the name - if ( fgets(line, sizeof(line), fp) == NULL ) { printf("Can't get entries kind\n"); } // Get the entries kind - if(fgets(line, sizeof(line), fp)) // Get the rev numver - { - snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(line)); - } - } - } - fclose(fp); - - if( svn_version_buffer[0] != '\0' ) - return svn_version_buffer; - } - - // fallback - snprintf(svn_version_buffer, sizeof(svn_version_buffer), "Unknown"); - return svn_version_buffer; + static char svn_version_buffer[16] = ""; + FILE *fp; + + if (svn_version_buffer[0] != '\0') + return svn_version_buffer; + + // subversion 1.7 uses a sqlite3 database + // FIXME this is hackish at best... + // - ignores database file structure + // - assumes the data in NODES.dav_cache column ends with "!svn/ver//)" + // - since it's a cache column, the data might not even exist + if ((fp = fopen(".svn"PATHSEP_STR"wc.db", "rb")) != NULL || (fp = fopen(".."PATHSEP_STR".svn"PATHSEP_STR"wc.db", "rb")) != NULL) { +#ifndef SVNNODEPATH + //not sure how to handle branches, so i'll leave this overridable define until a better solution comes up +#define SVNNODEPATH trunk +#endif + const char *prefix = "!svn/ver/"; + const char *postfix = "/"EXPAND_AND_QUOTE(SVNNODEPATH)")"; // there should exist only 1 entry like this + size_t prefix_len = strlen(prefix); + size_t postfix_len = strlen(postfix); + size_t i,j,len; + char *buffer; + + // read file to buffer + fseek(fp, 0, SEEK_END); + len = ftell(fp); + buffer = (char *)aMalloc(len + 1); + fseek(fp, 0, SEEK_SET); + len = fread(buffer, 1, len, fp); + buffer[len] = '\0'; + fclose(fp); + + // parse buffer + for (i = prefix_len + 1; i + postfix_len <= len; ++i) { + if (buffer[i] != postfix[0] || memcmp(buffer + i, postfix, postfix_len) != 0) + continue; // postfix missmatch + for (j = i; j > 0; --j) { + // skip digits + if (!ISDIGIT(buffer[j - 1])) + break; + } + if (memcmp(buffer + j - prefix_len, prefix, prefix_len) != 0) + continue; // prefix missmatch + // done + snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(buffer + j)); + break; + } + aFree(buffer); + + if (svn_version_buffer[0] != '\0') + return svn_version_buffer; + } + + // subversion 1.6 and older? + if ((fp = fopen(".svn/entries", "r")) != NULL) { + char line[1024]; + int rev; + // Check the version + if (fgets(line, sizeof(line), fp)) { + if (!ISDIGIT(line[0])) { + // XML File format + while (fgets(line,sizeof(line),fp)) + if (strstr(line,"revision=")) break; + if (sscanf(line," %*[^\"]\"%d%*[^\n]", &rev) == 1) { + snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", rev); + } + } else { + // Bin File format + if (fgets(line, sizeof(line), fp) == NULL) { + printf("Can't get bin name\n"); // Get the name + } + if (fgets(line, sizeof(line), fp) == NULL) { + printf("Can't get entries kind\n"); // Get the entries kind + } + if (fgets(line, sizeof(line), fp)) { // Get the rev numver + snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(line)); + } + } + } + fclose(fp); + + if (svn_version_buffer[0] != '\0') + return svn_version_buffer; + } + + // fallback + snprintf(svn_version_buffer, sizeof(svn_version_buffer), "Unknown"); + return svn_version_buffer; } #endif /*====================================== - * CORE : Display title + * CORE : Display title * ASCII By CalciumKid 1/12/2011 *--------------------------------------*/ -static void display_title(void) { - //ClearScreen(); // clear screen and go up/left (0, 0 position in text) - - ShowMessage("\n"); - ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BT_WHITE" rAthena Development Team presents "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" ___ __ __ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" _____/ | / /_/ /_ ___ ____ ____ _ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" / ___/ /| |/ __/ __ \\/ _ \\/ __ \\/ __ `/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" / / / ___ / /_/ / / / __/ / / / /_/ / "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" /_/ /_/ |_\\__/_/ /_/\\___/_/ /_/\\__,_/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_GREEN" http://rathena.org/board/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); - ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); - - ShowInfo("SVN Revision: '"CL_WHITE"%s"CL_RESET"'.\n", get_svn_revision()); +static void display_title(void) +{ + //ClearScreen(); // clear screen and go up/left (0, 0 position in text) + + ShowMessage("\n"); + ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BT_WHITE" rAthena Development Team presents "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" ___ __ __ "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" _____/ | / /_/ /_ ___ ____ ____ _ "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" / ___/ /| |/ __/ __ \\/ _ \\/ __ \\/ __ `/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" / / / ___ / /_/ / / / __/ / / / /_/ / "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" /_/ /_/ |_\\__/_/ /_/\\___/_/ /_/\\__,_/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_GREEN" http://rathena.org/board/ "CL_PASS""CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n"); + + ShowInfo("SVN Revision: '"CL_WHITE"%s"CL_RESET"'.\n", get_svn_revision()); } // Warning if executed as superuser (root) @@ -284,72 +280,73 @@ void usercheck(void) { #ifndef _WIN32 if (geteuid() == 0) { - ShowWarning ("You are running rAthena with root privileges, it is not necessary.\n"); + ShowWarning("You are running rAthena with root privileges, it is not necessary.\n"); } #endif } /*====================================== - * CORE : MAINROUTINE + * CORE : MAINROUTINE *--------------------------------------*/ -int main (int argc, char **argv) +int main(int argc, char **argv) { - {// initialize program arguments - char *p1 = SERVER_NAME = argv[0]; - char *p2 = p1; - while ((p1 = strchr(p2, '/')) != NULL || (p1 = strchr(p2, '\\')) != NULL) - { - SERVER_NAME = ++p1; - p2 = p1; - } - arg_c = argc; - arg_v = argv; - } - - malloc_init();// needed for Show* in display_title() [FlavioJS] + { + // initialize program arguments + char *p1 = SERVER_NAME = argv[0]; + char *p2 = p1; + while ((p1 = strchr(p2, '/')) != NULL || (p1 = strchr(p2, '\\')) != NULL) { + SERVER_NAME = ++p1; + p2 = p1; + } + arg_c = argc; + arg_v = argv; + } + + malloc_init();// needed for Show* in display_title() [FlavioJS] #ifdef MINICORE // minimalist Core - display_title(); - usercheck(); - do_init(argc,argv); - do_final(); + display_title(); + usercheck(); + do_init(argc,argv); + do_final(); #else// not MINICORE - set_server_type(); - display_title(); - usercheck(); + set_server_type(); + display_title(); + usercheck(); - rathread_init(); - mempool_init(); - db_init(); - signals_init(); + rathread_init(); + mempool_init(); + db_init(); + signals_init(); #ifdef _WIN32 - cevents_init(); + cevents_init(); #endif - timer_init(); - socket_init(); + timer_init(); + socket_init(); - do_init(argc,argv); + do_init(argc,argv); - {// Main runtime cycle - int next; - while (runflag != CORE_ST_STOP) { - next = do_timer(gettick_nocache()); - do_sockets(next); - } - } + { + // Main runtime cycle + int next; + while (runflag != CORE_ST_STOP) { + next = do_timer(gettick_nocache()); + do_sockets(next); + } + } - do_final(); + do_final(); - timer_final(); - socket_final(); - db_final(); - mempool_final(); - rathread_final(); + timer_final(); + socket_final(); + db_final(); + mempool_final(); + rathread_final(); #endif - malloc_final(); + malloc_final(); - return 0; + return 0; } diff --git a/src/common/core.h b/src/common/core.h index d48962c94..d12723445 100644 --- a/src/common/core.h +++ b/src/common/core.h @@ -1,14 +1,14 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _CORE_H_ -#define _CORE_H_ +#ifndef _CORE_H_ +#define _CORE_H_ extern int arg_c; extern char **arg_v; #if defined(BUILDBOT) - extern int buildbotflag; +extern int buildbotflag; #endif /// @see E_CORE_ST @@ -16,28 +16,27 @@ extern int runflag; extern char *SERVER_NAME; enum { - ATHENA_SERVER_NONE = 0, // not defined - ATHENA_SERVER_LOGIN = 1, // login server - ATHENA_SERVER_CHAR = 2, // char server - ATHENA_SERVER_INTER = 4, // inter server - ATHENA_SERVER_MAP = 8, // map server + ATHENA_SERVER_NONE = 0, // not defined + ATHENA_SERVER_LOGIN = 1, // login server + ATHENA_SERVER_CHAR = 2, // char server + ATHENA_SERVER_INTER = 4, // inter server + ATHENA_SERVER_MAP = 8, // map server }; extern char SERVER_TYPE; -extern int parse_console(const char* buf); +extern int parse_console(const char *buf); extern const char *get_svn_revision(void); -extern int do_init(int,char**); +extern int do_init(int,char **); extern void set_server_type(void); extern void do_abort(void); extern void do_final(void); /// The main loop continues until runflag is CORE_ST_STOP -enum E_CORE_ST -{ - CORE_ST_STOP = 0, - CORE_ST_RUN, - CORE_ST_LAST +enum E_CORE_ST { + CORE_ST_STOP = 0, + CORE_ST_RUN, + CORE_ST_LAST }; /// Called when a terminate signal is received. (Ctrl+C pressed) diff --git a/src/common/db.c b/src/common/db.c index 204c6d2ea..c5db21a02 100644 --- a/src/common/db.c +++ b/src/common/db.c @@ -88,7 +88,7 @@ \*****************************************************************************/ /** - * If defined statistics about database nodes, database creating/destruction + * If defined statistics about database nodes, database creating/destruction * and function usage are keept and displayed when finalizing the database * system. * WARNING: This adds overhead to every database operation (not shure how much). @@ -112,8 +112,8 @@ * @see struct dbn */ typedef enum node_color { - RED, - BLACK + RED, + BLACK } node_color; /** @@ -129,16 +129,16 @@ typedef enum node_color { * @see DBMap_impl#ht */ typedef struct dbn { - // Tree structure - struct dbn *parent; - struct dbn *left; - struct dbn *right; - // Node data - DBKey key; - DBData data; - // Other - node_color color; - unsigned deleted : 1; + // Tree structure + struct dbn *parent; + struct dbn *left; + struct dbn *right; + // Node data + DBKey key; + DBData data; + // Other + node_color color; + unsigned deleted : 1; } *DBNode; /** @@ -149,8 +149,8 @@ typedef struct dbn { * @see DBMap_impl#free_list */ struct db_free { - DBNode node; - DBNode *root; + DBNode node; + DBNode *root; }; /** @@ -176,28 +176,28 @@ struct db_free { * @see #db_alloc(const char*,int,DBType,DBOptions,unsigned short) */ typedef struct DBMap_impl { - // Database interface - struct DBMap vtable; - // File and line of allocation - const char *alloc_file; - int alloc_line; - // Lock system - struct db_free *free_list; - unsigned int free_count; - unsigned int free_max; - unsigned int free_lock; - // Other - ERS nodes; - DBComparator cmp; - DBHasher hash; - DBReleaser release; - DBNode ht[HASH_SIZE]; - DBNode cache; - DBType type; - DBOptions options; - uint32 item_count; - unsigned short maxlen; - unsigned global_lock : 1; + // Database interface + struct DBMap vtable; + // File and line of allocation + const char *alloc_file; + int alloc_line; + // Lock system + struct db_free *free_list; + unsigned int free_count; + unsigned int free_max; + unsigned int free_lock; + // Other + ERS nodes; + DBComparator cmp; + DBHasher hash; + DBReleaser release; + DBNode ht[HASH_SIZE]; + DBNode cache; + DBType type; + DBOptions options; + uint32 item_count; + unsigned short maxlen; + unsigned global_lock : 1; } DBMap_impl; /** @@ -212,11 +212,11 @@ typedef struct DBMap_impl { * @see #DBNode */ typedef struct DBIterator_impl { - // Iterator interface - struct DBIterator vtable; - DBMap_impl* db; - int ht_index; - DBNode node; + // Iterator interface + struct DBIterator vtable; + DBMap_impl *db; + int ht_index; + DBNode node; } DBIterator_impl; #if defined(DB_ENABLE_STATS) @@ -227,92 +227,92 @@ typedef struct DBIterator_impl { * @see #stats */ static struct db_stats { - // Node alloc/free - uint32 db_node_alloc; - uint32 db_node_free; - // Database creating/destruction counters - uint32 db_int_alloc; - uint32 db_uint_alloc; - uint32 db_string_alloc; - uint32 db_istring_alloc; - uint32 db_int_destroy; - uint32 db_uint_destroy; - uint32 db_string_destroy; - uint32 db_istring_destroy; - // Function usage counters - uint32 db_rotate_left; - uint32 db_rotate_right; - uint32 db_rebalance; - uint32 db_rebalance_erase; - uint32 db_is_key_null; - uint32 db_dup_key; - uint32 db_dup_key_free; - uint32 db_free_add; - uint32 db_free_remove; - uint32 db_free_lock; - uint32 db_free_unlock; - uint32 db_int_cmp; - uint32 db_uint_cmp; - uint32 db_string_cmp; - uint32 db_istring_cmp; - uint32 db_int_hash; - uint32 db_uint_hash; - uint32 db_string_hash; - uint32 db_istring_hash; - uint32 db_release_nothing; - uint32 db_release_key; - uint32 db_release_data; - uint32 db_release_both; - uint32 dbit_first; - uint32 dbit_last; - uint32 dbit_next; - uint32 dbit_prev; - uint32 dbit_exists; - uint32 dbit_remove; - uint32 dbit_destroy; - uint32 db_iterator; - uint32 db_exists; - uint32 db_get; - uint32 db_getall; - uint32 db_vgetall; - uint32 db_ensure; - uint32 db_vensure; - uint32 db_put; - uint32 db_remove; - uint32 db_foreach; - uint32 db_vforeach; - uint32 db_clear; - uint32 db_vclear; - uint32 db_destroy; - uint32 db_vdestroy; - uint32 db_size; - uint32 db_type; - uint32 db_options; - uint32 db_fix_options; - uint32 db_default_cmp; - uint32 db_default_hash; - uint32 db_default_release; - uint32 db_custom_release; - uint32 db_alloc; - uint32 db_i2key; - uint32 db_ui2key; - uint32 db_str2key; - uint32 db_i2data; - uint32 db_ui2data; - uint32 db_ptr2data; - uint32 db_data2i; - uint32 db_data2ui; - uint32 db_data2ptr; - uint32 db_init; - uint32 db_final; + // Node alloc/free + uint32 db_node_alloc; + uint32 db_node_free; + // Database creating/destruction counters + uint32 db_int_alloc; + uint32 db_uint_alloc; + uint32 db_string_alloc; + uint32 db_istring_alloc; + uint32 db_int_destroy; + uint32 db_uint_destroy; + uint32 db_string_destroy; + uint32 db_istring_destroy; + // Function usage counters + uint32 db_rotate_left; + uint32 db_rotate_right; + uint32 db_rebalance; + uint32 db_rebalance_erase; + uint32 db_is_key_null; + uint32 db_dup_key; + uint32 db_dup_key_free; + uint32 db_free_add; + uint32 db_free_remove; + uint32 db_free_lock; + uint32 db_free_unlock; + uint32 db_int_cmp; + uint32 db_uint_cmp; + uint32 db_string_cmp; + uint32 db_istring_cmp; + uint32 db_int_hash; + uint32 db_uint_hash; + uint32 db_string_hash; + uint32 db_istring_hash; + uint32 db_release_nothing; + uint32 db_release_key; + uint32 db_release_data; + uint32 db_release_both; + uint32 dbit_first; + uint32 dbit_last; + uint32 dbit_next; + uint32 dbit_prev; + uint32 dbit_exists; + uint32 dbit_remove; + uint32 dbit_destroy; + uint32 db_iterator; + uint32 db_exists; + uint32 db_get; + uint32 db_getall; + uint32 db_vgetall; + uint32 db_ensure; + uint32 db_vensure; + uint32 db_put; + uint32 db_remove; + uint32 db_foreach; + uint32 db_vforeach; + uint32 db_clear; + uint32 db_vclear; + uint32 db_destroy; + uint32 db_vdestroy; + uint32 db_size; + uint32 db_type; + uint32 db_options; + uint32 db_fix_options; + uint32 db_default_cmp; + uint32 db_default_hash; + uint32 db_default_release; + uint32 db_custom_release; + uint32 db_alloc; + uint32 db_i2key; + uint32 db_ui2key; + uint32 db_str2key; + uint32 db_i2data; + uint32 db_ui2data; + uint32 db_ptr2data; + uint32 db_data2i; + uint32 db_data2ui; + uint32 db_data2ptr; + uint32 db_init; + uint32 db_final; } stats = { - 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, 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, 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, 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, 0, 0 }; #define DB_COUNTSTAT(token) if (stats. ## token != UINT32_MAX) ++stats. ## token #else /* !defined(DB_ENABLE_STATS) */ @@ -346,25 +346,25 @@ static struct db_stats { */ static void db_rotate_left(DBNode node, DBNode *root) { - DBNode y = node->right; + DBNode y = node->right; - DB_COUNTSTAT(db_rotate_left); - // put the left of y at the right of node - node->right = y->left; - if (y->left) - y->left->parent = node; - y->parent = node->parent; - // link y and node's parent - if (node == *root) { - *root = y; // node was root - } else if (node == node->parent->left) { - node->parent->left = y; // node was at the left - } else { - node->parent->right = y; // node was at the right - } - // put node at the left of y - y->left = node; - node->parent = y; + DB_COUNTSTAT(db_rotate_left); + // put the left of y at the right of node + node->right = y->left; + if (y->left) + y->left->parent = node; + y->parent = node->parent; + // link y and node's parent + if (node == *root) { + *root = y; // node was root + } else if (node == node->parent->left) { + node->parent->left = y; // node was at the left + } else { + node->parent->right = y; // node was at the right + } + // put node at the left of y + y->left = node; + node->parent = y; } /** @@ -377,25 +377,25 @@ static void db_rotate_left(DBNode node, DBNode *root) */ static void db_rotate_right(DBNode node, DBNode *root) { - DBNode y = node->left; + DBNode y = node->left; - DB_COUNTSTAT(db_rotate_right); - // put the right of y at the left of node - node->left = y->right; - if (y->right != 0) - y->right->parent = node; - y->parent = node->parent; - // link y and node's parent - if (node == *root) { - *root = y; // node was root - } else if (node == node->parent->right) { - node->parent->right = y; // node was at the right - } else { - node->parent->left = y; // node was at the left - } - // put node at the right of y - y->right = node; - node->parent = y; + DB_COUNTSTAT(db_rotate_right); + // put the right of y at the left of node + node->left = y->right; + if (y->right != 0) + y->right->parent = node; + y->parent = node->parent; + // link y and node's parent + if (node == *root) { + *root = y; // node was root + } else if (node == node->parent->right) { + node->parent->right = y; // node was at the right + } else { + node->parent->left = y; // node was at the left + } + // put node at the right of y + y->right = node; + node->parent = y; } /** @@ -410,55 +410,55 @@ static void db_rotate_right(DBNode node, DBNode *root) */ static void db_rebalance(DBNode node, DBNode *root) { - DBNode y; - - DB_COUNTSTAT(db_rebalance); - // Restore the RED-BLACK properties - node->color = RED; - while (node != *root && node->parent->color == RED) { - if (node->parent == node->parent->parent->left) { - // If node's parent is a left, y is node's right 'uncle' - y = node->parent->parent->right; - if (y && y->color == RED) { // case 1 - // change the colors and move up the tree - node->parent->color = BLACK; - y->color = BLACK; - node->parent->parent->color = RED; - node = node->parent->parent; - } else { - if (node == node->parent->right) { // case 2 - // move up and rotate - node = node->parent; - db_rotate_left(node, root); - } - // case 3 - node->parent->color = BLACK; - node->parent->parent->color = RED; - db_rotate_right(node->parent->parent, root); - } - } else { - // If node's parent is a right, y is node's left 'uncle' - y = node->parent->parent->left; - if (y && y->color == RED) { // case 1 - // change the colors and move up the tree - node->parent->color = BLACK; - y->color = BLACK; - node->parent->parent->color = RED; - node = node->parent->parent; - } else { - if (node == node->parent->left) { // case 2 - // move up and rotate - node = node->parent; - db_rotate_right(node, root); - } - // case 3 - node->parent->color = BLACK; - node->parent->parent->color = RED; - db_rotate_left(node->parent->parent, root); - } - } - } - (*root)->color = BLACK; // the root can and should always be black + DBNode y; + + DB_COUNTSTAT(db_rebalance); + // Restore the RED-BLACK properties + node->color = RED; + while (node != *root && node->parent->color == RED) { + if (node->parent == node->parent->parent->left) { + // If node's parent is a left, y is node's right 'uncle' + y = node->parent->parent->right; + if (y && y->color == RED) { // case 1 + // change the colors and move up the tree + node->parent->color = BLACK; + y->color = BLACK; + node->parent->parent->color = RED; + node = node->parent->parent; + } else { + if (node == node->parent->right) { // case 2 + // move up and rotate + node = node->parent; + db_rotate_left(node, root); + } + // case 3 + node->parent->color = BLACK; + node->parent->parent->color = RED; + db_rotate_right(node->parent->parent, root); + } + } else { + // If node's parent is a right, y is node's left 'uncle' + y = node->parent->parent->left; + if (y && y->color == RED) { // case 1 + // change the colors and move up the tree + node->parent->color = BLACK; + y->color = BLACK; + node->parent->parent->color = RED; + node = node->parent->parent; + } else { + if (node == node->parent->left) { // case 2 + // move up and rotate + node = node->parent; + db_rotate_right(node, root); + } + // case 3 + node->parent->color = BLACK; + node->parent->parent->color = RED; + db_rotate_left(node->parent->parent, root); + } + } + } + (*root)->color = BLACK; // the root can and should always be black } /** @@ -472,133 +472,133 @@ static void db_rebalance(DBNode node, DBNode *root) */ static void db_rebalance_erase(DBNode node, DBNode *root) { - DBNode y = node; - DBNode x = NULL; - DBNode x_parent = NULL; - DBNode w; - - DB_COUNTSTAT(db_rebalance_erase); - // Select where to change the tree - if (y->left == NULL) { // no left - x = y->right; - } else if (y->right == NULL) { // no right - x = y->left; - } else { // both exist, go to the leftmost node of the right sub-tree - y = y->right; - while (y->left != NULL) - y = y->left; - x = y->right; - } - - // Remove the node from the tree - if (y != node) { // both childs existed - // put the left of 'node' in the left of 'y' - node->left->parent = y; - y->left = node->left; - - // 'y' is not the direct child of 'node' - if (y != node->right) { - // put 'x' in the old position of 'y' - x_parent = y->parent; - if (x) x->parent = y->parent; - y->parent->left = x; - // put the right of 'node' in 'y' - y->right = node->right; - node->right->parent = y; - // 'y' is a direct child of 'node' - } else { - x_parent = y; - } - - // link 'y' and the parent of 'node' - if (*root == node) { - *root = y; // 'node' was the root - } else if (node->parent->left == node) { - node->parent->left = y; // 'node' was at the left - } else { - node->parent->right = y; // 'node' was at the right - } - y->parent = node->parent; - // switch colors - { - node_color tmp = y->color; - y->color = node->color; - node->color = tmp; - } - y = node; - } else { // one child did not exist - // put x in node's position - x_parent = y->parent; - if (x) x->parent = y->parent; - // link x and node's parent - if (*root == node) { - *root = x; // node was the root - } else if (node->parent->left == node) { - node->parent->left = x; // node was at the left - } else { - node->parent->right = x; // node was at the right - } - } - - // Restore the RED-BLACK properties - if (y->color != RED) { - while (x != *root && (x == NULL || x->color == BLACK)) { - if (x == x_parent->left) { - w = x_parent->right; - if (w->color == RED) { - w->color = BLACK; - x_parent->color = RED; - db_rotate_left(x_parent, root); - w = x_parent->right; - } - if ((w->left == NULL || w->left->color == BLACK) && - (w->right == NULL || w->right->color == BLACK)) { - w->color = RED; - x = x_parent; - x_parent = x_parent->parent; - } else { - if (w->right == NULL || w->right->color == BLACK) { - if (w->left) w->left->color = BLACK; - w->color = RED; - db_rotate_right(w, root); - w = x_parent->right; - } - w->color = x_parent->color; - x_parent->color = BLACK; - if (w->right) w->right->color = BLACK; - db_rotate_left(x_parent, root); - break; - } - } else { - w = x_parent->left; - if (w->color == RED) { - w->color = BLACK; - x_parent->color = RED; - db_rotate_right(x_parent, root); - w = x_parent->left; - } - if ((w->right == NULL || w->right->color == BLACK) && - (w->left == NULL || w->left->color == BLACK)) { - w->color = RED; - x = x_parent; - x_parent = x_parent->parent; - } else { - if (w->left == NULL || w->left->color == BLACK) { - if (w->right) w->right->color = BLACK; - w->color = RED; - db_rotate_left(w, root); - w = x_parent->left; - } - w->color = x_parent->color; - x_parent->color = BLACK; - if (w->left) w->left->color = BLACK; - db_rotate_right(x_parent, root); - break; - } - } - } - if (x) x->color = BLACK; - } + DBNode y = node; + DBNode x = NULL; + DBNode x_parent = NULL; + DBNode w; + + DB_COUNTSTAT(db_rebalance_erase); + // Select where to change the tree + if (y->left == NULL) { // no left + x = y->right; + } else if (y->right == NULL) { // no right + x = y->left; + } else { // both exist, go to the leftmost node of the right sub-tree + y = y->right; + while (y->left != NULL) + y = y->left; + x = y->right; + } + + // Remove the node from the tree + if (y != node) { // both childs existed + // put the left of 'node' in the left of 'y' + node->left->parent = y; + y->left = node->left; + + // 'y' is not the direct child of 'node' + if (y != node->right) { + // put 'x' in the old position of 'y' + x_parent = y->parent; + if (x) x->parent = y->parent; + y->parent->left = x; + // put the right of 'node' in 'y' + y->right = node->right; + node->right->parent = y; + // 'y' is a direct child of 'node' + } else { + x_parent = y; + } + + // link 'y' and the parent of 'node' + if (*root == node) { + *root = y; // 'node' was the root + } else if (node->parent->left == node) { + node->parent->left = y; // 'node' was at the left + } else { + node->parent->right = y; // 'node' was at the right + } + y->parent = node->parent; + // switch colors + { + node_color tmp = y->color; + y->color = node->color; + node->color = tmp; + } + y = node; + } else { // one child did not exist + // put x in node's position + x_parent = y->parent; + if (x) x->parent = y->parent; + // link x and node's parent + if (*root == node) { + *root = x; // node was the root + } else if (node->parent->left == node) { + node->parent->left = x; // node was at the left + } else { + node->parent->right = x; // node was at the right + } + } + + // Restore the RED-BLACK properties + if (y->color != RED) { + while (x != *root && (x == NULL || x->color == BLACK)) { + if (x == x_parent->left) { + w = x_parent->right; + if (w->color == RED) { + w->color = BLACK; + x_parent->color = RED; + db_rotate_left(x_parent, root); + w = x_parent->right; + } + if ((w->left == NULL || w->left->color == BLACK) && + (w->right == NULL || w->right->color == BLACK)) { + w->color = RED; + x = x_parent; + x_parent = x_parent->parent; + } else { + if (w->right == NULL || w->right->color == BLACK) { + if (w->left) w->left->color = BLACK; + w->color = RED; + db_rotate_right(w, root); + w = x_parent->right; + } + w->color = x_parent->color; + x_parent->color = BLACK; + if (w->right) w->right->color = BLACK; + db_rotate_left(x_parent, root); + break; + } + } else { + w = x_parent->left; + if (w->color == RED) { + w->color = BLACK; + x_parent->color = RED; + db_rotate_right(x_parent, root); + w = x_parent->left; + } + if ((w->right == NULL || w->right->color == BLACK) && + (w->left == NULL || w->left->color == BLACK)) { + w->color = RED; + x = x_parent; + x_parent = x_parent->parent; + } else { + if (w->left == NULL || w->left->color == BLACK) { + if (w->right) w->right->color = BLACK; + w->color = RED; + db_rotate_left(w, root); + w = x_parent->left; + } + w->color = x_parent->color; + x_parent->color = BLACK; + if (w->left) w->left->color = BLACK; + db_rotate_right(x_parent, root); + break; + } + } + } + if (x) x->color = BLACK; + } } /** @@ -613,15 +613,15 @@ static void db_rebalance_erase(DBNode node, DBNode *root) */ static int db_is_key_null(DBType type, DBKey key) { - DB_COUNTSTAT(db_is_key_null); - switch (type) { - case DB_STRING: - case DB_ISTRING: - return (key.str == NULL); + DB_COUNTSTAT(db_is_key_null); + switch (type) { + case DB_STRING: + case DB_ISTRING: + return (key.str == NULL); - default: // Not a pointer - return 0; - } + default: // Not a pointer + return 0; + } } /** @@ -635,25 +635,25 @@ static int db_is_key_null(DBType type, DBKey key) * @see #db_obj_put(DBMap*,DBKey,void *) * @see #db_dup_key_free(DBMap_impl*,DBKey) */ -static DBKey db_dup_key(DBMap_impl* db, DBKey key) +static DBKey db_dup_key(DBMap_impl *db, DBKey key) { - char *str; - size_t len; + char *str; + size_t len; - DB_COUNTSTAT(db_dup_key); - switch (db->type) { - case DB_STRING: - case DB_ISTRING: - len = strnlen(key.str, db->maxlen); - str = (char*)aMalloc(len + 1); - memcpy(str, key.str, len); - str[len] = '\0'; - key.str = str; - return key; + DB_COUNTSTAT(db_dup_key); + switch (db->type) { + case DB_STRING: + case DB_ISTRING: + len = strnlen(key.str, db->maxlen); + str = (char *)aMalloc(len + 1); + memcpy(str, key.str, len); + str[len] = '\0'; + key.str = str; + return key; - default: - return key; - } + default: + return key; + } } /** @@ -663,18 +663,18 @@ static DBKey db_dup_key(DBMap_impl* db, DBKey key) * @private * @see #db_dup_key(DBMap_impl*,DBKey) */ -static void db_dup_key_free(DBMap_impl* db, DBKey key) +static void db_dup_key_free(DBMap_impl *db, DBKey key) { - DB_COUNTSTAT(db_dup_key_free); - switch (db->type) { - case DB_STRING: - case DB_ISTRING: - aFree((char*)key.str); - return; + DB_COUNTSTAT(db_dup_key_free); + switch (db->type) { + case DB_STRING: + case DB_ISTRING: + aFree((char *)key.str); + return; - default: - return; - } + default: + return; + } } /** @@ -692,40 +692,40 @@ static void db_dup_key_free(DBMap_impl* db, DBKey key) * @see #db_obj_remove(DBMap*,DBKey) * @see #db_free_remove(DBMap_impl*,DBNode) */ -static void db_free_add(DBMap_impl* db, DBNode node, DBNode *root) -{ - DBKey old_key; - - DB_COUNTSTAT(db_free_add); - if (db->free_lock == (unsigned int)~0) { - ShowFatalError("db_free_add: free_lock overflow\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - exit(EXIT_FAILURE); - } - if (!(db->options&DB_OPT_DUP_KEY)) { // Make sure we have a key until the node is freed - old_key = node->key; - node->key = db_dup_key(db, node->key); - db->release(old_key, node->data, DB_RELEASE_KEY); - } - if (db->free_count == db->free_max) { // No more space, expand free_list - db->free_max = (db->free_max<<2) +3; // = db->free_max*4 +3 - if (db->free_max <= db->free_count) { - if (db->free_count == (unsigned int)~0) { - ShowFatalError("db_free_add: free_count overflow\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - exit(EXIT_FAILURE); - } - db->free_max = (unsigned int)~0; - } - RECREATE(db->free_list, struct db_free, db->free_max); - } - node->deleted = 1; - db->free_list[db->free_count].node = node; - db->free_list[db->free_count].root = root; - db->free_count++; - db->item_count--; +static void db_free_add(DBMap_impl *db, DBNode node, DBNode *root) +{ + DBKey old_key; + + DB_COUNTSTAT(db_free_add); + if (db->free_lock == (unsigned int)~0) { + ShowFatalError("db_free_add: free_lock overflow\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + exit(EXIT_FAILURE); + } + if (!(db->options&DB_OPT_DUP_KEY)) { // Make sure we have a key until the node is freed + old_key = node->key; + node->key = db_dup_key(db, node->key); + db->release(old_key, node->data, DB_RELEASE_KEY); + } + if (db->free_count == db->free_max) { // No more space, expand free_list + db->free_max = (db->free_max<<2) +3; // = db->free_max*4 +3 + if (db->free_max <= db->free_count) { + if (db->free_count == (unsigned int)~0) { + ShowFatalError("db_free_add: free_count overflow\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + exit(EXIT_FAILURE); + } + db->free_max = (unsigned int)~0; + } + RECREATE(db->free_list, struct db_free, db->free_max); + } + node->deleted = 1; + db->free_list[db->free_count].node = node; + db->free_list[db->free_count].root = root; + db->free_count++; + db->item_count--; } /** @@ -741,26 +741,26 @@ static void db_free_add(DBMap_impl* db, DBNode node, DBNode *root) * @see #db_obj_put(DBMap*,DBKey,DBData) * @see #db_free_add(DBMap_impl*,DBNode*,DBNode) */ -static void db_free_remove(DBMap_impl* db, DBNode node) +static void db_free_remove(DBMap_impl *db, DBNode node) { - unsigned int i; + unsigned int i; - DB_COUNTSTAT(db_free_remove); - for (i = 0; i < db->free_count; i++) { - if (db->free_list[i].node == node) { - if (i < db->free_count -1) // copy the last item to where the removed one was - memcpy(&db->free_list[i], &db->free_list[db->free_count -1], sizeof(struct db_free)); - db_dup_key_free(db, node->key); - break; - } - } - node->deleted = 0; - if (i == db->free_count) { - ShowWarning("db_free_remove: node was not found - database allocated at %s:%d\n", db->alloc_file, db->alloc_line); - } else { - db->free_count--; - } - db->item_count++; + DB_COUNTSTAT(db_free_remove); + for (i = 0; i < db->free_count; i++) { + if (db->free_list[i].node == node) { + if (i < db->free_count -1) // copy the last item to where the removed one was + memcpy(&db->free_list[i], &db->free_list[db->free_count -1], sizeof(struct db_free)); + db_dup_key_free(db, node->key); + break; + } + } + node->deleted = 0; + if (i == db->free_count) { + ShowWarning("db_free_remove: node was not found - database allocated at %s:%d\n", db->alloc_file, db->alloc_line); + } else { + db->free_count--; + } + db->item_count++; } /** @@ -770,16 +770,16 @@ static void db_free_remove(DBMap_impl* db, DBNode node) * @see DBMap_impl#free_lock * @see #db_unlock(DBMap_impl*) */ -static void db_free_lock(DBMap_impl* db) +static void db_free_lock(DBMap_impl *db) { - DB_COUNTSTAT(db_free_lock); - if (db->free_lock == (unsigned int)~0) { - ShowFatalError("db_free_lock: free_lock overflow\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - exit(EXIT_FAILURE); - } - db->free_lock++; + DB_COUNTSTAT(db_free_lock); + if (db->free_lock == (unsigned int)~0) { + ShowFatalError("db_free_lock: free_lock overflow\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + exit(EXIT_FAILURE); + } + db->free_lock++; } /** @@ -793,28 +793,28 @@ static void db_free_lock(DBMap_impl* db) * @see #db_free_dbn(DBNode) * @see #db_lock(DBMap_impl*) */ -static void db_free_unlock(DBMap_impl* db) +static void db_free_unlock(DBMap_impl *db) { - unsigned int i; + unsigned int i; - DB_COUNTSTAT(db_free_unlock); - if (db->free_lock == 0) { - ShowWarning("db_free_unlock: free_lock was already 0\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - } else { - db->free_lock--; - } - if (db->free_lock) - return; // Not last lock + DB_COUNTSTAT(db_free_unlock); + if (db->free_lock == 0) { + ShowWarning("db_free_unlock: free_lock was already 0\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + } else { + db->free_lock--; + } + if (db->free_lock) + return; // Not last lock - for (i = 0; i < db->free_count ; i++) { - db_rebalance_erase(db->free_list[i].node, db->free_list[i].root); - db_dup_key_free(db, db->free_list[i].node->key); - DB_COUNTSTAT(db_node_free); - ers_free(db->nodes, db->free_list[i].node); - } - db->free_count = 0; + for (i = 0; i < db->free_count ; i++) { + db_rebalance_erase(db->free_list[i].node, db->free_list[i].root); + db_dup_key_free(db, db->free_list[i].node->key); + DB_COUNTSTAT(db_node_free); + ers_free(db->nodes, db->free_list[i].node); + } + db->free_count = 0; } /*****************************************************************************\ @@ -850,11 +850,11 @@ static void db_free_unlock(DBMap_impl* db) */ static int db_int_cmp(DBKey key1, DBKey key2, unsigned short maxlen) { - (void)maxlen;//not used - DB_COUNTSTAT(db_int_cmp); - if (key1.i < key2.i) return -1; - if (key1.i > key2.i) return 1; - return 0; + (void)maxlen;//not used + DB_COUNTSTAT(db_int_cmp); + if (key1.i < key2.i) return -1; + if (key1.i > key2.i) return 1; + return 0; } /** @@ -872,11 +872,11 @@ static int db_int_cmp(DBKey key1, DBKey key2, unsigned short maxlen) */ static int db_uint_cmp(DBKey key1, DBKey key2, unsigned short maxlen) { - (void)maxlen;//not used - DB_COUNTSTAT(db_uint_cmp); - if (key1.ui < key2.ui) return -1; - if (key1.ui > key2.ui) return 1; - return 0; + (void)maxlen;//not used + DB_COUNTSTAT(db_uint_cmp); + if (key1.ui < key2.ui) return -1; + if (key1.ui > key2.ui) return 1; + return 0; } /** @@ -893,8 +893,8 @@ static int db_uint_cmp(DBKey key1, DBKey key2, unsigned short maxlen) */ static int db_string_cmp(DBKey key1, DBKey key2, unsigned short maxlen) { - DB_COUNTSTAT(db_string_cmp); - return strncmp((const char *)key1.str, (const char *)key2.str, maxlen); + DB_COUNTSTAT(db_string_cmp); + return strncmp((const char *)key1.str, (const char *)key2.str, maxlen); } /** @@ -911,8 +911,8 @@ static int db_string_cmp(DBKey key1, DBKey key2, unsigned short maxlen) */ static int db_istring_cmp(DBKey key1, DBKey key2, unsigned short maxlen) { - DB_COUNTSTAT(db_istring_cmp); - return strncasecmp((const char *)key1.str, (const char *)key2.str, maxlen); + DB_COUNTSTAT(db_istring_cmp); + return strncasecmp((const char *)key1.str, (const char *)key2.str, maxlen); } /** @@ -928,9 +928,9 @@ static int db_istring_cmp(DBKey key1, DBKey key2, unsigned short maxlen) */ static unsigned int db_int_hash(DBKey key, unsigned short maxlen) { - (void)maxlen;//not used - DB_COUNTSTAT(db_int_hash); - return (unsigned int)key.i; + (void)maxlen;//not used + DB_COUNTSTAT(db_int_hash); + return (unsigned int)key.i; } /** @@ -946,9 +946,9 @@ static unsigned int db_int_hash(DBKey key, unsigned short maxlen) */ static unsigned int db_uint_hash(DBKey key, unsigned short maxlen) { - (void)maxlen;//not used - DB_COUNTSTAT(db_uint_hash); - return key.ui; + (void)maxlen;//not used + DB_COUNTSTAT(db_uint_hash); + return key.ui; } /** @@ -962,20 +962,20 @@ static unsigned int db_uint_hash(DBKey key, unsigned short maxlen) */ static unsigned int db_string_hash(DBKey key, unsigned short maxlen) { - const char *k = key.str; - unsigned int hash = 0; - unsigned short i; + const char *k = key.str; + unsigned int hash = 0; + unsigned short i; - DB_COUNTSTAT(db_string_hash); + DB_COUNTSTAT(db_string_hash); - for (i = 0; *k; ++i) { - hash = (hash*33 + ((unsigned char)*k))^(hash>>24); - k++; - if (i == maxlen) - break; - } + for (i = 0; *k; ++i) { + hash = (hash*33 + ((unsigned char)*k))^(hash>>24); + k++; + if (i == maxlen) + break; + } - return hash; + return hash; } /** @@ -988,20 +988,20 @@ static unsigned int db_string_hash(DBKey key, unsigned short maxlen) */ static unsigned int db_istring_hash(DBKey key, unsigned short maxlen) { - const char *k = key.str; - unsigned int hash = 0; - unsigned short i; + const char *k = key.str; + unsigned int hash = 0; + unsigned short i; - DB_COUNTSTAT(db_istring_hash); + DB_COUNTSTAT(db_istring_hash); - for (i = 0; *k; i++) { - hash = (hash*33 + ((unsigned char)TOLOWER(*k)))^(hash>>24); - k++; - if (i == maxlen) - break; - } + for (i = 0; *k; i++) { + hash = (hash*33 + ((unsigned char)TOLOWER(*k)))^(hash>>24); + k++; + if (i == maxlen) + break; + } - return hash; + return hash; } /** @@ -1015,8 +1015,10 @@ static unsigned int db_istring_hash(DBKey key, unsigned short maxlen) */ static void db_release_nothing(DBKey key, DBData data, DBRelease which) { - (void)key;(void)data;(void)which;//not used - DB_COUNTSTAT(db_release_nothing); + (void)key; + (void)data; + (void)which;//not used + DB_COUNTSTAT(db_release_nothing); } /** @@ -1030,9 +1032,9 @@ static void db_release_nothing(DBKey key, DBData data, DBRelease which) */ static void db_release_key(DBKey key, DBData data, DBRelease which) { - (void)data;//not used - DB_COUNTSTAT(db_release_key); - if (which&DB_RELEASE_KEY) aFree((char*)key.str); // needs to be a pointer + (void)data;//not used + DB_COUNTSTAT(db_release_key); + if (which&DB_RELEASE_KEY) aFree((char *)key.str); // needs to be a pointer } /** @@ -1048,9 +1050,9 @@ static void db_release_key(DBKey key, DBData data, DBRelease which) */ static void db_release_data(DBKey key, DBData data, DBRelease which) { - (void)key;//not used - DB_COUNTSTAT(db_release_data); - if (which&DB_RELEASE_DATA && data.type == DB_DATA_PTR) aFree(data.u.ptr); + (void)key;//not used + DB_COUNTSTAT(db_release_data); + if (which&DB_RELEASE_DATA && data.type == DB_DATA_PTR) aFree(data.u.ptr); } /** @@ -1067,9 +1069,9 @@ static void db_release_data(DBKey key, DBData data, DBRelease which) */ static void db_release_both(DBKey key, DBData data, DBRelease which) { - DB_COUNTSTAT(db_release_both); - if (which&DB_RELEASE_KEY) aFree((char*)key.str); // needs to be a pointer - if (which&DB_RELEASE_DATA && data.type == DB_DATA_PTR) aFree(data.u.ptr); + DB_COUNTSTAT(db_release_both); + if (which&DB_RELEASE_KEY) aFree((char *)key.str); // needs to be a pointer + if (which&DB_RELEASE_DATA && data.type == DB_DATA_PTR) aFree(data.u.ptr); } /*****************************************************************************\ @@ -1115,16 +1117,16 @@ static void db_release_both(DBKey key, DBData data, DBRelease which) * @protected * @see DBIterator#first */ -DBData* dbit_obj_first(DBIterator* self, DBKey* out_key) +DBData *dbit_obj_first(DBIterator *self, DBKey *out_key) { - DBIterator_impl* it = (DBIterator_impl*)self; - - DB_COUNTSTAT(dbit_first); - // position before the first entry - it->ht_index = -1; - it->node = NULL; - // get next entry - return self->next(self, out_key); + DBIterator_impl *it = (DBIterator_impl *)self; + + DB_COUNTSTAT(dbit_first); + // position before the first entry + it->ht_index = -1; + it->node = NULL; + // get next entry + return self->next(self, out_key); } /** @@ -1137,16 +1139,16 @@ DBData* dbit_obj_first(DBIterator* self, DBKey* out_key) * @protected * @see DBIterator#last */ -DBData* dbit_obj_last(DBIterator* self, DBKey* out_key) +DBData *dbit_obj_last(DBIterator *self, DBKey *out_key) { - DBIterator_impl* it = (DBIterator_impl*)self; - - DB_COUNTSTAT(dbit_last); - // position after the last entry - it->ht_index = HASH_SIZE; - it->node = NULL; - // get previous entry - return self->prev(self, out_key); + DBIterator_impl *it = (DBIterator_impl *)self; + + DB_COUNTSTAT(dbit_last); + // position after the last entry + it->ht_index = HASH_SIZE; + it->node = NULL; + // get previous entry + return self->prev(self, out_key); } /** @@ -1159,70 +1161,67 @@ DBData* dbit_obj_last(DBIterator* self, DBKey* out_key) * @protected * @see DBIterator#next */ -DBData* dbit_obj_next(DBIterator* self, DBKey* out_key) -{ - DBIterator_impl* it = (DBIterator_impl*)self; - DBNode node; - DBNode parent; - struct dbn fake; - - DB_COUNTSTAT(dbit_next); - if( it->ht_index < 0 ) - {// get first node - it->ht_index = 0; - it->node = NULL; - } - node = it->node; - memset(&fake, 0, sizeof(fake)); - for( ; it->ht_index < HASH_SIZE; ++(it->ht_index) ) - { - // Iterate in the order: left tree, current node, right tree - if( node == NULL ) - {// prepare initial node of this hash - node = it->db->ht[it->ht_index]; - if( node == NULL ) - continue;// next hash - fake.right = node; - node = &fake; - } - - while( node ) - {// next node - if( node->right ) - {// continue in the right subtree - node = node->right; - while( node->left ) - node = node->left;// get leftmost node - } - else - {// continue to the next parent (recursive) - parent = node->parent; - while( parent ) - { - if( parent->right != node ) - break; - node = parent; - parent = node->parent; - } - if( parent == NULL ) - {// next hash - node = NULL; - break; - } - node = parent; - } - - if( !node->deleted ) - {// found next entry - it->node = node; - if( out_key ) - memcpy(out_key, &node->key, sizeof(DBKey)); - return &node->data; - } - } - } - it->node = NULL; - return NULL;// not found +DBData *dbit_obj_next(DBIterator *self, DBKey *out_key) +{ + DBIterator_impl *it = (DBIterator_impl *)self; + DBNode node; + DBNode parent; + struct dbn fake; + + DB_COUNTSTAT(dbit_next); + if (it->ht_index < 0) { + // get first node + it->ht_index = 0; + it->node = NULL; + } + node = it->node; + memset(&fake, 0, sizeof(fake)); + for (; it->ht_index < HASH_SIZE; ++(it->ht_index)) { + // Iterate in the order: left tree, current node, right tree + if (node == NULL) { + // prepare initial node of this hash + node = it->db->ht[it->ht_index]; + if (node == NULL) + continue;// next hash + fake.right = node; + node = &fake; + } + + while (node) { + // next node + if (node->right) { + // continue in the right subtree + node = node->right; + while (node->left) + node = node->left;// get leftmost node + } else { + // continue to the next parent (recursive) + parent = node->parent; + while (parent) { + if (parent->right != node) + break; + node = parent; + parent = node->parent; + } + if (parent == NULL) { + // next hash + node = NULL; + break; + } + node = parent; + } + + if (!node->deleted) { + // found next entry + it->node = node; + if (out_key) + memcpy(out_key, &node->key, sizeof(DBKey)); + return &node->data; + } + } + } + it->node = NULL; + return NULL;// not found } /** @@ -1235,93 +1234,90 @@ DBData* dbit_obj_next(DBIterator* self, DBKey* out_key) * @protected * @see DBIterator#prev */ -DBData* dbit_obj_prev(DBIterator* self, DBKey* out_key) -{ - DBIterator_impl* it = (DBIterator_impl*)self; - DBNode node; - DBNode parent; - struct dbn fake; - - DB_COUNTSTAT(dbit_prev); - if( it->ht_index >= HASH_SIZE ) - {// get last node - it->ht_index = HASH_SIZE-1; - it->node = NULL; - } - node = it->node; - memset(&fake, 0, sizeof(fake)); - for( ; it->ht_index >= 0; --(it->ht_index) ) - { - // Iterate in the order: right tree, current node, left tree - if( node == NULL ) - {// prepare initial node of this hash - node = it->db->ht[it->ht_index]; - if( node == NULL ) - continue;// next hash - fake.left = node; - node = &fake; - } - - - while( node ) - {// next node - if( node->left ) - {// continue in the left subtree - node = node->left; - while( node->right ) - node = node->right;// get rightmost node - } - else - {// continue to the next parent (recursive) - parent = node->parent; - while( parent ) - { - if( parent->left != node ) - break; - node = parent; - parent = node->parent; - } - if( parent == NULL ) - {// next hash - node = NULL; - break; - } - node = parent; - } - - if( !node->deleted ) - {// found previous entry - it->node = node; - if( out_key ) - memcpy(out_key, &node->key, sizeof(DBKey)); - return &node->data; - } - } - } - it->node = NULL; - return NULL;// not found +DBData *dbit_obj_prev(DBIterator *self, DBKey *out_key) +{ + DBIterator_impl *it = (DBIterator_impl *)self; + DBNode node; + DBNode parent; + struct dbn fake; + + DB_COUNTSTAT(dbit_prev); + if (it->ht_index >= HASH_SIZE) { + // get last node + it->ht_index = HASH_SIZE-1; + it->node = NULL; + } + node = it->node; + memset(&fake, 0, sizeof(fake)); + for (; it->ht_index >= 0; --(it->ht_index)) { + // Iterate in the order: right tree, current node, left tree + if (node == NULL) { + // prepare initial node of this hash + node = it->db->ht[it->ht_index]; + if (node == NULL) + continue;// next hash + fake.left = node; + node = &fake; + } + + + while (node) { + // next node + if (node->left) { + // continue in the left subtree + node = node->left; + while (node->right) + node = node->right;// get rightmost node + } else { + // continue to the next parent (recursive) + parent = node->parent; + while (parent) { + if (parent->left != node) + break; + node = parent; + parent = node->parent; + } + if (parent == NULL) { + // next hash + node = NULL; + break; + } + node = parent; + } + + if (!node->deleted) { + // found previous entry + it->node = node; + if (out_key) + memcpy(out_key, &node->key, sizeof(DBKey)); + return &node->data; + } + } + } + it->node = NULL; + return NULL;// not found } /** * Returns true if the fetched entry exists. - * The databases entries might have NULL data, so use this to to test if + * The databases entries might have NULL data, so use this to to test if * the iterator is done. * @param self Iterator * @return true if the entry exists * @protected * @see DBIterator#exists */ -bool dbit_obj_exists(DBIterator* self) +bool dbit_obj_exists(DBIterator *self) { - DBIterator_impl* it = (DBIterator_impl*)self; + DBIterator_impl *it = (DBIterator_impl *)self; - DB_COUNTSTAT(dbit_exists); - return (it->node && !it->node->deleted); + DB_COUNTSTAT(dbit_exists); + return (it->node && !it->node->deleted); } /** * Removes the current entry from the database. - * NOTE: {@link DBIterator#exists} will return false until another entry + * NOTE: {@link DBIterator#exists} will return false until another entry * is fetched * Puts data of the removed entry in out_data, if out_data is not NULL. * @param self Iterator @@ -1331,26 +1327,25 @@ bool dbit_obj_exists(DBIterator* self) * @see DBMap#remove * @see DBIterator#remove */ -int dbit_obj_remove(DBIterator* self, DBData *out_data) +int dbit_obj_remove(DBIterator *self, DBData *out_data) { - DBIterator_impl* it = (DBIterator_impl*)self; - DBNode node; - int retval = 0; + DBIterator_impl *it = (DBIterator_impl *)self; + DBNode node; + int retval = 0; - DB_COUNTSTAT(dbit_remove); - node = it->node; - if( node && !node->deleted ) - { - DBMap_impl* db = it->db; - if( db->cache == node ) - db->cache = NULL; - if( out_data ) - memcpy(out_data, &node->data, sizeof(DBData)); - retval = 1; - db->release(node->key, node->data, DB_RELEASE_DATA); - db_free_add(db, node, &db->ht[it->ht_index]); - } - return retval; + DB_COUNTSTAT(dbit_remove); + node = it->node; + if (node && !node->deleted) { + DBMap_impl *db = it->db; + if (db->cache == node) + db->cache = NULL; + if (out_data) + memcpy(out_data, &node->data, sizeof(DBData)); + retval = 1; + db->release(node->key, node->data, DB_RELEASE_DATA); + db_free_add(db, node, &db->ht[it->ht_index]); + } + return retval; } /** @@ -1358,48 +1353,48 @@ int dbit_obj_remove(DBIterator* self, DBData *out_data) * @param self Iterator * @protected */ -void dbit_obj_destroy(DBIterator* self) +void dbit_obj_destroy(DBIterator *self) { - DBIterator_impl* it = (DBIterator_impl*)self; + DBIterator_impl *it = (DBIterator_impl *)self; - DB_COUNTSTAT(dbit_destroy); - // unlock the database - db_free_unlock(it->db); - // free iterator - aFree(self); + DB_COUNTSTAT(dbit_destroy); + // unlock the database + db_free_unlock(it->db); + // free iterator + aFree(self); } /** * Returns a new iterator for this database. * The iterator keeps the database locked until it is destroyed. - * The database will keep functioning normally but will only free internal + * The database will keep functioning normally but will only free internal * memory when unlocked, so destroy the iterator as soon as possible. * @param self Database * @return New iterator * @protected */ -static DBIterator* db_obj_iterator(DBMap* self) +static DBIterator *db_obj_iterator(DBMap *self) { - DBMap_impl* db = (DBMap_impl*)self; - DBIterator_impl* it; + DBMap_impl *db = (DBMap_impl *)self; + DBIterator_impl *it; - DB_COUNTSTAT(db_iterator); - CREATE(it, struct DBIterator_impl, 1); - /* Interface of the iterator **/ - it->vtable.first = dbit_obj_first; - it->vtable.last = dbit_obj_last; - it->vtable.next = dbit_obj_next; - it->vtable.prev = dbit_obj_prev; - it->vtable.exists = dbit_obj_exists; - it->vtable.remove = dbit_obj_remove; - it->vtable.destroy = dbit_obj_destroy; - /* Initial state (before the first entry) */ - it->db = db; - it->ht_index = -1; - it->node = NULL; - /* Lock the database */ - db_free_lock(db); - return &it->vtable; + DB_COUNTSTAT(db_iterator); + CREATE(it, struct DBIterator_impl, 1); + /* Interface of the iterator **/ + it->vtable.first = dbit_obj_first; + it->vtable.last = dbit_obj_last; + it->vtable.next = dbit_obj_next; + it->vtable.prev = dbit_obj_prev; + it->vtable.exists = dbit_obj_exists; + it->vtable.remove = dbit_obj_remove; + it->vtable.destroy = dbit_obj_destroy; + /* Initial state (before the first entry) */ + it->db = db; + it->ht_index = -1; + it->node = NULL; + /* Lock the database */ + db_free_lock(db); + return &it->vtable; } /** @@ -1410,47 +1405,47 @@ static DBIterator* db_obj_iterator(DBMap* self) * @protected * @see DBMap#exists */ -static bool db_obj_exists(DBMap* self, DBKey key) +static bool db_obj_exists(DBMap *self, DBKey key) { - DBMap_impl* db = (DBMap_impl*)self; - DBNode node; - int c; - bool found = false; + DBMap_impl *db = (DBMap_impl *)self; + DBNode node; + int c; + bool found = false; - DB_COUNTSTAT(db_exists); - if (db == NULL) return false; // nullpo candidate - if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { - return false; // nullpo candidate - } + DB_COUNTSTAT(db_exists); + if (db == NULL) return false; // nullpo candidate + if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { + return false; // nullpo candidate + } - if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) { + if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) { #if defined(DEBUG) - if (db->cache->deleted) { - ShowDebug("db_exists: Cache contains a deleted node. Please report this!!!\n"); - return false; - } + if (db->cache->deleted) { + ShowDebug("db_exists: Cache contains a deleted node. Please report this!!!\n"); + return false; + } #endif - return true; // cache hit - } - - db_free_lock(db); - node = db->ht[db->hash(key, db->maxlen)%HASH_SIZE]; - while (node) { - c = db->cmp(key, node->key, db->maxlen); - if (c == 0) { - if (!(node->deleted)) { - db->cache = node; - found = true; - } - break; - } - if (c < 0) - node = node->left; - else - node = node->right; - } - db_free_unlock(db); - return found; + return true; // cache hit + } + + db_free_lock(db); + node = db->ht[db->hash(key, db->maxlen)%HASH_SIZE]; + while (node) { + c = db->cmp(key, node->key, db->maxlen); + if (c == 0) { + if (!(node->deleted)) { + db->cache = node; + found = true; + } + break; + } + if (c < 0) + node = node->left; + else + node = node->right; + } + db_free_unlock(db); + return found; } /** @@ -1461,48 +1456,48 @@ static bool db_obj_exists(DBMap* self, DBKey key) * @protected * @see DBMap#get */ -static DBData* db_obj_get(DBMap* self, DBKey key) +static DBData *db_obj_get(DBMap *self, DBKey key) { - DBMap_impl* db = (DBMap_impl*)self; - DBNode node; - int c; - DBData *data = NULL; + DBMap_impl *db = (DBMap_impl *)self; + DBNode node; + int c; + DBData *data = NULL; - DB_COUNTSTAT(db_get); - if (db == NULL) return NULL; // nullpo candidate - if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { - ShowError("db_get: Attempted to retrieve non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return NULL; // nullpo candidate - } + DB_COUNTSTAT(db_get); + if (db == NULL) return NULL; // nullpo candidate + if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { + ShowError("db_get: Attempted to retrieve non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return NULL; // nullpo candidate + } - if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) { + if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) { #if defined(DEBUG) - if (db->cache->deleted) { - ShowDebug("db_get: Cache contains a deleted node. Please report this!!!\n"); - return NULL; - } + if (db->cache->deleted) { + ShowDebug("db_get: Cache contains a deleted node. Please report this!!!\n"); + return NULL; + } #endif - return &db->cache->data; // cache hit - } - - db_free_lock(db); - node = db->ht[db->hash(key, db->maxlen)%HASH_SIZE]; - while (node) { - c = db->cmp(key, node->key, db->maxlen); - if (c == 0) { - if (!(node->deleted)) { - data = &node->data; - db->cache = node; - } - break; - } - if (c < 0) - node = node->left; - else - node = node->right; - } - db_free_unlock(db); - return data; + return &db->cache->data; // cache hit + } + + db_free_lock(db); + node = db->ht[db->hash(key, db->maxlen)%HASH_SIZE]; + while (node) { + c = db->cmp(key, node->key, db->maxlen); + if (c == 0) { + if (!(node->deleted)) { + data = &node->data; + db->cache = node; + } + break; + } + if (c < 0) + node = node->left; + else + node = node->right; + } + db_free_unlock(db); + return data; } /** @@ -1510,7 +1505,7 @@ static DBData* db_obj_get(DBMap* self, DBKey key) * It puts a maximum of max entries into buf. * If buf is NULL, it only counts the matches. * Returns the number of entries that matched. - * NOTE: if the value returned is greater than max, only the + * NOTE: if the value returned is greater than max, only the * first max entries found are put into the buffer. * @param self Interface of the database * @param buf Buffer to put the data of the matched entries @@ -1521,58 +1516,58 @@ static DBData* db_obj_get(DBMap* self, DBKey key) * @protected * @see DBMap#vgetall */ -static unsigned int db_obj_vgetall(DBMap* self, DBData **buf, unsigned int max, DBMatcher match, va_list args) -{ - DBMap_impl* db = (DBMap_impl*)self; - unsigned int i; - DBNode node; - DBNode parent; - unsigned int ret = 0; - - DB_COUNTSTAT(db_vgetall); - if (db == NULL) return 0; // nullpo candidate - if (match == NULL) return 0; // nullpo candidate - - db_free_lock(db); - for (i = 0; i < HASH_SIZE; i++) { - // Match in the order: current node, left tree, right tree - node = db->ht[i]; - while (node) { - - if (!(node->deleted)) { - va_list argscopy; - va_copy(argscopy, args); - if (match(node->key, node->data, argscopy) == 0) { - if (buf && ret < max) - buf[ret] = &node->data; - ret++; - } - va_end(argscopy); - } - - if (node->left) { - node = node->left; - continue; - } - - if (node->right) { - node = node->right; - continue; - } - - while (node) { - parent = node->parent; - if (parent && parent->right && parent->left == node) { - node = parent->right; - break; - } - node = parent; - } - - } - } - db_free_unlock(db); - return ret; +static unsigned int db_obj_vgetall(DBMap *self, DBData **buf, unsigned int max, DBMatcher match, va_list args) +{ + DBMap_impl *db = (DBMap_impl *)self; + unsigned int i; + DBNode node; + DBNode parent; + unsigned int ret = 0; + + DB_COUNTSTAT(db_vgetall); + if (db == NULL) return 0; // nullpo candidate + if (match == NULL) return 0; // nullpo candidate + + db_free_lock(db); + for (i = 0; i < HASH_SIZE; i++) { + // Match in the order: current node, left tree, right tree + node = db->ht[i]; + while (node) { + + if (!(node->deleted)) { + va_list argscopy; + va_copy(argscopy, args); + if (match(node->key, node->data, argscopy) == 0) { + if (buf && ret < max) + buf[ret] = &node->data; + ret++; + } + va_end(argscopy); + } + + if (node->left) { + node = node->left; + continue; + } + + if (node->right) { + node = node->right; + continue; + } + + while (node) { + parent = node->parent; + if (parent && parent->right && parent->left == node) { + node = parent->right; + break; + } + node = parent; + } + + } + } + db_free_unlock(db); + return ret; } /** @@ -1581,7 +1576,7 @@ static unsigned int db_obj_vgetall(DBMap* self, DBData **buf, unsigned int max, * It puts a maximum of max entries into buf. * If buf is NULL, it only counts the matches. * Returns the number of entries that matched. - * NOTE: if the value returned is greater than max, only the + * NOTE: if the value returned is greater than max, only the * first max entries found are put into the buffer. * @param self Interface of the database * @param buf Buffer to put the data of the matched entries @@ -1593,23 +1588,23 @@ static unsigned int db_obj_vgetall(DBMap* self, DBData **buf, unsigned int max, * @see DBMap#vgetall * @see DBMap#getall */ -static unsigned int db_obj_getall(DBMap* self, DBData **buf, unsigned int max, DBMatcher match, ...) +static unsigned int db_obj_getall(DBMap *self, DBData **buf, unsigned int max, DBMatcher match, ...) { - va_list args; - unsigned int ret; + va_list args; + unsigned int ret; - DB_COUNTSTAT(db_getall); - if (self == NULL) return 0; // nullpo candidate + DB_COUNTSTAT(db_getall); + if (self == NULL) return 0; // nullpo candidate - va_start(args, match); - ret = self->vgetall(self, buf, max, match, args); - va_end(args); - return ret; + va_start(args, match); + ret = self->vgetall(self, buf, max, match, args); + va_end(args); + return ret; } /** * Get the data of the entry identified by the key. - * If the entry does not exist, an entry is added with the data returned by + * If the entry does not exist, an entry is added with the data returned by * create. * @param self Interface of the database * @param key Key that identifies the entry @@ -1619,96 +1614,96 @@ static unsigned int db_obj_getall(DBMap* self, DBData **buf, unsigned int max, D * @protected * @see DBMap#vensure */ -static DBData* db_obj_vensure(DBMap* self, DBKey key, DBCreateData create, va_list args) -{ - DBMap_impl* db = (DBMap_impl*)self; - DBNode node; - DBNode parent = NULL; - unsigned int hash; - int c = 0; - DBData *data = NULL; - - DB_COUNTSTAT(db_vensure); - if (db == NULL) return NULL; // nullpo candidate - if (create == NULL) { - ShowError("db_ensure: Create function is NULL for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return NULL; // nullpo candidate - } - if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { - ShowError("db_ensure: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return NULL; // nullpo candidate - } - - if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) - return &db->cache->data; // cache hit - - db_free_lock(db); - hash = db->hash(key, db->maxlen)%HASH_SIZE; - node = db->ht[hash]; - while (node) { - c = db->cmp(key, node->key, db->maxlen); - if (c == 0) { - break; - } - parent = node; - if (c < 0) - node = node->left; - else - node = node->right; - } - // Create node if necessary - if (node == NULL) { - va_list argscopy; - if (db->item_count == UINT32_MAX) { - ShowError("db_vensure: item_count overflow, aborting item insertion.\n" - "Database allocated at %s:%d", - db->alloc_file, db->alloc_line); - return NULL; - } - DB_COUNTSTAT(db_node_alloc); - node = ers_alloc(db->nodes, struct dbn); - node->left = NULL; - node->right = NULL; - node->deleted = 0; - db->item_count++; - if (c == 0) { // hash entry is empty - node->color = BLACK; - node->parent = NULL; - db->ht[hash] = node; - } else { - node->color = RED; - if (c < 0) { // put at the left - parent->left = node; - node->parent = parent; - } else { // put at the right - parent->right = node; - node->parent = parent; - } - if (parent->color == RED) // two consecutive RED nodes, must rebalance - db_rebalance(node, &db->ht[hash]); - } - // put key and data in the node - if (db->options&DB_OPT_DUP_KEY) { - node->key = db_dup_key(db, key); - if (db->options&DB_OPT_RELEASE_KEY) - db->release(key, *data, DB_RELEASE_KEY); - } else { - node->key = key; - } - va_copy(argscopy, args); - node->data = create(key, argscopy); - va_end(argscopy); - } - data = &node->data; - db->cache = node; - db_free_unlock(db); - return data; +static DBData *db_obj_vensure(DBMap *self, DBKey key, DBCreateData create, va_list args) +{ + DBMap_impl *db = (DBMap_impl *)self; + DBNode node; + DBNode parent = NULL; + unsigned int hash; + int c = 0; + DBData *data = NULL; + + DB_COUNTSTAT(db_vensure); + if (db == NULL) return NULL; // nullpo candidate + if (create == NULL) { + ShowError("db_ensure: Create function is NULL for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return NULL; // nullpo candidate + } + if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { + ShowError("db_ensure: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return NULL; // nullpo candidate + } + + if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) + return &db->cache->data; // cache hit + + db_free_lock(db); + hash = db->hash(key, db->maxlen)%HASH_SIZE; + node = db->ht[hash]; + while (node) { + c = db->cmp(key, node->key, db->maxlen); + if (c == 0) { + break; + } + parent = node; + if (c < 0) + node = node->left; + else + node = node->right; + } + // Create node if necessary + if (node == NULL) { + va_list argscopy; + if (db->item_count == UINT32_MAX) { + ShowError("db_vensure: item_count overflow, aborting item insertion.\n" + "Database allocated at %s:%d", + db->alloc_file, db->alloc_line); + return NULL; + } + DB_COUNTSTAT(db_node_alloc); + node = ers_alloc(db->nodes, struct dbn); + node->left = NULL; + node->right = NULL; + node->deleted = 0; + db->item_count++; + if (c == 0) { // hash entry is empty + node->color = BLACK; + node->parent = NULL; + db->ht[hash] = node; + } else { + node->color = RED; + if (c < 0) { // put at the left + parent->left = node; + node->parent = parent; + } else { // put at the right + parent->right = node; + node->parent = parent; + } + if (parent->color == RED) // two consecutive RED nodes, must rebalance + db_rebalance(node, &db->ht[hash]); + } + // put key and data in the node + if (db->options&DB_OPT_DUP_KEY) { + node->key = db_dup_key(db, key); + if (db->options&DB_OPT_RELEASE_KEY) + db->release(key, *data, DB_RELEASE_KEY); + } else { + node->key = key; + } + va_copy(argscopy, args); + node->data = create(key, argscopy); + va_end(argscopy); + } + data = &node->data; + db->cache = node; + db_free_unlock(db); + return data; } /** * Just calls {@link DBMap#vensure}. * Get the data of the entry identified by the key. - * If the entry does not exist, an entry is added with the data returned by + * If the entry does not exist, an entry is added with the data returned by * create. * @param self Interface of the database * @param key Key that identifies the entry @@ -1719,18 +1714,18 @@ static DBData* db_obj_vensure(DBMap* self, DBKey key, DBCreateData create, va_li * @see DBMap#vensure * @see DBMap#ensure */ -static DBData* db_obj_ensure(DBMap* self, DBKey key, DBCreateData create, ...) +static DBData *db_obj_ensure(DBMap *self, DBKey key, DBCreateData create, ...) { - va_list args; - DBData *ret = NULL; + va_list args; + DBData *ret = NULL; - DB_COUNTSTAT(db_ensure); - if (self == NULL) return NULL; // nullpo candidate + DB_COUNTSTAT(db_ensure); + if (self == NULL) return NULL; // nullpo candidate - va_start(args, create); - ret = self->vensure(self, key, create, args); - va_end(args); - return ret; + va_start(args, create); + ret = self->vensure(self, key, create, args); + va_end(args); + return ret; } /** @@ -1746,97 +1741,97 @@ static DBData* db_obj_ensure(DBMap* self, DBKey key, DBCreateData create, ...) * @see #db_malloc_dbn(void) * @see DBMap#put */ -static int db_obj_put(DBMap* self, DBKey key, DBData data, DBData *out_data) -{ - DBMap_impl* db = (DBMap_impl*)self; - DBNode node; - DBNode parent = NULL; - int c = 0, retval = 0; - unsigned int hash; - - DB_COUNTSTAT(db_put); - if (db == NULL) return 0; // nullpo candidate - if (db->global_lock) { - ShowError("db_put: Database is being destroyed, aborting entry insertion.\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - return 0; // nullpo candidate - } - if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { - ShowError("db_put: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return 0; // nullpo candidate - } - if (!(db->options&DB_OPT_ALLOW_NULL_DATA) && (data.type == DB_DATA_PTR && data.u.ptr == NULL)) { - ShowError("db_put: Attempted to use non-allowed NULL data for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return 0; // nullpo candidate - } - - if (db->item_count == UINT32_MAX) { - ShowError("db_put: item_count overflow, aborting item insertion.\n" - "Database allocated at %s:%d", - db->alloc_file, db->alloc_line); - return 0; - } - // search for an equal node - db_free_lock(db); - hash = db->hash(key, db->maxlen)%HASH_SIZE; - for (node = db->ht[hash]; node; ) { - c = db->cmp(key, node->key, db->maxlen); - if (c == 0) { // equal entry, replace - if (node->deleted) { - db_free_remove(db, node); - } else { - db->release(node->key, node->data, DB_RELEASE_BOTH); - if (out_data) - memcpy(out_data, &node->data, sizeof(*out_data)); - retval = 1; - } - break; - } - parent = node; - if (c < 0) { - node = node->left; - } else { - node = node->right; - } - } - // allocate a new node if necessary - if (node == NULL) { - DB_COUNTSTAT(db_node_alloc); - node = ers_alloc(db->nodes, struct dbn); - node->left = NULL; - node->right = NULL; - node->deleted = 0; - db->item_count++; - if (c == 0) { // hash entry is empty - node->color = BLACK; - node->parent = NULL; - db->ht[hash] = node; - } else { - node->color = RED; - if (c < 0) { // put at the left - parent->left = node; - node->parent = parent; - } else { // put at the right - parent->right = node; - node->parent = parent; - } - if (parent->color == RED) // two consecutive RED nodes, must rebalance - db_rebalance(node, &db->ht[hash]); - } - } - // put key and data in the node - if (db->options&DB_OPT_DUP_KEY) { - node->key = db_dup_key(db, key); - if (db->options&DB_OPT_RELEASE_KEY) - db->release(key, data, DB_RELEASE_KEY); - } else { - node->key = key; - } - node->data = data; - db->cache = node; - db_free_unlock(db); - return retval; +static int db_obj_put(DBMap *self, DBKey key, DBData data, DBData *out_data) +{ + DBMap_impl *db = (DBMap_impl *)self; + DBNode node; + DBNode parent = NULL; + int c = 0, retval = 0; + unsigned int hash; + + DB_COUNTSTAT(db_put); + if (db == NULL) return 0; // nullpo candidate + if (db->global_lock) { + ShowError("db_put: Database is being destroyed, aborting entry insertion.\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + return 0; // nullpo candidate + } + if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { + ShowError("db_put: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return 0; // nullpo candidate + } + if (!(db->options&DB_OPT_ALLOW_NULL_DATA) && (data.type == DB_DATA_PTR && data.u.ptr == NULL)) { + ShowError("db_put: Attempted to use non-allowed NULL data for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return 0; // nullpo candidate + } + + if (db->item_count == UINT32_MAX) { + ShowError("db_put: item_count overflow, aborting item insertion.\n" + "Database allocated at %s:%d", + db->alloc_file, db->alloc_line); + return 0; + } + // search for an equal node + db_free_lock(db); + hash = db->hash(key, db->maxlen)%HASH_SIZE; + for (node = db->ht[hash]; node;) { + c = db->cmp(key, node->key, db->maxlen); + if (c == 0) { // equal entry, replace + if (node->deleted) { + db_free_remove(db, node); + } else { + db->release(node->key, node->data, DB_RELEASE_BOTH); + if (out_data) + memcpy(out_data, &node->data, sizeof(*out_data)); + retval = 1; + } + break; + } + parent = node; + if (c < 0) { + node = node->left; + } else { + node = node->right; + } + } + // allocate a new node if necessary + if (node == NULL) { + DB_COUNTSTAT(db_node_alloc); + node = ers_alloc(db->nodes, struct dbn); + node->left = NULL; + node->right = NULL; + node->deleted = 0; + db->item_count++; + if (c == 0) { // hash entry is empty + node->color = BLACK; + node->parent = NULL; + db->ht[hash] = node; + } else { + node->color = RED; + if (c < 0) { // put at the left + parent->left = node; + node->parent = parent; + } else { // put at the right + parent->right = node; + node->parent = parent; + } + if (parent->color == RED) // two consecutive RED nodes, must rebalance + db_rebalance(node, &db->ht[hash]); + } + } + // put key and data in the node + if (db->options&DB_OPT_DUP_KEY) { + node->key = db_dup_key(db, key); + if (db->options&DB_OPT_RELEASE_KEY) + db->release(key, data, DB_RELEASE_KEY); + } else { + node->key = key; + } + node->data = data; + db->cache = node; + db_free_unlock(db); + return retval; } /** @@ -1851,49 +1846,49 @@ static int db_obj_put(DBMap* self, DBKey key, DBData data, DBData *out_data) * @see #db_free_add(DBMap_impl*,DBNode,DBNode *) * @see DBMap#remove */ -static int db_obj_remove(DBMap* self, DBKey key, DBData *out_data) -{ - DBMap_impl* db = (DBMap_impl*)self; - DBNode node; - unsigned int hash; - int c = 0, retval = 0; - - DB_COUNTSTAT(db_remove); - if (db == NULL) return 0; // nullpo candidate - if (db->global_lock) { - ShowError("db_remove: Database is being destroyed. Aborting entry deletion.\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - return 0; // nullpo candidate - } - if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { - ShowError("db_remove: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return 0; // nullpo candidate - } - - db_free_lock(db); - hash = db->hash(key, db->maxlen)%HASH_SIZE; - for(node = db->ht[hash]; node; ){ - c = db->cmp(key, node->key, db->maxlen); - if (c == 0) { - if (!(node->deleted)) { - if (db->cache == node) - db->cache = NULL; - if (out_data) - memcpy(out_data, &node->data, sizeof(*out_data)); - retval = 1; - db->release(node->key, node->data, DB_RELEASE_DATA); - db_free_add(db, node, &db->ht[hash]); - } - break; - } - if (c < 0) - node = node->left; - else - node = node->right; - } - db_free_unlock(db); - return retval; +static int db_obj_remove(DBMap *self, DBKey key, DBData *out_data) +{ + DBMap_impl *db = (DBMap_impl *)self; + DBNode node; + unsigned int hash; + int c = 0, retval = 0; + + DB_COUNTSTAT(db_remove); + if (db == NULL) return 0; // nullpo candidate + if (db->global_lock) { + ShowError("db_remove: Database is being destroyed. Aborting entry deletion.\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + return 0; // nullpo candidate + } + if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) { + ShowError("db_remove: Attempted to use non-allowed NULL key for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return 0; // nullpo candidate + } + + db_free_lock(db); + hash = db->hash(key, db->maxlen)%HASH_SIZE; + for (node = db->ht[hash]; node;) { + c = db->cmp(key, node->key, db->maxlen); + if (c == 0) { + if (!(node->deleted)) { + if (db->cache == node) + db->cache = NULL; + if (out_data) + memcpy(out_data, &node->data, sizeof(*out_data)); + retval = 1; + db->release(node->key, node->data, DB_RELEASE_DATA); + db_free_add(db, node, &db->ht[hash]); + } + break; + } + if (c < 0) + node = node->left; + else + node = node->right; + } + db_free_unlock(db); + return retval; } /** @@ -1906,52 +1901,52 @@ static int db_obj_remove(DBMap* self, DBKey key, DBData *out_data) * @protected * @see DBMap#vforeach */ -static int db_obj_vforeach(DBMap* self, DBApply func, va_list args) -{ - DBMap_impl* db = (DBMap_impl*)self; - unsigned int i; - int sum = 0; - DBNode node; - DBNode parent; - - DB_COUNTSTAT(db_vforeach); - if (db == NULL) return 0; // nullpo candidate - if (func == NULL) { - ShowError("db_foreach: Passed function is NULL for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); - return 0; // nullpo candidate - } - - db_free_lock(db); - for (i = 0; i < HASH_SIZE; i++) { - // Apply func in the order: current node, left node, right node - node = db->ht[i]; - while (node) { - if (!(node->deleted)) { - va_list argscopy; - va_copy(argscopy, args); - sum += func(node->key, &node->data, argscopy); - va_end(argscopy); - } - if (node->left) { - node = node->left; - continue; - } - if (node->right) { - node = node->right; - continue; - } - while (node) { - parent = node->parent; - if (parent && parent->right && parent->left == node) { - node = parent->right; - break; - } - node = parent; - } - } - } - db_free_unlock(db); - return sum; +static int db_obj_vforeach(DBMap *self, DBApply func, va_list args) +{ + DBMap_impl *db = (DBMap_impl *)self; + unsigned int i; + int sum = 0; + DBNode node; + DBNode parent; + + DB_COUNTSTAT(db_vforeach); + if (db == NULL) return 0; // nullpo candidate + if (func == NULL) { + ShowError("db_foreach: Passed function is NULL for db allocated at %s:%d\n",db->alloc_file, db->alloc_line); + return 0; // nullpo candidate + } + + db_free_lock(db); + for (i = 0; i < HASH_SIZE; i++) { + // Apply func in the order: current node, left node, right node + node = db->ht[i]; + while (node) { + if (!(node->deleted)) { + va_list argscopy; + va_copy(argscopy, args); + sum += func(node->key, &node->data, argscopy); + va_end(argscopy); + } + if (node->left) { + node = node->left; + continue; + } + if (node->right) { + node = node->right; + continue; + } + while (node) { + parent = node->parent; + if (parent && parent->right && parent->left == node) { + node = parent->right; + break; + } + node = parent; + } + } + } + db_free_unlock(db); + return sum; } /** @@ -1966,18 +1961,18 @@ static int db_obj_vforeach(DBMap* self, DBApply func, va_list args) * @see DBMap#vforeach * @see DBMap#foreach */ -static int db_obj_foreach(DBMap* self, DBApply func, ...) +static int db_obj_foreach(DBMap *self, DBApply func, ...) { - va_list args; - int ret; + va_list args; + int ret; - DB_COUNTSTAT(db_foreach); - if (self == NULL) return 0; // nullpo candidate + DB_COUNTSTAT(db_foreach); + if (self == NULL) return 0; // nullpo candidate - va_start(args, func); - ret = self->vforeach(self, func, args); - va_end(args); - return ret; + va_start(args, func); + ret = self->vforeach(self, func, args); + va_end(args); + return ret; } /** @@ -1992,62 +1987,61 @@ static int db_obj_foreach(DBMap* self, DBApply func, ...) * @protected * @see DBMap#vclear */ -static int db_obj_vclear(DBMap* self, DBApply func, va_list args) -{ - DBMap_impl* db = (DBMap_impl*)self; - int sum = 0; - unsigned int i; - DBNode node; - DBNode parent; - - DB_COUNTSTAT(db_vclear); - if (db == NULL) return 0; // nullpo candidate - - db_free_lock(db); - db->cache = NULL; - for (i = 0; i < HASH_SIZE; i++) { - // Apply the func and delete in the order: left tree, right tree, current node - node = db->ht[i]; - db->ht[i] = NULL; - while (node) { - parent = node->parent; - if (node->left) { - node = node->left; - continue; - } - if (node->right) { - node = node->right; - continue; - } - if (node->deleted) { - db_dup_key_free(db, node->key); - } else { - if (func) - { - va_list argscopy; - va_copy(argscopy, args); - sum += func(node->key, &node->data, argscopy); - va_end(argscopy); - } - db->release(node->key, node->data, DB_RELEASE_BOTH); - node->deleted = 1; - } - DB_COUNTSTAT(db_node_free); - if (parent) { - if (parent->left == node) - parent->left = NULL; - else - parent->right = NULL; - } - ers_free(db->nodes, node); - node = parent; - } - db->ht[i] = NULL; - } - db->free_count = 0; - db->item_count = 0; - db_free_unlock(db); - return sum; +static int db_obj_vclear(DBMap *self, DBApply func, va_list args) +{ + DBMap_impl *db = (DBMap_impl *)self; + int sum = 0; + unsigned int i; + DBNode node; + DBNode parent; + + DB_COUNTSTAT(db_vclear); + if (db == NULL) return 0; // nullpo candidate + + db_free_lock(db); + db->cache = NULL; + for (i = 0; i < HASH_SIZE; i++) { + // Apply the func and delete in the order: left tree, right tree, current node + node = db->ht[i]; + db->ht[i] = NULL; + while (node) { + parent = node->parent; + if (node->left) { + node = node->left; + continue; + } + if (node->right) { + node = node->right; + continue; + } + if (node->deleted) { + db_dup_key_free(db, node->key); + } else { + if (func) { + va_list argscopy; + va_copy(argscopy, args); + sum += func(node->key, &node->data, argscopy); + va_end(argscopy); + } + db->release(node->key, node->data, DB_RELEASE_BOTH); + node->deleted = 1; + } + DB_COUNTSTAT(db_node_free); + if (parent) { + if (parent->left == node) + parent->left = NULL; + else + parent->right = NULL; + } + ers_free(db->nodes, node); + node = parent; + } + db->ht[i] = NULL; + } + db->free_count = 0; + db->item_count = 0; + db_free_unlock(db); + return sum; } /** @@ -2056,7 +2050,7 @@ static int db_obj_vclear(DBMap* self, DBApply func, va_list args) * Before deleting an entry, func is applied to it. * Releases the key and the data. * Returns the sum of values returned by func, if it exists. - * NOTE: This locks the database globally. Any attempt to insert or remove + * NOTE: This locks the database globally. Any attempt to insert or remove * a database entry will give an error and be aborted (except for clearing). * @param self Interface of the database * @param func Function to be applied to every entry before deleting @@ -2066,25 +2060,25 @@ static int db_obj_vclear(DBMap* self, DBApply func, va_list args) * @see DBMap#vclear * @see DBMap#clear */ -static int db_obj_clear(DBMap* self, DBApply func, ...) +static int db_obj_clear(DBMap *self, DBApply func, ...) { - va_list args; - int ret; + va_list args; + int ret; - DB_COUNTSTAT(db_clear); - if (self == NULL) return 0; // nullpo candidate + DB_COUNTSTAT(db_clear); + if (self == NULL) return 0; // nullpo candidate - va_start(args, func); - ret = self->vclear(self, func, args); - va_end(args); - return ret; + va_start(args, func); + ret = self->vclear(self, func, args); + va_end(args); + return ret; } /** * Finalize the database, feeing all the memory it uses. * Before deleting an entry, func is applied to it. * Returns the sum of values returned by func, if it exists. - * NOTE: This locks the database globally. Any attempt to insert or remove + * NOTE: This locks the database globally. Any attempt to insert or remove * a database entry will give an error and be aborted (except for clearing). * @param self Interface of the database * @param func Function to be applied to every entry before deleting @@ -2093,42 +2087,50 @@ static int db_obj_clear(DBMap* self, DBApply func, ...) * @protected * @see DBMap#vdestroy */ -static int db_obj_vdestroy(DBMap* self, DBApply func, va_list args) +static int db_obj_vdestroy(DBMap *self, DBApply func, va_list args) { - DBMap_impl* db = (DBMap_impl*)self; - int sum; + DBMap_impl *db = (DBMap_impl *)self; + int sum; - DB_COUNTSTAT(db_vdestroy); - if (db == NULL) return 0; // nullpo candidate - if (db->global_lock) { - ShowError("db_vdestroy: Database is already locked for destruction. Aborting second database destruction.\n" - "Database allocated at %s:%d\n", - db->alloc_file, db->alloc_line); - return 0; - } - if (db->free_lock) - ShowWarning("db_vdestroy: Database is still in use, %u lock(s) left. Continuing database destruction.\n" - "Database allocated at %s:%d\n", - db->free_lock, db->alloc_file, db->alloc_line); + DB_COUNTSTAT(db_vdestroy); + if (db == NULL) return 0; // nullpo candidate + if (db->global_lock) { + ShowError("db_vdestroy: Database is already locked for destruction. Aborting second database destruction.\n" + "Database allocated at %s:%d\n", + db->alloc_file, db->alloc_line); + return 0; + } + if (db->free_lock) + ShowWarning("db_vdestroy: Database is still in use, %u lock(s) left. Continuing database destruction.\n" + "Database allocated at %s:%d\n", + db->free_lock, db->alloc_file, db->alloc_line); #ifdef DB_ENABLE_STATS - switch (db->type) { - case DB_INT: DB_COUNTSTAT(db_int_destroy); break; - case DB_UINT: DB_COUNTSTAT(db_uint_destroy); break; - case DB_STRING: DB_COUNTSTAT(db_string_destroy); break; - case DB_ISTRING: DB_COUNTSTAT(db_istring_destroy); break; - } + switch (db->type) { + case DB_INT: + DB_COUNTSTAT(db_int_destroy); + break; + case DB_UINT: + DB_COUNTSTAT(db_uint_destroy); + break; + case DB_STRING: + DB_COUNTSTAT(db_string_destroy); + break; + case DB_ISTRING: + DB_COUNTSTAT(db_istring_destroy); + break; + } #endif /* DB_ENABLE_STATS */ - db_free_lock(db); - db->global_lock = 1; - sum = self->vclear(self, func, args); - aFree(db->free_list); - db->free_list = NULL; - db->free_max = 0; - ers_destroy(db->nodes); - db_free_unlock(db); - aFree(db); - return sum; + db_free_lock(db); + db->global_lock = 1; + sum = self->vclear(self, func, args); + aFree(db->free_list); + db->free_list = NULL; + db->free_max = 0; + ers_destroy(db->nodes); + db_free_unlock(db); + aFree(db); + return sum; } /** @@ -2137,7 +2139,7 @@ static int db_obj_vdestroy(DBMap* self, DBApply func, va_list args) * Before deleting an entry, func is applied to it. * Releases the key and the data. * Returns the sum of values returned by func, if it exists. - * NOTE: This locks the database globally. Any attempt to insert or remove + * NOTE: This locks the database globally. Any attempt to insert or remove * a database entry will give an error and be aborted. * @param self Database * @param func Function to be applied to every entry before deleting @@ -2147,18 +2149,18 @@ static int db_obj_vdestroy(DBMap* self, DBApply func, va_list args) * @see DBMap#vdestroy * @see DBMap#destroy */ -static int db_obj_destroy(DBMap* self, DBApply func, ...) +static int db_obj_destroy(DBMap *self, DBApply func, ...) { - va_list args; - int ret; + va_list args; + int ret; - DB_COUNTSTAT(db_destroy); - if (self == NULL) return 0; // nullpo candidate + DB_COUNTSTAT(db_destroy); + if (self == NULL) return 0; // nullpo candidate - va_start(args, func); - ret = self->vdestroy(self, func, args); - va_end(args); - return ret; + va_start(args, func); + ret = self->vdestroy(self, func, args); + va_end(args); + return ret; } /** @@ -2169,19 +2171,19 @@ static int db_obj_destroy(DBMap* self, DBApply func, ...) * @see DBMap_impl#item_count * @see DBMap#size */ -static unsigned int db_obj_size(DBMap* self) +static unsigned int db_obj_size(DBMap *self) { - DBMap_impl* db = (DBMap_impl*)self; - unsigned int item_count; + DBMap_impl *db = (DBMap_impl *)self; + unsigned int item_count; - DB_COUNTSTAT(db_size); - if (db == NULL) return 0; // nullpo candidate + DB_COUNTSTAT(db_size); + if (db == NULL) return 0; // nullpo candidate - db_free_lock(db); - item_count = db->item_count; - db_free_unlock(db); + db_free_lock(db); + item_count = db->item_count; + db_free_unlock(db); - return item_count; + return item_count; } /** @@ -2192,19 +2194,19 @@ static unsigned int db_obj_size(DBMap* self) * @see DBMap_impl#type * @see DBMap#type */ -static DBType db_obj_type(DBMap* self) +static DBType db_obj_type(DBMap *self) { - DBMap_impl* db = (DBMap_impl*)self; - DBType type; + DBMap_impl *db = (DBMap_impl *)self; + DBType type; - DB_COUNTSTAT(db_type); - if (db == NULL) return (DBType)-1; // nullpo candidate - TODO what should this return? + DB_COUNTSTAT(db_type); + if (db == NULL) return (DBType)-1; // nullpo candidate - TODO what should this return? - db_free_lock(db); - type = db->type; - db_free_unlock(db); + db_free_lock(db); + type = db->type; + db_free_unlock(db); - return type; + return type; } /** @@ -2215,19 +2217,19 @@ static DBType db_obj_type(DBMap* self) * @see DBMap_impl#options * @see DBMap#options */ -static DBOptions db_obj_options(DBMap* self) +static DBOptions db_obj_options(DBMap *self) { - DBMap_impl* db = (DBMap_impl*)self; - DBOptions options; + DBMap_impl *db = (DBMap_impl *)self; + DBOptions options; - DB_COUNTSTAT(db_options); - if (db == NULL) return DB_OPT_BASE; // nullpo candidate - TODO what should this return? + DB_COUNTSTAT(db_options); + if (db == NULL) return DB_OPT_BASE; // nullpo candidate - TODO what should this return? - db_free_lock(db); - options = db->options; - db_free_unlock(db); + db_free_lock(db); + options = db->options; + db_free_unlock(db); - return options; + return options; } /*****************************************************************************\ @@ -2264,18 +2266,18 @@ static DBOptions db_obj_options(DBMap* self) */ DBOptions db_fix_options(DBType type, DBOptions options) { - DB_COUNTSTAT(db_fix_options); - switch (type) { - case DB_INT: - case DB_UINT: // Numeric database, do nothing with the keys - return (DBOptions)(options&~(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)); + DB_COUNTSTAT(db_fix_options); + switch (type) { + case DB_INT: + case DB_UINT: // Numeric database, do nothing with the keys + return (DBOptions)(options&~(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)); - default: - ShowError("db_fix_options: Unknown database type %u with options %x\n", type, options); - case DB_STRING: - case DB_ISTRING: // String databases, no fix required - return options; - } + default: + ShowError("db_fix_options: Unknown database type %u with options %x\n", type, options); + case DB_STRING: + case DB_ISTRING: // String databases, no fix required + return options; + } } /** @@ -2290,16 +2292,20 @@ DBOptions db_fix_options(DBType type, DBOptions options) */ DBComparator db_default_cmp(DBType type) { - DB_COUNTSTAT(db_default_cmp); - switch (type) { - case DB_INT: return &db_int_cmp; - case DB_UINT: return &db_uint_cmp; - case DB_STRING: return &db_string_cmp; - case DB_ISTRING: return &db_istring_cmp; - default: - ShowError("db_default_cmp: Unknown database type %u\n", type); - return NULL; - } + DB_COUNTSTAT(db_default_cmp); + switch (type) { + case DB_INT: + return &db_int_cmp; + case DB_UINT: + return &db_uint_cmp; + case DB_STRING: + return &db_string_cmp; + case DB_ISTRING: + return &db_istring_cmp; + default: + ShowError("db_default_cmp: Unknown database type %u\n", type); + return NULL; + } } /** @@ -2314,20 +2320,24 @@ DBComparator db_default_cmp(DBType type) */ DBHasher db_default_hash(DBType type) { - DB_COUNTSTAT(db_default_hash); - switch (type) { - case DB_INT: return &db_int_hash; - case DB_UINT: return &db_uint_hash; - case DB_STRING: return &db_string_hash; - case DB_ISTRING: return &db_istring_hash; - default: - ShowError("db_default_hash: Unknown database type %u\n", type); - return NULL; - } + DB_COUNTSTAT(db_default_hash); + switch (type) { + case DB_INT: + return &db_int_hash; + case DB_UINT: + return &db_uint_hash; + case DB_STRING: + return &db_string_hash; + case DB_ISTRING: + return &db_istring_hash; + default: + ShowError("db_default_hash: Unknown database type %u\n", type); + return NULL; + } } /** - * Returns the default releaser for the specified type of database with the + * Returns the default releaser for the specified type of database with the * specified options. * NOTE: the options are fixed with {@link #db_fix_options(DBType,DBOptions)} * before choosing the releaser. @@ -2343,16 +2353,16 @@ DBHasher db_default_hash(DBType type) */ DBReleaser db_default_release(DBType type, DBOptions options) { - DB_COUNTSTAT(db_default_release); - options = db_fix_options(type, options); - if (options&DB_OPT_RELEASE_DATA) { // Release data, what about the key? - if (options&(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)) - return &db_release_both; // Release both key and data - return &db_release_data; // Only release data - } - if (options&(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)) - return &db_release_key; // Only release key - return &db_release_nothing; // Release nothing + DB_COUNTSTAT(db_default_release); + options = db_fix_options(type, options); + if (options&DB_OPT_RELEASE_DATA) { // Release data, what about the key? + if (options&(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)) + return &db_release_both; // Release both key and data + return &db_release_data; // Only release data + } + if (options&(DB_OPT_DUP_KEY|DB_OPT_RELEASE_KEY)) + return &db_release_key; // Only release key + return &db_release_nothing; // Release nothing } /** @@ -2368,16 +2378,20 @@ DBReleaser db_default_release(DBType type, DBOptions options) */ DBReleaser db_custom_release(DBRelease which) { - DB_COUNTSTAT(db_custom_release); - switch (which) { - case DB_RELEASE_NOTHING: return &db_release_nothing; - case DB_RELEASE_KEY: return &db_release_key; - case DB_RELEASE_DATA: return &db_release_data; - case DB_RELEASE_BOTH: return &db_release_both; - default: - ShowError("db_custom_release: Unknown release options %u\n", which); - return NULL; - } + DB_COUNTSTAT(db_custom_release); + switch (which) { + case DB_RELEASE_NOTHING: + return &db_release_nothing; + case DB_RELEASE_KEY: + return &db_release_key; + case DB_RELEASE_DATA: + return &db_release_data; + case DB_RELEASE_BOTH: + return &db_release_both; + default: + ShowError("db_custom_release: Unknown release options %u\n", which); + return NULL; + } } /** @@ -2388,75 +2402,83 @@ DBReleaser db_custom_release(DBRelease which) * @param line Line of the file where the database is being allocated * @param type Type of database * @param options Options of the database - * @param maxlen Maximum length of the string to be used as key in string + * @param maxlen Maximum length of the string to be used as key in string * databases. If 0, the maximum number of maxlen is used (64K). * @return The interface of the database * @public * @see #DBMap_impl * @see #db_fix_options(DBType,DBOptions) */ -DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsigned short maxlen) +DBMap *db_alloc(const char *file, int line, DBType type, DBOptions options, unsigned short maxlen) { - DBMap_impl* db; - unsigned int i; + DBMap_impl *db; + unsigned int i; #ifdef DB_ENABLE_STATS - DB_COUNTSTAT(db_alloc); - switch (type) { - case DB_INT: DB_COUNTSTAT(db_int_alloc); break; - case DB_UINT: DB_COUNTSTAT(db_uint_alloc); break; - case DB_STRING: DB_COUNTSTAT(db_string_alloc); break; - case DB_ISTRING: DB_COUNTSTAT(db_istring_alloc); break; - } + DB_COUNTSTAT(db_alloc); + switch (type) { + case DB_INT: + DB_COUNTSTAT(db_int_alloc); + break; + case DB_UINT: + DB_COUNTSTAT(db_uint_alloc); + break; + case DB_STRING: + DB_COUNTSTAT(db_string_alloc); + break; + case DB_ISTRING: + DB_COUNTSTAT(db_istring_alloc); + break; + } #endif /* DB_ENABLE_STATS */ - CREATE(db, struct DBMap_impl, 1); - - options = db_fix_options(type, options); - /* Interface of the database */ - db->vtable.iterator = db_obj_iterator; - db->vtable.exists = db_obj_exists; - db->vtable.get = db_obj_get; - db->vtable.getall = db_obj_getall; - db->vtable.vgetall = db_obj_vgetall; - db->vtable.ensure = db_obj_ensure; - db->vtable.vensure = db_obj_vensure; - db->vtable.put = db_obj_put; - db->vtable.remove = db_obj_remove; - db->vtable.foreach = db_obj_foreach; - db->vtable.vforeach = db_obj_vforeach; - db->vtable.clear = db_obj_clear; - db->vtable.vclear = db_obj_vclear; - db->vtable.destroy = db_obj_destroy; - db->vtable.vdestroy = db_obj_vdestroy; - db->vtable.size = db_obj_size; - db->vtable.type = db_obj_type; - db->vtable.options = db_obj_options; - /* File and line of allocation */ - db->alloc_file = file; - db->alloc_line = line; - /* Lock system */ - db->free_list = NULL; - db->free_count = 0; - db->free_max = 0; - db->free_lock = 0; - /* Other */ - db->nodes = ers_new(sizeof(struct dbn),"db.c::db_alloc",ERS_OPT_NONE); - db->cmp = db_default_cmp(type); - db->hash = db_default_hash(type); - db->release = db_default_release(type, options); - for (i = 0; i < HASH_SIZE; i++) - db->ht[i] = NULL; - db->cache = NULL; - db->type = type; - db->options = options; - db->item_count = 0; - db->maxlen = maxlen; - db->global_lock = 0; - - if( db->maxlen == 0 && (type == DB_STRING || type == DB_ISTRING) ) - db->maxlen = UINT16_MAX; - - return &db->vtable; + CREATE(db, struct DBMap_impl, 1); + + options = db_fix_options(type, options); + /* Interface of the database */ + db->vtable.iterator = db_obj_iterator; + db->vtable.exists = db_obj_exists; + db->vtable.get = db_obj_get; + db->vtable.getall = db_obj_getall; + db->vtable.vgetall = db_obj_vgetall; + db->vtable.ensure = db_obj_ensure; + db->vtable.vensure = db_obj_vensure; + db->vtable.put = db_obj_put; + db->vtable.remove = db_obj_remove; + db->vtable.foreach = db_obj_foreach; + db->vtable.vforeach = db_obj_vforeach; + db->vtable.clear = db_obj_clear; + db->vtable.vclear = db_obj_vclear; + db->vtable.destroy = db_obj_destroy; + db->vtable.vdestroy = db_obj_vdestroy; + db->vtable.size = db_obj_size; + db->vtable.type = db_obj_type; + db->vtable.options = db_obj_options; + /* File and line of allocation */ + db->alloc_file = file; + db->alloc_line = line; + /* Lock system */ + db->free_list = NULL; + db->free_count = 0; + db->free_max = 0; + db->free_lock = 0; + /* Other */ + db->nodes = ers_new(sizeof(struct dbn),"db.c::db_alloc",ERS_OPT_NONE); + db->cmp = db_default_cmp(type); + db->hash = db_default_hash(type); + db->release = db_default_release(type, options); + for (i = 0; i < HASH_SIZE; i++) + db->ht[i] = NULL; + db->cache = NULL; + db->type = type; + db->options = options; + db->item_count = 0; + db->maxlen = maxlen; + db->global_lock = 0; + + if (db->maxlen == 0 && (type == DB_STRING || type == DB_ISTRING)) + db->maxlen = UINT16_MAX; + + return &db->vtable; } /** @@ -2467,11 +2489,11 @@ DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsi */ DBKey db_i2key(int key) { - DBKey ret; + DBKey ret; - DB_COUNTSTAT(db_i2key); - ret.i = key; - return ret; + DB_COUNTSTAT(db_i2key); + ret.i = key; + return ret; } /** @@ -2482,11 +2504,11 @@ DBKey db_i2key(int key) */ DBKey db_ui2key(unsigned int key) { - DBKey ret; + DBKey ret; - DB_COUNTSTAT(db_ui2key); - ret.ui = key; - return ret; + DB_COUNTSTAT(db_ui2key); + ret.ui = key; + return ret; } /** @@ -2497,11 +2519,11 @@ DBKey db_ui2key(unsigned int key) */ DBKey db_str2key(const char *key) { - DBKey ret; + DBKey ret; - DB_COUNTSTAT(db_str2key); - ret.str = key; - return ret; + DB_COUNTSTAT(db_str2key); + ret.str = key; + return ret; } /** @@ -2512,12 +2534,12 @@ DBKey db_str2key(const char *key) */ DBData db_i2data(int data) { - DBData ret; + DBData ret; - DB_COUNTSTAT(db_i2data); - ret.type = DB_DATA_INT; - ret.u.i = data; - return ret; + DB_COUNTSTAT(db_i2data); + ret.type = DB_DATA_INT; + ret.u.i = data; + return ret; } /** @@ -2528,12 +2550,12 @@ DBData db_i2data(int data) */ DBData db_ui2data(unsigned int data) { - DBData ret; + DBData ret; - DB_COUNTSTAT(db_ui2data); - ret.type = DB_DATA_UINT; - ret.u.ui = data; - return ret; + DB_COUNTSTAT(db_ui2data); + ret.type = DB_DATA_UINT; + ret.u.ui = data; + return ret; } /** @@ -2544,12 +2566,12 @@ DBData db_ui2data(unsigned int data) */ DBData db_ptr2data(void *data) { - DBData ret; + DBData ret; - DB_COUNTSTAT(db_ptr2data); - ret.type = DB_DATA_PTR; - ret.u.ptr = data; - return ret; + DB_COUNTSTAT(db_ptr2data); + ret.type = DB_DATA_PTR; + ret.u.ptr = data; + return ret; } /** @@ -2561,10 +2583,10 @@ DBData db_ptr2data(void *data) */ int db_data2i(DBData *data) { - DB_COUNTSTAT(db_data2i); - if (data && DB_DATA_INT == data->type) - return data->u.i; - return 0; + DB_COUNTSTAT(db_data2i); + if (data && DB_DATA_INT == data->type) + return data->u.i; + return 0; } /** @@ -2576,10 +2598,10 @@ int db_data2i(DBData *data) */ unsigned int db_data2ui(DBData *data) { - DB_COUNTSTAT(db_data2ui); - if (data && DB_DATA_UINT == data->type) - return data->u.ui; - return 0; + DB_COUNTSTAT(db_data2ui); + if (data && DB_DATA_UINT == data->type) + return data->u.ui; + return 0; } /** @@ -2589,12 +2611,12 @@ unsigned int db_data2ui(DBData *data) * @return Void* value of the data. * @public */ -void* db_data2ptr(DBData *data) +void *db_data2ptr(DBData *data) { - DB_COUNTSTAT(db_data2ptr); - if (data && DB_DATA_PTR == data->type) - return data->u.ptr; - return NULL; + DB_COUNTSTAT(db_data2ptr); + if (data && DB_DATA_PTR == data->type) + return data->u.ptr; + return NULL; } /** @@ -2604,7 +2626,7 @@ void* db_data2ptr(DBData *data) */ void db_init(void) { - DB_COUNTSTAT(db_init); + DB_COUNTSTAT(db_init); } /** @@ -2615,208 +2637,208 @@ void db_init(void) void db_final(void) { #ifdef DB_ENABLE_STATS - DB_COUNTSTAT(db_final); - ShowInfo(CL_WHITE"Database nodes"CL_RESET":\n" - "allocated %u, freed %u\n", - stats.db_node_alloc, stats.db_node_free); - ShowInfo(CL_WHITE"Database types"CL_RESET":\n" - "DB_INT : allocated %10u, destroyed %10u\n" - "DB_UINT : allocated %10u, destroyed %10u\n" - "DB_STRING : allocated %10u, destroyed %10u\n" - "DB_ISTRING : allocated %10u, destroyed %10u\n", - stats.db_int_alloc, stats.db_int_destroy, - stats.db_uint_alloc, stats.db_uint_destroy, - stats.db_string_alloc, stats.db_string_destroy, - stats.db_istring_alloc, stats.db_istring_destroy); - ShowInfo(CL_WHITE"Database function counters"CL_RESET":\n" - "db_rotate_left %10u, db_rotate_right %10u,\n" - "db_rebalance %10u, db_rebalance_erase %10u,\n" - "db_is_key_null %10u,\n" - "db_dup_key %10u, db_dup_key_free %10u,\n" - "db_free_add %10u, db_free_remove %10u,\n" - "db_free_lock %10u, db_free_unlock %10u,\n" - "db_int_cmp %10u, db_uint_cmp %10u,\n" - "db_string_cmp %10u, db_istring_cmp %10u,\n" - "db_int_hash %10u, db_uint_hash %10u,\n" - "db_string_hash %10u, db_istring_hash %10u,\n" - "db_release_nothing %10u, db_release_key %10u,\n" - "db_release_data %10u, db_release_both %10u,\n" - "dbit_first %10u, dbit_last %10u,\n" - "dbit_next %10u, dbit_prev %10u,\n" - "dbit_exists %10u, dbit_remove %10u,\n" - "dbit_destroy %10u, db_iterator %10u,\n" - "db_exits %10u, db_get %10u,\n" - "db_getall %10u, db_vgetall %10u,\n" - "db_ensure %10u, db_vensure %10u,\n" - "db_put %10u, db_remove %10u,\n" - "db_foreach %10u, db_vforeach %10u,\n" - "db_clear %10u, db_vclear %10u,\n" - "db_destroy %10u, db_vdestroy %10u,\n" - "db_size %10u, db_type %10u,\n" - "db_options %10u, db_fix_options %10u,\n" - "db_default_cmp %10u, db_default_hash %10u,\n" - "db_default_release %10u, db_custom_release %10u,\n" - "db_alloc %10u, db_i2key %10u,\n" - "db_ui2key %10u, db_str2key %10u,\n" - "db_i2data %10u, db_ui2data %10u,\n" - "db_ptr2data %10u, db_data2i %10u,\n" - "db_data2ui %10u, db_data2ptr %10u,\n" - "db_init %10u, db_final %10u\n", - stats.db_rotate_left, stats.db_rotate_right, - stats.db_rebalance, stats.db_rebalance_erase, - stats.db_is_key_null, - stats.db_dup_key, stats.db_dup_key_free, - stats.db_free_add, stats.db_free_remove, - stats.db_free_lock, stats.db_free_unlock, - stats.db_int_cmp, stats.db_uint_cmp, - stats.db_string_cmp, stats.db_istring_cmp, - stats.db_int_hash, stats.db_uint_hash, - stats.db_string_hash, stats.db_istring_hash, - stats.db_release_nothing, stats.db_release_key, - stats.db_release_data, stats.db_release_both, - stats.dbit_first, stats.dbit_last, - stats.dbit_next, stats.dbit_prev, - stats.dbit_exists, stats.dbit_remove, - stats.dbit_destroy, stats.db_iterator, - stats.db_exists, stats.db_get, - stats.db_getall, stats.db_vgetall, - stats.db_ensure, stats.db_vensure, - stats.db_put, stats.db_remove, - stats.db_foreach, stats.db_vforeach, - stats.db_clear, stats.db_vclear, - stats.db_destroy, stats.db_vdestroy, - stats.db_size, stats.db_type, - stats.db_options, stats.db_fix_options, - stats.db_default_cmp, stats.db_default_hash, - stats.db_default_release, stats.db_custom_release, - stats.db_alloc, stats.db_i2key, - stats.db_ui2key, stats.db_str2key, - stats.db_i2data, stats.db_ui2data, - stats.db_ptr2data, stats.db_data2i, - stats.db_data2ui, stats.db_data2ptr, - stats.db_init, stats.db_final); + DB_COUNTSTAT(db_final); + ShowInfo(CL_WHITE"Database nodes"CL_RESET":\n" + "allocated %u, freed %u\n", + stats.db_node_alloc, stats.db_node_free); + ShowInfo(CL_WHITE"Database types"CL_RESET":\n" + "DB_INT : allocated %10u, destroyed %10u\n" + "DB_UINT : allocated %10u, destroyed %10u\n" + "DB_STRING : allocated %10u, destroyed %10u\n" + "DB_ISTRING : allocated %10u, destroyed %10u\n", + stats.db_int_alloc, stats.db_int_destroy, + stats.db_uint_alloc, stats.db_uint_destroy, + stats.db_string_alloc, stats.db_string_destroy, + stats.db_istring_alloc, stats.db_istring_destroy); + ShowInfo(CL_WHITE"Database function counters"CL_RESET":\n" + "db_rotate_left %10u, db_rotate_right %10u,\n" + "db_rebalance %10u, db_rebalance_erase %10u,\n" + "db_is_key_null %10u,\n" + "db_dup_key %10u, db_dup_key_free %10u,\n" + "db_free_add %10u, db_free_remove %10u,\n" + "db_free_lock %10u, db_free_unlock %10u,\n" + "db_int_cmp %10u, db_uint_cmp %10u,\n" + "db_string_cmp %10u, db_istring_cmp %10u,\n" + "db_int_hash %10u, db_uint_hash %10u,\n" + "db_string_hash %10u, db_istring_hash %10u,\n" + "db_release_nothing %10u, db_release_key %10u,\n" + "db_release_data %10u, db_release_both %10u,\n" + "dbit_first %10u, dbit_last %10u,\n" + "dbit_next %10u, dbit_prev %10u,\n" + "dbit_exists %10u, dbit_remove %10u,\n" + "dbit_destroy %10u, db_iterator %10u,\n" + "db_exits %10u, db_get %10u,\n" + "db_getall %10u, db_vgetall %10u,\n" + "db_ensure %10u, db_vensure %10u,\n" + "db_put %10u, db_remove %10u,\n" + "db_foreach %10u, db_vforeach %10u,\n" + "db_clear %10u, db_vclear %10u,\n" + "db_destroy %10u, db_vdestroy %10u,\n" + "db_size %10u, db_type %10u,\n" + "db_options %10u, db_fix_options %10u,\n" + "db_default_cmp %10u, db_default_hash %10u,\n" + "db_default_release %10u, db_custom_release %10u,\n" + "db_alloc %10u, db_i2key %10u,\n" + "db_ui2key %10u, db_str2key %10u,\n" + "db_i2data %10u, db_ui2data %10u,\n" + "db_ptr2data %10u, db_data2i %10u,\n" + "db_data2ui %10u, db_data2ptr %10u,\n" + "db_init %10u, db_final %10u\n", + stats.db_rotate_left, stats.db_rotate_right, + stats.db_rebalance, stats.db_rebalance_erase, + stats.db_is_key_null, + stats.db_dup_key, stats.db_dup_key_free, + stats.db_free_add, stats.db_free_remove, + stats.db_free_lock, stats.db_free_unlock, + stats.db_int_cmp, stats.db_uint_cmp, + stats.db_string_cmp, stats.db_istring_cmp, + stats.db_int_hash, stats.db_uint_hash, + stats.db_string_hash, stats.db_istring_hash, + stats.db_release_nothing, stats.db_release_key, + stats.db_release_data, stats.db_release_both, + stats.dbit_first, stats.dbit_last, + stats.dbit_next, stats.dbit_prev, + stats.dbit_exists, stats.dbit_remove, + stats.dbit_destroy, stats.db_iterator, + stats.db_exists, stats.db_get, + stats.db_getall, stats.db_vgetall, + stats.db_ensure, stats.db_vensure, + stats.db_put, stats.db_remove, + stats.db_foreach, stats.db_vforeach, + stats.db_clear, stats.db_vclear, + stats.db_destroy, stats.db_vdestroy, + stats.db_size, stats.db_type, + stats.db_options, stats.db_fix_options, + stats.db_default_cmp, stats.db_default_hash, + stats.db_default_release, stats.db_custom_release, + stats.db_alloc, stats.db_i2key, + stats.db_ui2key, stats.db_str2key, + stats.db_i2data, stats.db_ui2data, + stats.db_ptr2data, stats.db_data2i, + stats.db_data2ui, stats.db_data2ptr, + stats.db_init, stats.db_final); #endif /* DB_ENABLE_STATS */ } // Link DB System - jAthena -void linkdb_insert( struct linkdb_node** head, void *key, void* data) -{ - struct linkdb_node *node; - if( head == NULL ) return ; - node = (struct linkdb_node*)aMalloc( sizeof(struct linkdb_node) ); - if( *head == NULL ) { - // first node - *head = node; - node->prev = NULL; - node->next = NULL; - } else { - // link nodes - node->next = *head; - node->prev = (*head)->prev; - (*head)->prev = node; - (*head) = node; - } - node->key = key; - node->data = data; -} - -void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ) -{ - struct linkdb_node *node; - if( head == NULL ) return; - node = *head; - while ( node ) { - va_list args; - va_start(args, func); - func( node->key, node->data, args ); - va_end(args); - node = node->next; - } -} - -void* linkdb_search( struct linkdb_node** head, void *key) -{ - int n = 0; - struct linkdb_node *node; - if( head == NULL ) return NULL; - node = *head; - while( node ) { - if( node->key == key ) { - if( node->prev && n > 5 ) { - //Moving the head in order to improve processing efficiency - if(node->prev) node->prev->next = node->next; - if(node->next) node->next->prev = node->prev; - node->next = *head; - node->prev = (*head)->prev; - (*head)->prev = node; - (*head) = node; - } - return node->data; - } - node = node->next; - n++; - } - return NULL; -} - -void* linkdb_erase( struct linkdb_node** head, void *key) -{ - struct linkdb_node *node; - if( head == NULL ) return NULL; - node = *head; - while( node ) { - if( node->key == key ) { - void *data = node->data; - if( node->prev == NULL ) - *head = node->next; - else - node->prev->next = node->next; - if( node->next ) - node->next->prev = node->prev; - aFree( node ); - return data; - } - node = node->next; - } - return NULL; -} - -void linkdb_replace( struct linkdb_node** head, void *key, void *data ) -{ - int n = 0; - struct linkdb_node *node; - if( head == NULL ) return ; - node = *head; - while( node ) { - if( node->key == key ) { - if( node->prev && n > 5 ) { - //Moving the head in order to improve processing efficiency - if(node->prev) node->prev->next = node->next; - if(node->next) node->next->prev = node->prev; - node->next = *head; - node->prev = (*head)->prev; - (*head)->prev = node; - (*head) = node; - } - node->data = data; - return ; - } - node = node->next; - n++; - } - //Insert because it can not find - linkdb_insert( head, key, data ); -} - -void linkdb_final( struct linkdb_node** head ) -{ - struct linkdb_node *node, *node2; - if( head == NULL ) return ; - node = *head; - while( node ) { - node2 = node->next; - aFree( node ); - node = node2; - } - *head = NULL; +void linkdb_insert(struct linkdb_node **head, void *key, void *data) +{ + struct linkdb_node *node; + if (head == NULL) return ; + node = (struct linkdb_node *)aMalloc(sizeof(struct linkdb_node)); + if (*head == NULL) { + // first node + *head = node; + node->prev = NULL; + node->next = NULL; + } else { + // link nodes + node->next = *head; + node->prev = (*head)->prev; + (*head)->prev = node; + (*head) = node; + } + node->key = key; + node->data = data; +} + +void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...) +{ + struct linkdb_node *node; + if (head == NULL) return; + node = *head; + while (node) { + va_list args; + va_start(args, func); + func(node->key, node->data, args); + va_end(args); + node = node->next; + } +} + +void *linkdb_search(struct linkdb_node **head, void *key) +{ + int n = 0; + struct linkdb_node *node; + if (head == NULL) return NULL; + node = *head; + while (node) { + if (node->key == key) { + if (node->prev && n > 5) { + //Moving the head in order to improve processing efficiency + if (node->prev) node->prev->next = node->next; + if (node->next) node->next->prev = node->prev; + node->next = *head; + node->prev = (*head)->prev; + (*head)->prev = node; + (*head) = node; + } + return node->data; + } + node = node->next; + n++; + } + return NULL; +} + +void *linkdb_erase(struct linkdb_node **head, void *key) +{ + struct linkdb_node *node; + if (head == NULL) return NULL; + node = *head; + while (node) { + if (node->key == key) { + void *data = node->data; + if (node->prev == NULL) + *head = node->next; + else + node->prev->next = node->next; + if (node->next) + node->next->prev = node->prev; + aFree(node); + return data; + } + node = node->next; + } + return NULL; +} + +void linkdb_replace(struct linkdb_node **head, void *key, void *data) +{ + int n = 0; + struct linkdb_node *node; + if (head == NULL) return ; + node = *head; + while (node) { + if (node->key == key) { + if (node->prev && n > 5) { + //Moving the head in order to improve processing efficiency + if (node->prev) node->prev->next = node->next; + if (node->next) node->next->prev = node->prev; + node->next = *head; + node->prev = (*head)->prev; + (*head)->prev = node; + (*head) = node; + } + node->data = data; + return ; + } + node = node->next; + n++; + } + //Insert because it can not find + linkdb_insert(head, key, data); +} + +void linkdb_final(struct linkdb_node **head) +{ + struct linkdb_node *node, *node2; + if (head == NULL) return ; + node = *head; + while (node) { + node2 = node->next; + aFree(node); + node = node2; + } + *head = NULL; } diff --git a/src/common/db.h b/src/common/db.h index 4fe6a93d6..eff3b775e 100644 --- a/src/common/db.h +++ b/src/common/db.h @@ -69,15 +69,15 @@ * @see #db_custom_release(DBRelease) */ typedef enum DBRelease { - DB_RELEASE_NOTHING = 0, - DB_RELEASE_KEY = 1, - DB_RELEASE_DATA = 2, - DB_RELEASE_BOTH = 3 + DB_RELEASE_NOTHING = 0, + DB_RELEASE_KEY = 1, + DB_RELEASE_DATA = 2, + DB_RELEASE_BOTH = 3 } DBRelease; /** * Supported types of database. - * See {@link #db_fix_options(DBType,DBOptions)} for restrictions of the + * See {@link #db_fix_options(DBType,DBOptions)} for restrictions of the * types of databases. * @param DB_INT Uses int's for keys * @param DB_UINT Uses unsigned int's for keys @@ -93,22 +93,22 @@ typedef enum DBRelease { * @see #db_alloc(const char *,int,DBType,DBOptions,unsigned short) */ typedef enum DBType { - DB_INT, - DB_UINT, - DB_STRING, - DB_ISTRING + DB_INT, + DB_UINT, + DB_STRING, + DB_ISTRING } DBType; /** * Bitfield of options that define the behaviour of the database. - * See {@link #db_fix_options(DBType,DBOptions)} for restrictions of the + * See {@link #db_fix_options(DBType,DBOptions)} for restrictions of the * types of databases. * @param DB_OPT_BASE Base options: does not duplicate keys, releases nothing * and does not allow NULL keys or NULL data. - * @param DB_OPT_DUP_KEY Duplicates the keys internally. If DB_OPT_RELEASE_KEY + * @param DB_OPT_DUP_KEY Duplicates the keys internally. If DB_OPT_RELEASE_KEY * is defined, the real key is freed as soon as the entry is added. * @param DB_OPT_RELEASE_KEY Releases the key. - * @param DB_OPT_RELEASE_DATA Releases the data whenever an entry is removed + * @param DB_OPT_RELEASE_DATA Releases the data whenever an entry is removed * from the database. * WARNING: for funtions that return the data (like DBMap::remove), * a dangling pointer will be returned. @@ -121,13 +121,13 @@ typedef enum DBType { * @see #db_alloc(const char *,int,DBType,DBOptions,unsigned short) */ typedef enum DBOptions { - DB_OPT_BASE = 0, - DB_OPT_DUP_KEY = 1, - DB_OPT_RELEASE_KEY = 2, - DB_OPT_RELEASE_DATA = 4, - DB_OPT_RELEASE_BOTH = 6, - DB_OPT_ALLOW_NULL_KEY = 8, - DB_OPT_ALLOW_NULL_DATA = 16, + DB_OPT_BASE = 0, + DB_OPT_DUP_KEY = 1, + DB_OPT_RELEASE_KEY = 2, + DB_OPT_RELEASE_DATA = 4, + DB_OPT_RELEASE_BOTH = 6, + DB_OPT_ALLOW_NULL_KEY = 8, + DB_OPT_ALLOW_NULL_DATA = 16, } DBOptions; /** @@ -142,9 +142,9 @@ typedef enum DBOptions { * @see DBMap#remove */ typedef union DBKey { - int i; - unsigned int ui; - const char *str; + int i; + unsigned int ui; + const char *str; } DBKey; /** @@ -156,9 +156,9 @@ typedef union DBKey { * @see #DBData */ typedef enum DBDataType { - DB_DATA_INT, - DB_DATA_UINT, - DB_DATA_PTR + DB_DATA_INT, + DB_DATA_UINT, + DB_DATA_PTR } DBDataType; /** @@ -171,16 +171,16 @@ typedef enum DBDataType { * @public */ typedef struct DBData { - DBDataType type; - union { - int i; - unsigned int ui; - void *ptr; - } u; + DBDataType type; + union { + int i; + unsigned int ui; + void *ptr; + } u; } DBData; /** - * Format of functions that create the data for the key when the entry doesn't + * Format of functions that create the data for the key when the entry doesn't * exist in the database yet. * @param key Key of the database entry * @param args Extra arguments of the function @@ -189,12 +189,12 @@ typedef struct DBData { * @see DBMap#vensure * @see DBMap#ensure */ -typedef DBData (*DBCreateData)(DBKey key, va_list args); +typedef DBData(*DBCreateData)(DBKey key, va_list args); /** - * Format of functions to be applied to an unspecified quantity of entries of + * Format of functions to be applied to an unspecified quantity of entries of * a database. - * Any function that applies this function to the database will return the sum + * Any function that applies this function to the database will return the sum * of values returned by this function. * @param key Key of the database entry * @param data Data of the database entry @@ -272,87 +272,86 @@ typedef struct DBMap DBMap; * Database iterator. * Supports forward iteration, backward iteration and removing entries from the database. * The iterator is initially positioned before the first entry of the database. - * While the iterator exists the database is locked internally, so invoke + * While the iterator exists the database is locked internally, so invoke * {@link DBIterator#destroy} as soon as possible. * @public * @see #DBMap */ -struct DBIterator -{ - - /** - * Fetches the first entry in the database. - * Returns the data of the entry. - * Puts the key in out_key, if out_key is not NULL. - * @param self Iterator - * @param out_key Key of the entry - * @return Data of the entry - * @protected - */ - DBData* (*first)(DBIterator* self, DBKey* out_key); - - /** - * Fetches the last entry in the database. - * Returns the data of the entry. - * Puts the key in out_key, if out_key is not NULL. - * @param self Iterator - * @param out_key Key of the entry - * @return Data of the entry - * @protected - */ - DBData* (*last)(DBIterator* self, DBKey* out_key); - - /** - * Fetches the next entry in the database. - * Returns the data of the entry. - * Puts the key in out_key, if out_key is not NULL. - * @param self Iterator - * @param out_key Key of the entry - * @return Data of the entry - * @protected - */ - DBData* (*next)(DBIterator* self, DBKey* out_key); - - /** - * Fetches the previous entry in the database. - * Returns the data of the entry. - * Puts the key in out_key, if out_key is not NULL. - * @param self Iterator - * @param out_key Key of the entry - * @return Data of the entry - * @protected - */ - DBData* (*prev)(DBIterator* self, DBKey* out_key); - - /** - * Returns true if the fetched entry exists. - * The databases entries might have NULL data, so use this to to test if - * the iterator is done. - * @param self Iterator - * @return true is the entry exists - * @protected - */ - bool (*exists)(DBIterator* self); - - /** - * Removes the current entry from the database. - * NOTE: {@link DBIterator#exists} will return false until another entry - * is fetched - * Puts data of the removed entry in out_data, if out_data is not NULL. - * @param self Iterator - * @param out_data Data of the removed entry. - * @return 1 if entry was removed, 0 otherwise - * @protected - * @see DBMap#remove - */ - int (*remove)(DBIterator* self, DBData *out_data); - - /** - * Destroys this iterator and unlocks the database. - * @param self Iterator - * @protected - */ - void (*destroy)(DBIterator* self); +struct DBIterator { + + /** + * Fetches the first entry in the database. + * Returns the data of the entry. + * Puts the key in out_key, if out_key is not NULL. + * @param self Iterator + * @param out_key Key of the entry + * @return Data of the entry + * @protected + */ + DBData *(*first)(DBIterator *self, DBKey *out_key); + + /** + * Fetches the last entry in the database. + * Returns the data of the entry. + * Puts the key in out_key, if out_key is not NULL. + * @param self Iterator + * @param out_key Key of the entry + * @return Data of the entry + * @protected + */ + DBData *(*last)(DBIterator *self, DBKey *out_key); + + /** + * Fetches the next entry in the database. + * Returns the data of the entry. + * Puts the key in out_key, if out_key is not NULL. + * @param self Iterator + * @param out_key Key of the entry + * @return Data of the entry + * @protected + */ + DBData *(*next)(DBIterator *self, DBKey *out_key); + + /** + * Fetches the previous entry in the database. + * Returns the data of the entry. + * Puts the key in out_key, if out_key is not NULL. + * @param self Iterator + * @param out_key Key of the entry + * @return Data of the entry + * @protected + */ + DBData *(*prev)(DBIterator *self, DBKey *out_key); + + /** + * Returns true if the fetched entry exists. + * The databases entries might have NULL data, so use this to to test if + * the iterator is done. + * @param self Iterator + * @return true is the entry exists + * @protected + */ + bool (*exists)(DBIterator *self); + + /** + * Removes the current entry from the database. + * NOTE: {@link DBIterator#exists} will return false until another entry + * is fetched + * Puts data of the removed entry in out_data, if out_data is not NULL. + * @param self Iterator + * @param out_data Data of the removed entry. + * @return 1 if entry was removed, 0 otherwise + * @protected + * @see DBMap#remove + */ + int (*remove)(DBIterator *self, DBData *out_data); + + /** + * Destroys this iterator and unlocks the database. + * @param self Iterator + * @protected + */ + void (*destroy)(DBIterator *self); }; @@ -364,235 +363,235 @@ struct DBIterator */ struct DBMap { - /** - * Returns a new iterator for this database. - * The iterator keeps the database locked until it is destroyed. - * The database will keep functioning normally but will only free internal - * memory when unlocked, so destroy the iterator as soon as possible. - * @param self Database - * @return New iterator - * @protected - */ - DBIterator* (*iterator)(DBMap* self); - - /** - * Returns true if the entry exists. - * @param self Database - * @param key Key that identifies the entry - * @return true is the entry exists - * @protected - */ - bool (*exists)(DBMap* self, DBKey key); - - /** - * Get the data of the entry identified by the key. - * @param self Database - * @param key Key that identifies the entry - * @return Data of the entry or NULL if not found - * @protected - */ - DBData* (*get)(DBMap* self, DBKey key); - - /** - * Just calls {@link DBMap#vgetall}. - * Get the data of the entries matched by match. - * It puts a maximum of max entries into buf. - * If buf is NULL, it only counts the matches. - * Returns the number of entries that matched. - * NOTE: if the value returned is greater than max, only the - * first max entries found are put into the buffer. - * @param self Database - * @param buf Buffer to put the data of the matched entries - * @param max Maximum number of data entries to be put into buf - * @param match Function that matches the database entries - * @param ... Extra arguments for match - * @return The number of entries that matched - * @protected - * @see DBMap#vgetall(DBMap*,void **,unsigned int,DBMatcher,va_list) - */ - unsigned int (*getall)(DBMap* self, DBData** buf, unsigned int max, DBMatcher match, ...); - - /** - * Get the data of the entries matched by match. - * It puts a maximum of max entries into buf. - * If buf is NULL, it only counts the matches. - * Returns the number of entries that matched. - * NOTE: if the value returned is greater than max, only the - * first max entries found are put into the buffer. - * @param self Database - * @param buf Buffer to put the data of the matched entries - * @param max Maximum number of data entries to be put into buf - * @param match Function that matches the database entries - * @param ... Extra arguments for match - * @return The number of entries that matched - * @protected - * @see DBMap#getall(DBMap*,void **,unsigned int,DBMatcher,...) - */ - unsigned int (*vgetall)(DBMap* self, DBData** buf, unsigned int max, DBMatcher match, va_list args); - - /** - * Just calls {@link DBMap#vensure}. - * Get the data of the entry identified by the key. - * If the entry does not exist, an entry is added with the data returned by - * create. - * @param self Database - * @param key Key that identifies the entry - * @param create Function used to create the data if the entry doesn't exist - * @param ... Extra arguments for create - * @return Data of the entry - * @protected - * @see DBMap#vensure(DBMap*,DBKey,DBCreateData,va_list) - */ - DBData* (*ensure)(DBMap* self, DBKey key, DBCreateData create, ...); - - /** - * Get the data of the entry identified by the key. - * If the entry does not exist, an entry is added with the data returned by - * create. - * @param self Database - * @param key Key that identifies the entry - * @param create Function used to create the data if the entry doesn't exist - * @param args Extra arguments for create - * @return Data of the entry - * @protected - * @see DBMap#ensure(DBMap*,DBKey,DBCreateData,...) - */ - DBData* (*vensure)(DBMap* self, DBKey key, DBCreateData create, va_list args); - - /** - * Put the data identified by the key in the database. - * Puts the previous data in out_data, if out_data is not NULL. - * NOTE: Uses the new key, the old one is released. - * @param self Database - * @param key Key that identifies the data - * @param data Data to be put in the database - * @param out_data Previous data if the entry exists - * @return 1 if if the entry already exists, 0 otherwise - * @protected - */ - int (*put)(DBMap* self, DBKey key, DBData data, DBData *out_data); - - /** - * Remove an entry from the database. - * Puts the previous data in out_data, if out_data is not NULL. - * NOTE: The key (of the database) is released. - * @param self Database - * @param key Key that identifies the entry - * @param out_data Previous data if the entry exists - * @return 1 if if the entry already exists, 0 otherwise - * @protected - */ - int (*remove)(DBMap* self, DBKey key, DBData *out_data); - - /** - * Just calls {@link DBMap#vforeach}. - * Apply func to every entry in the database. - * Returns the sum of values returned by func. - * @param self Database - * @param func Function to be applied - * @param ... Extra arguments for func - * @return Sum of the values returned by func - * @protected - * @see DBMap#vforeach(DBMap*,DBApply,va_list) - */ - int (*foreach)(DBMap* self, DBApply func, ...); - - /** - * Apply func to every entry in the database. - * Returns the sum of values returned by func. - * @param self Database - * @param func Function to be applied - * @param args Extra arguments for func - * @return Sum of the values returned by func - * @protected - * @see DBMap#foreach(DBMap*,DBApply,...) - */ - int (*vforeach)(DBMap* self, DBApply func, va_list args); - - /** - * Just calls {@link DBMap#vclear}. - * Removes all entries from the database. - * Before deleting an entry, func is applied to it. - * Releases the key and the data. - * Returns the sum of values returned by func, if it exists. - * @param self Database - * @param func Function to be applied to every entry before deleting - * @param ... Extra arguments for func - * @return Sum of values returned by func - * @protected - * @see DBMap#vclear(DBMap*,DBApply,va_list) - */ - int (*clear)(DBMap* self, DBApply func, ...); - - /** - * Removes all entries from the database. - * Before deleting an entry, func is applied to it. - * Releases the key and the data. - * Returns the sum of values returned by func, if it exists. - * @param self Database - * @param func Function to be applied to every entry before deleting - * @param args Extra arguments for func - * @return Sum of values returned by func - * @protected - * @see DBMap#clear(DBMap*,DBApply,...) - */ - int (*vclear)(DBMap* self, DBApply func, va_list args); - - /** - * Just calls {@link DBMap#vdestroy}. - * Finalize the database, feeing all the memory it uses. - * Before deleting an entry, func is applied to it. - * Releases the key and the data. - * Returns the sum of values returned by func, if it exists. - * NOTE: This locks the database globally. Any attempt to insert or remove - * a database entry will give an error and be aborted (except for clearing). - * @param self Database - * @param func Function to be applied to every entry before deleting - * @param ... Extra arguments for func - * @return Sum of values returned by func - * @protected - * @see DBMap#vdestroy(DBMap*,DBApply,va_list) - */ - int (*destroy)(DBMap* self, DBApply func, ...); - - /** - * Finalize the database, feeing all the memory it uses. - * Before deleting an entry, func is applied to it. - * Returns the sum of values returned by func, if it exists. - * NOTE: This locks the database globally. Any attempt to insert or remove - * a database entry will give an error and be aborted (except for clearing). - * @param self Database - * @param func Function to be applied to every entry before deleting - * @param args Extra arguments for func - * @return Sum of values returned by func - * @protected - * @see DBMap#destroy(DBMap*,DBApply,...) - */ - int (*vdestroy)(DBMap* self, DBApply func, va_list args); - - /** - * Return the size of the database (number of items in the database). - * @param self Database - * @return Size of the database - * @protected - */ - unsigned int (*size)(DBMap* self); - - /** - * Return the type of the database. - * @param self Database - * @return Type of the database - * @protected - */ - DBType (*type)(DBMap* self); - - /** - * Return the options of the database. - * @param self Database - * @return Options of the database - * @protected - */ - DBOptions (*options)(DBMap* self); + /** + * Returns a new iterator for this database. + * The iterator keeps the database locked until it is destroyed. + * The database will keep functioning normally but will only free internal + * memory when unlocked, so destroy the iterator as soon as possible. + * @param self Database + * @return New iterator + * @protected + */ + DBIterator *(*iterator)(DBMap *self); + + /** + * Returns true if the entry exists. + * @param self Database + * @param key Key that identifies the entry + * @return true is the entry exists + * @protected + */ + bool (*exists)(DBMap *self, DBKey key); + + /** + * Get the data of the entry identified by the key. + * @param self Database + * @param key Key that identifies the entry + * @return Data of the entry or NULL if not found + * @protected + */ + DBData *(*get)(DBMap *self, DBKey key); + + /** + * Just calls {@link DBMap#vgetall}. + * Get the data of the entries matched by match. + * It puts a maximum of max entries into buf. + * If buf is NULL, it only counts the matches. + * Returns the number of entries that matched. + * NOTE: if the value returned is greater than max, only the + * first max entries found are put into the buffer. + * @param self Database + * @param buf Buffer to put the data of the matched entries + * @param max Maximum number of data entries to be put into buf + * @param match Function that matches the database entries + * @param ... Extra arguments for match + * @return The number of entries that matched + * @protected + * @see DBMap#vgetall(DBMap*,void **,unsigned int,DBMatcher,va_list) + */ + unsigned int (*getall)(DBMap *self, DBData **buf, unsigned int max, DBMatcher match, ...); + + /** + * Get the data of the entries matched by match. + * It puts a maximum of max entries into buf. + * If buf is NULL, it only counts the matches. + * Returns the number of entries that matched. + * NOTE: if the value returned is greater than max, only the + * first max entries found are put into the buffer. + * @param self Database + * @param buf Buffer to put the data of the matched entries + * @param max Maximum number of data entries to be put into buf + * @param match Function that matches the database entries + * @param ... Extra arguments for match + * @return The number of entries that matched + * @protected + * @see DBMap#getall(DBMap*,void **,unsigned int,DBMatcher,...) + */ + unsigned int (*vgetall)(DBMap *self, DBData **buf, unsigned int max, DBMatcher match, va_list args); + + /** + * Just calls {@link DBMap#vensure}. + * Get the data of the entry identified by the key. + * If the entry does not exist, an entry is added with the data returned by + * create. + * @param self Database + * @param key Key that identifies the entry + * @param create Function used to create the data if the entry doesn't exist + * @param ... Extra arguments for create + * @return Data of the entry + * @protected + * @see DBMap#vensure(DBMap*,DBKey,DBCreateData,va_list) + */ + DBData *(*ensure)(DBMap *self, DBKey key, DBCreateData create, ...); + + /** + * Get the data of the entry identified by the key. + * If the entry does not exist, an entry is added with the data returned by + * create. + * @param self Database + * @param key Key that identifies the entry + * @param create Function used to create the data if the entry doesn't exist + * @param args Extra arguments for create + * @return Data of the entry + * @protected + * @see DBMap#ensure(DBMap*,DBKey,DBCreateData,...) + */ + DBData *(*vensure)(DBMap *self, DBKey key, DBCreateData create, va_list args); + + /** + * Put the data identified by the key in the database. + * Puts the previous data in out_data, if out_data is not NULL. + * NOTE: Uses the new key, the old one is released. + * @param self Database + * @param key Key that identifies the data + * @param data Data to be put in the database + * @param out_data Previous data if the entry exists + * @return 1 if if the entry already exists, 0 otherwise + * @protected + */ + int (*put)(DBMap *self, DBKey key, DBData data, DBData *out_data); + + /** + * Remove an entry from the database. + * Puts the previous data in out_data, if out_data is not NULL. + * NOTE: The key (of the database) is released. + * @param self Database + * @param key Key that identifies the entry + * @param out_data Previous data if the entry exists + * @return 1 if if the entry already exists, 0 otherwise + * @protected + */ + int (*remove)(DBMap *self, DBKey key, DBData *out_data); + + /** + * Just calls {@link DBMap#vforeach}. + * Apply func to every entry in the database. + * Returns the sum of values returned by func. + * @param self Database + * @param func Function to be applied + * @param ... Extra arguments for func + * @return Sum of the values returned by func + * @protected + * @see DBMap#vforeach(DBMap*,DBApply,va_list) + */ + int (*foreach)(DBMap *self, DBApply func, ...); + + /** + * Apply func to every entry in the database. + * Returns the sum of values returned by func. + * @param self Database + * @param func Function to be applied + * @param args Extra arguments for func + * @return Sum of the values returned by func + * @protected + * @see DBMap#foreach(DBMap*,DBApply,...) + */ + int (*vforeach)(DBMap *self, DBApply func, va_list args); + + /** + * Just calls {@link DBMap#vclear}. + * Removes all entries from the database. + * Before deleting an entry, func is applied to it. + * Releases the key and the data. + * Returns the sum of values returned by func, if it exists. + * @param self Database + * @param func Function to be applied to every entry before deleting + * @param ... Extra arguments for func + * @return Sum of values returned by func + * @protected + * @see DBMap#vclear(DBMap*,DBApply,va_list) + */ + int (*clear)(DBMap *self, DBApply func, ...); + + /** + * Removes all entries from the database. + * Before deleting an entry, func is applied to it. + * Releases the key and the data. + * Returns the sum of values returned by func, if it exists. + * @param self Database + * @param func Function to be applied to every entry before deleting + * @param args Extra arguments for func + * @return Sum of values returned by func + * @protected + * @see DBMap#clear(DBMap*,DBApply,...) + */ + int (*vclear)(DBMap *self, DBApply func, va_list args); + + /** + * Just calls {@link DBMap#vdestroy}. + * Finalize the database, feeing all the memory it uses. + * Before deleting an entry, func is applied to it. + * Releases the key and the data. + * Returns the sum of values returned by func, if it exists. + * NOTE: This locks the database globally. Any attempt to insert or remove + * a database entry will give an error and be aborted (except for clearing). + * @param self Database + * @param func Function to be applied to every entry before deleting + * @param ... Extra arguments for func + * @return Sum of values returned by func + * @protected + * @see DBMap#vdestroy(DBMap*,DBApply,va_list) + */ + int (*destroy)(DBMap *self, DBApply func, ...); + + /** + * Finalize the database, feeing all the memory it uses. + * Before deleting an entry, func is applied to it. + * Returns the sum of values returned by func, if it exists. + * NOTE: This locks the database globally. Any attempt to insert or remove + * a database entry will give an error and be aborted (except for clearing). + * @param self Database + * @param func Function to be applied to every entry before deleting + * @param args Extra arguments for func + * @return Sum of values returned by func + * @protected + * @see DBMap#destroy(DBMap*,DBApply,...) + */ + int (*vdestroy)(DBMap *self, DBApply func, va_list args); + + /** + * Return the size of the database (number of items in the database). + * @param self Database + * @return Size of the database + * @protected + */ + unsigned int (*size)(DBMap *self); + + /** + * Return the type of the database. + * @param self Database + * @return Type of the database + * @protected + */ + DBType(*type)(DBMap *self); + + /** + * Return the options of the database. + * @param self Database + * @return Options of the database + * @protected + */ + DBOptions(*options)(DBMap *self); }; @@ -727,7 +726,7 @@ DBComparator db_default_cmp(DBType type); DBHasher db_default_hash(DBType type); /** - * Returns the default releaser for the specified type of database with the + * Returns the default releaser for the specified type of database with the * specified options. * NOTE: the options are fixed by {@link #db_fix_options(DBType,DBOptions)} * before choosing the releaser @@ -756,7 +755,7 @@ DBReleaser db_custom_release(DBRelease which); /** * Allocate a new database of the specified type. - * It uses the default comparator, hasher and releaser of the specified + * It uses the default comparator, hasher and releaser of the specified * database type and fixed options. * NOTE: the options are fixed by {@link #db_fix_options(DBType,DBOptions)} * before creating the database. @@ -764,7 +763,7 @@ DBReleaser db_custom_release(DBRelease which); * @param line Line of the file where the database is being allocated * @param type Type of database * @param options Options of the database - * @param maxlen Maximum length of the string to be used as key in string + * @param maxlen Maximum length of the string to be used as key in string * databases. If 0, the maximum number of maxlen is used (64K). * @return The interface of the database * @public @@ -775,7 +774,7 @@ DBReleaser db_custom_release(DBRelease which); * @see #db_default_release(DBType,DBOptions) * @see #db_fix_options(DBType,DBOptions) */ -DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsigned short maxlen); +DBMap *db_alloc(const char *file, int line, DBType type, DBOptions options, unsigned short maxlen); /** * Manual cast from 'int' to the union DBKey. @@ -850,7 +849,7 @@ unsigned int db_data2ui(DBData *data); * @return Void* value of the data. * @public */ -void* db_data2ptr(DBData *data); +void *db_data2ptr(DBData *data); /** * Initialize the database system. @@ -869,20 +868,20 @@ void db_final(void); // Link DB System - From jAthena struct linkdb_node { - struct linkdb_node *next; - struct linkdb_node *prev; - void *key; - void *data; + struct linkdb_node *next; + struct linkdb_node *prev; + void *key; + void *data; }; -typedef void (*LinkDBFunc)(void* key, void* data, va_list args); +typedef void (*LinkDBFunc)(void *key, void *data, va_list args); -void linkdb_insert ( struct linkdb_node** head, void *key, void* data); // 重複を考慮しない -void linkdb_replace( struct linkdb_node** head, void *key, void* data); // 重複を考慮する -void* linkdb_search ( struct linkdb_node** head, void *key); -void* linkdb_erase ( struct linkdb_node** head, void *key); -void linkdb_final ( struct linkdb_node** head ); -void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); +void linkdb_insert(struct linkdb_node **head, void *key, void *data); // 重複を考慮しない +void linkdb_replace(struct linkdb_node **head, void *key, void *data); // 重複を考慮する +void *linkdb_search(struct linkdb_node **head, void *key); +void *linkdb_erase(struct linkdb_node **head, void *key); +void linkdb_final(struct linkdb_node **head); +void linkdb_foreach(struct linkdb_node **head, LinkDBFunc func, ...); @@ -894,11 +893,11 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __var Index variable /// @param __cmp Expression that returns true when the target entry is found #define ARR_FIND(__start, __end, __var, __cmp) \ - do{ \ - for( (__var) = (__start); (__var) < (__end); ++(__var) ) \ - if( __cmp ) \ - break; \ - }while(0) + do{ \ + for( (__var) = (__start); (__var) < (__end); ++(__var) ) \ + if( __cmp ) \ + break; \ + }while(0) @@ -912,18 +911,18 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __arr Array /// @param __type Type of entry #define ARR_MOVE(__from, __to, __arr, __type) \ - do{ \ - if( (__from) != (__to) ) \ - { \ - __type __backup__; \ - memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ - if( (__from) < (__to) ) \ - memmove((__arr)+(__from), (__arr)+(__from)+1, ((__to)-(__from))*sizeof(__type)); \ - else if( (__from) > (__to) ) \ - memmove((__arr)+(__to)+1, (__arr)+(__to), ((__from)-(__to))*sizeof(__type)); \ - memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ - } \ - }while(0) + do{ \ + if( (__from) != (__to) ) \ + { \ + __type __backup__; \ + memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ + if( (__from) < (__to) ) \ + memmove((__arr)+(__from), (__arr)+(__from)+1, ((__to)-(__from))*sizeof(__type)); \ + else if( (__from) > (__to) ) \ + memmove((__arr)+(__to)+1, (__arr)+(__to), ((__from)-(__to))*sizeof(__type)); \ + memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ + } \ + }while(0) @@ -935,12 +934,12 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __arr Array /// @param __type Type of entry #define ARR_MOVERIGHT(__from, __to, __arr, __type) \ - do{ \ - __type __backup__; \ - memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ - memmove((__arr)+(__from), (__arr)+(__from)+1, ((__to)-(__from))*sizeof(__type)); \ - memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ - }while(0) + do{ \ + __type __backup__; \ + memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ + memmove((__arr)+(__from), (__arr)+(__from)+1, ((__to)-(__from))*sizeof(__type)); \ + memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ + }while(0) @@ -952,12 +951,12 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __arr Array /// @param __type Type of entry #define ARR_MOVELEFT(__from, __to, __arr, __type) \ - do{ \ - __type __backup__; \ - memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ - memmove((__arr)+(__to)+1, (__arr)+(__to), ((__from)-(__to))*sizeof(__type)); \ - memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ - }while(0) + do{ \ + __type __backup__; \ + memmove(&__backup__, (__arr)+(__from), sizeof(__type)); \ + memmove((__arr)+(__to)+1, (__arr)+(__to), ((__from)-(__to))*sizeof(__type)); \ + memmove((__arr)+(__to), &__backup__, sizeof(__type)); \ + }while(0) @@ -971,11 +970,11 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// /// @param __type Type of data #define VECTOR_DECL(__type) \ - struct { \ - size_t _max_; \ - size_t _len_; \ - __type* _data_; \ - } + struct { \ + size_t _max_; \ + size_t _len_; \ + __type* _data_; \ + } @@ -984,11 +983,11 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __name Structure name /// @param __type Type of data #define VECTOR_STRUCT_DECL(__name,__type) \ - struct __name { \ - size_t _max_; \ - size_t _len_; \ - __type* _data_; \ - } + struct __name { \ + size_t _max_; \ + size_t _len_; \ + __type* _data_; \ + } @@ -997,7 +996,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __type Type of data /// @param __var Variable name #define VECTOR_VAR(__type,__var) \ - VECTOR_DECL(__type) __var = {0,0,NULL} + VECTOR_DECL(__type) __var = {0,0,NULL} @@ -1006,7 +1005,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __name Structure name /// @param __var Variable name #define VECTOR_STRUCT_VAR(__name,__var) \ - struct __name __var = {0,0,NULL} + struct __name __var = {0,0,NULL} @@ -1014,7 +1013,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// /// @param __vec Vector #define VECTOR_INIT(__vec) \ - memset(&(__vec), 0, sizeof(__vec)) + memset(&(__vec), 0, sizeof(__vec)) @@ -1023,7 +1022,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @return Array of values #define VECTOR_DATA(__vec) \ - ( (__vec)._data_ ) + ( (__vec)._data_ ) @@ -1032,7 +1031,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @return Length #define VECTOR_LENGTH(__vec) \ - ( (__vec)._len_ ) + ( (__vec)._len_ ) @@ -1041,7 +1040,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @return Capacity #define VECTOR_CAPACITY(__vec) \ - ( (__vec)._max_ ) + ( (__vec)._max_ ) @@ -1052,7 +1051,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __idx Index /// @return Value #define VECTOR_INDEX(__vec,__idx) \ - ( VECTOR_DATA(__vec)[__idx] ) + ( VECTOR_DATA(__vec)[__idx] ) @@ -1062,7 +1061,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @return First value #define VECTOR_FIRST(__vec) \ - ( VECTOR_INDEX(__vec,0) ) + ( VECTOR_INDEX(__vec,0) ) @@ -1072,7 +1071,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @return Last value #define VECTOR_LAST(__vec) \ - ( VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)-1) ) + ( VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)-1) ) @@ -1082,27 +1081,27 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @param __n Size #define VECTOR_RESIZE(__vec,__n) \ - do{ \ - if( (__n) > VECTOR_CAPACITY(__vec) ) \ - { /* increase size */ \ - if( VECTOR_CAPACITY(__vec) == 0 ) SET_POINTER(VECTOR_DATA(__vec), aMalloc((__n)*sizeof(VECTOR_FIRST(__vec)))); /* allocate new */ \ - else SET_POINTER(VECTOR_DATA(__vec), aRealloc(VECTOR_DATA(__vec),(__n)*sizeof(VECTOR_FIRST(__vec)))); /* reallocate */ \ - memset(VECTOR_DATA(__vec)+VECTOR_LENGTH(__vec), 0, (VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec))*sizeof(VECTOR_FIRST(__vec))); /* clear new data */ \ - VECTOR_CAPACITY(__vec) = (__n); /* update capacity */ \ - } \ - else if( (__n) == 0 && VECTOR_CAPACITY(__vec) ) \ - { /* clear vector */ \ - aFree(VECTOR_DATA(__vec)); VECTOR_DATA(__vec) = NULL; /* free data */ \ - VECTOR_CAPACITY(__vec) = 0; /* clear capacity */ \ - VECTOR_LENGTH(__vec) = 0; /* clear length */ \ - } \ - else if( (__n) < VECTOR_CAPACITY(__vec) ) \ - { /* reduce size */ \ - SET_POINTER(VECTOR_DATA(__vec), aRealloc(VECTOR_DATA(__vec),(__n)*sizeof(VECTOR_FIRST(__vec)))); /* reallocate */ \ - VECTOR_CAPACITY(__vec) = (__n); /* update capacity */ \ - if( VECTOR_LENGTH(__vec) > (__n) ) VECTOR_LENGTH(__vec) = (__n); /* update length */ \ - } \ - }while(0) + do{ \ + if( (__n) > VECTOR_CAPACITY(__vec) ) \ + { /* increase size */ \ + if( VECTOR_CAPACITY(__vec) == 0 ) SET_POINTER(VECTOR_DATA(__vec), aMalloc((__n)*sizeof(VECTOR_FIRST(__vec)))); /* allocate new */ \ + else SET_POINTER(VECTOR_DATA(__vec), aRealloc(VECTOR_DATA(__vec),(__n)*sizeof(VECTOR_FIRST(__vec)))); /* reallocate */ \ + memset(VECTOR_DATA(__vec)+VECTOR_LENGTH(__vec), 0, (VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec))*sizeof(VECTOR_FIRST(__vec))); /* clear new data */ \ + VECTOR_CAPACITY(__vec) = (__n); /* update capacity */ \ + } \ + else if( (__n) == 0 && VECTOR_CAPACITY(__vec) ) \ + { /* clear vector */ \ + aFree(VECTOR_DATA(__vec)); VECTOR_DATA(__vec) = NULL; /* free data */ \ + VECTOR_CAPACITY(__vec) = 0; /* clear capacity */ \ + VECTOR_LENGTH(__vec) = 0; /* clear length */ \ + } \ + else if( (__n) < VECTOR_CAPACITY(__vec) ) \ + { /* reduce size */ \ + SET_POINTER(VECTOR_DATA(__vec), aRealloc(VECTOR_DATA(__vec),(__n)*sizeof(VECTOR_FIRST(__vec)))); /* reallocate */ \ + VECTOR_CAPACITY(__vec) = (__n); /* update capacity */ \ + if( VECTOR_LENGTH(__vec) > (__n) ) VECTOR_LENGTH(__vec) = (__n); /* update length */ \ + } \ + }while(0) @@ -1113,11 +1112,11 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __n Empty positions /// @param __step Increase #define VECTOR_ENSURE(__vec,__n,__step) \ - do{ \ - size_t _empty_ = VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec); \ - while( (__n) > _empty_ ) _empty_ += (__step); \ - if( _empty_ != VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec) ) VECTOR_RESIZE(__vec,_empty_+VECTOR_LENGTH(__vec)); \ - }while(0) + do{ \ + size_t _empty_ = VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec); \ + while( (__n) > _empty_ ) _empty_ += (__step); \ + if( _empty_ != VECTOR_CAPACITY(__vec)-VECTOR_LENGTH(__vec) ) VECTOR_RESIZE(__vec,_empty_+VECTOR_LENGTH(__vec)); \ + }while(0) @@ -1127,12 +1126,12 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @param __idx Index #define VECTOR_INSERTZEROED(__vec,__idx) \ - do{ \ - if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ - memmove(&VECTOR_INDEX(__vec,(__idx)+1),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ - memset(&VECTOR_INDEX(__vec,__idx), 0, sizeof(VECTOR_INDEX(__vec,__idx))); /* set zeroed value */ \ - ++VECTOR_LENGTH(__vec); /* increase length */ \ - }while(0) + do{ \ + if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ + memmove(&VECTOR_INDEX(__vec,(__idx)+1),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ + memset(&VECTOR_INDEX(__vec,__idx), 0, sizeof(VECTOR_INDEX(__vec,__idx))); /* set zeroed value */ \ + ++VECTOR_LENGTH(__vec); /* increase length */ \ + }while(0) @@ -1143,12 +1142,12 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __idx Index /// @param __val Value #define VECTOR_INSERT(__vec,__idx,__val) \ - do{ \ - if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ - memmove(&VECTOR_INDEX(__vec,(__idx)+1),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ - VECTOR_INDEX(__vec,__idx) = (__val); /* set value */ \ - ++VECTOR_LENGTH(__vec); /* increase length */ \ - }while(0) + do{ \ + if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ + memmove(&VECTOR_INDEX(__vec,(__idx)+1),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ + VECTOR_INDEX(__vec,__idx) = (__val); /* set value */ \ + ++VECTOR_LENGTH(__vec); /* increase length */ \ + }while(0) @@ -1159,7 +1158,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __idx Index /// @param __val Value #define VECTOR_INSERTCOPY(__vec,__idx,__val) \ - VECTOR_INSERTARRAY(__vec,__idx,&(__val),1) + VECTOR_INSERTARRAY(__vec,__idx,&(__val),1) @@ -1171,12 +1170,12 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __pval Array of values /// @param __n Number of values #define VECTOR_INSERTARRAY(__vec,__idx,__pval,__n) \ - do{ \ - if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ - memmove(&VECTOR_INDEX(__vec,(__idx)+(__n)),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ - memcpy(&VECTOR_INDEX(__vec,__idx), (__pval), (__n)*sizeof(VECTOR_FIRST(__vec))); /* set values */ \ - VECTOR_LENGTH(__vec) += (__n); /* increase length */ \ - }while(0) + do{ \ + if( (__idx) < VECTOR_LENGTH(__vec) ) /* move data */ \ + memmove(&VECTOR_INDEX(__vec,(__idx)+(__n)),&VECTOR_INDEX(__vec,__idx),(VECTOR_LENGTH(__vec)-(__idx))*sizeof(VECTOR_FIRST(__vec))); \ + memcpy(&VECTOR_INDEX(__vec,__idx), (__pval), (__n)*sizeof(VECTOR_FIRST(__vec))); /* set values */ \ + VECTOR_LENGTH(__vec) += (__n); /* increase length */ \ + }while(0) @@ -1185,10 +1184,10 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// /// @param __vec Vector #define VECTOR_PUSHZEROED(__vec) \ - do{ \ - memset(&VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)), 0, sizeof(VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)))); /* set zeroed value */ \ - ++VECTOR_LENGTH(__vec); /* increase length */ \ - }while(0) + do{ \ + memset(&VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)), 0, sizeof(VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)))); /* set zeroed value */ \ + ++VECTOR_LENGTH(__vec); /* increase length */ \ + }while(0) /// Inserts a value in the end of the vector. (using the '=' operator) @@ -1197,10 +1196,10 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @param __val Value #define VECTOR_PUSH(__vec,__val) \ - do{ \ - VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)) = (__val); /* set value */ \ - ++VECTOR_LENGTH(__vec); /* increase length */ \ - }while(0) + do{ \ + VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)) = (__val); /* set value */ \ + ++VECTOR_LENGTH(__vec); /* increase length */ \ + }while(0) @@ -1210,7 +1209,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @param __val Value #define VECTOR_PUSHCOPY(__vec,__val) \ - VECTOR_PUSHARRAY(__vec,&(__val),1) + VECTOR_PUSHARRAY(__vec,&(__val),1) @@ -1221,10 +1220,10 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __pval Array of values /// @param __n Number of values #define VECTOR_PUSHARRAY(__vec,__pval,__n) \ - do{ \ - memcpy(&VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)), (__pval), (__n)*sizeof(VECTOR_FIRST(__vec))); /* set values */ \ - VECTOR_LENGTH(__vec) += (__n); /* increase length */ \ - }while(0) + do{ \ + memcpy(&VECTOR_INDEX(__vec,VECTOR_LENGTH(__vec)), (__pval), (__n)*sizeof(VECTOR_FIRST(__vec))); /* set values */ \ + VECTOR_LENGTH(__vec) += (__n); /* increase length */ \ + }while(0) @@ -1234,7 +1233,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @return Removed value #define VECTOR_POP(__vec) \ - ( VECTOR_INDEX(__vec,--VECTOR_LENGTH(__vec)) ) + ( VECTOR_INDEX(__vec,--VECTOR_LENGTH(__vec)) ) @@ -1245,7 +1244,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __n Number of pops /// @return Last removed value #define VECTOR_POPN(__vec,__n) \ - ( VECTOR_INDEX(__vec,(VECTOR_LENGTH(__vec)-=(__n))) ) + ( VECTOR_INDEX(__vec,(VECTOR_LENGTH(__vec)-=(__n))) ) @@ -1255,7 +1254,7 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __vec Vector /// @param __idx Index #define VECTOR_ERASE(__vec,__idx) \ - VECTOR_ERASEN(__vec,__idx,1) + VECTOR_ERASEN(__vec,__idx,1) @@ -1266,11 +1265,11 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __idx Index /// @param __n Number of values #define VECTOR_ERASEN(__vec,__idx,__n) \ - do{ \ - if( (__idx) < VECTOR_LENGTH(__vec)-(__n) ) /* move data */ \ - memmove(&VECTOR_INDEX(__vec,__idx),&VECTOR_INDEX(__vec,(__idx)+(__n)),(VECTOR_LENGTH(__vec)-((__idx)+(__n)))*sizeof(VECTOR_FIRST(__vec))); \ - VECTOR_LENGTH(__vec) -= (__n); /* decrease length */ \ - }while(0) + do{ \ + if( (__idx) < VECTOR_LENGTH(__vec)-(__n) ) /* move data */ \ + memmove(&VECTOR_INDEX(__vec,__idx),&VECTOR_INDEX(__vec,(__idx)+(__n)),(VECTOR_LENGTH(__vec)-((__idx)+(__n)))*sizeof(VECTOR_FIRST(__vec))); \ + VECTOR_LENGTH(__vec) -= (__n); /* decrease length */ \ + }while(0) @@ -1278,14 +1277,14 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// /// @param __vec Vector #define VECTOR_CLEAR(__vec) \ - do{ \ - if( VECTOR_CAPACITY(__vec) ) \ - { \ - aFree(VECTOR_DATA(__vec)); VECTOR_DATA(__vec) = NULL; /* clear allocated array */ \ - VECTOR_CAPACITY(__vec) = 0; /* clear capacity */ \ - VECTOR_LENGTH(__vec) = 0; /* clear length */ \ - } \ - }while(0) + do{ \ + if( VECTOR_CAPACITY(__vec) ) \ + { \ + aFree(VECTOR_DATA(__vec)); VECTOR_DATA(__vec) = NULL; /* clear allocated array */ \ + VECTOR_CAPACITY(__vec) = 0; /* clear capacity */ \ + VECTOR_LENGTH(__vec) = 0; /* clear length */ \ + } \ + }while(0) @@ -1388,18 +1387,18 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __val Value /// @param __topcmp Comparator #define BHEAP_PUSH(__heap,__val,__topcmp) \ - do{ \ - size_t _i_ = VECTOR_LENGTH(__heap); \ - VECTOR_PUSH(__heap,__val); /* insert at end */ \ - while( _i_ ) \ - { /* restore heap property in parents */ \ - size_t _parent_ = (_i_-1)/2; \ - if( __topcmp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)) < 0 ) \ - break; /* done */ \ - swap(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)); \ - _i_ = _parent_; \ - } \ - }while(0) + do{ \ + size_t _i_ = VECTOR_LENGTH(__heap); \ + VECTOR_PUSH(__heap,__val); /* insert at end */ \ + while( _i_ ) \ + { /* restore heap property in parents */ \ + size_t _parent_ = (_i_-1)/2; \ + if( __topcmp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)) < 0 ) \ + break; /* done */ \ + swap(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)); \ + _i_ = _parent_; \ + } \ + }while(0) @@ -1429,36 +1428,36 @@ void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); /// @param __idx Index /// @param __topcmp Comparator #define BHEAP_POPINDEX(__heap,__idx,__topcmp) \ - do{ \ - size_t _i_ = __idx; \ - VECTOR_INDEX(__heap,__idx) = VECTOR_POP(__heap); /* put last at index */ \ - while( _i_ ) \ - { /* restore heap property in parents */ \ - size_t _parent_ = (_i_-1)/2; \ - if( __topcmp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)) < 0 ) \ - break; /* done */ \ - swap(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)); \ - _i_ = _parent_; \ - } \ - while( _i_ < VECTOR_LENGTH(__heap) ) \ - { /* restore heap property in childs */ \ - size_t _lchild_ = _i_*2 + 1; \ - size_t _rchild_ = _i_*2 + 2; \ - if( (_lchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)) <= 0) && \ - (_rchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)) <= 0) ) \ - break; /* done */ \ - else if( _rchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_lchild_),VECTOR_INDEX(__heap,_rchild_)) <= 0 ) \ - { /* left child */ \ - swap(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)); \ - _i_ = _lchild_; \ - } \ - else \ - { /* right child */ \ - swap(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)); \ - _i_ = _rchild_; \ - } \ - } \ - }while(0) + do{ \ + size_t _i_ = __idx; \ + VECTOR_INDEX(__heap,__idx) = VECTOR_POP(__heap); /* put last at index */ \ + while( _i_ ) \ + { /* restore heap property in parents */ \ + size_t _parent_ = (_i_-1)/2; \ + if( __topcmp(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)) < 0 ) \ + break; /* done */ \ + swap(VECTOR_INDEX(__heap,_parent_),VECTOR_INDEX(__heap,_i_)); \ + _i_ = _parent_; \ + } \ + while( _i_ < VECTOR_LENGTH(__heap) ) \ + { /* restore heap property in childs */ \ + size_t _lchild_ = _i_*2 + 1; \ + size_t _rchild_ = _i_*2 + 2; \ + if( (_lchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)) <= 0) && \ + (_rchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)) <= 0) ) \ + break; /* done */ \ + else if( _rchild_ >= VECTOR_LENGTH(__heap) || __topcmp(VECTOR_INDEX(__heap,_lchild_),VECTOR_INDEX(__heap,_rchild_)) <= 0 ) \ + { /* left child */ \ + swap(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_lchild_)); \ + _i_ = _lchild_; \ + } \ + else \ + { /* right child */ \ + swap(VECTOR_INDEX(__heap,_i_),VECTOR_INDEX(__heap,_rchild_)); \ + _i_ = _rchild_; \ + } \ + } \ + }while(0) diff --git a/src/common/des.c b/src/common/des.c index 917fc33e0..f2347f3c4 100644 --- a/src/common/des.c +++ b/src/common/des.c @@ -12,207 +12,201 @@ /// Bitmask for accessing individual bits of a byte. static const uint8_t mask[8] = { - 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 + 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; /// Initial permutation (IP). -static void IP(BIT64* src) +static void IP(BIT64 *src) { - BIT64 tmp = {{0}}; - - static const uint8_t ip_table[64] = { - 58, 50, 42, 34, 26, 18, 10, 2, - 60, 52, 44, 36, 28, 20, 12, 4, - 62, 54, 46, 38, 30, 22, 14, 6, - 64, 56, 48, 40, 32, 24, 16, 8, - 57, 49, 41, 33, 25, 17, 9, 1, - 59, 51, 43, 35, 27, 19, 11, 3, - 61, 53, 45, 37, 29, 21, 13, 5, - 63, 55, 47, 39, 31, 23, 15, 7, - }; - - size_t i; - for( i = 0; i < ARRAYLENGTH(ip_table); ++i ) - { - uint8_t j = ip_table[i] - 1; - if( src->b[(j >> 3) & 7] & mask[j & 7] ) - tmp .b[(i >> 3) & 7] |= mask[i & 7]; - } - - *src = tmp; + BIT64 tmp = {{0}}; + + static const uint8_t ip_table[64] = { + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7, + }; + + size_t i; + for (i = 0; i < ARRAYLENGTH(ip_table); ++i) { + uint8_t j = ip_table[i] - 1; + if (src->b[(j >> 3) & 7] & mask[j & 7]) + tmp .b[(i >> 3) & 7] |= mask[i & 7]; + } + + *src = tmp; } /// Final permutation (IP^-1). -static void FP(BIT64* src) +static void FP(BIT64 *src) { - BIT64 tmp = {{0}}; - - static const uint8_t fp_table[64] = { - 40, 8, 48, 16, 56, 24, 64, 32, - 39, 7, 47, 15, 55, 23, 63, 31, - 38, 6, 46, 14, 54, 22, 62, 30, - 37, 5, 45, 13, 53, 21, 61, 29, - 36, 4, 44, 12, 52, 20, 60, 28, - 35, 3, 43, 11, 51, 19, 59, 27, - 34, 2, 42, 10, 50, 18, 58, 26, - 33, 1, 41, 9, 49, 17, 57, 25, - }; - - size_t i; - for( i = 0; i < ARRAYLENGTH(fp_table); ++i ) - { - uint8_t j = fp_table[i] - 1; - if( src->b[(j >> 3) & 7] & mask[j & 7] ) - tmp .b[(i >> 3) & 7] |= mask[i & 7]; - } - - *src = tmp; + BIT64 tmp = {{0}}; + + static const uint8_t fp_table[64] = { + 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25, + }; + + size_t i; + for (i = 0; i < ARRAYLENGTH(fp_table); ++i) { + uint8_t j = fp_table[i] - 1; + if (src->b[(j >> 3) & 7] & mask[j & 7]) + tmp .b[(i >> 3) & 7] |= mask[i & 7]; + } + + *src = tmp; } /// Expansion (E). /// Expands upper four 8-bits (32b) into eight 6-bits (48b). -static void E(BIT64* src) +static void E(BIT64 *src) { - BIT64 tmp = {{0}}; - -if( false ) -{// original - static const uint8_t expand_table[48] = { - 32, 1, 2, 3, 4, 5, - 4, 5, 6, 7, 8, 9, - 8, 9, 10, 11, 12, 13, - 12, 13, 14, 15, 16, 17, - 16, 17, 18, 19, 20, 21, - 20, 21, 22, 23, 24, 25, - 24, 25, 26, 27, 28, 29, - 28, 29, 30, 31, 32, 1, - }; - - size_t i; - for( i = 0; i < ARRAYLENGTH(expand_table); ++i ) - { - uint8_t j = expand_table[i] - 1; - if( src->b[j / 8 + 4] & mask[j % 8] ) - tmp .b[i / 6 + 0] |= mask[i % 6]; - } -} -else -{// optimized - tmp.b[0] = ((src->b[7]<<5) | (src->b[4]>>3)) & 0x3f; // ..0 vutsr - tmp.b[1] = ((src->b[4]<<1) | (src->b[5]>>7)) & 0x3f; // ..srqpo n - tmp.b[2] = ((src->b[4]<<5) | (src->b[5]>>3)) & 0x3f; // ..o nmlkj - tmp.b[3] = ((src->b[5]<<1) | (src->b[6]>>7)) & 0x3f; // ..kjihg f - tmp.b[4] = ((src->b[5]<<5) | (src->b[6]>>3)) & 0x3f; // ..g fedcb - tmp.b[5] = ((src->b[6]<<1) | (src->b[7]>>7)) & 0x3f; // ..cba98 7 - tmp.b[6] = ((src->b[6]<<5) | (src->b[7]>>3)) & 0x3f; // ..8 76543 - tmp.b[7] = ((src->b[7]<<1) | (src->b[4]>>7)) & 0x3f; // ..43210 v -} - - *src = tmp; + BIT64 tmp = {{0}}; + + if (false) { + // original + static const uint8_t expand_table[48] = { + 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, + 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, + 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, + 28, 29, 30, 31, 32, 1, + }; + + size_t i; + for (i = 0; i < ARRAYLENGTH(expand_table); ++i) { + uint8_t j = expand_table[i] - 1; + if (src->b[j / 8 + 4] & mask[j % 8]) + tmp .b[i / 6 + 0] |= mask[i % 6]; + } + } else { + // optimized + tmp.b[0] = ((src->b[7]<<5) | (src->b[4]>>3)) & 0x3f; // ..0 vutsr + tmp.b[1] = ((src->b[4]<<1) | (src->b[5]>>7)) & 0x3f; // ..srqpo n + tmp.b[2] = ((src->b[4]<<5) | (src->b[5]>>3)) & 0x3f; // ..o nmlkj + tmp.b[3] = ((src->b[5]<<1) | (src->b[6]>>7)) & 0x3f; // ..kjihg f + tmp.b[4] = ((src->b[5]<<5) | (src->b[6]>>3)) & 0x3f; // ..g fedcb + tmp.b[5] = ((src->b[6]<<1) | (src->b[7]>>7)) & 0x3f; // ..cba98 7 + tmp.b[6] = ((src->b[6]<<5) | (src->b[7]>>3)) & 0x3f; // ..8 76543 + tmp.b[7] = ((src->b[7]<<1) | (src->b[4]>>7)) & 0x3f; // ..43210 v + } + + *src = tmp; } /// Transposition (P-BOX). -static void TP(BIT64* src) +static void TP(BIT64 *src) { - BIT64 tmp = {{0}}; - - static const uint8_t tp_table[32] = { - 16, 7, 20, 21, - 29, 12, 28, 17, - 1, 15, 23, 26, - 5, 18, 31, 10, - 2, 8, 24, 14, - 32, 27, 3, 9, - 19, 13, 30, 6, - 22, 11, 4, 25, - }; - - size_t i; - for( i = 0; i < ARRAYLENGTH(tp_table); ++i ) - { - uint8_t j = tp_table[i] - 1; - if( src->b[(j >> 3) + 0] & mask[j & 7] ) - tmp .b[(i >> 3) + 4] |= mask[i & 7]; - } - - *src = tmp; + BIT64 tmp = {{0}}; + + static const uint8_t tp_table[32] = { + 16, 7, 20, 21, + 29, 12, 28, 17, + 1, 15, 23, 26, + 5, 18, 31, 10, + 2, 8, 24, 14, + 32, 27, 3, 9, + 19, 13, 30, 6, + 22, 11, 4, 25, + }; + + size_t i; + for (i = 0; i < ARRAYLENGTH(tp_table); ++i) { + uint8_t j = tp_table[i] - 1; + if (src->b[(j >> 3) + 0] & mask[j & 7]) + tmp .b[(i >> 3) + 4] |= mask[i & 7]; + } + + *src = tmp; } /// Substitution boxes (S-boxes). /// NOTE: This implementation was optimized to process two nibbles in one step (twice as fast). -static void SBOX(BIT64* src) +static void SBOX(BIT64 *src) { - BIT64 tmp = {{0}}; - - static const uint8_t s_table[4][64] = { - { - 0xef, 0x03, 0x41, 0xfd, 0xd8, 0x74, 0x1e, 0x47, 0x26, 0xef, 0xfb, 0x22, 0xb3, 0xd8, 0x84, 0x1e, - 0x39, 0xac, 0xa7, 0x60, 0x62, 0xc1, 0xcd, 0xba, 0x5c, 0x96, 0x90, 0x59, 0x05, 0x3b, 0x7a, 0x85, - 0x40, 0xfd, 0x1e, 0xc8, 0xe7, 0x8a, 0x8b, 0x21, 0xda, 0x43, 0x64, 0x9f, 0x2d, 0x14, 0xb1, 0x72, - 0xf5, 0x5b, 0xc8, 0xb6, 0x9c, 0x37, 0x76, 0xec, 0x39, 0xa0, 0xa3, 0x05, 0x52, 0x6e, 0x0f, 0xd9, - },{ - 0xa7, 0xdd, 0x0d, 0x78, 0x9e, 0x0b, 0xe3, 0x95, 0x60, 0x36, 0x36, 0x4f, 0xf9, 0x60, 0x5a, 0xa3, - 0x11, 0x24, 0xd2, 0x87, 0xc8, 0x52, 0x75, 0xec, 0xbb, 0xc1, 0x4c, 0xba, 0x24, 0xfe, 0x8f, 0x19, - 0xda, 0x13, 0x66, 0xaf, 0x49, 0xd0, 0x90, 0x06, 0x8c, 0x6a, 0xfb, 0x91, 0x37, 0x8d, 0x0d, 0x78, - 0xbf, 0x49, 0x11, 0xf4, 0x23, 0xe5, 0xce, 0x3b, 0x55, 0xbc, 0xa2, 0x57, 0xe8, 0x22, 0x74, 0xce, - },{ - 0x2c, 0xea, 0xc1, 0xbf, 0x4a, 0x24, 0x1f, 0xc2, 0x79, 0x47, 0xa2, 0x7c, 0xb6, 0xd9, 0x68, 0x15, - 0x80, 0x56, 0x5d, 0x01, 0x33, 0xfd, 0xf4, 0xae, 0xde, 0x30, 0x07, 0x9b, 0xe5, 0x83, 0x9b, 0x68, - 0x49, 0xb4, 0x2e, 0x83, 0x1f, 0xc2, 0xb5, 0x7c, 0xa2, 0x19, 0xd8, 0xe5, 0x7c, 0x2f, 0x83, 0xda, - 0xf7, 0x6b, 0x90, 0xfe, 0xc4, 0x01, 0x5a, 0x97, 0x61, 0xa6, 0x3d, 0x40, 0x0b, 0x58, 0xe6, 0x3d, - },{ - 0x4d, 0xd1, 0xb2, 0x0f, 0x28, 0xbd, 0xe4, 0x78, 0xf6, 0x4a, 0x0f, 0x93, 0x8b, 0x17, 0xd1, 0xa4, - 0x3a, 0xec, 0xc9, 0x35, 0x93, 0x56, 0x7e, 0xcb, 0x55, 0x20, 0xa0, 0xfe, 0x6c, 0x89, 0x17, 0x62, - 0x17, 0x62, 0x4b, 0xb1, 0xb4, 0xde, 0xd1, 0x87, 0xc9, 0x14, 0x3c, 0x4a, 0x7e, 0xa8, 0xe2, 0x7d, - 0xa0, 0x9f, 0xf6, 0x5c, 0x6a, 0x09, 0x8d, 0xf0, 0x0f, 0xe3, 0x53, 0x25, 0x95, 0x36, 0x28, 0xcb, - } - }; - - size_t i; - for( i = 0; i < ARRAYLENGTH(s_table); ++i ) - { - tmp.b[i] = (s_table[i][src->b[i*2+0]] & 0xf0) - | (s_table[i][src->b[i*2+1]] & 0x0f); - } - - *src = tmp; + BIT64 tmp = {{0}}; + + static const uint8_t s_table[4][64] = { + { + 0xef, 0x03, 0x41, 0xfd, 0xd8, 0x74, 0x1e, 0x47, 0x26, 0xef, 0xfb, 0x22, 0xb3, 0xd8, 0x84, 0x1e, + 0x39, 0xac, 0xa7, 0x60, 0x62, 0xc1, 0xcd, 0xba, 0x5c, 0x96, 0x90, 0x59, 0x05, 0x3b, 0x7a, 0x85, + 0x40, 0xfd, 0x1e, 0xc8, 0xe7, 0x8a, 0x8b, 0x21, 0xda, 0x43, 0x64, 0x9f, 0x2d, 0x14, 0xb1, 0x72, + 0xf5, 0x5b, 0xc8, 0xb6, 0x9c, 0x37, 0x76, 0xec, 0x39, 0xa0, 0xa3, 0x05, 0x52, 0x6e, 0x0f, 0xd9, + },{ + 0xa7, 0xdd, 0x0d, 0x78, 0x9e, 0x0b, 0xe3, 0x95, 0x60, 0x36, 0x36, 0x4f, 0xf9, 0x60, 0x5a, 0xa3, + 0x11, 0x24, 0xd2, 0x87, 0xc8, 0x52, 0x75, 0xec, 0xbb, 0xc1, 0x4c, 0xba, 0x24, 0xfe, 0x8f, 0x19, + 0xda, 0x13, 0x66, 0xaf, 0x49, 0xd0, 0x90, 0x06, 0x8c, 0x6a, 0xfb, 0x91, 0x37, 0x8d, 0x0d, 0x78, + 0xbf, 0x49, 0x11, 0xf4, 0x23, 0xe5, 0xce, 0x3b, 0x55, 0xbc, 0xa2, 0x57, 0xe8, 0x22, 0x74, 0xce, + },{ + 0x2c, 0xea, 0xc1, 0xbf, 0x4a, 0x24, 0x1f, 0xc2, 0x79, 0x47, 0xa2, 0x7c, 0xb6, 0xd9, 0x68, 0x15, + 0x80, 0x56, 0x5d, 0x01, 0x33, 0xfd, 0xf4, 0xae, 0xde, 0x30, 0x07, 0x9b, 0xe5, 0x83, 0x9b, 0x68, + 0x49, 0xb4, 0x2e, 0x83, 0x1f, 0xc2, 0xb5, 0x7c, 0xa2, 0x19, 0xd8, 0xe5, 0x7c, 0x2f, 0x83, 0xda, + 0xf7, 0x6b, 0x90, 0xfe, 0xc4, 0x01, 0x5a, 0x97, 0x61, 0xa6, 0x3d, 0x40, 0x0b, 0x58, 0xe6, 0x3d, + },{ + 0x4d, 0xd1, 0xb2, 0x0f, 0x28, 0xbd, 0xe4, 0x78, 0xf6, 0x4a, 0x0f, 0x93, 0x8b, 0x17, 0xd1, 0xa4, + 0x3a, 0xec, 0xc9, 0x35, 0x93, 0x56, 0x7e, 0xcb, 0x55, 0x20, 0xa0, 0xfe, 0x6c, 0x89, 0x17, 0x62, + 0x17, 0x62, 0x4b, 0xb1, 0xb4, 0xde, 0xd1, 0x87, 0xc9, 0x14, 0x3c, 0x4a, 0x7e, 0xa8, 0xe2, 0x7d, + 0xa0, 0x9f, 0xf6, 0x5c, 0x6a, 0x09, 0x8d, 0xf0, 0x0f, 0xe3, 0x53, 0x25, 0x95, 0x36, 0x28, 0xcb, + } + }; + + size_t i; + for (i = 0; i < ARRAYLENGTH(s_table); ++i) { + tmp.b[i] = (s_table[i][src->b[i*2+0]] & 0xf0) + | (s_table[i][src->b[i*2+1]] & 0x0f); + } + + *src = tmp; } /// DES round function. /// XORs src[0..3] with TP(SBOX(E(src[4..7]))). -static void RoundFunction(BIT64* src) +static void RoundFunction(BIT64 *src) { - BIT64 tmp = *src; - E(&tmp); - SBOX(&tmp); - TP(&tmp); - - src->b[0] ^= tmp.b[4]; - src->b[1] ^= tmp.b[5]; - src->b[2] ^= tmp.b[6]; - src->b[3] ^= tmp.b[7]; + BIT64 tmp = *src; + E(&tmp); + SBOX(&tmp); + TP(&tmp); + + src->b[0] ^= tmp.b[4]; + src->b[1] ^= tmp.b[5]; + src->b[2] ^= tmp.b[6]; + src->b[3] ^= tmp.b[7]; } -void des_decrypt_block(BIT64* block) +void des_decrypt_block(BIT64 *block) { - IP(block); - RoundFunction(block); - FP(block); + IP(block); + RoundFunction(block); + FP(block); } -void des_decrypt(unsigned char* data, size_t size) +void des_decrypt(unsigned char *data, size_t size) { - BIT64* p = (BIT64*)data; - size_t i; + BIT64 *p = (BIT64 *)data; + size_t i; - for( i = 0; i*8 < size; i += 8 ) - des_decrypt_block(p); + for (i = 0; i*8 < size; i += 8) + des_decrypt_block(p); } diff --git a/src/common/des.h b/src/common/des.h index e42136436..a13a17165 100644 --- a/src/common/des.h +++ b/src/common/des.h @@ -1,15 +1,17 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _DES_H_ -#define _DES_H_ +#ifndef _DES_H_ +#define _DES_H_ /// One 64-bit block. -typedef struct BIT64 { uint8_t b[8]; } BIT64; +typedef struct BIT64 { + uint8_t b[8]; +} BIT64; -void des_decrypt_block(BIT64* block); -void des_decrypt(unsigned char* data, size_t size); +void des_decrypt_block(BIT64 *block); +void des_decrypt(unsigned char *data, size_t size); #endif // _DES_H_ diff --git a/src/common/ers.c b/src/common/ers.c index b94b0888d..d75f23f6f 100644 --- a/src/common/ers.c +++ b/src/common/ers.c @@ -51,54 +51,51 @@ #define ERS_ROOT_SIZE 256 #define ERS_BLOCK_ENTRIES 4096 -struct ers_list -{ - struct ers_list *Next; +struct ers_list { + struct ers_list *Next; }; -typedef struct ers_cache -{ - // Allocated object size, including ers_list size - unsigned int ObjectSize; +typedef struct ers_cache { + // Allocated object size, including ers_list size + unsigned int ObjectSize; + + // Number of ers_instances referencing this + int ReferenceCount; - // Number of ers_instances referencing this - int ReferenceCount; + // Reuse linked list + struct ers_list *ReuseList; - // Reuse linked list - struct ers_list *ReuseList; + // Memory blocks array + unsigned char **Blocks; - // Memory blocks array - unsigned char **Blocks; + // Max number of blocks + unsigned int Max; - // Max number of blocks - unsigned int Max; + // Free objects count + unsigned int Free; - // Free objects count - unsigned int Free; - - // Used objects count - unsigned int Used; + // Used objects count + unsigned int Used; - // Linked list - struct ers_cache *Next, *Prev; + // Linked list + struct ers_cache *Next, *Prev; } ers_cache_t; -typedef struct -{ - // Interface to ERS - struct eri VTable; - - // Name, used for debbuging purpouses - char *Name; +typedef struct { + // Interface to ERS + struct eri VTable; + + // Name, used for debbuging purpouses + char *Name; - // Misc options - enum ERSOptions Options; + // Misc options + enum ERSOptions Options; - // Our cache - ers_cache_t *Cache; + // Our cache + ers_cache_t *Cache; - // Count of objects in use, used for detecting memory leaks - unsigned int Count; + // Count of objects in use, used for detecting memory leaks + unsigned int Count; } ers_instance_t; @@ -107,186 +104,171 @@ static ers_cache_t *CacheList; static ers_cache_t *ers_find_cache(unsigned int size) { - ers_cache_t *cache; - - for (cache = CacheList; cache; cache = cache->Next) - if (cache->ObjectSize == size) - return cache; - - CREATE(cache, ers_cache_t, 1); - cache->ObjectSize = size; - cache->ReferenceCount = 0; - cache->ReuseList = NULL; - cache->Blocks = NULL; - cache->Free = 0; - cache->Used = 0; - cache->Max = 0; - - if (CacheList == NULL) - { - CacheList = cache; - } - else - { - cache->Next = CacheList; - cache->Next->Prev = cache; - CacheList = cache; - CacheList->Prev = NULL; - } - - return cache; + ers_cache_t *cache; + + for (cache = CacheList; cache; cache = cache->Next) + if (cache->ObjectSize == size) + return cache; + + CREATE(cache, ers_cache_t, 1); + cache->ObjectSize = size; + cache->ReferenceCount = 0; + cache->ReuseList = NULL; + cache->Blocks = NULL; + cache->Free = 0; + cache->Used = 0; + cache->Max = 0; + + if (CacheList == NULL) { + CacheList = cache; + } else { + cache->Next = CacheList; + cache->Next->Prev = cache; + CacheList = cache; + CacheList->Prev = NULL; + } + + return cache; } static void ers_free_cache(ers_cache_t *cache, bool remove) { - unsigned int i; + unsigned int i; - for (i = 0; i < cache->Used; i++) - aFree(cache->Blocks[i]); + for (i = 0; i < cache->Used; i++) + aFree(cache->Blocks[i]); - if (cache->Next) - cache->Next->Prev = cache->Prev; + if (cache->Next) + cache->Next->Prev = cache->Prev; - if (cache->Prev) - cache->Prev->Next = cache->Next; - else - CacheList = cache->Next; + if (cache->Prev) + cache->Prev->Next = cache->Next; + else + CacheList = cache->Next; - aFree(cache->Blocks); - aFree(cache); + aFree(cache->Blocks); + aFree(cache); } static void *ers_obj_alloc_entry(ERS self) { - ers_instance_t *instance = (ers_instance_t *)self; - void *ret; - - if (instance == NULL) - { - ShowError("ers_obj_alloc_entry: NULL object, aborting entry freeing.\n"); - return NULL; - } - - if (instance->Cache->ReuseList != NULL) - { - ret = (void *)((unsigned char *)instance->Cache->ReuseList + sizeof(struct ers_list)); - instance->Cache->ReuseList = instance->Cache->ReuseList->Next; - } - else if (instance->Cache->Free > 0) - { - instance->Cache->Free--; - ret = &instance->Cache->Blocks[instance->Cache->Used - 1][instance->Cache->Free * instance->Cache->ObjectSize + sizeof(struct ers_list)]; - } - else - { - if (instance->Cache->Used == instance->Cache->Max) - { - instance->Cache->Max = (instance->Cache->Max * 4) + 3; - RECREATE(instance->Cache->Blocks, unsigned char *, instance->Cache->Max); - } - - CREATE(instance->Cache->Blocks[instance->Cache->Used], unsigned char, instance->Cache->ObjectSize * ERS_BLOCK_ENTRIES); - instance->Cache->Used++; - - instance->Cache->Free = ERS_BLOCK_ENTRIES -1; - ret = &instance->Cache->Blocks[instance->Cache->Used - 1][instance->Cache->Free * instance->Cache->ObjectSize + sizeof(struct ers_list)]; - } - - instance->Count++; - - return ret; + ers_instance_t *instance = (ers_instance_t *)self; + void *ret; + + if (instance == NULL) { + ShowError("ers_obj_alloc_entry: NULL object, aborting entry freeing.\n"); + return NULL; + } + + if (instance->Cache->ReuseList != NULL) { + ret = (void *)((unsigned char *)instance->Cache->ReuseList + sizeof(struct ers_list)); + instance->Cache->ReuseList = instance->Cache->ReuseList->Next; + } else if (instance->Cache->Free > 0) { + instance->Cache->Free--; + ret = &instance->Cache->Blocks[instance->Cache->Used - 1][instance->Cache->Free * instance->Cache->ObjectSize + sizeof(struct ers_list)]; + } else { + if (instance->Cache->Used == instance->Cache->Max) { + instance->Cache->Max = (instance->Cache->Max * 4) + 3; + RECREATE(instance->Cache->Blocks, unsigned char *, instance->Cache->Max); + } + + CREATE(instance->Cache->Blocks[instance->Cache->Used], unsigned char, instance->Cache->ObjectSize * ERS_BLOCK_ENTRIES); + instance->Cache->Used++; + + instance->Cache->Free = ERS_BLOCK_ENTRIES -1; + ret = &instance->Cache->Blocks[instance->Cache->Used - 1][instance->Cache->Free * instance->Cache->ObjectSize + sizeof(struct ers_list)]; + } + + instance->Count++; + + return ret; } static void ers_obj_free_entry(ERS self, void *entry) { - ers_instance_t *instance = (ers_instance_t *)self; - struct ers_list *reuse = (struct ers_list *)((unsigned char *)entry - sizeof(struct ers_list)); - - if (instance == NULL) - { - ShowError("ers_obj_free_entry: NULL object, aborting entry freeing.\n"); - return; - } - else if (entry == NULL) - { - ShowError("ers_obj_free_entry: NULL entry, nothing to free.\n"); - return; - } - - reuse->Next = instance->Cache->ReuseList; - instance->Cache->ReuseList = reuse; - instance->Count--; + ers_instance_t *instance = (ers_instance_t *)self; + struct ers_list *reuse = (struct ers_list *)((unsigned char *)entry - sizeof(struct ers_list)); + + if (instance == NULL) { + ShowError("ers_obj_free_entry: NULL object, aborting entry freeing.\n"); + return; + } else if (entry == NULL) { + ShowError("ers_obj_free_entry: NULL entry, nothing to free.\n"); + return; + } + + reuse->Next = instance->Cache->ReuseList; + instance->Cache->ReuseList = reuse; + instance->Count--; } static size_t ers_obj_entry_size(ERS self) { - ers_instance_t *instance = (ers_instance_t *)self; + ers_instance_t *instance = (ers_instance_t *)self; - if (instance == NULL) - { - ShowError("ers_obj_entry_size: NULL object, aborting entry freeing.\n"); - return 0; - } + if (instance == NULL) { + ShowError("ers_obj_entry_size: NULL object, aborting entry freeing.\n"); + return 0; + } - return instance->Cache->ObjectSize; + return instance->Cache->ObjectSize; } static void ers_obj_destroy(ERS self) { - ers_instance_t *instance = (ers_instance_t *)self; + ers_instance_t *instance = (ers_instance_t *)self; - if (instance == NULL) - { - ShowError("ers_obj_destroy: NULL object, aborting entry freeing.\n"); - return; - } + if (instance == NULL) { + ShowError("ers_obj_destroy: NULL object, aborting entry freeing.\n"); + return; + } - if (instance->Count > 0) - if (!(instance->Options & ERS_OPT_CLEAR)) - ShowWarning("Memory leak detected at ERS '%s', %d objects not freed.\n", instance->Name, instance->Count); + if (instance->Count > 0) + if (!(instance->Options & ERS_OPT_CLEAR)) + ShowWarning("Memory leak detected at ERS '%s', %d objects not freed.\n", instance->Name, instance->Count); - if (--instance->Cache->ReferenceCount <= 0) - ers_free_cache(instance->Cache, true); + if (--instance->Cache->ReferenceCount <= 0) + ers_free_cache(instance->Cache, true); - aFree(instance); + aFree(instance); } ERS ers_new(uint32 size, char *name, enum ERSOptions options) { - ers_instance_t *instance; - CREATE(instance, ers_instance_t, 1); + ers_instance_t *instance; + CREATE(instance, ers_instance_t, 1); - size += sizeof(struct ers_list); - if (size % ERS_ALIGNED) - size += ERS_ALIGNED - size % ERS_ALIGNED; + size += sizeof(struct ers_list); + if (size % ERS_ALIGNED) + size += ERS_ALIGNED - size % ERS_ALIGNED; - instance->VTable.alloc = ers_obj_alloc_entry; - instance->VTable.free = ers_obj_free_entry; - instance->VTable.entry_size = ers_obj_entry_size; - instance->VTable.destroy = ers_obj_destroy; + instance->VTable.alloc = ers_obj_alloc_entry; + instance->VTable.free = ers_obj_free_entry; + instance->VTable.entry_size = ers_obj_entry_size; + instance->VTable.destroy = ers_obj_destroy; - instance->Name = name; - instance->Options = options; + instance->Name = name; + instance->Options = options; - instance->Cache = ers_find_cache(size); - instance->Cache->ReferenceCount++; + instance->Cache = ers_find_cache(size); + instance->Cache->ReferenceCount++; - instance->Count = 0; + instance->Count = 0; - return &instance->VTable; + return &instance->VTable; } void ers_report(void) { - // FIXME: Someone use this? Is it really needed? + // FIXME: Someone use this? Is it really needed? } void ers_force_destroy_all(void) { - ers_cache_t *cache; - - for (cache = CacheList; cache; cache = cache->Next) - ers_free_cache(cache, false); + ers_cache_t *cache; + + for (cache = CacheList; cache; cache = cache->Next) + ers_free_cache(cache, false); } #endif diff --git a/src/common/ers.h b/src/common/ers.h index dc66af5ef..c8fe2b4af 100644 --- a/src/common/ers.h +++ b/src/common/ers.h @@ -55,7 +55,7 @@ /** * Define this to disable the Entry Reusage System. * All code except the typedef of ERInterface will be disabled. - * To allow a smooth transition, + * To allow a smooth transition, */ //#define DISABLE_ERS @@ -63,16 +63,16 @@ * Entries are aligned to ERS_ALIGNED bytes in the blocks of entries. * By default it aligns to one byte, using the "natural order" of the entries. * This should NEVER be set to zero or less. - * If greater than one, some memory can be wasted. This should never be needed + * If greater than one, some memory can be wasted. This should never be needed * but is here just in case some aligment issues arise. */ #ifndef ERS_ALIGNED -# define ERS_ALIGNED 1 +# define ERS_ALIGNED 1 #endif /* not ERS_ALIGN_ENTRY */ enum ERSOptions { - ERS_OPT_NONE = 0, - ERS_OPT_CLEAR = 1,/* silently clears any entries left in the manager upon destruction */ + ERS_OPT_NONE = 0, + ERS_OPT_CLEAR = 1,/* silently clears any entries left in the manager upon destruction */ }; /** @@ -84,65 +84,65 @@ enum ERSOptions { */ typedef struct eri { - /** - * Allocate an entry from this entry manager. - * If there are reusable entries available, it reuses one instead. - * @param self Interface of the entry manager - * @return An entry - */ - void *(*alloc)(struct eri *self); - - /** - * Free an entry allocated from this manager. - * WARNING: Does not check if the entry was allocated by this manager. - * Freeing such an entry can lead to unexpected behaviour. - * @param self Interface of the entry manager - * @param entry Entry to be freed - */ - void (*free)(struct eri *self, void *entry); - - /** - * Return the size of the entries allocated from this manager. - * @param self Interface of the entry manager - * @return Size of the entries of this manager in bytes - */ - size_t (*entry_size)(struct eri *self); - - /** - * Destroy this instance of the manager. - * The manager is actually only destroyed when all the instances are destroyed. - * When destroying the manager a warning is shown if the manager has - * missing/extra entries. - * @param self Interface of the entry manager - */ - void (*destroy)(struct eri *self); + /** + * Allocate an entry from this entry manager. + * If there are reusable entries available, it reuses one instead. + * @param self Interface of the entry manager + * @return An entry + */ + void *(*alloc)(struct eri *self); + + /** + * Free an entry allocated from this manager. + * WARNING: Does not check if the entry was allocated by this manager. + * Freeing such an entry can lead to unexpected behaviour. + * @param self Interface of the entry manager + * @param entry Entry to be freed + */ + void (*free)(struct eri *self, void *entry); + + /** + * Return the size of the entries allocated from this manager. + * @param self Interface of the entry manager + * @return Size of the entries of this manager in bytes + */ + size_t (*entry_size)(struct eri *self); + + /** + * Destroy this instance of the manager. + * The manager is actually only destroyed when all the instances are destroyed. + * When destroying the manager a warning is shown if the manager has + * missing/extra entries. + * @param self Interface of the entry manager + */ + void (*destroy)(struct eri *self); } *ERS; #ifdef DISABLE_ERS // Use memory manager to allocate/free and disable other interface functions -# define ers_alloc(obj,type) (type *)aMalloc(sizeof(type)) -# define ers_free(obj,entry) aFree(entry) -# define ers_entry_size(obj) (size_t)0 -# define ers_destroy(obj) +# define ers_alloc(obj,type) (type *)aMalloc(sizeof(type)) +# define ers_free(obj,entry) aFree(entry) +# define ers_entry_size(obj) (size_t)0 +# define ers_destroy(obj) // Disable the public functions -# define ers_new(size,name,options) NULL -# define ers_report() -# define ers_force_destroy_all() +# define ers_new(size,name,options) NULL +# define ers_report() +# define ers_force_destroy_all() #else /* not DISABLE_ERS */ -// These defines should be used to allow the code to keep working whenever +// These defines should be used to allow the code to keep working whenever // the system is disabled -# define ers_alloc(obj,type) (type *)(obj)->alloc(obj) -# define ers_free(obj,entry) (obj)->free((obj),(entry)) -# define ers_entry_size(obj) (obj)->entry_size(obj) -# define ers_destroy(obj) (obj)->destroy(obj) +# define ers_alloc(obj,type) (type *)(obj)->alloc(obj) +# define ers_free(obj,entry) (obj)->free((obj),(entry)) +# define ers_entry_size(obj) (obj)->entry_size(obj) +# define ers_destroy(obj) (obj)->destroy(obj) /** * Get a new instance of the manager that handles the specified entry size. * Size has to greater than 0. - * If the specified size is smaller than a pointer, the size of a pointer is + * If the specified size is smaller than a pointer, the size of a pointer is * used instead. - * It's also aligned to ERS_ALIGNED bytes, so the smallest multiple of + * It's also aligned to ERS_ALIGNED bytes, so the smallest multiple of * ERS_ALIGNED that is greater or equal to size is what's actually used. * @param The requested size of the entry in bytes * @return Interface of the object @@ -152,7 +152,7 @@ ERS ers_new(uint32 size, char *name, enum ERSOptions options); /** * Print a report about the current state of the Entry Reusage System. * Shows information about the global system and each entry manager. - * The number of entries are checked and a warning is shown if extra reusable + * The number of entries are checked and a warning is shown if extra reusable * entries are found. * The extra entries are included in the count of reusable entries. */ @@ -163,7 +163,7 @@ void ers_report(void); * The system is left as if no instances or entries had ever been allocated. * All previous entries and instances of the managers become invalid. * The use of this is NOT recommended. - * It should only be used in extreme situations to make shure all the memory + * It should only be used in extreme situations to make shure all the memory * allocated by this system is released. */ void ers_force_destroy_all(void); diff --git a/src/common/evdp.h b/src/common/evdp.h index bc3454686..c9cff9e2b 100644 --- a/src/common/evdp.h +++ b/src/common/evdp.h @@ -8,27 +8,27 @@ typedef struct EVDP_DATA EVDP_DATA; //#idef EVDP_EPOLL #include -struct EVDP_DATA{ - struct epoll_event ev_data; - bool ev_added; +struct EVDP_DATA { + struct epoll_event ev_data; + bool ev_added; }; //#endif -enum EVDP_EVENTFLAGS{ - EVDP_EVENT_IN = 1, // Incomming data - EVDP_EVENT_OUT = 2, // Connection accepts writing. - EVDP_EVENT_HUP = 4 // Connection Closed. +enum EVDP_EVENTFLAGS { + EVDP_EVENT_IN = 1, // Incomming data + EVDP_EVENT_OUT = 2, // Connection accepts writing. + EVDP_EVENT_HUP = 4 // Connection Closed. }; -typedef struct EVDP_EVENT{ - int32 events; // due to performance reasons, this should be the first member. - int32 fd; // Connection Identifier +typedef struct EVDP_EVENT { + int32 events; // due to performance reasons, this should be the first member. + int32 fd; // Connection Identifier } EVDP_EVENT; -/** +/** * Network Event Dispatcher Initialization / Finalization routines */ void evdp_init(); @@ -38,56 +38,56 @@ void evdp_final(); /** * Will Wait for events. * - * @param *out_ev pointer to array in size at least of max_events. - * @param max_events max no of events to report with this call (coalesc) - * @param timeout_ticks max time to wait in ticks (milliseconds) + * @param *out_ev pointer to array in size at least of max_events. + * @param max_events max no of events to report with this call (coalesc) + * @param timeout_ticks max time to wait in ticks (milliseconds) * * @Note: - * The function will block until an event has occured on one of the monitored connections - * or the timeout of timeout_ticks has passed by. - * Upon successfull call (changed connections) this function will write the connection - * Identifier & event to the out_fds array. + * The function will block until an event has occured on one of the monitored connections + * or the timeout of timeout_ticks has passed by. + * Upon successfull call (changed connections) this function will write the connection + * Identifier & event to the out_fds array. * - * @return 0 -> Timeout, > 0 no of changed connections. + * @return 0 -> Timeout, > 0 no of changed connections. */ -int32 evdp_wait(EVDP_EVENT *out_fds, int32 max_events, int32 timeout_ticks); +int32 evdp_wait(EVDP_EVENT *out_fds, int32 max_events, int32 timeout_ticks); -/** +/** * Applys the given mask on the given connection. - * - * @param fd connection identifier - * @param *ep event data pointer for the connection - * @param mask new event mask we're monitoring for. + * + * @param fd connection identifier + * @param *ep event data pointer for the connection + * @param mask new event mask we're monitoring for. */ -//void evdp_apply(int32 fd, EVDP_DATA *ep, int32 mask); +//void evdp_apply(int32 fd, EVDP_DATA *ep, int32 mask); -/** +/** * Adds a connection (listner) to the event notification system. * - * @param fd connection identifier - * @param *ep event data pointer for the connection + * @param fd connection identifier + * @param *ep event data pointer for the connection * - * @note: - * Listener type sockets are edge triggered, (see epoll manual for more information) + * @note: + * Listener type sockets are edge triggered, (see epoll manual for more information) * - This basicaly means that youll receive one event, adn you have to accept until accept returns an error (nothing to accept) * * MONITORS by default: IN - * + * * @return success indicator. - */ + */ bool evdp_addlistener(int32 fd, EVDP_DATA *ep); /** * Adds a connection (client connectioN) to the event notification system * - * @param fd connection identifier - * @param *ep event data pointr for the connection - * + * @param fd connection identifier + * @param *ep event data pointr for the connection + * * @note: - * - * MONITORS by default: IN, HUP + * + * MONITORS by default: IN, HUP * * @return success indicator. */ @@ -96,17 +96,17 @@ bool evdp_addclient(int32 fd, EVDP_DATA *ep); /** * Adds a connection (pending / outgoing connection!) to the event notification system. * - * @param fd connection identifier - * @param *ep event data pointer for the conneciton. + * @param fd connection identifier + * @param *ep event data pointer for the conneciton. * * @note: - * Outgoing connection type sockets are getting monitored for connection established - * successfull - * - if the connection has been established - we're generitng a writable notification .. (send) - * this is typical for BSD / posix conform network stacks. - * - Additinionally its edge triggered. + * Outgoing connection type sockets are getting monitored for connection established + * successfull + * - if the connection has been established - we're generitng a writable notification .. (send) + * this is typical for BSD / posix conform network stacks. + * - Additinionally its edge triggered. * - * @see evdp_outgoingconnection_established + * @see evdp_outgoingconnection_established * * * @return success indicator @@ -114,14 +114,14 @@ bool evdp_addclient(int32 fd, EVDP_DATA *ep); bool evdp_addconnecting(int32 fd, EVDP_DATA *ep); /** - * Adds an outgoing connection to the normal event notification system after it has been successfully established. - * - * @param fd connection identifier - * @param *ep event data pointer for the conneciton. - - * @note - * after this call, its handled like a normal "client" connection (incomming) - * + * Adds an outgoing connection to the normal event notification system after it has been successfully established. + * + * @param fd connection identifier + * @param *ep event data pointer for the conneciton. + + * @note + * after this call, its handled like a normal "client" connection (incomming) + * * @rturn success indicator */ bool evdp_outgoingconnection_established(int32 fd, EVDP_DATA *ep); @@ -129,24 +129,24 @@ bool evdp_outgoingconnection_established(int32 fd, EVDP_DATA *ep); /** * Marks a connection to be monitored for writable. * - * @param fd connection identifier - * @param *ep event data pointer for the connection + * @param fd connection identifier + * @param *ep event data pointer for the connection * * @note: - * the connection must be already added (as client or listener) - * + * the connection must be already added (as client or listener) + * * * @return sucess indicator */ bool evdp_writable_add(int32 fd, EVDP_DATA *ep); -/** +/** * Removes the connection from writable notification monitoring * - * @param fd connection identifier - * @param *ep event data pointr for the connection + * @param fd connection identifier + * @param *ep event data pointr for the connection * - */ + */ void evdp_writable_remove(int32 fd, EVDP_DATA *ep); /** @@ -157,11 +157,11 @@ void evdp_writable_remove(int32 fd, EVDP_DATA *ep); * * * @note: - * this will also clear the given EVENT_DATA block - * so the connection slot is in an "initial" blank status / ready to get reused. + * this will also clear the given EVENT_DATA block + * so the connection slot is in an "initial" blank status / ready to get reused. * */ -void evdp_remove(int32 fd, EVDP_DATA *ep); +void evdp_remove(int32 fd, EVDP_DATA *ep); diff --git a/src/common/evdp_epoll.c b/src/common/evdp_epoll.c index 0357dfc66..9f7c3d8ea 100644 --- a/src/common/evdp_epoll.c +++ b/src/common/evdp_epoll.c @@ -1,5 +1,5 @@ // -// Event Dispatcher Abstraction for EPOLL +// Event Dispatcher Abstraction for EPOLL // // Author: Florian Wilkemeyer // @@ -23,210 +23,220 @@ #include "../common/evdp.h" -#define EPOLL_MAX_PER_CYCLE 10 // Max Events to coalesc. per cycle. +#define EPOLL_MAX_PER_CYCLE 10 // Max Events to coalesc. per cycle. static int epoll_fd = -1; -void evdp_init(){ - - epoll_fd = epoll_create( EPOLL_MAX_PER_CYCLE ); - if(epoll_fd == -1){ - ShowFatalError("evdp [EPOLL]: Cannot create event dispatcher (errno: %u / %s)\n", errno, strerror(errno) ); - exit(1); - } - +void evdp_init() +{ + + epoll_fd = epoll_create(EPOLL_MAX_PER_CYCLE); + if (epoll_fd == -1) { + ShowFatalError("evdp [EPOLL]: Cannot create event dispatcher (errno: %u / %s)\n", errno, strerror(errno)); + exit(1); + } + }//end: evdp_init() -void evdp_final(){ - - if(epoll_fd != -1){ - close(epoll_fd); - epoll_fd = -1; - } - +void evdp_final() +{ + + if (epoll_fd != -1) { + close(epoll_fd); + epoll_fd = -1; + } + }//end: evdp_final() -int32 evdp_wait(EVDP_EVENT *out_fds, int32 max_events, int32 timeout_ticks){ - struct epoll_event l_events[EPOLL_MAX_PER_CYCLE]; - register struct epoll_event *ev; - register int nfds, n; - - if(max_events > EPOLL_MAX_PER_CYCLE) - max_events = EPOLL_MAX_PER_CYCLE; - - nfds = epoll_wait( epoll_fd, l_events, max_events, timeout_ticks); - if(nfds == -1){ - // @TODO: check if core is in shutdown mode. if - ignroe error. - - ShowFatalError("evdp [EPOLL]: epoll_wait returned bad / unexpected status (errno: %u / %s)\n", errno, strerror(errno)); - exit(1); //.. - } - - // Loop thru all events and copy it to the local ra evdp_event.. struct. - for(n = 0; n < nfds; n++){ - ev = &l_events[n]; - - out_fds->fd = ev->data.fd; - out_fds->events = 0; // clear - - if(ev->events & EPOLLHUP) - out_fds->events |= EVDP_EVENT_HUP; - - if(ev->events & EPOLLIN) - out_fds->events |= EVDP_EVENT_IN; - - if(ev->events & EPOLLOUT) - out_fds->events |= EVDP_EVENT_OUT; - - out_fds++; - } - - return nfds; // 0 on timeout or > 0 .. +int32 evdp_wait(EVDP_EVENT *out_fds, int32 max_events, int32 timeout_ticks) +{ + struct epoll_event l_events[EPOLL_MAX_PER_CYCLE]; + register struct epoll_event *ev; + register int nfds, n; + + if (max_events > EPOLL_MAX_PER_CYCLE) + max_events = EPOLL_MAX_PER_CYCLE; + + nfds = epoll_wait(epoll_fd, l_events, max_events, timeout_ticks); + if (nfds == -1) { + // @TODO: check if core is in shutdown mode. if - ignroe error. + + ShowFatalError("evdp [EPOLL]: epoll_wait returned bad / unexpected status (errno: %u / %s)\n", errno, strerror(errno)); + exit(1); //.. + } + + // Loop thru all events and copy it to the local ra evdp_event.. struct. + for (n = 0; n < nfds; n++) { + ev = &l_events[n]; + + out_fds->fd = ev->data.fd; + out_fds->events = 0; // clear + + if (ev->events & EPOLLHUP) + out_fds->events |= EVDP_EVENT_HUP; + + if (ev->events & EPOLLIN) + out_fds->events |= EVDP_EVENT_IN; + + if (ev->events & EPOLLOUT) + out_fds->events |= EVDP_EVENT_OUT; + + out_fds++; + } + + return nfds; // 0 on timeout or > 0 .. }//end: evdp_wait() -void evdp_remove(int32 fd, EVDP_DATA *ep){ - - if(ep->ev_added == true){ - - if( epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ep->ev_data) != 0){ - ShowError("evdp [EPOLL]: evdp_remove - epoll_ctl (EPOLL_CTL_DEL) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); - } - - ep->ev_data.events = 0; // clear struct. - ep->ev_data.data.fd = -1; // .. clear struct .. +void evdp_remove(int32 fd, EVDP_DATA *ep) +{ + + if (ep->ev_added == true) { + + if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ep->ev_data) != 0) { + ShowError("evdp [EPOLL]: evdp_remove - epoll_ctl (EPOLL_CTL_DEL) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); + } + + ep->ev_data.events = 0; // clear struct. + ep->ev_data.data.fd = -1; // .. clear struct .. + + ep->ev_added = false; // not added! + } - ep->ev_added = false; // not added! - } - }//end: evdp_remove() -bool evdp_addlistener(int32 fd, EVDP_DATA *ep){ - - ep->ev_data.events = EPOLLET|EPOLLIN; - ep->ev_data.data.fd = fd; - - // No check here for 'added ?' - // listeners cannot be added twice. - // - if( epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ep->ev_data) != 0 ){ - ShowError("evdp [EPOLL]: evdp_addlistener - epoll_ctl (EPOLL_CTL_ADD) faield! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); - ep->ev_data.events = 0; - ep->ev_data.data.fd = -1; - return false; - } - - ep->ev_added = true; - - return true; +bool evdp_addlistener(int32 fd, EVDP_DATA *ep) +{ + + ep->ev_data.events = EPOLLET|EPOLLIN; + ep->ev_data.data.fd = fd; + + // No check here for 'added ?' + // listeners cannot be added twice. + // + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ep->ev_data) != 0) { + ShowError("evdp [EPOLL]: evdp_addlistener - epoll_ctl (EPOLL_CTL_ADD) faield! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); + ep->ev_data.events = 0; + ep->ev_data.data.fd = -1; + return false; + } + + ep->ev_added = true; + + return true; }//end: evdp_addlistener() -bool evdp_addclient(int32 fd, EVDP_DATA *ep){ - - ep->ev_data.events = EPOLLIN | EPOLLHUP; - ep->ev_data.data.fd = fd; - - // No check for "added?" here, - // this function only gets called upon accpept. - // - - if( epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ep->ev_data) != 0){ - ShowError("evdp [EPOLL]: evdp_addclient - epoll_ctl (EPOLL_CTL_ADD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); - ep->ev_data.events = 0; - ep->ev_data.data.fd = -1; - return false; - } - - ep->ev_added = true; - - return true; +bool evdp_addclient(int32 fd, EVDP_DATA *ep) +{ + + ep->ev_data.events = EPOLLIN | EPOLLHUP; + ep->ev_data.data.fd = fd; + + // No check for "added?" here, + // this function only gets called upon accpept. + // + + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ep->ev_data) != 0) { + ShowError("evdp [EPOLL]: evdp_addclient - epoll_ctl (EPOLL_CTL_ADD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); + ep->ev_data.events = 0; + ep->ev_data.data.fd = -1; + return false; + } + + ep->ev_added = true; + + return true; }//end: evdp_addclient() -bool evdp_addconnecting(int32 fd, EVDP_DATA *ep){ - - ep->ev_data.events = EPOLLET | EPOLLOUT | EPOLLHUP; - ep->ev_data.data.fd = fd; - - if( epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ep->ev_data) != 0){ - ShowError("evdp [EPOLL]: evdp_addconnecting - epoll_ctl (EPOLL_CTL_ADD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); - ep->ev_data.events = 0; - ep->ev_data.data.fd = -1; - } - - ep->ev_added = true; - - return true; +bool evdp_addconnecting(int32 fd, EVDP_DATA *ep) +{ + + ep->ev_data.events = EPOLLET | EPOLLOUT | EPOLLHUP; + ep->ev_data.data.fd = fd; + + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ep->ev_data) != 0) { + ShowError("evdp [EPOLL]: evdp_addconnecting - epoll_ctl (EPOLL_CTL_ADD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); + ep->ev_data.events = 0; + ep->ev_data.data.fd = -1; + } + + ep->ev_added = true; + + return true; }//end: evdp_addconnecting() -bool evdp_outgoingconnection_established(int32 fd, EVDP_DATA *ep){ - int32 saved_mask; - - if(ep->ev_added != true){ - // ! - ShowError("evdp [EPOLL]: evdp_outgoingconnection_established fd #%u is not added to event dispatcher! invalid call.\n", fd); - return false; - } - - saved_mask = ep->ev_data.events; - - ep->ev_data.events = EPOLLIN | EPOLLHUP; - - if( epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ep->ev_data) != 0){ - ep->ev_data.events = saved_mask; // restore old mask. - ShowError("evdp [EPOLL]: evdp_outgoingconnection_established - epoll_ctl (EPOLL_CTL_MOD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); - return false; - } - - return true; +bool evdp_outgoingconnection_established(int32 fd, EVDP_DATA *ep) +{ + int32 saved_mask; + + if (ep->ev_added != true) { + // ! + ShowError("evdp [EPOLL]: evdp_outgoingconnection_established fd #%u is not added to event dispatcher! invalid call.\n", fd); + return false; + } + + saved_mask = ep->ev_data.events; + + ep->ev_data.events = EPOLLIN | EPOLLHUP; + + if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ep->ev_data) != 0) { + ep->ev_data.events = saved_mask; // restore old mask. + ShowError("evdp [EPOLL]: evdp_outgoingconnection_established - epoll_ctl (EPOLL_CTL_MOD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); + return false; + } + + return true; }//end: evdp_outgoingconnection_established() -bool evdp_writable_add(int32 fd, EVDP_DATA *ep){ - - if(ep->ev_added != true){ - ShowError("evdp [EPOLL]: evdp_writable_add - tried to add not added fd #%u\n",fd); - return false; - } - - if(! (ep->ev_data.events & EPOLLOUT) ){ // - - ep->ev_data.events |= EPOLLOUT; - if( epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ep->ev_data) != 0 ){ - ShowError("evdp [EPOLL]: evdp_writable_add - epoll_ctl (EPOLL_CTL_MOD) failed! fd #%u (errno: %u / %s)\n", fd, errno, strerror(errno)); - ep->ev_data.events &= ~EPOLLOUT; // remove from local flagmask due to failed syscall. - return false; - } - } - - return true; +bool evdp_writable_add(int32 fd, EVDP_DATA *ep) +{ + + if (ep->ev_added != true) { + ShowError("evdp [EPOLL]: evdp_writable_add - tried to add not added fd #%u\n",fd); + return false; + } + + if (!(ep->ev_data.events & EPOLLOUT)) { // + + ep->ev_data.events |= EPOLLOUT; + if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ep->ev_data) != 0) { + ShowError("evdp [EPOLL]: evdp_writable_add - epoll_ctl (EPOLL_CTL_MOD) failed! fd #%u (errno: %u / %s)\n", fd, errno, strerror(errno)); + ep->ev_data.events &= ~EPOLLOUT; // remove from local flagmask due to failed syscall. + return false; + } + } + + return true; }//end: evdp_writable_add() -void evdp_writable_remove(int32 fd, EVDP_DATA *ep){ - - if(ep->ev_added != true){ - ShowError("evdp [EPOLL]: evdp_writable_remove - tried to remove not added fd #%u\n", fd); - return; - } - - if( ep->ev_data.events & EPOLLOUT ){ - - ep->ev_data.events &= ~EPOLLOUT; - if( epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ep->ev_data) != 0){ - ShowError("evdp [EPOLL]: evdp_writable_remove - epoll_ctl (EPOLL_CTL_MOD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); - ep->ev_data.events |= EPOLLOUT; // add back to local flagmask because of failed syscall. - return; - } - } - - return; +void evdp_writable_remove(int32 fd, EVDP_DATA *ep) +{ + + if (ep->ev_added != true) { + ShowError("evdp [EPOLL]: evdp_writable_remove - tried to remove not added fd #%u\n", fd); + return; + } + + if (ep->ev_data.events & EPOLLOUT) { + + ep->ev_data.events &= ~EPOLLOUT; + if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ep->ev_data) != 0) { + ShowError("evdp [EPOLL]: evdp_writable_remove - epoll_ctl (EPOLL_CTL_MOD) failed! fd #%u (errno %u / %s)\n", fd, errno, strerror(errno)); + ep->ev_data.events |= EPOLLOUT; // add back to local flagmask because of failed syscall. + return; + } + } + + return; }//end: evdp_writable_remove() diff --git a/src/common/grfio.c b/src/common/grfio.c index 8f430cfb9..f86f9c1cb 100644 --- a/src/common/grfio.c +++ b/src/common/grfio.c @@ -16,18 +16,18 @@ #include //---------------------------- -// file entry table struct +// file entry table struct //---------------------------- typedef struct _FILELIST { - int srclen; // compressed size - int srclen_aligned; - int declen; // original size - int srcpos; // position of entry in grf - int next; // index of next filelist entry with same hash (-1: end of entry chain) - char type; - char fn[128-4*5]; // file name - char* fnd; // if the file was cloned, contains name of original file - char gentry; // read grf file select + int srclen; // compressed size + int srclen_aligned; + int declen; // original size + int srcpos; // position of entry in grf + int next; // index of next filelist entry with same hash (-1: end of entry chain) + char type; + char fn[128-4*5]; // file name + char *fnd; // if the file was cloned, contains name of original file + char gentry; // read grf file select } FILELIST; #define FILELIST_TYPE_FILE 0x01 // entry is a file @@ -45,34 +45,33 @@ typedef struct _FILELIST { // stores info about every loaded file -FILELIST* filelist = NULL; -int filelist_entrys = 0; -int filelist_maxentry = 0; +FILELIST *filelist = NULL; +int filelist_entrys = 0; +int filelist_maxentry = 0; // stores grf file names -char** gentry_table = NULL; -int gentry_entrys = 0; -int gentry_maxentry = 0; +char **gentry_table = NULL; +int gentry_entrys = 0; +int gentry_maxentry = 0; // the path to the data directory char data_dir[1024] = ""; // little endian char array to uint conversion -static unsigned int getlong(unsigned char* p) +static unsigned int getlong(unsigned char *p) { - return (p[0] << 0 | p[1] << 8 | p[2] << 16 | p[3] << 24); + return (p[0] << 0 | p[1] << 8 | p[2] << 16 | p[3] << 24); } -static void NibbleSwap(unsigned char* src, int len) +static void NibbleSwap(unsigned char *src, int len) { - while( len > 0 ) - { - *src = (*src >> 4) | (*src << 4); - ++src; - --len; - } + while (len > 0) { + *src = (*src >> 4) | (*src << 4); + ++src; + --len; + } } @@ -80,114 +79,142 @@ static void NibbleSwap(unsigned char* src, int len) /// NOTE: Operation is symmetric (calling it twice gives back the original input). static uint8_t grf_substitution(uint8_t in) { - uint8_t out; - - switch( in ) - { - case 0x00: out = 0x2B; break; - case 0x2B: out = 0x00; break; - case 0x6C: out = 0x80; break; - case 0x01: out = 0x68; break; - case 0x68: out = 0x01; break; - case 0x48: out = 0x77; break; - case 0x60: out = 0xFF; break; - case 0x77: out = 0x48; break; - case 0xB9: out = 0xC0; break; - case 0xC0: out = 0xB9; break; - case 0xFE: out = 0xEB; break; - case 0xEB: out = 0xFE; break; - case 0x80: out = 0x6C; break; - case 0xFF: out = 0x60; break; - default: out = in; break; - } - - return out; + uint8_t out; + + switch (in) { + case 0x00: + out = 0x2B; + break; + case 0x2B: + out = 0x00; + break; + case 0x6C: + out = 0x80; + break; + case 0x01: + out = 0x68; + break; + case 0x68: + out = 0x01; + break; + case 0x48: + out = 0x77; + break; + case 0x60: + out = 0xFF; + break; + case 0x77: + out = 0x48; + break; + case 0xB9: + out = 0xC0; + break; + case 0xC0: + out = 0xB9; + break; + case 0xFE: + out = 0xEB; + break; + case 0xEB: + out = 0xFE; + break; + case 0x80: + out = 0x6C; + break; + case 0xFF: + out = 0x60; + break; + default: + out = in; + break; + } + + return out; } /* this is not used anywhere, is it ok to delete? */ //static void grf_shuffle_enc(BIT64* src) { -// BIT64 out; +// BIT64 out; // -// out.b[0] = src->b[3]; -// out.b[1] = src->b[4]; -// out.b[2] = src->b[5]; -// out.b[3] = src->b[0]; -// out.b[4] = src->b[1]; -// out.b[5] = src->b[6]; -// out.b[6] = src->b[2]; -// out.b[7] = grf_substitution(src->b[7]); +// out.b[0] = src->b[3]; +// out.b[1] = src->b[4]; +// out.b[2] = src->b[5]; +// out.b[3] = src->b[0]; +// out.b[4] = src->b[1]; +// out.b[5] = src->b[6]; +// out.b[6] = src->b[2]; +// out.b[7] = grf_substitution(src->b[7]); // -// *src = out; +// *src = out; //} -static void grf_shuffle_dec(BIT64* src) +static void grf_shuffle_dec(BIT64 *src) { - BIT64 out; - - out.b[0] = src->b[3]; - out.b[1] = src->b[4]; - out.b[2] = src->b[6]; - out.b[3] = src->b[0]; - out.b[4] = src->b[1]; - out.b[5] = src->b[2]; - out.b[6] = src->b[5]; - out.b[7] = grf_substitution(src->b[7]); - - *src = out; + BIT64 out; + + out.b[0] = src->b[3]; + out.b[1] = src->b[4]; + out.b[2] = src->b[6]; + out.b[3] = src->b[0]; + out.b[4] = src->b[1]; + out.b[5] = src->b[2]; + out.b[6] = src->b[5]; + out.b[7] = grf_substitution(src->b[7]); + + *src = out; } -static void grf_decode_header(unsigned char* buf, size_t len) +static void grf_decode_header(unsigned char *buf, size_t len) { - BIT64* p = (BIT64*)buf; - size_t nblocks = len / sizeof(BIT64); - size_t i; + BIT64 *p = (BIT64 *)buf; + size_t nblocks = len / sizeof(BIT64); + size_t i; - // first 20 blocks are all des-encrypted - for( i = 0; i < 20 && i < nblocks; ++i ) - des_decrypt_block(&p[i]); + // first 20 blocks are all des-encrypted + for (i = 0; i < 20 && i < nblocks; ++i) + des_decrypt_block(&p[i]); - // the rest is plaintext, done. + // the rest is plaintext, done. } -static void grf_decode_full(unsigned char* buf, size_t len, int cycle) +static void grf_decode_full(unsigned char *buf, size_t len, int cycle) { - BIT64* p = (BIT64*)buf; - size_t nblocks = len / sizeof(BIT64); - int dcycle, scycle; - size_t i, j; - - // first 20 blocks are all des-encrypted - for( i = 0; i < 20 && i < nblocks; ++i ) - des_decrypt_block(&p[i]); - - // after that only one of every 'dcycle' blocks is des-encrypted - dcycle = cycle; - - // and one of every 'scycle' plaintext blocks is shuffled (starting from the 0th but skipping the 0th) - scycle = 7; - - // so decrypt/de-shuffle periodically - j = -1; // 0, adjusted to fit the ++j step - for( i = 20; i < nblocks; ++i ) - { - if( i % dcycle == 0 ) - {// decrypt block - des_decrypt_block(&p[i]); - continue; - } - - ++j; - if( j % scycle == 0 && j != 0 ) - {// de-shuffle block - grf_shuffle_dec(&p[i]); - continue; - } - - // plaintext, do nothing. - } + BIT64 *p = (BIT64 *)buf; + size_t nblocks = len / sizeof(BIT64); + int dcycle, scycle; + size_t i, j; + + // first 20 blocks are all des-encrypted + for (i = 0; i < 20 && i < nblocks; ++i) + des_decrypt_block(&p[i]); + + // after that only one of every 'dcycle' blocks is des-encrypted + dcycle = cycle; + + // and one of every 'scycle' plaintext blocks is shuffled (starting from the 0th but skipping the 0th) + scycle = 7; + + // so decrypt/de-shuffle periodically + j = -1; // 0, adjusted to fit the ++j step + for (i = 20; i < nblocks; ++i) { + if (i % dcycle == 0) { + // decrypt block + des_decrypt_block(&p[i]); + continue; + } + + ++j; + if (j % scycle == 0 && j != 0) { + // de-shuffle block + grf_shuffle_dec(&p[i]); + continue; + } + + // plaintext, do nothing. + } } @@ -196,38 +223,35 @@ static void grf_decode_full(unsigned char* buf, size_t len, int cycle) /// @param len length of the data /// @param entry_type flags associated with the data /// @param entry_len true (unaligned) length of the data -static void grf_decode(unsigned char* buf, size_t len, char entry_type, int entry_len) +static void grf_decode(unsigned char *buf, size_t len, char entry_type, int entry_len) { - if( entry_type & FILELIST_TYPE_ENCRYPT_MIXED ) - {// fully encrypted - int digits; - int cycle; - int i; - - // compute number of digits of the entry length - digits = 1; - for( i = 10; i <= entry_len; i *= 10 ) - ++digits; - - // choose size of gap between two encrypted blocks - // digits: 0 1 2 3 4 5 6 7 8 9 ... - // cycle: 1 1 1 4 5 14 15 22 23 24 ... - cycle = ( digits < 3 ) ? 1 - : ( digits < 5 ) ? digits + 1 - : ( digits < 7 ) ? digits + 9 - : digits + 15; - - grf_decode_full(buf, len, cycle); - } - else - if( entry_type & FILELIST_TYPE_ENCRYPT_HEADER ) - {// header encrypted - grf_decode_header(buf, len); - } - else - {// plaintext - ; - } + if (entry_type & FILELIST_TYPE_ENCRYPT_MIXED) { + // fully encrypted + int digits; + int cycle; + int i; + + // compute number of digits of the entry length + digits = 1; + for (i = 10; i <= entry_len; i *= 10) + ++digits; + + // choose size of gap between two encrypted blocks + // digits: 0 1 2 3 4 5 6 7 8 9 ... + // cycle: 1 1 1 4 5 14 15 22 23 24 ... + cycle = (digits < 3) ? 1 + : (digits < 5) ? digits + 1 + : (digits < 7) ? digits + 9 + : digits + 15; + + grf_decode_full(buf, len, cycle); + } else if (entry_type & FILELIST_TYPE_ENCRYPT_HEADER) { + // header encrypted + grf_decode_header(buf, len); + } else { + // plaintext + ; + } } @@ -236,23 +260,23 @@ static void grf_decode(unsigned char* buf, size_t len, char entry_type, int entr ******************************************************/ /// zlib crc32 -unsigned long grfio_crc32(const unsigned char* buf, unsigned int len) +unsigned long grfio_crc32(const unsigned char *buf, unsigned int len) { - return crc32(crc32(0L, Z_NULL, 0), buf, len); + return crc32(crc32(0L, Z_NULL, 0), buf, len); } /// zlib uncompress -int decode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen) +int decode_zip(void *dest, unsigned long *destLen, const void *source, unsigned long sourceLen) { - return uncompress((Bytef*)dest, destLen, (const Bytef*)source, sourceLen); + return uncompress((Bytef *)dest, destLen, (const Bytef *)source, sourceLen); } /// zlib compress -int encode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen) +int encode_zip(void *dest, unsigned long *destLen, const void *source, unsigned long sourceLen) { - return compress((Bytef*)dest, destLen, (const Bytef*)source, sourceLen); + return compress((Bytef *)dest, destLen, (const Bytef *)source, sourceLen); } @@ -265,94 +289,94 @@ int filelist_hash[256]; // initializes the table that holds the first elements of all hash chains static void hashinit(void) { - int i; - for (i = 0; i < 256; i++) - filelist_hash[i] = -1; + int i; + for (i = 0; i < 256; i++) + filelist_hash[i] = -1; } // hashes a filename string into a number from {0..255} -static int filehash(const char* fname) +static int filehash(const char *fname) { - unsigned int hash = 0; - while(*fname) { - hash = (hash<<1) + (hash>>7)*9 + TOLOWER(*fname); - fname++; - } - return hash & 255; + unsigned int hash = 0; + while (*fname) { + hash = (hash<<1) + (hash>>7)*9 + TOLOWER(*fname); + fname++; + } + return hash & 255; } // finds a FILELIST entry with the specified file name -static FILELIST* filelist_find(const char* fname) +static FILELIST *filelist_find(const char *fname) { - int hash, index; + int hash, index; - if (!filelist) - return NULL; + if (!filelist) + return NULL; - hash = filelist_hash[filehash(fname)]; - for (index = hash; index != -1; index = filelist[index].next) - if(!strcmpi(filelist[index].fn, fname)) - break; + hash = filelist_hash[filehash(fname)]; + for (index = hash; index != -1; index = filelist[index].next) + if (!strcmpi(filelist[index].fn, fname)) + break; - return (index >= 0) ? &filelist[index] : NULL; + return (index >= 0) ? &filelist[index] : NULL; } // returns the original file name -char* grfio_find_file(const char* fname) +char *grfio_find_file(const char *fname) { - FILELIST *filelist = filelist_find(fname); - if (!filelist) return NULL; - return (!filelist->fnd ? filelist->fn : filelist->fnd); + FILELIST *filelist = filelist_find(fname); + if (!filelist) return NULL; + return (!filelist->fnd ? filelist->fn : filelist->fnd); } // adds a FILELIST entry into the list of loaded files -static FILELIST* filelist_add(FILELIST* entry) +static FILELIST *filelist_add(FILELIST *entry) { - int hash; + int hash; - #define FILELIST_ADDS 1024 // number increment of file lists ` +#define FILELIST_ADDS 1024 // number increment of file lists ` - if (filelist_entrys >= filelist_maxentry) { - filelist = (FILELIST *)aRealloc(filelist, (filelist_maxentry + FILELIST_ADDS) * sizeof(FILELIST)); - memset(filelist + filelist_maxentry, '\0', FILELIST_ADDS * sizeof(FILELIST)); - filelist_maxentry += FILELIST_ADDS; - } + if (filelist_entrys >= filelist_maxentry) { + filelist = (FILELIST *)aRealloc(filelist, (filelist_maxentry + FILELIST_ADDS) * sizeof(FILELIST)); + memset(filelist + filelist_maxentry, '\0', FILELIST_ADDS * sizeof(FILELIST)); + filelist_maxentry += FILELIST_ADDS; + } - memcpy (&filelist[filelist_entrys], entry, sizeof(FILELIST)); + memcpy(&filelist[filelist_entrys], entry, sizeof(FILELIST)); - hash = filehash(entry->fn); - filelist[filelist_entrys].next = filelist_hash[hash]; - filelist_hash[hash] = filelist_entrys; + hash = filehash(entry->fn); + filelist[filelist_entrys].next = filelist_hash[hash]; + filelist_hash[hash] = filelist_entrys; - filelist_entrys++; + filelist_entrys++; - return &filelist[filelist_entrys - 1]; + return &filelist[filelist_entrys - 1]; } // adds a new FILELIST entry or overwrites an existing one -static FILELIST* filelist_modify(FILELIST* entry) +static FILELIST *filelist_modify(FILELIST *entry) { - FILELIST* fentry = filelist_find(entry->fn); - if (fentry != NULL) { - int tmp = fentry->next; - memcpy(fentry, entry, sizeof(FILELIST)); - fentry->next = tmp; - } else { - fentry = filelist_add(entry); - } - return fentry; + FILELIST *fentry = filelist_find(entry->fn); + if (fentry != NULL) { + int tmp = fentry->next; + memcpy(fentry, entry, sizeof(FILELIST)); + fentry->next = tmp; + } else { + fentry = filelist_add(entry); + } + return fentry; } // shrinks the file list array if too long static void filelist_compact(void) { - if (filelist == NULL) - return; + if (filelist == NULL) + return; - if (filelist_entrys < filelist_maxentry) { - filelist = (FILELIST *)aRealloc(filelist, filelist_entrys * sizeof(FILELIST)); - filelist_maxentry = filelist_entrys; - } + if (filelist_entrys < filelist_maxentry) { + filelist = (FILELIST *)aRealloc(filelist, filelist_entrys * sizeof(FILELIST)); + filelist_maxentry = filelist_entrys; + } } @@ -362,457 +386,448 @@ static void filelist_compact(void) /// Combines are resource path with the data folder location to create local resource path. -static void grfio_localpath_create(char* buffer, size_t size, const char* filename) +static void grfio_localpath_create(char *buffer, size_t size, const char *filename) { - unsigned int i; - size_t len; - - len = strlen(data_dir); - - if( data_dir[0] == '\0' || data_dir[len-1] == '/' || data_dir[len-1] == '\\' ) - { - safesnprintf(buffer, size, "%s%s", data_dir, filename); - } - else - { - safesnprintf(buffer, size, "%s/%s", data_dir, filename); - } - - // normalize path - for( i = 0; buffer[i] != '\0'; ++i ) - if( buffer[i] == '\\' ) - buffer[i] = '/'; + unsigned int i; + size_t len; + + len = strlen(data_dir); + + if (data_dir[0] == '\0' || data_dir[len-1] == '/' || data_dir[len-1] == '\\') { + safesnprintf(buffer, size, "%s%s", data_dir, filename); + } else { + safesnprintf(buffer, size, "%s/%s", data_dir, filename); + } + + // normalize path + for (i = 0; buffer[i] != '\0'; ++i) + if (buffer[i] == '\\') + buffer[i] = '/'; } /// Reads a file into a newly allocated buffer (from grf or data directory). -void* grfio_reads(const char* fname, int* size) +void *grfio_reads(const char *fname, int *size) { - unsigned char* buf2 = NULL; - - FILELIST* entry = filelist_find(fname); - if( entry == NULL || entry->gentry <= 0 ) {// LocalFileCheck - char lfname[256]; - int declen; - FILE* in; - grfio_localpath_create(lfname, sizeof(lfname), ( entry && entry->fnd ) ? entry->fnd : fname); - - in = fopen(lfname, "rb"); - if( in != NULL ) { - fseek(in,0,SEEK_END); - declen = ftell(in); - fseek(in,0,SEEK_SET); - buf2 = (unsigned char *)aMalloc(declen+1); // +1 for resnametable zero-termination - if(fread(buf2, 1, declen, in) != declen) ShowError("An error occured in fread grfio_reads, fname=%s \n",fname); - fclose(in); - - if( size ) - *size = declen; - } else { - if (entry != NULL && entry->gentry < 0) { - entry->gentry = -entry->gentry; // local file checked - } else { - ShowError("grfio_reads: %s not found (local file: %s)\n", fname, lfname); - return NULL; - } - } - } - - if( entry != NULL && entry->gentry > 0 ) {// Archive[GRF] File Read - char* grfname = gentry_table[entry->gentry - 1]; - FILE* in = fopen(grfname, "rb"); - if( in != NULL ) { - int fsize = entry->srclen_aligned; - unsigned char *buf = (unsigned char *)aMalloc(fsize); - fseek(in, entry->srcpos, 0); - if(fread(buf, 1, fsize, in) != fsize) ShowError("An error occured in fread in grfio_reads, grfname=%s\n",grfname); - fclose(in); - - buf2 = (unsigned char *)aMalloc(entry->declen+1); // +1 for resnametable zero-termination - if( entry->type & FILELIST_TYPE_FILE ) - {// file - uLongf len; - grf_decode(buf, fsize, entry->type, entry->srclen); - len = entry->declen; - decode_zip(buf2, &len, buf, entry->srclen); - if (len != (uLong)entry->declen) { - ShowError("decode_zip size mismatch err: %d != %d\n", (int)len, entry->declen); - aFree(buf); - aFree(buf2); - return NULL; - } - } else {// directory? - memcpy(buf2, buf, entry->declen); - } - - if( size ) - *size = entry->declen; - - aFree(buf); - } else { - ShowError("grfio_reads: %s not found (GRF file: %s)\n", fname, grfname); - return NULL; - } - } - - return buf2; + unsigned char *buf2 = NULL; + + FILELIST *entry = filelist_find(fname); + if (entry == NULL || entry->gentry <= 0) { // LocalFileCheck + char lfname[256]; + int declen; + FILE *in; + grfio_localpath_create(lfname, sizeof(lfname), (entry && entry->fnd) ? entry->fnd : fname); + + in = fopen(lfname, "rb"); + if (in != NULL) { + fseek(in,0,SEEK_END); + declen = ftell(in); + fseek(in,0,SEEK_SET); + buf2 = (unsigned char *)aMalloc(declen+1); // +1 for resnametable zero-termination + if (fread(buf2, 1, declen, in) != declen) ShowError("An error occured in fread grfio_reads, fname=%s \n",fname); + fclose(in); + + if (size) + *size = declen; + } else { + if (entry != NULL && entry->gentry < 0) { + entry->gentry = -entry->gentry; // local file checked + } else { + ShowError("grfio_reads: %s not found (local file: %s)\n", fname, lfname); + return NULL; + } + } + } + + if (entry != NULL && entry->gentry > 0) { // Archive[GRF] File Read + char *grfname = gentry_table[entry->gentry - 1]; + FILE *in = fopen(grfname, "rb"); + if (in != NULL) { + int fsize = entry->srclen_aligned; + unsigned char *buf = (unsigned char *)aMalloc(fsize); + fseek(in, entry->srcpos, 0); + if (fread(buf, 1, fsize, in) != fsize) ShowError("An error occured in fread in grfio_reads, grfname=%s\n",grfname); + fclose(in); + + buf2 = (unsigned char *)aMalloc(entry->declen+1); // +1 for resnametable zero-termination + if (entry->type & FILELIST_TYPE_FILE) { + // file + uLongf len; + grf_decode(buf, fsize, entry->type, entry->srclen); + len = entry->declen; + decode_zip(buf2, &len, buf, entry->srclen); + if (len != (uLong)entry->declen) { + ShowError("decode_zip size mismatch err: %d != %d\n", (int)len, entry->declen); + aFree(buf); + aFree(buf2); + return NULL; + } + } else {// directory? + memcpy(buf2, buf, entry->declen); + } + + if (size) + *size = entry->declen; + + aFree(buf); + } else { + ShowError("grfio_reads: %s not found (GRF file: %s)\n", fname, grfname); + return NULL; + } + } + + return buf2; } /// Decodes encrypted filename from a version 01xx grf index. -static char* decode_filename(unsigned char* buf, int len) +static char *decode_filename(unsigned char *buf, int len) { - int lop; - for(lop=0;lop> 8; - - if( grf_version == 0x01 ) {// ****** Grf version 01xx ****** - list_size = grf_size - ftell(fp); - grf_filelist = (unsigned char *) aMalloc(list_size); - if(fread(grf_filelist,1,list_size,fp) != list_size) { ShowError("Couldn't read all grf_filelist element of %s \n", grfname); } - fclose(fp); - - entrys = getlong(grf_header+0x26) - getlong(grf_header+0x22) - 7; - - // Get an entry - for( entry = 0, ofs = 0; entry < entrys; ++entry ) { - FILELIST aentry; - - int ofs2 = ofs+getlong(grf_filelist+ofs)+4; - unsigned char type = grf_filelist[ofs2+12]; - if( type & FILELIST_TYPE_FILE ) { - char* fname = decode_filename(grf_filelist+ofs+6, grf_filelist[ofs]-6); - int srclen = getlong(grf_filelist+ofs2+0) - getlong(grf_filelist+ofs2+8) - 715; - - if( strlen(fname) > sizeof(aentry.fn) - 1 ) { - ShowFatalError("GRF file name %s is too long\n", fname); - aFree(grf_filelist); - exit(EXIT_FAILURE); - } - - type |= ( isFullEncrypt(fname) ) ? FILELIST_TYPE_ENCRYPT_MIXED : FILELIST_TYPE_ENCRYPT_HEADER; - - aentry.srclen = srclen; - aentry.srclen_aligned = getlong(grf_filelist+ofs2+4)-37579; - aentry.declen = getlong(grf_filelist+ofs2+8); - aentry.srcpos = getlong(grf_filelist+ofs2+13)+0x2e; - aentry.type = type; - safestrncpy(aentry.fn, fname, sizeof(aentry.fn)); - aentry.fnd = NULL; -#ifdef GRFIO_LOCAL - aentry.gentry = -(gentry+1); // As Flag for making it a negative number carrying out the first time LocalFileCheck + long grf_size,list_size; + unsigned char grf_header[0x2e]; + int entry,entrys,ofs,grf_version; + unsigned char *grf_filelist; + + FILE *fp = fopen(grfname, "rb"); + if (fp == NULL) { + ShowWarning("GRF data file not found: '%s'\n",grfname); + return 1; // 1:not found error + } else + ShowInfo("GRF data file found: '%s'\n",grfname); + + fseek(fp,0,SEEK_END); + grf_size = ftell(fp); + fseek(fp,0,SEEK_SET); + + if (fread(grf_header,1,0x2e,fp) != 0x2e) { + ShowError("Couldn't read all grf_header element of %s \n", grfname); + } + if (strcmp((const char *)grf_header,"Master of Magic") != 0 || fseek(fp,getlong(grf_header+0x1e),SEEK_CUR) != 0) { + fclose(fp); + ShowError("GRF %s read error\n", grfname); + return 2; // 2:file format error + } + + grf_version = getlong(grf_header+0x2a) >> 8; + + if (grf_version == 0x01) { // ****** Grf version 01xx ****** + list_size = grf_size - ftell(fp); + grf_filelist = (unsigned char *) aMalloc(list_size); + if (fread(grf_filelist,1,list_size,fp) != list_size) { + ShowError("Couldn't read all grf_filelist element of %s \n", grfname); + } + fclose(fp); + + entrys = getlong(grf_header+0x26) - getlong(grf_header+0x22) - 7; + + // Get an entry + for (entry = 0, ofs = 0; entry < entrys; ++entry) { + FILELIST aentry; + + int ofs2 = ofs+getlong(grf_filelist+ofs)+4; + unsigned char type = grf_filelist[ofs2+12]; + if (type & FILELIST_TYPE_FILE) { + char *fname = decode_filename(grf_filelist+ofs+6, grf_filelist[ofs]-6); + int srclen = getlong(grf_filelist+ofs2+0) - getlong(grf_filelist+ofs2+8) - 715; + + if (strlen(fname) > sizeof(aentry.fn) - 1) { + ShowFatalError("GRF file name %s is too long\n", fname); + aFree(grf_filelist); + exit(EXIT_FAILURE); + } + + type |= (isFullEncrypt(fname)) ? FILELIST_TYPE_ENCRYPT_MIXED : FILELIST_TYPE_ENCRYPT_HEADER; + + aentry.srclen = srclen; + aentry.srclen_aligned = getlong(grf_filelist+ofs2+4)-37579; + aentry.declen = getlong(grf_filelist+ofs2+8); + aentry.srcpos = getlong(grf_filelist+ofs2+13)+0x2e; + aentry.type = type; + safestrncpy(aentry.fn, fname, sizeof(aentry.fn)); + aentry.fnd = NULL; +#ifdef GRFIO_LOCAL + aentry.gentry = -(gentry+1); // As Flag for making it a negative number carrying out the first time LocalFileCheck #else - aentry.gentry = gentry+1; // With no first time LocalFileCheck + aentry.gentry = gentry+1; // With no first time LocalFileCheck #endif - filelist_modify(&aentry); - } - - ofs = ofs2 + 17; - } - - aFree(grf_filelist); - } else if( grf_version == 0x02 ) {// ****** Grf version 02xx ****** - unsigned char eheader[8]; - unsigned char *rBuf; - uLongf rSize, eSize; - - if(fread(eheader,1,8,fp) != 8) ShowError("An error occured in fread while reading eheader buffer\n"); - rSize = getlong(eheader); // Read Size - eSize = getlong(eheader+4); // Extend Size - - if( (long)rSize > grf_size-ftell(fp) ) { - fclose(fp); - ShowError("Illegal data format: GRF compress entry size\n"); - return 4; - } - - rBuf = (unsigned char *)aMalloc(rSize); // Get a Read Size - grf_filelist = (unsigned char *)aMalloc(eSize); // Get a Extend Size - if(fread(rBuf,1,rSize,fp) != rSize) ShowError("An error occured in fread \n"); - fclose(fp); - decode_zip(grf_filelist, &eSize, rBuf, rSize); // Decode function - aFree(rBuf); - - entrys = getlong(grf_header+0x26) - 7; - - // Get an entry - for( entry = 0, ofs = 0; entry < entrys; ++entry ) { - FILELIST aentry; - - char* fname = (char*)(grf_filelist+ofs); - int ofs2 = ofs + (int)strlen(fname)+1; - int type = grf_filelist[ofs2+12]; - - if( strlen(fname) > sizeof(aentry.fn)-1 ) { - ShowFatalError("GRF file name %s is too long\n", fname); - aFree(grf_filelist); - exit(EXIT_FAILURE); - } - - if( type & FILELIST_TYPE_FILE ) {// file - aentry.srclen = getlong(grf_filelist+ofs2+0); - aentry.srclen_aligned = getlong(grf_filelist+ofs2+4); - aentry.declen = getlong(grf_filelist+ofs2+8); - aentry.srcpos = getlong(grf_filelist+ofs2+13)+0x2e; - aentry.type = type; - safestrncpy(aentry.fn, fname, sizeof(aentry.fn)); - aentry.fnd = NULL; -#ifdef GRFIO_LOCAL - aentry.gentry = -(gentry+1); // As Flag for making it a negative number carrying out the first time LocalFileCheck + filelist_modify(&aentry); + } + + ofs = ofs2 + 17; + } + + aFree(grf_filelist); + } else if (grf_version == 0x02) { // ****** Grf version 02xx ****** + unsigned char eheader[8]; + unsigned char *rBuf; + uLongf rSize, eSize; + + if (fread(eheader,1,8,fp) != 8) ShowError("An error occured in fread while reading eheader buffer\n"); + rSize = getlong(eheader); // Read Size + eSize = getlong(eheader+4); // Extend Size + + if ((long)rSize > grf_size-ftell(fp)) { + fclose(fp); + ShowError("Illegal data format: GRF compress entry size\n"); + return 4; + } + + rBuf = (unsigned char *)aMalloc(rSize); // Get a Read Size + grf_filelist = (unsigned char *)aMalloc(eSize); // Get a Extend Size + if (fread(rBuf,1,rSize,fp) != rSize) ShowError("An error occured in fread \n"); + fclose(fp); + decode_zip(grf_filelist, &eSize, rBuf, rSize); // Decode function + aFree(rBuf); + + entrys = getlong(grf_header+0x26) - 7; + + // Get an entry + for (entry = 0, ofs = 0; entry < entrys; ++entry) { + FILELIST aentry; + + char *fname = (char *)(grf_filelist+ofs); + int ofs2 = ofs + (int)strlen(fname)+1; + int type = grf_filelist[ofs2+12]; + + if (strlen(fname) > sizeof(aentry.fn)-1) { + ShowFatalError("GRF file name %s is too long\n", fname); + aFree(grf_filelist); + exit(EXIT_FAILURE); + } + + if (type & FILELIST_TYPE_FILE) { // file + aentry.srclen = getlong(grf_filelist+ofs2+0); + aentry.srclen_aligned = getlong(grf_filelist+ofs2+4); + aentry.declen = getlong(grf_filelist+ofs2+8); + aentry.srcpos = getlong(grf_filelist+ofs2+13)+0x2e; + aentry.type = type; + safestrncpy(aentry.fn, fname, sizeof(aentry.fn)); + aentry.fnd = NULL; +#ifdef GRFIO_LOCAL + aentry.gentry = -(gentry+1); // As Flag for making it a negative number carrying out the first time LocalFileCheck #else - aentry.gentry = gentry+1; // With no first time LocalFileCheck + aentry.gentry = gentry+1; // With no first time LocalFileCheck #endif - filelist_modify(&aentry); - } + filelist_modify(&aentry); + } - ofs = ofs2 + 17; - } + ofs = ofs2 + 17; + } - aFree(grf_filelist); - } else {// ****** Grf Other version ****** - fclose(fp); - ShowError("GRF version %04x not supported\n",getlong(grf_header+0x2a)); - return 4; - } + aFree(grf_filelist); + } else {// ****** Grf Other version ****** + fclose(fp); + ShowError("GRF version %04x not supported\n",getlong(grf_header+0x2a)); + return 4; + } - filelist_compact(); // Unnecessary area release of filelist + filelist_compact(); // Unnecessary area release of filelist - return 0; // 0:no error + return 0; // 0:no error } -static bool grfio_parse_restable_row(const char* row) +static bool grfio_parse_restable_row(const char *row) { - char w1[256], w2[256]; - char src[256], dst[256]; - char local[256]; - FILELIST* entry; - - if( sscanf(row, "%[^#\r\n]#%[^#\r\n]#", w1, w2) != 2 ) - return false; - - if( strstr(w2, ".gat") == NULL && strstr(w2, ".rsw") == NULL ) - return false; // we only need the maps' GAT and RSW files - - sprintf(src, "data\\%s", w1); - sprintf(dst, "data\\%s", w2); - - entry = filelist_find(dst); - if( entry != NULL ) - {// alias for GRF resource - FILELIST fentry; - memcpy(&fentry, entry, sizeof(FILELIST)); - safestrncpy(fentry.fn, src, sizeof(fentry.fn)); - fentry.fnd = aStrdup(dst); - filelist_modify(&fentry); - return true; - } - - grfio_localpath_create(local, sizeof(local), dst); - if( exists(local) ) - {// alias for local resource - FILELIST fentry; - memset(&fentry, 0, sizeof(fentry)); - safestrncpy(fentry.fn, src, sizeof(fentry.fn)); - fentry.fnd = aStrdup(dst); - filelist_modify(&fentry); - return true; - } - - return false; + char w1[256], w2[256]; + char src[256], dst[256]; + char local[256]; + FILELIST *entry; + + if (sscanf(row, "%[^#\r\n]#%[^#\r\n]#", w1, w2) != 2) + return false; + + if (strstr(w2, ".gat") == NULL && strstr(w2, ".rsw") == NULL) + return false; // we only need the maps' GAT and RSW files + + sprintf(src, "data\\%s", w1); + sprintf(dst, "data\\%s", w2); + + entry = filelist_find(dst); + if (entry != NULL) { + // alias for GRF resource + FILELIST fentry; + memcpy(&fentry, entry, sizeof(FILELIST)); + safestrncpy(fentry.fn, src, sizeof(fentry.fn)); + fentry.fnd = aStrdup(dst); + filelist_modify(&fentry); + return true; + } + + grfio_localpath_create(local, sizeof(local), dst); + if (exists(local)) { + // alias for local resource + FILELIST fentry; + memset(&fentry, 0, sizeof(fentry)); + safestrncpy(fentry.fn, src, sizeof(fentry.fn)); + fentry.fnd = aStrdup(dst); + filelist_modify(&fentry); + return true; + } + + return false; } /// Grfio Resource file check. static void grfio_resourcecheck(void) { - char restable[256]; - char *ptr, *buf; - int size; - FILE* fp; - int i = 0; - - // read resnametable from data directory and return if successful - grfio_localpath_create(restable, sizeof(restable), "data\\resnametable.txt"); - - fp = fopen(restable, "rb"); - if( fp != NULL ) - { - char line[256]; - while( fgets(line, sizeof(line), fp) ) - { - if( grfio_parse_restable_row(line) ) - ++i; - } - - fclose(fp); - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, "resnametable.txt"); - return; // we're done here! - } - - // read resnametable from loaded GRF's, only if it cannot be loaded from the data directory - buf = (char *)grfio_reads("data\\resnametable.txt", &size); - if( buf != NULL ) - { - buf[size] = '\0'; - - ptr = buf; - while( ptr - buf < size ) - { - if( grfio_parse_restable_row(ptr) ) - ++i; - - ptr = strchr(ptr, '\n'); - if( ptr == NULL ) break; - ptr++; - } - - aFree(buf); - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, "data\\resnametable.txt"); - return; - } + char restable[256]; + char *ptr, *buf; + int size; + FILE *fp; + int i = 0; + + // read resnametable from data directory and return if successful + grfio_localpath_create(restable, sizeof(restable), "data\\resnametable.txt"); + + fp = fopen(restable, "rb"); + if (fp != NULL) { + char line[256]; + while (fgets(line, sizeof(line), fp)) { + if (grfio_parse_restable_row(line)) + ++i; + } + + fclose(fp); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, "resnametable.txt"); + return; // we're done here! + } + + // read resnametable from loaded GRF's, only if it cannot be loaded from the data directory + buf = (char *)grfio_reads("data\\resnametable.txt", &size); + if (buf != NULL) { + buf[size] = '\0'; + + ptr = buf; + while (ptr - buf < size) { + if (grfio_parse_restable_row(ptr)) + ++i; + + ptr = strchr(ptr, '\n'); + if (ptr == NULL) break; + ptr++; + } + + aFree(buf); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, "data\\resnametable.txt"); + return; + } } /// Reads a grf file and adds it to the list. -static int grfio_add(const char* fname) +static int grfio_add(const char *fname) { - if( gentry_entrys >= gentry_maxentry ) - { - #define GENTRY_ADDS 4 // The number increment of gentry_table entries - gentry_maxentry += GENTRY_ADDS; - gentry_table = (char**)aRealloc(gentry_table, gentry_maxentry * sizeof(char*)); - memset(gentry_table + (gentry_maxentry - GENTRY_ADDS), 0, sizeof(char*) * GENTRY_ADDS); - } + if (gentry_entrys >= gentry_maxentry) { +#define GENTRY_ADDS 4 // The number increment of gentry_table entries + gentry_maxentry += GENTRY_ADDS; + gentry_table = (char **)aRealloc(gentry_table, gentry_maxentry * sizeof(char *)); + memset(gentry_table + (gentry_maxentry - GENTRY_ADDS), 0, sizeof(char *) * GENTRY_ADDS); + } - gentry_table[gentry_entrys++] = aStrdup(fname); + gentry_table[gentry_entrys++] = aStrdup(fname); - return grfio_entryread(fname, gentry_entrys - 1); + return grfio_entryread(fname, gentry_entrys - 1); } /// Finalizes grfio. void grfio_final(void) { - if (filelist != NULL) { - int i; - for (i = 0; i < filelist_entrys; i++) - if (filelist[i].fnd != NULL) - aFree(filelist[i].fnd); - - aFree(filelist); - filelist = NULL; - } - filelist_entrys = filelist_maxentry = 0; - - if (gentry_table != NULL) { - int i; - for (i = 0; i < gentry_entrys; i++) - if (gentry_table[i] != NULL) - aFree(gentry_table[i]); - - aFree(gentry_table); - gentry_table = NULL; - } - gentry_entrys = gentry_maxentry = 0; + if (filelist != NULL) { + int i; + for (i = 0; i < filelist_entrys; i++) + if (filelist[i].fnd != NULL) + aFree(filelist[i].fnd); + + aFree(filelist); + filelist = NULL; + } + filelist_entrys = filelist_maxentry = 0; + + if (gentry_table != NULL) { + int i; + for (i = 0; i < gentry_entrys; i++) + if (gentry_table[i] != NULL) + aFree(gentry_table[i]); + + aFree(gentry_table); + gentry_table = NULL; + } + gentry_entrys = gentry_maxentry = 0; } /// Initializes grfio. -void grfio_init(const char* fname) +void grfio_init(const char *fname) { - FILE* data_conf; - int grf_num = 0; - - hashinit(); // hash table initialization - - data_conf = fopen(fname, "r"); - if( data_conf != NULL ) - { - char line[1024]; - while( fgets(line, sizeof(line), data_conf) ) - { - char w1[1024], w2[1024]; - - if( line[0] == '/' && line[1] == '/' ) - continue; // skip comments - - if( sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2 ) - continue; // skip unrecognized lines - - // Entry table reading - if( strcmp(w1, "grf") == 0 ) // GRF file - { - if( grfio_add(w2) == 0 ) - ++grf_num; - } - else if( strcmp(w1,"data_dir") == 0 ) // Data directory - { - safestrncpy(data_dir, w2, sizeof(data_dir)); - } - } - - fclose(data_conf); - ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n", fname); - } - - if( grf_num == 0 ) - ShowInfo("No GRF loaded, using default data directory\n"); - - // Unneccessary area release of filelist - filelist_compact(); - - // Resource check - grfio_resourcecheck(); + FILE *data_conf; + int grf_num = 0; + + hashinit(); // hash table initialization + + data_conf = fopen(fname, "r"); + if (data_conf != NULL) { + char line[1024]; + while (fgets(line, sizeof(line), data_conf)) { + char w1[1024], w2[1024]; + + if (line[0] == '/' && line[1] == '/') + continue; // skip comments + + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; // skip unrecognized lines + + // Entry table reading + if (strcmp(w1, "grf") == 0) { // GRF file + if (grfio_add(w2) == 0) + ++grf_num; + } else if (strcmp(w1,"data_dir") == 0) { // Data directory + safestrncpy(data_dir, w2, sizeof(data_dir)); + } + } + + fclose(data_conf); + ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n", fname); + } + + if (grf_num == 0) + ShowInfo("No GRF loaded, using default data directory\n"); + + // Unneccessary area release of filelist + filelist_compact(); + + // Resource check + grfio_resourcecheck(); } diff --git a/src/common/grfio.h b/src/common/grfio.h index c5a56a14e..ae2fbd67c 100644 --- a/src/common/grfio.h +++ b/src/common/grfio.h @@ -1,17 +1,17 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _GRFIO_H_ -#define _GRFIO_H_ +#ifndef _GRFIO_H_ +#define _GRFIO_H_ -void grfio_init(const char* fname); +void grfio_init(const char *fname); void grfio_final(void); -void* grfio_reads(const char* fname, int* size); -char* grfio_find_file(const char* fname); +void *grfio_reads(const char *fname, int *size); +char *grfio_find_file(const char *fname); #define grfio_read(fn) grfio_reads(fn, NULL) unsigned long grfio_crc32(const unsigned char *buf, unsigned int len); -int decode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen); -int encode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen); +int decode_zip(void *dest, unsigned long *destLen, const void *source, unsigned long sourceLen); +int encode_zip(void *dest, unsigned long *destLen, const void *source, unsigned long sourceLen); #endif /* _GRFIO_H_ */ diff --git a/src/common/malloc.c b/src/common/malloc.c index 9976a28d5..396ec33cb 100644 --- a/src/common/malloc.c +++ b/src/common/malloc.c @@ -14,109 +14,109 @@ #if defined(MEMWATCH) -# include -# include "memwatch.h" -# define MALLOC(n,file,line,func) mwMalloc((n),(file),(line)) -# define CALLOC(m,n,file,line,func) mwCalloc((m),(n),(file),(line)) -# define REALLOC(p,n,file,line,func) mwRealloc((p),(n),(file),(line)) -# define STRDUP(p,file,line,func) mwStrdup((p),(file),(line)) -# define FREE(p,file,line,func) mwFree((p),(file),(line)) -# define MEMORY_USAGE() 0 -# define MEMORY_VERIFY(ptr) mwIsSafeAddr(ptr, 1) -# define MEMORY_CHECK() CHECK() +# include +# include "memwatch.h" +# define MALLOC(n,file,line,func) mwMalloc((n),(file),(line)) +# define CALLOC(m,n,file,line,func) mwCalloc((m),(n),(file),(line)) +# define REALLOC(p,n,file,line,func) mwRealloc((p),(n),(file),(line)) +# define STRDUP(p,file,line,func) mwStrdup((p),(file),(line)) +# define FREE(p,file,line,func) mwFree((p),(file),(line)) +# define MEMORY_USAGE() 0 +# define MEMORY_VERIFY(ptr) mwIsSafeAddr(ptr, 1) +# define MEMORY_CHECK() CHECK() #elif defined(DMALLOC) -# include -# include -# include "dmalloc.h" -# define MALLOC(n,file,line,func) dmalloc_malloc((file),(line),(n),DMALLOC_FUNC_MALLOC,0,0) -# define CALLOC(m,n,file,line,func) dmalloc_malloc((file),(line),(m)*(n),DMALLOC_FUNC_CALLOC,0,0) -# define REALLOC(p,n,file,line,func) dmalloc_realloc((file),(line),(p),(n),DMALLOC_FUNC_REALLOC,0) -# define STRDUP(p,file,line,func) strdup(p) -# define FREE(p,file,line,func) free(p) -# define MEMORY_USAGE() dmalloc_memory_allocated() -# define MEMORY_VERIFY(ptr) (dmalloc_verify(ptr) == DMALLOC_VERIFY_NOERROR) -# define MEMORY_CHECK() dmalloc_log_stats(); dmalloc_log_unfreed() +# include +# include +# include "dmalloc.h" +# define MALLOC(n,file,line,func) dmalloc_malloc((file),(line),(n),DMALLOC_FUNC_MALLOC,0,0) +# define CALLOC(m,n,file,line,func) dmalloc_malloc((file),(line),(m)*(n),DMALLOC_FUNC_CALLOC,0,0) +# define REALLOC(p,n,file,line,func) dmalloc_realloc((file),(line),(p),(n),DMALLOC_FUNC_REALLOC,0) +# define STRDUP(p,file,line,func) strdup(p) +# define FREE(p,file,line,func) free(p) +# define MEMORY_USAGE() dmalloc_memory_allocated() +# define MEMORY_VERIFY(ptr) (dmalloc_verify(ptr) == DMALLOC_VERIFY_NOERROR) +# define MEMORY_CHECK() dmalloc_log_stats(); dmalloc_log_unfreed() #elif defined(GCOLLECT) -# include "gc.h" -# ifdef GC_ADD_CALLER -# define RETURN_ADDR 0, -# else -# define RETURN_ADDR -# endif -# define MALLOC(n,file,line,func) GC_debug_malloc((n), RETURN_ADDR (file),(line)) -# define CALLOC(m,n,file,line,func) GC_debug_malloc((m)*(n), RETURN_ADDR (file),(line)) -# define REALLOC(p,n,file,line,func) GC_debug_realloc((p),(n), RETURN_ADDR (file),(line)) -# define STRDUP(p,file,line,func) GC_debug_strdup((p), RETURN_ADDR (file),(line)) -# define FREE(p,file,line,func) GC_debug_free(p) -# define MEMORY_USAGE() GC_get_heap_size() -# define MEMORY_VERIFY(ptr) (GC_base(ptr) != NULL) -# define MEMORY_CHECK() GC_gcollect() +# include "gc.h" +# ifdef GC_ADD_CALLER +# define RETURN_ADDR 0, +# else +# define RETURN_ADDR +# endif +# define MALLOC(n,file,line,func) GC_debug_malloc((n), RETURN_ADDR (file),(line)) +# define CALLOC(m,n,file,line,func) GC_debug_malloc((m)*(n), RETURN_ADDR (file),(line)) +# define REALLOC(p,n,file,line,func) GC_debug_realloc((p),(n), RETURN_ADDR (file),(line)) +# define STRDUP(p,file,line,func) GC_debug_strdup((p), RETURN_ADDR (file),(line)) +# define FREE(p,file,line,func) GC_debug_free(p) +# define MEMORY_USAGE() GC_get_heap_size() +# define MEMORY_VERIFY(ptr) (GC_base(ptr) != NULL) +# define MEMORY_CHECK() GC_gcollect() #else -# define MALLOC(n,file,line,func) malloc(n) -# define CALLOC(m,n,file,line,func) calloc((m),(n)) -# define REALLOC(p,n,file,line,func) realloc((p),(n)) -# define STRDUP(p,file,line,func) strdup(p) -# define FREE(p,file,line,func) free(p) -# define MEMORY_USAGE() 0 -# define MEMORY_VERIFY(ptr) true -# define MEMORY_CHECK() +# define MALLOC(n,file,line,func) malloc(n) +# define CALLOC(m,n,file,line,func) calloc((m),(n)) +# define REALLOC(p,n,file,line,func) realloc((p),(n)) +# define STRDUP(p,file,line,func) strdup(p) +# define FREE(p,file,line,func) free(p) +# define MEMORY_USAGE() 0 +# define MEMORY_VERIFY(ptr) true +# define MEMORY_CHECK() #endif -void* aMalloc_(size_t size, const char *file, int line, const char *func) +void *aMalloc_(size_t size, const char *file, int line, const char *func) { - void *ret = MALLOC(size, file, line, func); - // ShowMessage("%s:%d: in func %s: aMalloc %d\n",file,line,func,size); - if (ret == NULL){ - ShowFatalError("%s:%d: in func %s: aMalloc error out of memory!\n",file,line,func); - exit(EXIT_FAILURE); - } - - return ret; + void *ret = MALLOC(size, file, line, func); + // ShowMessage("%s:%d: in func %s: aMalloc %d\n",file,line,func,size); + if (ret == NULL) { + ShowFatalError("%s:%d: in func %s: aMalloc error out of memory!\n",file,line,func); + exit(EXIT_FAILURE); + } + + return ret; } -void* aCalloc_(size_t num, size_t size, const char *file, int line, const char *func) +void *aCalloc_(size_t num, size_t size, const char *file, int line, const char *func) { - void *ret = CALLOC(num, size, file, line, func); - // ShowMessage("%s:%d: in func %s: aCalloc %d %d\n",file,line,func,num,size); - if (ret == NULL){ - ShowFatalError("%s:%d: in func %s: aCalloc error out of memory!\n", file, line, func); - exit(EXIT_FAILURE); - } - return ret; + void *ret = CALLOC(num, size, file, line, func); + // ShowMessage("%s:%d: in func %s: aCalloc %d %d\n",file,line,func,num,size); + if (ret == NULL) { + ShowFatalError("%s:%d: in func %s: aCalloc error out of memory!\n", file, line, func); + exit(EXIT_FAILURE); + } + return ret; } -void* aRealloc_(void *p, size_t size, const char *file, int line, const char *func) +void *aRealloc_(void *p, size_t size, const char *file, int line, const char *func) { - void *ret = REALLOC(p, size, file, line, func); - // ShowMessage("%s:%d: in func %s: aRealloc %p %d\n",file,line,func,p,size); - if (ret == NULL){ - ShowFatalError("%s:%d: in func %s: aRealloc error out of memory!\n",file,line,func); - exit(EXIT_FAILURE); - } - return ret; + void *ret = REALLOC(p, size, file, line, func); + // ShowMessage("%s:%d: in func %s: aRealloc %p %d\n",file,line,func,p,size); + if (ret == NULL) { + ShowFatalError("%s:%d: in func %s: aRealloc error out of memory!\n",file,line,func); + exit(EXIT_FAILURE); + } + return ret; } -char* aStrdup_(const char *p, const char *file, int line, const char *func) +char *aStrdup_(const char *p, const char *file, int line, const char *func) { - char *ret = STRDUP(p, file, line, func); - // ShowMessage("%s:%d: in func %s: aStrdup %p\n",file,line,func,p); - if (ret == NULL){ - ShowFatalError("%s:%d: in func %s: aStrdup error out of memory!\n", file, line, func); - exit(EXIT_FAILURE); - } - return ret; + char *ret = STRDUP(p, file, line, func); + // ShowMessage("%s:%d: in func %s: aStrdup %p\n",file,line,func,p); + if (ret == NULL) { + ShowFatalError("%s:%d: in func %s: aStrdup error out of memory!\n", file, line, func); + exit(EXIT_FAILURE); + } + return ret; } void aFree_(void *p, const char *file, int line, const char *func) { - // ShowMessage("%s:%d: in func %s: aFree %p\n",file,line,func,p); - if (p) - FREE(p, file, line, func); + // ShowMessage("%s:%d: in func %s: aFree %p\n",file,line,func,p); + if (p) + FREE(p, file, line, func); - p = NULL; + p = NULL; } @@ -146,405 +146,397 @@ void aFree_(void *p, const char *file, int line, const char *func) */ /* ブロックのアライメント */ -#define BLOCK_ALIGNMENT1 16 -#define BLOCK_ALIGNMENT2 64 +#define BLOCK_ALIGNMENT1 16 +#define BLOCK_ALIGNMENT2 64 /* ブロックに入るデータ量 */ -#define BLOCK_DATA_COUNT1 128 -#define BLOCK_DATA_COUNT2 608 +#define BLOCK_DATA_COUNT1 128 +#define BLOCK_DATA_COUNT2 608 /* ブロックの大きさ: 16*128 + 64*576 = 40KB */ -#define BLOCK_DATA_SIZE1 ( BLOCK_ALIGNMENT1 * BLOCK_DATA_COUNT1 ) -#define BLOCK_DATA_SIZE2 ( BLOCK_ALIGNMENT2 * BLOCK_DATA_COUNT2 ) -#define BLOCK_DATA_SIZE ( BLOCK_DATA_SIZE1 + BLOCK_DATA_SIZE2 ) +#define BLOCK_DATA_SIZE1 ( BLOCK_ALIGNMENT1 * BLOCK_DATA_COUNT1 ) +#define BLOCK_DATA_SIZE2 ( BLOCK_ALIGNMENT2 * BLOCK_DATA_COUNT2 ) +#define BLOCK_DATA_SIZE ( BLOCK_DATA_SIZE1 + BLOCK_DATA_SIZE2 ) /* 一度に確保するブロックの数。 */ -#define BLOCK_ALLOC 104 +#define BLOCK_ALLOC 104 /* ブロック */ struct block { - struct block* block_next; /* 次に確保した領域 */ - struct block* unfill_prev; /* 次の埋まっていない領域 */ - struct block* unfill_next; /* 次の埋まっていない領域 */ - unsigned short unit_size; /* ユニットの大きさ */ - unsigned short unit_hash; /* ユニットのハッシュ */ - unsigned short unit_count; /* ユニットの個数 */ - unsigned short unit_used; /* 使用ユニット数 */ - unsigned short unit_unfill; /* 未使用ユニットの場所 */ - unsigned short unit_maxused; /* 使用ユニットの最大値 */ - char data[ BLOCK_DATA_SIZE ]; + struct block *block_next; /* 次に確保した領域 */ + struct block *unfill_prev; /* 次の埋まっていない領域 */ + struct block *unfill_next; /* 次の埋まっていない領域 */ + unsigned short unit_size; /* ユニットの大きさ */ + unsigned short unit_hash; /* ユニットのハッシュ */ + unsigned short unit_count; /* ユニットの個数 */ + unsigned short unit_used; /* 使用ユニット数 */ + unsigned short unit_unfill; /* 未使用ユニットの場所 */ + unsigned short unit_maxused; /* 使用ユニットの最大値 */ + char data[ BLOCK_DATA_SIZE ]; }; struct unit_head { - struct block *block; - const char* file; - unsigned short line; - unsigned short size; - long checksum; + struct block *block; + const char *file; + unsigned short line; + unsigned short size; + long checksum; }; -static struct block* hash_unfill[BLOCK_DATA_COUNT1 + BLOCK_DATA_COUNT2 + 1]; -static struct block* block_first, *block_last, block_head; +static struct block *hash_unfill[BLOCK_DATA_COUNT1 + BLOCK_DATA_COUNT2 + 1]; +static struct block *block_first, *block_last, block_head; /* メモリを使い回せない領域用のデータ */ struct unit_head_large { - size_t size; - struct unit_head_large* prev; - struct unit_head_large* next; - struct unit_head unit_head; + size_t size; + struct unit_head_large *prev; + struct unit_head_large *next; + struct unit_head unit_head; }; static struct unit_head_large *unit_head_large_first = NULL; -static struct block* block_malloc(unsigned short hash); -static void block_free(struct block* p); +static struct block *block_malloc(unsigned short hash); +static void block_free(struct block *p); static size_t memmgr_usage_bytes; #define block2unit(p, n) ((struct unit_head*)(&(p)->data[ p->unit_size * (n) ])) #define memmgr_assert(v) do { if(!(v)) { ShowError("Memory manager: assertion '" #v "' failed!\n"); } } while(0) -static unsigned short size2hash( size_t size ) +static unsigned short size2hash(size_t size) { - if( size <= BLOCK_DATA_SIZE1 ) { - return (unsigned short)(size + BLOCK_ALIGNMENT1 - 1) / BLOCK_ALIGNMENT1; - } else if( size <= BLOCK_DATA_SIZE ){ - return (unsigned short)(size - BLOCK_DATA_SIZE1 + BLOCK_ALIGNMENT2 - 1) / BLOCK_ALIGNMENT2 - + BLOCK_DATA_COUNT1; - } else { - return 0xffff; // ブロック長を超える場合は hash にしない - } + if (size <= BLOCK_DATA_SIZE1) { + return (unsigned short)(size + BLOCK_ALIGNMENT1 - 1) / BLOCK_ALIGNMENT1; + } else if (size <= BLOCK_DATA_SIZE) { + return (unsigned short)(size - BLOCK_DATA_SIZE1 + BLOCK_ALIGNMENT2 - 1) / BLOCK_ALIGNMENT2 + + BLOCK_DATA_COUNT1; + } else { + return 0xffff; // ブロック長を超える場合は hash にしない + } } -static size_t hash2size( unsigned short hash ) +static size_t hash2size(unsigned short hash) { - if( hash <= BLOCK_DATA_COUNT1) { - return hash * BLOCK_ALIGNMENT1; - } else { - return (hash - BLOCK_DATA_COUNT1) * BLOCK_ALIGNMENT2 + BLOCK_DATA_SIZE1; - } + if (hash <= BLOCK_DATA_COUNT1) { + return hash * BLOCK_ALIGNMENT1; + } else { + return (hash - BLOCK_DATA_COUNT1) * BLOCK_ALIGNMENT2 + BLOCK_DATA_SIZE1; + } } -void* _mmalloc(size_t size, const char *file, int line, const char *func ) +void *_mmalloc(size_t size, const char *file, int line, const char *func) { - struct block *block; - short size_hash = size2hash( size ); - struct unit_head *head; - - if (((long) size) < 0) { - ShowError("_mmalloc: %d\n", size); - return NULL; - } - - if(size == 0) { - return NULL; - } - memmgr_usage_bytes += size; - - /* ブロック長を超える領域の確保には、malloc() を用いる */ - /* その際、unit_head.block に NULL を代入して区別する */ - if(hash2size(size_hash) > BLOCK_DATA_SIZE - sizeof(struct unit_head)) { - struct unit_head_large* p = (struct unit_head_large*)MALLOC(sizeof(struct unit_head_large)+size,file,line,func); - if(p != NULL) { - p->size = size; - p->unit_head.block = NULL; - p->unit_head.size = 0; - p->unit_head.file = file; - p->unit_head.line = line; - p->prev = NULL; - if (unit_head_large_first == NULL) - p->next = NULL; - else { - unit_head_large_first->prev = p; - p->next = unit_head_large_first; - } - unit_head_large_first = p; - *(long*)((char*)p + sizeof(struct unit_head_large) - sizeof(long) + size) = 0xdeadbeaf; - return (char *)p + sizeof(struct unit_head_large) - sizeof(long); - } else { - ShowFatalError("Memory manager::memmgr_alloc failed (allocating %d+%d bytes at %s:%d).\n", sizeof(struct unit_head_large), size, file, line); - exit(EXIT_FAILURE); - } - } - - /* 同一サイズのブロックが確保されていない時、新たに確保する */ - if(hash_unfill[size_hash]) { - block = hash_unfill[size_hash]; - } else { - block = block_malloc(size_hash); - } - - if( block->unit_unfill == 0xFFFF ) { - // free済み領域が残っていない - memmgr_assert(block->unit_used < block->unit_count); - memmgr_assert(block->unit_used == block->unit_maxused); - head = block2unit(block, block->unit_maxused); - block->unit_used++; - block->unit_maxused++; - } else { - head = block2unit(block, block->unit_unfill); - block->unit_unfill = head->size; - block->unit_used++; - } - - if( block->unit_unfill == 0xFFFF && block->unit_maxused >= block->unit_count) { - // ユニットを使い果たしたので、unfillリストから削除 - if( block->unfill_prev == &block_head) { - hash_unfill[ size_hash ] = block->unfill_next; - } else { - block->unfill_prev->unfill_next = block->unfill_next; - } - if( block->unfill_next ) { - block->unfill_next->unfill_prev = block->unfill_prev; - } - block->unfill_prev = NULL; - } + struct block *block; + short size_hash = size2hash(size); + struct unit_head *head; + + if (((long) size) < 0) { + ShowError("_mmalloc: %d\n", size); + return NULL; + } + + if (size == 0) { + return NULL; + } + memmgr_usage_bytes += size; + + /* ブロック長を超える領域の確保には、malloc() を用いる */ + /* その際、unit_head.block に NULL を代入して区別する */ + if (hash2size(size_hash) > BLOCK_DATA_SIZE - sizeof(struct unit_head)) { + struct unit_head_large *p = (struct unit_head_large *)MALLOC(sizeof(struct unit_head_large)+size,file,line,func); + if (p != NULL) { + p->size = size; + p->unit_head.block = NULL; + p->unit_head.size = 0; + p->unit_head.file = file; + p->unit_head.line = line; + p->prev = NULL; + if (unit_head_large_first == NULL) + p->next = NULL; + else { + unit_head_large_first->prev = p; + p->next = unit_head_large_first; + } + unit_head_large_first = p; + *(long *)((char *)p + sizeof(struct unit_head_large) - sizeof(long) + size) = 0xdeadbeaf; + return (char *)p + sizeof(struct unit_head_large) - sizeof(long); + } else { + ShowFatalError("Memory manager::memmgr_alloc failed (allocating %d+%d bytes at %s:%d).\n", sizeof(struct unit_head_large), size, file, line); + exit(EXIT_FAILURE); + } + } + + /* 同一サイズのブロックが確保されていない時、新たに確保する */ + if (hash_unfill[size_hash]) { + block = hash_unfill[size_hash]; + } else { + block = block_malloc(size_hash); + } + + if (block->unit_unfill == 0xFFFF) { + // free済み領域が残っていない + memmgr_assert(block->unit_used < block->unit_count); + memmgr_assert(block->unit_used == block->unit_maxused); + head = block2unit(block, block->unit_maxused); + block->unit_used++; + block->unit_maxused++; + } else { + head = block2unit(block, block->unit_unfill); + block->unit_unfill = head->size; + block->unit_used++; + } + + if (block->unit_unfill == 0xFFFF && block->unit_maxused >= block->unit_count) { + // ユニットを使い果たしたので、unfillリストから削除 + if (block->unfill_prev == &block_head) { + hash_unfill[ size_hash ] = block->unfill_next; + } else { + block->unfill_prev->unfill_next = block->unfill_next; + } + if (block->unfill_next) { + block->unfill_next->unfill_prev = block->unfill_prev; + } + block->unfill_prev = NULL; + } #ifdef DEBUG_MEMMGR - { - size_t i, sz = hash2size( size_hash ); - for( i=0; iline != 0xfdfd ) - { - ShowError("Memory manager: freed-data is changed. (freed in %s line %d)\n", head->file,head->line); - } - else - { - ShowError("Memory manager: not-allocated-data is changed.\n"); - } - break; - } - } - memset( (char *)head + sizeof(struct unit_head) - sizeof(long), 0xcd, sz ); - } + { + size_t i, sz = hash2size(size_hash); + for (i=0; iline != 0xfdfd) { + ShowError("Memory manager: freed-data is changed. (freed in %s line %d)\n", head->file,head->line); + } else { + ShowError("Memory manager: not-allocated-data is changed.\n"); + } + break; + } + } + memset((char *)head + sizeof(struct unit_head) - sizeof(long), 0xcd, sz); + } #endif - head->block = block; - head->file = file; - head->line = line; - head->size = (unsigned short)size; - *(long*)((char*)head + sizeof(struct unit_head) - sizeof(long) + size) = 0xdeadbeaf; - return (char *)head + sizeof(struct unit_head) - sizeof(long); + head->block = block; + head->file = file; + head->line = line; + head->size = (unsigned short)size; + *(long *)((char *)head + sizeof(struct unit_head) - sizeof(long) + size) = 0xdeadbeaf; + return (char *)head + sizeof(struct unit_head) - sizeof(long); } -void* _mcalloc(size_t num, size_t size, const char *file, int line, const char *func ) +void *_mcalloc(size_t num, size_t size, const char *file, int line, const char *func) { - void *p = _mmalloc(num * size,file,line,func); - memset(p,0,num * size); - return p; + void *p = _mmalloc(num * size,file,line,func); + memset(p,0,num * size); + return p; } -void* _mrealloc(void *memblock, size_t size, const char *file, int line, const char *func ) +void *_mrealloc(void *memblock, size_t size, const char *file, int line, const char *func) { - size_t old_size; - if(memblock == NULL) { - return _mmalloc(size,file,line,func); - } - - old_size = ((struct unit_head *)((char *)memblock - sizeof(struct unit_head) + sizeof(long)))->size; - if( old_size == 0 ) { - old_size = ((struct unit_head_large *)((char *)memblock - sizeof(struct unit_head_large) + sizeof(long)))->size; - } - if(old_size > size) { - // サイズ縮小 -> そのまま返す(手抜き) - return memblock; - } else { - // サイズ拡大 - void *p = _mmalloc(size,file,line,func); - if(p != NULL) { - memcpy(p,memblock,old_size); - } - _mfree(memblock,file,line,func); - return p; - } + size_t old_size; + if (memblock == NULL) { + return _mmalloc(size,file,line,func); + } + + old_size = ((struct unit_head *)((char *)memblock - sizeof(struct unit_head) + sizeof(long)))->size; + if (old_size == 0) { + old_size = ((struct unit_head_large *)((char *)memblock - sizeof(struct unit_head_large) + sizeof(long)))->size; + } + if (old_size > size) { + // サイズ縮小 -> そのまま返す(手抜き) + return memblock; + } else { + // サイズ拡大 + void *p = _mmalloc(size,file,line,func); + if (p != NULL) { + memcpy(p,memblock,old_size); + } + _mfree(memblock,file,line,func); + return p; + } } -char* _mstrdup(const char *p, const char *file, int line, const char *func ) +char *_mstrdup(const char *p, const char *file, int line, const char *func) { - if(p == NULL) { - return NULL; - } else { - size_t len = strlen(p); - char *string = (char *)_mmalloc(len + 1,file,line,func); - memcpy(string,p,len+1); - return string; - } + if (p == NULL) { + return NULL; + } else { + size_t len = strlen(p); + char *string = (char *)_mmalloc(len + 1,file,line,func); + memcpy(string,p,len+1); + return string; + } } -void _mfree(void *ptr, const char *file, int line, const char *func ) +void _mfree(void *ptr, const char *file, int line, const char *func) { - struct unit_head *head; - - if (ptr == NULL) - return; - - head = (struct unit_head *)((char *)ptr - sizeof(struct unit_head) + sizeof(long)); - if(head->size == 0) { - /* malloc() で直に確保された領域 */ - struct unit_head_large *head_large = (struct unit_head_large *)((char *)ptr - sizeof(struct unit_head_large) + sizeof(long)); - if( - *(long*)((char*)head_large + sizeof(struct unit_head_large) - sizeof(long) + head_large->size) - != 0xdeadbeaf) - { - ShowError("Memory manager: args of aFree 0x%p is overflowed pointer %s line %d\n", ptr, file, line); - } else { - head->size = 0xFFFF; - if(head_large->prev) { - head_large->prev->next = head_large->next; - } else { - unit_head_large_first = head_large->next; - } - if(head_large->next) { - head_large->next->prev = head_large->prev; - } - memmgr_usage_bytes -= head_large->size; + struct unit_head *head; + + if (ptr == NULL) + return; + + head = (struct unit_head *)((char *)ptr - sizeof(struct unit_head) + sizeof(long)); + if (head->size == 0) { + /* malloc() で直に確保された領域 */ + struct unit_head_large *head_large = (struct unit_head_large *)((char *)ptr - sizeof(struct unit_head_large) + sizeof(long)); + if ( + *(long *)((char *)head_large + sizeof(struct unit_head_large) - sizeof(long) + head_large->size) + != 0xdeadbeaf) { + ShowError("Memory manager: args of aFree 0x%p is overflowed pointer %s line %d\n", ptr, file, line); + } else { + head->size = 0xFFFF; + if (head_large->prev) { + head_large->prev->next = head_large->next; + } else { + unit_head_large_first = head_large->next; + } + if (head_large->next) { + head_large->next->prev = head_large->prev; + } + memmgr_usage_bytes -= head_large->size; #ifdef DEBUG_MEMMGR - // set freed memory to 0xfd - memset(ptr, 0xfd, head_large->size); + // set freed memory to 0xfd + memset(ptr, 0xfd, head_large->size); #endif - FREE(head_large,file,line,func); - } - } else { - /* ユニット解放 */ - struct block *block = head->block; - if( (char*)head - (char*)block > sizeof(struct block) ) { - ShowError("Memory manager: args of aFree 0x%p is invalid pointer %s line %d\n", ptr, file, line); - } else if(head->block == NULL) { - ShowError("Memory manager: args of aFree 0x%p is freed pointer %s:%d@%s\n", ptr, file, line, func); - } else if(*(long*)((char*)head + sizeof(struct unit_head) - sizeof(long) + head->size) != 0xdeadbeaf) { - ShowError("Memory manager: args of aFree 0x%p is overflowed pointer %s line %d\n", ptr, file, line); - } else { - memmgr_usage_bytes -= head->size; - head->block = NULL; + FREE(head_large,file,line,func); + } + } else { + /* ユニット解放 */ + struct block *block = head->block; + if ((char *)head - (char *)block > sizeof(struct block)) { + ShowError("Memory manager: args of aFree 0x%p is invalid pointer %s line %d\n", ptr, file, line); + } else if (head->block == NULL) { + ShowError("Memory manager: args of aFree 0x%p is freed pointer %s:%d@%s\n", ptr, file, line, func); + } else if (*(long *)((char *)head + sizeof(struct unit_head) - sizeof(long) + head->size) != 0xdeadbeaf) { + ShowError("Memory manager: args of aFree 0x%p is overflowed pointer %s line %d\n", ptr, file, line); + } else { + memmgr_usage_bytes -= head->size; + head->block = NULL; #ifdef DEBUG_MEMMGR - memset(ptr, 0xfd, block->unit_size - sizeof(struct unit_head) + sizeof(long) ); - head->file = file; - head->line = line; + memset(ptr, 0xfd, block->unit_size - sizeof(struct unit_head) + sizeof(long)); + head->file = file; + head->line = line; #endif - memmgr_assert( block->unit_used > 0 ); - if(--block->unit_used == 0) { - /* ブロックの解放 */ - block_free(block); - } else { - if( block->unfill_prev == NULL) { - // unfill リストに追加 - if( hash_unfill[ block->unit_hash ] ) { - hash_unfill[ block->unit_hash ]->unfill_prev = block; - } - block->unfill_prev = &block_head; - block->unfill_next = hash_unfill[ block->unit_hash ]; - hash_unfill[ block->unit_hash ] = block; - } - head->size = block->unit_unfill; - block->unit_unfill = (unsigned short)(((uintptr_t)head - (uintptr_t)block->data) / block->unit_size); - } - } - } + memmgr_assert(block->unit_used > 0); + if (--block->unit_used == 0) { + /* ブロックの解放 */ + block_free(block); + } else { + if (block->unfill_prev == NULL) { + // unfill リストに追加 + if (hash_unfill[ block->unit_hash ]) { + hash_unfill[ block->unit_hash ]->unfill_prev = block; + } + block->unfill_prev = &block_head; + block->unfill_next = hash_unfill[ block->unit_hash ]; + hash_unfill[ block->unit_hash ] = block; + } + head->size = block->unit_unfill; + block->unit_unfill = (unsigned short)(((uintptr_t)head - (uintptr_t)block->data) / block->unit_size); + } + } + } } /* ブロックを確保する */ -static struct block* block_malloc(unsigned short hash) -{ - int i; - struct block *p; - if(hash_unfill[0] != NULL) { - /* ブロック用の領域は確保済み */ - p = hash_unfill[0]; - hash_unfill[0] = hash_unfill[0]->unfill_next; - } else { - /* ブロック用の領域を新たに確保する */ - p = (struct block*)MALLOC(sizeof(struct block) * (BLOCK_ALLOC), __FILE__, __LINE__, __func__ ); - if(p == NULL) { - ShowFatalError("Memory manager::block_alloc failed.\n"); - exit(EXIT_FAILURE); - } - - if(block_first == NULL) { - /* 初回確保 */ - block_first = p; - } else { - block_last->block_next = p; - } - block_last = &p[BLOCK_ALLOC - 1]; - block_last->block_next = NULL; - /* ブロックを連結させる */ - for(i=0;iunfill_prev = &block_head; - p->unfill_next = NULL; - p->unit_size = (unsigned short)(hash2size( hash ) + sizeof(struct unit_head)); - p->unit_hash = hash; - p->unit_count = BLOCK_DATA_SIZE / p->unit_size; - p->unit_used = 0; - p->unit_unfill = 0xFFFF; - p->unit_maxused = 0; +static struct block *block_malloc(unsigned short hash) { + int i; + struct block *p; + if (hash_unfill[0] != NULL) { + /* ブロック用の領域は確保済み */ + p = hash_unfill[0]; + hash_unfill[0] = hash_unfill[0]->unfill_next; + } else { + /* ブロック用の領域を新たに確保する */ + p = (struct block *)MALLOC(sizeof(struct block) * (BLOCK_ALLOC), __FILE__, __LINE__, __func__); + if (p == NULL) { + ShowFatalError("Memory manager::block_alloc failed.\n"); + exit(EXIT_FAILURE); + } + + if (block_first == NULL) { + /* 初回確保 */ + block_first = p; + } else { + block_last->block_next = p; + } + block_last = &p[BLOCK_ALLOC - 1]; + block_last->block_next = NULL; + /* ブロックを連結させる */ + for (i=0; iunfill_prev = &block_head; + p->unfill_next = NULL; + p->unit_size = (unsigned short)(hash2size(hash) + sizeof(struct unit_head)); + p->unit_hash = hash; + p->unit_count = BLOCK_DATA_SIZE / p->unit_size; + p->unit_used = 0; + p->unit_unfill = 0xFFFF; + p->unit_maxused = 0; #ifdef DEBUG_MEMMGR - memset( p->data, 0xfd, sizeof(p->data) ); + memset(p->data, 0xfd, sizeof(p->data)); #endif - return p; + return p; } -static void block_free(struct block* p) +static void block_free(struct block *p) { - if( p->unfill_prev ) { - if( p->unfill_prev == &block_head) { - hash_unfill[ p->unit_hash ] = p->unfill_next; - } else { - p->unfill_prev->unfill_next = p->unfill_next; - } - if( p->unfill_next ) { - p->unfill_next->unfill_prev = p->unfill_prev; - } - p->unfill_prev = NULL; - } - - p->unfill_next = hash_unfill[0]; - hash_unfill[0] = p; + if (p->unfill_prev) { + if (p->unfill_prev == &block_head) { + hash_unfill[ p->unit_hash ] = p->unfill_next; + } else { + p->unfill_prev->unfill_next = p->unfill_next; + } + if (p->unfill_next) { + p->unfill_next->unfill_prev = p->unfill_prev; + } + p->unfill_prev = NULL; + } + + p->unfill_next = hash_unfill[0]; + hash_unfill[0] = p; } -size_t memmgr_usage (void) +size_t memmgr_usage(void) { - return memmgr_usage_bytes / 1024; + return memmgr_usage_bytes / 1024; } #ifdef LOG_MEMMGR static char memmer_logfile[128]; static FILE *log_fp; -static void memmgr_log (char *buf) +static void memmgr_log(char *buf) { - if( !log_fp ) - { - time_t raw; - struct tm* t; - - log_fp = fopen(memmer_logfile,"at"); - if (!log_fp) log_fp = stdout; - - time(&raw); - t = localtime(&raw); - fprintf(log_fp, "\nMemory manager: Memory leaks found at %d/%02d/%02d %02dh%02dm%02ds (Revision %s).\n", - (t->tm_year+1900), (t->tm_mon+1), t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, get_svn_revision()); - } - fprintf(log_fp, "%s", buf); - return; + if (!log_fp) { + time_t raw; + struct tm *t; + + log_fp = fopen(memmer_logfile,"at"); + if (!log_fp) log_fp = stdout; + + time(&raw); + t = localtime(&raw); + fprintf(log_fp, "\nMemory manager: Memory leaks found at %d/%02d/%02d %02dh%02dm%02ds (Revision %s).\n", + (t->tm_year+1900), (t->tm_mon+1), t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, get_svn_revision()); + } + fprintf(log_fp, "%s", buf); + return; } #endif /* LOG_MEMMGR */ @@ -553,107 +545,105 @@ static void memmgr_log (char *buf) /// /// @param ptr Pointer to the memory /// @return true if the memory is active -bool memmgr_verify(void* ptr) +bool memmgr_verify(void *ptr) { - struct block* block = block_first; - struct unit_head_large* large = unit_head_large_first; - - if( ptr == NULL ) - return false;// never valid - - // search small blocks - while( block ) - { - if( (char*)ptr >= (char*)block && (char*)ptr < ((char*)block) + sizeof(struct block) ) - {// found memory block - if( block->unit_used && (char*)ptr >= block->data ) - {// memory block is being used and ptr points to a sub-unit - size_t i = (size_t)((char*)ptr - block->data)/block->unit_size; - struct unit_head* head = block2unit(block, i); - if( i < block->unit_maxused && head->block != NULL ) - {// memory unit is allocated, check if ptr points to the usable part - return ( (char*)ptr >= ((char*)head) + sizeof(struct unit_head) - sizeof(long) - && (char*)ptr < ((char*)head) + sizeof(struct unit_head) - sizeof(long) + head->size ); - } - } - return false; - } - block = block->block_next; - } - - // search large blocks - while( large ) - { - if( (char*)ptr >= (char*)large && (char*)ptr < ((char*)large) + large->size ) - {// found memory block, check if ptr points to the usable part - return ( (char*)ptr >= ((char*)large) + sizeof(struct unit_head_large) - sizeof(long) - && (char*)ptr < ((char*)large) + sizeof(struct unit_head_large) - sizeof(long) + large->size ); - } - large = large->next; - } - return false; + struct block *block = block_first; + struct unit_head_large *large = unit_head_large_first; + + if (ptr == NULL) + return false;// never valid + + // search small blocks + while (block) { + if ((char *)ptr >= (char *)block && (char *)ptr < ((char *)block) + sizeof(struct block)) { + // found memory block + if (block->unit_used && (char *)ptr >= block->data) { + // memory block is being used and ptr points to a sub-unit + size_t i = (size_t)((char *)ptr - block->data)/block->unit_size; + struct unit_head *head = block2unit(block, i); + if (i < block->unit_maxused && head->block != NULL) { + // memory unit is allocated, check if ptr points to the usable part + return ((char *)ptr >= ((char *)head) + sizeof(struct unit_head) - sizeof(long) + && (char *)ptr < ((char *)head) + sizeof(struct unit_head) - sizeof(long) + head->size); + } + } + return false; + } + block = block->block_next; + } + + // search large blocks + while (large) { + if ((char *)ptr >= (char *)large && (char *)ptr < ((char *)large) + large->size) { + // found memory block, check if ptr points to the usable part + return ((char *)ptr >= ((char *)large) + sizeof(struct unit_head_large) - sizeof(long) + && (char *)ptr < ((char *)large) + sizeof(struct unit_head_large) - sizeof(long) + large->size); + } + large = large->next; + } + return false; } -static void memmgr_final (void) +static void memmgr_final(void) { - struct block *block = block_first; - struct unit_head_large *large = unit_head_large_first; + struct block *block = block_first; + struct unit_head_large *large = unit_head_large_first; #ifdef LOG_MEMMGR - int count = 0; + int count = 0; #endif /* LOG_MEMMGR */ - while (block) { - if (block->unit_used) { - int i; - for (i = 0; i < block->unit_maxused; i++) { - struct unit_head *head = block2unit(block, i); - if(head->block != NULL) { - char* ptr = (char *)head + sizeof(struct unit_head) - sizeof(long); + while (block) { + if (block->unit_used) { + int i; + for (i = 0; i < block->unit_maxused; i++) { + struct unit_head *head = block2unit(block, i); + if (head->block != NULL) { + char *ptr = (char *)head + sizeof(struct unit_head) - sizeof(long); #ifdef LOG_MEMMGR - char buf[1024]; - sprintf (buf, - "%04d : %s line %d size %lu address 0x%p\n", ++count, - head->file, head->line, (unsigned long)head->size, ptr); - memmgr_log (buf); + char buf[1024]; + sprintf(buf, + "%04d : %s line %d size %lu address 0x%p\n", ++count, + head->file, head->line, (unsigned long)head->size, ptr); + memmgr_log(buf); #endif /* LOG_MEMMGR */ - // get block pointer and free it [celest] - _mfree(ptr, ALC_MARK); - } - } - } - block = block->block_next; - } - - while(large) { - struct unit_head_large *large2; + // get block pointer and free it [celest] + _mfree(ptr, ALC_MARK); + } + } + } + block = block->block_next; + } + + while (large) { + struct unit_head_large *large2; #ifdef LOG_MEMMGR - char buf[1024]; - sprintf (buf, - "%04d : %s line %d size %lu address 0x%p\n", ++count, - large->unit_head.file, large->unit_head.line, (unsigned long)large->size, &large->unit_head.checksum); - memmgr_log (buf); + char buf[1024]; + sprintf(buf, + "%04d : %s line %d size %lu address 0x%p\n", ++count, + large->unit_head.file, large->unit_head.line, (unsigned long)large->size, &large->unit_head.checksum); + memmgr_log(buf); #endif /* LOG_MEMMGR */ - large2 = large->next; - FREE(large,file,line,func); - large = large2; - } + large2 = large->next; + FREE(large,file,line,func); + large = large2; + } #ifdef LOG_MEMMGR - if(count == 0) { - ShowInfo("Memory manager: No memory leaks found.\n"); - } else { - ShowWarning("Memory manager: Memory leaks found and fixed.\n"); - fclose(log_fp); - } + if (count == 0) { + ShowInfo("Memory manager: No memory leaks found.\n"); + } else { + ShowWarning("Memory manager: Memory leaks found and fixed.\n"); + fclose(log_fp); + } #endif /* LOG_MEMMGR */ } -static void memmgr_init (void) +static void memmgr_init(void) { #ifdef LOG_MEMMGR - sprintf(memmer_logfile, "log/%s.leaks", SERVER_NAME); - ShowStatus("Memory manager initialised: "CL_WHITE"%s"CL_RESET"\n", memmer_logfile); - memset(hash_unfill, 0, sizeof(hash_unfill)); + sprintf(memmer_logfile, "log/%s.leaks", SERVER_NAME); + ShowStatus("Memory manager initialised: "CL_WHITE"%s"CL_RESET"\n", memmer_logfile); + memset(hash_unfill, 0, sizeof(hash_unfill)); #endif /* LOG_MEMMGR */ } #endif /* USE_MEMMGR */ @@ -668,51 +658,51 @@ static void memmgr_init (void) /// Tests the memory for errors and memory leaks. void malloc_memory_check(void) { - MEMORY_CHECK(); + MEMORY_CHECK(); } /// Returns true if a pointer is valid. /// The check is best-effort, false positives are possible. -bool malloc_verify_ptr(void* ptr) +bool malloc_verify_ptr(void *ptr) { #ifdef USE_MEMMGR - return memmgr_verify(ptr) && MEMORY_VERIFY(ptr); + return memmgr_verify(ptr) && MEMORY_VERIFY(ptr); #else - return MEMORY_VERIFY(ptr); + return MEMORY_VERIFY(ptr); #endif } -size_t malloc_usage (void) +size_t malloc_usage(void) { #ifdef USE_MEMMGR - return memmgr_usage (); + return memmgr_usage(); #else - return MEMORY_USAGE(); + return MEMORY_USAGE(); #endif } -void malloc_final (void) +void malloc_final(void) { #ifdef USE_MEMMGR - memmgr_final (); + memmgr_final(); #endif - MEMORY_CHECK(); + MEMORY_CHECK(); } -void malloc_init (void) +void malloc_init(void) { #if defined(DMALLOC) && defined(CYGWIN) - // http://dmalloc.com/docs/latest/online/dmalloc_19.html - dmalloc_debug_setup(getenv("DMALLOC_OPTIONS")); + // http://dmalloc.com/docs/latest/online/dmalloc_19.html + dmalloc_debug_setup(getenv("DMALLOC_OPTIONS")); #endif #ifdef GCOLLECT - // don't garbage collect, only report inaccessible memory that was not deallocated - GC_find_leak = 1; - GC_INIT(); + // don't garbage collect, only report inaccessible memory that was not deallocated + GC_find_leak = 1; + GC_INIT(); #endif #ifdef USE_MEMMGR - memmgr_init (); + memmgr_init(); #endif } diff --git a/src/common/malloc.h b/src/common/malloc.h index 6b4e8e5c4..58dcee6d7 100644 --- a/src/common/malloc.h +++ b/src/common/malloc.h @@ -33,31 +33,31 @@ #undef LOG_MEMMGR #endif -# define aMalloc(n) _mmalloc(n,ALC_MARK) -# define aCalloc(m,n) _mcalloc(m,n,ALC_MARK) -# define aRealloc(p,n) _mrealloc(p,n,ALC_MARK) -# define aStrdup(p) _mstrdup(p,ALC_MARK) -# define aFree(p) _mfree(p,ALC_MARK) - - void* _mmalloc (size_t size, const char *file, int line, const char *func); - void* _mcalloc (size_t num, size_t size, const char *file, int line, const char *func); - void* _mrealloc (void *p, size_t size, const char *file, int line, const char *func); - char* _mstrdup (const char *p, const char *file, int line, const char *func); - void _mfree (void *p, const char *file, int line, const char *func); +# define aMalloc(n) _mmalloc(n,ALC_MARK) +# define aCalloc(m,n) _mcalloc(m,n,ALC_MARK) +# define aRealloc(p,n) _mrealloc(p,n,ALC_MARK) +# define aStrdup(p) _mstrdup(p,ALC_MARK) +# define aFree(p) _mfree(p,ALC_MARK) + +void *_mmalloc(size_t size, const char *file, int line, const char *func); +void *_mcalloc(size_t num, size_t size, const char *file, int line, const char *func); +void *_mrealloc(void *p, size_t size, const char *file, int line, const char *func); +char *_mstrdup(const char *p, const char *file, int line, const char *func); +void _mfree(void *p, const char *file, int line, const char *func); #else -# define aMalloc(n) aMalloc_((n),ALC_MARK) -# define aCalloc(m,n) aCalloc_((m),(n),ALC_MARK) -# define aRealloc(p,n) aRealloc_(p,n,ALC_MARK) -# define aStrdup(p) aStrdup_(p,ALC_MARK) -# define aFree(p) aFree_(p,ALC_MARK) +# define aMalloc(n) aMalloc_((n),ALC_MARK) +# define aCalloc(m,n) aCalloc_((m),(n),ALC_MARK) +# define aRealloc(p,n) aRealloc_(p,n,ALC_MARK) +# define aStrdup(p) aStrdup_(p,ALC_MARK) +# define aFree(p) aFree_(p,ALC_MARK) - void* aMalloc_ (size_t size, const char *file, int line, const char *func); - void* aCalloc_ (size_t num, size_t size, const char *file, int line, const char *func); - void* aRealloc_ (void *p, size_t size, const char *file, int line, const char *func); - char* aStrdup_ (const char *p, const char *file, int line, const char *func); - void aFree_ (void *p, const char *file, int line, const char *func); +void *aMalloc_(size_t size, const char *file, int line, const char *func); +void *aCalloc_(size_t num, size_t size, const char *file, int line, const char *func); +void *aRealloc_(void *p, size_t size, const char *file, int line, const char *func); +char *aStrdup_(const char *p, const char *file, int line, const char *func); +void aFree_(void *p, const char *file, int line, const char *func); #endif @@ -66,13 +66,13 @@ #ifdef __GNUC__ // GCC has variable length arrays - #define CREATE_BUFFER(name, type, size) type name[size] - #define DELETE_BUFFER(name) +#define CREATE_BUFFER(name, type, size) type name[size] +#define DELETE_BUFFER(name) #else // others don't, so we emulate them - #define CREATE_BUFFER(name, type, size) type *name = (type *) aCalloc (size, sizeof(type)) - #define DELETE_BUFFER(name) aFree(name) +#define CREATE_BUFFER(name, type, size) type *name = (type *) aCalloc (size, sizeof(type)) +#define DELETE_BUFFER(name) aFree(name) #endif @@ -84,9 +84,9 @@ //////////////////////////////////////////////// void malloc_memory_check(void); -bool malloc_verify_ptr(void* ptr); -size_t malloc_usage (void); -void malloc_init (void); -void malloc_final (void); +bool malloc_verify_ptr(void *ptr); +size_t malloc_usage(void); +void malloc_init(void); +void malloc_final(void); #endif /* _MALLOC_H_ */ diff --git a/src/common/mapindex.c b/src/common/mapindex.c index d46047833..62d14590e 100644 --- a/src/common/mapindex.c +++ b/src/common/mapindex.c @@ -12,7 +12,7 @@ #include struct _indexes { - char name[MAP_NAME_LENGTH]; //Stores map name + char name[MAP_NAME_LENGTH]; //Stores map name } indexes[MAX_MAPINDEX]; int max_index = 0; @@ -23,161 +23,158 @@ char mapindex_cfgfile[80] = "db/map_index.txt"; /// Retrieves the map name from 'string' (removing .gat extension if present). /// Result gets placed either into 'buf' or in a static local buffer. -const char* mapindex_getmapname(const char* string, char* output) +const char *mapindex_getmapname(const char *string, char *output) { - static char buf[MAP_NAME_LENGTH]; - char* dest = (output != NULL) ? output : buf; - - size_t len = strnlen(string, MAP_NAME_LENGTH_EXT); - if (len == MAP_NAME_LENGTH_EXT) { - ShowWarning("(mapindex_normalize_name) Map name '%*s' is too long!\n", 2*MAP_NAME_LENGTH_EXT, string); - len--; - } - if (len >= 4 && stricmp(&string[len-4], ".gat") == 0) - len -= 4; // strip .gat extension - - len = min(len, MAP_NAME_LENGTH-1); - strncpy(dest, string, len+1); - memset(&dest[len], '\0', MAP_NAME_LENGTH-len); - - return dest; + static char buf[MAP_NAME_LENGTH]; + char *dest = (output != NULL) ? output : buf; + + size_t len = strnlen(string, MAP_NAME_LENGTH_EXT); + if (len == MAP_NAME_LENGTH_EXT) { + ShowWarning("(mapindex_normalize_name) Map name '%*s' is too long!\n", 2*MAP_NAME_LENGTH_EXT, string); + len--; + } + if (len >= 4 && stricmp(&string[len-4], ".gat") == 0) + len -= 4; // strip .gat extension + + len = min(len, MAP_NAME_LENGTH-1); + strncpy(dest, string, len+1); + memset(&dest[len], '\0', MAP_NAME_LENGTH-len); + + return dest; } /// Retrieves the map name from 'string' (adding .gat extension if not already present). /// Result gets placed either into 'buf' or in a static local buffer. -const char* mapindex_getmapname_ext(const char* string, char* output) +const char *mapindex_getmapname_ext(const char *string, char *output) { - static char buf[MAP_NAME_LENGTH_EXT]; - char* dest = (output != NULL) ? output : buf; + static char buf[MAP_NAME_LENGTH_EXT]; + char *dest = (output != NULL) ? output : buf; - size_t len; + size_t len; - strcpy(buf,string); - sscanf(string,"%*[^#]%*[#]%s",buf); + strcpy(buf,string); + sscanf(string,"%*[^#]%*[#]%s",buf); - len = safestrnlen(buf, MAP_NAME_LENGTH); + len = safestrnlen(buf, MAP_NAME_LENGTH); - if (len == MAP_NAME_LENGTH) { - ShowWarning("(mapindex_normalize_name) Map name '%*s' is too long!\n", 2*MAP_NAME_LENGTH, buf); - len--; - } - strncpy(dest, buf, len+1); + if (len == MAP_NAME_LENGTH) { + ShowWarning("(mapindex_normalize_name) Map name '%*s' is too long!\n", 2*MAP_NAME_LENGTH, buf); + len--; + } + strncpy(dest, buf, len+1); - if (len < 4 || stricmp(&dest[len-4], ".gat") != 0) { - strcpy(&dest[len], ".gat"); - len += 4; // add .gat extension - } + if (len < 4 || stricmp(&dest[len-4], ".gat") != 0) { + strcpy(&dest[len], ".gat"); + len += 4; // add .gat extension + } - memset(&dest[len], '\0', MAP_NAME_LENGTH_EXT-len); - - return dest; + memset(&dest[len], '\0', MAP_NAME_LENGTH_EXT-len); + + return dest; } /// Adds a map to the specified index /// Returns 1 if successful, 0 oherwise -int mapindex_addmap(int index, const char* name) +int mapindex_addmap(int index, const char *name) { - char map_name[MAP_NAME_LENGTH]; - - if (index == -1){ - for (index = 1; index < max_index; index++) - { - //if (strcmp(indexes[index].name,"#CLEARED#")==0) - if (indexes[index].name[0] == '\0') - break; - } - } - - if (index < 0 || index >= MAX_MAPINDEX) { - ShowError("(mapindex_add) Map index (%d) for \"%s\" out of range (max is %d)\n", index, name, MAX_MAPINDEX); - return 0; - } - - mapindex_getmapname(name, map_name); - - if (map_name[0] == '\0') { - ShowError("(mapindex_add) Cannot add maps with no name.\n"); - return 0; - } - - if (strlen(map_name) >= MAP_NAME_LENGTH) { - ShowError("(mapindex_add) Map name %s is too long. Maps are limited to %d characters.\n", map_name, MAP_NAME_LENGTH); - return 0; - } - - if (mapindex_exists(index)) - ShowWarning("(mapindex_add) Overriding index %d: map \"%s\" -> \"%s\"\n", index, indexes[index].name, map_name); - - safestrncpy(indexes[index].name, map_name, MAP_NAME_LENGTH); - if (max_index <= index) - max_index = index+1; - - return index; + char map_name[MAP_NAME_LENGTH]; + + if (index == -1) { + for (index = 1; index < max_index; index++) { + //if (strcmp(indexes[index].name,"#CLEARED#")==0) + if (indexes[index].name[0] == '\0') + break; + } + } + + if (index < 0 || index >= MAX_MAPINDEX) { + ShowError("(mapindex_add) Map index (%d) for \"%s\" out of range (max is %d)\n", index, name, MAX_MAPINDEX); + return 0; + } + + mapindex_getmapname(name, map_name); + + if (map_name[0] == '\0') { + ShowError("(mapindex_add) Cannot add maps with no name.\n"); + return 0; + } + + if (strlen(map_name) >= MAP_NAME_LENGTH) { + ShowError("(mapindex_add) Map name %s is too long. Maps are limited to %d characters.\n", map_name, MAP_NAME_LENGTH); + return 0; + } + + if (mapindex_exists(index)) + ShowWarning("(mapindex_add) Overriding index %d: map \"%s\" -> \"%s\"\n", index, indexes[index].name, map_name); + + safestrncpy(indexes[index].name, map_name, MAP_NAME_LENGTH); + if (max_index <= index) + max_index = index+1; + + return index; } -unsigned short mapindex_name2id(const char* name) +unsigned short mapindex_name2id(const char *name) { - //TODO: Perhaps use a db to speed this up? [Skotlex] - int i; - - char map_name[MAP_NAME_LENGTH]; - mapindex_getmapname(name, map_name); - - for (i = 1; i < max_index; i++) - { - if (strcmpi(indexes[i].name,map_name)==0) - return i; - } - ShowDebug("mapindex_name2id: Map \"%s\" not found in index list!\n", map_name); - return 0; + //TODO: Perhaps use a db to speed this up? [Skotlex] + int i; + + char map_name[MAP_NAME_LENGTH]; + mapindex_getmapname(name, map_name); + + for (i = 1; i < max_index; i++) { + if (strcmpi(indexes[i].name,map_name)==0) + return i; + } + ShowDebug("mapindex_name2id: Map \"%s\" not found in index list!\n", map_name); + return 0; } -const char* mapindex_id2name(unsigned short id) +const char *mapindex_id2name(unsigned short id) { - if (id > MAX_MAPINDEX || !mapindex_exists(id)) { - ShowDebug("mapindex_id2name: Requested name for non-existant map index [%d] in cache.\n", id); - return indexes[0].name; // dummy empty string so that the callee doesn't crash - } - return indexes[id].name; + if (id > MAX_MAPINDEX || !mapindex_exists(id)) { + ShowDebug("mapindex_id2name: Requested name for non-existant map index [%d] in cache.\n", id); + return indexes[0].name; // dummy empty string so that the callee doesn't crash + } + return indexes[id].name; } void mapindex_init(void) { - FILE *fp; - char line[1024]; - int last_index = -1; - int index; - char map_name[1024]; - - memset (&indexes, 0, sizeof (indexes)); - fp=fopen(mapindex_cfgfile,"r"); - if(fp==NULL){ - ShowFatalError("Unable to read mapindex config file %s!\n", mapindex_cfgfile); - exit(EXIT_FAILURE); //Server can't really run without this file. - } - while(fgets(line, sizeof(line), fp)) - { - if(line[0] == '/' && line[1] == '/') - continue; - - switch (sscanf(line, "%1023s\t%d", map_name, &index)) - { - case 1: //Map with no ID given, auto-assign - index = last_index+1; - case 2: //Map with ID given - mapindex_addmap(index,map_name); - break; - default: - continue; - } - last_index = index; - } - fclose(fp); + FILE *fp; + char line[1024]; + int last_index = -1; + int index; + char map_name[1024]; + + memset(&indexes, 0, sizeof(indexes)); + fp=fopen(mapindex_cfgfile,"r"); + if (fp==NULL) { + ShowFatalError("Unable to read mapindex config file %s!\n", mapindex_cfgfile); + exit(EXIT_FAILURE); //Server can't really run without this file. + } + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') + continue; + + switch (sscanf(line, "%1023s\t%d", map_name, &index)) { + case 1: //Map with no ID given, auto-assign + index = last_index+1; + case 2: //Map with ID given + mapindex_addmap(index,map_name); + break; + default: + continue; + } + last_index = index; + } + fclose(fp); } -int mapindex_removemap(int index){ - indexes[index].name[0] = '\0'; - return 0; +int mapindex_removemap(int index) +{ + indexes[index].name[0] = '\0'; + return 0; } void mapindex_final(void) diff --git a/src/common/mapindex.h b/src/common/mapindex.h index 75cb254c0..4889d20f1 100644 --- a/src/common/mapindex.h +++ b/src/common/mapindex.h @@ -47,14 +47,14 @@ extern char mapindex_cfgfile[80]; #define MAP_MALAYA "malaya" #define MAP_ECLAGE "eclage" -const char* mapindex_getmapname(const char* string, char* output); -const char* mapindex_getmapname_ext(const char* string, char* output); -unsigned short mapindex_name2id(const char*); -const char* mapindex_id2name(unsigned short); +const char *mapindex_getmapname(const char *string, char *output); +const char *mapindex_getmapname_ext(const char *string, char *output); +unsigned short mapindex_name2id(const char *); +const char *mapindex_id2name(unsigned short); void mapindex_init(void); void mapindex_final(void); -int mapindex_addmap(int index, const char* name); +int mapindex_addmap(int index, const char *name); int mapindex_removemap(int index); #endif /* _MAPINDEX_H_ */ diff --git a/src/common/md5calc.c b/src/common/md5calc.c index 05fde42cc..bd4b59ad0 100644 --- a/src/common/md5calc.c +++ b/src/common/md5calc.c @@ -21,22 +21,22 @@ static unsigned int *pX; // String Table static const unsigned int T[] = { - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, //0 - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, //4 - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, //8 - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, //12 - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, //16 - 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, //20 - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, //24 - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, //28 - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, //32 - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, //36 - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, //40 - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, //44 - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, //48 - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, //52 - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, //56 - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 //60 + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, //0 + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, //4 + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, //8 + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, //12 + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, //16 + 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, //20 + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, //24 + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, //28 + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, //32 + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, //36 + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, //40 + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, //44 + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, //48 + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, //52 + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, //56 + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 //60 }; // ROTATE_LEFT The left is made to rotate x [ n-bit ]. This is diverted as it is from RFC. @@ -45,196 +45,244 @@ static const unsigned int T[] = { // The function used for other calculation static unsigned int F(unsigned int X, unsigned int Y, unsigned int Z) { - return (X & Y) | (~X & Z); + return (X & Y) | (~X & Z); } static unsigned int G(unsigned int X, unsigned int Y, unsigned int Z) { - return (X & Z) | (Y & ~Z); + return (X & Z) | (Y & ~Z); } static unsigned int H(unsigned int X, unsigned int Y, unsigned int Z) { - return X ^ Y ^ Z; + return X ^ Y ^ Z; } static unsigned int I(unsigned int X, unsigned int Y, unsigned int Z) { - return Y ^ (X | ~Z); + return Y ^ (X | ~Z); } static unsigned int Round(unsigned int a, unsigned int b, unsigned int FGHI, - unsigned int k, unsigned int s, unsigned int i) + unsigned int k, unsigned int s, unsigned int i) { - return b + ROTATE_LEFT(a + FGHI + pX[k] + T[i], s); + return b + ROTATE_LEFT(a + FGHI + pX[k] + T[i], s); } static void Round1(unsigned int *a, unsigned int b, unsigned int c, - unsigned int d,unsigned int k, unsigned int s, unsigned int i) + unsigned int d,unsigned int k, unsigned int s, unsigned int i) { - *a = Round(*a, b, F(b,c,d), k, s, i); + *a = Round(*a, b, F(b,c,d), k, s, i); } static void Round2(unsigned int *a, unsigned int b, unsigned int c, - unsigned int d,unsigned int k, unsigned int s, unsigned int i) + unsigned int d,unsigned int k, unsigned int s, unsigned int i) { - *a = Round(*a, b, G(b,c,d), k, s, i); + *a = Round(*a, b, G(b,c,d), k, s, i); } static void Round3(unsigned int *a, unsigned int b, unsigned int c, - unsigned int d,unsigned int k, unsigned int s, unsigned int i) + unsigned int d,unsigned int k, unsigned int s, unsigned int i) { - *a = Round(*a, b, H(b,c,d), k, s, i); + *a = Round(*a, b, H(b,c,d), k, s, i); } static void Round4(unsigned int *a, unsigned int b, unsigned int c, - unsigned int d,unsigned int k, unsigned int s, unsigned int i) + unsigned int d,unsigned int k, unsigned int s, unsigned int i) { - *a = Round(*a, b, I(b,c,d), k, s, i); + *a = Round(*a, b, I(b,c,d), k, s, i); } static void MD5_Round_Calculate(const unsigned char *block, - unsigned int *A2, unsigned int *B2, unsigned int *C2, unsigned int *D2) + unsigned int *A2, unsigned int *B2, unsigned int *C2, unsigned int *D2) { - //create X It is since it is required. - unsigned int X[16]; //512bit 64byte - int j,k; - - //Save A as AA, B as BB, C as CC, and and D as DD (saving of A, B, C, and D) - unsigned int A=*A2, B=*B2, C=*C2, D=*D2; - unsigned int AA = A,BB = B,CC = C,DD = D; - - //It is a large region variable reluctantly because of calculation of a round. . . for Round1...4 - pX = X; - - //Copy block(padding_message) i into X - for (j=0,k=0; j<64; j+=4,k++) - X[k] = ( (unsigned int )block[j] ) // 8byte*4 -> 32byte conversion - | ( ((unsigned int )block[j+1]) << 8 ) // A function called Decode as used in the field of RFC - | ( ((unsigned int )block[j+2]) << 16 ) - | ( ((unsigned int )block[j+3]) << 24 ); - - - //Round 1 - Round1(&A,B,C,D, 0, 7, 0); Round1(&D,A,B,C, 1, 12, 1); Round1(&C,D,A,B, 2, 17, 2); Round1(&B,C,D,A, 3, 22, 3); - Round1(&A,B,C,D, 4, 7, 4); Round1(&D,A,B,C, 5, 12, 5); Round1(&C,D,A,B, 6, 17, 6); Round1(&B,C,D,A, 7, 22, 7); - Round1(&A,B,C,D, 8, 7, 8); Round1(&D,A,B,C, 9, 12, 9); Round1(&C,D,A,B, 10, 17, 10); Round1(&B,C,D,A, 11, 22, 11); - Round1(&A,B,C,D, 12, 7, 12); Round1(&D,A,B,C, 13, 12, 13); Round1(&C,D,A,B, 14, 17, 14); Round1(&B,C,D,A, 15, 22, 15); - - //Round 2 - Round2(&A,B,C,D, 1, 5, 16); Round2(&D,A,B,C, 6, 9, 17); Round2(&C,D,A,B, 11, 14, 18); Round2(&B,C,D,A, 0, 20, 19); - Round2(&A,B,C,D, 5, 5, 20); Round2(&D,A,B,C, 10, 9, 21); Round2(&C,D,A,B, 15, 14, 22); Round2(&B,C,D,A, 4, 20, 23); - Round2(&A,B,C,D, 9, 5, 24); Round2(&D,A,B,C, 14, 9, 25); Round2(&C,D,A,B, 3, 14, 26); Round2(&B,C,D,A, 8, 20, 27); - Round2(&A,B,C,D, 13, 5, 28); Round2(&D,A,B,C, 2, 9, 29); Round2(&C,D,A,B, 7, 14, 30); Round2(&B,C,D,A, 12, 20, 31); - - //Round 3 - Round3(&A,B,C,D, 5, 4, 32); Round3(&D,A,B,C, 8, 11, 33); Round3(&C,D,A,B, 11, 16, 34); Round3(&B,C,D,A, 14, 23, 35); - Round3(&A,B,C,D, 1, 4, 36); Round3(&D,A,B,C, 4, 11, 37); Round3(&C,D,A,B, 7, 16, 38); Round3(&B,C,D,A, 10, 23, 39); - Round3(&A,B,C,D, 13, 4, 40); Round3(&D,A,B,C, 0, 11, 41); Round3(&C,D,A,B, 3, 16, 42); Round3(&B,C,D,A, 6, 23, 43); - Round3(&A,B,C,D, 9, 4, 44); Round3(&D,A,B,C, 12, 11, 45); Round3(&C,D,A,B, 15, 16, 46); Round3(&B,C,D,A, 2, 23, 47); - - //Round 4 - Round4(&A,B,C,D, 0, 6, 48); Round4(&D,A,B,C, 7, 10, 49); Round4(&C,D,A,B, 14, 15, 50); Round4(&B,C,D,A, 5, 21, 51); - Round4(&A,B,C,D, 12, 6, 52); Round4(&D,A,B,C, 3, 10, 53); Round4(&C,D,A,B, 10, 15, 54); Round4(&B,C,D,A, 1, 21, 55); - Round4(&A,B,C,D, 8, 6, 56); Round4(&D,A,B,C, 15, 10, 57); Round4(&C,D,A,B, 6, 15, 58); Round4(&B,C,D,A, 13, 21, 59); - Round4(&A,B,C,D, 4, 6, 60); Round4(&D,A,B,C, 11, 10, 61); Round4(&C,D,A,B, 2, 15, 62); Round4(&B,C,D,A, 9, 21, 63); - - // Then perform the following additions. (let's add) - *A2 = A + AA; - *B2 = B + BB; - *C2 = C + CC; - *D2 = D + DD; - - //The clearance of confidential information - memset(pX, 0, sizeof(X)); + //create X It is since it is required. + unsigned int X[16]; //512bit 64byte + int j,k; + + //Save A as AA, B as BB, C as CC, and and D as DD (saving of A, B, C, and D) + unsigned int A=*A2, B=*B2, C=*C2, D=*D2; + unsigned int AA = A,BB = B,CC = C,DD = D; + + //It is a large region variable reluctantly because of calculation of a round. . . for Round1...4 + pX = X; + + //Copy block(padding_message) i into X + for (j=0,k=0; j<64; j+=4,k++) + X[k] = ((unsigned int)block[j]) // 8byte*4 -> 32byte conversion + | (((unsigned int)block[j+1]) << 8) // A function called Decode as used in the field of RFC + | (((unsigned int)block[j+2]) << 16) + | (((unsigned int)block[j+3]) << 24); + + + //Round 1 + Round1(&A,B,C,D, 0, 7, 0); + Round1(&D,A,B,C, 1, 12, 1); + Round1(&C,D,A,B, 2, 17, 2); + Round1(&B,C,D,A, 3, 22, 3); + Round1(&A,B,C,D, 4, 7, 4); + Round1(&D,A,B,C, 5, 12, 5); + Round1(&C,D,A,B, 6, 17, 6); + Round1(&B,C,D,A, 7, 22, 7); + Round1(&A,B,C,D, 8, 7, 8); + Round1(&D,A,B,C, 9, 12, 9); + Round1(&C,D,A,B, 10, 17, 10); + Round1(&B,C,D,A, 11, 22, 11); + Round1(&A,B,C,D, 12, 7, 12); + Round1(&D,A,B,C, 13, 12, 13); + Round1(&C,D,A,B, 14, 17, 14); + Round1(&B,C,D,A, 15, 22, 15); + + //Round 2 + Round2(&A,B,C,D, 1, 5, 16); + Round2(&D,A,B,C, 6, 9, 17); + Round2(&C,D,A,B, 11, 14, 18); + Round2(&B,C,D,A, 0, 20, 19); + Round2(&A,B,C,D, 5, 5, 20); + Round2(&D,A,B,C, 10, 9, 21); + Round2(&C,D,A,B, 15, 14, 22); + Round2(&B,C,D,A, 4, 20, 23); + Round2(&A,B,C,D, 9, 5, 24); + Round2(&D,A,B,C, 14, 9, 25); + Round2(&C,D,A,B, 3, 14, 26); + Round2(&B,C,D,A, 8, 20, 27); + Round2(&A,B,C,D, 13, 5, 28); + Round2(&D,A,B,C, 2, 9, 29); + Round2(&C,D,A,B, 7, 14, 30); + Round2(&B,C,D,A, 12, 20, 31); + + //Round 3 + Round3(&A,B,C,D, 5, 4, 32); + Round3(&D,A,B,C, 8, 11, 33); + Round3(&C,D,A,B, 11, 16, 34); + Round3(&B,C,D,A, 14, 23, 35); + Round3(&A,B,C,D, 1, 4, 36); + Round3(&D,A,B,C, 4, 11, 37); + Round3(&C,D,A,B, 7, 16, 38); + Round3(&B,C,D,A, 10, 23, 39); + Round3(&A,B,C,D, 13, 4, 40); + Round3(&D,A,B,C, 0, 11, 41); + Round3(&C,D,A,B, 3, 16, 42); + Round3(&B,C,D,A, 6, 23, 43); + Round3(&A,B,C,D, 9, 4, 44); + Round3(&D,A,B,C, 12, 11, 45); + Round3(&C,D,A,B, 15, 16, 46); + Round3(&B,C,D,A, 2, 23, 47); + + //Round 4 + Round4(&A,B,C,D, 0, 6, 48); + Round4(&D,A,B,C, 7, 10, 49); + Round4(&C,D,A,B, 14, 15, 50); + Round4(&B,C,D,A, 5, 21, 51); + Round4(&A,B,C,D, 12, 6, 52); + Round4(&D,A,B,C, 3, 10, 53); + Round4(&C,D,A,B, 10, 15, 54); + Round4(&B,C,D,A, 1, 21, 55); + Round4(&A,B,C,D, 8, 6, 56); + Round4(&D,A,B,C, 15, 10, 57); + Round4(&C,D,A,B, 6, 15, 58); + Round4(&B,C,D,A, 13, 21, 59); + Round4(&A,B,C,D, 4, 6, 60); + Round4(&D,A,B,C, 11, 10, 61); + Round4(&C,D,A,B, 2, 15, 62); + Round4(&B,C,D,A, 9, 21, 63); + + // Then perform the following additions. (let's add) + *A2 = A + AA; + *B2 = B + BB; + *C2 = C + CC; + *D2 = D + DD; + + //The clearance of confidential information + memset(pX, 0, sizeof(X)); } -static void MD5_String2binary(const char * string, unsigned char * output) +static void MD5_String2binary(const char *string, unsigned char *output) { -//var - /*8bit*/ - unsigned char padding_message[64]; //Extended message 512bit 64byte - unsigned char *pstring; //The position of string in the present scanning notes is held. - - /*32bit*/ - unsigned int string_byte_len, //The byte chief of string is held. - string_bit_len, //The bit length of string is held. - copy_len, //The number of bytes which is used by 1-3 and which remained - msg_digest[4]; //Message digest 128bit 4byte - unsigned int *A = &msg_digest[0], //The message digest in accordance with RFC (reference) - *B = &msg_digest[1], - *C = &msg_digest[2], - *D = &msg_digest[3]; - int i; - -//prog - //Step 3.Initialize MD Buffer (although it is the initialization; step 3 of A, B, C, and D -- unavoidable -- a head) - *A = 0x67452301; - *B = 0xefcdab89; - *C = 0x98badcfe; - *D = 0x10325476; - - //Step 1.Append Padding Bits (extension of a mark bit) - //1-1 - string_byte_len = (unsigned int)strlen(string); //The byte chief of a character sequence is acquired. - pstring = (unsigned char *)string; //The position of the present character sequence is set. - - //1-2 Repeat calculation until length becomes less than 64 bytes. - for (i=string_byte_len; 64<=i; i-=64,pstring+=64) + //var + /*8bit*/ + unsigned char padding_message[64]; //Extended message 512bit 64byte + unsigned char *pstring; //The position of string in the present scanning notes is held. + + /*32bit*/ + unsigned int string_byte_len, //The byte chief of string is held. + string_bit_len, //The bit length of string is held. + copy_len, //The number of bytes which is used by 1-3 and which remained + msg_digest[4]; //Message digest 128bit 4byte + unsigned int *A = &msg_digest[0], //The message digest in accordance with RFC (reference) + *B = &msg_digest[1], + *C = &msg_digest[2], + *D = &msg_digest[3]; + int i; + + //prog + //Step 3.Initialize MD Buffer (although it is the initialization; step 3 of A, B, C, and D -- unavoidable -- a head) + *A = 0x67452301; + *B = 0xefcdab89; + *C = 0x98badcfe; + *D = 0x10325476; + + //Step 1.Append Padding Bits (extension of a mark bit) + //1-1 + string_byte_len = (unsigned int)strlen(string); //The byte chief of a character sequence is acquired. + pstring = (unsigned char *)string; //The position of the present character sequence is set. + + //1-2 Repeat calculation until length becomes less than 64 bytes. + for (i=string_byte_len; 64<=i; i-=64,pstring+=64) MD5_Round_Calculate(pstring, A,B,C,D); - //1-3 - copy_len = string_byte_len % 64; //The number of bytes which remained is computed. - strncpy((char *)padding_message, (char *)pstring, copy_len); //A message is copied to an extended bit sequence. - memset(padding_message+copy_len, 0, 64 - copy_len); //It buries by 0 until it becomes extended bit length. - padding_message[copy_len] |= 0x80; //The next of a message is 1. - - //1-4 - //If 56 bytes or more (less than 64 bytes) of remainder becomes, it will calculate by extending to 64 bytes. - if (56 <= copy_len) { - MD5_Round_Calculate(padding_message, A,B,C,D); - memset(padding_message, 0, 56); //56 bytes is newly fill uped with 0. - } - - //Step 2.Append Length (the information on length is added) - string_bit_len = string_byte_len * 8; //From the byte chief to bit length (32 bytes of low rank) - memcpy(&padding_message[56], &string_bit_len, 4); //32 bytes of low rank is set. - - //When bit length cannot be expressed in 32 bytes of low rank, it is a beam raising to a higher rank. - if (UINT_MAX / 8 < string_byte_len) { - unsigned int high = (string_byte_len - UINT_MAX / 8) * 8; - memcpy(&padding_message[60], &high, 4); - } else - memset(&padding_message[60], 0, 4); //In this case, it is good for a higher rank at 0. - - //Step 4.Process Message in 16-Word Blocks (calculation of MD5) - MD5_Round_Calculate(padding_message, A,B,C,D); - - //Step 5.Output (output) - memcpy(output,msg_digest,16); + //1-3 + copy_len = string_byte_len % 64; //The number of bytes which remained is computed. + strncpy((char *)padding_message, (char *)pstring, copy_len); //A message is copied to an extended bit sequence. + memset(padding_message+copy_len, 0, 64 - copy_len); //It buries by 0 until it becomes extended bit length. + padding_message[copy_len] |= 0x80; //The next of a message is 1. + + //1-4 + //If 56 bytes or more (less than 64 bytes) of remainder becomes, it will calculate by extending to 64 bytes. + if (56 <= copy_len) { + MD5_Round_Calculate(padding_message, A,B,C,D); + memset(padding_message, 0, 56); //56 bytes is newly fill uped with 0. + } + + //Step 2.Append Length (the information on length is added) + string_bit_len = string_byte_len * 8; //From the byte chief to bit length (32 bytes of low rank) + memcpy(&padding_message[56], &string_bit_len, 4); //32 bytes of low rank is set. + + //When bit length cannot be expressed in 32 bytes of low rank, it is a beam raising to a higher rank. + if (UINT_MAX / 8 < string_byte_len) { + unsigned int high = (string_byte_len - UINT_MAX / 8) * 8; + memcpy(&padding_message[60], &high, 4); + } else + memset(&padding_message[60], 0, 4); //In this case, it is good for a higher rank at 0. + + //Step 4.Process Message in 16-Word Blocks (calculation of MD5) + MD5_Round_Calculate(padding_message, A,B,C,D); + + //Step 5.Output (output) + memcpy(output,msg_digest,16); } //------------------------------------------------------------------- // The function for the exteriors /** output is the coded binary in the character sequence which wants to code string. */ -void MD5_Binary(const char * string, unsigned char * output) +void MD5_Binary(const char *string, unsigned char *output) { - MD5_String2binary(string,output); + MD5_String2binary(string,output); } /** output is the coded character sequence in the character sequence which wants to code string. */ -void MD5_String(const char * string, char * output) +void MD5_String(const char *string, char *output) { - unsigned char digest[16]; - - MD5_String2binary(string,digest); - sprintf(output, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - digest[ 0], digest[ 1], digest[ 2], digest[ 3], - digest[ 4], digest[ 5], digest[ 6], digest[ 7], - digest[ 8], digest[ 9], digest[10], digest[11], - digest[12], digest[13], digest[14], digest[15]); + unsigned char digest[16]; + + MD5_String2binary(string,digest); + sprintf(output, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + digest[ 0], digest[ 1], digest[ 2], digest[ 3], + digest[ 4], digest[ 5], digest[ 6], digest[ 7], + digest[ 8], digest[ 9], digest[10], digest[11], + digest[12], digest[13], digest[14], digest[15]); } /** output is a sequence of non-zero characters to be used as password salt. */ -void MD5_Salt(unsigned int len, char * output) +void MD5_Salt(unsigned int len, char *output) { - unsigned int i; - for( i = 0; i < len; ++i ) - output[i] = (char)(1 + rnd() % 255); + unsigned int i; + for (i = 0; i < len; ++i) + output[i] = (char)(1 + rnd() % 255); } diff --git a/src/common/md5calc.h b/src/common/md5calc.h index 323affa2c..4a112a660 100644 --- a/src/common/md5calc.h +++ b/src/common/md5calc.h @@ -1,8 +1,8 @@ #ifndef _MD5CALC_H_ #define _MD5CALC_H_ -void MD5_String(const char * string, char * output); -void MD5_Binary(const char * string, unsigned char * output); -void MD5_Salt(unsigned int len, char * output); +void MD5_String(const char *string, char *output); +void MD5_Binary(const char *string, unsigned char *output); +void MD5_Salt(unsigned int len, char *output); #endif /* _MD5CALC_H_ */ diff --git a/src/common/mempool.c b/src/common/mempool.c index 35b03034d..62db7b9e3 100644 --- a/src/common/mempool.c +++ b/src/common/mempool.c @@ -30,9 +30,9 @@ #include "../common/malloc.h" #include "../common/mutex.h" -#define ALIGN16 ra_align(16) +#define ALIGN16 ra_align(16) #define ALIGN_TO(x, a) (x + ( a - ( x % a) ) ) -#define ALIGN_TO_16(x) ALIGN_TO(x, 16) +#define ALIGN_TO_16(x) ALIGN_TO(x, 16) #undef MEMPOOL_DEBUG #define MEMPOOLASSERT @@ -40,523 +40,532 @@ #define NODE_TO_DATA(x) ( ((char*)x) + sizeof(struct node) ) #define DATA_TO_NODE(x) ( (struct node*)(((char*)x) - sizeof(struct node)) ) -struct ra_align(16) node{ - void *next; - void *segment; +struct ra_align(16) node { + void *next; + void *segment; #ifdef MEMPOOLASSERT - bool used; - uint64 magic; - #define NODE_MAGIC 0xBEEF00EAEACAFE07ll + bool used; + uint64 magic; +#define NODE_MAGIC 0xBEEF00EAEACAFE07ll #endif }; // The Pointer to this struct is the base address of the segment itself. -struct pool_segment{ - mempool pool; // pool, this segment belongs to - struct pool_segment *next; - int64 num_nodes_total; - int64 num_bytes; +struct pool_segment { + mempool pool; // pool, this segment belongs to + struct pool_segment *next; + int64 num_nodes_total; + int64 num_bytes; }; -struct mempool{ - // Settings - char *name; - uint64 elem_size; - uint64 elem_realloc_step; - int64 elem_realloc_thresh; - - // Callbacks that get called for every node that gets allocated - // Example usage: initialization of mutex/lock for each node. - memPoolOnNodeAllocationProc onalloc; - memPoolOnNodeDeallocationProc ondealloc; - - // Locks - SPIN_LOCK segmentLock; - SPIN_LOCK nodeLock; - - - // Internal - struct pool_segment *segments; - struct node *free_list; - - volatile int64 num_nodes_total; - volatile int64 num_nodes_free; - - volatile int64 num_segments; - volatile int64 num_bytes_total; - - volatile int64 peak_nodes_used; // Peak Node Usage - volatile int64 num_realloc_events; // Number of reallocations done. (allocate additional nodes) - - // list (used for global management such as allocator..) - struct mempool *next; +struct mempool { + // Settings + char *name; + uint64 elem_size; + uint64 elem_realloc_step; + int64 elem_realloc_thresh; + + // Callbacks that get called for every node that gets allocated + // Example usage: initialization of mutex/lock for each node. + memPoolOnNodeAllocationProc onalloc; + memPoolOnNodeDeallocationProc ondealloc; + + // Locks + SPIN_LOCK segmentLock; + SPIN_LOCK nodeLock; + + + // Internal + struct pool_segment *segments; + struct node *free_list; + + volatile int64 num_nodes_total; + volatile int64 num_nodes_free; + + volatile int64 num_segments; + volatile int64 num_bytes_total; + + volatile int64 peak_nodes_used; // Peak Node Usage + volatile int64 num_realloc_events; // Number of reallocations done. (allocate additional nodes) + + // list (used for global management such as allocator..) + struct mempool *next; } ra_align(8); // Dont touch the alignment, otherwise interlocked functions are broken .. -/// +/// // Implementation: // static void segment_allocate_add(mempool p, uint64 count); static SPIN_LOCK l_mempoolListLock; -static mempool l_mempoolList = NULL; +static mempool l_mempoolList = NULL; static rAthread l_async_thread = NULL; -static ramutex l_async_lock = NULL; -static racond l_async_cond = NULL; +static ramutex l_async_lock = NULL; +static racond l_async_cond = NULL; static volatile int32 l_async_terminate = 0; -static void *mempool_async_allocator(void *x){ - mempool p; - - - while(1){ - if(l_async_terminate > 0) - break; - - EnterSpinLock(&l_mempoolListLock); - - for(p = l_mempoolList; p != NULL; p = p->next){ - - if(p->num_nodes_free < p->elem_realloc_thresh){ - // add new segment. - segment_allocate_add(p, p->elem_realloc_step); - // increase stats counter - InterlockedIncrement64(&p->num_realloc_events); - } - - } - - LeaveSpinLock(&l_mempoolListLock); - - ramutex_lock( l_async_lock ); - racond_wait( l_async_cond, l_async_lock, -1 ); - ramutex_unlock( l_async_lock ); - } - - - return NULL; +static void *mempool_async_allocator(void *x) +{ + mempool p; + + + while (1) { + if (l_async_terminate > 0) + break; + + EnterSpinLock(&l_mempoolListLock); + + for (p = l_mempoolList; p != NULL; p = p->next) { + + if (p->num_nodes_free < p->elem_realloc_thresh) { + // add new segment. + segment_allocate_add(p, p->elem_realloc_step); + // increase stats counter + InterlockedIncrement64(&p->num_realloc_events); + } + + } + + LeaveSpinLock(&l_mempoolListLock); + + ramutex_lock(l_async_lock); + racond_wait(l_async_cond, l_async_lock, -1); + ramutex_unlock(l_async_lock); + } + + + return NULL; }//end: mempool_async_allocator() -void mempool_init(){ - - if(sizeof(struct node)%16 != 0 ){ - ShowFatalError("mempool_init: struct node alignment failure. %u != multiple of 16\n", sizeof(struct node)); - exit(EXIT_FAILURE); - } - - // Global List start - InitializeSpinLock(&l_mempoolListLock); - l_mempoolList = NULL; - - // Initialize mutex + stuff needed for async allocator worker. - l_async_terminate = 0; - l_async_lock = ramutex_create(); - l_async_cond = racond_create(); - - l_async_thread = rathread_createEx(mempool_async_allocator, NULL, 1024*1024, RAT_PRIO_NORMAL); - if(l_async_thread == NULL){ - ShowFatalError("mempool_init: cannot spawn Async Allocator Thread.\n"); - exit(EXIT_FAILURE); - } +void mempool_init() +{ + + if (sizeof(struct node)%16 != 0) { + ShowFatalError("mempool_init: struct node alignment failure. %u != multiple of 16\n", sizeof(struct node)); + exit(EXIT_FAILURE); + } + + // Global List start + InitializeSpinLock(&l_mempoolListLock); + l_mempoolList = NULL; + + // Initialize mutex + stuff needed for async allocator worker. + l_async_terminate = 0; + l_async_lock = ramutex_create(); + l_async_cond = racond_create(); + + l_async_thread = rathread_createEx(mempool_async_allocator, NULL, 1024*1024, RAT_PRIO_NORMAL); + if (l_async_thread == NULL) { + ShowFatalError("mempool_init: cannot spawn Async Allocator Thread.\n"); + exit(EXIT_FAILURE); + } }//end: mempool_init() -void mempool_final(){ - mempool p, pn; - - ShowStatus("Mempool: Terminating async. allocation worker and remaining pools.\n"); - - // Terminate worker / wait until its terminated. - InterlockedIncrement(&l_async_terminate); - racond_signal(l_async_cond); - rathread_wait(l_async_thread, NULL); - - // Destroy cond var and mutex. - racond_destroy( l_async_cond ); - ramutex_destroy( l_async_lock ); - - // Free remaining mempools - // ((bugged code! this should halppen, every mempool should - // be freed by the subsystem that has allocated it.) - // - EnterSpinLock(&l_mempoolListLock); - p = l_mempoolList; - while(1){ - if(p == NULL) - break; - - pn = p->next; - - ShowWarning("Mempool [%s] was not properly destroyed - forcing destroy.\n", p->name); - mempool_destroy(p); - - p = pn; - } - LeaveSpinLock(&l_mempoolListLock); - +void mempool_final() +{ + mempool p, pn; + + ShowStatus("Mempool: Terminating async. allocation worker and remaining pools.\n"); + + // Terminate worker / wait until its terminated. + InterlockedIncrement(&l_async_terminate); + racond_signal(l_async_cond); + rathread_wait(l_async_thread, NULL); + + // Destroy cond var and mutex. + racond_destroy(l_async_cond); + ramutex_destroy(l_async_lock); + + // Free remaining mempools + // ((bugged code! this should halppen, every mempool should + // be freed by the subsystem that has allocated it.) + // + EnterSpinLock(&l_mempoolListLock); + p = l_mempoolList; + while (1) { + if (p == NULL) + break; + + pn = p->next; + + ShowWarning("Mempool [%s] was not properly destroyed - forcing destroy.\n", p->name); + mempool_destroy(p); + + p = pn; + } + LeaveSpinLock(&l_mempoolListLock); + }//end: mempool_final() -static void segment_allocate_add(mempool p, uint64 count){ - - // Required Memory: - // sz( segment ) - // count * sz( real_node_size ) - // - // where real node size is: - // ALIGN_TO_16( sz( node ) ) + p->elem_size - // so the nodes usable address is nodebase + ALIGN_TO_16(sz(node)) - // - size_t total_sz; - struct pool_segment *seg = NULL; - struct node *nodeList = NULL; - struct node *node = NULL; - char *ptr = NULL; - uint64 i; - - total_sz = ALIGN_TO_16( sizeof(struct pool_segment) ) - + ( (size_t)count * (sizeof(struct node) + (size_t)p->elem_size) ) ; +static void segment_allocate_add(mempool p, uint64 count) +{ + + // Required Memory: + // sz( segment ) + // count * sz( real_node_size ) + // + // where real node size is: + // ALIGN_TO_16( sz( node ) ) + p->elem_size + // so the nodes usable address is nodebase + ALIGN_TO_16(sz(node)) + // + size_t total_sz; + struct pool_segment *seg = NULL; + struct node *nodeList = NULL; + struct node *node = NULL; + char *ptr = NULL; + uint64 i; + + total_sz = ALIGN_TO_16(sizeof(struct pool_segment)) + + ((size_t)count * (sizeof(struct node) + (size_t)p->elem_size)) ; #ifdef MEMPOOL_DEBUG - ShowDebug("Mempool [%s] Segment AllocateAdd (num: %u, total size: %0.2fMiB)\n", p->name, count, (float)total_sz/1024.f/1024.f); + ShowDebug("Mempool [%s] Segment AllocateAdd (num: %u, total size: %0.2fMiB)\n", p->name, count, (float)total_sz/1024.f/1024.f); #endif - // allocate! (spin forever until weve got the memory.) - i=0; - while(1){ - ptr = (char*)aMalloc(total_sz); - if(ptr != NULL) break; - - i++; // increase failcount. - if(!(i & 7)){ - ShowWarning("Mempool [%s] Segment AllocateAdd => System seems to be Out of Memory (%0.2f MiB). Try #%u\n", (float)total_sz/1024.f/1024.f, i); + // allocate! (spin forever until weve got the memory.) + i=0; + while (1) { + ptr = (char *)aMalloc(total_sz); + if (ptr != NULL) break; + + i++; // increase failcount. + if (!(i & 7)) { + ShowWarning("Mempool [%s] Segment AllocateAdd => System seems to be Out of Memory (%0.2f MiB). Try #%u\n", (float)total_sz/1024.f/1024.f, i); #ifdef WIN32 - Sleep(1000); + Sleep(1000); #else - sleep(1); + sleep(1); #endif - }else{ - rathread_yield(); /// allow/force vuln. ctxswitch - } - }//endwhile: allocation spinloop. - - // Clear Memory. - memset(ptr, 0x00, total_sz); - - // Initialize segment struct. - seg = (struct pool_segment*)ptr; - ptr += ALIGN_TO_16(sizeof(struct pool_segment)); - - seg->pool = p; - seg->num_nodes_total = count; - seg->num_bytes = total_sz; - - - // Initialze nodes! - nodeList = NULL; - for(i = 0; i < count; i++){ - node = (struct node*)ptr; - ptr += sizeof(struct node); - ptr += p->elem_size; - - node->segment = seg; + } else { + rathread_yield(); /// allow/force vuln. ctxswitch + } + }//endwhile: allocation spinloop. + + // Clear Memory. + memset(ptr, 0x00, total_sz); + + // Initialize segment struct. + seg = (struct pool_segment *)ptr; + ptr += ALIGN_TO_16(sizeof(struct pool_segment)); + + seg->pool = p; + seg->num_nodes_total = count; + seg->num_bytes = total_sz; + + + // Initialze nodes! + nodeList = NULL; + for (i = 0; i < count; i++) { + node = (struct node *)ptr; + ptr += sizeof(struct node); + ptr += p->elem_size; + + node->segment = seg; #ifdef MEMPOOLASSERT - node->used = false; - node->magic = NODE_MAGIC; + node->used = false; + node->magic = NODE_MAGIC; #endif - if(p->onalloc != NULL) p->onalloc( NODE_TO_DATA(node) ); - - node->next = nodeList; - nodeList = node; - } - - - - // Link in Segment. - EnterSpinLock(&p->segmentLock); - seg->next = p->segments; - p->segments = seg; - LeaveSpinLock(&p->segmentLock); - - // Link in Nodes - EnterSpinLock(&p->nodeLock); - nodeList->next = p->free_list; - p->free_list = nodeList; - LeaveSpinLock(&p->nodeLock); - - - // Increase Stats: - InterlockedExchangeAdd64(&p->num_nodes_total, count); - InterlockedExchangeAdd64(&p->num_nodes_free, count); - InterlockedIncrement64(&p->num_segments); - InterlockedExchangeAdd64(&p->num_bytes_total, total_sz); - + if (p->onalloc != NULL) p->onalloc(NODE_TO_DATA(node)); + + node->next = nodeList; + nodeList = node; + } + + + + // Link in Segment. + EnterSpinLock(&p->segmentLock); + seg->next = p->segments; + p->segments = seg; + LeaveSpinLock(&p->segmentLock); + + // Link in Nodes + EnterSpinLock(&p->nodeLock); + nodeList->next = p->free_list; + p->free_list = nodeList; + LeaveSpinLock(&p->nodeLock); + + + // Increase Stats: + InterlockedExchangeAdd64(&p->num_nodes_total, count); + InterlockedExchangeAdd64(&p->num_nodes_free, count); + InterlockedIncrement64(&p->num_segments); + InterlockedExchangeAdd64(&p->num_bytes_total, total_sz); + }//end: segment_allocate_add() mempool mempool_create(const char *name, - uint64 elem_size, - uint64 initial_count, - uint64 realloc_count, - memPoolOnNodeAllocationProc onNodeAlloc, - memPoolOnNodeDeallocationProc onNodeDealloc){ - //.. - uint64 realloc_thresh; - mempool pool; - pool = (mempool)aCalloc( 1, sizeof(struct mempool) ); - - if(pool == NULL){ - ShowFatalError("mempool_create: Failed to allocate %u bytes memory.\n", sizeof(struct mempool) ); - exit(EXIT_FAILURE); - } - - // Check minimum initial count / realloc count requirements. - if(initial_count < 50) - initial_count = 50; - if(realloc_count < 50) - realloc_count = 50; - - // Set Reallocation threshold to 5% of realloc_count, at least 10. - realloc_thresh = (realloc_count/100)*5; // - if(realloc_thresh < 10) - realloc_thresh = 10; - - // Initialize members.. - pool->name = aStrdup(name); - pool->elem_size = ALIGN_TO_16(elem_size); - pool->elem_realloc_step = realloc_count; - pool->elem_realloc_thresh = realloc_thresh; - pool->onalloc = onNodeAlloc; - pool->ondealloc = onNodeDealloc; - - InitializeSpinLock(&pool->segmentLock); - InitializeSpinLock(&pool->nodeLock); - - // Initial Statistic values: - pool->num_nodes_total = 0; - pool->num_nodes_free = 0; - pool->num_segments = 0; - pool->num_bytes_total = 0; - pool->peak_nodes_used = 0; - pool->num_realloc_events = 0; - - // + uint64 elem_size, + uint64 initial_count, + uint64 realloc_count, + memPoolOnNodeAllocationProc onNodeAlloc, + memPoolOnNodeDeallocationProc onNodeDealloc) +{ + //.. + uint64 realloc_thresh; + mempool pool; + pool = (mempool)aCalloc(1, sizeof(struct mempool)); + + if (pool == NULL) { + ShowFatalError("mempool_create: Failed to allocate %u bytes memory.\n", sizeof(struct mempool)); + exit(EXIT_FAILURE); + } + + // Check minimum initial count / realloc count requirements. + if (initial_count < 50) + initial_count = 50; + if (realloc_count < 50) + realloc_count = 50; + + // Set Reallocation threshold to 5% of realloc_count, at least 10. + realloc_thresh = (realloc_count/100)*5; // + if (realloc_thresh < 10) + realloc_thresh = 10; + + // Initialize members.. + pool->name = aStrdup(name); + pool->elem_size = ALIGN_TO_16(elem_size); + pool->elem_realloc_step = realloc_count; + pool->elem_realloc_thresh = realloc_thresh; + pool->onalloc = onNodeAlloc; + pool->ondealloc = onNodeDealloc; + + InitializeSpinLock(&pool->segmentLock); + InitializeSpinLock(&pool->nodeLock); + + // Initial Statistic values: + pool->num_nodes_total = 0; + pool->num_nodes_free = 0; + pool->num_segments = 0; + pool->num_bytes_total = 0; + pool->peak_nodes_used = 0; + pool->num_realloc_events = 0; + + // #ifdef MEMPOOL_DEBUG - ShowDebug("Mempool [%s] Init (ElemSize: %u, Initial Count: %u, Realloc Count: %u)\n", pool->name, pool->elem_size, initial_count, pool->elem_realloc_step); + ShowDebug("Mempool [%s] Init (ElemSize: %u, Initial Count: %u, Realloc Count: %u)\n", pool->name, pool->elem_size, initial_count, pool->elem_realloc_step); #endif - // Allocate first segment directly :) - segment_allocate_add(pool, initial_count); - + // Allocate first segment directly :) + segment_allocate_add(pool, initial_count); + + + // Add Pool to the global pool list + EnterSpinLock(&l_mempoolListLock); + pool->next = l_mempoolList; + l_mempoolList = pool; + LeaveSpinLock(&l_mempoolListLock); - // Add Pool to the global pool list - EnterSpinLock(&l_mempoolListLock); - pool->next = l_mempoolList; - l_mempoolList = pool; - LeaveSpinLock(&l_mempoolListLock); - - return pool; + return pool; }//end: mempool_create() -void mempool_destroy(mempool p){ - struct pool_segment *seg, *segnext; - struct node *niter; - mempool piter, pprev; - char *ptr; - int64 i; +void mempool_destroy(mempool p) +{ + struct pool_segment *seg, *segnext; + struct node *niter; + mempool piter, pprev; + char *ptr; + int64 i; #ifdef MEMPOOL_DEBUG ShowDebug("Mempool [%s] Destroy\n", p->name); #endif - - // Unlink from global list. - EnterSpinLock(&l_mempoolListLock); - piter = l_mempoolList; - pprev = l_mempoolList; - while(1){ - if(piter == NULL) - break; - - - if(piter == p){ - // unlink from list, - // - if(pprev == l_mempoolList){ - // this (p) is list begin. so set next as head. - l_mempoolList = p->next; - }else{ - // replace prevs next wuth our next. - pprev->next = p->next; - } - break; - } - - pprev = piter; - piter = piter->next; - } - - p->next = NULL; - LeaveSpinLock(&l_mempoolListLock); - - - // Get both locks. - EnterSpinLock(&p->segmentLock); - EnterSpinLock(&p->nodeLock); - - - if(p->num_nodes_free != p->num_nodes_total) - ShowWarning("Mempool [%s] Destroy - %u nodes are not freed properly!\n", p->name, (p->num_nodes_total - p->num_nodes_free) ); - - // Free All Segments (this will also free all nodes) - // The segment pointer is the base pointer to the whole segment. - seg = p->segments; - while(1){ - if(seg == NULL) - break; - - segnext = seg->next; - - // .. - if(p->ondealloc != NULL){ - // walk over the segment, and call dealloc callback! - ptr = (char*)seg; - ptr += ALIGN_TO_16(sizeof(struct pool_segment)); - for(i = 0; i < seg->num_nodes_total; i++){ - niter = (struct node*)ptr; - ptr += sizeof(struct node); - ptr += p->elem_size; + + // Unlink from global list. + EnterSpinLock(&l_mempoolListLock); + piter = l_mempoolList; + pprev = l_mempoolList; + while (1) { + if (piter == NULL) + break; + + + if (piter == p) { + // unlink from list, + // + if (pprev == l_mempoolList) { + // this (p) is list begin. so set next as head. + l_mempoolList = p->next; + } else { + // replace prevs next wuth our next. + pprev->next = p->next; + } + break; + } + + pprev = piter; + piter = piter->next; + } + + p->next = NULL; + LeaveSpinLock(&l_mempoolListLock); + + + // Get both locks. + EnterSpinLock(&p->segmentLock); + EnterSpinLock(&p->nodeLock); + + + if (p->num_nodes_free != p->num_nodes_total) + ShowWarning("Mempool [%s] Destroy - %u nodes are not freed properly!\n", p->name, (p->num_nodes_total - p->num_nodes_free)); + + // Free All Segments (this will also free all nodes) + // The segment pointer is the base pointer to the whole segment. + seg = p->segments; + while (1) { + if (seg == NULL) + break; + + segnext = seg->next; + + // .. + if (p->ondealloc != NULL) { + // walk over the segment, and call dealloc callback! + ptr = (char *)seg; + ptr += ALIGN_TO_16(sizeof(struct pool_segment)); + for (i = 0; i < seg->num_nodes_total; i++) { + niter = (struct node *)ptr; + ptr += sizeof(struct node); + ptr += p->elem_size; #ifdef MEMPOOLASSERT - if(niter->magic != NODE_MAGIC){ - ShowError("Mempool [%s] Destroy - walk over segment - node %p invalid magic!\n", p->name, niter); - continue; - } + if (niter->magic != NODE_MAGIC) { + ShowError("Mempool [%s] Destroy - walk over segment - node %p invalid magic!\n", p->name, niter); + continue; + } #endif - - p->ondealloc( NODE_TO_DATA(niter) ); - - - } - }//endif: ondealloc callback? - - // simple .. - aFree(seg); - - seg = segnext; - } - - // Clear node ptr - p->free_list = NULL; - InterlockedExchange64(&p->num_nodes_free, 0); - InterlockedExchange64(&p->num_nodes_total, 0); - InterlockedExchange64(&p->num_segments, 0); - InterlockedExchange64(&p->num_bytes_total, 0); - - LeaveSpinLock(&p->nodeLock); - LeaveSpinLock(&p->segmentLock); - - // Free pool itself :D - aFree(p->name); - aFree(p); + + p->ondealloc(NODE_TO_DATA(niter)); + + + } + }//endif: ondealloc callback? + + // simple .. + aFree(seg); + + seg = segnext; + } + + // Clear node ptr + p->free_list = NULL; + InterlockedExchange64(&p->num_nodes_free, 0); + InterlockedExchange64(&p->num_nodes_total, 0); + InterlockedExchange64(&p->num_segments, 0); + InterlockedExchange64(&p->num_bytes_total, 0); + + LeaveSpinLock(&p->nodeLock); + LeaveSpinLock(&p->segmentLock); + + // Free pool itself :D + aFree(p->name); + aFree(p); }//end: mempool_destroy() -void *mempool_node_get(mempool p){ - struct node *node; - int64 num_used; - - if(p->num_nodes_free < p->elem_realloc_thresh) - racond_signal(l_async_cond); - - while(1){ - - EnterSpinLock(&p->nodeLock); - - node = p->free_list; - if(node != NULL) - p->free_list = node->next; - - LeaveSpinLock(&p->nodeLock); - - if(node != NULL) - break; - - rathread_yield(); - } - - InterlockedDecrement64(&p->num_nodes_free); - - // Update peak value - num_used = (p->num_nodes_total - p->num_nodes_free); - if(num_used > p->peak_nodes_used){ - InterlockedExchange64(&p->peak_nodes_used, num_used); - } - +void *mempool_node_get(mempool p) +{ + struct node *node; + int64 num_used; + + if (p->num_nodes_free < p->elem_realloc_thresh) + racond_signal(l_async_cond); + + while (1) { + + EnterSpinLock(&p->nodeLock); + + node = p->free_list; + if (node != NULL) + p->free_list = node->next; + + LeaveSpinLock(&p->nodeLock); + + if (node != NULL) + break; + + rathread_yield(); + } + + InterlockedDecrement64(&p->num_nodes_free); + + // Update peak value + num_used = (p->num_nodes_total - p->num_nodes_free); + if (num_used > p->peak_nodes_used) { + InterlockedExchange64(&p->peak_nodes_used, num_used); + } + #ifdef MEMPOOLASSERT - node->used = true; + node->used = true; #endif - return NODE_TO_DATA(node); + return NODE_TO_DATA(node); }//end: mempool_node_get() -void mempool_node_put(mempool p, void *data){ - struct node *node; - - node = DATA_TO_NODE(data); +void mempool_node_put(mempool p, void *data) +{ + struct node *node; + + node = DATA_TO_NODE(data); #ifdef MEMPOOLASSERT - if(node->magic != NODE_MAGIC){ - ShowError("Mempool [%s] node_put failed, given address (%p) has invalid magic.\n", p->name, data); - return; // lost, - } - - { - struct pool_segment *node_seg = node->segment; - if(node_seg->pool != p){ - ShowError("Mempool [%s] node_put faild, given node (data address %p) doesnt belongs to this pool. ( Node Origin is [%s] )\n", p->name, data, node_seg->pool); - return; - } - } - - // reset used flag. - node->used = false; + if (node->magic != NODE_MAGIC) { + ShowError("Mempool [%s] node_put failed, given address (%p) has invalid magic.\n", p->name, data); + return; // lost, + } + + { + struct pool_segment *node_seg = node->segment; + if (node_seg->pool != p) { + ShowError("Mempool [%s] node_put faild, given node (data address %p) doesnt belongs to this pool. ( Node Origin is [%s] )\n", p->name, data, node_seg->pool); + return; + } + } + + // reset used flag. + node->used = false; #endif - // - EnterSpinLock(&p->nodeLock); - node->next = p->free_list; - p->free_list = node; - LeaveSpinLock(&p->nodeLock); - - InterlockedIncrement64(&p->num_nodes_free); + // + EnterSpinLock(&p->nodeLock); + node->next = p->free_list; + p->free_list = node; + LeaveSpinLock(&p->nodeLock); + + InterlockedIncrement64(&p->num_nodes_free); }//end: mempool_node_put() -mempool_stats mempool_get_stats(mempool pool){ - mempool_stats stats; - - // initialize all with zeros - memset(&stats, 0x00, sizeof(mempool_stats)); - - stats.num_nodes_total = pool->num_nodes_total; - stats.num_nodes_free = pool->num_nodes_free; - stats.num_nodes_used = (stats.num_nodes_total - stats.num_nodes_free); - stats.num_segments = pool->num_segments; - stats.num_realloc_events= pool->num_realloc_events; - stats.peak_nodes_used = pool->peak_nodes_used; - stats.num_bytes_total = pool->num_bytes_total; - - // Pushing such a large block over the stack as return value isnt nice - // but lazy :) and should be okay in this case (Stats / Debug..) - // if you dont like it - feel free and refactor it. - return stats; +mempool_stats mempool_get_stats(mempool pool) +{ + mempool_stats stats; + + // initialize all with zeros + memset(&stats, 0x00, sizeof(mempool_stats)); + + stats.num_nodes_total = pool->num_nodes_total; + stats.num_nodes_free = pool->num_nodes_free; + stats.num_nodes_used = (stats.num_nodes_total - stats.num_nodes_free); + stats.num_segments = pool->num_segments; + stats.num_realloc_events= pool->num_realloc_events; + stats.peak_nodes_used = pool->peak_nodes_used; + stats.num_bytes_total = pool->num_bytes_total; + + // Pushing such a large block over the stack as return value isnt nice + // but lazy :) and should be okay in this case (Stats / Debug..) + // if you dont like it - feel free and refactor it. + return stats; }//end: mempool_get_stats() diff --git a/src/common/mempool.h b/src/common/mempool.h index aeaebe7fe..9c4f1563e 100644 --- a/src/common/mempool.h +++ b/src/common/mempool.h @@ -8,67 +8,67 @@ typedef struct mempool *mempool; typedef void (*memPoolOnNodeAllocationProc)(void *ptr); typedef void (*memPoolOnNodeDeallocationProc)(void *ptr); -typedef struct mempool_stats{ - int64 num_nodes_total; - int64 num_nodes_free; - int64 num_nodes_used; - - int64 num_segments; - int64 num_realloc_events; - - int64 peak_nodes_used; - - int64 num_bytes_total; +typedef struct mempool_stats { + int64 num_nodes_total; + int64 num_nodes_free; + int64 num_nodes_used; + + int64 num_segments; + int64 num_realloc_events; + + int64 peak_nodes_used; + + int64 num_bytes_total; } mempool_stats; -// +// void mempool_init(); void mempool_final(); -/** +/** * Creates a new Mempool * * @param name - Name of the pool (used for debug / error messages) * @param elem_size - size of each element - * @param initial_count - preallocation count + * @param initial_count - preallocation count * @param realloc_count - #no of nodes being allocated when pool is running empty. * @param onNodeAlloc - Node Allocation callback (see @note!) * @param onNodeDealloc - Node Deallocation callback (see @note!) * * @note: - * The onNode(De)alloc callbacks are only called once during segment allocation - * (pool initialization / rallocation ) + * The onNode(De)alloc callbacks are only called once during segment allocation + * (pool initialization / rallocation ) * you can use this callbacks for example to initlaize a mutex or somethingelse - * you definitly need during runtime + * you definitly need during runtime * * @return not NULL */ mempool mempool_create(const char *name, - uint64 elem_size, - uint64 initial_count, - uint64 realloc_count, - - memPoolOnNodeAllocationProc onNodeAlloc, - memPoolOnNodeDeallocationProc onNodeDealloc); - - + uint64 elem_size, + uint64 initial_count, + uint64 realloc_count, + + memPoolOnNodeAllocationProc onNodeAlloc, + memPoolOnNodeDeallocationProc onNodeDealloc); + + /** * Destroys a Mempool - * + * * @param pool - the mempool to destroy * * @note: - * Everything gets deallocated, regardless if everything was freed properly! - * So you have to ensure that all references are cleared properly! + * Everything gets deallocated, regardless if everything was freed properly! + * So you have to ensure that all references are cleared properly! */ void mempool_destroy(mempool pool); /** * Gets a new / empty node from the given mempool. - * + * * @param pool - the pool to get an empty node from. * * @return Address of empty Node @@ -80,12 +80,12 @@ void *mempool_node_get(mempool pool); * Returns the given node to the given mempool * * @param pool - the pool to put the node, to - * @param node - the node to return + * @param node - the node to return */ void mempool_node_put(mempool pool, void *node); -/** +/** * Returns Statistics for the given mempool * * @param pool - the pool to get thats for diff --git a/src/common/mmo.h b/src/common/mmo.h index 5f6108b33..4236eb4c6 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -1,8 +1,8 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _MMO_H_ -#define _MMO_H_ +#ifndef _MMO_H_ +#define _MMO_H_ #include "cbasetypes.h" #include @@ -46,25 +46,25 @@ // 20120307 - 2012-03-07aRagexeRE+ - 0x970 #ifndef PACKETVER - #define PACKETVER 20120410 - //#define PACKETVER 20111116 +#define PACKETVER 20120410 +//#define PACKETVER 20111116 #endif //Remove/Comment this line to disable sc_data saving. [Skotlex] -#define ENABLE_SC_SAVING +#define ENABLE_SC_SAVING //Remove/Comment this line to disable server-side hot-key saving support [Skotlex] //Note that newer clients no longer save hotkeys in the registry! #define HOTKEY_SAVING #if PACKETVER < 20090603 - // (27 = 9 skills x 3 bars) (0x02b9,191) - #define MAX_HOTKEYS 27 +// (27 = 9 skills x 3 bars) (0x02b9,191) +#define MAX_HOTKEYS 27 #elif PACKETVER < 20090617 - // (36 = 9 skills x 4 bars) (0x07d9,254) - #define MAX_HOTKEYS 36 +// (36 = 9 skills x 4 bars) (0x07d9,254) +#define MAX_HOTKEYS 36 #else - // (38 = 9 skills x 4 bars & 2 Quickslots)(0x07d9,268) - #define MAX_HOTKEYS 38 +// (38 = 9 skills x 4 bars & 2 Quickslots)(0x07d9,268) +#define MAX_HOTKEYS 38 #endif #define MAX_MAP_PER_SERVER 1500 // Increased to allow creation of Instance Maps @@ -91,13 +91,13 @@ #define MAX_STORAGE 600 #define MAX_GUILD_STORAGE 600 #define MAX_PARTY 12 -#define MAX_GUILD 16+10*6 // increased max guild members +6 per 1 extension levels [Lupus] -#define MAX_GUILDPOSITION 20 // increased max guild positions to accomodate for all members [Valaris] (removed) [PoW] +#define MAX_GUILD 16+10*6 // increased max guild members +6 per 1 extension levels [Lupus] +#define MAX_GUILDPOSITION 20 // increased max guild positions to accomodate for all members [Valaris] (removed) [PoW] #define MAX_GUILDEXPULSION 32 #define MAX_GUILDALLIANCE 16 -#define MAX_GUILDSKILL 15 // increased max guild skills because of new skills [Sara-chan] +#define MAX_GUILDSKILL 15 // increased max guild skills because of new skills [Sara-chan] #define MAX_GUILDLEVEL 50 -#define MAX_GUARDIANS 8 //Local max per castle. [Skotlex] +#define MAX_GUARDIANS 8 //Local max per castle. [Skotlex] #define MAX_QUEST_DB 2000 //Max quests that the server will load #define MAX_QUEST_OBJECTIVES 3 //Max quest objectives for a quest @@ -140,7 +140,7 @@ //Base Homun skill. #define HM_SKILLBASE 8001 #define MAX_HOMUNSKILL 43 -#define MAX_HOMUNCULUS_CLASS 52 //[orn], Increased to 60 from 16 to allow new Homun-S. +#define MAX_HOMUNCULUS_CLASS 52 //[orn], Increased to 60 from 16 to allow new Homun-S. #define HM_CLASS_BASE 6001 #define HM_CLASS_MAX (HM_CLASS_BASE+MAX_HOMUNCULUS_CLASS-1) @@ -163,20 +163,20 @@ #define EL_CLASS_MAX (EL_CLASS_BASE+MAX_ELEMENTAL_CLASS-1) enum item_types { - IT_HEALING = 0, - IT_UNKNOWN, //1 - IT_USABLE, //2 - IT_ETC, //3 - IT_WEAPON, //4 - IT_ARMOR, //5 - IT_CARD, //6 - IT_PETEGG, //7 - IT_PETARMOR,//8 - IT_UNKNOWN2,//9 - IT_AMMO, //10 - IT_DELAYCONSUME,//11 - IT_CASH = 18, - IT_MAX + IT_HEALING = 0, + IT_UNKNOWN, //1 + IT_USABLE, //2 + IT_ETC, //3 + IT_WEAPON, //4 + IT_ARMOR, //5 + IT_CARD, //6 + IT_PETEGG, //7 + IT_PETARMOR,//8 + IT_UNKNOWN2,//9 + IT_AMMO, //10 + IT_DELAYCONSUME,//11 + IT_CASH = 18, + IT_MAX }; @@ -184,556 +184,555 @@ enum item_types { typedef enum quest_state { Q_INACTIVE, Q_ACTIVE, Q_COMPLETE } quest_state; struct quest { - int quest_id; - unsigned int time; - int count[MAX_QUEST_OBJECTIVES]; - quest_state state; + int quest_id; + unsigned int time; + int count[MAX_QUEST_OBJECTIVES]; + quest_state state; }; struct item { - int id; - short nameid; - short amount; - unsigned short equip; // location(s) where item is equipped (using enum equip_pos for bitmasking) - char identify; - char refine; - char attribute; - short card[MAX_SLOTS]; - unsigned int expire_time; - char favorite; + int id; + short nameid; + short amount; + unsigned short equip; // location(s) where item is equipped (using enum equip_pos for bitmasking) + char identify; + char refine; + char attribute; + short card[MAX_SLOTS]; + unsigned int expire_time; + char favorite; }; struct point { - unsigned short map; - short x,y; + unsigned short map; + short x,y; }; -enum e_skill_flag -{ - SKILL_FLAG_PERMANENT, - SKILL_FLAG_TEMPORARY, - SKILL_FLAG_PLAGIARIZED, - SKILL_FLAG_REPLACED_LV_0, // temporary skill overshadowing permanent skill of level 'N - SKILL_FLAG_REPLACED_LV_0' - //... +enum e_skill_flag { + SKILL_FLAG_PERMANENT, + SKILL_FLAG_TEMPORARY, + SKILL_FLAG_PLAGIARIZED, + SKILL_FLAG_REPLACED_LV_0, // temporary skill overshadowing permanent skill of level 'N - SKILL_FLAG_REPLACED_LV_0' + //... }; struct s_skill { - unsigned short id; - unsigned char lv; - unsigned char flag; // see enum e_skill_flag + unsigned short id; + unsigned char lv; + unsigned char flag; // see enum e_skill_flag }; struct global_reg { - char str[32]; - char value[256]; + char str[32]; + char value[256]; }; //Holds array of global registries, used by the char server and converter. struct accreg { - int account_id, char_id; - int reg_num; - struct global_reg reg[MAX_REG_NUM]; + int account_id, char_id; + int reg_num; + struct global_reg reg[MAX_REG_NUM]; }; //For saving status changes across sessions. [Skotlex] struct status_change_data { - unsigned short type; //SC_type - long val1, val2, val3, val4, tick; //Remaining duration. + unsigned short type; //SC_type + long val1, val2, val3, val4, tick; //Remaining duration. }; struct storage_data { - int storage_amount; - struct item items[MAX_STORAGE]; + int storage_amount; + struct item items[MAX_STORAGE]; }; struct guild_storage { - int dirty; - int guild_id; - short storage_status; - short storage_amount; - struct item items[MAX_GUILD_STORAGE]; + int dirty; + int guild_id; + short storage_status; + short storage_amount; + struct item items[MAX_GUILD_STORAGE]; }; struct s_pet { - int account_id; - int char_id; - int pet_id; - short class_; - short level; - short egg_id;//pet egg id - short equip;//pet equip name_id - short intimate;//pet friendly - short hungry;//pet hungry - char name[NAME_LENGTH]; - char rename_flag; - char incuvate; -}; - -struct s_homunculus { //[orn] - char name[NAME_LENGTH]; - int hom_id; - int char_id; - short class_; - short prev_class; - int hp,max_hp,sp,max_sp; - unsigned int intimacy; //[orn] - short hunger; - struct s_skill hskill[MAX_HOMUNSKILL]; //albator - short skillpts; - short level; - unsigned int exp; - short rename_flag; - short vaporize; //albator - int str ; - int agi ; - int vit ; - int int_ ; - int dex ; - int luk ; + int account_id; + int char_id; + int pet_id; + short class_; + short level; + short egg_id;//pet egg id + short equip;//pet equip name_id + short intimate;//pet friendly + short hungry;//pet hungry + char name[NAME_LENGTH]; + char rename_flag; + char incuvate; +}; + +struct s_homunculus { //[orn] + char name[NAME_LENGTH]; + int hom_id; + int char_id; + short class_; + short prev_class; + int hp,max_hp,sp,max_sp; + unsigned int intimacy; //[orn] + short hunger; + struct s_skill hskill[MAX_HOMUNSKILL]; //albator + short skillpts; + short level; + unsigned int exp; + short rename_flag; + short vaporize; //albator + int str ; + int agi ; + int vit ; + int int_ ; + int dex ; + int luk ; }; struct s_mercenary { - int mercenary_id; - int char_id; - short class_; - int hp, sp; - unsigned int kill_count; - unsigned int life_time; + int mercenary_id; + int char_id; + short class_; + int hp, sp; + unsigned int kill_count; + unsigned int life_time; }; struct s_elemental { - int elemental_id; - int char_id; - short class_; - int mode; - int hp, sp, max_hp, max_sp, str, agi, vit, int_, dex, luk; - int life_time; + int elemental_id; + int char_id; + short class_; + int mode; + int hp, sp, max_hp, max_sp, str, agi, vit, int_, dex, luk; + int life_time; }; struct s_friend { - int account_id; - int char_id; - char name[NAME_LENGTH]; + int account_id; + int char_id; + char name[NAME_LENGTH]; }; #ifdef HOTKEY_SAVING struct hotkey { - unsigned int id; - unsigned short lv; - unsigned char type; // 0: item, 1: skill + unsigned int id; + unsigned short lv; + unsigned char type; // 0: item, 1: skill }; #endif struct mmo_charstatus { - int char_id; - int account_id; - int partner_id; - int father; - int mother; - int child; - - unsigned int base_exp,job_exp; - int zeny; - - short class_; - unsigned int status_point,skill_point; - int hp,max_hp,sp,max_sp; - unsigned int option; - short manner; - unsigned char karma; - short hair,hair_color,clothes_color; - int party_id,guild_id,pet_id,hom_id,mer_id,ele_id; - int fame; - - // Mercenary Guilds Rank - int arch_faith, arch_calls; - int spear_faith, spear_calls; - int sword_faith, sword_calls; - - short weapon; // enum weapon_type - short shield; // view-id - short head_top,head_mid,head_bottom; - short robe; - - char name[NAME_LENGTH]; - unsigned int base_level,job_level; - short str,agi,vit,int_,dex,luk; - unsigned char slot,sex; - - uint32 mapip; - uint16 mapport; - - struct point last_point,save_point,memo_point[MAX_MEMOPOINTS]; - struct item inventory[MAX_INVENTORY],cart[MAX_CART]; - struct storage_data storage; - struct s_skill skill[MAX_SKILL]; - - struct s_friend friends[MAX_FRIENDS]; //New friend system [Skotlex] + int char_id; + int account_id; + int partner_id; + int father; + int mother; + int child; + + unsigned int base_exp,job_exp; + int zeny; + + short class_; + unsigned int status_point,skill_point; + int hp,max_hp,sp,max_sp; + unsigned int option; + short manner; + unsigned char karma; + short hair,hair_color,clothes_color; + int party_id,guild_id,pet_id,hom_id,mer_id,ele_id; + int fame; + + // Mercenary Guilds Rank + int arch_faith, arch_calls; + int spear_faith, spear_calls; + int sword_faith, sword_calls; + + short weapon; // enum weapon_type + short shield; // view-id + short head_top,head_mid,head_bottom; + short robe; + + char name[NAME_LENGTH]; + unsigned int base_level,job_level; + short str,agi,vit,int_,dex,luk; + unsigned char slot,sex; + + uint32 mapip; + uint16 mapport; + + struct point last_point,save_point,memo_point[MAX_MEMOPOINTS]; + struct item inventory[MAX_INVENTORY],cart[MAX_CART]; + struct storage_data storage; + struct s_skill skill[MAX_SKILL]; + + struct s_friend friends[MAX_FRIENDS]; //New friend system [Skotlex] #ifdef HOTKEY_SAVING - struct hotkey hotkeys[MAX_HOTKEYS]; + struct hotkey hotkeys[MAX_HOTKEYS]; #endif - bool show_equip; - short rename; + bool show_equip; + short rename; - time_t delete_date; + time_t delete_date; }; typedef enum mail_status { - MAIL_NEW, - MAIL_UNREAD, - MAIL_READ, + MAIL_NEW, + MAIL_UNREAD, + MAIL_READ, } mail_status; struct mail_message { - int id; - int send_id; - char send_name[NAME_LENGTH]; - int dest_id; - char dest_name[NAME_LENGTH]; - char title[MAIL_TITLE_LENGTH]; - char body[MAIL_BODY_LENGTH]; + int id; + int send_id; + char send_name[NAME_LENGTH]; + int dest_id; + char dest_name[NAME_LENGTH]; + char title[MAIL_TITLE_LENGTH]; + char body[MAIL_BODY_LENGTH]; - mail_status status; - time_t timestamp; // marks when the message was sent + mail_status status; + time_t timestamp; // marks when the message was sent - int zeny; - struct item item; + int zeny; + struct item item; }; struct mail_data { - short amount; - bool full; - short unchecked, unread; - struct mail_message msg[MAIL_MAX_INBOX]; + short amount; + bool full; + short unchecked, unread; + struct mail_message msg[MAIL_MAX_INBOX]; }; struct auction_data { - unsigned int auction_id; - int seller_id; - char seller_name[NAME_LENGTH]; - int buyer_id; - char buyer_name[NAME_LENGTH]; - - struct item item; - // This data is required for searching, as itemdb is not read by char server - char item_name[ITEM_NAME_LENGTH]; - short type; - - unsigned short hours; - int price, buynow; - time_t timestamp; // auction's end time - int auction_end_timer; + unsigned int auction_id; + int seller_id; + char seller_name[NAME_LENGTH]; + int buyer_id; + char buyer_name[NAME_LENGTH]; + + struct item item; + // This data is required for searching, as itemdb is not read by char server + char item_name[ITEM_NAME_LENGTH]; + short type; + + unsigned short hours; + int price, buynow; + time_t timestamp; // auction's end time + int auction_end_timer; }; struct registry { - int global_num; - struct global_reg global[GLOBAL_REG_NUM]; - int account_num; - struct global_reg account[ACCOUNT_REG_NUM]; - int account2_num; - struct global_reg account2[ACCOUNT_REG2_NUM]; + int global_num; + struct global_reg global[GLOBAL_REG_NUM]; + int account_num; + struct global_reg account[ACCOUNT_REG_NUM]; + int account2_num; + struct global_reg account2[ACCOUNT_REG2_NUM]; }; struct party_member { - int account_id; - int char_id; - char name[NAME_LENGTH]; - unsigned short class_; - unsigned short map; - unsigned short lv; - unsigned leader : 1, - online : 1; + int account_id; + int char_id; + char name[NAME_LENGTH]; + unsigned short class_; + unsigned short map; + unsigned short lv; + unsigned leader : 1, + online : 1; }; struct party { - int party_id; - char name[NAME_LENGTH]; - unsigned char count; //Count of online characters. - unsigned exp : 1, - item : 2; //&1: Party-Share (round-robin), &2: pickup style: shared. - struct party_member member[MAX_PARTY]; + int party_id; + char name[NAME_LENGTH]; + unsigned char count; //Count of online characters. + unsigned exp : 1, + item : 2; //&1: Party-Share (round-robin), &2: pickup style: shared. + struct party_member member[MAX_PARTY]; }; struct map_session_data; struct guild_member { - int account_id, char_id; - short hair,hair_color,gender,class_,lv; - uint64 exp; - int exp_payper; - short online,position; - char name[NAME_LENGTH]; - struct map_session_data *sd; - unsigned char modified; + int account_id, char_id; + short hair,hair_color,gender,class_,lv; + uint64 exp; + int exp_payper; + short online,position; + char name[NAME_LENGTH]; + struct map_session_data *sd; + unsigned char modified; }; struct guild_position { - char name[NAME_LENGTH]; - int mode; - int exp_mode; - unsigned char modified; + char name[NAME_LENGTH]; + int mode; + int exp_mode; + unsigned char modified; }; struct guild_alliance { - int opposition; - int guild_id; - char name[NAME_LENGTH]; + int opposition; + int guild_id; + char name[NAME_LENGTH]; }; struct guild_expulsion { - char name[NAME_LENGTH]; - char mes[40]; - int account_id; + char name[NAME_LENGTH]; + char mes[40]; + int account_id; }; struct guild_skill { - int id,lv; + int id,lv; }; struct guild { - int guild_id; - short guild_lv, connect_member, max_member, average_lv; - uint64 exp; - unsigned int next_exp; - int skill_point; - char name[NAME_LENGTH],master[NAME_LENGTH]; - struct guild_member member[MAX_GUILD]; - struct guild_position position[MAX_GUILDPOSITION]; - char mes1[MAX_GUILDMES1],mes2[MAX_GUILDMES2]; - int emblem_len,emblem_id; - char emblem_data[2048]; - struct guild_alliance alliance[MAX_GUILDALLIANCE]; - struct guild_expulsion expulsion[MAX_GUILDEXPULSION]; - struct guild_skill skill[MAX_GUILDSKILL]; - - unsigned short save_flag; // for TXT saving + int guild_id; + short guild_lv, connect_member, max_member, average_lv; + uint64 exp; + unsigned int next_exp; + int skill_point; + char name[NAME_LENGTH],master[NAME_LENGTH]; + struct guild_member member[MAX_GUILD]; + struct guild_position position[MAX_GUILDPOSITION]; + char mes1[MAX_GUILDMES1],mes2[MAX_GUILDMES2]; + int emblem_len,emblem_id; + char emblem_data[2048]; + struct guild_alliance alliance[MAX_GUILDALLIANCE]; + struct guild_expulsion expulsion[MAX_GUILDEXPULSION]; + struct guild_skill skill[MAX_GUILDSKILL]; + + unsigned short save_flag; // for TXT saving }; struct guild_castle { - int castle_id; - int mapindex; - char castle_name[NAME_LENGTH]; - char castle_event[NAME_LENGTH]; - int guild_id; - int economy; - int defense; - int triggerE; - int triggerD; - int nextTime; - int payTime; - int createTime; - int visibleC; - struct { - unsigned visible : 1; - int id; // object id - } guardian[MAX_GUARDIANS]; - int* temp_guardians; // ids of temporary guardians (mobs) - int temp_guardians_max; + int castle_id; + int mapindex; + char castle_name[NAME_LENGTH]; + char castle_event[NAME_LENGTH]; + int guild_id; + int economy; + int defense; + int triggerE; + int triggerD; + int nextTime; + int payTime; + int createTime; + int visibleC; + struct { + unsigned visible : 1; + int id; // object id + } guardian[MAX_GUARDIANS]; + int *temp_guardians; // ids of temporary guardians (mobs) + int temp_guardians_max; }; struct fame_list { - int id; - int fame; - char name[NAME_LENGTH]; + int id; + int fame; + char name[NAME_LENGTH]; }; -enum { //Change Guild Infos - GBI_EXP =1, // Guild Experience (EXP) - GBI_GUILDLV, // Guild level - GBI_SKILLPOINT, // Guild skillpoints - GBI_SKILLLV, // Guild skilllv ?? seem unused +enum { //Change Guild Infos + GBI_EXP =1, // Guild Experience (EXP) + GBI_GUILDLV, // Guild level + GBI_SKILLPOINT, // Guild skillpoints + GBI_SKILLLV, // Guild skilllv ?? seem unused }; enum { //Change Member Infos - GMI_POSITION =0, - GMI_EXP, - GMI_HAIR, - GMI_HAIR_COLOR, - GMI_GENDER, - GMI_CLASS, - GMI_LEVEL, + GMI_POSITION =0, + GMI_EXP, + GMI_HAIR, + GMI_HAIR_COLOR, + GMI_GENDER, + GMI_CLASS, + GMI_LEVEL, }; enum { - GD_SKILLBASE=10000, - GD_APPROVAL=10000, - GD_KAFRACONTRACT=10001, - GD_GUARDRESEARCH=10002, - GD_GUARDUP=10003, - GD_EXTENSION=10004, - GD_GLORYGUILD=10005, - GD_LEADERSHIP=10006, - GD_GLORYWOUNDS=10007, - GD_SOULCOLD=10008, - GD_HAWKEYES=10009, - GD_BATTLEORDER=10010, - GD_REGENERATION=10011, - GD_RESTORE=10012, - GD_EMERGENCYCALL=10013, - GD_DEVELOPMENT=10014, - GD_MAX, + GD_SKILLBASE=10000, + GD_APPROVAL=10000, + GD_KAFRACONTRACT=10001, + GD_GUARDRESEARCH=10002, + GD_GUARDUP=10003, + GD_EXTENSION=10004, + GD_GLORYGUILD=10005, + GD_LEADERSHIP=10006, + GD_GLORYWOUNDS=10007, + GD_SOULCOLD=10008, + GD_HAWKEYES=10009, + GD_BATTLEORDER=10010, + GD_REGENERATION=10011, + GD_RESTORE=10012, + GD_EMERGENCYCALL=10013, + GD_DEVELOPMENT=10014, + GD_MAX, }; //These mark the ID of the jobs, as expected by the client. [Skotlex] enum { - JOB_NOVICE, - JOB_SWORDMAN, - JOB_MAGE, - JOB_ARCHER, - JOB_ACOLYTE, - JOB_MERCHANT, - JOB_THIEF, - JOB_KNIGHT, - JOB_PRIEST, - JOB_WIZARD, - JOB_BLACKSMITH, - JOB_HUNTER, - JOB_ASSASSIN, - JOB_KNIGHT2, - JOB_CRUSADER, - JOB_MONK, - JOB_SAGE, - JOB_ROGUE, - JOB_ALCHEMIST, - JOB_BARD, - JOB_DANCER, - JOB_CRUSADER2, - JOB_WEDDING, - JOB_SUPER_NOVICE, - JOB_GUNSLINGER, - JOB_NINJA, - JOB_XMAS, - JOB_SUMMER, - JOB_MAX_BASIC, - - JOB_NOVICE_HIGH = 4001, - JOB_SWORDMAN_HIGH, - JOB_MAGE_HIGH, - JOB_ARCHER_HIGH, - JOB_ACOLYTE_HIGH, - JOB_MERCHANT_HIGH, - JOB_THIEF_HIGH, - JOB_LORD_KNIGHT, - JOB_HIGH_PRIEST, - JOB_HIGH_WIZARD, - JOB_WHITESMITH, - JOB_SNIPER, - JOB_ASSASSIN_CROSS, - JOB_LORD_KNIGHT2, - JOB_PALADIN, - JOB_CHAMPION, - JOB_PROFESSOR, - JOB_STALKER, - JOB_CREATOR, - JOB_CLOWN, - JOB_GYPSY, - JOB_PALADIN2, - - JOB_BABY, - JOB_BABY_SWORDMAN, - JOB_BABY_MAGE, - JOB_BABY_ARCHER, - JOB_BABY_ACOLYTE, - JOB_BABY_MERCHANT, - JOB_BABY_THIEF, - JOB_BABY_KNIGHT, - JOB_BABY_PRIEST, - JOB_BABY_WIZARD, - JOB_BABY_BLACKSMITH, - JOB_BABY_HUNTER, - JOB_BABY_ASSASSIN, - JOB_BABY_KNIGHT2, - JOB_BABY_CRUSADER, - JOB_BABY_MONK, - JOB_BABY_SAGE, - JOB_BABY_ROGUE, - JOB_BABY_ALCHEMIST, - JOB_BABY_BARD, - JOB_BABY_DANCER, - JOB_BABY_CRUSADER2, - JOB_SUPER_BABY, - - JOB_TAEKWON, - JOB_STAR_GLADIATOR, - JOB_STAR_GLADIATOR2, - JOB_SOUL_LINKER, - - JOB_GANGSI, - JOB_DEATH_KNIGHT, - JOB_DARK_COLLECTOR, - - JOB_RUNE_KNIGHT = 4054, - JOB_WARLOCK, - JOB_RANGER, - JOB_ARCH_BISHOP, - JOB_MECHANIC, - JOB_GUILLOTINE_CROSS, - - JOB_RUNE_KNIGHT_T, - JOB_WARLOCK_T, - JOB_RANGER_T, - JOB_ARCH_BISHOP_T, - JOB_MECHANIC_T, - JOB_GUILLOTINE_CROSS_T, - - JOB_ROYAL_GUARD, - JOB_SORCERER, - JOB_MINSTREL, - JOB_WANDERER, - JOB_SURA, - JOB_GENETIC, - JOB_SHADOW_CHASER, - - JOB_ROYAL_GUARD_T, - JOB_SORCERER_T, - JOB_MINSTREL_T, - JOB_WANDERER_T, - JOB_SURA_T, - JOB_GENETIC_T, - JOB_SHADOW_CHASER_T, - - JOB_RUNE_KNIGHT2, - JOB_RUNE_KNIGHT_T2, - JOB_ROYAL_GUARD2, - JOB_ROYAL_GUARD_T2, - JOB_RANGER2, - JOB_RANGER_T2, - JOB_MECHANIC2, - JOB_MECHANIC_T2, - - JOB_BABY_RUNE = 4096, - JOB_BABY_WARLOCK, - JOB_BABY_RANGER, - JOB_BABY_BISHOP, - JOB_BABY_MECHANIC, - JOB_BABY_CROSS, - - JOB_BABY_GUARD, - JOB_BABY_SORCERER, - JOB_BABY_MINSTREL, - JOB_BABY_WANDERER, - JOB_BABY_SURA, - JOB_BABY_GENETIC, - JOB_BABY_CHASER, - - JOB_BABY_RUNE2, - JOB_BABY_GUARD2, - JOB_BABY_RANGER2, - JOB_BABY_MECHANIC2, - - JOB_SUPER_NOVICE_E = 4190, - JOB_SUPER_BABY_E, - - JOB_KAGEROU = 4211, - JOB_OBORO, - - JOB_MAX, + JOB_NOVICE, + JOB_SWORDMAN, + JOB_MAGE, + JOB_ARCHER, + JOB_ACOLYTE, + JOB_MERCHANT, + JOB_THIEF, + JOB_KNIGHT, + JOB_PRIEST, + JOB_WIZARD, + JOB_BLACKSMITH, + JOB_HUNTER, + JOB_ASSASSIN, + JOB_KNIGHT2, + JOB_CRUSADER, + JOB_MONK, + JOB_SAGE, + JOB_ROGUE, + JOB_ALCHEMIST, + JOB_BARD, + JOB_DANCER, + JOB_CRUSADER2, + JOB_WEDDING, + JOB_SUPER_NOVICE, + JOB_GUNSLINGER, + JOB_NINJA, + JOB_XMAS, + JOB_SUMMER, + JOB_MAX_BASIC, + + JOB_NOVICE_HIGH = 4001, + JOB_SWORDMAN_HIGH, + JOB_MAGE_HIGH, + JOB_ARCHER_HIGH, + JOB_ACOLYTE_HIGH, + JOB_MERCHANT_HIGH, + JOB_THIEF_HIGH, + JOB_LORD_KNIGHT, + JOB_HIGH_PRIEST, + JOB_HIGH_WIZARD, + JOB_WHITESMITH, + JOB_SNIPER, + JOB_ASSASSIN_CROSS, + JOB_LORD_KNIGHT2, + JOB_PALADIN, + JOB_CHAMPION, + JOB_PROFESSOR, + JOB_STALKER, + JOB_CREATOR, + JOB_CLOWN, + JOB_GYPSY, + JOB_PALADIN2, + + JOB_BABY, + JOB_BABY_SWORDMAN, + JOB_BABY_MAGE, + JOB_BABY_ARCHER, + JOB_BABY_ACOLYTE, + JOB_BABY_MERCHANT, + JOB_BABY_THIEF, + JOB_BABY_KNIGHT, + JOB_BABY_PRIEST, + JOB_BABY_WIZARD, + JOB_BABY_BLACKSMITH, + JOB_BABY_HUNTER, + JOB_BABY_ASSASSIN, + JOB_BABY_KNIGHT2, + JOB_BABY_CRUSADER, + JOB_BABY_MONK, + JOB_BABY_SAGE, + JOB_BABY_ROGUE, + JOB_BABY_ALCHEMIST, + JOB_BABY_BARD, + JOB_BABY_DANCER, + JOB_BABY_CRUSADER2, + JOB_SUPER_BABY, + + JOB_TAEKWON, + JOB_STAR_GLADIATOR, + JOB_STAR_GLADIATOR2, + JOB_SOUL_LINKER, + + JOB_GANGSI, + JOB_DEATH_KNIGHT, + JOB_DARK_COLLECTOR, + + JOB_RUNE_KNIGHT = 4054, + JOB_WARLOCK, + JOB_RANGER, + JOB_ARCH_BISHOP, + JOB_MECHANIC, + JOB_GUILLOTINE_CROSS, + + JOB_RUNE_KNIGHT_T, + JOB_WARLOCK_T, + JOB_RANGER_T, + JOB_ARCH_BISHOP_T, + JOB_MECHANIC_T, + JOB_GUILLOTINE_CROSS_T, + + JOB_ROYAL_GUARD, + JOB_SORCERER, + JOB_MINSTREL, + JOB_WANDERER, + JOB_SURA, + JOB_GENETIC, + JOB_SHADOW_CHASER, + + JOB_ROYAL_GUARD_T, + JOB_SORCERER_T, + JOB_MINSTREL_T, + JOB_WANDERER_T, + JOB_SURA_T, + JOB_GENETIC_T, + JOB_SHADOW_CHASER_T, + + JOB_RUNE_KNIGHT2, + JOB_RUNE_KNIGHT_T2, + JOB_ROYAL_GUARD2, + JOB_ROYAL_GUARD_T2, + JOB_RANGER2, + JOB_RANGER_T2, + JOB_MECHANIC2, + JOB_MECHANIC_T2, + + JOB_BABY_RUNE = 4096, + JOB_BABY_WARLOCK, + JOB_BABY_RANGER, + JOB_BABY_BISHOP, + JOB_BABY_MECHANIC, + JOB_BABY_CROSS, + + JOB_BABY_GUARD, + JOB_BABY_SORCERER, + JOB_BABY_MINSTREL, + JOB_BABY_WANDERER, + JOB_BABY_SURA, + JOB_BABY_GENETIC, + JOB_BABY_CHASER, + + JOB_BABY_RUNE2, + JOB_BABY_GUARD2, + JOB_BABY_RANGER2, + JOB_BABY_MECHANIC2, + + JOB_SUPER_NOVICE_E = 4190, + JOB_SUPER_BABY_E, + + JOB_KAGEROU = 4211, + JOB_OBORO, + + JOB_MAX, }; enum { - SEX_FEMALE = 0, - SEX_MALE, - SEX_SERVER + SEX_FEMALE = 0, + SEX_MALE, + SEX_SERVER }; // sanity checks... diff --git a/src/common/mutex.c b/src/common/mutex.c index 6b4f55119..813bef31b 100644 --- a/src/common/mutex.c +++ b/src/common/mutex.c @@ -15,26 +15,26 @@ #include "../common/timer.h" #include "../common/mutex.h" -struct ramutex{ +struct ramutex { #ifdef WIN32 - CRITICAL_SECTION hMutex; + CRITICAL_SECTION hMutex; #else - pthread_mutex_t hMutex; + pthread_mutex_t hMutex; #endif }; -struct racond{ +struct racond { #ifdef WIN32 - HANDLE events[2]; - ra_align(8) volatile LONG nWaiters; - CRITICAL_SECTION waiters_lock; + HANDLE events[2]; + ra_align(8) volatile LONG nWaiters; + CRITICAL_SECTION waiters_lock; #define EVENT_COND_SIGNAL 0 #define EVENT_COND_BROADCAST 1 #else - pthread_cond_t hCond; + pthread_cond_t hCond; #endif }; @@ -46,68 +46,73 @@ struct racond{ // -ramutex ramutex_create(){ - struct ramutex *m; - - m = (struct ramutex*)aMalloc( sizeof(struct ramutex) ); - if(m == NULL){ - ShowFatalError("ramutex_create: OOM while allocating %u bytes.\n", sizeof(struct ramutex)); - return NULL; - } - +ramutex ramutex_create() +{ + struct ramutex *m; + + m = (struct ramutex *)aMalloc(sizeof(struct ramutex)); + if (m == NULL) { + ShowFatalError("ramutex_create: OOM while allocating %u bytes.\n", sizeof(struct ramutex)); + return NULL; + } + #ifdef WIN32 - InitializeCriticalSection(&m->hMutex); + InitializeCriticalSection(&m->hMutex); #else - pthread_mutex_init(&m->hMutex, NULL); + pthread_mutex_init(&m->hMutex, NULL); #endif - - return m; + + return m; }//end: ramutex_create() -void ramutex_destroy( ramutex m ){ +void ramutex_destroy(ramutex m) +{ #ifdef WIN32 - DeleteCriticalSection(&m->hMutex); + DeleteCriticalSection(&m->hMutex); #else - pthread_mutex_destroy(&m->hMutex); + pthread_mutex_destroy(&m->hMutex); #endif - aFree(m); + aFree(m); }//end: ramutex_destroy() -void ramutex_lock( ramutex m ){ +void ramutex_lock(ramutex m) +{ #ifdef WIN32 - EnterCriticalSection(&m->hMutex); + EnterCriticalSection(&m->hMutex); #else - pthread_mutex_lock(&m->hMutex); + pthread_mutex_lock(&m->hMutex); #endif }//end: ramutex_lock -bool ramutex_trylock( ramutex m ){ +bool ramutex_trylock(ramutex m) +{ #ifdef WIN32 - if(TryEnterCriticalSection(&m->hMutex) == TRUE) - return true; + if (TryEnterCriticalSection(&m->hMutex) == TRUE) + return true; - return false; + return false; #else - if(pthread_mutex_trylock(&m->hMutex) == 0) - return true; - - return false; + if (pthread_mutex_trylock(&m->hMutex) == 0) + return true; + + return false; #endif }//end: ramutex_trylock() -void ramutex_unlock( ramutex m ){ +void ramutex_unlock(ramutex m) +{ #ifdef WIN32 - LeaveCriticalSection(&m->hMutex); + LeaveCriticalSection(&m->hMutex); #else - pthread_mutex_unlock(&m->hMutex); + pthread_mutex_unlock(&m->hMutex); #endif }//end: ramutex_unlock() @@ -116,131 +121,136 @@ void ramutex_unlock( ramutex m ){ /////////////// // Condition Variables -// +// // Implementation: // -racond racond_create(){ - struct racond *c; - - c = (struct racond*)aMalloc( sizeof(struct racond) ); - if(c == NULL){ - ShowFatalError("racond_create: OOM while allocating %u bytes\n", sizeof(struct racond)); - return NULL; - } +racond racond_create() +{ + struct racond *c; + + c = (struct racond *)aMalloc(sizeof(struct racond)); + if (c == NULL) { + ShowFatalError("racond_create: OOM while allocating %u bytes\n", sizeof(struct racond)); + return NULL; + } #ifdef WIN32 - c->nWaiters = 0; - c->events[ EVENT_COND_SIGNAL ] = CreateEvent( NULL, FALSE, FALSE, NULL ); - c->events[ EVENT_COND_BROADCAST ] = CreateEvent( NULL, TRUE, FALSE, NULL ); - InitializeCriticalSection( &c->waiters_lock ); + c->nWaiters = 0; + c->events[ EVENT_COND_SIGNAL ] = CreateEvent(NULL, FALSE, FALSE, NULL); + c->events[ EVENT_COND_BROADCAST ] = CreateEvent(NULL, TRUE, FALSE, NULL); + InitializeCriticalSection(&c->waiters_lock); #else - pthread_cond_init(&c->hCond, NULL); + pthread_cond_init(&c->hCond, NULL); #endif - - return c; + + return c; }//end: racond_create() -void racond_destroy( racond c ){ +void racond_destroy(racond c) +{ #ifdef WIN32 - CloseHandle( c->events[ EVENT_COND_SIGNAL ] ); - CloseHandle( c->events[ EVENT_COND_BROADCAST ] ); - DeleteCriticalSection( &c->waiters_lock ); + CloseHandle(c->events[ EVENT_COND_SIGNAL ]); + CloseHandle(c->events[ EVENT_COND_BROADCAST ]); + DeleteCriticalSection(&c->waiters_lock); #else - pthread_cond_destroy(&c->hCond); + pthread_cond_destroy(&c->hCond); #endif - aFree(c); + aFree(c); }//end: racond_destroy() -void racond_wait( racond c, ramutex m, sysint timeout_ticks){ +void racond_wait(racond c, ramutex m, sysint timeout_ticks) +{ #ifdef WIN32 - register DWORD ms; - int result; - bool is_last = false; + register DWORD ms; + int result; + bool is_last = false; - EnterCriticalSection(&c->waiters_lock); - c->nWaiters++; - LeaveCriticalSection(&c->waiters_lock); + EnterCriticalSection(&c->waiters_lock); + c->nWaiters++; + LeaveCriticalSection(&c->waiters_lock); - if(timeout_ticks < 0) - ms = INFINITE; - else - ms = (timeout_ticks > MAXDWORD) ? (MAXDWORD - 1) : (DWORD)timeout_ticks; - - - // we can release the mutex (m) here, cause win's - // manual reset events maintain state when used with - // SetEvent() - ramutex_unlock(m); + if (timeout_ticks < 0) + ms = INFINITE; + else + ms = (timeout_ticks > MAXDWORD) ? (MAXDWORD - 1) : (DWORD)timeout_ticks; - result = WaitForMultipleObjects(2, c->events, FALSE, ms); - - - EnterCriticalSection(&c->waiters_lock); - c->nWaiters--; - if( (result == WAIT_OBJECT_0 + EVENT_COND_BROADCAST) && (c->nWaiters == 0) ) - is_last = true; // Broadcast called! - LeaveCriticalSection(&c->waiters_lock); - + // we can release the mutex (m) here, cause win's + // manual reset events maintain state when used with + // SetEvent() + ramutex_unlock(m); - // we are the last waiter that has to be notified, or to stop waiting - // so we have to do a manual reset - if(is_last == true) - ResetEvent( c->events[EVENT_COND_BROADCAST] ); + result = WaitForMultipleObjects(2, c->events, FALSE, ms); - ramutex_lock(m); + EnterCriticalSection(&c->waiters_lock); + c->nWaiters--; + if ((result == WAIT_OBJECT_0 + EVENT_COND_BROADCAST) && (c->nWaiters == 0)) + is_last = true; // Broadcast called! + LeaveCriticalSection(&c->waiters_lock); + + + + // we are the last waiter that has to be notified, or to stop waiting + // so we have to do a manual reset + if (is_last == true) + ResetEvent(c->events[EVENT_COND_BROADCAST]); + + + ramutex_lock(m); #else - if(timeout_ticks < 0){ - pthread_cond_wait( &c->hCond, &m->hMutex ); - }else{ - struct timespec wtime; - int64 exact_timeout = gettick() + timeout_ticks; - - wtime.tv_sec = exact_timeout/1000; - wtime.tv_nsec = (exact_timeout%1000)*1000000; - - pthread_cond_timedwait( &c->hCond, &m->hMutex, &wtime); - } + if (timeout_ticks < 0) { + pthread_cond_wait(&c->hCond, &m->hMutex); + } else { + struct timespec wtime; + int64 exact_timeout = gettick() + timeout_ticks; + + wtime.tv_sec = exact_timeout/1000; + wtime.tv_nsec = (exact_timeout%1000)*1000000; + + pthread_cond_timedwait(&c->hCond, &m->hMutex, &wtime); + } #endif }//end: racond_wait() -void racond_signal( racond c ){ +void racond_signal(racond c) +{ #ifdef WIN32 -// bool has_waiters = false; -// EnterCriticalSection(&c->waiters_lock); -// if(c->nWaiters > 0) -// has_waiters = true; -// LeaveCriticalSection(&c->waiters_lock); - -// if(has_waiters == true) - SetEvent( c->events[ EVENT_COND_SIGNAL ] ); + // bool has_waiters = false; + // EnterCriticalSection(&c->waiters_lock); + // if(c->nWaiters > 0) + // has_waiters = true; + // LeaveCriticalSection(&c->waiters_lock); + + // if(has_waiters == true) + SetEvent(c->events[ EVENT_COND_SIGNAL ]); #else - pthread_cond_signal(&c->hCond); + pthread_cond_signal(&c->hCond); #endif }//end: racond_signal() -void racond_broadcast( racond c ){ +void racond_broadcast(racond c) +{ #ifdef WIN32 -// bool has_waiters = false; -// EnterCriticalSection(&c->waiters_lock); -// if(c->nWaiters > 0) -// has_waiters = true; -// LeaveCriticalSection(&c->waiters_lock); - -// if(has_waiters == true) - SetEvent( c->events[ EVENT_COND_BROADCAST ] ); + // bool has_waiters = false; + // EnterCriticalSection(&c->waiters_lock); + // if(c->nWaiters > 0) + // has_waiters = true; + // LeaveCriticalSection(&c->waiters_lock); + + // if(has_waiters == true) + SetEvent(c->events[ EVENT_COND_BROADCAST ]); #else - pthread_cond_broadcast(&c->hCond); + pthread_cond_broadcast(&c->hCond); #endif }//end: racond_broadcast() diff --git a/src/common/mutex.h b/src/common/mutex.h index 1999627cd..abef731f4 100644 --- a/src/common/mutex.h +++ b/src/common/mutex.h @@ -1,5 +1,5 @@ // Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// For more information, see LICENCE in the main folder #ifndef _rA_MUTEX_H_ #define _rA_MUTEX_H_ @@ -9,67 +9,67 @@ typedef struct ramutex *ramutex; // Mutex typedef struct racond *racond; // Condition Var /** - * Creates a Mutex + * Creates a Mutex * * @return not NULL */ ramutex ramutex_create(); -/** +/** * Destroys a Mutex - * + * * @param m - the mutex to destroy */ -void ramutex_destroy( ramutex m ); +void ramutex_destroy(ramutex m); -/** +/** * Gets a lock * * @param m - the mutex to lock */ -void ramutex_lock( ramutex m); +void ramutex_lock(ramutex m); -/** +/** * Trys to get the Lock - * + * * @param m - the mutex try to lock - * + * * @return boolean (true = got the lock) */ -bool ramutex_trylock( ramutex m ); +bool ramutex_trylock(ramutex m); -/** +/** * Unlocks a mutex * * @param m - the mutex to unlock */ -void ramutex_unlock( ramutex m); +void ramutex_unlock(ramutex m); -/** +/** * Creates a Condition variable * * @return not NULL */ racond racond_create(); -/** +/** * Destroy a Condition variable * * @param c - the condition varaible to destroy */ -void racond_destroy( racond c ); +void racond_destroy(racond c); /** * Waits Until state is signalled - * - * @param c - the condition var to wait for signalled state + * + * @param c - the condition var to wait for signalled state * @param m - the mutex used for syncronization * @param timeout_ticks - timeout in ticks ( -1 = INFINITE ) */ -void racond_wait( racond c, ramutex m, sysint timeout_ticks); +void racond_wait(racond c, ramutex m, sysint timeout_ticks); -/** +/** * Sets the given condition var to signalled state * * @param c - condition var to set in signalled state. @@ -77,16 +77,16 @@ void racond_wait( racond c, ramutex m, sysint timeout_ticks); * @note: * Only one waiter gets notified. */ -void racond_signal( racond c ); +void racond_signal(racond c); -/** +/** * Sets notifys all waiting threads thats signalled. * @param c - condition var to set in signalled state - * + * * @note: * All Waiters getting notified. - */ -void racond_broadcast( racond c ); + */ +void racond_broadcast(racond c); #endif diff --git a/src/common/netbuffer.c b/src/common/netbuffer.c index 57742d612..9ce13ffc3 100644 --- a/src/common/netbuffer.c +++ b/src/common/netbuffer.c @@ -26,10 +26,10 @@ #include "../common/netbuffer.h" -// +// // Buffers are available in the following sizes: -// 48, 192, 2048, 8192 -// 65536 (inter server connects may use it for charstatus struct..) +// 48, 192, 2048, 8192 +// 65536 (inter server connects may use it for charstatus struct..) // @@ -42,180 +42,197 @@ static sysint *l_poolElemSize = NULL; static mempool *l_pool = NULL; -void netbuffer_init(){ - char localsection[32]; - raconf conf; - sysint i; - - // Initialize Statistic counters: - l_nEmergencyAllocations = 0; - - // Set localsection name according to running serverype. - switch(SERVER_TYPE){ - case ATHENA_SERVER_LOGIN: strcpy(localsection, "login-netbuffer"); break; - case ATHENA_SERVER_CHAR: strcpy(localsection, "char-netbuffer"); break; - case ATHENA_SERVER_INTER: strcpy(localsection, "inter-netbuffer"); break; - case ATHENA_SERVER_MAP: strcpy(localsection, "map-netbuffer"); break; - default: strcpy(localsection, "unsupported_type"); break; - } - - - conf = raconf_parse("conf/network.conf"); - if(conf == NULL){ - ShowFatalError("Failed to Parse required Configuration (conf/network.conf)"); - exit(EXIT_FAILURE); - } - - // Get Values from config file - l_nPools = (sysint)raconf_getintEx(conf, localsection, "netbuffer", "num", 0); - if(l_nPools == 0){ - ShowFatalError("Netbuffer (network.conf) failure - requires at least 1 Pool.\n"); - exit(EXIT_FAILURE); - } - - // Allocate arrays. - l_poolElemSize = (sysint*)aCalloc( l_nPools, sizeof(sysint) ); - l_pool = (mempool*)aCalloc( l_nPools, sizeof(mempool) ); - - - for(i = 0; i < l_nPools; i++){ - int64 num_prealloc, num_realloc; - char key[32]; - - sprintf(key, "pool_%u_size", (uint32)i+1); - l_poolElemSize[i] = (sysint)raconf_getintEx(conf, localsection, "netbuffer", key, 4096); - if(l_poolElemSize[i] < 32){ - ShowWarning("Netbuffer (network.conf) failure - minimum allowed buffer size is 32 byte) - fixed.\n"); - l_poolElemSize[i] = 32; - } - - sprintf(key, "pool_%u_prealloc", (uint32)i+1); - num_prealloc = raconf_getintEx(conf, localsection, "netbuffer", key, 150); - - sprintf(key, "pool_%u_realloc_step", (uint32)i+1); - num_realloc = raconf_getintEx(conf, localsection, "netbuffer", key, 100); - - // Create Pool! - sprintf(key, "Netbuffer %u", (uint32)l_poolElemSize[i]); // name. - - // Info - ShowInfo("NetBuffer: Creating Pool %u (Prealloc: %u, Realloc Step: %u) - %0.2f MiB\n", l_poolElemSize[i], num_prealloc, num_realloc, (float)((sizeof(struct netbuf) + l_poolElemSize[i] - 32)* num_prealloc)/1024.0f/1024.0f); - - // - // Size Calculation: - // struct netbuf + requested buffer size - 32 (because the struct already contains 32 byte buffer space at the end of struct) - l_pool[i] = mempool_create(key, (sizeof(struct netbuf) + l_poolElemSize[i] - 32), num_prealloc, num_realloc, NULL, NULL); - if(l_pool[i] == NULL){ - ShowFatalError("Netbuffer: cannot create Pool for %u byte buffers.\n", l_poolElemSize[i]); - // @leak: clean everything :D - exit(EXIT_FAILURE); - } - - }// - - - raconf_destroy(conf); +void netbuffer_init() +{ + char localsection[32]; + raconf conf; + sysint i; + + // Initialize Statistic counters: + l_nEmergencyAllocations = 0; + + // Set localsection name according to running serverype. + switch (SERVER_TYPE) { + case ATHENA_SERVER_LOGIN: + strcpy(localsection, "login-netbuffer"); + break; + case ATHENA_SERVER_CHAR: + strcpy(localsection, "char-netbuffer"); + break; + case ATHENA_SERVER_INTER: + strcpy(localsection, "inter-netbuffer"); + break; + case ATHENA_SERVER_MAP: + strcpy(localsection, "map-netbuffer"); + break; + default: + strcpy(localsection, "unsupported_type"); + break; + } + + + conf = raconf_parse("conf/network.conf"); + if (conf == NULL) { + ShowFatalError("Failed to Parse required Configuration (conf/network.conf)"); + exit(EXIT_FAILURE); + } + + // Get Values from config file + l_nPools = (sysint)raconf_getintEx(conf, localsection, "netbuffer", "num", 0); + if (l_nPools == 0) { + ShowFatalError("Netbuffer (network.conf) failure - requires at least 1 Pool.\n"); + exit(EXIT_FAILURE); + } + + // Allocate arrays. + l_poolElemSize = (sysint *)aCalloc(l_nPools, sizeof(sysint)); + l_pool = (mempool *)aCalloc(l_nPools, sizeof(mempool)); + + + for (i = 0; i < l_nPools; i++) { + int64 num_prealloc, num_realloc; + char key[32]; + + sprintf(key, "pool_%u_size", (uint32)i+1); + l_poolElemSize[i] = (sysint)raconf_getintEx(conf, localsection, "netbuffer", key, 4096); + if (l_poolElemSize[i] < 32) { + ShowWarning("Netbuffer (network.conf) failure - minimum allowed buffer size is 32 byte) - fixed.\n"); + l_poolElemSize[i] = 32; + } + + sprintf(key, "pool_%u_prealloc", (uint32)i+1); + num_prealloc = raconf_getintEx(conf, localsection, "netbuffer", key, 150); + + sprintf(key, "pool_%u_realloc_step", (uint32)i+1); + num_realloc = raconf_getintEx(conf, localsection, "netbuffer", key, 100); + + // Create Pool! + sprintf(key, "Netbuffer %u", (uint32)l_poolElemSize[i]); // name. + + // Info + ShowInfo("NetBuffer: Creating Pool %u (Prealloc: %u, Realloc Step: %u) - %0.2f MiB\n", l_poolElemSize[i], num_prealloc, num_realloc, (float)((sizeof(struct netbuf) + l_poolElemSize[i] - 32)* num_prealloc)/1024.0f/1024.0f); + + // + // Size Calculation: + // struct netbuf + requested buffer size - 32 (because the struct already contains 32 byte buffer space at the end of struct) + l_pool[i] = mempool_create(key, (sizeof(struct netbuf) + l_poolElemSize[i] - 32), num_prealloc, num_realloc, NULL, NULL); + if (l_pool[i] == NULL) { + ShowFatalError("Netbuffer: cannot create Pool for %u byte buffers.\n", l_poolElemSize[i]); + // @leak: clean everything :D + exit(EXIT_FAILURE); + } + + }// + + + raconf_destroy(conf); }//end: netbuffer_init() -void netbuffer_final(){ - sysint i; - - if(l_nPools > 0){ - /// .. finalize mempools - for(i = 0; i < l_nPools; i++){ - mempool_stats stats = mempool_get_stats(l_pool[i]); - - ShowInfo("Netbuffer: Freeing Pool %u (Peak Usage: %u, Realloc Events: %u)\n", l_poolElemSize[i], stats.peak_nodes_used, stats.num_realloc_events); - - mempool_destroy(l_pool[i]); - } - - if(l_nEmergencyAllocations > 0){ - ShowWarning("Netbuffer: did %u Emergency Allocations, please tune your network.conf!\n", l_nEmergencyAllocations); - l_nEmergencyAllocations = 0; - } - - aFree(l_poolElemSize); l_poolElemSize = NULL; - aFree(l_pool); l_pool = NULL; - l_nPools = 0; - } - - +void netbuffer_final() +{ + sysint i; + + if (l_nPools > 0) { + /// .. finalize mempools + for (i = 0; i < l_nPools; i++) { + mempool_stats stats = mempool_get_stats(l_pool[i]); + + ShowInfo("Netbuffer: Freeing Pool %u (Peak Usage: %u, Realloc Events: %u)\n", l_poolElemSize[i], stats.peak_nodes_used, stats.num_realloc_events); + + mempool_destroy(l_pool[i]); + } + + if (l_nEmergencyAllocations > 0) { + ShowWarning("Netbuffer: did %u Emergency Allocations, please tune your network.conf!\n", l_nEmergencyAllocations); + l_nEmergencyAllocations = 0; + } + + aFree(l_poolElemSize); + l_poolElemSize = NULL; + aFree(l_pool); + l_pool = NULL; + l_nPools = 0; + } + + }//end: netbuffer_final() -netbuf netbuffer_get( sysint sz ){ - sysint i; - netbuf nb = NULL; - - // Search an appropriate pool - for(i = 0; i < l_nPools; i++){ - if(sz <= l_poolElemSize[i]){ - // match - - nb = (netbuf)mempool_node_get(l_pool[i]); - nb->pool = i; - - break; - } - } - - // No Bufferpool found that mets there quirements?.. (thats bad..) - if(nb == NULL){ - ShowWarning("Netbuffer: get(%u): => no appropriate pool found - emergency allocation required.\n", sz); - ShowWarning("Please reconfigure your network.conf!"); - - InterlockedIncrement(&l_nEmergencyAllocations); - - // .. better to check (netbuf struct provides 32 byte bufferspace itself. - if(sz < 32) sz = 32; - - // allocate memory using malloc .. - while(1){ - nb = (netbuf) aMalloc( (sizeof(struct netbuf) + sz - 32) ); - if(nb != NULL){ - memset(nb, 0x00, (sizeof(struct netbuf) + sz - 32) ); // zero memory! (to enforce commit @ os.) - nb->pool = -1; // emergency alloc. - break; - } - - rathread_yield(); - }// spin allocation. - - } - - - nb->refcnt = 1; // Initial refcount is 1 - - return nb; +netbuf netbuffer_get(sysint sz) +{ + sysint i; + netbuf nb = NULL; + + // Search an appropriate pool + for (i = 0; i < l_nPools; i++) { + if (sz <= l_poolElemSize[i]) { + // match + + nb = (netbuf)mempool_node_get(l_pool[i]); + nb->pool = i; + + break; + } + } + + // No Bufferpool found that mets there quirements?.. (thats bad..) + if (nb == NULL) { + ShowWarning("Netbuffer: get(%u): => no appropriate pool found - emergency allocation required.\n", sz); + ShowWarning("Please reconfigure your network.conf!"); + + InterlockedIncrement(&l_nEmergencyAllocations); + + // .. better to check (netbuf struct provides 32 byte bufferspace itself. + if (sz < 32) sz = 32; + + // allocate memory using malloc .. + while (1) { + nb = (netbuf) aMalloc((sizeof(struct netbuf) + sz - 32)); + if (nb != NULL) { + memset(nb, 0x00, (sizeof(struct netbuf) + sz - 32)); // zero memory! (to enforce commit @ os.) + nb->pool = -1; // emergency alloc. + break; + } + + rathread_yield(); + }// spin allocation. + + } + + + nb->refcnt = 1; // Initial refcount is 1 + + return nb; }//end: netbuffer_get() -void netbuffer_put( netbuf nb ){ - - // Decrement reference counter, if > 0 do nothing :) - if( InterlockedDecrement(&nb->refcnt) > 0 ) - return; - - // Is this buffer an emergency allocated buffer? - if(nb->pool == -1){ - aFree(nb); - return; - } - - - // Otherwise its a normal mempool based buffer - // return it to the according mempool: - mempool_node_put( l_pool[nb->pool], nb); - - +void netbuffer_put(netbuf nb) +{ + + // Decrement reference counter, if > 0 do nothing :) + if (InterlockedDecrement(&nb->refcnt) > 0) + return; + + // Is this buffer an emergency allocated buffer? + if (nb->pool == -1) { + aFree(nb); + return; + } + + + // Otherwise its a normal mempool based buffer + // return it to the according mempool: + mempool_node_put(l_pool[nb->pool], nb); + + }//end: netbuffer_put() -void netbuffer_incref( netbuf nb ){ - - InterlockedIncrement(&nb->refcnt); - +void netbuffer_incref(netbuf nb) +{ + + InterlockedIncrement(&nb->refcnt); + }//end: netbuf_incref() diff --git a/src/common/netbuffer.h b/src/common/netbuffer.h index 844241226..a4feb7287 100644 --- a/src/common/netbuffer.h +++ b/src/common/netbuffer.h @@ -6,37 +6,37 @@ #include "../common/cbasetypes.h" -typedef struct netbuf{ - sysint pool; // The pool ID this buffer belongs to, - // is set to -1 if its an emergency allocated buffer - - struct netbuf *next; // Used by Network system. - - volatile int32 refcnt; // Internal Refcount, it gets lowered every call to netbuffer_put, - // if its getting zero, the buffer will returned back to the pool - // and can be reused. - - int32 dataPos; // Current Offset - // Used only for Reading (recv job) - // write cases are using the sessions local datapos member due to - // shared write buffer support. - - int32 dataLen; // read buffer case: - // The length expected to read to. - // when this->dataPos == dateLen, read job has been completed. - // write buffer case: - // The lngth of data in te buffer - // when s->dataPos == dataLen, write job has been completed - // - // Note: - // leftBytes = (dateLen - dataPos) - // - // Due to shared buffer support - // dataPos gets not used in write case (each connection has its local offset) - // - - // The Bufferspace itself. - char buf[32]; +typedef struct netbuf { + sysint pool; // The pool ID this buffer belongs to, + // is set to -1 if its an emergency allocated buffer + + struct netbuf *next; // Used by Network system. + + volatile int32 refcnt; // Internal Refcount, it gets lowered every call to netbuffer_put, + // if its getting zero, the buffer will returned back to the pool + // and can be reused. + + int32 dataPos; // Current Offset + // Used only for Reading (recv job) + // write cases are using the sessions local datapos member due to + // shared write buffer support. + + int32 dataLen; // read buffer case: + // The length expected to read to. + // when this->dataPos == dateLen, read job has been completed. + // write buffer case: + // The lngth of data in te buffer + // when s->dataPos == dataLen, write job has been completed + // + // Note: + // leftBytes = (dateLen - dataPos) + // + // Due to shared buffer support + // dataPos gets not used in write case (each connection has its local offset) + // + + // The Bufferspace itself. + char buf[32]; } *netbuf; @@ -47,29 +47,29 @@ void netbuffer_final(); * Gets a netbuffer that has atleast (sz) byes space. * * @note: The netbuffer system guarantees that youll always recevie a buffer. - * no check for null is required! + * no check for null is required! * * @param sz - minimum size needed. * * @return pointer to netbuf struct */ -netbuf netbuffer_get( sysint sz ); +netbuf netbuffer_get(sysint sz); -/** +/** * Returns the given netbuffer (decreases refcount, if its 0 - the buffer will get returned to the pool) * - * @param buf - the buffer to return + * @param buf - the buffer to return */ -void netbuffer_put( netbuf buf ); +void netbuffer_put(netbuf buf); -/** - * Increases the Refcount on the given buffer +/** + * Increases the Refcount on the given buffer * (used for areasends .. etc) * */ -void netbuffer_incref( netbuf buf ); +void netbuffer_incref(netbuf buf); // Some Useful macros diff --git a/src/common/network.c b/src/common/network.c index 1f1621363..1c968200d 100644 --- a/src/common/network.c +++ b/src/common/network.c @@ -51,1011 +51,1020 @@ static bool onSend(int32 fd); #define _network_free_netbuf_async( buf ) add_timer( 0, _network_async_free_netbuf_proc, 0, (intptr_t) buf) -static int _network_async_free_netbuf_proc(int tid, unsigned int tick, int id, intptr_t data){ - // netbuf is in data - netbuffer_put( (netbuf)data ); +static int _network_async_free_netbuf_proc(int tid, unsigned int tick, int id, intptr_t data) +{ + // netbuf is in data + netbuffer_put((netbuf)data); - return 0; + return 0; }//end: _network_async_free_netbuf_proc() -void network_init(){ - SESSION *s; - int32 i; - - memset(g_Session, 0x00, (sizeof(SESSION) * MAXCONN) ); - - for(i = 0; i < MAXCONN; i++){ - s = &g_Session[i]; - - s->type = NST_FREE; - s->disconnect_in_progress = false; - - } - - // Initialize the correspondig event dispatcher - evdp_init(); - - // - add_timer_func_list(_network_async_free_netbuf_proc, "_network_async_free_netbuf_proc"); - +void network_init() +{ + SESSION *s; + int32 i; + + memset(g_Session, 0x00, (sizeof(SESSION) * MAXCONN)); + + for (i = 0; i < MAXCONN; i++) { + s = &g_Session[i]; + + s->type = NST_FREE; + s->disconnect_in_progress = false; + + } + + // Initialize the correspondig event dispatcher + evdp_init(); + + // + add_timer_func_list(_network_async_free_netbuf_proc, "_network_async_free_netbuf_proc"); + }//end: network_init() -void network_final(){ +void network_final() +{ + + // @TODO: + // .. disconnect and cleanup everything! - // @TODO: - // .. disconnect and cleanup everything! - - evdp_final(); + evdp_final(); }//end: network_final() -void network_do(){ - struct EVDP_EVENT l_events[EVENTS_PER_CYCLE]; - register struct EVDP_EVENT *ev; - register int n, nfds; - register SESSION *s; - - nfds = evdp_wait( l_events, EVENTS_PER_CYCLE, 1000); // @TODO: timer_getnext() - - for(n = 0; n < nfds; n++){ - ev = &l_events[n]; - s = &g_Session[ ev->fd ]; - - if(ev->events & EVDP_EVENT_HUP){ - network_disconnect( ev->fd ); - continue; // no further event processing. - }// endif vent is HUP (disconnect) - - - if(ev->events & EVDP_EVENT_IN){ - - if(s->onRecv != NULL){ - if( false == s->onRecv(ev->fd) ){ - network_disconnect(ev->fd); - continue; // .. - } - }else{ - ShowError("network_do: fd #%u has no onRecv proc set. - disconnecting\n", ev->fd); - network_disconnect(ev->fd); - continue; - } - - }// endif event is IN (recv) - - - if(ev->events & EVDP_EVENT_OUT){ - if(s->onSend != NULL){ - if( false == s->onSend(ev->fd) ){ - network_disconnect(ev->fd); - continue; - } - }else{ - ShowError("network_do: fd #%u has no onSend proc set. - disconnecting\n", ev->fd); - network_disconnect(ev->fd); - continue; - } - }// endif event is OUT (send) - - }//endfor - +void network_do() +{ + struct EVDP_EVENT l_events[EVENTS_PER_CYCLE]; + register struct EVDP_EVENT *ev; + register int n, nfds; + register SESSION *s; + + nfds = evdp_wait(l_events, EVENTS_PER_CYCLE, 1000); // @TODO: timer_getnext() + + for (n = 0; n < nfds; n++) { + ev = &l_events[n]; + s = &g_Session[ ev->fd ]; + + if (ev->events & EVDP_EVENT_HUP) { + network_disconnect(ev->fd); + continue; // no further event processing. + }// endif vent is HUP (disconnect) + + + if (ev->events & EVDP_EVENT_IN) { + + if (s->onRecv != NULL) { + if (false == s->onRecv(ev->fd)) { + network_disconnect(ev->fd); + continue; // .. + } + } else { + ShowError("network_do: fd #%u has no onRecv proc set. - disconnecting\n", ev->fd); + network_disconnect(ev->fd); + continue; + } + + }// endif event is IN (recv) + + + if (ev->events & EVDP_EVENT_OUT) { + if (s->onSend != NULL) { + if (false == s->onSend(ev->fd)) { + network_disconnect(ev->fd); + continue; + } + } else { + ShowError("network_do: fd #%u has no onSend proc set. - disconnecting\n", ev->fd); + network_disconnect(ev->fd); + continue; + } + }// endif event is OUT (send) + + }//endfor + }//end: network_do() -static bool _setnonblock(int32 fd){ - int flags = fcntl(fd, F_GETFL, 0); - if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) - return false; +static bool _setnonblock(int32 fd) +{ + int flags = fcntl(fd, F_GETFL, 0); + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) + return false; - return true; + return true; }//end: _setnonblock() -static bool _network_accept(int32 fd){ - SESSION *listener = &g_Session[fd]; - SESSION *s; - union{ - struct sockaddr_in v4; +static bool _network_accept(int32 fd) +{ + SESSION *listener = &g_Session[fd]; + SESSION *s; + union { + struct sockaddr_in v4; #ifdef ENABLE_IPV6 - struct sockaddr_in6 v6; + struct sockaddr_in6 v6; #endif - } _addr; - int newfd; - socklen_t addrlen; - struct sockaddr *addr; - - // Accept until OS returns - nothing to accept anymore - // - this is required due to our EVDP abstraction. (which handles on listening sockets similar to epoll's EPOLLET flag.) - while(1){ + } _addr; + int newfd; + socklen_t addrlen; + struct sockaddr *addr; + + // Accept until OS returns - nothing to accept anymore + // - this is required due to our EVDP abstraction. (which handles on listening sockets similar to epoll's EPOLLET flag.) + while (1) { #ifdef ENABLE_IPV6 - if(listener->v6 == true){ - addrlen = sizeof(_addr.v6); - addr = (struct sockaddr*)&_addr.v6; - }else{ + if (listener->v6 == true) { + addrlen = sizeof(_addr.v6); + addr = (struct sockaddr *)&_addr.v6; + } else { #endif - addrlen = sizeof(_addr.v4); - addr = (struct sockaddr*)&_addr.v4; + addrlen = sizeof(_addr.v4); + addr = (struct sockaddr *)&_addr.v4; #ifdef ENABLE_IPV6 - } + } #endif #ifdef HAVE_ACCEPT4 - newfd = accept4(fd, addr, &addrlen, SOCK_NONBLOCK); + newfd = accept4(fd, addr, &addrlen, SOCK_NONBLOCK); #else - newfd = accept(fd, addr, &addrlen); + newfd = accept(fd, addr, &addrlen); #endif - if(newfd == -1){ - if(errno == EAGAIN || errno == EWOULDBLOCK) - break; // this is fully valid & whished., se explaination on top of while(1) - - // Otherwis .. we have serious problems :( seems tahat our listner has gone away.. - // @TODO handle this .. - ShowError("_network_accept: accept() returned error. closing listener. (errno: %u / %s)\n", errno, strerror(errno)); + if (newfd == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + break; // this is fully valid & whished., se explaination on top of while(1) + + // Otherwis .. we have serious problems :( seems tahat our listner has gone away.. + // @TODO handle this .. + ShowError("_network_accept: accept() returned error. closing listener. (errno: %u / %s)\n", errno, strerror(errno)); - return false; // will call disconnect after return. - //break; - } + return false; // will call disconnect after return. + //break; + } #ifndef HAVE_ACCEPT4 // no accept4 means, we have to set nonblock by ourself. .. - if(_setnonblock(newfd) == false){ - ShowError("_network_accept: failed to set newly accepted connection nonblocking (errno: %u / %s). - disconnecting.\n", errno, strerror(errno)); - close(newfd); - continue; - } + if (_setnonblock(newfd) == false) { + ShowError("_network_accept: failed to set newly accepted connection nonblocking (errno: %u / %s). - disconnecting.\n", errno, strerror(errno)); + close(newfd); + continue; + } #endif - // Check connection limits. - if(newfd >= MAXCONN){ - ShowError("_network_accept: failed to accept connection - MAXCONN (%u) exceeded.\n", MAXCONN); - close(newfd); - continue; // we have to loop over the events (and disconnect them too ..) but otherwise we would leak event notifications. - } - - - // Create new Session. - s = &g_Session[newfd]; - s->type = NST_CLIENT; - - // The new connection inherits listenr's handlers. - s->onDisconnect = listener->onDisconnect; - s->onConnect = listener->onConnect; // maybe useless but .. fear the future .. :~ - - // Register the new connection @ EVDP - if( evdp_addclient(newfd, &s->evdp_data) == false){ - ShowError("_network_accept: failed to accept connection - event subsystem returned an error.\n"); - close(newfd); - s->type = NST_FREE; - } - - // Call the onConnect handler on the listener. - if( listener->onConnect(newfd) == false ){ - // Resfused by onConnect handler.. - evdp_remove(newfd, &s->evdp_data); - - close(newfd); - s->type = NST_FREE; - - s->data = NULL; // be on the safe side ~ ! - continue; - } - - - } - - return true; + // Check connection limits. + if (newfd >= MAXCONN) { + ShowError("_network_accept: failed to accept connection - MAXCONN (%u) exceeded.\n", MAXCONN); + close(newfd); + continue; // we have to loop over the events (and disconnect them too ..) but otherwise we would leak event notifications. + } + + + // Create new Session. + s = &g_Session[newfd]; + s->type = NST_CLIENT; + + // The new connection inherits listenr's handlers. + s->onDisconnect = listener->onDisconnect; + s->onConnect = listener->onConnect; // maybe useless but .. fear the future .. :~ + + // Register the new connection @ EVDP + if (evdp_addclient(newfd, &s->evdp_data) == false) { + ShowError("_network_accept: failed to accept connection - event subsystem returned an error.\n"); + close(newfd); + s->type = NST_FREE; + } + + // Call the onConnect handler on the listener. + if (listener->onConnect(newfd) == false) { + // Resfused by onConnect handler.. + evdp_remove(newfd, &s->evdp_data); + + close(newfd); + s->type = NST_FREE; + + s->data = NULL; // be on the safe side ~ ! + continue; + } + + + } + + return true; }//end: _network_accept() -void network_disconnect(int32 fd){ - SESSION *s = &g_Session[fd]; - netbuf b, bn; - - // Prevent recursive calls - // by wrong implemented on disconnect handlers.. and such.. - if(s->disconnect_in_progress == true) - return; - - s->disconnect_in_progress = true; - - - // Disconnect Todo: - // - Call onDisconnect Handler - // - Release all Assigned buffers. - // - remove from event system (notifications) - // - cleanup session structure - // - close connection. - // - - if(s->onDisconnect != NULL && - s->type != NST_LISTENER){ - - s->onDisconnect( fd ); - } - - // Read Buffer - if(s->read.buf != NULL){ - netbuffer_put(s->read.buf); - s->read.buf = NULL; - } - - // Write Buffer(s) - b = s->write.buf; - while(1){ - if(b == NULL) break; - - bn = b->next; - - netbuffer_put(b); - - b = bn; - } - s->write.buf = NULL; - s->write.buf_last = NULL; - - s->write.n_outstanding = 0; - s->write.max_outstanding = 0; - - - // Remove from event system. - evdp_remove(fd, &s->evdp_data); - - // Cleanup Session Structure. - s->type = NST_FREE; - s->data = NULL; // no application level data assigned - s->disconnect_in_progress = false; - - - // Close connection - close(fd); - +void network_disconnect(int32 fd) +{ + SESSION *s = &g_Session[fd]; + netbuf b, bn; + + // Prevent recursive calls + // by wrong implemented on disconnect handlers.. and such.. + if (s->disconnect_in_progress == true) + return; + + s->disconnect_in_progress = true; + + + // Disconnect Todo: + // - Call onDisconnect Handler + // - Release all Assigned buffers. + // - remove from event system (notifications) + // - cleanup session structure + // - close connection. + // + + if (s->onDisconnect != NULL && + s->type != NST_LISTENER) { + + s->onDisconnect(fd); + } + + // Read Buffer + if (s->read.buf != NULL) { + netbuffer_put(s->read.buf); + s->read.buf = NULL; + } + + // Write Buffer(s) + b = s->write.buf; + while (1) { + if (b == NULL) break; + + bn = b->next; + + netbuffer_put(b); + + b = bn; + } + s->write.buf = NULL; + s->write.buf_last = NULL; + + s->write.n_outstanding = 0; + s->write.max_outstanding = 0; + + + // Remove from event system. + evdp_remove(fd, &s->evdp_data); + + // Cleanup Session Structure. + s->type = NST_FREE; + s->data = NULL; // no application level data assigned + s->disconnect_in_progress = false; + + + // Close connection + close(fd); + }//end: network_disconnect() -int32 network_addlistener(bool v6, const char *addr, uint16 port){ - SESSION *s; - int optval, fd; +int32 network_addlistener(bool v6, const char *addr, uint16 port) +{ + SESSION *s; + int optval, fd; #if !defined(ENABLE_IPV6) - if(v6 == true){ - ShowError("network_addlistener(%c, '%s', %u): this release has no IPV6 support.\n", (v6==true?'t':'f'), addr, port); - return -1; - } + if (v6 == true) { + ShowError("network_addlistener(%c, '%s', %u): this release has no IPV6 support.\n", (v6==true?'t':'f'), addr, port); + return -1; + } #endif #ifdef ENABLE_IPV6 - if(v6 == true) - fd = socket(AF_INET6, SOCK_STREAM, 0); - else + if (v6 == true) + fd = socket(AF_INET6, SOCK_STREAM, 0); + else #endif - fd = socket(AF_INET, SOCK_STREAM, 0); - - // Error? - if(fd == -1){ - ShowError("network_addlistener(%c, '%s', %u): socket() failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - return -1; - } - - // Too many connections? - if(fd >= MAXCONN){ - ShowError("network_addlistener(%c, '%s', %u): cannot create listener, exceeds more than supported connections (%u).\n", (v6==true?'t':'f'), addr, port, MAXCONN); - close(fd); - return -1; - } - - - s = &g_Session[fd]; - if(s->type != NST_FREE){ // additional checks.. :) - ShowError("network_addlistener(%c, '%s', %u): failed, got fd #%u which is already in use in local session table?!\n", (v6==true?'t':'f'), addr, port, fd); - close(fd); - return -1; - } - - - // Fill ip addr structs + fd = socket(AF_INET, SOCK_STREAM, 0); + + // Error? + if (fd == -1) { + ShowError("network_addlistener(%c, '%s', %u): socket() failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + return -1; + } + + // Too many connections? + if (fd >= MAXCONN) { + ShowError("network_addlistener(%c, '%s', %u): cannot create listener, exceeds more than supported connections (%u).\n", (v6==true?'t':'f'), addr, port, MAXCONN); + close(fd); + return -1; + } + + + s = &g_Session[fd]; + if (s->type != NST_FREE) { // additional checks.. :) + ShowError("network_addlistener(%c, '%s', %u): failed, got fd #%u which is already in use in local session table?!\n", (v6==true?'t':'f'), addr, port, fd); + close(fd); + return -1; + } + + + // Fill ip addr structs #ifdef ENABLE_IPV6 - if(v6 == true){ - memset(&s->addr.v6, 0x00, sizeof(s->addr.v6)); - s->addr.v6.sin6_family = AF_INET6; - s->addr.v6.sin6_port = htons(port); - if(inet_pton(AF_INET6, addr, &s->addr.v6.sin6_addr) != 1){ - ShowError("network_addlistener(%c, '%s', %u): failed to parse the given IPV6 address.\n", (v6==true?'t':'f'), addr, port); - close(fd); - return -1; - } - - }else{ + if (v6 == true) { + memset(&s->addr.v6, 0x00, sizeof(s->addr.v6)); + s->addr.v6.sin6_family = AF_INET6; + s->addr.v6.sin6_port = htons(port); + if (inet_pton(AF_INET6, addr, &s->addr.v6.sin6_addr) != 1) { + ShowError("network_addlistener(%c, '%s', %u): failed to parse the given IPV6 address.\n", (v6==true?'t':'f'), addr, port); + close(fd); + return -1; + } + + } else { #endif - memset(&s->addr.v4, 0x00, sizeof(s->addr.v4)); - s->addr.v4.sin_family = AF_INET; - s->addr.v4.sin_port = htons(port); - s->addr.v4.sin_addr.s_addr = inet_addr(addr); + memset(&s->addr.v4, 0x00, sizeof(s->addr.v4)); + s->addr.v4.sin_family = AF_INET; + s->addr.v4.sin_port = htons(port); + s->addr.v4.sin_addr.s_addr = inet_addr(addr); #ifdef ENABLE_IPV6 - } + } #endif - - // if OS has support for SO_REUSEADDR, apply the flag - // so the address could be used when there're still time_wait sockets outstanding from previous application run. + + // if OS has support for SO_REUSEADDR, apply the flag + // so the address could be used when there're still time_wait sockets outstanding from previous application run. #ifdef SO_REUSEADDR - optval=1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + optval=1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); #endif - // Bind + // Bind #ifdef ENABLE_IPV6 - if(v6 == true){ - if( bind(fd, (struct sockaddr*)&s->addr.v6, sizeof(s->addr.v6)) == -1) { - ShowError("network_addlistener(%c, '%s', %u): bind failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } - }else{ + if (v6 == true) { + if (bind(fd, (struct sockaddr *)&s->addr.v6, sizeof(s->addr.v6)) == -1) { + ShowError("network_addlistener(%c, '%s', %u): bind failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } + } else { #endif - if( bind(fd, (struct sockaddr*)&s->addr.v4, sizeof(s->addr.v4)) == -1) { - ShowError("network_addlistener(%c, '%s', %u): bind failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } + if (bind(fd, (struct sockaddr *)&s->addr.v4, sizeof(s->addr.v4)) == -1) { + ShowError("network_addlistener(%c, '%s', %u): bind failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } #ifdef ENABLE_IPV6 - } + } #endif - if( listen(fd, l_ListenBacklog) == -1){ - ShowError("network_addlistener(%c, '%s', %u): listen failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } - - - // Set to nonblock! - if(_setnonblock(fd) == false){ - ShowError("network_addlistener(%c, '%s', %u): cannot set to nonblock (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } - - - // Rgister @ evdp. - if( evdp_addlistener(fd, &s->evdp_data) != true){ - ShowError("network_addlistener(%c, '%s', %u): eventdispatcher subsystem returned an error.\n", (v6==true?'t':'f'), addr, port); - close(fd); - return -1; - } - - - // Apply flags on Session array for this conneciton. - if(v6 == true) s->v6 = true; - else s->v6 = false; - - s->type = NST_LISTENER; - s->onRecv = _network_accept; - - ShowStatus("Added Listener on '%s':%u\n", addr, port, (v6==true ? "(ipv6)":"(ipv4)") ); - - return fd; + if (listen(fd, l_ListenBacklog) == -1) { + ShowError("network_addlistener(%c, '%s', %u): listen failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } + + + // Set to nonblock! + if (_setnonblock(fd) == false) { + ShowError("network_addlistener(%c, '%s', %u): cannot set to nonblock (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } + + + // Rgister @ evdp. + if (evdp_addlistener(fd, &s->evdp_data) != true) { + ShowError("network_addlistener(%c, '%s', %u): eventdispatcher subsystem returned an error.\n", (v6==true?'t':'f'), addr, port); + close(fd); + return -1; + } + + + // Apply flags on Session array for this conneciton. + if (v6 == true) s->v6 = true; + else s->v6 = false; + + s->type = NST_LISTENER; + s->onRecv = _network_accept; + + ShowStatus("Added Listener on '%s':%u\n", addr, port, (v6==true ? "(ipv6)":"(ipv4)")); + + return fd; }//end: network_addlistener() -static bool _network_connect_establishedHandler(int32 fd){ - register SESSION *s = &g_Session[fd]; - int val; - socklen_t val_len; - - if(s->type == NST_FREE) - return true; // due to multiple non coalesced event notifications - // this can happen .. when a previous handled event has already disconnected the connection - // within the same cycle.. - - val = -1; - val_len = sizeof(val); - getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &val_len); - - if(val != 0){ - // :( .. cleanup session.. - s->type = NST_FREE; - s->onSend = NULL; - s->onConnect = NULL; - s->onDisconnect = NULL; - - evdp_remove(fd, &s->evdp_data); - close(fd); - - return true; // we CANT return false, - // becuase the normal disconnect procedure would execute the ondisconnect handler, which we dont want .. in this case. - }else{ - // ok - if(s->onConnect(fd) == false) { - // onConnect handler has refused the connection .. - // cleanup .. and ok - s->type = NST_FREE; - s->onSend = NULL; - s->onConnect = NULL; - s->onDisconnect = NULL; - - evdp_remove(fd, &s->evdp_data); - close(fd); - - return true; // we dnot want the ondisconnect handler to be executed, so its okay to handle this by ourself. - } - - // connection established ! - // - if( evdp_outgoingconnection_established(fd, &s->evdp_data) == false ){ - return false; // we want the normal disconnect procedure.. with call to ondisconnect handler. - } - - s->onSend = NULL; - - ShowStatus("#%u connection successfull!\n", fd); - } - - return true; +static bool _network_connect_establishedHandler(int32 fd) +{ + register SESSION *s = &g_Session[fd]; + int val; + socklen_t val_len; + + if (s->type == NST_FREE) + return true; // due to multiple non coalesced event notifications + // this can happen .. when a previous handled event has already disconnected the connection + // within the same cycle.. + + val = -1; + val_len = sizeof(val); + getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &val_len); + + if (val != 0) { + // :( .. cleanup session.. + s->type = NST_FREE; + s->onSend = NULL; + s->onConnect = NULL; + s->onDisconnect = NULL; + + evdp_remove(fd, &s->evdp_data); + close(fd); + + return true; // we CANT return false, + // becuase the normal disconnect procedure would execute the ondisconnect handler, which we dont want .. in this case. + } else { + // ok + if (s->onConnect(fd) == false) { + // onConnect handler has refused the connection .. + // cleanup .. and ok + s->type = NST_FREE; + s->onSend = NULL; + s->onConnect = NULL; + s->onDisconnect = NULL; + + evdp_remove(fd, &s->evdp_data); + close(fd); + + return true; // we dnot want the ondisconnect handler to be executed, so its okay to handle this by ourself. + } + + // connection established ! + // + if (evdp_outgoingconnection_established(fd, &s->evdp_data) == false) { + return false; // we want the normal disconnect procedure.. with call to ondisconnect handler. + } + + s->onSend = NULL; + + ShowStatus("#%u connection successfull!\n", fd); + } + + return true; }//end: _network_connect_establishedHandler() int32 network_connect(bool v6, - const char *addr, - uint16 port, - const char *from_addr, - uint16 from_port, - bool (*onConnectionEstablishedHandler)(int32 fd), - void (*onConnectionLooseHandler)(int32 fd) -){ - register SESSION *s; - int32 fd, optval, ret; - struct sockaddr_in ip4; + const char *addr, + uint16 port, + const char *from_addr, + uint16 from_port, + bool (*onConnectionEstablishedHandler)(int32 fd), + void (*onConnectionLooseHandler)(int32 fd) + ) +{ + register SESSION *s; + int32 fd, optval, ret; + struct sockaddr_in ip4; #ifdef ENABLE_IPV6 - struct sockaddr_in6 ip6; + struct sockaddr_in6 ip6; #endif #ifdef ENABLE_IPV6 - if(v6 == true) - fd = socket(AF_INET6, SOCK_STREAM, 0); - else + if (v6 == true) + fd = socket(AF_INET6, SOCK_STREAM, 0); + else #endif - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = socket(AF_INET, SOCK_STREAM, 0); #ifndef ENABLE_IPV6 - // check.. - if(v6 == true){ - ShowError("network_connect(%c, '%s', %u...): tried to create an ipv6 connection, IPV6 is not supported in this release.\n", (v6==true?'t':'f'), addr, port); - return -1; - } + // check.. + if (v6 == true) { + ShowError("network_connect(%c, '%s', %u...): tried to create an ipv6 connection, IPV6 is not supported in this release.\n", (v6==true?'t':'f'), addr, port); + return -1; + } #endif - // check connection limits. - if(fd >= MAXCONN){ - ShowError("network_connect(%c, '%s', %u...): cannot create new connection, exceeeds more than supported connections (%u)\n", (v6==true?'t':'f'), addr, port ); - close(fd); - return -1; - } - - - // Originating IP/Port pair given ? - if(from_addr != NULL && *from_addr != 0){ - //.. - #ifdef SO_REUSEADDR - optval=1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); - #endif - - #ifdef ENABLE_IPV6 - if(v6 == true){ - memset(&ip6, 0x00, sizeof(ip6)); - ip6.sin6_family = AF_INET6; - ip6.sin6_port = htons(from_port); - - if(inet_pton(AF_INET6, from_addr, &ip6.sin6_addr) != 1){ - ShowError("network_connect(%c, '%s', %u...): cannot parse originating (from) IPV6 address (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } - - ret = bind(fd, (struct sockaddr*)&ip6, sizeof(ip6)); - }else{ - #endif - memset(&ip4, 0x00, sizeof(ip4)); - - ip4.sin_family = AF_INET; - ip4.sin_port = htons(from_port); - ip4.sin_addr.s_addr = inet_addr(from_addr); - ret = bind(fd, (struct sockaddr*)&ip4, sizeof(ip4)); - #ifdef ENABLE_IPV6 - } - #endif - - } - - - // Set non block - if(_setnonblock(fd) == false){ - ShowError("network_connect(%c, '%s', %u...): cannot set socket to nonblocking (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } - - - // Create ip addr block to connect to .. + // check connection limits. + if (fd >= MAXCONN) { + ShowError("network_connect(%c, '%s', %u...): cannot create new connection, exceeeds more than supported connections (%u)\n", (v6==true?'t':'f'), addr, port); + close(fd); + return -1; + } + + + // Originating IP/Port pair given ? + if (from_addr != NULL && *from_addr != 0) { + //.. +#ifdef SO_REUSEADDR + optval=1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); +#endif + +#ifdef ENABLE_IPV6 + if (v6 == true) { + memset(&ip6, 0x00, sizeof(ip6)); + ip6.sin6_family = AF_INET6; + ip6.sin6_port = htons(from_port); + + if (inet_pton(AF_INET6, from_addr, &ip6.sin6_addr) != 1) { + ShowError("network_connect(%c, '%s', %u...): cannot parse originating (from) IPV6 address (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } + + ret = bind(fd, (struct sockaddr *)&ip6, sizeof(ip6)); + } else { +#endif + memset(&ip4, 0x00, sizeof(ip4)); + + ip4.sin_family = AF_INET; + ip4.sin_port = htons(from_port); + ip4.sin_addr.s_addr = inet_addr(from_addr); + ret = bind(fd, (struct sockaddr *)&ip4, sizeof(ip4)); #ifdef ENABLE_IPV6 - if(v6 == true){ - memset(&ip6, 0x00, sizeof(ip6)); - ip6.sin6_family = AF_INET6; - ip6.sin6_port = htons(port); - - if(inet_pton(AF_INET6, addr, &ip6.sin6_addr) != 1){ - ShowError("network_connect(%c, '%s', %u...): cannot parse destination IPV6 address (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - close(fd); - return -1; - } - - }else{ + } #endif - memset(&ip4, 0x00, sizeof(ip4)); - - ip4.sin_family = AF_INET; - ip4.sin_port = htons(port); - ip4.sin_addr.s_addr = inet_addr(addr); + + } + + + // Set non block + if (_setnonblock(fd) == false) { + ShowError("network_connect(%c, '%s', %u...): cannot set socket to nonblocking (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } + + + // Create ip addr block to connect to .. +#ifdef ENABLE_IPV6 + if (v6 == true) { + memset(&ip6, 0x00, sizeof(ip6)); + ip6.sin6_family = AF_INET6; + ip6.sin6_port = htons(port); + + if (inet_pton(AF_INET6, addr, &ip6.sin6_addr) != 1) { + ShowError("network_connect(%c, '%s', %u...): cannot parse destination IPV6 address (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + close(fd); + return -1; + } + + } else { +#endif + memset(&ip4, 0x00, sizeof(ip4)); + + ip4.sin_family = AF_INET; + ip4.sin_port = htons(port); + ip4.sin_addr.s_addr = inet_addr(addr); #ifdef ENABLE_IPV6 - } + } #endif - // Assign Session.. - s = &g_Session[fd]; - s->type = NST_OUTGOING; - s->v6 = v6; - s->onConnect = onConnectionEstablishedHandler; - s->onDisconnect = onConnectionLooseHandler; - s->onRecv = NULL; - s->onSend = _network_connect_establishedHandler; + // Assign Session.. + s = &g_Session[fd]; + s->type = NST_OUTGOING; + s->v6 = v6; + s->onConnect = onConnectionEstablishedHandler; + s->onDisconnect = onConnectionLooseHandler; + s->onRecv = NULL; + s->onSend = _network_connect_establishedHandler; #ifdef ENABLE_IPV6 - if(v6 == true) - memcpy(&s->addr.v6, &ip6, sizeof(ip6)); - else + if (v6 == true) + memcpy(&s->addr.v6, &ip6, sizeof(ip6)); + else #endif - memcpy(&s->addr.v4, &ip4, sizeof(ip4)); - - // Register @ EVDP. as outgoing (see doc of the function) - if(evdp_addconnecting(fd, &s->evdp_data) == false){ - ShowError("network_connect(%c, '%s', %u...): eventdispatcher subsystem returned an error.\n", (v6==true?'t':'f'), addr, port); - - // cleanup session x.x.. - s->type = NST_FREE; - s->onConnect = NULL; - s->onDisconnect = NULL; - s->onSend = NULL; - - // close, return error code. - close(fd); - return -1; - } + memcpy(&s->addr.v4, &ip4, sizeof(ip4)); + + // Register @ EVDP. as outgoing (see doc of the function) + if (evdp_addconnecting(fd, &s->evdp_data) == false) { + ShowError("network_connect(%c, '%s', %u...): eventdispatcher subsystem returned an error.\n", (v6==true?'t':'f'), addr, port); + + // cleanup session x.x.. + s->type = NST_FREE; + s->onConnect = NULL; + s->onDisconnect = NULL; + s->onSend = NULL; + + // close, return error code. + close(fd); + return -1; + } #ifdef ENABLE_IPV6 - if(v6 == true) - ret = connect(fd, (struct sockaddr*)&ip6, sizeof(ip6)); - else + if (v6 == true) + ret = connect(fd, (struct sockaddr *)&ip6, sizeof(ip6)); + else #endif - ret = connect(fd, (struct sockaddr*)&ip4, sizeof(ip4)); - - - // - if(ret != 0 && errno != EINPROGRESS){ - ShowWarning("network_connect(%c, '%s', %u...): connection failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); - - // Cleanup session .. - s->type = NST_FREE; - s->onConnect = NULL; - s->onDisconnect = NULL; - s->onSend = NULL; - - // .. remove from evdp and close fd. - evdp_remove(fd, &s->evdp_data); - close(fd); - return -1; - } - - - // ! The Info Message :~D - ShowStatus("network_connect fd#%u (%s:%u) in progress.. \n", fd, addr, port); - -return fd; + ret = connect(fd, (struct sockaddr *)&ip4, sizeof(ip4)); + + + // + if (ret != 0 && errno != EINPROGRESS) { + ShowWarning("network_connect(%c, '%s', %u...): connection failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); + + // Cleanup session .. + s->type = NST_FREE; + s->onConnect = NULL; + s->onDisconnect = NULL; + s->onSend = NULL; + + // .. remove from evdp and close fd. + evdp_remove(fd, &s->evdp_data); + close(fd); + return -1; + } + + + // ! The Info Message :~D + ShowStatus("network_connect fd#%u (%s:%u) in progress.. \n", fd, addr, port); + + return fd; }//end: network_connect() -static bool _onSend(int32 fd){ - register SESSION *s = &g_Session[fd]; - register netbuf buf, buf_next; - register uint32 szNeeded; - register int wLen; - - if(s->type == NST_FREE) - return true; // Possible due to multipl non coalsced event notifications - // so onSend gets called after disconnect caused by an previous vent. - // we can ignore the call to onSend, then. - - buf = s->write.buf; - while(1){ - if(buf == NULL) - break; - - buf_next = buf->next; - - - szNeeded = (buf->dataLen - s->write.dataPos); // using th session-local .dataPos member, due to shared write buffer support. - - // try to write. - wLen = write(fd, &buf->buf[s->write.dataPos], szNeeded); - if(wLen == 0){ - return false; // eof. - }else if(wLen == -1){ - if(errno == EAGAIN || errno == EWOULDBLOCK) - return true; // dont disconnect / try again later. - - // all other errors. . - return false; - } - - // Wrote data.. => - szNeeded -= wLen; - if(szNeeded > 0){ - // still data left .. - // - s->write.dataPos += wLen; // fix offset. - return true; - }else{ - // this buffer has been written successfully - // could be returned to pool. - netbuffer_put(buf); - s->write.n_outstanding--; // When threadsafe -> Interlocked here. - s->write.dataPos = 0; - } - - - buf = buf_next; - } - - // okay, - // reaching this part means: - // while interrupted by break - - // which means all buffers are written, nothing left - // - - s->write.buf_last = NULL; - s->write.buf = NULL; - s->write.n_outstanding = 0; - s->write.dataPos = 0; - - // Remove from event dispatcher (write notification) - // - evdp_writable_remove(fd, &s->evdp_data); - - return true; +static bool _onSend(int32 fd) +{ + register SESSION *s = &g_Session[fd]; + register netbuf buf, buf_next; + register uint32 szNeeded; + register int wLen; + + if (s->type == NST_FREE) + return true; // Possible due to multipl non coalsced event notifications + // so onSend gets called after disconnect caused by an previous vent. + // we can ignore the call to onSend, then. + + buf = s->write.buf; + while (1) { + if (buf == NULL) + break; + + buf_next = buf->next; + + + szNeeded = (buf->dataLen - s->write.dataPos); // using th session-local .dataPos member, due to shared write buffer support. + + // try to write. + wLen = write(fd, &buf->buf[s->write.dataPos], szNeeded); + if (wLen == 0) { + return false; // eof. + } else if (wLen == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + return true; // dont disconnect / try again later. + + // all other errors. . + return false; + } + + // Wrote data.. => + szNeeded -= wLen; + if (szNeeded > 0) { + // still data left .. + // + s->write.dataPos += wLen; // fix offset. + return true; + } else { + // this buffer has been written successfully + // could be returned to pool. + netbuffer_put(buf); + s->write.n_outstanding--; // When threadsafe -> Interlocked here. + s->write.dataPos = 0; + } + + + buf = buf_next; + } + + // okay, + // reaching this part means: + // while interrupted by break - + // which means all buffers are written, nothing left + // + + s->write.buf_last = NULL; + s->write.buf = NULL; + s->write.n_outstanding = 0; + s->write.dataPos = 0; + + // Remove from event dispatcher (write notification) + // + evdp_writable_remove(fd, &s->evdp_data); + + return true; }//end: _onSend() -static bool _onRORecv(int32 fd){ - register SESSION *s = &g_Session[fd]; - register uint32 szNeeded; - register char *p; - register int rLen; - - if(s->type == NST_FREE) - return true; // Possible due to multiple non coalesced events by evdp. - // simply ignore this call returning positive result. - - // Initialize p and szNeeded depending on change - // - switch(s->read.state){ - case NRS_WAITOP: - szNeeded = s->read.head_left; - p = ((char*)&s->read.head[0]) + (2-szNeeded); - break; - - case NRS_WAITLEN: - szNeeded = s->read.head_left; - p = ((char*)&s->read.head[1]) + (2-szNeeded); - break; - - case NRS_WAITDATA:{ - register netbuf buf = s->read.buf; - - szNeeded = (buf->dataLen - buf->dataPos); - p = (char*)&buf->buf[ buf->dataPos ]; - } - break; - - default: - // .. the impossible gets possible .. - ShowError("_onRORecv: fd #%u has unknown read.state (%d) - disconnecting\n", fd, s->read.state); - return false; - break; - } - - - // - - rLen = read(fd, p, szNeeded); - if(rLen == 0){ - // eof.. - return false; - }else if(rLen == -1){ - - if(errno == EAGAIN || errno == EWOULDBLOCK){ - // try again later .. (this case shouldnt happen, because we're event trigered.. but .. sometimes it happens :) - return true; - } - - // an additional interesting case would be - // EINTR, this 'could' be handled .. but: - // posix says that its possible that data gets currupted during irq - // or data gor read and not reported.., so we'd have a data loss.. - // (which shouldnt happen with stream based protocols such as tcp) - // its better to disonnect the client in that case. - - return false; - } - - // - // Got Data: - // next action also depends on current state .. - // - szNeeded -= rLen; - switch(s->read.state){ - case NRS_WAITOP: - - if(szNeeded > 0){ - // still data missing .. - s->read.head_left = szNeeded; - return true; // wait for completion. - }else{ - // complete .. - // next state depends on packet type. - - s->read.head[1] = ((uint16*)s->netparser_data)[ s->read.head[0] ]; // store lenght of packet by opcode head[0] to head[1] - - if(s->read.head[1] == ROPACKET_UNKNOWN){ - // unknown packet - disconnect - ShowWarning("_onRORecv: fd #%u got unlnown packet 0x%04x - disconnecting.\n", fd, s->read.head[0]); - return false; - } - else if(s->read.head[1] == ROPACKET_DYNLEN){ - // dynamic length - // next state: requrie len. - s->read.state = NRS_WAITLEN; - s->read.head_left = 2; - return true; // - } - else if(s->read.head[1] == 2){ - // packet has no data (only opcode) - register netbuf buf = netbuffer_get(2); // :D whoohoo its giant! - - NBUFW(buf, 0) = s->read.head[0]; // store opcode @ packet begin. - buf->dataPos = 2; - buf->dataLen = 2; - buf->next = NULL; - - // Back to initial state -> Need opcode. - s->read.state = NRS_WAITOP; - s->read.head_left = 2; - s->read.buf = NULL; - - // Call completion routine here. - s->onPacketComplete(fd, s->read.head[0], 2, buf); - - return true; // done :) - } - else{ - // paket needs .. data .. - register netbuf buf = netbuffer_get( s->read.head[1] ); - - NBUFW(buf, 0) = s->read.head[0]; // store opcode @ packet begin. - buf->dataPos = 2; - buf->dataLen = s->read.head[1]; - buf->next = NULL; - - // attach buffer. - s->read.buf = buf; - - // set state: - s->read.state = NRS_WAITDATA; - - return true; - } - - }//endif: szNeeded > 0 (opcode read completed?) - - break; - - - case NRS_WAITLEN: - - if(szNeeded > 0){ - // incomplete .. - s->read.head_left = szNeeded; - return true; - }else{ - - if(s->read.head[1] == 4){ - // packet has no data (only opcode + length) - register netbuf buf = netbuffer_get( 4 ); - - NBUFL(buf, 0) = *((uint32*)&s->read.head[0]); // copy Opcode + length to netbuffer using MOVL - buf->dataPos = 4; - buf->dataLen = 4; - buf->next = NULL; - - // set initial state (need opcode) - s->read.state = NRS_WAITOP; - s->read.head_left = 2; - s->read.buf = NULL; - - // call completion routine. - s->onPacketComplete(fd, s->read.head[0], 4, buf); - - return true; - } - else if(s->read.head[1] < 4){ - // invalid header. - ShowWarning("_onRORecv: fd #%u invalid header - got packet 0x%04x, reported length < 4 - INVALID - disconnecting\n", fd, s->read.head[0]); - return false; - } - else{ - // Data needed - // next state -> waitdata! - register netbuf buf = netbuffer_get( s->read.head[1] ); - - NBUFL(buf, 0) = *((uint32*)&s->read.head[0]); // copy Opcode + length to netbuffer using MOVL - buf->dataPos = 4; - buf->dataLen = s->read.head[1]; - buf->next = NULL; - - // attach to session: - s->read.buf = buf; - s->read.state = NRS_WAITDATA; - - return true; - } - - }//endif: szNeeded > 0 (length read complete?) - - break; - - - case NRS_WAITDATA: - - if(szNeeded == 0){ - // Packet finished! - // compltion. - register netbuf buf = s->read.buf; - - // set initial state. - s->read.state = NRS_WAITOP; - s->read.head_left = 2; - s->read.buf = NULL; - - // Call completion routine. - s->onPacketComplete(fd, NBUFW(buf, 0), buf->dataLen, buf); - - return true; - }else{ - // still data needed - s->read.buf->dataPos += rLen; - - return true; - } - break; - - - // - default: - ShowError("_onRORecv: fd #%u has unknown read.state (%d) [2] - disconnecting\n", fd, s->read.state); - return false; - break; - } - - - return false; +static bool _onRORecv(int32 fd) +{ + register SESSION *s = &g_Session[fd]; + register uint32 szNeeded; + register char *p; + register int rLen; + + if (s->type == NST_FREE) + return true; // Possible due to multiple non coalesced events by evdp. + // simply ignore this call returning positive result. + + // Initialize p and szNeeded depending on change + // + switch (s->read.state) { + case NRS_WAITOP: + szNeeded = s->read.head_left; + p = ((char *)&s->read.head[0]) + (2-szNeeded); + break; + + case NRS_WAITLEN: + szNeeded = s->read.head_left; + p = ((char *)&s->read.head[1]) + (2-szNeeded); + break; + + case NRS_WAITDATA: { + register netbuf buf = s->read.buf; + + szNeeded = (buf->dataLen - buf->dataPos); + p = (char *)&buf->buf[ buf->dataPos ]; + } + break; + + default: + // .. the impossible gets possible .. + ShowError("_onRORecv: fd #%u has unknown read.state (%d) - disconnecting\n", fd, s->read.state); + return false; + break; + } + + + // + + rLen = read(fd, p, szNeeded); + if (rLen == 0) { + // eof.. + return false; + } else if (rLen == -1) { + + if (errno == EAGAIN || errno == EWOULDBLOCK) { + // try again later .. (this case shouldnt happen, because we're event trigered.. but .. sometimes it happens :) + return true; + } + + // an additional interesting case would be + // EINTR, this 'could' be handled .. but: + // posix says that its possible that data gets currupted during irq + // or data gor read and not reported.., so we'd have a data loss.. + // (which shouldnt happen with stream based protocols such as tcp) + // its better to disonnect the client in that case. + + return false; + } + + // + // Got Data: + // next action also depends on current state .. + // + szNeeded -= rLen; + switch (s->read.state) { + case NRS_WAITOP: + + if (szNeeded > 0) { + // still data missing .. + s->read.head_left = szNeeded; + return true; // wait for completion. + } else { + // complete .. + // next state depends on packet type. + + s->read.head[1] = ((uint16 *)s->netparser_data)[ s->read.head[0] ]; // store lenght of packet by opcode head[0] to head[1] + + if (s->read.head[1] == ROPACKET_UNKNOWN) { + // unknown packet - disconnect + ShowWarning("_onRORecv: fd #%u got unlnown packet 0x%04x - disconnecting.\n", fd, s->read.head[0]); + return false; + } else if (s->read.head[1] == ROPACKET_DYNLEN) { + // dynamic length + // next state: requrie len. + s->read.state = NRS_WAITLEN; + s->read.head_left = 2; + return true; // + } else if (s->read.head[1] == 2) { + // packet has no data (only opcode) + register netbuf buf = netbuffer_get(2); // :D whoohoo its giant! + + NBUFW(buf, 0) = s->read.head[0]; // store opcode @ packet begin. + buf->dataPos = 2; + buf->dataLen = 2; + buf->next = NULL; + + // Back to initial state -> Need opcode. + s->read.state = NRS_WAITOP; + s->read.head_left = 2; + s->read.buf = NULL; + + // Call completion routine here. + s->onPacketComplete(fd, s->read.head[0], 2, buf); + + return true; // done :) + } else { + // paket needs .. data .. + register netbuf buf = netbuffer_get(s->read.head[1]); + + NBUFW(buf, 0) = s->read.head[0]; // store opcode @ packet begin. + buf->dataPos = 2; + buf->dataLen = s->read.head[1]; + buf->next = NULL; + + // attach buffer. + s->read.buf = buf; + + // set state: + s->read.state = NRS_WAITDATA; + + return true; + } + + }//endif: szNeeded > 0 (opcode read completed?) + + break; + + + case NRS_WAITLEN: + + if (szNeeded > 0) { + // incomplete .. + s->read.head_left = szNeeded; + return true; + } else { + + if (s->read.head[1] == 4) { + // packet has no data (only opcode + length) + register netbuf buf = netbuffer_get(4); + + NBUFL(buf, 0) = *((uint32 *)&s->read.head[0]); // copy Opcode + length to netbuffer using MOVL + buf->dataPos = 4; + buf->dataLen = 4; + buf->next = NULL; + + // set initial state (need opcode) + s->read.state = NRS_WAITOP; + s->read.head_left = 2; + s->read.buf = NULL; + + // call completion routine. + s->onPacketComplete(fd, s->read.head[0], 4, buf); + + return true; + } else if (s->read.head[1] < 4) { + // invalid header. + ShowWarning("_onRORecv: fd #%u invalid header - got packet 0x%04x, reported length < 4 - INVALID - disconnecting\n", fd, s->read.head[0]); + return false; + } else { + // Data needed + // next state -> waitdata! + register netbuf buf = netbuffer_get(s->read.head[1]); + + NBUFL(buf, 0) = *((uint32 *)&s->read.head[0]); // copy Opcode + length to netbuffer using MOVL + buf->dataPos = 4; + buf->dataLen = s->read.head[1]; + buf->next = NULL; + + // attach to session: + s->read.buf = buf; + s->read.state = NRS_WAITDATA; + + return true; + } + + }//endif: szNeeded > 0 (length read complete?) + + break; + + + case NRS_WAITDATA: + + if (szNeeded == 0) { + // Packet finished! + // compltion. + register netbuf buf = s->read.buf; + + // set initial state. + s->read.state = NRS_WAITOP; + s->read.head_left = 2; + s->read.buf = NULL; + + // Call completion routine. + s->onPacketComplete(fd, NBUFW(buf, 0), buf->dataLen, buf); + + return true; + } else { + // still data needed + s->read.buf->dataPos += rLen; + + return true; + } + break; + + + // + default: + ShowError("_onRORecv: fd #%u has unknown read.state (%d) [2] - disconnecting\n", fd, s->read.state); + return false; + break; + } + + + return false; }//end: _onRORecv() -void network_send(int32 fd, netbuf buf){ - register SESSION *s = &g_Session[fd]; - +void network_send(int32 fd, netbuf buf) +{ + register SESSION *s = &g_Session[fd]; + #ifdef PARANOID_CHECKS - if(fd >= MAXCONN){ - ShowError("network_send: tried to attach buffer to connection idientifer #%u which is out of bounds.\n", fd); - _network_free_netbuf_async(buf); - return; - } + if (fd >= MAXCONN) { + ShowError("network_send: tried to attach buffer to connection idientifer #%u which is out of bounds.\n", fd); + _network_free_netbuf_async(buf); + return; + } #endif - if(s->type == NST_FREE) - return; - - // Check Max Outstanding buffers limit. - if( (s->write.max_outstanding > 0) && - (s->write.n_outstanding >= s->write.max_outstanding) ){ - - ShowWarning("network_send: fd #%u max Outstanding buffers exceeded. - disconnecting.\n", fd); - network_disconnect(fd); - // - _network_free_netbuf_async(buf); - return; - } - - - // Attach to the end: - buf->next = NULL; - if(s->write.buf_last != NULL){ - s->write.buf_last->next = buf; - s->write.buf_last = buf; - - }else{ - // currently no buffer attached. - s->write.buf = s->write.buf_last = buf; - - // register @ evdp for writable notification. - evdp_writable_add(fd, &s->evdp_data); // - } - - - // - s->write.n_outstanding++; - + if (s->type == NST_FREE) + return; + + // Check Max Outstanding buffers limit. + if ((s->write.max_outstanding > 0) && + (s->write.n_outstanding >= s->write.max_outstanding)) { + + ShowWarning("network_send: fd #%u max Outstanding buffers exceeded. - disconnecting.\n", fd); + network_disconnect(fd); + // + _network_free_netbuf_async(buf); + return; + } + + + // Attach to the end: + buf->next = NULL; + if (s->write.buf_last != NULL) { + s->write.buf_last->next = buf; + s->write.buf_last = buf; + + } else { + // currently no buffer attached. + s->write.buf = s->write.buf_last = buf; + + // register @ evdp for writable notification. + evdp_writable_add(fd, &s->evdp_data); // + } + + + // + s->write.n_outstanding++; + }//end: network_send() void network_parser_set_ro(int32 fd, - int16 *packetlentable, - void (*onPacketCompleteProc)(int32 fd, uint16 op, uint16 len, netbuf buf) - ){ - register SESSION *s = &g_Session[fd]; - register netbuf b, nb; // used for potential free attached buffers. - - if(s->type == NST_FREE) - return; - - s->onPacketComplete = onPacketCompleteProc; - - s->onRecv = _onRORecv; // .. - s->onSend = _onSend; // Using the normal generic netbuf based send function. - - s->netparser_data = packetlentable; - - // Initial State -> Need Packet OPCode. - s->read.state = NRS_WAITOP; - s->read.head_left = 2; - - - // Detach (if..) all buffers. - if(s->read.buf != NULL){ - _network_free_netbuf_async(s->read.buf); // - s->read.buf = NULL; - } - - if(s->write.buf != NULL){ - b = s->write.buf; - while(1){ - nb = b->next; - - _network_free_netbuf_async(b); - - b = nb; - } - - s->write.buf = NULL; - s->write.buf_last = NULL; - s->write.n_outstanding = 0; - } - - // not changing any limits on outstanding .. - // - + int16 *packetlentable, + void (*onPacketCompleteProc)(int32 fd, uint16 op, uint16 len, netbuf buf) + ) +{ + register SESSION *s = &g_Session[fd]; + register netbuf b, nb; // used for potential free attached buffers. + + if (s->type == NST_FREE) + return; + + s->onPacketComplete = onPacketCompleteProc; + + s->onRecv = _onRORecv; // .. + s->onSend = _onSend; // Using the normal generic netbuf based send function. + + s->netparser_data = packetlentable; + + // Initial State -> Need Packet OPCode. + s->read.state = NRS_WAITOP; + s->read.head_left = 2; + + + // Detach (if..) all buffers. + if (s->read.buf != NULL) { + _network_free_netbuf_async(s->read.buf); // + s->read.buf = NULL; + } + + if (s->write.buf != NULL) { + b = s->write.buf; + while (1) { + nb = b->next; + + _network_free_netbuf_async(b); + + b = nb; + } + + s->write.buf = NULL; + s->write.buf_last = NULL; + s->write.n_outstanding = 0; + } + + // not changing any limits on outstanding .. + // + }//end: network_parser_set_ro() diff --git a/src/common/network.h b/src/common/network.h index d7b463a2f..b883b41e6 100644 --- a/src/common/network.h +++ b/src/common/network.h @@ -3,7 +3,7 @@ #include #include "../common/cbasetypes.h" -#include "../common/netbuffer.h" +#include "../common/netbuffer.h" #include "../common/evdp.h" #ifndef MAXCONN @@ -11,79 +11,79 @@ #endif -typedef struct SESSION{ - EVDP_DATA evdp_data; // Must be always the frist member! (some evdp's may rely on this fact) - - // Connection Type - enum{ NST_FREE=0, NST_LISTENER = 1, NST_CLIENT=2, NST_OUTGOING=3} type; - - // Flags / Settings. - bool v6; // is v6? - bool disconnect_in_progress; // To prevent stack overflows / recursive calls. - - - union{ // union to save memory. - struct sockaddr_in v4; - struct sockaddr_in6 v6; - }addr; - - - // "lowlevel" Handlers - // (Implemented by the protocol specific parser) - // - bool (*onRecv)(int32 fd); // return false = disconnect - bool (*onSend)(int32 fd); // return false = disconnect - - // Event Handlers for LISTENER type sockets - // - // onConnect gets Called when a connection has been - // successfully accepted. - // Session entry is available in this Handler! - // A returncode of false will reejct the connection (disconnect) - // Note: When rejecting a connection in onConnect by returning false - // The onDisconnect handler wont get called! - // Note: the onConnect Handler is also responsible for setting - // the appropriate netparser (which implements onRecv/onSend..) [protocol specific] - // - // onDisconnect gets called when a connection gets disconnected - // (by peer as well as by core) - // - bool (*onConnect)(int32 fd); // return false = disconnect (wont accept) - void (*onDisconnect)(int32 fd); - - - // - // Parser specific data - // - void *netparser_data; // incase of RO Packet Parser, pointer to packet len table (uint16array) - void (*onPacketComplete)(int32 fd, uint16 op, uint16 len, netbuf buf); - - - // - // Buffers - // - struct{ - enum NETREADSTATE { NRS_WAITOP = 0, NRS_WAITLEN = 1, NRS_WAITDATA = 2} state; - - uint32 head_left; - uint16 head[2]; - - netbuf buf; - } read; - - struct{ - uint32 max_outstanding; - uint32 n_outstanding; - - uint32 dataPos; - - netbuf buf, buf_last; - } write; - - // Application Level data Pointer - // (required for backward compatibility with previous athena socket system.) - void *data; - +typedef struct SESSION { + EVDP_DATA evdp_data; // Must be always the frist member! (some evdp's may rely on this fact) + + // Connection Type + enum { NST_FREE=0, NST_LISTENER = 1, NST_CLIENT=2, NST_OUTGOING=3} type; + + // Flags / Settings. + bool v6; // is v6? + bool disconnect_in_progress; // To prevent stack overflows / recursive calls. + + + union { // union to save memory. + struct sockaddr_in v4; + struct sockaddr_in6 v6; + } addr; + + + // "lowlevel" Handlers + // (Implemented by the protocol specific parser) + // + bool (*onRecv)(int32 fd); // return false = disconnect + bool (*onSend)(int32 fd); // return false = disconnect + + // Event Handlers for LISTENER type sockets + // + // onConnect gets Called when a connection has been + // successfully accepted. + // Session entry is available in this Handler! + // A returncode of false will reejct the connection (disconnect) + // Note: When rejecting a connection in onConnect by returning false + // The onDisconnect handler wont get called! + // Note: the onConnect Handler is also responsible for setting + // the appropriate netparser (which implements onRecv/onSend..) [protocol specific] + // + // onDisconnect gets called when a connection gets disconnected + // (by peer as well as by core) + // + bool (*onConnect)(int32 fd); // return false = disconnect (wont accept) + void (*onDisconnect)(int32 fd); + + + // + // Parser specific data + // + void *netparser_data; // incase of RO Packet Parser, pointer to packet len table (uint16array) + void (*onPacketComplete)(int32 fd, uint16 op, uint16 len, netbuf buf); + + + // + // Buffers + // + struct { + enum NETREADSTATE { NRS_WAITOP = 0, NRS_WAITLEN = 1, NRS_WAITDATA = 2} state; + + uint32 head_left; + uint16 head[2]; + + netbuf buf; + } read; + + struct { + uint32 max_outstanding; + uint32 n_outstanding; + + uint32 dataPos; + + netbuf buf, buf_last; + } write; + + // Application Level data Pointer + // (required for backward compatibility with previous athena socket system.) + void *data; + } SESSION; @@ -101,12 +101,12 @@ void network_final(); void network_do(); -/** +/** * Adds a new listner. * - * @param v6 v6 listner? - * @param *addr the address to listen on. - * @param port port to listen on + * @param v6 v6 listner? + * @param *addr the address to listen on. + * @param port port to listen on * * @return -1 on error otherwise the identifier of the new listener. */ @@ -116,26 +116,26 @@ int32 network_addlistener(bool v6, const char *addr, uint16 port); /** * Tries to establish an outgoing connection. * - * @param v6 operate with IPv6 addresses? - * @param addr the address to connect to - * @param port the port to connect to - * @param from_addr the address to connect from (local source / optional if auto -> NULL) + * @param v6 operate with IPv6 addresses? + * @param addr the address to connect to + * @param port the port to connect to + * @param from_addr the address to connect from (local source / optional if auto -> NULL) * @param from_port the port to connect from (local source / optional if auto -> 0) - * @param onConnectionEstablishedHandler callback that gets called when the connection is established. - * @param onConnectionLooseHandler callback that gets called when the connection gets disconnected (or the connection couldnt be established) + * @param onConnectionEstablishedHandler callback that gets called when the connection is established. + * @param onConnectionLooseHandler callback that gets called when the connection gets disconnected (or the connection couldnt be established) * * @return -1 on error otherwise the identifier of the new connection */ int32 network_connect(bool v6, - const char *addr, - uint16 port, - const char *from_addr, - uint16 from_port, - bool (*onConnectionEstablishedHandler)(int32 fd), - void (*onConnectionLooseHandler)(int32 fd) -); + const char *addr, + uint16 port, + const char *from_addr, + uint16 from_port, + bool (*onConnectionEstablishedHandler)(int32 fd), + void (*onConnectionLooseHandler)(int32 fd) + ); + - /** * Disconnects the given connection @@ -143,43 +143,43 @@ int32 network_connect(bool v6, * @param fd connection identifier. * * @Note: - * - onDisconnect callback gets called! - * - cleares (returns) all assigned buffers + * - onDisconnect callback gets called! + * - cleares (returns) all assigned buffers * */ void network_disconnect(int32 fd); -/** +/** * Attach's a netbuffer at the end of sending queue to the given connection * - * @param fd connection identifier - * @param buf netbuffer to attach. + * @param fd connection identifier + * @param buf netbuffer to attach. */ void network_send(int32 fd, netbuf buf); /** * Sets the parser to RO Protocol like Packet Parser. - * - * @param fd connection identifier - * @param *packetlentable pointer to array of uint16 in size of UINT16_MAX, - * @param onComplteProc callback for packet completion. + * + * @param fd connection identifier + * @param *packetlentable pointer to array of uint16 in size of UINT16_MAX, + * @param onComplteProc callback for packet completion. * * @note: - * PacketLen Table Fromat: - * each element's offsets represents th ro opcode. - * value is length. - * a length of 0 means the packet is dynamic. - * a length of UINT16_MAX means the packet is unknown. + * PacketLen Table Fromat: + * each element's offsets represents th ro opcode. + * value is length. + * a length of 0 means the packet is dynamic. + * a length of UINT16_MAX means the packet is unknown. * - * Static Packets must contain their hader in len so (0x64 == 55 ..) + * Static Packets must contain their hader in len so (0x64 == 55 ..) * */ void network_parser_set_ro(int32 fd, - int16 *packetlentable, - void (*onPacketCompleteProc)(int32 fd, uint16 op, uint16 len, netbuf buf) - ); + int16 *packetlentable, + void (*onPacketCompleteProc)(int32 fd, uint16 op, uint16 len, netbuf buf) + ); #define ROPACKET_UNKNOWN UINT16_MAX #define ROPACKET_DYNLEN 0 diff --git a/src/common/nullpo.c b/src/common/nullpo.c index 4383109a7..ef2f3cd66 100644 --- a/src/common/nullpo.c +++ b/src/common/nullpo.c @@ -8,7 +8,7 @@ #include "../common/showmsg.h" // #include "logs.h" // 布石してみる -static void nullpo_info_core(const char *file, int line, const char *func, +static void nullpo_info_core(const char *file, int line, const char *func, const char *fmt, va_list ap); /*====================================== @@ -17,75 +17,73 @@ static void nullpo_info_core(const char *file, int line, const char *func, int nullpo_chk_f(const char *file, int line, const char *func, const void *target, const char *fmt, ...) { - va_list ap; - - if (target != NULL) - return 0; - - va_start(ap, fmt); - nullpo_info_core(file, line, func, fmt, ap); - va_end(ap); - return 1; + va_list ap; + + if (target != NULL) + return 0; + + va_start(ap, fmt); + nullpo_info_core(file, line, func, fmt, ap); + va_end(ap); + return 1; } int nullpo_chk(const char *file, int line, const char *func, const void *target) { - if (target != NULL) - return 0; - - nullpo_info_core(file, line, func, NULL, NULL); - return 1; + if (target != NULL) + return 0; + + nullpo_info_core(file, line, func, NULL, NULL); + return 1; } /*====================================== * nullpo情報出力(外部呼出し向けラッパ) *--------------------------------------*/ -void nullpo_info_f(const char *file, int line, const char *func, - const char *fmt, ...) +void nullpo_info_f(const char *file, int line, const char *func, + const char *fmt, ...) { - va_list ap; - - va_start(ap, fmt); - nullpo_info_core(file, line, func, fmt, ap); - va_end(ap); + va_list ap; + + va_start(ap, fmt); + nullpo_info_core(file, line, func, fmt, ap); + va_end(ap); } void nullpo_info(const char *file, int line, const char *func) { - nullpo_info_core(file, line, func, NULL, NULL); + nullpo_info_core(file, line, func, NULL, NULL); } /*====================================== * nullpo情報出力(Main) *--------------------------------------*/ -static void nullpo_info_core(const char *file, int line, const char *func, +static void nullpo_info_core(const char *file, int line, const char *func, const char *fmt, va_list ap) { - if (file == NULL) - file = "??"; - - func = - func == NULL ? "unknown": - func[0] == '\0' ? "unknown": - func; - - ShowMessage("--- nullpo info --------------------------------------------\n"); - ShowMessage("%s:%d: in func `%s'\n", file, line, func); - if (fmt != NULL) - { - if (fmt[0] != '\0') - { - vprintf(fmt, ap); - - // 最後に改行したか確認 - if (fmt[strlen(fmt)-1] != '\n') - ShowMessage("\n"); - } - } - ShowMessage("--- end nullpo info ----------------------------------------\n"); - - // ここらでnullpoログをファイルに書き出せたら - // まとめて提出できるなと思っていたり。 + if (file == NULL) + file = "??"; + + func = + func == NULL ? "unknown": + func[0] == '\0' ? "unknown": + func; + + ShowMessage("--- nullpo info --------------------------------------------\n"); + ShowMessage("%s:%d: in func `%s'\n", file, line, func); + if (fmt != NULL) { + if (fmt[0] != '\0') { + vprintf(fmt, ap); + + // 最後に改行したか確認 + if (fmt[strlen(fmt)-1] != '\n') + ShowMessage("\n"); + } + } + ShowMessage("--- end nullpo info ----------------------------------------\n"); + + // ここらでnullpoログをファイルに書き出せたら + // まとめて提出できるなと思っていたり。 } diff --git a/src/common/nullpo.h b/src/common/nullpo.h index 8ee86a782..67679432f 100644 --- a/src/common/nullpo.h +++ b/src/common/nullpo.h @@ -71,45 +71,45 @@ #if defined(NULLPO_CHECK) #define nullpo_ret(t) \ - if (nullpo_chk(NLP_MARK, (void *)(t))) {return(0);} + if (nullpo_chk(NLP_MARK, (void *)(t))) {return(0);} #define nullpo_retv(t) \ - if (nullpo_chk(NLP_MARK, (void *)(t))) {return;} + if (nullpo_chk(NLP_MARK, (void *)(t))) {return;} #define nullpo_retr(ret, t) \ - if (nullpo_chk(NLP_MARK, (void *)(t))) {return(ret);} + if (nullpo_chk(NLP_MARK, (void *)(t))) {return(ret);} #define nullpo_retb(t) \ - if (nullpo_chk(NLP_MARK, (void *)(t))) {break;} + if (nullpo_chk(NLP_MARK, (void *)(t))) {break;} // 可変引数マクロに関する条件コンパイル #if __STDC_VERSION__ >= 199901L /* C99に対応 */ #define nullpo_ret_f(t, fmt, ...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return(0);} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return(0);} #define nullpo_retv_f(t, fmt, ...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return;} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return;} #define nullpo_retr_f(ret, t, fmt, ...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return(ret);} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {return(ret);} #define nullpo_retb_f(t, fmt, ...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {break;} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), __VA_ARGS__)) {break;} #elif __GNUC__ >= 2 /* GCC用 */ #define nullpo_ret_f(t, fmt, args...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return(0);} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return(0);} #define nullpo_retv_f(t, fmt, args...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return;} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return;} #define nullpo_retr_f(ret, t, fmt, args...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return(ret);} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {return(ret);} #define nullpo_retb_f(t, fmt, args...) \ - if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {break;} + if (nullpo_chk_f(NLP_MARK, (void *)(t), (fmt), ## args)) {break;} #else @@ -189,7 +189,7 @@ int nullpo_chk(const char *file, int line, const char *func, const void *target) */ int nullpo_chk_f(const char *file, int line, const char *func, const void *target, const char *fmt, ...) - __attribute__((format(printf,5,6))); +__attribute__((format(printf,5,6))); /*====================================== @@ -217,9 +217,9 @@ void nullpo_info(const char *file, int line, const char *func); * 備考や関係変数の書き出しなどに *-------------------------------------- */ -void nullpo_info_f(const char *file, int line, const char *func, +void nullpo_info_f(const char *file, int line, const char *func, const char *fmt, ...) - __attribute__((format(printf,4,5))); +__attribute__((format(printf,4,5))); #endif /* _NULLPO_H_ */ diff --git a/src/common/raconf.c b/src/common/raconf.c index 2703560ff..e73154f50 100644 --- a/src/common/raconf.c +++ b/src/common/raconf.c @@ -1,7 +1,7 @@ -// +// // Athena style config parser -// (would be better to have "one" implementation instead of .. 4 :) -// +// (would be better to have "one" implementation instead of .. 4 :) +// // // Author: Florian Wilkemeyer // @@ -25,560 +25,571 @@ #define VARNAME_LEN 64 struct raconf { - DBMap *db; + DBMap *db; }; -struct conf_value{ - int64 intval; - bool bval; - double floatval; - size_t strval_len; // not includung \0 - char strval[16]; +struct conf_value { + int64 intval; + bool bval; + double floatval; + size_t strval_len; // not includung \0 + char strval[16]; }; -static struct conf_value *makeValue(const char *key, char *val, size_t val_len){ - struct conf_value *v; - char *p; - size_t sz; - - sz = sizeof(struct conf_value); - if(val_len >= sizeof(v->strval)) - sz += (val_len - sizeof(v->strval) + 1); - - v = (struct conf_value*)aCalloc(1, sizeof(struct conf_value)); - if(v == NULL){ - ShowFatalError("raconf: makeValue => Out of Memory while allocating new node.\n"); - return NULL; - } - - memcpy(v->strval, val, val_len); - v->strval[val_len+1] = '\0'; - v->strval_len = val_len; - - - // Parse boolean value: - if((val_len == 4) && (strncmpi("true", val, 4) == 0)) - v->bval = true; - else if((val_len == 3) && (strncmpi("yes", val, 3) == 0)) - v->bval = true; - else if((val_len == 3) && (strncmpi("oui", val, 3) == 0)) - v->bval = true; - else if((val_len == 2) && (strncmpi("si", val, 2) == 0)) - v->bval = true; - else if((val_len == 2) && (strncmpi("ja", val, 2) == 0)) - v->bval = true; - else if((val_len == 1) && (*val == '1')) - v->bval = true; - else if((val_len == 5) && (strncmpi("false", val, 5) == 0)) - v->bval = false; - else if((val_len == 2) && (strncmpi("no", val, 2) == 0)) - v->bval = false; - else if((val_len == 3) && (strncmpi("non", val, 3) == 0)) - v->bval = false; - else if((val_len == 2) && (strncmpi("no", val, 2) == 0)) - v->bval = false; - else if((val_len == 4) && (strncmpi("nein", val, 4) == 0)) - v->bval = false; - else if((val_len == 1) && (*val == '0')) - v->bval = false; - else - v->bval = false; // assume false. - - // Parse number - // Supported formats: - // prefix: 0x hex . - // postix: h for hex - // b for bin (dual) - if( (val_len >= 1 && (val[val_len] == 'h')) || (val_len >= 2 && (val[0] == '0' && val[1] == 'x')) ){//HEX! - if(val[val_len] == 'h'){ - val[val_len]= '\0'; - v->intval = strtoull(val, NULL, 16); - val[val_len] = 'h'; - }else - v->intval = strtoull(&val[2], NULL, 16); - }else if( val_len >= 1 && (val[val_len] == 'b') ){ //BIN - val[val_len] = '\0'; - v->intval = strtoull(val, NULL, 2); - val[val_len] = 'b'; - }else if( *val >='0' && *val <= '9'){ // begins with normal digit, so assume its dec. - // is it float? - bool is_float = false; - - for(p = val; *p != '\0'; p++){ - if(*p == '.'){ - v->floatval = strtod(val, NULL); - v->intval = (int64) v->floatval; - is_float = true; - break; - } - } - - if(is_float == false){ - v->intval = strtoull(val, NULL, 10); - v->floatval = (double) v->intval; - } - }else{ - // Everything else: lets use boolean for fallback - if(v->bval == true) - v->intval = 1; - else - v->intval = 0; - } - - return v; +static struct conf_value *makeValue(const char *key, char *val, size_t val_len) { + struct conf_value *v; + char *p; + size_t sz; + + sz = sizeof(struct conf_value); + if (val_len >= sizeof(v->strval)) + sz += (val_len - sizeof(v->strval) + 1); + + v = (struct conf_value *)aCalloc(1, sizeof(struct conf_value)); + if (v == NULL) { + ShowFatalError("raconf: makeValue => Out of Memory while allocating new node.\n"); + return NULL; + } + + memcpy(v->strval, val, val_len); + v->strval[val_len+1] = '\0'; + v->strval_len = val_len; + + + // Parse boolean value: + if ((val_len == 4) && (strncmpi("true", val, 4) == 0)) + v->bval = true; + else if ((val_len == 3) && (strncmpi("yes", val, 3) == 0)) + v->bval = true; + else if ((val_len == 3) && (strncmpi("oui", val, 3) == 0)) + v->bval = true; + else if ((val_len == 2) && (strncmpi("si", val, 2) == 0)) + v->bval = true; + else if ((val_len == 2) && (strncmpi("ja", val, 2) == 0)) + v->bval = true; + else if ((val_len == 1) && (*val == '1')) + v->bval = true; + else if ((val_len == 5) && (strncmpi("false", val, 5) == 0)) + v->bval = false; + else if ((val_len == 2) && (strncmpi("no", val, 2) == 0)) + v->bval = false; + else if ((val_len == 3) && (strncmpi("non", val, 3) == 0)) + v->bval = false; + else if ((val_len == 2) && (strncmpi("no", val, 2) == 0)) + v->bval = false; + else if ((val_len == 4) && (strncmpi("nein", val, 4) == 0)) + v->bval = false; + else if ((val_len == 1) && (*val == '0')) + v->bval = false; + else + v->bval = false; // assume false. + + // Parse number + // Supported formats: + // prefix: 0x hex . + // postix: h for hex + // b for bin (dual) + if ((val_len >= 1 && (val[val_len] == 'h')) || (val_len >= 2 && (val[0] == '0' && val[1] == 'x'))) {//HEX! + if (val[val_len] == 'h') { + val[val_len]= '\0'; + v->intval = strtoull(val, NULL, 16); + val[val_len] = 'h'; + } else + v->intval = strtoull(&val[2], NULL, 16); + } else if (val_len >= 1 && (val[val_len] == 'b')) { //BIN + val[val_len] = '\0'; + v->intval = strtoull(val, NULL, 2); + val[val_len] = 'b'; + } else if (*val >='0' && *val <= '9') { // begins with normal digit, so assume its dec. + // is it float? + bool is_float = false; + + for (p = val; *p != '\0'; p++) { + if (*p == '.') { + v->floatval = strtod(val, NULL); + v->intval = (int64) v->floatval; + is_float = true; + break; + } + } + + if (is_float == false) { + v->intval = strtoull(val, NULL, 10); + v->floatval = (double) v->intval; + } + } else { + // Everything else: lets use boolean for fallback + if (v->bval == true) + v->intval = 1; + else + v->intval = 0; + } + + return v; }//end: makeValue() -static bool configParse(raconf inst, const char *fileName){ - FILE *fp; - char line[4096]; - char currentSection[SECTION_LEN]; - char *p; - char c; - int linecnt; - size_t linelen; - size_t currentSection_len; - - fp = fopen(fileName, "r"); - if(fp == NULL){ - ShowError("configParse: cannot open '%s' for reading.\n", fileName); - return false; - } - - - // Start with empty section: - currentSection[0] = '\0'; - currentSection_len = 0; - - // - linecnt = 0; - while(1){ - linecnt++; - - if(fgets(line, sizeof(line), fp) != line) - break; - - linelen = strlen(line); - p = line; - - // Skip whitespaces from beginning (space and tab) - _line_begin_skip_whities: - c = *p; - if(c == ' ' || c == '\t'){ - p++; - linelen--; - goto _line_begin_skip_whities; - } - - // Remove linebreaks as (cr or lf) and whitespaces from line end! - _line_end_skip_whities_and_breaks: - c = p[linelen-1]; - if(c == '\r' || c == '\n' || c == ' ' || c == '\t'){ - p[--linelen] = '\0'; - goto _line_end_skip_whities_and_breaks; - } - - // Empty line? - // or line starts with comment (commented out)? - if(linelen == 0 || (p[0] == '/' && p[1] == '/') || p[0] == ';') - continue; - - // Variable names can contain: - // A-Za-z-_.0-9 - // - // Sections start with [ .. ] (INI Style) - // - c = *p; - - // check what we have.. :) - if(c == '['){ // got section! - // Got Section! - // Search for ] - char *start = (p+1); - - while(1){ - ++p; - c = *p; - - if(c == '\0'){ - ShowError("Syntax Error: unterminated Section name in %s:%u (expected ']')\n", fileName, linecnt); - fclose(fp); - return false; - }else if(c == ']'){ // closing backet (section name termination) - if( (p - start + 1) > (sizeof(currentSection) ) ){ - ShowError("Syntax Error: Section name in %s:%u is too large (max Supported length: %u chars)\n", fileName, linecnt, sizeof(currentSection)-1); - fclose(fp); - return false; - } - - // Set section! - *p = '\0'; // add termination here. - memcpy(currentSection, start, (p-start)+1 ); // we'll copy \0, too! (we replaced the ] backet with \0.) - currentSection_len = (p-start); - - break; - - }else if( (c >= '0' && c <= '9') || (c == '-') || (c == ' ') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ){ - // skip .. (allowed char / specifier) - continue; - }else{ - ShowError("Syntax Error: Invalid Character '%c' in %s:%u (offset %u) for Section name.\n", c, fileName, linecnt, (p-line)); - fclose(fp); - return false; - } - - }//endwhile: parse section name - - - }else if( (c >= '0' && c <= '9') || (c == '-') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ){ - // Got variable! - // Search for '=' or ':' wich termiantes the name - char *start = p; - char *valuestart = NULL; - size_t start_len; - - while(1){ - ++p; - c = *p; - - if(c == '\0'){ - ShowError("Syntax Error: unterminated Variable name in %s:%u\n", fileName, linecnt); - fclose(fp); - return false; - }else if( (c == '=') || (c == ':') ){ - // got name termination - - *p = '\0'; // Terminate it so (start) will hold the pointer to the name. - - break; - - }else if( (c >= '0' && c <= '9') || (c == '-') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ){ - // skip .. allowed char - continue; - }else{ - ShowError("Syntax Error: Invalid Character '%c' in %s:%u (offset %u) for Variable name.\n", c, fileName, linecnt, (p-line)); - fclose(fp); - return false; - } - - }//endwhile: parse var name - - start_len = (p-start); - if(start_len >= VARNAME_LEN){ - ShowError("%s:%u Variable length exceeds limit of %u Characters.\n", fileName, linecnt, VARNAME_LEN-1); - fclose(fp); - return false; - }else if(start_len == 0){ - ShowError("%s:%u Empty Variable name is not allowed.\n", fileName, linecnt); - fclose(fp); - return false; - } - - - valuestart = (p+1); - - - // Skip whitespace from begin of value (tab and space) - _skip_value_begin_whities: - c = *valuestart; - if(c == ' ' || c == '\t'){ - valuestart++; - goto _skip_value_begin_whities; - } - - // Scan for value termination, - // wich can be \0 or comment start (// or ; (INI) ) - // - p = valuestart; - while(1){ - c = *p; - if(c == '\0'){ - // Terminated by line end. - break; - }else if(c == '/' && p[1] == '/'){ - // terminated by c++ style comment. - *p = '\0'; - break; - }else if(c == ';'){ - // terminated by ini style comment. - *p = '\0'; - break; - } - - p++; - }//endwhile: search var value end. - - - // Strip whitespaces from end of value. - if(valuestart != p){ // not empty! - p--; - _strip_value_end_whities: - c = *p; - if(c == ' ' || c == '\t'){ - *p = '\0'; - p--; - goto _strip_value_end_whities; - } - p++; - } - - - // Buildin Hook: - if( stricmp(start, "import") == 0){ - if( configParse(inst, valuestart) != true){ - ShowError("%s:%u - Import of '%s' failed!\n", fileName, linecnt, valuestart); - } - }else{ - // put it to db. - struct conf_value *v, *o; - char key[ (SECTION_LEN+VARNAME_LEN+1+1) ]; //+1 for delimiter, +1 for termination. - size_t section_len; - - if(*currentSection == '\0'){ // empty / none - strncpy(key, "",9); - section_len = 9; - }else{ - strncpy(key, currentSection, currentSection_len); - section_len = currentSection_len; - } - - key[section_len] = '.'; // Delim - - strncpy(&key[section_len+1], start, start_len); - - key[section_len + start_len + 1] = '\0'; - - - v = makeValue(key, valuestart, (p-valuestart) ); - - // Try to get the old one before - o = strdb_get(inst->db, key); - if(o != NULL){ - strdb_remove(inst->db, key); - aFree(o); // - } - - strdb_put( inst->db, key, v); - } - - - }else{ - ShowError("Syntax Error: unexpected Character '%c' in %s:%u (offset %u)\n", c, fileName, linecnt, (p-line) ); - fclose(fp); - return false; - } - - - - } - - - - fclose(fp); - return true; +static bool configParse(raconf inst, const char *fileName) +{ + FILE *fp; + char line[4096]; + char currentSection[SECTION_LEN]; + char *p; + char c; + int linecnt; + size_t linelen; + size_t currentSection_len; + + fp = fopen(fileName, "r"); + if (fp == NULL) { + ShowError("configParse: cannot open '%s' for reading.\n", fileName); + return false; + } + + + // Start with empty section: + currentSection[0] = '\0'; + currentSection_len = 0; + + // + linecnt = 0; + while (1) { + linecnt++; + + if (fgets(line, sizeof(line), fp) != line) + break; + + linelen = strlen(line); + p = line; + + // Skip whitespaces from beginning (space and tab) + _line_begin_skip_whities: + c = *p; + if (c == ' ' || c == '\t') { + p++; + linelen--; + goto _line_begin_skip_whities; + } + + // Remove linebreaks as (cr or lf) and whitespaces from line end! + _line_end_skip_whities_and_breaks: + c = p[linelen-1]; + if (c == '\r' || c == '\n' || c == ' ' || c == '\t') { + p[--linelen] = '\0'; + goto _line_end_skip_whities_and_breaks; + } + + // Empty line? + // or line starts with comment (commented out)? + if (linelen == 0 || (p[0] == '/' && p[1] == '/') || p[0] == ';') + continue; + + // Variable names can contain: + // A-Za-z-_.0-9 + // + // Sections start with [ .. ] (INI Style) + // + c = *p; + + // check what we have.. :) + if (c == '[') { // got section! + // Got Section! + // Search for ] + char *start = (p+1); + + while (1) { + ++p; + c = *p; + + if (c == '\0') { + ShowError("Syntax Error: unterminated Section name in %s:%u (expected ']')\n", fileName, linecnt); + fclose(fp); + return false; + } else if (c == ']') { // closing backet (section name termination) + if ((p - start + 1) > (sizeof(currentSection))) { + ShowError("Syntax Error: Section name in %s:%u is too large (max Supported length: %u chars)\n", fileName, linecnt, sizeof(currentSection)-1); + fclose(fp); + return false; + } + + // Set section! + *p = '\0'; // add termination here. + memcpy(currentSection, start, (p-start)+1); // we'll copy \0, too! (we replaced the ] backet with \0.) + currentSection_len = (p-start); + + break; + + } else if ((c >= '0' && c <= '9') || (c == '-') || (c == ' ') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + // skip .. (allowed char / specifier) + continue; + } else { + ShowError("Syntax Error: Invalid Character '%c' in %s:%u (offset %u) for Section name.\n", c, fileName, linecnt, (p-line)); + fclose(fp); + return false; + } + + }//endwhile: parse section name + + + } else if ((c >= '0' && c <= '9') || (c == '-') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + // Got variable! + // Search for '=' or ':' wich termiantes the name + char *start = p; + char *valuestart = NULL; + size_t start_len; + + while (1) { + ++p; + c = *p; + + if (c == '\0') { + ShowError("Syntax Error: unterminated Variable name in %s:%u\n", fileName, linecnt); + fclose(fp); + return false; + } else if ((c == '=') || (c == ':')) { + // got name termination + + *p = '\0'; // Terminate it so (start) will hold the pointer to the name. + + break; + + } else if ((c >= '0' && c <= '9') || (c == '-') || (c == '_') || (c == '.') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + // skip .. allowed char + continue; + } else { + ShowError("Syntax Error: Invalid Character '%c' in %s:%u (offset %u) for Variable name.\n", c, fileName, linecnt, (p-line)); + fclose(fp); + return false; + } + + }//endwhile: parse var name + + start_len = (p-start); + if (start_len >= VARNAME_LEN) { + ShowError("%s:%u Variable length exceeds limit of %u Characters.\n", fileName, linecnt, VARNAME_LEN-1); + fclose(fp); + return false; + } else if (start_len == 0) { + ShowError("%s:%u Empty Variable name is not allowed.\n", fileName, linecnt); + fclose(fp); + return false; + } + + + valuestart = (p+1); + + + // Skip whitespace from begin of value (tab and space) + _skip_value_begin_whities: + c = *valuestart; + if (c == ' ' || c == '\t') { + valuestart++; + goto _skip_value_begin_whities; + } + + // Scan for value termination, + // wich can be \0 or comment start (// or ; (INI) ) + // + p = valuestart; + while (1) { + c = *p; + if (c == '\0') { + // Terminated by line end. + break; + } else if (c == '/' && p[1] == '/') { + // terminated by c++ style comment. + *p = '\0'; + break; + } else if (c == ';') { + // terminated by ini style comment. + *p = '\0'; + break; + } + + p++; + }//endwhile: search var value end. + + + // Strip whitespaces from end of value. + if (valuestart != p) { // not empty! + p--; + _strip_value_end_whities: + c = *p; + if (c == ' ' || c == '\t') { + *p = '\0'; + p--; + goto _strip_value_end_whities; + } + p++; + } + + + // Buildin Hook: + if (stricmp(start, "import") == 0) { + if (configParse(inst, valuestart) != true) { + ShowError("%s:%u - Import of '%s' failed!\n", fileName, linecnt, valuestart); + } + } else { + // put it to db. + struct conf_value *v, *o; + char key[(SECTION_LEN+VARNAME_LEN+1+1) ]; //+1 for delimiter, +1 for termination. + size_t section_len; + + if (*currentSection == '\0') { // empty / none + strncpy(key, "",9); + section_len = 9; + } else { + strncpy(key, currentSection, currentSection_len); + section_len = currentSection_len; + } + + key[section_len] = '.'; // Delim + + strncpy(&key[section_len+1], start, start_len); + + key[section_len + start_len + 1] = '\0'; + + + v = makeValue(key, valuestart, (p-valuestart)); + + // Try to get the old one before + o = strdb_get(inst->db, key); + if (o != NULL) { + strdb_remove(inst->db, key); + aFree(o); // + } + + strdb_put(inst->db, key, v); + } + + + } else { + ShowError("Syntax Error: unexpected Character '%c' in %s:%u (offset %u)\n", c, fileName, linecnt, (p-line)); + fclose(fp); + return false; + } + + + + } + + + + fclose(fp); + return true; }//end: configParse() #define MAKEKEY(dest, section, key) { size_t section_len, key_len; \ - if(section == NULL || *section == '\0'){ \ - strncpy(dest, "", 9); \ - section_len = 9; \ - }else{ \ - section_len = strlen(section); \ - strncpy(dest, section, section_len); \ - } \ - \ - dest[section_len] = '.'; \ - \ - key_len = strlen(key); \ - strncpy(&dest[section_len+1], key, key_len); \ - dest[section_len + key_len + 1] = '\0'; \ - } - - -raconf raconf_parse(const char *file_name){ - struct raconf *rc; - - rc = aCalloc(1, sizeof(struct raconf) ); - if(rc == NULL){ - ShowFatalError("raconf_parse: failed to allocate memory for new handle\n"); - return NULL; - } - - rc->db = strdb_alloc(DB_OPT_BASE | DB_OPT_DUP_KEY, 98); - // - - if(configParse(rc, file_name) != true){ - ShowError("Failed to Parse Configuration file '%s'\n", file_name); - } - - return rc; + if(section == NULL || *section == '\0'){ \ + strncpy(dest, "", 9); \ + section_len = 9; \ + }else{ \ + section_len = strlen(section); \ + strncpy(dest, section, section_len); \ + } \ + \ + dest[section_len] = '.'; \ + \ + key_len = strlen(key); \ + strncpy(&dest[section_len+1], key, key_len); \ + dest[section_len + key_len + 1] = '\0'; \ + } + + +raconf raconf_parse(const char *file_name) +{ + struct raconf *rc; + + rc = aCalloc(1, sizeof(struct raconf)); + if (rc == NULL) { + ShowFatalError("raconf_parse: failed to allocate memory for new handle\n"); + return NULL; + } + + rc->db = strdb_alloc(DB_OPT_BASE | DB_OPT_DUP_KEY, 98); + // + + if (configParse(rc, file_name) != true) { + ShowError("Failed to Parse Configuration file '%s'\n", file_name); + } + + return rc; }//end: raconf_parse() -void raconf_destroy(raconf rc){ - DBIterator *iter; - struct conf_value *v; - - // Clear all entrys in db. - iter = db_iterator(rc->db); - for( v = (struct conf_value*)dbi_first(iter); dbi_exists(iter); v = (struct conf_value*)dbi_next(iter) ){ - aFree(v); - } - dbi_destroy(iter); - - db_destroy(rc->db); - - aFree(rc); - +void raconf_destroy(raconf rc) +{ + DBIterator *iter; + struct conf_value *v; + + // Clear all entrys in db. + iter = db_iterator(rc->db); + for (v = (struct conf_value *)dbi_first(iter); dbi_exists(iter); v = (struct conf_value *)dbi_next(iter)) { + aFree(v); + } + dbi_destroy(iter); + + db_destroy(rc->db); + + aFree(rc); + }//end: raconf_destroy() -bool raconf_getbool(raconf rc, const char *section, const char *key, bool _default){ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); - - v = strdb_get(rc->db, keystr); - if(v == NULL) - return _default; - else - return v->bval; +bool raconf_getbool(raconf rc, const char *section, const char *key, bool _default) +{ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + + v = strdb_get(rc->db, keystr); + if (v == NULL) + return _default; + else + return v->bval; }//end: raconf_getbool() -float raconf_getfloat(raconf rc,const char *section, const char *key, float _default){ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); +float raconf_getfloat(raconf rc,const char *section, const char *key, float _default) +{ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL) - return _default; - else - return (float)v->floatval; + v = strdb_get(rc->db, keystr); + if (v == NULL) + return _default; + else + return (float)v->floatval; }//end: raconf_getfloat() -int64 raconf_getint(raconf rc, const char *section, const char *key, int64 _default){ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); - - v = strdb_get(rc->db, keystr); - if(v == NULL) - return _default; - else - return v->intval; +int64 raconf_getint(raconf rc, const char *section, const char *key, int64 _default) +{ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + + v = strdb_get(rc->db, keystr); + if (v == NULL) + return _default; + else + return v->intval; }//end: raconf_getint() -const char* raconf_getstr(raconf rc, const char *section, const char *key, const char *_default){ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; +const char *raconf_getstr(raconf rc, const char *section, const char *key, const char *_default) +{ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; - MAKEKEY(keystr, section, key); + MAKEKEY(keystr, section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL) - return _default; - else - return v->strval; + v = strdb_get(rc->db, keystr); + if (v == NULL) + return _default; + else + return v->strval; }//end: raconf_getstr() -bool raconf_getboolEx(raconf rc, const char *section, const char *fallback_section, const char *key, bool _default){ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL){ - - MAKEKEY(keystr, fallback_section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL){ - return _default; - }else{ - return v->bval; - } - - }else{ - return v->bval; - } +bool raconf_getboolEx(raconf rc, const char *section, const char *fallback_section, const char *key, bool _default) +{ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + v = strdb_get(rc->db, keystr); + if (v == NULL) { + + MAKEKEY(keystr, fallback_section, key); + v = strdb_get(rc->db, keystr); + if (v == NULL) { + return _default; + } else { + return v->bval; + } + + } else { + return v->bval; + } }//end: raconf_getboolEx() -float raconf_getfloatEx(raconf rc,const char *section, const char *fallback_section, const char *key, float _default){ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL){ - - MAKEKEY(keystr, fallback_section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL){ - return _default; - }else{ - return (float)v->floatval; - } - - }else{ - return (float)v->floatval; - } - +float raconf_getfloatEx(raconf rc,const char *section, const char *fallback_section, const char *key, float _default) +{ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + v = strdb_get(rc->db, keystr); + if (v == NULL) { + + MAKEKEY(keystr, fallback_section, key); + v = strdb_get(rc->db, keystr); + if (v == NULL) { + return _default; + } else { + return (float)v->floatval; + } + + } else { + return (float)v->floatval; + } + }//end: raconf_getfloatEx() -int64 raconf_getintEx(raconf rc, const char *section, const char *fallback_section, const char *key, int64 _default){ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL){ - - MAKEKEY(keystr, fallback_section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL){ - return _default; - }else{ - return v->intval; - } - - }else{ - return v->intval; - } +int64 raconf_getintEx(raconf rc, const char *section, const char *fallback_section, const char *key, int64 _default) +{ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + v = strdb_get(rc->db, keystr); + if (v == NULL) { + + MAKEKEY(keystr, fallback_section, key); + v = strdb_get(rc->db, keystr); + if (v == NULL) { + return _default; + } else { + return v->intval; + } + + } else { + return v->intval; + } }//end: raconf_getintEx() -const char* raconf_getstrEx(raconf rc, const char *section, const char *fallback_section, const char *key, const char *_default){ - char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; - struct conf_value *v; - - MAKEKEY(keystr, section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL){ - - MAKEKEY(keystr, fallback_section, key); - v = strdb_get(rc->db, keystr); - if(v == NULL){ - return _default; - }else{ - return v->strval; - } - - }else{ - return v->strval; - } +const char *raconf_getstrEx(raconf rc, const char *section, const char *fallback_section, const char *key, const char *_default) +{ + char keystr[SECTION_LEN + VARNAME_LEN + 1 + 1]; + struct conf_value *v; + + MAKEKEY(keystr, section, key); + v = strdb_get(rc->db, keystr); + if (v == NULL) { + + MAKEKEY(keystr, fallback_section, key); + v = strdb_get(rc->db, keystr); + if (v == NULL) { + return _default; + } else { + return v->strval; + } + + } else { + return v->strval; + } }//end: raconf_getstrEx() diff --git a/src/common/raconf.h b/src/common/raconf.h index 68a2b51b2..242c585bb 100644 --- a/src/common/raconf.h +++ b/src/common/raconf.h @@ -7,52 +7,52 @@ #include "../common/cbasetypes.h" // rAthena generic configuration file parser -// -// Config file Syntax is athena style -// extended with ini style support (including sections) // -// Comments are started with // or ; (ini style) +// Config file Syntax is athena style +// extended with ini style support (including sections) +// +// Comments are started with // or ; (ini style) // typedef struct raconf *raconf; -/** +/** * Parses a rAthna Configuration file - * + * * @param file_name path to the file to parse * * @returns not NULL incase of success */ -raconf raconf_parse(const char *file_name); +raconf raconf_parse(const char *file_name); -/** +/** * Frees a Handle received from raconf_parse * * @param rc - the handle to free */ -void raconf_destroy(raconf rc); +void raconf_destroy(raconf rc); -/** - * Gets the value for Section / Key pair, if key not exists returns _default! +/** + * Gets the value for Section / Key pair, if key not exists returns _default! * */ -bool raconf_getbool(raconf rc, const char *section, const char *key, bool _default); -float raconf_getfloat(raconf rc,const char *section, const char *key, float _default); -int64 raconf_getint(raconf rc, const char *section, const char *key, int64 _default); -const char* raconf_getstr(raconf rc, const char *section, const char *key, const char *_default); +bool raconf_getbool(raconf rc, const char *section, const char *key, bool _default); +float raconf_getfloat(raconf rc,const char *section, const char *key, float _default); +int64 raconf_getint(raconf rc, const char *section, const char *key, int64 _default); +const char *raconf_getstr(raconf rc, const char *section, const char *key, const char *_default); /** - * Gets the value for Section / Key pair, but has fallback section option if not found in section, + * Gets the value for Section / Key pair, but has fallback section option if not found in section, * if not found in both - default gets returned. * */ bool raconf_getboolEx(raconf rc, const char *section, const char *fallback_section, const char *key, bool _default); float raconf_getfloatEx(raconf rc,const char *section, const char *fallback_section, const char *key, float _default); int64 raconf_getintEx(raconf rc, const char *section, const char *fallback_section, const char *key, int64 _default); -const char* raconf_getstrEx(raconf rc, const char *section, const char *fallback_section, const char *key, const char *_default); +const char *raconf_getstrEx(raconf rc, const char *section, const char *fallback_section, const char *key, const char *_default); diff --git a/src/common/random.c b/src/common/random.c index 5c048c7eb..ab9b0052f 100644 --- a/src/common/random.c +++ b/src/common/random.c @@ -5,10 +5,10 @@ #include "../common/timer.h" // gettick #include "random.h" #if defined(WIN32) - #include "../common/winapi.h" +#include "../common/winapi.h" #elif defined(HAVE_GETPID) || defined(HAVE_GETTID) - #include - #include +#include +#include #endif #include // time #include // init_genrand, genrand_int32, genrand_res53 @@ -17,34 +17,34 @@ /// Initializes the random number generator with an appropriate seed. void rnd_init(void) { - uint32 seed = gettick(); - seed += (uint32)time(NULL); + uint32 seed = gettick(); + seed += (uint32)time(NULL); #if defined(WIN32) - seed += GetCurrentProcessId(); - seed += GetCurrentThreadId(); + seed += GetCurrentProcessId(); + seed += GetCurrentThreadId(); #else #if defined(HAVE_GETPID) - seed += (uint32)getpid(); + seed += (uint32)getpid(); #endif // HAVE_GETPID #if defined(HAVE_GETTID) - seed += (uint32)gettid(); + seed += (uint32)gettid(); #endif // HAVE_GETTID #endif - init_genrand(seed); + init_genrand(seed); } /// Initializes the random number generator. void rnd_seed(uint32 seed) { - init_genrand(seed); + init_genrand(seed); } /// Generates a random number in the interval [0, SINT32_MAX] int32 rnd(void) { - return (int32)genrand_int31(); + return (int32)genrand_int31(); } @@ -52,7 +52,7 @@ int32 rnd(void) /// NOTE: interval is open ended, so dice_faces is excluded (unless it's 0) uint32 rnd_roll(uint32 dice_faces) { - return (uint32)(rnd_uniform()*dice_faces); + return (uint32)(rnd_uniform()*dice_faces); } @@ -60,9 +60,9 @@ uint32 rnd_roll(uint32 dice_faces) /// Returns min if range is invalid. int32 rnd_value(int32 min, int32 max) { - if( min >= max ) - return min; - return min + (int32)(rnd_uniform()*(max-min+1)); + if (min >= max) + return min; + return min + (int32)(rnd_uniform()*(max-min+1)); } @@ -70,7 +70,7 @@ int32 rnd_value(int32 min, int32 max) /// NOTE: interval is open ended, so 1.0 is excluded double rnd_uniform(void) { - return ((uint32)genrand_int32())*(1.0/4294967296.0);// divided by 2^32 + return ((uint32)genrand_int32())*(1.0/4294967296.0);// divided by 2^32 } @@ -79,5 +79,5 @@ double rnd_uniform(void) /// NOTE: 53 bits is the maximum precision of a double double rnd_uniform53(void) { - return genrand_res53(); + return genrand_res53(); } diff --git a/src/common/showmsg.c b/src/common/showmsg.c index 609ae3c50..cfa1587e5 100644 --- a/src/common/showmsg.c +++ b/src/common/showmsg.c @@ -15,33 +15,33 @@ #include "libconfig.h" #ifdef WIN32 - #include "../common/winapi.h" - - #ifdef DEBUGLOGMAP - #define DEBUGLOGPATH "log\\map-server.log" - #else - #ifdef DEBUGLOGCHAR - #define DEBUGLOGPATH "log\\char-server.log" - #else - #ifdef DEBUGLOGLOGIN - #define DEBUGLOGPATH "log\\login-server.log" - #endif - #endif - #endif +#include "../common/winapi.h" + +#ifdef DEBUGLOGMAP +#define DEBUGLOGPATH "log\\map-server.log" +#else +#ifdef DEBUGLOGCHAR +#define DEBUGLOGPATH "log\\char-server.log" +#else +#ifdef DEBUGLOGLOGIN +#define DEBUGLOGPATH "log\\login-server.log" +#endif +#endif +#endif #else - #include - - #ifdef DEBUGLOGMAP - #define DEBUGLOGPATH "log/map-server.log" - #else - #ifdef DEBUGLOGCHAR - #define DEBUGLOGPATH "log/char-server.log" - #else - #ifdef DEBUGLOGLOGIN - #define DEBUGLOGPATH "log/login-server.log" - #endif - #endif - #endif +#include + +#ifdef DEBUGLOGMAP +#define DEBUGLOGPATH "log/map-server.log" +#else +#ifdef DEBUGLOGCHAR +#define DEBUGLOGPATH "log/char-server.log" +#else +#ifdef DEBUGLOGLOGIN +#define DEBUGLOGPATH "log/login-server.log" +#endif +#endif +#endif #endif /////////////////////////////////////////////////////////////////////////////// @@ -60,41 +60,41 @@ int console_msg_log = 0;//[Ind] msg error logging #define SBUF_SIZE 2054 // never put less that what's required for the debug message -#define NEWBUF(buf) \ - struct { \ - char s_[SBUF_SIZE]; \ - StringBuf *d_; \ - char *v_; \ - int l_; \ - } buf ={"",NULL,NULL,0}; \ -//define NEWBUF - -#define BUFVPRINTF(buf,fmt,args) \ - buf.l_ = vsnprintf(buf.s_, SBUF_SIZE, fmt, args); \ - if( buf.l_ >= 0 && buf.l_ < SBUF_SIZE ) \ - {/* static buffer */ \ - buf.v_ = buf.s_; \ - } \ - else \ - {/* dynamic buffer */ \ - buf.d_ = StringBuf_Malloc(); \ - buf.l_ = StringBuf_Vprintf(buf.d_, fmt, args); \ - buf.v_ = StringBuf_Value(buf.d_); \ - ShowDebug("showmsg: dynamic buffer used, increase the static buffer size to %d or more.\n", buf.l_+1);\ - } \ -//define BUFVPRINTF +#define NEWBUF(buf) \ + struct { \ + char s_[SBUF_SIZE]; \ + StringBuf *d_; \ + char *v_; \ + int l_; \ + } buf ={"",NULL,NULL,0}; \ + //define NEWBUF + +#define BUFVPRINTF(buf,fmt,args) \ + buf.l_ = vsnprintf(buf.s_, SBUF_SIZE, fmt, args); \ + if( buf.l_ >= 0 && buf.l_ < SBUF_SIZE ) \ + {/* static buffer */ \ + buf.v_ = buf.s_; \ + } \ + else \ + {/* dynamic buffer */ \ + buf.d_ = StringBuf_Malloc(); \ + buf.l_ = StringBuf_Vprintf(buf.d_, fmt, args); \ + buf.v_ = StringBuf_Value(buf.d_); \ + ShowDebug("showmsg: dynamic buffer used, increase the static buffer size to %d or more.\n", buf.l_+1);\ + } \ + //define BUFVPRINTF #define BUFVAL(buf) buf.v_ #define BUFLEN(buf) buf.l_ -#define FREEBUF(buf) \ - if( buf.d_ ) \ - { \ - StringBuf_Free(buf.d_); \ - buf.d_ = NULL; \ - } \ - buf.v_ = NULL; \ -//define FREEBUF +#define FREEBUF(buf) \ + if( buf.d_ ) \ + { \ + StringBuf_Free(buf.d_); \ + buf.d_ = NULL; \ + } \ + buf.v_ = NULL; \ + //define FREEBUF /////////////////////////////////////////////////////////////////////////////// #ifdef _WIN32 @@ -104,38 +104,38 @@ int console_msg_log = 0;//[Ind] msg error logging // ansi compatible printf with control sequence parser for windows // fast hack, handle with care, not everything implemented // -// \033[#;...;#m - Set Graphics Rendition (SGR) +// \033[#;...;#m - Set Graphics Rendition (SGR) // -// printf("\x1b[1;31;40m"); // Bright red on black -// printf("\x1b[3;33;45m"); // Blinking yellow on magenta (blink not implemented) -// printf("\x1b[1;30;47m"); // Bright black (grey) on dim white +// printf("\x1b[1;31;40m"); // Bright red on black +// printf("\x1b[3;33;45m"); // Blinking yellow on magenta (blink not implemented) +// printf("\x1b[1;30;47m"); // Bright black (grey) on dim white // // Style Foreground Background -// 1st Digit 2nd Digit 3rd Digit RGB -// 0 - Reset 30 - Black 40 - Black 000 -// 1 - FG Bright 31 - Red 41 - Red 100 -// 2 - Unknown 32 - Green 42 - Green 010 -// 3 - Blink 33 - Yellow 43 - Yellow 110 -// 4 - Underline 34 - Blue 44 - Blue 001 -// 5 - BG Bright 35 - Magenta 45 - Magenta 101 -// 6 - Unknown 36 - Cyan 46 - Cyan 011 -// 7 - Reverse 37 - White 47 - White 111 +// 1st Digit 2nd Digit 3rd Digit RGB +// 0 - Reset 30 - Black 40 - Black 000 +// 1 - FG Bright 31 - Red 41 - Red 100 +// 2 - Unknown 32 - Green 42 - Green 010 +// 3 - Blink 33 - Yellow 43 - Yellow 110 +// 4 - Underline 34 - Blue 44 - Blue 001 +// 5 - BG Bright 35 - Magenta 45 - Magenta 101 +// 6 - Unknown 36 - Cyan 46 - Cyan 011 +// 7 - Reverse 37 - White 47 - White 111 // 8 - Concealed (invisible) // // \033[#A - Cursor Up (CUU) -// Moves the cursor up by the specified number of lines without changing columns. +// Moves the cursor up by the specified number of lines without changing columns. // If the cursor is already on the top line, this sequence is ignored. \e[A is equivalent to \e[1A. // // \033[#B - Cursor Down (CUD) -// Moves the cursor down by the specified number of lines without changing columns. +// Moves the cursor down by the specified number of lines without changing columns. // If the cursor is already on the bottom line, this sequence is ignored. \e[B is equivalent to \e[1B. // // \033[#C - Cursor Forward (CUF) -// Moves the cursor forward by the specified number of columns without changing lines. +// Moves the cursor forward by the specified number of columns without changing lines. // If the cursor is already in the rightmost column, this sequence is ignored. \e[C is equivalent to \e[1C. // // \033[#D - Cursor Backward (CUB) -// Moves the cursor back by the specified number of columns without changing lines. +// Moves the cursor back by the specified number of columns without changing lines. // If the cursor is already in the leftmost column, this sequence is ignored. \e[D is equivalent to \e[1D. // // \033[#E - Cursor Next Line (CNL) @@ -148,15 +148,15 @@ int console_msg_log = 0;//[Ind] msg error logging // Moves the cursor to indicated column in current row. \e[G is equivalent to \e[1G. // // \033[#;#H - Cursor Position (CUP) -// Moves the cursor to the specified position. The first # specifies the line number, -// the second # specifies the column. If you do not specify a position, the cursor moves to the home position: +// Moves the cursor to the specified position. The first # specifies the line number, +// the second # specifies the column. If you do not specify a position, the cursor moves to the home position: // the upper-left corner of the screen (line 1, column 1). // // \033[#;#f - Horizontal & Vertical Position // (same as \033[#;#H) // // \033[s - Save Cursor Position (SCP) -// The current cursor position is saved. +// The current cursor position is saved. // // \033[u - Restore cursor position (RCP) // Restores the cursor position saved with the (SCP) sequence \033[s. @@ -194,331 +194,295 @@ Escape sequences for Select Character Set #define is_console(handle) (FILE_TYPE_CHAR==GetFileType(handle)) /////////////////////////////////////////////////////////////////////////////// -int VFPRINTF(HANDLE handle, const char *fmt, va_list argptr) +int VFPRINTF(HANDLE handle, const char *fmt, va_list argptr) { - ///////////////////////////////////////////////////////////////// - /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] - static COORD saveposition = {0,0}; - */ - - ///////////////////////////////////////////////////////////////// - DWORD written; - char *p, *q; - NEWBUF(tempbuf); // temporary buffer - - if(!fmt || !*fmt) - return 0; - - // Print everything to the buffer - BUFVPRINTF(tempbuf,fmt,argptr); - - if( !is_console(handle) && stdout_with_ansisequence ) - { - WriteFile(handle, BUFVAL(tempbuf), BUFLEN(tempbuf), &written, 0); - return 0; - } - - // start with processing - p = BUFVAL(tempbuf); - while ((q = strchr(p, 0x1b)) != NULL) - { // find the escape character - if( 0==WriteConsole(handle, p, (DWORD)(q-p), &written, 0) ) // write up to the escape - WriteFile(handle, p, (DWORD)(q-p), &written, 0); - - if( q[1]!='[' ) - { // write the escape char (whatever purpose it has) - if(0==WriteConsole(handle, q, 1, &written, 0) ) - WriteFile(handle,q, 1, &written, 0); - p=q+1; //and start searching again - } - else - { // from here, we will skip the '\033[' - // we break at the first unprocessible position - // assuming regular text is starting there - uint8 numbers[16], numpoint=0; - CONSOLE_SCREEN_BUFFER_INFO info; - - // initialize - GetConsoleScreenBufferInfo(handle, &info); - memset(numbers,0,sizeof(numbers)); - - // skip escape and bracket - q=q+2; - for(;;) - { - if( ISDIGIT(*q) ) - { // add number to number array, only accept 2digits, shift out the rest - // so // \033[123456789m will become \033[89m - numbers[numpoint] = (numbers[numpoint]<<4) | (*q-'0'); - ++q; - // and next character - continue; - } - else if( *q == ';' ) - { // delimiter - if(numpoint7) num=7; // set white for 37, 38 and 39 - info.wAttributes &= ~(FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE); - if( (num & 0x01)>0 ) // lowest bit set = red - info.wAttributes |= FOREGROUND_RED; - if( (num & 0x02)>0 ) // second bit set = green - info.wAttributes |= FOREGROUND_GREEN; - if( (num & 0x04)>0 ) // third bit set = blue - info.wAttributes |= FOREGROUND_BLUE; - } - else if( 0x40 == (0xF0 & numbers[i]) ) - { // background - uint8 num = numbers[i]&0x0F; - if(num==9) info.wAttributes |= BACKGROUND_INTENSITY; - if(num>7) num=7; // set white for 47, 48 and 49 - info.wAttributes &= ~(BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE); - if( (num & 0x01)>0 ) // lowest bit set = red - info.wAttributes |= BACKGROUND_RED; - if( (num & 0x02)>0 ) // second bit set = green - info.wAttributes |= BACKGROUND_GREEN; - if( (num & 0x04)>0 ) // third bit set = blue - info.wAttributes |= BACKGROUND_BLUE; - } - } - // set the attributes - SetConsoleTextAttribute(handle, info.wAttributes); - } - else if( *q=='J' ) - { // \033[#J - Erase Display (ED) - // \033[0J - Clears the screen from cursor to end of display. The cursor position is unchanged. - // \033[1J - Clears the screen from start to cursor. The cursor position is unchanged. - // \033[2J - Clears the screen and moves the cursor to the home position (line 1, column 1). - uint8 num = (numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F); - int cnt; - DWORD tmp; - COORD origin = {0,0}; - if(num==1) - { // chars from start up to and including cursor - cnt = info.dwSize.X * info.dwCursorPosition.Y + info.dwCursorPosition.X + 1; - } - else if(num==2) - { // Number of chars on screen. - cnt = info.dwSize.X * info.dwSize.Y; - SetConsoleCursorPosition(handle, origin); - } - else// 0 and default - { // number of chars from cursor to end - origin = info.dwCursorPosition; - cnt = info.dwSize.X * (info.dwSize.Y - info.dwCursorPosition.Y) - info.dwCursorPosition.X; - } - FillConsoleOutputAttribute(handle, info.wAttributes, cnt, origin, &tmp); - FillConsoleOutputCharacter(handle, ' ', cnt, origin, &tmp); - } - else if( *q=='K' ) - { // \033[K : clear line from actual position to end of the line - // \033[0K - Clears all characters from the cursor position to the end of the line. - // \033[1K - Clears all characters from start of line to the cursor position. - // \033[2K - Clears all characters of the whole line. - - uint8 num = (numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F); - COORD origin = {0,info.dwCursorPosition.Y}; //warning C4204 - SHORT cnt; - DWORD tmp; - if(num==1) - { - cnt = info.dwCursorPosition.X + 1; - } - else if(num==2) - { - cnt = info.dwSize.X; - } - else// 0 and default - { - origin = info.dwCursorPosition; - cnt = info.dwSize.X - info.dwCursorPosition.X; // how many spaces until line is full - } - FillConsoleOutputAttribute(handle, info.wAttributes, cnt, origin, &tmp); - FillConsoleOutputCharacter(handle, ' ', cnt, origin, &tmp); - } - else if( *q == 'H' || *q == 'f' ) - { // \033[#;#H - Cursor Position (CUP) - // \033[#;#f - Horizontal & Vertical Position - // The first # specifies the line number, the second # specifies the column. - // The default for both is 1 - info.dwCursorPosition.X = (numbers[numpoint])?(numbers[numpoint]>>4)*10+((numbers[numpoint]&0x0F)-1):0; - info.dwCursorPosition.Y = (numpoint && numbers[numpoint-1])?(numbers[numpoint-1]>>4)*10+((numbers[numpoint-1]&0x0F)-1):0; - - if( info.dwCursorPosition.X >= info.dwSize.X ) info.dwCursorPosition.Y = info.dwSize.X-1; - if( info.dwCursorPosition.Y >= info.dwSize.Y ) info.dwCursorPosition.Y = info.dwSize.Y-1; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } - else if( *q=='s' ) - { // \033[s - Save Cursor Position (SCP) - /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] - CONSOLE_SCREEN_BUFFER_INFO info; - GetConsoleScreenBufferInfo(handle, &info); - saveposition = info.dwCursorPosition; - */ - } - else if( *q=='u' ) - { // \033[u - Restore cursor position (RCP) - /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] - SetConsoleCursorPosition(handle, saveposition); - */ - } - else if( *q == 'A' ) - { // \033[#A - Cursor Up (CUU) - // Moves the cursor UP # number of lines - info.dwCursorPosition.Y -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; - - if( info.dwCursorPosition.Y < 0 ) - info.dwCursorPosition.Y = 0; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } - else if( *q == 'B' ) - { // \033[#B - Cursor Down (CUD) - // Moves the cursor DOWN # number of lines - info.dwCursorPosition.Y += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; - - if( info.dwCursorPosition.Y >= info.dwSize.Y ) - info.dwCursorPosition.Y = info.dwSize.Y-1; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } - else if( *q == 'C' ) - { // \033[#C - Cursor Forward (CUF) - // Moves the cursor RIGHT # number of columns - info.dwCursorPosition.X += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; - - if( info.dwCursorPosition.X >= info.dwSize.X ) - info.dwCursorPosition.X = info.dwSize.X-1; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } - else if( *q == 'D' ) - { // \033[#D - Cursor Backward (CUB) - // Moves the cursor LEFT # number of columns - info.dwCursorPosition.X -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; - - if( info.dwCursorPosition.X < 0 ) - info.dwCursorPosition.X = 0; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } - else if( *q == 'E' ) - { // \033[#E - Cursor Next Line (CNL) - // Moves the cursor down the indicated # of rows, to column 1 - info.dwCursorPosition.Y += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; - info.dwCursorPosition.X = 0; - - if( info.dwCursorPosition.Y >= info.dwSize.Y ) - info.dwCursorPosition.Y = info.dwSize.Y-1; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } - else if( *q == 'F' ) - { // \033[#F - Cursor Preceding Line (CPL) - // Moves the cursor up the indicated # of rows, to column 1. - info.dwCursorPosition.Y -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; - info.dwCursorPosition.X = 0; - - if( info.dwCursorPosition.Y < 0 ) - info.dwCursorPosition.Y = 0; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } - else if( *q == 'G' ) - { // \033[#G - Cursor Horizontal Absolute (CHA) - // Moves the cursor to indicated column in current row. - info.dwCursorPosition.X = (numbers[numpoint])?(numbers[numpoint]>>4)*10+((numbers[numpoint]&0x0F)-1):0; - - if( info.dwCursorPosition.X >= info.dwSize.X ) - info.dwCursorPosition.X = info.dwSize.X-1; - SetConsoleCursorPosition(handle, info.dwCursorPosition); - } - else if( *q == 'L' || *q == 'M' || *q == '@' || *q == 'P') - { // not implemented, just skip - } - else - { // no number nor valid sequencer - // something is fishy, we break and give the current char free - --q; - } - // skip the sequencer and search again - p = q+1; - break; - }// end while - } - } - if (*p) // write the rest of the buffer - if( 0==WriteConsole(handle, p, (DWORD)strlen(p), &written, 0) ) - WriteFile(handle, p, (DWORD)strlen(p), &written, 0); - FREEBUF(tempbuf); - return 0; + ///////////////////////////////////////////////////////////////// + /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] + static COORD saveposition = {0,0}; + */ + + ///////////////////////////////////////////////////////////////// + DWORD written; + char *p, *q; + NEWBUF(tempbuf); // temporary buffer + + if (!fmt || !*fmt) + return 0; + + // Print everything to the buffer + BUFVPRINTF(tempbuf,fmt,argptr); + + if (!is_console(handle) && stdout_with_ansisequence) { + WriteFile(handle, BUFVAL(tempbuf), BUFLEN(tempbuf), &written, 0); + return 0; + } + + // start with processing + p = BUFVAL(tempbuf); + while ((q = strchr(p, 0x1b)) != NULL) { + // find the escape character + if (0==WriteConsole(handle, p, (DWORD)(q-p), &written, 0)) // write up to the escape + WriteFile(handle, p, (DWORD)(q-p), &written, 0); + + if (q[1]!='[') { + // write the escape char (whatever purpose it has) + if (0==WriteConsole(handle, q, 1, &written, 0)) + WriteFile(handle,q, 1, &written, 0); + p=q+1; //and start searching again + } else { + // from here, we will skip the '\033[' + // we break at the first unprocessible position + // assuming regular text is starting there + uint8 numbers[16], numpoint=0; + CONSOLE_SCREEN_BUFFER_INFO info; + + // initialize + GetConsoleScreenBufferInfo(handle, &info); + memset(numbers,0,sizeof(numbers)); + + // skip escape and bracket + q=q+2; + for (;;) { + if (ISDIGIT(*q)) { + // add number to number array, only accept 2digits, shift out the rest + // so // \033[123456789m will become \033[89m + numbers[numpoint] = (numbers[numpoint]<<4) | (*q-'0'); + ++q; + // and next character + continue; + } else if (*q == ';') { + // delimiter + if (numpoint7) num=7; // set white for 37, 38 and 39 + info.wAttributes &= ~(FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE); + if ((num & 0x01)>0) // lowest bit set = red + info.wAttributes |= FOREGROUND_RED; + if ((num & 0x02)>0) // second bit set = green + info.wAttributes |= FOREGROUND_GREEN; + if ((num & 0x04)>0) // third bit set = blue + info.wAttributes |= FOREGROUND_BLUE; + } else if (0x40 == (0xF0 & numbers[i])) { + // background + uint8 num = numbers[i]&0x0F; + if (num==9) info.wAttributes |= BACKGROUND_INTENSITY; + if (num>7) num=7; // set white for 47, 48 and 49 + info.wAttributes &= ~(BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE); + if ((num & 0x01)>0) // lowest bit set = red + info.wAttributes |= BACKGROUND_RED; + if ((num & 0x02)>0) // second bit set = green + info.wAttributes |= BACKGROUND_GREEN; + if ((num & 0x04)>0) // third bit set = blue + info.wAttributes |= BACKGROUND_BLUE; + } + } + // set the attributes + SetConsoleTextAttribute(handle, info.wAttributes); + } else if (*q=='J') { + // \033[#J - Erase Display (ED) + // \033[0J - Clears the screen from cursor to end of display. The cursor position is unchanged. + // \033[1J - Clears the screen from start to cursor. The cursor position is unchanged. + // \033[2J - Clears the screen and moves the cursor to the home position (line 1, column 1). + uint8 num = (numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F); + int cnt; + DWORD tmp; + COORD origin = {0,0}; + if (num==1) { + // chars from start up to and including cursor + cnt = info.dwSize.X * info.dwCursorPosition.Y + info.dwCursorPosition.X + 1; + } else if (num==2) { + // Number of chars on screen. + cnt = info.dwSize.X * info.dwSize.Y; + SetConsoleCursorPosition(handle, origin); + } else { // 0 and default + // number of chars from cursor to end + origin = info.dwCursorPosition; + cnt = info.dwSize.X * (info.dwSize.Y - info.dwCursorPosition.Y) - info.dwCursorPosition.X; + } + FillConsoleOutputAttribute(handle, info.wAttributes, cnt, origin, &tmp); + FillConsoleOutputCharacter(handle, ' ', cnt, origin, &tmp); + } else if (*q=='K') { + // \033[K : clear line from actual position to end of the line + // \033[0K - Clears all characters from the cursor position to the end of the line. + // \033[1K - Clears all characters from start of line to the cursor position. + // \033[2K - Clears all characters of the whole line. + + uint8 num = (numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F); + COORD origin = {0,info.dwCursorPosition.Y}; //warning C4204 + SHORT cnt; + DWORD tmp; + if (num==1) { + cnt = info.dwCursorPosition.X + 1; + } else if (num==2) { + cnt = info.dwSize.X; + } else { // 0 and default + origin = info.dwCursorPosition; + cnt = info.dwSize.X - info.dwCursorPosition.X; // how many spaces until line is full + } + FillConsoleOutputAttribute(handle, info.wAttributes, cnt, origin, &tmp); + FillConsoleOutputCharacter(handle, ' ', cnt, origin, &tmp); + } else if (*q == 'H' || *q == 'f') { + // \033[#;#H - Cursor Position (CUP) + // \033[#;#f - Horizontal & Vertical Position + // The first # specifies the line number, the second # specifies the column. + // The default for both is 1 + info.dwCursorPosition.X = (numbers[numpoint])?(numbers[numpoint]>>4)*10+((numbers[numpoint]&0x0F)-1):0; + info.dwCursorPosition.Y = (numpoint && numbers[numpoint-1])?(numbers[numpoint-1]>>4)*10+((numbers[numpoint-1]&0x0F)-1):0; + + if (info.dwCursorPosition.X >= info.dwSize.X) info.dwCursorPosition.Y = info.dwSize.X-1; + if (info.dwCursorPosition.Y >= info.dwSize.Y) info.dwCursorPosition.Y = info.dwSize.Y-1; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } else if (*q=='s') { + // \033[s - Save Cursor Position (SCP) + /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] + CONSOLE_SCREEN_BUFFER_INFO info; + GetConsoleScreenBufferInfo(handle, &info); + saveposition = info.dwCursorPosition; + */ + } else if (*q=='u') { + // \033[u - Restore cursor position (RCP) + /* XXX Two streams are being used. Disabled to avoid inconsistency [flaviojs] + SetConsoleCursorPosition(handle, saveposition); + */ + } else if (*q == 'A') { + // \033[#A - Cursor Up (CUU) + // Moves the cursor UP # number of lines + info.dwCursorPosition.Y -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; + + if (info.dwCursorPosition.Y < 0) + info.dwCursorPosition.Y = 0; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } else if (*q == 'B') { + // \033[#B - Cursor Down (CUD) + // Moves the cursor DOWN # number of lines + info.dwCursorPosition.Y += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; + + if (info.dwCursorPosition.Y >= info.dwSize.Y) + info.dwCursorPosition.Y = info.dwSize.Y-1; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } else if (*q == 'C') { + // \033[#C - Cursor Forward (CUF) + // Moves the cursor RIGHT # number of columns + info.dwCursorPosition.X += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; + + if (info.dwCursorPosition.X >= info.dwSize.X) + info.dwCursorPosition.X = info.dwSize.X-1; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } else if (*q == 'D') { + // \033[#D - Cursor Backward (CUB) + // Moves the cursor LEFT # number of columns + info.dwCursorPosition.X -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; + + if (info.dwCursorPosition.X < 0) + info.dwCursorPosition.X = 0; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } else if (*q == 'E') { + // \033[#E - Cursor Next Line (CNL) + // Moves the cursor down the indicated # of rows, to column 1 + info.dwCursorPosition.Y += (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; + info.dwCursorPosition.X = 0; + + if (info.dwCursorPosition.Y >= info.dwSize.Y) + info.dwCursorPosition.Y = info.dwSize.Y-1; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } else if (*q == 'F') { + // \033[#F - Cursor Preceding Line (CPL) + // Moves the cursor up the indicated # of rows, to column 1. + info.dwCursorPosition.Y -= (numbers[numpoint])?(numbers[numpoint]>>4)*10+(numbers[numpoint]&0x0F):1; + info.dwCursorPosition.X = 0; + + if (info.dwCursorPosition.Y < 0) + info.dwCursorPosition.Y = 0; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } else if (*q == 'G') { + // \033[#G - Cursor Horizontal Absolute (CHA) + // Moves the cursor to indicated column in current row. + info.dwCursorPosition.X = (numbers[numpoint])?(numbers[numpoint]>>4)*10+((numbers[numpoint]&0x0F)-1):0; + + if (info.dwCursorPosition.X >= info.dwSize.X) + info.dwCursorPosition.X = info.dwSize.X-1; + SetConsoleCursorPosition(handle, info.dwCursorPosition); + } else if (*q == 'L' || *q == 'M' || *q == '@' || *q == 'P') { + // not implemented, just skip + } else { + // no number nor valid sequencer + // something is fishy, we break and give the current char free + --q; + } + // skip the sequencer and search again + p = q+1; + break; + }// end while + } + } + if (*p) // write the rest of the buffer + if (0==WriteConsole(handle, p, (DWORD)strlen(p), &written, 0)) + WriteFile(handle, p, (DWORD)strlen(p), &written, 0); + FREEBUF(tempbuf); + return 0; } -int FPRINTF(HANDLE handle, const char *fmt, ...) +int FPRINTF(HANDLE handle, const char *fmt, ...) { - int ret; - va_list argptr; - va_start(argptr, fmt); - ret = VFPRINTF(handle,fmt,argptr); - va_end(argptr); - return ret; + int ret; + va_list argptr; + va_start(argptr, fmt); + ret = VFPRINTF(handle,fmt,argptr); + va_end(argptr); + return ret; } #define FFLUSH(handle) @@ -532,129 +496,109 @@ int FPRINTF(HANDLE handle, const char *fmt, ...) #define is_console(file) (0!=isatty(fileno(file))) //vprintf_without_ansiformats -int VFPRINTF(FILE *file, const char *fmt, va_list argptr) +int VFPRINTF(FILE *file, const char *fmt, va_list argptr) { - char *p, *q; - NEWBUF(tempbuf); // temporary buffer - - if(!fmt || !*fmt) - return 0; - - if( is_console(file) || stdout_with_ansisequence ) - { - vfprintf(file, fmt, argptr); - return 0; - } - - // Print everything to the buffer - BUFVPRINTF(tempbuf,fmt,argptr); - - // start with processing - p = BUFVAL(tempbuf); - while ((q = strchr(p, 0x1b)) != NULL) - { // find the escape character - fprintf(file, "%.*s", (int)(q-p), p); // write up to the escape - if( q[1]!='[' ) - { // write the escape char (whatever purpose it has) - fprintf(file, "%.*s", 1, q); - p=q+1; //and start searching again - } - else - { // from here, we will skip the '\033[' - // we break at the first unprocessible position - // assuming regular text is starting there - - // skip escape and bracket - q=q+2; - while(1) - { - if( ISDIGIT(*q) ) - { - ++q; - // and next character - continue; - } - else if( *q == ';' ) - { // delimiter - ++q; - // and next number - continue; - } - else if( *q == 'm' ) - { // \033[#;...;#m - Set Graphics Rendition (SGR) - // set the attributes - } - else if( *q=='J' ) - { // \033[#J - Erase Display (ED) - } - else if( *q=='K' ) - { // \033[K : clear line from actual position to end of the line - } - else if( *q == 'H' || *q == 'f' ) - { // \033[#;#H - Cursor Position (CUP) - // \033[#;#f - Horizontal & Vertical Position - } - else if( *q=='s' ) - { // \033[s - Save Cursor Position (SCP) - } - else if( *q=='u' ) - { // \033[u - Restore cursor position (RCP) - } - else if( *q == 'A' ) - { // \033[#A - Cursor Up (CUU) - // Moves the cursor UP # number of lines - } - else if( *q == 'B' ) - { // \033[#B - Cursor Down (CUD) - // Moves the cursor DOWN # number of lines - } - else if( *q == 'C' ) - { // \033[#C - Cursor Forward (CUF) - // Moves the cursor RIGHT # number of columns - } - else if( *q == 'D' ) - { // \033[#D - Cursor Backward (CUB) - // Moves the cursor LEFT # number of columns - } - else if( *q == 'E' ) - { // \033[#E - Cursor Next Line (CNL) - // Moves the cursor down the indicated # of rows, to column 1 - } - else if( *q == 'F' ) - { // \033[#F - Cursor Preceding Line (CPL) - // Moves the cursor up the indicated # of rows, to column 1. - } - else if( *q == 'G' ) - { // \033[#G - Cursor Horizontal Absolute (CHA) - // Moves the cursor to indicated column in current row. - } - else if( *q == 'L' || *q == 'M' || *q == '@' || *q == 'P') - { // not implemented, just skip - } - else - { // no number nor valid sequencer - // something is fishy, we break and give the current char free - --q; - } - // skip the sequencer and search again - p = q+1; - break; - }// end while - } - } - if (*p) // write the rest of the buffer - fprintf(file, "%s", p); - FREEBUF(tempbuf); - return 0; + char *p, *q; + NEWBUF(tempbuf); // temporary buffer + + if (!fmt || !*fmt) + return 0; + + if (is_console(file) || stdout_with_ansisequence) { + vfprintf(file, fmt, argptr); + return 0; + } + + // Print everything to the buffer + BUFVPRINTF(tempbuf,fmt,argptr); + + // start with processing + p = BUFVAL(tempbuf); + while ((q = strchr(p, 0x1b)) != NULL) { + // find the escape character + fprintf(file, "%.*s", (int)(q-p), p); // write up to the escape + if (q[1]!='[') { + // write the escape char (whatever purpose it has) + fprintf(file, "%.*s", 1, q); + p=q+1; //and start searching again + } else { + // from here, we will skip the '\033[' + // we break at the first unprocessible position + // assuming regular text is starting there + + // skip escape and bracket + q=q+2; + while (1) { + if (ISDIGIT(*q)) { + ++q; + // and next character + continue; + } else if (*q == ';') { + // delimiter + ++q; + // and next number + continue; + } else if (*q == 'm') { + // \033[#;...;#m - Set Graphics Rendition (SGR) + // set the attributes + } else if (*q=='J') { + // \033[#J - Erase Display (ED) + } else if (*q=='K') { + // \033[K : clear line from actual position to end of the line + } else if (*q == 'H' || *q == 'f') { + // \033[#;#H - Cursor Position (CUP) + // \033[#;#f - Horizontal & Vertical Position + } else if (*q=='s') { + // \033[s - Save Cursor Position (SCP) + } else if (*q=='u') { + // \033[u - Restore cursor position (RCP) + } else if (*q == 'A') { + // \033[#A - Cursor Up (CUU) + // Moves the cursor UP # number of lines + } else if (*q == 'B') { + // \033[#B - Cursor Down (CUD) + // Moves the cursor DOWN # number of lines + } else if (*q == 'C') { + // \033[#C - Cursor Forward (CUF) + // Moves the cursor RIGHT # number of columns + } else if (*q == 'D') { + // \033[#D - Cursor Backward (CUB) + // Moves the cursor LEFT # number of columns + } else if (*q == 'E') { + // \033[#E - Cursor Next Line (CNL) + // Moves the cursor down the indicated # of rows, to column 1 + } else if (*q == 'F') { + // \033[#F - Cursor Preceding Line (CPL) + // Moves the cursor up the indicated # of rows, to column 1. + } else if (*q == 'G') { + // \033[#G - Cursor Horizontal Absolute (CHA) + // Moves the cursor to indicated column in current row. + } else if (*q == 'L' || *q == 'M' || *q == '@' || *q == 'P') { + // not implemented, just skip + } else { + // no number nor valid sequencer + // something is fishy, we break and give the current char free + --q; + } + // skip the sequencer and search again + p = q+1; + break; + }// end while + } + } + if (*p) // write the rest of the buffer + fprintf(file, "%s", p); + FREEBUF(tempbuf); + return 0; } -int FPRINTF(FILE *file, const char *fmt, ...) +int FPRINTF(FILE *file, const char *fmt, ...) { - int ret; - va_list argptr; - va_start(argptr, fmt); - ret = VFPRINTF(file,fmt,argptr); - va_end(argptr); - return ret; + int ret; + va_list argptr; + va_start(argptr, fmt); + ret = VFPRINTF(file,fmt,argptr); + va_end(argptr); + return ret; } #define FFLUSH fflush @@ -677,216 +621,225 @@ char timestamp_format[20] = ""; //For displaying Timestamps int _vShowMessage(enum msg_type flag, const char *string, va_list ap) { - va_list apcopy; - char prefix[100]; + va_list apcopy; + char prefix[100]; #if defined(DEBUGLOGMAP) || defined(DEBUGLOGCHAR) || defined(DEBUGLOGLOGIN) - FILE *fp; + FILE *fp; #endif - - if (!string || *string == '\0') { - ShowError("Empty string passed to _vShowMessage().\n"); - return 1; - } - /** - * For the buildbot, these result in a EXIT_FAILURE from core.c when done reading the params. - **/ + + if (!string || *string == '\0') { + ShowError("Empty string passed to _vShowMessage().\n"); + return 1; + } + /** + * For the buildbot, these result in a EXIT_FAILURE from core.c when done reading the params. + **/ #if defined(BUILDBOT) - if( flag == MSG_WARNING || - flag == MSG_ERROR || - flag == MSG_SQL ) { - buildbotflag = 1; - } + if (flag == MSG_WARNING || + flag == MSG_ERROR || + flag == MSG_SQL) { + buildbotflag = 1; + } #endif - if( - ( flag == MSG_WARNING && console_msg_log&1 ) || - ( ( flag == MSG_ERROR || flag == MSG_SQL ) && console_msg_log&2 ) || - ( flag == MSG_DEBUG && console_msg_log&4 ) ) {//[Ind] - FILE *log = NULL; - if( (log = fopen(SERVER_TYPE == ATHENA_SERVER_MAP ? "./log/map-msg_log.log" : "./log/unknown.log","a+")) ) { - char timestring[255]; - time_t curtime; - time(&curtime); - strftime(timestring, 254, "%m/%d/%Y %H:%M:%S", localtime(&curtime)); - fprintf(log,"(%s) [ %s ] : ", - timestring, - flag == MSG_WARNING ? "Warning" : - flag == MSG_ERROR ? "Error" : - flag == MSG_SQL ? "SQL Error" : - flag == MSG_DEBUG ? "Debug" : - "Unknown"); - va_copy(apcopy, ap); - vfprintf(log,string,apcopy); - va_end(apcopy); - fclose(log); - } - } - if( - (flag == MSG_INFORMATION && msg_silent&1) || - (flag == MSG_STATUS && msg_silent&2) || - (flag == MSG_NOTICE && msg_silent&4) || - (flag == MSG_WARNING && msg_silent&8) || - (flag == MSG_ERROR && msg_silent&16) || - (flag == MSG_SQL && msg_silent&16) || - (flag == MSG_DEBUG && msg_silent&32) - ) - return 0; //Do not print it. - - if (timestamp_format[0] && flag != MSG_NONE) - { //Display time format. [Skotlex] - time_t t = time(NULL); - strftime(prefix, 80, timestamp_format, localtime(&t)); - } else prefix[0]='\0'; - - switch (flag) { - case MSG_NONE: // direct printf replacement - break; - case MSG_STATUS: //Bright Green (To inform about good things) - strcat(prefix,CL_GREEN"[Status]"CL_RESET":"); - break; - case MSG_SQL: //Bright Violet (For dumping out anything related with SQL) <- Actually, this is mostly used for SQL errors with the database, as successes can as well just be anything else... [Skotlex] - strcat(prefix,CL_MAGENTA"[SQL]"CL_RESET":"); - break; - case MSG_INFORMATION: //Bright White (Variable information) - strcat(prefix,CL_WHITE"[Info]"CL_RESET":"); - break; - case MSG_NOTICE: //Bright White (Less than a warning) - strcat(prefix,CL_WHITE"[Notice]"CL_RESET":"); - break; - case MSG_WARNING: //Bright Yellow - strcat(prefix,CL_YELLOW"[Warning]"CL_RESET":"); - break; - case MSG_DEBUG: //Bright Cyan, important stuff! - strcat(prefix,CL_CYAN"[Debug]"CL_RESET":"); - break; - case MSG_ERROR: //Bright Red (Regular errors) - strcat(prefix,CL_RED"[Error]"CL_RESET":"); - break; - case MSG_FATALERROR: //Bright Red (Fatal errors, abort(); if possible) - strcat(prefix,CL_RED"[Fatal Error]"CL_RESET":"); - break; - default: - ShowError("In function _vShowMessage() -> Invalid flag passed.\n"); - return 1; - } - - if (flag == MSG_ERROR || flag == MSG_FATALERROR || flag == MSG_SQL) - { //Send Errors to StdErr [Skotlex] - FPRINTF(STDERR, "%s ", prefix); - va_copy(apcopy, ap); - VFPRINTF(STDERR, string, apcopy); - va_end(apcopy); - FFLUSH(STDERR); - } else { - if (flag != MSG_NONE) - FPRINTF(STDOUT, "%s ", prefix); - va_copy(apcopy, ap); - VFPRINTF(STDOUT, string, apcopy); - va_end(apcopy); - FFLUSH(STDOUT); - } + if ( + (flag == MSG_WARNING && console_msg_log&1) || + ((flag == MSG_ERROR || flag == MSG_SQL) && console_msg_log&2) || + (flag == MSG_DEBUG && console_msg_log&4)) { //[Ind] + FILE *log = NULL; + if ((log = fopen(SERVER_TYPE == ATHENA_SERVER_MAP ? "./log/map-msg_log.log" : "./log/unknown.log","a+"))) { + char timestring[255]; + time_t curtime; + time(&curtime); + strftime(timestring, 254, "%m/%d/%Y %H:%M:%S", localtime(&curtime)); + fprintf(log,"(%s) [ %s ] : ", + timestring, + flag == MSG_WARNING ? "Warning" : + flag == MSG_ERROR ? "Error" : + flag == MSG_SQL ? "SQL Error" : + flag == MSG_DEBUG ? "Debug" : + "Unknown"); + va_copy(apcopy, ap); + vfprintf(log,string,apcopy); + va_end(apcopy); + fclose(log); + } + } + if ( + (flag == MSG_INFORMATION && msg_silent&1) || + (flag == MSG_STATUS && msg_silent&2) || + (flag == MSG_NOTICE && msg_silent&4) || + (flag == MSG_WARNING && msg_silent&8) || + (flag == MSG_ERROR && msg_silent&16) || + (flag == MSG_SQL && msg_silent&16) || + (flag == MSG_DEBUG && msg_silent&32) + ) + return 0; //Do not print it. + + if (timestamp_format[0] && flag != MSG_NONE) { + //Display time format. [Skotlex] + time_t t = time(NULL); + strftime(prefix, 80, timestamp_format, localtime(&t)); + } else prefix[0]='\0'; + + switch (flag) { + case MSG_NONE: // direct printf replacement + break; + case MSG_STATUS: //Bright Green (To inform about good things) + strcat(prefix,CL_GREEN"[Status]"CL_RESET":"); + break; + case MSG_SQL: //Bright Violet (For dumping out anything related with SQL) <- Actually, this is mostly used for SQL errors with the database, as successes can as well just be anything else... [Skotlex] + strcat(prefix,CL_MAGENTA"[SQL]"CL_RESET":"); + break; + case MSG_INFORMATION: //Bright White (Variable information) + strcat(prefix,CL_WHITE"[Info]"CL_RESET":"); + break; + case MSG_NOTICE: //Bright White (Less than a warning) + strcat(prefix,CL_WHITE"[Notice]"CL_RESET":"); + break; + case MSG_WARNING: //Bright Yellow + strcat(prefix,CL_YELLOW"[Warning]"CL_RESET":"); + break; + case MSG_DEBUG: //Bright Cyan, important stuff! + strcat(prefix,CL_CYAN"[Debug]"CL_RESET":"); + break; + case MSG_ERROR: //Bright Red (Regular errors) + strcat(prefix,CL_RED"[Error]"CL_RESET":"); + break; + case MSG_FATALERROR: //Bright Red (Fatal errors, abort(); if possible) + strcat(prefix,CL_RED"[Fatal Error]"CL_RESET":"); + break; + default: + ShowError("In function _vShowMessage() -> Invalid flag passed.\n"); + return 1; + } + + if (flag == MSG_ERROR || flag == MSG_FATALERROR || flag == MSG_SQL) { + //Send Errors to StdErr [Skotlex] + FPRINTF(STDERR, "%s ", prefix); + va_copy(apcopy, ap); + VFPRINTF(STDERR, string, apcopy); + va_end(apcopy); + FFLUSH(STDERR); + } else { + if (flag != MSG_NONE) + FPRINTF(STDOUT, "%s ", prefix); + va_copy(apcopy, ap); + VFPRINTF(STDOUT, string, apcopy); + va_end(apcopy); + FFLUSH(STDOUT); + } #if defined(DEBUGLOGMAP) || defined(DEBUGLOGCHAR) || defined(DEBUGLOGLOGIN) - if(strlen(DEBUGLOGPATH) > 0) { - fp=fopen(DEBUGLOGPATH,"a"); - if (fp == NULL) { - FPRINTF(STDERR, CL_RED"[ERROR]"CL_RESET": Could not open '"CL_WHITE"%s"CL_RESET"', access denied.\n", DEBUGLOGPATH); - FFLUSH(STDERR); - } else { - fprintf(fp,"%s ", prefix); - va_copy(apcopy, ap); - vfprintf(fp,string,apcopy); - va_end(apcopy); - fclose(fp); - } - } else { - FPRINTF(STDERR, CL_RED"[ERROR]"CL_RESET": DEBUGLOGPATH not defined!\n"); - FFLUSH(STDERR); - } + if (strlen(DEBUGLOGPATH) > 0) { + fp=fopen(DEBUGLOGPATH,"a"); + if (fp == NULL) { + FPRINTF(STDERR, CL_RED"[ERROR]"CL_RESET": Could not open '"CL_WHITE"%s"CL_RESET"', access denied.\n", DEBUGLOGPATH); + FFLUSH(STDERR); + } else { + fprintf(fp,"%s ", prefix); + va_copy(apcopy, ap); + vfprintf(fp,string,apcopy); + va_end(apcopy); + fclose(fp); + } + } else { + FPRINTF(STDERR, CL_RED"[ERROR]"CL_RESET": DEBUGLOGPATH not defined!\n"); + FFLUSH(STDERR); + } #endif - return 0; + return 0; } void ClearScreen(void) { #ifndef _WIN32 - ShowMessage(CL_CLS); // to prevent empty string passed messages + ShowMessage(CL_CLS); // to prevent empty string passed messages #endif } int _ShowMessage(enum msg_type flag, const char *string, ...) { - int ret; - va_list ap; - va_start(ap, string); - ret = _vShowMessage(flag, string, ap); - va_end(ap); - return ret; + int ret; + va_list ap; + va_start(ap, string); + ret = _vShowMessage(flag, string, ap); + va_end(ap); + return ret; } // direct printf replacement -void ShowMessage(const char *string, ...) { - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_NONE, string, ap); - va_end(ap); +void ShowMessage(const char *string, ...) +{ + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_NONE, string, ap); + va_end(ap); } -void ShowStatus(const char *string, ...) { - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_STATUS, string, ap); - va_end(ap); +void ShowStatus(const char *string, ...) +{ + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_STATUS, string, ap); + va_end(ap); } -void ShowSQL(const char *string, ...) { - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_SQL, string, ap); - va_end(ap); +void ShowSQL(const char *string, ...) +{ + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_SQL, string, ap); + va_end(ap); } -void ShowInfo(const char *string, ...) { - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_INFORMATION, string, ap); - va_end(ap); +void ShowInfo(const char *string, ...) +{ + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_INFORMATION, string, ap); + va_end(ap); } -void ShowNotice(const char *string, ...) { - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_NOTICE, string, ap); - va_end(ap); +void ShowNotice(const char *string, ...) +{ + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_NOTICE, string, ap); + va_end(ap); } -void ShowWarning(const char *string, ...) { - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_WARNING, string, ap); - va_end(ap); +void ShowWarning(const char *string, ...) +{ + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_WARNING, string, ap); + va_end(ap); } void ShowConfigWarning(config_setting_t *config, const char *string, ...) { - StringBuf buf; - va_list ap; - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, string); - StringBuf_Printf(&buf, " (%s:%d)\n", config_setting_source_file(config), config_setting_source_line(config)); - va_start(ap, string); - _vShowMessage(MSG_WARNING, StringBuf_Value(&buf), ap); - va_end(ap); - StringBuf_Destroy(&buf); + StringBuf buf; + va_list ap; + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, string); + StringBuf_Printf(&buf, " (%s:%d)\n", config_setting_source_file(config), config_setting_source_line(config)); + va_start(ap, string); + _vShowMessage(MSG_WARNING, StringBuf_Value(&buf), ap); + va_end(ap); + StringBuf_Destroy(&buf); } -void ShowDebug(const char *string, ...) { - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_DEBUG, string, ap); - va_end(ap); +void ShowDebug(const char *string, ...) +{ + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_DEBUG, string, ap); + va_end(ap); } -void ShowError(const char *string, ...) { - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_ERROR, string, ap); - va_end(ap); +void ShowError(const char *string, ...) +{ + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_ERROR, string, ap); + va_end(ap); } -void ShowFatalError(const char *string, ...) { - va_list ap; - va_start(ap, string); - _vShowMessage(MSG_FATALERROR, string, ap); - va_end(ap); +void ShowFatalError(const char *string, ...) +{ + va_list ap; + va_start(ap, string); + _vShowMessage(MSG_FATALERROR, string, ap); + va_end(ap); } diff --git a/src/common/showmsg.h b/src/common/showmsg.h index 0d6cb5c9f..8c2b5bd42 100644 --- a/src/common/showmsg.h +++ b/src/common/showmsg.h @@ -14,58 +14,58 @@ // \033[0m : reset color parameter // \033[1m : use bold for font -#define CL_RESET "\033[0m" -#define CL_CLS "\033[2J" -#define CL_CLL "\033[K" +#define CL_RESET "\033[0m" +#define CL_CLS "\033[2J" +#define CL_CLL "\033[K" // font settings -#define CL_BOLD "\033[1m" -#define CL_NORM CL_RESET -#define CL_NORMAL CL_RESET -#define CL_NONE CL_RESET +#define CL_BOLD "\033[1m" +#define CL_NORM CL_RESET +#define CL_NORMAL CL_RESET +#define CL_NONE CL_RESET // foreground color and bold font (bright color on windows) -#define CL_WHITE "\033[1;37m" -#define CL_GRAY "\033[1;30m" -#define CL_RED "\033[1;31m" -#define CL_GREEN "\033[1;32m" -#define CL_YELLOW "\033[1;33m" -#define CL_BLUE "\033[1;34m" -#define CL_MAGENTA "\033[1;35m" -#define CL_CYAN "\033[1;36m" +#define CL_WHITE "\033[1;37m" +#define CL_GRAY "\033[1;30m" +#define CL_RED "\033[1;31m" +#define CL_GREEN "\033[1;32m" +#define CL_YELLOW "\033[1;33m" +#define CL_BLUE "\033[1;34m" +#define CL_MAGENTA "\033[1;35m" +#define CL_CYAN "\033[1;36m" // background color -#define CL_BG_BLACK "\033[40m" -#define CL_BG_RED "\033[41m" -#define CL_BG_GREEN "\033[42m" -#define CL_BG_YELLOW "\033[43m" -#define CL_BG_BLUE "\033[44m" -#define CL_BG_MAGENTA "\033[45m" -#define CL_BG_CYAN "\033[46m" -#define CL_BG_WHITE "\033[47m" +#define CL_BG_BLACK "\033[40m" +#define CL_BG_RED "\033[41m" +#define CL_BG_GREEN "\033[42m" +#define CL_BG_YELLOW "\033[43m" +#define CL_BG_BLUE "\033[44m" +#define CL_BG_MAGENTA "\033[45m" +#define CL_BG_CYAN "\033[46m" +#define CL_BG_WHITE "\033[47m" // foreground color and normal font (normal color on windows) -#define CL_LT_BLACK "\033[0;30m" -#define CL_LT_RED "\033[0;31m" -#define CL_LT_GREEN "\033[0;32m" -#define CL_LT_YELLOW "\033[0;33m" -#define CL_LT_BLUE "\033[0;34m" -#define CL_LT_MAGENTA "\033[0;35m" -#define CL_LT_CYAN "\033[0;36m" -#define CL_LT_WHITE "\033[0;37m" +#define CL_LT_BLACK "\033[0;30m" +#define CL_LT_RED "\033[0;31m" +#define CL_LT_GREEN "\033[0;32m" +#define CL_LT_YELLOW "\033[0;33m" +#define CL_LT_BLUE "\033[0;34m" +#define CL_LT_MAGENTA "\033[0;35m" +#define CL_LT_CYAN "\033[0;36m" +#define CL_LT_WHITE "\033[0;37m" // foreground color and bold font (bright color on windows) -#define CL_BT_BLACK "\033[1;30m" -#define CL_BT_RED "\033[1;31m" -#define CL_BT_GREEN "\033[1;32m" -#define CL_BT_YELLOW "\033[1;33m" -#define CL_BT_BLUE "\033[1;34m" -#define CL_BT_MAGENTA "\033[1;35m" -#define CL_BT_CYAN "\033[1;36m" -#define CL_BT_WHITE "\033[1;37m" +#define CL_BT_BLACK "\033[1;30m" +#define CL_BT_RED "\033[1;31m" +#define CL_BT_GREEN "\033[1;32m" +#define CL_BT_YELLOW "\033[1;33m" +#define CL_BT_BLUE "\033[1;34m" +#define CL_BT_MAGENTA "\033[1;35m" +#define CL_BT_CYAN "\033[1;36m" +#define CL_BT_WHITE "\033[1;37m" -#define CL_WTBL "\033[37;44m" // white on blue -#define CL_XXBL "\033[0;44m" // default on blue -#define CL_PASS "\033[0;32;42m" // green on green +#define CL_WTBL "\033[37;44m" // white on blue +#define CL_XXBL "\033[0;44m" // default on blue +#define CL_PASS "\033[0;32;42m" // green on green -#define CL_SPACE " " // space aquivalent of the print messages +#define CL_SPACE " " // space aquivalent of the print messages extern int stdout_with_ansisequence; //If the color ansi sequences are to be used. [flaviojs] extern int msg_silent; //Specifies how silent the console is. [Skotlex] @@ -73,15 +73,15 @@ extern int console_msg_log; //Specifies what error messages to log. [Ind] extern char timestamp_format[20]; //For displaying Timestamps [Skotlex] enum msg_type { - MSG_NONE, - MSG_STATUS, - MSG_SQL, - MSG_INFORMATION, - MSG_NOTICE, - MSG_WARNING, - MSG_DEBUG, - MSG_ERROR, - MSG_FATALERROR + MSG_NONE, + MSG_STATUS, + MSG_SQL, + MSG_INFORMATION, + MSG_NOTICE, + MSG_WARNING, + MSG_DEBUG, + MSG_ERROR, + MSG_FATALERROR }; extern void ClearScreen(void); diff --git a/src/common/socket.c b/src/common/socket.c index d24a9c1d8..4a6e01459 100644 --- a/src/common/socket.c +++ b/src/common/socket.c @@ -15,35 +15,35 @@ #include #ifdef WIN32 - #include "../common/winapi.h" +#include "../common/winapi.h" #else - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - - #ifndef SIOCGIFCONF - #include // SIOCGIFCONF on Solaris, maybe others? [Shinomori] - #endif - #ifndef FIONBIO - #include // FIONBIO on Solaris [FlavioJS] - #endif - - #ifdef HAVE_SETRLIMIT - #include - #endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef SIOCGIFCONF +#include // SIOCGIFCONF on Solaris, maybe others? [Shinomori] +#endif +#ifndef FIONBIO +#include // FIONBIO on Solaris [FlavioJS] +#endif + +#ifdef HAVE_SETRLIMIT +#include +#endif #endif ///////////////////////////////////////////////////////////////////// #if defined(WIN32) ///////////////////////////////////////////////////////////////////// -// windows portability layer +// windows portability layer typedef int socklen_t; @@ -75,21 +75,21 @@ static int sock_arr_len = 0; /// @return Fd or -1 int sock2fd(SOCKET s) { - int fd; - - // search for the socket - for( fd = 1; fd < sock_arr_len; ++fd ) - if( sock_arr[fd] == s ) - break;// found the socket - if( fd == sock_arr_len ) - return -1;// not found - return fd; + int fd; + + // search for the socket + for (fd = 1; fd < sock_arr_len; ++fd) + if (sock_arr[fd] == s) + break;// found the socket + if (fd == sock_arr_len) + return -1;// not found + return fd; } /// Inserts the socket into the global array of sockets. /// Returns a new fd associated with the socket. -/// If there are too many sockets it closes the socket, sets an error and +/// If there are too many sockets it closes the socket, sets an error and // returns -1 instead. /// Since fd 0 is reserved, it returns values in the range [1,FD_SETSIZE[. /// @@ -97,61 +97,61 @@ int sock2fd(SOCKET s) /// @return New fd or -1 int sock2newfd(SOCKET s) { - int fd; - - // find an empty position - for( fd = 1; fd < sock_arr_len; ++fd ) - if( sock_arr[fd] == INVALID_SOCKET ) - break;// empty position - if( fd == ARRAYLENGTH(sock_arr) ) - {// too many sockets - closesocket(s); - WSASetLastError(WSAEMFILE); - return -1; - } - sock_arr[fd] = s; - if( sock_arr_len <= fd ) - sock_arr_len = fd+1; - return fd; + int fd; + + // find an empty position + for (fd = 1; fd < sock_arr_len; ++fd) + if (sock_arr[fd] == INVALID_SOCKET) + break;// empty position + if (fd == ARRAYLENGTH(sock_arr)) { + // too many sockets + closesocket(s); + WSASetLastError(WSAEMFILE); + return -1; + } + sock_arr[fd] = s; + if (sock_arr_len <= fd) + sock_arr_len = fd+1; + return fd; } -int sAccept(int fd, struct sockaddr* addr, int* addrlen) +int sAccept(int fd, struct sockaddr *addr, int *addrlen) { - SOCKET s; + SOCKET s; - // accept connection - s = accept(fd2sock(fd), addr, addrlen); - if( s == INVALID_SOCKET ) - return -1;// error - return sock2newfd(s); + // accept connection + s = accept(fd2sock(fd), addr, addrlen); + if (s == INVALID_SOCKET) + return -1;// error + return sock2newfd(s); } int sClose(int fd) { - int ret = closesocket(fd2sock(fd)); - fd2sock(fd) = INVALID_SOCKET; - return ret; + int ret = closesocket(fd2sock(fd)); + fd2sock(fd) = INVALID_SOCKET; + return ret; } int sSocket(int af, int type, int protocol) { - SOCKET s; + SOCKET s; - // create socket - s = socket(af,type,protocol); - if( s == INVALID_SOCKET ) - return -1;// error - return sock2newfd(s); + // create socket + s = socket(af,type,protocol); + if (s == INVALID_SOCKET) + return -1;// error + return sock2newfd(s); } -char* sErr(int code) +char *sErr(int code) { - static char sbuf[512]; - // strerror does not handle socket codes - if( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, - code, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (LPTSTR)&sbuf, sizeof(sbuf), NULL) == 0 ) - snprintf(sbuf, sizeof(sbuf), "unknown error"); - return sbuf; + static char sbuf[512]; + // strerror does not handle socket codes + if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, + code, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (LPTSTR)&sbuf, sizeof(sbuf), NULL) == 0) + snprintf(sbuf, sizeof(sbuf), "unknown error"); + return sbuf; } #define sBind(fd,name,namelen) bind(fd2sock(fd),name,namelen) @@ -205,7 +205,7 @@ char* sErr(int code) ///////////////////////////////////////////////////////////////////// #ifndef MSG_NOSIGNAL - #define MSG_NOSIGNAL 0 +#define MSG_NOSIGNAL 0 #endif fd_set readfds; @@ -230,7 +230,7 @@ static size_t socket_max_client_packet = 24576; // The connection is closed if it goes over the limit. #define WFIFO_MAX (1*1024*1024) -struct socket_data* session[FD_SETSIZE]; +struct socket_data *session[FD_SETSIZE]; #ifdef SEND_SHORTLIST int send_shortlist_array[FD_SETSIZE];// we only support FD_SETSIZE sockets, limit the array to that @@ -241,387 +241,390 @@ uint32 send_shortlist_set[(FD_SETSIZE+31)/32];// to know if specific fd's are al static int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseFunc func_parse); #ifndef MINICORE - int ip_rules = 1; - static int connect_check(uint32 ip); +int ip_rules = 1; +static int connect_check(uint32 ip); #endif -const char* error_msg(void) +const char *error_msg(void) { - static char buf[512]; - int code = sErrno; - snprintf(buf, sizeof(buf), "error %d: %s", code, sErr(code)); - return buf; + static char buf[512]; + int code = sErrno; + snprintf(buf, sizeof(buf), "error %d: %s", code, sErr(code)); + return buf; } /*====================================== - * CORE : Default processing functions + * CORE : Default processing functions *--------------------------------------*/ -int null_recv(int fd) { return 0; } -int null_send(int fd) { return 0; } -int null_parse(int fd) { return 0; } +int null_recv(int fd) +{ + return 0; +} +int null_send(int fd) +{ + return 0; +} +int null_parse(int fd) +{ + return 0; +} ParseFunc default_func_parse = null_parse; void set_defaultparse(ParseFunc defaultparse) { - default_func_parse = defaultparse; + default_func_parse = defaultparse; } /*====================================== - * CORE : Socket options + * CORE : Socket options *--------------------------------------*/ void set_nonblocking(int fd, unsigned long yes) { - // FIONBIO Use with a nonzero argp parameter to enable the nonblocking mode of socket s. - // The argp parameter is zero if nonblocking is to be disabled. - if( sIoctl(fd, FIONBIO, &yes) != 0 ) - ShowError("set_nonblocking: Failed to set socket #%d to non-blocking mode (%s) - Please report this!!!\n", fd, error_msg()); + // FIONBIO Use with a nonzero argp parameter to enable the nonblocking mode of socket s. + // The argp parameter is zero if nonblocking is to be disabled. + if (sIoctl(fd, FIONBIO, &yes) != 0) + ShowError("set_nonblocking: Failed to set socket #%d to non-blocking mode (%s) - Please report this!!!\n", fd, error_msg()); } void setsocketopts(int fd) { - int yes = 1; // reuse fix + int yes = 1; // reuse fix #if !defined(WIN32) - // set SO_REAUSEADDR to true, unix only. on windows this option causes - // the previous owner of the socket to give up, which is not desirable - // in most cases, neither compatible with unix. - sSetsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char *)&yes,sizeof(yes)); + // set SO_REAUSEADDR to true, unix only. on windows this option causes + // the previous owner of the socket to give up, which is not desirable + // in most cases, neither compatible with unix. + sSetsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char *)&yes,sizeof(yes)); #ifdef SO_REUSEPORT - sSetsockopt(fd,SOL_SOCKET,SO_REUSEPORT,(char *)&yes,sizeof(yes)); + sSetsockopt(fd,SOL_SOCKET,SO_REUSEPORT,(char *)&yes,sizeof(yes)); #endif #endif - // Set the socket into no-delay mode; otherwise packets get delayed for up to 200ms, likely creating server-side lag. - // The RO protocol is mainly single-packet request/response, plus the FIFO model already does packet grouping anyway. - sSetsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof(yes)); - - // force the socket into no-wait, graceful-close mode (should be the default, but better make sure) - //(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/closesocket_2.asp) - { - struct linger opt; - opt.l_onoff = 0; // SO_DONTLINGER - opt.l_linger = 0; // Do not care - if( sSetsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&opt, sizeof(opt)) ) - ShowWarning("setsocketopts: Unable to set SO_LINGER mode for connection #%d!\n", fd); - } + // Set the socket into no-delay mode; otherwise packets get delayed for up to 200ms, likely creating server-side lag. + // The RO protocol is mainly single-packet request/response, plus the FIFO model already does packet grouping anyway. + sSetsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof(yes)); + + // force the socket into no-wait, graceful-close mode (should be the default, but better make sure) + //(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/closesocket_2.asp) + { + struct linger opt; + opt.l_onoff = 0; // SO_DONTLINGER + opt.l_linger = 0; // Do not care + if (sSetsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&opt, sizeof(opt))) + ShowWarning("setsocketopts: Unable to set SO_LINGER mode for connection #%d!\n", fd); + } } /*====================================== - * CORE : Socket Sub Function + * CORE : Socket Sub Function *--------------------------------------*/ void set_eof(int fd) { - if( session_isActive(fd) ) - { + if (session_isActive(fd)) { #ifdef SEND_SHORTLIST - // Add this socket to the shortlist for eof handling. - send_shortlist_add_fd(fd); + // Add this socket to the shortlist for eof handling. + send_shortlist_add_fd(fd); #endif - session[fd]->flag.eof = 1; - } + session[fd]->flag.eof = 1; + } } int recv_to_fifo(int fd) { - int len; - - if( !session_isActive(fd) ) - return -1; - - len = sRecv(fd, (char *) session[fd]->rdata + session[fd]->rdata_size, (int)RFIFOSPACE(fd), 0); - - if( len == SOCKET_ERROR ) - {//An exception has occured - if( sErrno != S_EWOULDBLOCK ) { - //ShowDebug("recv_to_fifo: %s, closing connection #%d\n", error_msg(), fd); - set_eof(fd); - } - return 0; - } - - if( len == 0 ) - {//Normal connection end. - set_eof(fd); - return 0; - } - - session[fd]->rdata_size += len; - session[fd]->rdata_tick = last_tick; - return 0; + int len; + + if (!session_isActive(fd)) + return -1; + + len = sRecv(fd, (char *) session[fd]->rdata + session[fd]->rdata_size, (int)RFIFOSPACE(fd), 0); + + if (len == SOCKET_ERROR) { + //An exception has occured + if (sErrno != S_EWOULDBLOCK) { + //ShowDebug("recv_to_fifo: %s, closing connection #%d\n", error_msg(), fd); + set_eof(fd); + } + return 0; + } + + if (len == 0) { + //Normal connection end. + set_eof(fd); + return 0; + } + + session[fd]->rdata_size += len; + session[fd]->rdata_tick = last_tick; + return 0; } int send_from_fifo(int fd) { - int len; + int len; - if( !session_isValid(fd) ) - return -1; + if (!session_isValid(fd)) + return -1; - if( session[fd]->wdata_size == 0 ) - return 0; // nothing to send + if (session[fd]->wdata_size == 0) + return 0; // nothing to send - len = sSend(fd, (const char *) session[fd]->wdata, (int)session[fd]->wdata_size, MSG_NOSIGNAL); + len = sSend(fd, (const char *) session[fd]->wdata, (int)session[fd]->wdata_size, MSG_NOSIGNAL); - if( len == SOCKET_ERROR ) - {//An exception has occured - if( sErrno != S_EWOULDBLOCK ) { - //ShowDebug("send_from_fifo: %s, ending connection #%d\n", error_msg(), fd); - session[fd]->wdata_size = 0; //Clear the send queue as we can't send anymore. [Skotlex] - set_eof(fd); - } - return 0; - } + if (len == SOCKET_ERROR) { + //An exception has occured + if (sErrno != S_EWOULDBLOCK) { + //ShowDebug("send_from_fifo: %s, ending connection #%d\n", error_msg(), fd); + session[fd]->wdata_size = 0; //Clear the send queue as we can't send anymore. [Skotlex] + set_eof(fd); + } + return 0; + } - if( len > 0 ) - { - // some data could not be transferred? - // shift unsent data to the beginning of the queue - if( (size_t)len < session[fd]->wdata_size ) - memmove(session[fd]->wdata, session[fd]->wdata + len, session[fd]->wdata_size - len); + if (len > 0) { + // some data could not be transferred? + // shift unsent data to the beginning of the queue + if ((size_t)len < session[fd]->wdata_size) + memmove(session[fd]->wdata, session[fd]->wdata + len, session[fd]->wdata_size - len); - session[fd]->wdata_size -= len; - } + session[fd]->wdata_size -= len; + } - return 0; + return 0; } /// Best effort - there's no warranty that the data will be sent. void flush_fifo(int fd) { - if(session[fd] != NULL) - session[fd]->func_send(fd); + if (session[fd] != NULL) + session[fd]->func_send(fd); } void flush_fifos(void) { - int i; - for(i = 1; i < fd_max; i++) - flush_fifo(i); + int i; + for (i = 1; i < fd_max; i++) + flush_fifo(i); } /*====================================== - * CORE : Connection functions + * CORE : Connection functions *--------------------------------------*/ int connect_client(int listen_fd) { - int fd; - struct sockaddr_in client_address; - socklen_t len; - - len = sizeof(client_address); - - fd = sAccept(listen_fd, (struct sockaddr*)&client_address, &len); - if ( fd == -1 ) { - ShowError("connect_client: accept failed (%s)!\n", error_msg()); - return -1; - } - if( fd == 0 ) - {// reserved - ShowError("connect_client: Socket #0 is reserved - Please report this!!!\n"); - sClose(fd); - return -1; - } - if( fd >= FD_SETSIZE ) - {// socket number too big - ShowError("connect_client: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); - sClose(fd); - return -1; - } - - setsocketopts(fd); - set_nonblocking(fd, 1); + int fd; + struct sockaddr_in client_address; + socklen_t len; + + len = sizeof(client_address); + + fd = sAccept(listen_fd, (struct sockaddr *)&client_address, &len); + if (fd == -1) { + ShowError("connect_client: accept failed (%s)!\n", error_msg()); + return -1; + } + if (fd == 0) { + // reserved + ShowError("connect_client: Socket #0 is reserved - Please report this!!!\n"); + sClose(fd); + return -1; + } + if (fd >= FD_SETSIZE) { + // socket number too big + ShowError("connect_client: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); + sClose(fd); + return -1; + } + + setsocketopts(fd); + set_nonblocking(fd, 1); #ifndef MINICORE - if( ip_rules && !connect_check(ntohl(client_address.sin_addr.s_addr)) ) { - do_close(fd); - return -1; - } + if (ip_rules && !connect_check(ntohl(client_address.sin_addr.s_addr))) { + do_close(fd); + return -1; + } #endif - if( fd_max <= fd ) fd_max = fd + 1; - sFD_SET(fd,&readfds); + if (fd_max <= fd) fd_max = fd + 1; + sFD_SET(fd,&readfds); - create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse); - session[fd]->client_addr = ntohl(client_address.sin_addr.s_addr); + create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse); + session[fd]->client_addr = ntohl(client_address.sin_addr.s_addr); - return fd; + return fd; } int make_listen_bind(uint32 ip, uint16 port) { - struct sockaddr_in server_address; - int fd; - int result; - - fd = sSocket(AF_INET, SOCK_STREAM, 0); - - if( fd == -1 ) - { - ShowError("make_listen_bind: socket creation failed (%s)!\n", error_msg()); - exit(EXIT_FAILURE); - } - if( fd == 0 ) - {// reserved - ShowError("make_listen_bind: Socket #0 is reserved - Please report this!!!\n"); - sClose(fd); - return -1; - } - if( fd >= FD_SETSIZE ) - {// socket number too big - ShowError("make_listen_bind: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); - sClose(fd); - return -1; - } - - setsocketopts(fd); - set_nonblocking(fd, 1); - - server_address.sin_family = AF_INET; - server_address.sin_addr.s_addr = htonl(ip); - server_address.sin_port = htons(port); - - result = sBind(fd, (struct sockaddr*)&server_address, sizeof(server_address)); - if( result == SOCKET_ERROR ) { - ShowError("make_listen_bind: bind failed (socket #%d, %s)!\n", fd, error_msg()); - exit(EXIT_FAILURE); - } - result = sListen(fd,5); - if( result == SOCKET_ERROR ) { - ShowError("make_listen_bind: listen failed (socket #%d, %s)!\n", fd, error_msg()); - exit(EXIT_FAILURE); - } - - if(fd_max <= fd) fd_max = fd + 1; - sFD_SET(fd, &readfds); - - create_session(fd, connect_client, null_send, null_parse); - session[fd]->client_addr = 0; // just listens - session[fd]->rdata_tick = 0; // disable timeouts on this socket - - return fd; + struct sockaddr_in server_address; + int fd; + int result; + + fd = sSocket(AF_INET, SOCK_STREAM, 0); + + if (fd == -1) { + ShowError("make_listen_bind: socket creation failed (%s)!\n", error_msg()); + exit(EXIT_FAILURE); + } + if (fd == 0) { + // reserved + ShowError("make_listen_bind: Socket #0 is reserved - Please report this!!!\n"); + sClose(fd); + return -1; + } + if (fd >= FD_SETSIZE) { + // socket number too big + ShowError("make_listen_bind: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); + sClose(fd); + return -1; + } + + setsocketopts(fd); + set_nonblocking(fd, 1); + + server_address.sin_family = AF_INET; + server_address.sin_addr.s_addr = htonl(ip); + server_address.sin_port = htons(port); + + result = sBind(fd, (struct sockaddr *)&server_address, sizeof(server_address)); + if (result == SOCKET_ERROR) { + ShowError("make_listen_bind: bind failed (socket #%d, %s)!\n", fd, error_msg()); + exit(EXIT_FAILURE); + } + result = sListen(fd,5); + if (result == SOCKET_ERROR) { + ShowError("make_listen_bind: listen failed (socket #%d, %s)!\n", fd, error_msg()); + exit(EXIT_FAILURE); + } + + if (fd_max <= fd) fd_max = fd + 1; + sFD_SET(fd, &readfds); + + create_session(fd, connect_client, null_send, null_parse); + session[fd]->client_addr = 0; // just listens + session[fd]->rdata_tick = 0; // disable timeouts on this socket + + return fd; } -int make_connection(uint32 ip, uint16 port, bool silent) { - struct sockaddr_in remote_address; - int fd; - int result; - - fd = sSocket(AF_INET, SOCK_STREAM, 0); - - if (fd == -1) { - ShowError("make_connection: socket creation failed (%s)!\n", error_msg()); - return -1; - } - if( fd == 0 ) - {// reserved - ShowError("make_connection: Socket #0 is reserved - Please report this!!!\n"); - sClose(fd); - return -1; - } - if( fd >= FD_SETSIZE ) - {// socket number too big - ShowError("make_connection: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); - sClose(fd); - return -1; - } - - setsocketopts(fd); - - remote_address.sin_family = AF_INET; - remote_address.sin_addr.s_addr = htonl(ip); - remote_address.sin_port = htons(port); - - if( !silent ) - ShowStatus("Connecting to %d.%d.%d.%d:%i\n", CONVIP(ip), port); - - result = sConnect(fd, (struct sockaddr *)(&remote_address), sizeof(struct sockaddr_in)); - if( result == SOCKET_ERROR ) { - if( !silent ) - ShowError("make_connection: connect failed (socket #%d, %s)!\n", fd, error_msg()); - do_close(fd); - return -1; - } - //Now the socket can be made non-blocking. [Skotlex] - set_nonblocking(fd, 1); - - if (fd_max <= fd) fd_max = fd + 1; - sFD_SET(fd,&readfds); - - create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse); - session[fd]->client_addr = ntohl(remote_address.sin_addr.s_addr); - - return fd; +int make_connection(uint32 ip, uint16 port, bool silent) +{ + struct sockaddr_in remote_address; + int fd; + int result; + + fd = sSocket(AF_INET, SOCK_STREAM, 0); + + if (fd == -1) { + ShowError("make_connection: socket creation failed (%s)!\n", error_msg()); + return -1; + } + if (fd == 0) { + // reserved + ShowError("make_connection: Socket #0 is reserved - Please report this!!!\n"); + sClose(fd); + return -1; + } + if (fd >= FD_SETSIZE) { + // socket number too big + ShowError("make_connection: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); + sClose(fd); + return -1; + } + + setsocketopts(fd); + + remote_address.sin_family = AF_INET; + remote_address.sin_addr.s_addr = htonl(ip); + remote_address.sin_port = htons(port); + + if (!silent) + ShowStatus("Connecting to %d.%d.%d.%d:%i\n", CONVIP(ip), port); + + result = sConnect(fd, (struct sockaddr *)(&remote_address), sizeof(struct sockaddr_in)); + if (result == SOCKET_ERROR) { + if (!silent) + ShowError("make_connection: connect failed (socket #%d, %s)!\n", fd, error_msg()); + do_close(fd); + return -1; + } + //Now the socket can be made non-blocking. [Skotlex] + set_nonblocking(fd, 1); + + if (fd_max <= fd) fd_max = fd + 1; + sFD_SET(fd,&readfds); + + create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse); + session[fd]->client_addr = ntohl(remote_address.sin_addr.s_addr); + + return fd; } static int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseFunc func_parse) { - CREATE(session[fd], struct socket_data, 1); - CREATE(session[fd]->rdata, unsigned char, RFIFO_SIZE); - CREATE(session[fd]->wdata, unsigned char, WFIFO_SIZE); - session[fd]->max_rdata = RFIFO_SIZE; - session[fd]->max_wdata = WFIFO_SIZE; - session[fd]->func_recv = func_recv; - session[fd]->func_send = func_send; - session[fd]->func_parse = func_parse; - session[fd]->rdata_tick = last_tick; - return 0; + CREATE(session[fd], struct socket_data, 1); + CREATE(session[fd]->rdata, unsigned char, RFIFO_SIZE); + CREATE(session[fd]->wdata, unsigned char, WFIFO_SIZE); + session[fd]->max_rdata = RFIFO_SIZE; + session[fd]->max_wdata = WFIFO_SIZE; + session[fd]->func_recv = func_recv; + session[fd]->func_send = func_send; + session[fd]->func_parse = func_parse; + session[fd]->rdata_tick = last_tick; + return 0; } static void delete_session(int fd) { - if( session_isValid(fd) ) - { - aFree(session[fd]->rdata); - aFree(session[fd]->wdata); - aFree(session[fd]->session_data); - aFree(session[fd]); - session[fd] = NULL; - } + if (session_isValid(fd)) { + aFree(session[fd]->rdata); + aFree(session[fd]->wdata); + aFree(session[fd]->session_data); + aFree(session[fd]); + session[fd] = NULL; + } } int realloc_fifo(int fd, unsigned int rfifo_size, unsigned int wfifo_size) { - if( !session_isValid(fd) ) - return 0; - - if( session[fd]->max_rdata != rfifo_size && session[fd]->rdata_size < rfifo_size) { - RECREATE(session[fd]->rdata, unsigned char, rfifo_size); - session[fd]->max_rdata = rfifo_size; - } - - if( session[fd]->max_wdata != wfifo_size && session[fd]->wdata_size < wfifo_size) { - RECREATE(session[fd]->wdata, unsigned char, wfifo_size); - session[fd]->max_wdata = wfifo_size; - } - return 0; + if (!session_isValid(fd)) + return 0; + + if (session[fd]->max_rdata != rfifo_size && session[fd]->rdata_size < rfifo_size) { + RECREATE(session[fd]->rdata, unsigned char, rfifo_size); + session[fd]->max_rdata = rfifo_size; + } + + if (session[fd]->max_wdata != wfifo_size && session[fd]->wdata_size < wfifo_size) { + RECREATE(session[fd]->wdata, unsigned char, wfifo_size); + session[fd]->max_wdata = wfifo_size; + } + return 0; } int realloc_writefifo(int fd, size_t addition) { - size_t newsize; - - if( !session_isValid(fd) ) // might not happen - return 0; - - if( session[fd]->wdata_size + addition > session[fd]->max_wdata ) - { // grow rule; grow in multiples of WFIFO_SIZE - newsize = WFIFO_SIZE; - while( session[fd]->wdata_size + addition > newsize ) newsize += WFIFO_SIZE; - } - else - if( session[fd]->max_wdata >= (size_t)2*(session[fd]->flag.server?FIFOSIZE_SERVERLINK:WFIFO_SIZE) - && (session[fd]->wdata_size+addition)*4 < session[fd]->max_wdata ) - { // shrink rule, shrink by 2 when only a quarter of the fifo is used, don't shrink below nominal size. - newsize = session[fd]->max_wdata / 2; - } - else // no change - return 0; - - RECREATE(session[fd]->wdata, unsigned char, newsize); - session[fd]->max_wdata = newsize; - - return 0; + size_t newsize; + + if (!session_isValid(fd)) // might not happen + return 0; + + if (session[fd]->wdata_size + addition > session[fd]->max_wdata) { + // grow rule; grow in multiples of WFIFO_SIZE + newsize = WFIFO_SIZE; + while (session[fd]->wdata_size + addition > newsize) newsize += WFIFO_SIZE; + } else if (session[fd]->max_wdata >= (size_t)2*(session[fd]->flag.server?FIFOSIZE_SERVERLINK:WFIFO_SIZE) + && (session[fd]->wdata_size+addition)*4 < session[fd]->max_wdata) { + // shrink rule, shrink by 2 when only a quarter of the fifo is used, don't shrink below nominal size. + newsize = session[fd]->max_wdata / 2; + } else // no change + return 0; + + RECREATE(session[fd]->wdata, unsigned char, newsize); + session[fd]->max_wdata = newsize; + + return 0; } /// advance the RFIFO cursor (marking 'len' bytes as processed) @@ -629,197 +632,186 @@ int RFIFOSKIP(int fd, size_t len) { struct socket_data *s; - if ( !session_isActive(fd) ) - return 0; + if (!session_isActive(fd)) + return 0; - s = session[fd]; + s = session[fd]; - if ( s->rdata_size < s->rdata_pos + len ) { - ShowError("RFIFOSKIP: skipped past end of read buffer! Adjusting from %d to %d (session #%d)\n", len, RFIFOREST(fd), fd); - len = RFIFOREST(fd); - } + if (s->rdata_size < s->rdata_pos + len) { + ShowError("RFIFOSKIP: skipped past end of read buffer! Adjusting from %d to %d (session #%d)\n", len, RFIFOREST(fd), fd); + len = RFIFOREST(fd); + } - s->rdata_pos = s->rdata_pos + len; - return 0; + s->rdata_pos = s->rdata_pos + len; + return 0; } /// advance the WFIFO cursor (marking 'len' bytes for sending) int WFIFOSET(int fd, size_t len) { - size_t newreserve; - struct socket_data* s = session[fd]; - - if( !session_isValid(fd) || s->wdata == NULL ) - return 0; - - // we have written len bytes to the buffer already before calling WFIFOSET - if(s->wdata_size+len > s->max_wdata) - { // actually there was a buffer overflow already - uint32 ip = s->client_addr; - ShowFatalError("WFIFOSET: Write Buffer Overflow. Connection %d (%d.%d.%d.%d) has written %u bytes on a %u/%u bytes buffer.\n", fd, CONVIP(ip), (unsigned int)len, (unsigned int)s->wdata_size, (unsigned int)s->max_wdata); - ShowDebug("Likely command that caused it: 0x%x\n", (*(uint16*)(s->wdata + s->wdata_size))); - // no other chance, make a better fifo model - exit(EXIT_FAILURE); - } - - if( len > 0xFFFF ) - { - // dynamic packets allow up to UINT16_MAX bytes (.W .W ...) - // all known fixed-size packets are within this limit, so use the same limit - ShowFatalError("WFIFOSET: Packet 0x%x is too big. (len=%u, max=%u)\n", (*(uint16*)(s->wdata + s->wdata_size)), (unsigned int)len, 0xFFFF); - exit(EXIT_FAILURE); - } - else if( len == 0 ) - { - // abuses the fact, that the code that did WFIFOHEAD(fd,0), already wrote - // the packet type into memory, even if it could have overwritten vital data - // this can happen when a new packet was added on map-server, but packet len table was not updated - ShowWarning("WFIFOSET: Attempted to send zero-length packet, most likely 0x%04x (please report this).\n", WFIFOW(fd,0)); - return 0; - } - - if( !s->flag.server ) { - - if( len > socket_max_client_packet ) {// see declaration of socket_max_client_packet for details - ShowError("WFIFOSET: Dropped too large client packet 0x%04x (length=%u, max=%u).\n", WFIFOW(fd,0), len, socket_max_client_packet); - return 0; - } - - if( s->wdata_size+len > WFIFO_MAX ) {// reached maximum write fifo size - ShowError("WFIFOSET: Maximum write buffer size for client connection %d exceeded, most likely caused by packet 0x%04x (len=%u, ip=%lu.%lu.%lu.%lu).\n", fd, WFIFOW(fd,0), len, CONVIP(s->client_addr)); - set_eof(fd); - return 0; - } - - } - s->wdata_size += len; - //If the interserver has 200% of its normal size full, flush the data. - if( s->flag.server && s->wdata_size >= 2*FIFOSIZE_SERVERLINK ) - flush_fifo(fd); - - // always keep a WFIFO_SIZE reserve in the buffer - // For inter-server connections, let the reserve be 1/4th of the link size. - newreserve = s->flag.server ? FIFOSIZE_SERVERLINK / 4 : WFIFO_SIZE; - - // readjust the buffer to include the chosen reserve - realloc_writefifo(fd, newreserve); + size_t newreserve; + struct socket_data *s = session[fd]; + + if (!session_isValid(fd) || s->wdata == NULL) + return 0; + + // we have written len bytes to the buffer already before calling WFIFOSET + if (s->wdata_size+len > s->max_wdata) { + // actually there was a buffer overflow already + uint32 ip = s->client_addr; + ShowFatalError("WFIFOSET: Write Buffer Overflow. Connection %d (%d.%d.%d.%d) has written %u bytes on a %u/%u bytes buffer.\n", fd, CONVIP(ip), (unsigned int)len, (unsigned int)s->wdata_size, (unsigned int)s->max_wdata); + ShowDebug("Likely command that caused it: 0x%x\n", (*(uint16 *)(s->wdata + s->wdata_size))); + // no other chance, make a better fifo model + exit(EXIT_FAILURE); + } + + if (len > 0xFFFF) { + // dynamic packets allow up to UINT16_MAX bytes (.W .W ...) + // all known fixed-size packets are within this limit, so use the same limit + ShowFatalError("WFIFOSET: Packet 0x%x is too big. (len=%u, max=%u)\n", (*(uint16 *)(s->wdata + s->wdata_size)), (unsigned int)len, 0xFFFF); + exit(EXIT_FAILURE); + } else if (len == 0) { + // abuses the fact, that the code that did WFIFOHEAD(fd,0), already wrote + // the packet type into memory, even if it could have overwritten vital data + // this can happen when a new packet was added on map-server, but packet len table was not updated + ShowWarning("WFIFOSET: Attempted to send zero-length packet, most likely 0x%04x (please report this).\n", WFIFOW(fd,0)); + return 0; + } + + if (!s->flag.server) { + + if (len > socket_max_client_packet) { // see declaration of socket_max_client_packet for details + ShowError("WFIFOSET: Dropped too large client packet 0x%04x (length=%u, max=%u).\n", WFIFOW(fd,0), len, socket_max_client_packet); + return 0; + } + + if (s->wdata_size+len > WFIFO_MAX) { // reached maximum write fifo size + ShowError("WFIFOSET: Maximum write buffer size for client connection %d exceeded, most likely caused by packet 0x%04x (len=%u, ip=%lu.%lu.%lu.%lu).\n", fd, WFIFOW(fd,0), len, CONVIP(s->client_addr)); + set_eof(fd); + return 0; + } + + } + s->wdata_size += len; + //If the interserver has 200% of its normal size full, flush the data. + if (s->flag.server && s->wdata_size >= 2*FIFOSIZE_SERVERLINK) + flush_fifo(fd); + + // always keep a WFIFO_SIZE reserve in the buffer + // For inter-server connections, let the reserve be 1/4th of the link size. + newreserve = s->flag.server ? FIFOSIZE_SERVERLINK / 4 : WFIFO_SIZE; + + // readjust the buffer to include the chosen reserve + realloc_writefifo(fd, newreserve); #ifdef SEND_SHORTLIST - send_shortlist_add_fd(fd); + send_shortlist_add_fd(fd); #endif - return 0; + return 0; } int do_sockets(int next) { - fd_set rfd; - struct timeval timeout; - int ret,i; + fd_set rfd; + struct timeval timeout; + int ret,i; - // PRESEND Timers are executed before do_sendrecv and can send packets and/or set sessions to eof. - // Send remaining data and process client-side disconnects here. + // PRESEND Timers are executed before do_sendrecv and can send packets and/or set sessions to eof. + // Send remaining data and process client-side disconnects here. #ifdef SEND_SHORTLIST - send_shortlist_do_sends(); + send_shortlist_do_sends(); #else - for (i = 1; i < fd_max; i++) - { - if(!session[i]) - continue; - - if(session[i]->wdata_size) - session[i]->func_send(i); - } + for (i = 1; i < fd_max; i++) { + if (!session[i]) + continue; + + if (session[i]->wdata_size) + session[i]->func_send(i); + } #endif - // can timeout until the next tick - timeout.tv_sec = next/1000; - timeout.tv_usec = next%1000*1000; + // can timeout until the next tick + timeout.tv_sec = next/1000; + timeout.tv_usec = next%1000*1000; - memcpy(&rfd, &readfds, sizeof(rfd)); - ret = sSelect(fd_max, &rfd, NULL, NULL, &timeout); + memcpy(&rfd, &readfds, sizeof(rfd)); + ret = sSelect(fd_max, &rfd, NULL, NULL, &timeout); - if( ret == SOCKET_ERROR ) - { - if( sErrno != S_EINTR ) - { - ShowFatalError("do_sockets: select() failed, %s!\n", error_msg()); - exit(EXIT_FAILURE); - } - return 0; // interrupted by a signal, just loop and try again - } + if (ret == SOCKET_ERROR) { + if (sErrno != S_EINTR) { + ShowFatalError("do_sockets: select() failed, %s!\n", error_msg()); + exit(EXIT_FAILURE); + } + return 0; // interrupted by a signal, just loop and try again + } - last_tick = time(NULL); + last_tick = time(NULL); #if defined(WIN32) - // on windows, enumerating all members of the fd_set is way faster if we access the internals - for( i = 0; i < (int)rfd.fd_count; ++i ) - { - int fd = sock2fd(rfd.fd_array[i]); - if( session[fd] ) - session[fd]->func_recv(fd); - } + // on windows, enumerating all members of the fd_set is way faster if we access the internals + for (i = 0; i < (int)rfd.fd_count; ++i) { + int fd = sock2fd(rfd.fd_array[i]); + if (session[fd]) + session[fd]->func_recv(fd); + } #else - // otherwise assume that the fd_set is a bit-array and enumerate it in a standard way - for( i = 1; ret && i < fd_max; ++i ) - { - if(sFD_ISSET(i,&rfd) && session[i]) - { - session[i]->func_recv(i); - --ret; - } - } + // otherwise assume that the fd_set is a bit-array and enumerate it in a standard way + for (i = 1; ret && i < fd_max; ++i) { + if (sFD_ISSET(i,&rfd) && session[i]) { + session[i]->func_recv(i); + --ret; + } + } #endif - // POSTSEND Send remaining data and handle eof sessions. + // POSTSEND Send remaining data and handle eof sessions. #ifdef SEND_SHORTLIST - send_shortlist_do_sends(); + send_shortlist_do_sends(); #else - for (i = 1; i < fd_max; i++) - { - if(!session[i]) - continue; - - if(session[i]->wdata_size) - session[i]->func_send(i); - - if(session[i]->flag.eof) //func_send can't free a session, this is safe. - { //Finally, even if there is no data to parse, connections signalled eof should be closed, so we call parse_func [Skotlex] - session[i]->func_parse(i); //This should close the session immediately. - } - } + for (i = 1; i < fd_max; i++) { + if (!session[i]) + continue; + + if (session[i]->wdata_size) + session[i]->func_send(i); + + if (session[i]->flag.eof) { //func_send can't free a session, this is safe. + //Finally, even if there is no data to parse, connections signalled eof should be closed, so we call parse_func [Skotlex] + session[i]->func_parse(i); //This should close the session immediately. + } + } #endif - // parse input data on each socket - for(i = 1; i < fd_max; i++) - { - if(!session[i]) - continue; - - if (session[i]->rdata_tick && DIFF_TICK(last_tick, session[i]->rdata_tick) > stall_time) { - if( session[i]->flag.server ) {/* server is special */ - if( session[i]->flag.ping != 2 )/* only update if necessary otherwise it'd resend the ping unnecessarily */ - session[i]->flag.ping = 1; - } else { - ShowInfo("Session #%d timed out\n", i); - set_eof(i); - } - } - - session[i]->func_parse(i); - - if(!session[i]) - continue; - - // after parse, check client's RFIFO size to know if there is an invalid packet (too big and not parsed) - if (session[i]->rdata_size == RFIFO_SIZE && session[i]->max_rdata == RFIFO_SIZE) { - set_eof(i); - continue; - } - RFIFOFLUSH(i); - } - - return 0; + // parse input data on each socket + for (i = 1; i < fd_max; i++) { + if (!session[i]) + continue; + + if (session[i]->rdata_tick && DIFF_TICK(last_tick, session[i]->rdata_tick) > stall_time) { + if (session[i]->flag.server) { /* server is special */ + if (session[i]->flag.ping != 2) /* only update if necessary otherwise it'd resend the ping unnecessarily */ + session[i]->flag.ping = 1; + } else { + ShowInfo("Session #%d timed out\n", i); + set_eof(i); + } + } + + session[i]->func_parse(i); + + if (!session[i]) + continue; + + // after parse, check client's RFIFO size to know if there is an invalid packet (too big and not parsed) + if (session[i]->rdata_size == RFIFO_SIZE && session[i]->max_rdata == RFIFO_SIZE) { + set_eof(i); + continue; + } + RFIFOFLUSH(i); + } + + return 0; } ////////////////////////////// @@ -828,26 +820,26 @@ int do_sockets(int next) // IP rules and DDoS protection typedef struct _connect_history { - struct _connect_history* next; - uint32 ip; - uint32 tick; - int count; - unsigned ddos : 1; + struct _connect_history *next; + uint32 ip; + uint32 tick; + int count; + unsigned ddos : 1; } ConnectHistory; typedef struct _access_control { - uint32 ip; - uint32 mask; + uint32 ip; + uint32 mask; } AccessControl; enum _aco { - ACO_DENY_ALLOW, - ACO_ALLOW_DENY, - ACO_MUTUAL_FAILURE + ACO_DENY_ALLOW, + ACO_ALLOW_DENY, + ACO_MUTUAL_FAILURE }; -static AccessControl* access_allow = NULL; -static AccessControl* access_deny = NULL; +static AccessControl *access_allow = NULL; +static AccessControl *access_deny = NULL; static int access_order = ACO_DENY_ALLOW; static int access_allownum = 0; static int access_denynum = 0; @@ -857,7 +849,7 @@ static int ddos_interval = 3*1000; static int ddos_autoreset = 10*60*1000; /// Connection history, an array of linked lists. /// The array's index for any ip is ip&0xFFFF -static ConnectHistory* connect_history[0x10000]; +static ConnectHistory *connect_history[0x10000]; static int connect_check_(uint32 ip); @@ -865,11 +857,11 @@ static int connect_check_(uint32 ip); /// @see connect_check_() static int connect_check(uint32 ip) { - int result = connect_check_(ip); - if( access_debug ) { - ShowInfo("connect_check: Connection from %d.%d.%d.%d %s\n", CONVIP(ip),result ? "allowed." : "denied!"); - } - return result; + int result = connect_check_(ip); + if (access_debug) { + ShowInfo("connect_check: Connection from %d.%d.%d.%d %s\n", CONVIP(ip),result ? "allowed." : "denied!"); + } + return result; } /// Verifies if the IP can connect. @@ -877,504 +869,494 @@ static int connect_check(uint32 ip) /// 1 or 2 : Connection Accepted static int connect_check_(uint32 ip) { - ConnectHistory* hist = connect_history[ip&0xFFFF]; - int i; - int is_allowip = 0; - int is_denyip = 0; - int connect_ok = 0; - - // Search the allow list - for( i=0; i < access_allownum; ++i ){ - if( (ip & access_allow[i].mask) == (access_allow[i].ip & access_allow[i].mask) ){ - if( access_debug ){ - ShowInfo("connect_check: Found match from allow list:%d.%d.%d.%d IP:%d.%d.%d.%d Mask:%d.%d.%d.%d\n", - CONVIP(ip), - CONVIP(access_allow[i].ip), - CONVIP(access_allow[i].mask)); - } - is_allowip = 1; - break; - } - } - // Search the deny list - for( i=0; i < access_denynum; ++i ){ - if( (ip & access_deny[i].mask) == (access_deny[i].ip & access_deny[i].mask) ){ - if( access_debug ){ - ShowInfo("connect_check: Found match from deny list:%d.%d.%d.%d IP:%d.%d.%d.%d Mask:%d.%d.%d.%d\n", - CONVIP(ip), - CONVIP(access_deny[i].ip), - CONVIP(access_deny[i].mask)); - } - is_denyip = 1; - break; - } - } - // Decide connection status - // 0 : Reject - // 1 : Accept - // 2 : Unconditional Accept (accepts even if flagged as DDoS) - switch(access_order) { - case ACO_DENY_ALLOW: - default: - if( is_denyip ) - connect_ok = 0; // Reject - else if( is_allowip ) - connect_ok = 2; // Unconditional Accept - else - connect_ok = 1; // Accept - break; - case ACO_ALLOW_DENY: - if( is_allowip ) - connect_ok = 2; // Unconditional Accept - else if( is_denyip ) - connect_ok = 0; // Reject - else - connect_ok = 1; // Accept - break; - case ACO_MUTUAL_FAILURE: - if( is_allowip && !is_denyip ) - connect_ok = 2; // Unconditional Accept - else - connect_ok = 0; // Reject - break; - } - - // Inspect connection history - while( hist ) { - if( ip == hist->ip ) - {// IP found - if( hist->ddos ) - {// flagged as DDoS - return (connect_ok == 2 ? 1 : 0); - } else if( DIFF_TICK(gettick(),hist->tick) < ddos_interval ) - {// connection within ddos_interval - hist->tick = gettick(); - if( hist->count++ >= ddos_count ) - {// DDoS attack detected - hist->ddos = 1; - ShowWarning("connect_check: DDoS Attack detected from %d.%d.%d.%d!\n", CONVIP(ip)); - return (connect_ok == 2 ? 1 : 0); - } - return connect_ok; - } else - {// not within ddos_interval, clear data - hist->tick = gettick(); - hist->count = 0; - return connect_ok; - } - } - hist = hist->next; - } - // IP not found, add to history - CREATE(hist, ConnectHistory, 1); - memset(hist, 0, sizeof(ConnectHistory)); - hist->ip = ip; - hist->tick = gettick(); - hist->next = connect_history[ip&0xFFFF]; - connect_history[ip&0xFFFF] = hist; - return connect_ok; + ConnectHistory *hist = connect_history[ip&0xFFFF]; + int i; + int is_allowip = 0; + int is_denyip = 0; + int connect_ok = 0; + + // Search the allow list + for (i=0; i < access_allownum; ++i) { + if ((ip & access_allow[i].mask) == (access_allow[i].ip & access_allow[i].mask)) { + if (access_debug) { + ShowInfo("connect_check: Found match from allow list:%d.%d.%d.%d IP:%d.%d.%d.%d Mask:%d.%d.%d.%d\n", + CONVIP(ip), + CONVIP(access_allow[i].ip), + CONVIP(access_allow[i].mask)); + } + is_allowip = 1; + break; + } + } + // Search the deny list + for (i=0; i < access_denynum; ++i) { + if ((ip & access_deny[i].mask) == (access_deny[i].ip & access_deny[i].mask)) { + if (access_debug) { + ShowInfo("connect_check: Found match from deny list:%d.%d.%d.%d IP:%d.%d.%d.%d Mask:%d.%d.%d.%d\n", + CONVIP(ip), + CONVIP(access_deny[i].ip), + CONVIP(access_deny[i].mask)); + } + is_denyip = 1; + break; + } + } + // Decide connection status + // 0 : Reject + // 1 : Accept + // 2 : Unconditional Accept (accepts even if flagged as DDoS) + switch (access_order) { + case ACO_DENY_ALLOW: + default: + if (is_denyip) + connect_ok = 0; // Reject + else if (is_allowip) + connect_ok = 2; // Unconditional Accept + else + connect_ok = 1; // Accept + break; + case ACO_ALLOW_DENY: + if (is_allowip) + connect_ok = 2; // Unconditional Accept + else if (is_denyip) + connect_ok = 0; // Reject + else + connect_ok = 1; // Accept + break; + case ACO_MUTUAL_FAILURE: + if (is_allowip && !is_denyip) + connect_ok = 2; // Unconditional Accept + else + connect_ok = 0; // Reject + break; + } + + // Inspect connection history + while (hist) { + if (ip == hist->ip) { + // IP found + if (hist->ddos) { + // flagged as DDoS + return (connect_ok == 2 ? 1 : 0); + } else if (DIFF_TICK(gettick(),hist->tick) < ddos_interval) { + // connection within ddos_interval + hist->tick = gettick(); + if (hist->count++ >= ddos_count) { + // DDoS attack detected + hist->ddos = 1; + ShowWarning("connect_check: DDoS Attack detected from %d.%d.%d.%d!\n", CONVIP(ip)); + return (connect_ok == 2 ? 1 : 0); + } + return connect_ok; + } else { + // not within ddos_interval, clear data + hist->tick = gettick(); + hist->count = 0; + return connect_ok; + } + } + hist = hist->next; + } + // IP not found, add to history + CREATE(hist, ConnectHistory, 1); + memset(hist, 0, sizeof(ConnectHistory)); + hist->ip = ip; + hist->tick = gettick(); + hist->next = connect_history[ip&0xFFFF]; + connect_history[ip&0xFFFF] = hist; + return connect_ok; } /// Timer function. /// Deletes old connection history records. static int connect_check_clear(int tid, unsigned int tick, int id, intptr_t data) { - int i; - int clear = 0; - int list = 0; - ConnectHistory root; - ConnectHistory* prev_hist; - ConnectHistory* hist; - - for( i=0; i < 0x10000 ; ++i ){ - prev_hist = &root; - root.next = hist = connect_history[i]; - while( hist ){ - if( (!hist->ddos && DIFF_TICK(tick,hist->tick) > ddos_interval*3) || - (hist->ddos && DIFF_TICK(tick,hist->tick) > ddos_autoreset) ) - {// Remove connection history - prev_hist->next = hist->next; - aFree(hist); - hist = prev_hist->next; - clear++; - } else { - prev_hist = hist; - hist = hist->next; - } - list++; - } - connect_history[i] = root.next; - } - if( access_debug ){ - ShowInfo("connect_check_clear: Cleared %d of %d from IP list.\n", clear, list); - } - return list; + int i; + int clear = 0; + int list = 0; + ConnectHistory root; + ConnectHistory *prev_hist; + ConnectHistory *hist; + + for (i=0; i < 0x10000 ; ++i) { + prev_hist = &root; + root.next = hist = connect_history[i]; + while (hist) { + if ((!hist->ddos && DIFF_TICK(tick,hist->tick) > ddos_interval*3) || + (hist->ddos && DIFF_TICK(tick,hist->tick) > ddos_autoreset)) { + // Remove connection history + prev_hist->next = hist->next; + aFree(hist); + hist = prev_hist->next; + clear++; + } else { + prev_hist = hist; + hist = hist->next; + } + list++; + } + connect_history[i] = root.next; + } + if (access_debug) { + ShowInfo("connect_check_clear: Cleared %d of %d from IP list.\n", clear, list); + } + return list; } /// Parses the ip address and mask and puts it into acc. /// Returns 1 is successful, 0 otherwise. -int access_ipmask(const char* str, AccessControl* acc) +int access_ipmask(const char *str, AccessControl *acc) { - uint32 ip; - uint32 mask; - unsigned int a[4]; - unsigned int m[4]; - int n; - - if( strcmp(str,"all") == 0 ) { - ip = 0; - mask = 0; - } else { - if( ((n=sscanf(str,"%u.%u.%u.%u/%u.%u.%u.%u",a,a+1,a+2,a+3,m,m+1,m+2,m+3)) != 8 && // not an ip + standard mask - (n=sscanf(str,"%u.%u.%u.%u/%u",a,a+1,a+2,a+3,m)) != 5 && // not an ip + bit mask - (n=sscanf(str,"%u.%u.%u.%u",a,a+1,a+2,a+3)) != 4 ) || // not an ip - a[0] > 255 || a[1] > 255 || a[2] > 255 || a[3] > 255 || // invalid ip - (n == 8 && (m[0] > 255 || m[1] > 255 || m[2] > 255 || m[3] > 255)) || // invalid standard mask - (n == 5 && m[0] > 32) ){ // invalid bit mask - return 0; - } - ip = MAKEIP(a[0],a[1],a[2],a[3]); - if( n == 8 ) - {// standard mask - mask = MAKEIP(m[0],m[1],m[2],m[3]); - } else if( n == 5 ) - {// bit mask - mask = 0; - while( m[0] ){ - mask = (mask >> 1) | 0x80000000; - --m[0]; - } - } else - {// just this ip - mask = 0xFFFFFFFF; - } - } - if( access_debug ){ - ShowInfo("access_ipmask: Loaded IP:%d.%d.%d.%d mask:%d.%d.%d.%d\n", CONVIP(ip), CONVIP(mask)); - } - acc->ip = ip; - acc->mask = mask; - return 1; + uint32 ip; + uint32 mask; + unsigned int a[4]; + unsigned int m[4]; + int n; + + if (strcmp(str,"all") == 0) { + ip = 0; + mask = 0; + } else { + if (((n=sscanf(str,"%u.%u.%u.%u/%u.%u.%u.%u",a,a+1,a+2,a+3,m,m+1,m+2,m+3)) != 8 && // not an ip + standard mask + (n=sscanf(str,"%u.%u.%u.%u/%u",a,a+1,a+2,a+3,m)) != 5 && // not an ip + bit mask + (n=sscanf(str,"%u.%u.%u.%u",a,a+1,a+2,a+3)) != 4) || // not an ip + a[0] > 255 || a[1] > 255 || a[2] > 255 || a[3] > 255 || // invalid ip + (n == 8 && (m[0] > 255 || m[1] > 255 || m[2] > 255 || m[3] > 255)) || // invalid standard mask + (n == 5 && m[0] > 32)) { // invalid bit mask + return 0; + } + ip = MAKEIP(a[0],a[1],a[2],a[3]); + if (n == 8) { + // standard mask + mask = MAKEIP(m[0],m[1],m[2],m[3]); + } else if (n == 5) { + // bit mask + mask = 0; + while (m[0]) { + mask = (mask >> 1) | 0x80000000; + --m[0]; + } + } else { + // just this ip + mask = 0xFFFFFFFF; + } + } + if (access_debug) { + ShowInfo("access_ipmask: Loaded IP:%d.%d.%d.%d mask:%d.%d.%d.%d\n", CONVIP(ip), CONVIP(mask)); + } + acc->ip = ip; + acc->mask = mask; + return 1; } ////////////////////////////// #endif ////////////////////////////// -int socket_config_read(const char* cfgName) +int socket_config_read(const char *cfgName) { - char line[1024],w1[1024],w2[1024]; - FILE *fp; - - fp = fopen(cfgName, "r"); - if(fp == NULL) { - ShowError("File not found: %s\n", cfgName); - return 1; - } - - while(fgets(line, sizeof(line), fp)) - { - if(line[0] == '/' && line[1] == '/') - continue; - if(sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - if (!strcmpi(w1, "stall_time")) { - stall_time = atoi(w2); - if( stall_time < 3 ) - stall_time = 3;/* a minimum is required to refrain it from killing itself */ - } + char line[1024],w1[1024],w2[1024]; + FILE *fp; + + fp = fopen(cfgName, "r"); + if (fp == NULL) { + ShowError("File not found: %s\n", cfgName); + return 1; + } + + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') + continue; + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + if (!strcmpi(w1, "stall_time")) { + stall_time = atoi(w2); + if (stall_time < 3) + stall_time = 3;/* a minimum is required to refrain it from killing itself */ + } #ifndef MINICORE - else if (!strcmpi(w1, "enable_ip_rules")) { - ip_rules = config_switch(w2); - } else if (!strcmpi(w1, "order")) { - if (!strcmpi(w2, "deny,allow")) - access_order = ACO_DENY_ALLOW; - else if (!strcmpi(w2, "allow,deny")) - access_order = ACO_ALLOW_DENY; - else if (!strcmpi(w2, "mutual-failure")) - access_order = ACO_MUTUAL_FAILURE; - } else if (!strcmpi(w1, "allow")) { - RECREATE(access_allow, AccessControl, access_allownum+1); - if (access_ipmask(w2, &access_allow[access_allownum])) - ++access_allownum; - else - ShowError("socket_config_read: Invalid ip or ip range '%s'!\n", line); - } else if (!strcmpi(w1, "deny")) { - RECREATE(access_deny, AccessControl, access_denynum+1); - if (access_ipmask(w2, &access_deny[access_denynum])) - ++access_denynum; - else - ShowError("socket_config_read: Invalid ip or ip range '%s'!\n", line); - } - else if (!strcmpi(w1,"ddos_interval")) - ddos_interval = atoi(w2); - else if (!strcmpi(w1,"ddos_count")) - ddos_count = atoi(w2); - else if (!strcmpi(w1,"ddos_autoreset")) - ddos_autoreset = atoi(w2); - else if (!strcmpi(w1,"debug")) - access_debug = config_switch(w2); - else if (!strcmpi(w1,"socket_max_client_packet")) - socket_max_client_packet = strtoul(w2, NULL, 0); + else if (!strcmpi(w1, "enable_ip_rules")) { + ip_rules = config_switch(w2); + } else if (!strcmpi(w1, "order")) { + if (!strcmpi(w2, "deny,allow")) + access_order = ACO_DENY_ALLOW; + else if (!strcmpi(w2, "allow,deny")) + access_order = ACO_ALLOW_DENY; + else if (!strcmpi(w2, "mutual-failure")) + access_order = ACO_MUTUAL_FAILURE; + } else if (!strcmpi(w1, "allow")) { + RECREATE(access_allow, AccessControl, access_allownum+1); + if (access_ipmask(w2, &access_allow[access_allownum])) + ++access_allownum; + else + ShowError("socket_config_read: Invalid ip or ip range '%s'!\n", line); + } else if (!strcmpi(w1, "deny")) { + RECREATE(access_deny, AccessControl, access_denynum+1); + if (access_ipmask(w2, &access_deny[access_denynum])) + ++access_denynum; + else + ShowError("socket_config_read: Invalid ip or ip range '%s'!\n", line); + } else if (!strcmpi(w1,"ddos_interval")) + ddos_interval = atoi(w2); + else if (!strcmpi(w1,"ddos_count")) + ddos_count = atoi(w2); + else if (!strcmpi(w1,"ddos_autoreset")) + ddos_autoreset = atoi(w2); + else if (!strcmpi(w1,"debug")) + access_debug = config_switch(w2); + else if (!strcmpi(w1,"socket_max_client_packet")) + socket_max_client_packet = strtoul(w2, NULL, 0); #endif - else if (!strcmpi(w1, "import")) - socket_config_read(w2); - else - ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName); - } - - fclose(fp); - return 0; + else if (!strcmpi(w1, "import")) + socket_config_read(w2); + else + ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName); + } + + fclose(fp); + return 0; } void socket_final(void) { - int i; + int i; #ifndef MINICORE - ConnectHistory* hist; - ConnectHistory* next_hist; - - for( i=0; i < 0x10000; ++i ){ - hist = connect_history[i]; - while( hist ){ - next_hist = hist->next; - aFree(hist); - hist = next_hist; - } - } - if( access_allow ) - aFree(access_allow); - if( access_deny ) - aFree(access_deny); + ConnectHistory *hist; + ConnectHistory *next_hist; + + for (i=0; i < 0x10000; ++i) { + hist = connect_history[i]; + while (hist) { + next_hist = hist->next; + aFree(hist); + hist = next_hist; + } + } + if (access_allow) + aFree(access_allow); + if (access_deny) + aFree(access_deny); #endif - for( i = 1; i < fd_max; i++ ) - if(session[i]) - do_close(i); + for (i = 1; i < fd_max; i++) + if (session[i]) + do_close(i); - // session[0] のダミーデータを削除 - aFree(session[0]->rdata); - aFree(session[0]->wdata); - aFree(session[0]); + // session[0] のダミーデータを削除 + aFree(session[0]->rdata); + aFree(session[0]->wdata); + aFree(session[0]); } /// Closes a socket. void do_close(int fd) { - if( fd <= 0 ||fd >= FD_SETSIZE ) - return;// invalid - - flush_fifo(fd); // Try to send what's left (although it might not succeed since it's a nonblocking socket) - sFD_CLR(fd, &readfds);// this needs to be done before closing the socket - sShutdown(fd, SHUT_RDWR); // Disallow further reads/writes - sClose(fd); // We don't really care if these closing functions return an error, we are just shutting down and not reusing this socket. - if (session[fd]) delete_session(fd); + if (fd <= 0 ||fd >= FD_SETSIZE) + return;// invalid + + flush_fifo(fd); // Try to send what's left (although it might not succeed since it's a nonblocking socket) + sFD_CLR(fd, &readfds);// this needs to be done before closing the socket + sShutdown(fd, SHUT_RDWR); // Disallow further reads/writes + sClose(fd); // We don't really care if these closing functions return an error, we are just shutting down and not reusing this socket. + if (session[fd]) delete_session(fd); } /// Retrieve local ips in host byte order. /// Uses loopback is no address is found. -int socket_getips(uint32* ips, int max) +int socket_getips(uint32 *ips, int max) { - int num = 0; + int num = 0; - if( ips == NULL || max <= 0 ) - return 0; + if (ips == NULL || max <= 0) + return 0; #ifdef WIN32 - { - char fullhost[255]; - u_long** a; - struct hostent* hent; - - // XXX This should look up the local IP addresses in the registry - // instead of calling gethostbyname. However, the way IP addresses - // are stored in the registry is annoyingly complex, so I'll leave - // this as T.B.D. [Meruru] - if( gethostname(fullhost, sizeof(fullhost)) == SOCKET_ERROR ) - { - ShowError("socket_getips: No hostname defined!\n"); - return 0; - } - else - { - hent = gethostbyname(fullhost); - if( hent == NULL ){ - ShowError("socket_getips: Cannot resolve our own hostname to an IP address\n"); - return 0; - } - a = (u_long**)hent->h_addr_list; - for( ; a[num] != NULL && num < max; ++num) - ips[num] = (uint32)ntohl(*a[num]); - } - } + { + char fullhost[255]; + u_long **a; + struct hostent *hent; + + // XXX This should look up the local IP addresses in the registry + // instead of calling gethostbyname. However, the way IP addresses + // are stored in the registry is annoyingly complex, so I'll leave + // this as T.B.D. [Meruru] + if (gethostname(fullhost, sizeof(fullhost)) == SOCKET_ERROR) { + ShowError("socket_getips: No hostname defined!\n"); + return 0; + } else { + hent = gethostbyname(fullhost); + if (hent == NULL) { + ShowError("socket_getips: Cannot resolve our own hostname to an IP address\n"); + return 0; + } + a = (u_long **)hent->h_addr_list; + for (; a[num] != NULL && num < max; ++num) + ips[num] = (uint32)ntohl(*a[num]); + } + } #else // not WIN32 - { - int pos; - int fd; - char buf[2*16*sizeof(struct ifreq)]; - struct ifconf ic; - struct ifreq* ir; - struct sockaddr_in* a; - u_long ad; - - fd = sSocket(AF_INET, SOCK_STREAM, 0); - - memset(buf, 0x00, sizeof(buf)); - - // The ioctl call will fail with Invalid Argument if there are more - // interfaces than will fit in the buffer - ic.ifc_len = sizeof(buf); - ic.ifc_buf = buf; - if( sIoctl(fd, SIOCGIFCONF, &ic) == -1 ) - { - ShowError("socket_getips: SIOCGIFCONF failed!\n"); - return 0; - } - else - { - for( pos=0; pos < ic.ifc_len && num < max; ) - { - ir = (struct ifreq*)(buf+pos); - a = (struct sockaddr_in*) &(ir->ifr_addr); - if( a->sin_family == AF_INET ){ - ad = ntohl(a->sin_addr.s_addr); - if( ad != INADDR_LOOPBACK && ad != INADDR_ANY ) - ips[num++] = (uint32)ad; - } - #if (defined(BSD) && BSD >= 199103) || defined(_AIX) || defined(__APPLE__) - pos += ir->ifr_addr.sa_len + sizeof(ir->ifr_name); - #else// not AIX or APPLE - pos += sizeof(struct ifreq); - #endif//not AIX or APPLE - } - } - sClose(fd); - } + { + int pos; + int fd; + char buf[2*16*sizeof(struct ifreq)]; + struct ifconf ic; + struct ifreq *ir; + struct sockaddr_in *a; + u_long ad; + + fd = sSocket(AF_INET, SOCK_STREAM, 0); + + memset(buf, 0x00, sizeof(buf)); + + // The ioctl call will fail with Invalid Argument if there are more + // interfaces than will fit in the buffer + ic.ifc_len = sizeof(buf); + ic.ifc_buf = buf; + if (sIoctl(fd, SIOCGIFCONF, &ic) == -1) { + ShowError("socket_getips: SIOCGIFCONF failed!\n"); + return 0; + } else { + for (pos=0; pos < ic.ifc_len && num < max;) { + ir = (struct ifreq *)(buf+pos); + a = (struct sockaddr_in *) &(ir->ifr_addr); + if (a->sin_family == AF_INET) { + ad = ntohl(a->sin_addr.s_addr); + if (ad != INADDR_LOOPBACK && ad != INADDR_ANY) + ips[num++] = (uint32)ad; + } +#if (defined(BSD) && BSD >= 199103) || defined(_AIX) || defined(__APPLE__) + pos += ir->ifr_addr.sa_len + sizeof(ir->ifr_name); +#else// not AIX or APPLE + pos += sizeof(struct ifreq); +#endif//not AIX or APPLE + } + } + sClose(fd); + } #endif // not W32 - // Use loopback if no ips are found - if( num == 0 ) - ips[num++] = (uint32)INADDR_LOOPBACK; + // Use loopback if no ips are found + if (num == 0) + ips[num++] = (uint32)INADDR_LOOPBACK; - return num; + return num; } void socket_init(void) { - char *SOCKET_CONF_FILENAME = "conf/packet_athena.conf"; - unsigned int rlim_cur = FD_SETSIZE; + char *SOCKET_CONF_FILENAME = "conf/packet_athena.conf"; + unsigned int rlim_cur = FD_SETSIZE; #ifdef WIN32 - {// Start up windows networking - WSADATA wsaData; - WORD wVersionRequested = MAKEWORD(2, 0); - if( WSAStartup(wVersionRequested, &wsaData) != 0 ) - { - ShowError("socket_init: WinSock not available!\n"); - return; - } - if( LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0 ) - { - ShowError("socket_init: WinSock version mismatch (2.0 or compatible required)!\n"); - return; - } - } + { + // Start up windows networking + WSADATA wsaData; + WORD wVersionRequested = MAKEWORD(2, 0); + if (WSAStartup(wVersionRequested, &wsaData) != 0) { + ShowError("socket_init: WinSock not available!\n"); + return; + } + if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) { + ShowError("socket_init: WinSock version mismatch (2.0 or compatible required)!\n"); + return; + } + } #elif defined(HAVE_SETRLIMIT) && !defined(CYGWIN) - // NOTE: getrlimit and setrlimit have bogus behaviour in cygwin. - // "Number of fds is virtually unlimited in cygwin" (sys/param.h) - {// set socket limit to FD_SETSIZE - struct rlimit rlp; - if( 0 == getrlimit(RLIMIT_NOFILE, &rlp) ) - { - rlp.rlim_cur = FD_SETSIZE; - if( 0 != setrlimit(RLIMIT_NOFILE, &rlp) ) - {// failed, try setting the maximum too (permission to change system limits is required) - rlp.rlim_max = FD_SETSIZE; - if( 0 != setrlimit(RLIMIT_NOFILE, &rlp) ) - {// failed - const char *errmsg = error_msg(); - int rlim_ori; - // set to maximum allowed - getrlimit(RLIMIT_NOFILE, &rlp); - rlim_ori = (int)rlp.rlim_cur; - rlp.rlim_cur = rlp.rlim_max; - setrlimit(RLIMIT_NOFILE, &rlp); - // report limit - getrlimit(RLIMIT_NOFILE, &rlp); - rlim_cur = rlp.rlim_cur; - ShowWarning("socket_init: failed to set socket limit to %d, setting to maximum allowed (original limit=%d, current limit=%d, maximum allowed=%d, %s).\n", FD_SETSIZE, rlim_ori, (int)rlp.rlim_cur, (int)rlp.rlim_max, errmsg); - } - } - } - } + // NOTE: getrlimit and setrlimit have bogus behaviour in cygwin. + // "Number of fds is virtually unlimited in cygwin" (sys/param.h) + { + // set socket limit to FD_SETSIZE + struct rlimit rlp; + if (0 == getrlimit(RLIMIT_NOFILE, &rlp)) { + rlp.rlim_cur = FD_SETSIZE; + if (0 != setrlimit(RLIMIT_NOFILE, &rlp)) { + // failed, try setting the maximum too (permission to change system limits is required) + rlp.rlim_max = FD_SETSIZE; + if (0 != setrlimit(RLIMIT_NOFILE, &rlp)) { + // failed + const char *errmsg = error_msg(); + int rlim_ori; + // set to maximum allowed + getrlimit(RLIMIT_NOFILE, &rlp); + rlim_ori = (int)rlp.rlim_cur; + rlp.rlim_cur = rlp.rlim_max; + setrlimit(RLIMIT_NOFILE, &rlp); + // report limit + getrlimit(RLIMIT_NOFILE, &rlp); + rlim_cur = rlp.rlim_cur; + ShowWarning("socket_init: failed to set socket limit to %d, setting to maximum allowed (original limit=%d, current limit=%d, maximum allowed=%d, %s).\n", FD_SETSIZE, rlim_ori, (int)rlp.rlim_cur, (int)rlp.rlim_max, errmsg); + } + } + } + } #endif - // Get initial local ips - naddr_ = socket_getips(addr_,16); + // Get initial local ips + naddr_ = socket_getips(addr_,16); - sFD_ZERO(&readfds); + sFD_ZERO(&readfds); #if defined(SEND_SHORTLIST) - memset(send_shortlist_set, 0, sizeof(send_shortlist_set)); + memset(send_shortlist_set, 0, sizeof(send_shortlist_set)); #endif - socket_config_read(SOCKET_CONF_FILENAME); + socket_config_read(SOCKET_CONF_FILENAME); - // initialise last send-receive tick - last_tick = time(NULL); + // initialise last send-receive tick + last_tick = time(NULL); - // session[0] is now currently used for disconnected sessions of the map server, and as such, - // should hold enough buffer (it is a vacuum so to speak) as it is never flushed. [Skotlex] - create_session(0, null_recv, null_send, null_parse); + // session[0] is now currently used for disconnected sessions of the map server, and as such, + // should hold enough buffer (it is a vacuum so to speak) as it is never flushed. [Skotlex] + create_session(0, null_recv, null_send, null_parse); #ifndef MINICORE - // Delete old connection history every 5 minutes - memset(connect_history, 0, sizeof(connect_history)); - add_timer_func_list(connect_check_clear, "connect_check_clear"); - add_timer_interval(gettick()+1000, connect_check_clear, 0, 0, 5*60*1000); + // Delete old connection history every 5 minutes + memset(connect_history, 0, sizeof(connect_history)); + add_timer_func_list(connect_check_clear, "connect_check_clear"); + add_timer_interval(gettick()+1000, connect_check_clear, 0, 0, 5*60*1000); #endif - ShowInfo("Server supports up to '"CL_WHITE"%u"CL_RESET"' concurrent connections.\n", rlim_cur); + ShowInfo("Server supports up to '"CL_WHITE"%u"CL_RESET"' concurrent connections.\n", rlim_cur); } bool session_isValid(int fd) { - return ( fd > 0 && fd < FD_SETSIZE && session[fd] != NULL ); + return (fd > 0 && fd < FD_SETSIZE && session[fd] != NULL); } bool session_isActive(int fd) { - return ( session_isValid(fd) && !session[fd]->flag.eof ); + return (session_isValid(fd) && !session[fd]->flag.eof); } // Resolves hostname into a numeric ip. -uint32 host2ip(const char* hostname) +uint32 host2ip(const char *hostname) { - struct hostent* h = gethostbyname(hostname); - return (h != NULL) ? ntohl(*(uint32*)h->h_addr) : 0; + struct hostent *h = gethostbyname(hostname); + return (h != NULL) ? ntohl(*(uint32 *)h->h_addr) : 0; } // Converts a numeric ip into a dot-formatted string. // Result is placed either into a user-provided buffer or a static system buffer. -const char* ip2str(uint32 ip, char ip_str[16]) +const char *ip2str(uint32 ip, char ip_str[16]) { - struct in_addr addr; - addr.s_addr = htonl(ip); - return (ip_str == NULL) ? inet_ntoa(addr) : strncpy(ip_str, inet_ntoa(addr), 16); + struct in_addr addr; + addr.s_addr = htonl(ip); + return (ip_str == NULL) ? inet_ntoa(addr) : strncpy(ip_str, inet_ntoa(addr), 16); } // Converts a dot-formatted ip string into a numeric ip. -uint32 str2ip(const char* ip_str) +uint32 str2ip(const char *ip_str) { - return ntohl(inet_addr(ip_str)); + return ntohl(inet_addr(ip_str)); } // Reorders bytes from network to little endian (Windows). // Neccessary for sending port numbers to the RO client until Gravity notices that they forgot ntohs() calls. uint16 ntows(uint16 netshort) { - return ((netshort & 0xFF) << 8) | ((netshort & 0xFF00) >> 8); + return ((netshort & 0xFF) << 8) | ((netshort & 0xFF00) >> 8); } #ifdef SEND_SHORTLIST @@ -1382,75 +1364,70 @@ uint16 ntows(uint16 netshort) // sending or eof handling. void send_shortlist_add_fd(int fd) { - int i; - int bit; + int i; + int bit; - if( !session_isValid(fd) ) - return;// out of range + if (!session_isValid(fd)) + return;// out of range - i = fd/32; - bit = fd%32; + i = fd/32; + bit = fd%32; - if( (send_shortlist_set[i]>>bit)&1 ) - return;// already in the list + if ((send_shortlist_set[i]>>bit)&1) + return;// already in the list - if( send_shortlist_count >= ARRAYLENGTH(send_shortlist_array) ) - { - ShowDebug("send_shortlist_add_fd: shortlist is full, ignoring... (fd=%d shortlist.count=%d shortlist.length=%d)\n", fd, send_shortlist_count, ARRAYLENGTH(send_shortlist_array)); - return; - } + if (send_shortlist_count >= ARRAYLENGTH(send_shortlist_array)) { + ShowDebug("send_shortlist_add_fd: shortlist is full, ignoring... (fd=%d shortlist.count=%d shortlist.length=%d)\n", fd, send_shortlist_count, ARRAYLENGTH(send_shortlist_array)); + return; + } - // set the bit - send_shortlist_set[i] |= 1<= 0; --i ) - { - int fd = send_shortlist_array[i]; - int idx = fd/32; - int bit = fd%32; - - // Remove fd from shortlist, move the last fd to the current position - --send_shortlist_count; - send_shortlist_array[i] = send_shortlist_array[send_shortlist_count]; - send_shortlist_array[send_shortlist_count] = 0; - - if( fd <= 0 || fd >= FD_SETSIZE ) - { - ShowDebug("send_shortlist_do_sends: fd is out of range, corrupted memory? (fd=%d)\n", fd); - continue; - } - if( ((send_shortlist_set[idx]>>bit)&1) == 0 ) - { - ShowDebug("send_shortlist_do_sends: fd is not set, why is it in the shortlist? (fd=%d)\n", fd); - continue; - } - send_shortlist_set[idx]&=~(1<wdata_size ) - session[fd]->func_send(fd); - - // If it's been marked as eof, call the parse func on it so that - // the socket will be immediately closed. - if( session[fd]->flag.eof ) - session[fd]->func_parse(fd); - - // If the session still exists, is not eof and has things left to - // be sent from it we'll re-add it to the shortlist. - if( session[fd] && !session[fd]->flag.eof && session[fd]->wdata_size ) - send_shortlist_add_fd(fd); - } - } + int i; + + for (i = send_shortlist_count-1; i >= 0; --i) { + int fd = send_shortlist_array[i]; + int idx = fd/32; + int bit = fd%32; + + // Remove fd from shortlist, move the last fd to the current position + --send_shortlist_count; + send_shortlist_array[i] = send_shortlist_array[send_shortlist_count]; + send_shortlist_array[send_shortlist_count] = 0; + + if (fd <= 0 || fd >= FD_SETSIZE) { + ShowDebug("send_shortlist_do_sends: fd is out of range, corrupted memory? (fd=%d)\n", fd); + continue; + } + if (((send_shortlist_set[idx]>>bit)&1) == 0) { + ShowDebug("send_shortlist_do_sends: fd is not set, why is it in the shortlist? (fd=%d)\n", fd); + continue; + } + send_shortlist_set[idx]&=~(1<wdata_size) + session[fd]->func_send(fd); + + // If it's been marked as eof, call the parse func on it so that + // the socket will be immediately closed. + if (session[fd]->flag.eof) + session[fd]->func_parse(fd); + + // If the session still exists, is not eof and has things left to + // be sent from it we'll re-add it to the shortlist. + if (session[fd] && !session[fd]->flag.eof && session[fd]->wdata_size) + send_shortlist_add_fd(fd); + } + } } #endif diff --git a/src/common/socket.h b/src/common/socket.h index 7c0e02f5d..5c4008d62 100644 --- a/src/common/socket.h +++ b/src/common/socket.h @@ -1,18 +1,18 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _SOCKET_H_ +#ifndef _SOCKET_H_ #define _SOCKET_H_ #include "../common/cbasetypes.h" #ifdef WIN32 - #include "../common/winapi.h" - typedef long in_addr_t; +#include "../common/winapi.h" +typedef long in_addr_t; #else - #include - #include - #include +#include +#include +#include #endif #include @@ -38,15 +38,15 @@ #define RFIFOREST(fd) (session[fd]->flag.eof ? 0 : session[fd]->rdata_size - session[fd]->rdata_pos) #define RFIFOFLUSH(fd) \ - do { \ - if(session[fd]->rdata_size == session[fd]->rdata_pos){ \ - session[fd]->rdata_size = session[fd]->rdata_pos = 0; \ - } else { \ - session[fd]->rdata_size -= session[fd]->rdata_pos; \ - memmove(session[fd]->rdata, session[fd]->rdata+session[fd]->rdata_pos, session[fd]->rdata_size); \ - session[fd]->rdata_pos = 0; \ - } \ - } while(0) + do { \ + if(session[fd]->rdata_size == session[fd]->rdata_pos){ \ + session[fd]->rdata_size = session[fd]->rdata_pos = 0; \ + } else { \ + session[fd]->rdata_size -= session[fd]->rdata_pos; \ + memmove(session[fd]->rdata, session[fd]->rdata+session[fd]->rdata_pos, session[fd]->rdata_size); \ + session[fd]->rdata_pos = 0; \ + } \ + } while(0) // buffer I/O macros #define RBUFP(p,pos) (((uint8*)(p)) + (pos)) @@ -71,33 +71,32 @@ typedef int (*RecvFunc)(int fd); typedef int (*SendFunc)(int fd); typedef int (*ParseFunc)(int fd); -struct socket_data -{ - struct { - unsigned char eof : 1; - unsigned char server : 1; - unsigned char ping : 2; - } flag; +struct socket_data { + struct { + unsigned char eof : 1; + unsigned char server : 1; + unsigned char ping : 2; + } flag; - uint32 client_addr; // remote client address + uint32 client_addr; // remote client address - uint8 *rdata, *wdata; - size_t max_rdata, max_wdata; - size_t rdata_size, wdata_size; - size_t rdata_pos; - time_t rdata_tick; // time of last recv (for detecting timeouts); zero when timeout is disabled + uint8 *rdata, *wdata; + size_t max_rdata, max_wdata; + size_t rdata_size, wdata_size; + size_t rdata_pos; + time_t rdata_tick; // time of last recv (for detecting timeouts); zero when timeout is disabled - RecvFunc func_recv; - SendFunc func_send; - ParseFunc func_parse; + RecvFunc func_recv; + SendFunc func_send; + ParseFunc func_parse; - void* session_data; // stores application-specific data related to the session + void *session_data; // stores application-specific data related to the session }; // Data prototype declaration -extern struct socket_data* session[FD_SETSIZE]; +extern struct socket_data *session[FD_SETSIZE]; extern int fd_max; @@ -131,21 +130,21 @@ extern void set_nonblocking(int fd, unsigned long yes); void set_defaultparse(ParseFunc defaultparse); // hostname/ip conversion functions -uint32 host2ip(const char* hostname); -const char* ip2str(uint32 ip, char ip_str[16]); -uint32 str2ip(const char* ip_str); +uint32 host2ip(const char *hostname); +const char *ip2str(uint32 ip, char ip_str[16]); +uint32 str2ip(const char *ip_str); #define CONVIP(ip) ((ip)>>24)&0xFF,((ip)>>16)&0xFF,((ip)>>8)&0xFF,((ip)>>0)&0xFF #define MAKEIP(a,b,c,d) (uint32)( ( ( (a)&0xFF ) << 24 ) | ( ( (b)&0xFF ) << 16 ) | ( ( (c)&0xFF ) << 8 ) | ( ( (d)&0xFF ) << 0 ) ) uint16 ntows(uint16 netshort); -int socket_getips(uint32* ips, int max); +int socket_getips(uint32 *ips, int max); extern uint32 addr_[16]; // ip addresses of local host (host byte order) extern int naddr_; // # of ip addresses void set_eof(int fd); -/// Use a shortlist of sockets instead of iterating all sessions for sockets +/// Use a shortlist of sockets instead of iterating all sessions for sockets /// that have data to send or need eof handling. /// Adapted to use a static array instead of a linked list. /// diff --git a/src/common/spinlock.h b/src/common/spinlock.h index 3419bfdd5..8d1624b33 100644 --- a/src/common/spinlock.h +++ b/src/common/spinlock.h @@ -14,7 +14,7 @@ // For more information, see LICENCE in the main folder // // - + #ifdef WIN32 #include "../common/winapi.h" #endif @@ -25,77 +25,81 @@ #ifdef WIN32 -typedef struct __declspec( align(64) ) SPIN_LOCK{ - volatile LONG lock; - volatile LONG nest; - volatile LONG sync_lock; +typedef struct __declspec(align(64)) SPIN_LOCK { + volatile LONG lock; + volatile LONG nest; + volatile LONG sync_lock; } SPIN_LOCK, *PSPIN_LOCK; #else -typedef struct SPIN_LOCK{ - volatile int32 lock; - volatile int32 nest; // nesting level. - - volatile int32 sync_lock; +typedef struct SPIN_LOCK { + volatile int32 lock; + volatile int32 nest; // nesting level. + + volatile int32 sync_lock; } __attribute__((aligned(64))) SPIN_LOCK, *PSPIN_LOCK; #endif -static forceinline void InitializeSpinLock(PSPIN_LOCK lck){ - lck->lock = 0; - lck->nest = 0; - lck->sync_lock = 0; +static forceinline void InitializeSpinLock(PSPIN_LOCK lck) +{ + lck->lock = 0; + lck->nest = 0; + lck->sync_lock = 0; } -static forceinline void FinalizeSpinLock(PSPIN_LOCK lck){ - return; +static forceinline void FinalizeSpinLock(PSPIN_LOCK lck) +{ + return; } #define getsynclock(l) { while(1){ if(InterlockedCompareExchange(l, 1, 0) == 0) break; rathread_yield(); } } #define dropsynclock(l) { InterlockedExchange(l, 0); } -static forceinline void EnterSpinLock(PSPIN_LOCK lck){ - int tid = rathread_get_tid(); - - // Get Sync Lock && Check if the requester thread already owns the lock. - // if it owns, increase nesting level - getsynclock(&lck->sync_lock); - if(InterlockedCompareExchange(&lck->lock, tid, tid) == tid){ - InterlockedIncrement(&lck->nest); - dropsynclock(&lck->sync_lock); - return; // Got Lock - } - // drop sync lock - dropsynclock(&lck->sync_lock); - - - // Spin until we've got it ! - while(1){ - - if(InterlockedCompareExchange(&lck->lock, tid, 0) == 0){ - - InterlockedIncrement(&lck->nest); - return; // Got Lock - } - - rathread_yield(); // Force ctxswitch to another thread. - } +static forceinline void EnterSpinLock(PSPIN_LOCK lck) +{ + int tid = rathread_get_tid(); + + // Get Sync Lock && Check if the requester thread already owns the lock. + // if it owns, increase nesting level + getsynclock(&lck->sync_lock); + if (InterlockedCompareExchange(&lck->lock, tid, tid) == tid) { + InterlockedIncrement(&lck->nest); + dropsynclock(&lck->sync_lock); + return; // Got Lock + } + // drop sync lock + dropsynclock(&lck->sync_lock); + + + // Spin until we've got it ! + while (1) { + + if (InterlockedCompareExchange(&lck->lock, tid, 0) == 0) { + + InterlockedIncrement(&lck->nest); + return; // Got Lock + } + + rathread_yield(); // Force ctxswitch to another thread. + } } -static forceinline void LeaveSpinLock(PSPIN_LOCK lck){ - int tid = rathread_get_tid(); +static forceinline void LeaveSpinLock(PSPIN_LOCK lck) +{ + int tid = rathread_get_tid(); + + getsynclock(&lck->sync_lock); + + if (InterlockedCompareExchange(&lck->lock, tid, tid) == tid) { // this thread owns the lock. + if (InterlockedDecrement(&lck->nest) == 0) + InterlockedExchange(&lck->lock, 0); // Unlock! + } - getsynclock(&lck->sync_lock); - - if(InterlockedCompareExchange(&lck->lock, tid, tid) == tid){ // this thread owns the lock. - if(InterlockedDecrement(&lck->nest) == 0) - InterlockedExchange(&lck->lock, 0); // Unlock! - } - - dropsynclock(&lck->sync_lock); + dropsynclock(&lck->sync_lock); } diff --git a/src/common/sql.c b/src/common/sql.c index 800aa89b0..740da476d 100644 --- a/src/common/sql.c +++ b/src/common/sql.c @@ -18,41 +18,38 @@ /// Sql handle -struct Sql -{ - StringBuf buf; - MYSQL handle; - MYSQL_RES* result; - MYSQL_ROW row; - unsigned long* lengths; - int keepalive; +struct Sql { + StringBuf buf; + MYSQL handle; + MYSQL_RES *result; + MYSQL_ROW row; + unsigned long *lengths; + int keepalive; }; // Column length receiver. // Takes care of the possible size missmatch between uint32 and unsigned long. -struct s_column_length -{ - uint32* out_length; - unsigned long length; +struct s_column_length { + uint32 *out_length; + unsigned long length; }; typedef struct s_column_length s_column_length; /// Sql statement -struct SqlStmt -{ - StringBuf buf; - MYSQL_STMT* stmt; - MYSQL_BIND* params; - MYSQL_BIND* columns; - s_column_length* column_lengths; - size_t max_params; - size_t max_columns; - bool bind_params; - bool bind_columns; +struct SqlStmt { + StringBuf buf; + MYSQL_STMT *stmt; + MYSQL_BIND *params; + MYSQL_BIND *columns; + s_column_length *column_lengths; + size_t max_params; + size_t max_columns; + bool bind_params; + bool bind_columns; }; @@ -64,117 +61,111 @@ struct SqlStmt /// Allocates and initializes a new Sql handle. -Sql* Sql_Malloc(void) +Sql *Sql_Malloc(void) { - Sql* self; + Sql *self; - CREATE(self, Sql, 1); - mysql_init(&self->handle); - StringBuf_Init(&self->buf); - self->lengths = NULL; - self->result = NULL; - self->keepalive = INVALID_TIMER; + CREATE(self, Sql, 1); + mysql_init(&self->handle); + StringBuf_Init(&self->buf); + self->lengths = NULL; + self->result = NULL; + self->keepalive = INVALID_TIMER; - return self; + return self; } -static int Sql_P_Keepalive(Sql* self); +static int Sql_P_Keepalive(Sql *self); /// Establishes a connection. -int Sql_Connect(Sql* self, const char* user, const char* passwd, const char* host, uint16 port, const char* db) +int Sql_Connect(Sql *self, const char *user, const char *passwd, const char *host, uint16 port, const char *db) { - if( self == NULL ) - return SQL_ERROR; + if (self == NULL) + return SQL_ERROR; - StringBuf_Clear(&self->buf); - if( !mysql_real_connect(&self->handle, host, user, passwd, db, (unsigned int)port, NULL/*unix_socket*/, 0/*clientflag*/) ) - { - ShowSQL("%s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } + StringBuf_Clear(&self->buf); + if (!mysql_real_connect(&self->handle, host, user, passwd, db, (unsigned int)port, NULL/*unix_socket*/, 0/*clientflag*/)) { + ShowSQL("%s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } - self->keepalive = Sql_P_Keepalive(self); - if( self->keepalive == INVALID_TIMER ) - { - ShowSQL("Failed to establish keepalive for DB connection!\n"); - return SQL_ERROR; - } + self->keepalive = Sql_P_Keepalive(self); + if (self->keepalive == INVALID_TIMER) { + ShowSQL("Failed to establish keepalive for DB connection!\n"); + return SQL_ERROR; + } - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Retrieves the timeout of the connection. -int Sql_GetTimeout(Sql* self, uint32* out_timeout) +int Sql_GetTimeout(Sql *self, uint32 *out_timeout) { - if( self && out_timeout && SQL_SUCCESS == Sql_Query(self, "SHOW VARIABLES LIKE 'wait_timeout'") ) - { - char* data; - size_t len; - if( SQL_SUCCESS == Sql_NextRow(self) && - SQL_SUCCESS == Sql_GetData(self, 1, &data, &len) ) - { - *out_timeout = (uint32)strtoul(data, NULL, 10); - Sql_FreeResult(self); - return SQL_SUCCESS; - } - Sql_FreeResult(self); - } - return SQL_ERROR; + if (self && out_timeout && SQL_SUCCESS == Sql_Query(self, "SHOW VARIABLES LIKE 'wait_timeout'")) { + char *data; + size_t len; + if (SQL_SUCCESS == Sql_NextRow(self) && + SQL_SUCCESS == Sql_GetData(self, 1, &data, &len)) { + *out_timeout = (uint32)strtoul(data, NULL, 10); + Sql_FreeResult(self); + return SQL_SUCCESS; + } + Sql_FreeResult(self); + } + return SQL_ERROR; } /// Retrieves the name of the columns of a table into out_buf, with the separator after each name. -int Sql_GetColumnNames(Sql* self, const char* table, char* out_buf, size_t buf_len, char sep) +int Sql_GetColumnNames(Sql *self, const char *table, char *out_buf, size_t buf_len, char sep) { - char* data; - size_t len; - size_t off = 0; + char *data; + size_t len; + size_t off = 0; - if( self == NULL || SQL_ERROR == Sql_Query(self, "EXPLAIN `%s`", table) ) - return SQL_ERROR; + if (self == NULL || SQL_ERROR == Sql_Query(self, "EXPLAIN `%s`", table)) + return SQL_ERROR; - out_buf[off] = '\0'; - while( SQL_SUCCESS == Sql_NextRow(self) && SQL_SUCCESS == Sql_GetData(self, 0, &data, &len) ) - { - len = strnlen(data, len); - if( off + len + 2 > buf_len ) - { - ShowDebug("Sql_GetColumns: output buffer is too small\n"); - *out_buf = '\0'; - return SQL_ERROR; - } - memcpy(out_buf+off, data, len); - off += len; - out_buf[off++] = sep; - } - out_buf[off] = '\0'; - Sql_FreeResult(self); - return SQL_SUCCESS; + out_buf[off] = '\0'; + while (SQL_SUCCESS == Sql_NextRow(self) && SQL_SUCCESS == Sql_GetData(self, 0, &data, &len)) { + len = strnlen(data, len); + if (off + len + 2 > buf_len) { + ShowDebug("Sql_GetColumns: output buffer is too small\n"); + *out_buf = '\0'; + return SQL_ERROR; + } + memcpy(out_buf+off, data, len); + off += len; + out_buf[off++] = sep; + } + out_buf[off] = '\0'; + Sql_FreeResult(self); + return SQL_SUCCESS; } /// Changes the encoding of the connection. -int Sql_SetEncoding(Sql* self, const char* encoding) +int Sql_SetEncoding(Sql *self, const char *encoding) { - if( self && mysql_set_character_set(&self->handle, encoding) == 0 ) - return SQL_SUCCESS; - return SQL_ERROR; + if (self && mysql_set_character_set(&self->handle, encoding) == 0) + return SQL_SUCCESS; + return SQL_ERROR; } /// Pings the connection. -int Sql_Ping(Sql* self) +int Sql_Ping(Sql *self) { - if( self && mysql_ping(&self->handle) == 0 ) - return SQL_SUCCESS; - return SQL_ERROR; + if (self && mysql_ping(&self->handle) == 0) + return SQL_SUCCESS; + return SQL_ERROR; } @@ -184,10 +175,10 @@ int Sql_Ping(Sql* self) /// @private static int Sql_P_KeepaliveTimer(int tid, unsigned int tick, int id, intptr_t data) { - Sql* self = (Sql*)data; - ShowInfo("Pinging SQL server to keep connection alive...\n"); - Sql_Ping(self); - return 0; + Sql *self = (Sql *)data; + ShowInfo("Pinging SQL server to keep connection alive...\n"); + Sql_Ping(self); + return 0; } @@ -196,224 +187,213 @@ static int Sql_P_KeepaliveTimer(int tid, unsigned int tick, int id, intptr_t dat /// /// @return the keepalive timer id, or INVALID_TIMER /// @private -static int Sql_P_Keepalive(Sql* self) +static int Sql_P_Keepalive(Sql *self) { - uint32 timeout, ping_interval; + uint32 timeout, ping_interval; - // set a default value first - timeout = 28800; // 8 hours + // set a default value first + timeout = 28800; // 8 hours - // request the timeout value from the mysql server - Sql_GetTimeout(self, &timeout); + // request the timeout value from the mysql server + Sql_GetTimeout(self, &timeout); - if( timeout < 60 ) - timeout = 60; + if (timeout < 60) + timeout = 60; - // establish keepalive - ping_interval = timeout - 30; // 30-second reserve - //add_timer_func_list(Sql_P_KeepaliveTimer, "Sql_P_KeepaliveTimer"); - return add_timer_interval(gettick() + ping_interval*1000, Sql_P_KeepaliveTimer, 0, (intptr_t)self, ping_interval*1000); + // establish keepalive + ping_interval = timeout - 30; // 30-second reserve + //add_timer_func_list(Sql_P_KeepaliveTimer, "Sql_P_KeepaliveTimer"); + return add_timer_interval(gettick() + ping_interval*1000, Sql_P_KeepaliveTimer, 0, (intptr_t)self, ping_interval*1000); } /// Escapes a string. -size_t Sql_EscapeString(Sql* self, char *out_to, const char *from) +size_t Sql_EscapeString(Sql *self, char *out_to, const char *from) { - if( self ) - return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)strlen(from)); - else - return (size_t)mysql_escape_string(out_to, from, (unsigned long)strlen(from)); + if (self) + return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)strlen(from)); + else + return (size_t)mysql_escape_string(out_to, from, (unsigned long)strlen(from)); } /// Escapes a string. -size_t Sql_EscapeStringLen(Sql* self, char *out_to, const char *from, size_t from_len) +size_t Sql_EscapeStringLen(Sql *self, char *out_to, const char *from, size_t from_len) { - if( self ) - return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)from_len); - else - return (size_t)mysql_escape_string(out_to, from, (unsigned long)from_len); + if (self) + return (size_t)mysql_real_escape_string(&self->handle, out_to, from, (unsigned long)from_len); + else + return (size_t)mysql_escape_string(out_to, from, (unsigned long)from_len); } /// Executes a query. -int Sql_Query(Sql* self, const char* query, ...) +int Sql_Query(Sql *self, const char *query, ...) { - int res; - va_list args; + int res; + va_list args; - va_start(args, query); - res = Sql_QueryV(self, query, args); - va_end(args); + va_start(args, query); + res = Sql_QueryV(self, query, args); + va_end(args); - return res; + return res; } /// Executes a query. -int Sql_QueryV(Sql* self, const char* query, va_list args) +int Sql_QueryV(Sql *self, const char *query, va_list args) { - if( self == NULL ) - return SQL_ERROR; + if (self == NULL) + return SQL_ERROR; - Sql_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_Vprintf(&self->buf, query, args); - if( mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) - { - ShowSQL("DB error - %s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } - self->result = mysql_store_result(&self->handle); - if( mysql_errno(&self->handle) != 0 ) - { - ShowSQL("DB error - %s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } - return SQL_SUCCESS; + Sql_FreeResult(self); + StringBuf_Clear(&self->buf); + StringBuf_Vprintf(&self->buf, query, args); + if (mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf))) { + ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } + self->result = mysql_store_result(&self->handle); + if (mysql_errno(&self->handle) != 0) { + ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } + return SQL_SUCCESS; } /// Executes a query. -int Sql_QueryStr(Sql* self, const char* query) +int Sql_QueryStr(Sql *self, const char *query) { - if( self == NULL ) - return SQL_ERROR; + if (self == NULL) + return SQL_ERROR; - Sql_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_AppendStr(&self->buf, query); - if( mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) - { - ShowSQL("DB error - %s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } - self->result = mysql_store_result(&self->handle); - if( mysql_errno(&self->handle) != 0 ) - { - ShowSQL("DB error - %s\n", mysql_error(&self->handle)); - return SQL_ERROR; - } - return SQL_SUCCESS; + Sql_FreeResult(self); + StringBuf_Clear(&self->buf); + StringBuf_AppendStr(&self->buf, query); + if (mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf))) { + ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } + self->result = mysql_store_result(&self->handle); + if (mysql_errno(&self->handle) != 0) { + ShowSQL("DB error - %s\n", mysql_error(&self->handle)); + return SQL_ERROR; + } + return SQL_SUCCESS; } /// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE query. -uint64 Sql_LastInsertId(Sql* self) +uint64 Sql_LastInsertId(Sql *self) { - if( self ) - return (uint64)mysql_insert_id(&self->handle); - else - return 0; + if (self) + return (uint64)mysql_insert_id(&self->handle); + else + return 0; } /// Returns the number of columns in each row of the result. -uint32 Sql_NumColumns(Sql* self) +uint32 Sql_NumColumns(Sql *self) { - if( self && self->result ) - return (uint32)mysql_num_fields(self->result); - return 0; + if (self && self->result) + return (uint32)mysql_num_fields(self->result); + return 0; } /// Returns the number of rows in the result. -uint64 Sql_NumRows(Sql* self) +uint64 Sql_NumRows(Sql *self) { - if( self && self->result ) - return (uint64)mysql_num_rows(self->result); - return 0; + if (self && self->result) + return (uint64)mysql_num_rows(self->result); + return 0; } /// Fetches the next row. -int Sql_NextRow(Sql* self) +int Sql_NextRow(Sql *self) { - if( self && self->result ) - { - self->row = mysql_fetch_row(self->result); - if( self->row ) - { - self->lengths = mysql_fetch_lengths(self->result); - return SQL_SUCCESS; - } - self->lengths = NULL; - if( mysql_errno(&self->handle) == 0 ) - return SQL_NO_DATA; - } - return SQL_ERROR; + if (self && self->result) { + self->row = mysql_fetch_row(self->result); + if (self->row) { + self->lengths = mysql_fetch_lengths(self->result); + return SQL_SUCCESS; + } + self->lengths = NULL; + if (mysql_errno(&self->handle) == 0) + return SQL_NO_DATA; + } + return SQL_ERROR; } /// Gets the data of a column. -int Sql_GetData(Sql* self, size_t col, char** out_buf, size_t* out_len) +int Sql_GetData(Sql *self, size_t col, char **out_buf, size_t *out_len) { - if( self && self->row ) - { - if( col < Sql_NumColumns(self) ) - { - if( out_buf ) *out_buf = self->row[col]; - if( out_len ) *out_len = (size_t)self->lengths[col]; - } - else - {// out of range - ignore - if( out_buf ) *out_buf = NULL; - if( out_len ) *out_len = 0; - } - return SQL_SUCCESS; - } - return SQL_ERROR; + if (self && self->row) { + if (col < Sql_NumColumns(self)) { + if (out_buf) *out_buf = self->row[col]; + if (out_len) *out_len = (size_t)self->lengths[col]; + } else { + // out of range - ignore + if (out_buf) *out_buf = NULL; + if (out_len) *out_len = 0; + } + return SQL_SUCCESS; + } + return SQL_ERROR; } /// Frees the result of the query. -void Sql_FreeResult(Sql* self) +void Sql_FreeResult(Sql *self) { - if( self && self->result ) - { - mysql_free_result(self->result); - self->result = NULL; - self->row = NULL; - self->lengths = NULL; - } + if (self && self->result) { + mysql_free_result(self->result); + self->result = NULL; + self->row = NULL; + self->lengths = NULL; + } } /// Shows debug information (last query). -void Sql_ShowDebug_(Sql* self, const char* debug_file, const unsigned long debug_line) +void Sql_ShowDebug_(Sql *self, const char *debug_file, const unsigned long debug_line) { - if( self == NULL ) - ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); - else if( StringBuf_Length(&self->buf) > 0 ) - ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); - else - ShowDebug("at %s:%lu\n", debug_file, debug_line); + if (self == NULL) + ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); + else if (StringBuf_Length(&self->buf) > 0) + ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); + else + ShowDebug("at %s:%lu\n", debug_file, debug_line); } /// Frees a Sql handle returned by Sql_Malloc. -void Sql_Free(Sql* self) +void Sql_Free(Sql *self) { - if( self ) - { - Sql_FreeResult(self); - StringBuf_Destroy(&self->buf); - if( self->keepalive != INVALID_TIMER ) delete_timer(self->keepalive, Sql_P_KeepaliveTimer); - aFree(self); - } + if (self) { + Sql_FreeResult(self); + StringBuf_Destroy(&self->buf); + if (self->keepalive != INVALID_TIMER) delete_timer(self->keepalive, Sql_P_KeepaliveTimer); + aFree(self); + } } @@ -429,16 +409,19 @@ void Sql_Free(Sql* self) /// @private static enum enum_field_types Sql_P_SizeToMysqlIntType(int sz) { - switch( sz ) - { - case 1: return MYSQL_TYPE_TINY; - case 2: return MYSQL_TYPE_SHORT; - case 4: return MYSQL_TYPE_LONG; - case 8: return MYSQL_TYPE_LONGLONG; - default: - ShowDebug("SizeToMysqlIntType: unsupported size (%d)\n", sz); - return MYSQL_TYPE_NULL; - } + switch (sz) { + case 1: + return MYSQL_TYPE_TINY; + case 2: + return MYSQL_TYPE_SHORT; + case 4: + return MYSQL_TYPE_LONG; + case 8: + return MYSQL_TYPE_LONGLONG; + default: + ShowDebug("SizeToMysqlIntType: unsupported size (%d)\n", sz); + return MYSQL_TYPE_NULL; + } } @@ -446,74 +429,96 @@ static enum enum_field_types Sql_P_SizeToMysqlIntType(int sz) /// Binds a parameter/result. /// /// @private -static int Sql_P_BindSqlDataType(MYSQL_BIND* bind, enum SqlDataType buffer_type, void* buffer, size_t buffer_len, unsigned long* out_length, int8* out_is_null) -{ - memset(bind, 0, sizeof(MYSQL_BIND)); - switch( buffer_type ) - { - case SQLDT_NULL: bind->buffer_type = MYSQL_TYPE_NULL; - buffer_len = 0;// FIXME length = ? [FlavioJS] - break; - // fixed size - case SQLDT_UINT8: bind->is_unsigned = 1; - case SQLDT_INT8: bind->buffer_type = MYSQL_TYPE_TINY; - buffer_len = 1; - break; - case SQLDT_UINT16: bind->is_unsigned = 1; - case SQLDT_INT16: bind->buffer_type = MYSQL_TYPE_SHORT; - buffer_len = 2; - break; - case SQLDT_UINT32: bind->is_unsigned = 1; - case SQLDT_INT32: bind->buffer_type = MYSQL_TYPE_LONG; - buffer_len = 4; - break; - case SQLDT_UINT64: bind->is_unsigned = 1; - case SQLDT_INT64: bind->buffer_type = MYSQL_TYPE_LONGLONG; - buffer_len = 8; - break; - // platform dependent size - case SQLDT_UCHAR: bind->is_unsigned = 1; - case SQLDT_CHAR: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(char)); - buffer_len = sizeof(char); - break; - case SQLDT_USHORT: bind->is_unsigned = 1; - case SQLDT_SHORT: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(short)); - buffer_len = sizeof(short); - break; - case SQLDT_UINT: bind->is_unsigned = 1; - case SQLDT_INT: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int)); - buffer_len = sizeof(int); - break; - case SQLDT_ULONG: bind->is_unsigned = 1; - case SQLDT_LONG: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(long)); - buffer_len = sizeof(long); - break; - case SQLDT_ULONGLONG: bind->is_unsigned = 1; - case SQLDT_LONGLONG: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int64)); - buffer_len = sizeof(int64); - break; - // floating point - case SQLDT_FLOAT: bind->buffer_type = MYSQL_TYPE_FLOAT; - buffer_len = 4; - break; - case SQLDT_DOUBLE: bind->buffer_type = MYSQL_TYPE_DOUBLE; - buffer_len = 8; - break; - // other - case SQLDT_STRING: - case SQLDT_ENUM: bind->buffer_type = MYSQL_TYPE_STRING; - break; - case SQLDT_BLOB: bind->buffer_type = MYSQL_TYPE_BLOB; - break; - default: - ShowDebug("Sql_P_BindSqlDataType: unsupported buffer type (%d)\n", buffer_type); - return SQL_ERROR; - } - bind->buffer = buffer; - bind->buffer_length = (unsigned long)buffer_len; - bind->length = out_length; - bind->is_null = (my_bool*)out_is_null; - return SQL_SUCCESS; +static int Sql_P_BindSqlDataType(MYSQL_BIND *bind, enum SqlDataType buffer_type, void *buffer, size_t buffer_len, unsigned long *out_length, int8 *out_is_null) +{ + memset(bind, 0, sizeof(MYSQL_BIND)); + switch (buffer_type) { + case SQLDT_NULL: + bind->buffer_type = MYSQL_TYPE_NULL; + buffer_len = 0;// FIXME length = ? [FlavioJS] + break; + // fixed size + case SQLDT_UINT8: + bind->is_unsigned = 1; + case SQLDT_INT8: + bind->buffer_type = MYSQL_TYPE_TINY; + buffer_len = 1; + break; + case SQLDT_UINT16: + bind->is_unsigned = 1; + case SQLDT_INT16: + bind->buffer_type = MYSQL_TYPE_SHORT; + buffer_len = 2; + break; + case SQLDT_UINT32: + bind->is_unsigned = 1; + case SQLDT_INT32: + bind->buffer_type = MYSQL_TYPE_LONG; + buffer_len = 4; + break; + case SQLDT_UINT64: + bind->is_unsigned = 1; + case SQLDT_INT64: + bind->buffer_type = MYSQL_TYPE_LONGLONG; + buffer_len = 8; + break; + // platform dependent size + case SQLDT_UCHAR: + bind->is_unsigned = 1; + case SQLDT_CHAR: + bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(char)); + buffer_len = sizeof(char); + break; + case SQLDT_USHORT: + bind->is_unsigned = 1; + case SQLDT_SHORT: + bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(short)); + buffer_len = sizeof(short); + break; + case SQLDT_UINT: + bind->is_unsigned = 1; + case SQLDT_INT: + bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int)); + buffer_len = sizeof(int); + break; + case SQLDT_ULONG: + bind->is_unsigned = 1; + case SQLDT_LONG: + bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(long)); + buffer_len = sizeof(long); + break; + case SQLDT_ULONGLONG: + bind->is_unsigned = 1; + case SQLDT_LONGLONG: + bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int64)); + buffer_len = sizeof(int64); + break; + // floating point + case SQLDT_FLOAT: + bind->buffer_type = MYSQL_TYPE_FLOAT; + buffer_len = 4; + break; + case SQLDT_DOUBLE: + bind->buffer_type = MYSQL_TYPE_DOUBLE; + buffer_len = 8; + break; + // other + case SQLDT_STRING: + case SQLDT_ENUM: + bind->buffer_type = MYSQL_TYPE_STRING; + break; + case SQLDT_BLOB: + bind->buffer_type = MYSQL_TYPE_BLOB; + break; + default: + ShowDebug("Sql_P_BindSqlDataType: unsupported buffer type (%d)\n", buffer_type); + return SQL_ERROR; + } + bind->buffer = buffer; + bind->buffer_length = (unsigned long)buffer_len; + bind->length = out_length; + bind->is_null = (my_bool *)out_is_null; + return SQL_SUCCESS; } @@ -521,38 +526,37 @@ static int Sql_P_BindSqlDataType(MYSQL_BIND* bind, enum SqlDataType buffer_type, /// Prints debug information about a field (type and length). /// /// @private -static void Sql_P_ShowDebugMysqlFieldInfo(const char* prefix, enum enum_field_types type, int is_unsigned, unsigned long length, const char* length_postfix) -{ - const char* sign = (is_unsigned ? "UNSIGNED " : ""); - const char* type_string; - switch( type ) - { - default: - ShowDebug("%stype=%s%u, length=%d\n", prefix, sign, type, length); - return; +static void Sql_P_ShowDebugMysqlFieldInfo(const char *prefix, enum enum_field_types type, int is_unsigned, unsigned long length, const char *length_postfix) +{ + const char *sign = (is_unsigned ? "UNSIGNED " : ""); + const char *type_string; + switch (type) { + default: + ShowDebug("%stype=%s%u, length=%d\n", prefix, sign, type, length); + return; #define SHOW_DEBUG_OF(x) case x: type_string = #x; break - SHOW_DEBUG_OF(MYSQL_TYPE_TINY); - SHOW_DEBUG_OF(MYSQL_TYPE_SHORT); - SHOW_DEBUG_OF(MYSQL_TYPE_LONG); - SHOW_DEBUG_OF(MYSQL_TYPE_INT24); - SHOW_DEBUG_OF(MYSQL_TYPE_LONGLONG); - SHOW_DEBUG_OF(MYSQL_TYPE_DECIMAL); - SHOW_DEBUG_OF(MYSQL_TYPE_FLOAT); - SHOW_DEBUG_OF(MYSQL_TYPE_DOUBLE); - SHOW_DEBUG_OF(MYSQL_TYPE_TIMESTAMP); - SHOW_DEBUG_OF(MYSQL_TYPE_DATE); - SHOW_DEBUG_OF(MYSQL_TYPE_TIME); - SHOW_DEBUG_OF(MYSQL_TYPE_DATETIME); - SHOW_DEBUG_OF(MYSQL_TYPE_YEAR); - SHOW_DEBUG_OF(MYSQL_TYPE_STRING); - SHOW_DEBUG_OF(MYSQL_TYPE_VAR_STRING); - SHOW_DEBUG_OF(MYSQL_TYPE_BLOB); - SHOW_DEBUG_OF(MYSQL_TYPE_SET); - SHOW_DEBUG_OF(MYSQL_TYPE_ENUM); - SHOW_DEBUG_OF(MYSQL_TYPE_NULL); + SHOW_DEBUG_OF(MYSQL_TYPE_TINY); + SHOW_DEBUG_OF(MYSQL_TYPE_SHORT); + SHOW_DEBUG_OF(MYSQL_TYPE_LONG); + SHOW_DEBUG_OF(MYSQL_TYPE_INT24); + SHOW_DEBUG_OF(MYSQL_TYPE_LONGLONG); + SHOW_DEBUG_OF(MYSQL_TYPE_DECIMAL); + SHOW_DEBUG_OF(MYSQL_TYPE_FLOAT); + SHOW_DEBUG_OF(MYSQL_TYPE_DOUBLE); + SHOW_DEBUG_OF(MYSQL_TYPE_TIMESTAMP); + SHOW_DEBUG_OF(MYSQL_TYPE_DATE); + SHOW_DEBUG_OF(MYSQL_TYPE_TIME); + SHOW_DEBUG_OF(MYSQL_TYPE_DATETIME); + SHOW_DEBUG_OF(MYSQL_TYPE_YEAR); + SHOW_DEBUG_OF(MYSQL_TYPE_STRING); + SHOW_DEBUG_OF(MYSQL_TYPE_VAR_STRING); + SHOW_DEBUG_OF(MYSQL_TYPE_BLOB); + SHOW_DEBUG_OF(MYSQL_TYPE_SET); + SHOW_DEBUG_OF(MYSQL_TYPE_ENUM); + SHOW_DEBUG_OF(MYSQL_TYPE_NULL); #undef SHOW_DEBUG_TYPE_OF - } - ShowDebug("%stype=%s%s, length=%d%s\n", prefix, sign, type_string, length, length_postfix); + } + ShowDebug("%stype=%s%s, length=%d%s\n", prefix, sign, type_string, length, length_postfix); } @@ -560,389 +564,369 @@ static void Sql_P_ShowDebugMysqlFieldInfo(const char* prefix, enum enum_field_ty /// Reports debug information about a truncated column. /// /// @private -static void SqlStmt_P_ShowDebugTruncatedColumn(SqlStmt* self, size_t i) +static void SqlStmt_P_ShowDebugTruncatedColumn(SqlStmt *self, size_t i) { - MYSQL_RES* meta; - MYSQL_FIELD* field; - MYSQL_BIND* column; + MYSQL_RES *meta; + MYSQL_FIELD *field; + MYSQL_BIND *column; - meta = mysql_stmt_result_metadata(self->stmt); - field = mysql_fetch_field_direct(meta, (unsigned int)i); - ShowSQL("DB error - data of field '%s' was truncated.\n", field->name); - ShowDebug("column - %lu\n", (unsigned long)i); - Sql_P_ShowDebugMysqlFieldInfo("data - ", field->type, field->flags&UNSIGNED_FLAG, self->column_lengths[i].length, ""); - column = &self->columns[i]; - if( column->buffer_type == MYSQL_TYPE_STRING ) - Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, "+1(nul-terminator)"); - else - Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, ""); - mysql_free_result(meta); + meta = mysql_stmt_result_metadata(self->stmt); + field = mysql_fetch_field_direct(meta, (unsigned int)i); + ShowSQL("DB error - data of field '%s' was truncated.\n", field->name); + ShowDebug("column - %lu\n", (unsigned long)i); + Sql_P_ShowDebugMysqlFieldInfo("data - ", field->type, field->flags&UNSIGNED_FLAG, self->column_lengths[i].length, ""); + column = &self->columns[i]; + if (column->buffer_type == MYSQL_TYPE_STRING) + Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, "+1(nul-terminator)"); + else + Sql_P_ShowDebugMysqlFieldInfo("buffer - ", column->buffer_type, column->is_unsigned, column->buffer_length, ""); + mysql_free_result(meta); } /// Allocates and initializes a new SqlStmt handle. -SqlStmt* SqlStmt_Malloc(Sql* sql) +SqlStmt *SqlStmt_Malloc(Sql *sql) { - SqlStmt* self; - MYSQL_STMT* stmt; + SqlStmt *self; + MYSQL_STMT *stmt; - if( sql == NULL ) - return NULL; + if (sql == NULL) + return NULL; - stmt = mysql_stmt_init(&sql->handle); - if( stmt == NULL ) - { - ShowSQL("DB error - %s\n", mysql_error(&sql->handle)); - return NULL; - } - CREATE(self, SqlStmt, 1); - StringBuf_Init(&self->buf); - self->stmt = stmt; - self->params = NULL; - self->columns = NULL; - self->column_lengths = NULL; - self->max_params = 0; - self->max_columns = 0; - self->bind_params = false; - self->bind_columns = false; + stmt = mysql_stmt_init(&sql->handle); + if (stmt == NULL) { + ShowSQL("DB error - %s\n", mysql_error(&sql->handle)); + return NULL; + } + CREATE(self, SqlStmt, 1); + StringBuf_Init(&self->buf); + self->stmt = stmt; + self->params = NULL; + self->columns = NULL; + self->column_lengths = NULL; + self->max_params = 0; + self->max_columns = 0; + self->bind_params = false; + self->bind_columns = false; - return self; + return self; } /// Prepares the statement. -int SqlStmt_Prepare(SqlStmt* self, const char* query, ...) +int SqlStmt_Prepare(SqlStmt *self, const char *query, ...) { - int res; - va_list args; + int res; + va_list args; - va_start(args, query); - res = SqlStmt_PrepareV(self, query, args); - va_end(args); + va_start(args, query); + res = SqlStmt_PrepareV(self, query, args); + va_end(args); - return res; + return res; } /// Prepares the statement. -int SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args) +int SqlStmt_PrepareV(SqlStmt *self, const char *query, va_list args) { - if( self == NULL ) - return SQL_ERROR; + if (self == NULL) + return SQL_ERROR; - SqlStmt_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_Vprintf(&self->buf, query, args); - if( mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) - { - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } - self->bind_params = false; + SqlStmt_FreeResult(self); + StringBuf_Clear(&self->buf); + StringBuf_Vprintf(&self->buf, query, args); + if (mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf))) { + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } + self->bind_params = false; - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Prepares the statement. -int SqlStmt_PrepareStr(SqlStmt* self, const char* query) +int SqlStmt_PrepareStr(SqlStmt *self, const char *query) { - if( self == NULL ) - return SQL_ERROR; + if (self == NULL) + return SQL_ERROR; - SqlStmt_FreeResult(self); - StringBuf_Clear(&self->buf); - StringBuf_AppendStr(&self->buf, query); - if( mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) ) - { - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } - self->bind_params = false; + SqlStmt_FreeResult(self); + StringBuf_Clear(&self->buf); + StringBuf_AppendStr(&self->buf, query); + if (mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf))) { + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } + self->bind_params = false; - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Returns the number of parameters in the prepared statement. -size_t SqlStmt_NumParams(SqlStmt* self) +size_t SqlStmt_NumParams(SqlStmt *self) { - if( self ) - return (size_t)mysql_stmt_param_count(self->stmt); - else - return 0; + if (self) + return (size_t)mysql_stmt_param_count(self->stmt); + else + return 0; } /// Binds a parameter to a buffer. -int SqlStmt_BindParam(SqlStmt* self, size_t idx, enum SqlDataType buffer_type, void* buffer, size_t buffer_len) +int SqlStmt_BindParam(SqlStmt *self, size_t idx, enum SqlDataType buffer_type, void *buffer, size_t buffer_len) { - if( self == NULL ) - return SQL_ERROR; + if (self == NULL) + return SQL_ERROR; - if( !self->bind_params ) - {// initialize the bindings - size_t i; - size_t count; + if (!self->bind_params) { + // initialize the bindings + size_t i; + size_t count; - count = SqlStmt_NumParams(self); - if( self->max_params < count ) - { - self->max_params = count; - RECREATE(self->params, MYSQL_BIND, count); - } - memset(self->params, 0, count*sizeof(MYSQL_BIND)); - for( i = 0; i < count; ++i ) - self->params[i].buffer_type = MYSQL_TYPE_NULL; - self->bind_params = true; - } - if( idx < self->max_params ) - return Sql_P_BindSqlDataType(self->params+idx, buffer_type, buffer, buffer_len, NULL, NULL); - else - return SQL_SUCCESS;// out of range - ignore + count = SqlStmt_NumParams(self); + if (self->max_params < count) { + self->max_params = count; + RECREATE(self->params, MYSQL_BIND, count); + } + memset(self->params, 0, count*sizeof(MYSQL_BIND)); + for (i = 0; i < count; ++i) + self->params[i].buffer_type = MYSQL_TYPE_NULL; + self->bind_params = true; + } + if (idx < self->max_params) + return Sql_P_BindSqlDataType(self->params+idx, buffer_type, buffer, buffer_len, NULL, NULL); + else + return SQL_SUCCESS;// out of range - ignore } /// Executes the prepared statement. -int SqlStmt_Execute(SqlStmt* self) +int SqlStmt_Execute(SqlStmt *self) { - if( self == NULL ) - return SQL_ERROR; + if (self == NULL) + return SQL_ERROR; - SqlStmt_FreeResult(self); - if( (self->bind_params && mysql_stmt_bind_param(self->stmt, self->params)) || - mysql_stmt_execute(self->stmt) ) - { - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } - self->bind_columns = false; - if( mysql_stmt_store_result(self->stmt) )// store all the data - { - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } + SqlStmt_FreeResult(self); + if ((self->bind_params && mysql_stmt_bind_param(self->stmt, self->params)) || + mysql_stmt_execute(self->stmt)) { + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } + self->bind_columns = false; + if (mysql_stmt_store_result(self->stmt)) { // store all the data + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE statement. -uint64 SqlStmt_LastInsertId(SqlStmt* self) +uint64 SqlStmt_LastInsertId(SqlStmt *self) { - if( self ) - return (uint64)mysql_stmt_insert_id(self->stmt); - else - return 0; + if (self) + return (uint64)mysql_stmt_insert_id(self->stmt); + else + return 0; } /// Returns the number of columns in each row of the result. -size_t SqlStmt_NumColumns(SqlStmt* self) +size_t SqlStmt_NumColumns(SqlStmt *self) { - if( self ) - return (size_t)mysql_stmt_field_count(self->stmt); - else - return 0; + if (self) + return (size_t)mysql_stmt_field_count(self->stmt); + else + return 0; } /// Binds the result of a column to a buffer. -int SqlStmt_BindColumn(SqlStmt* self, size_t idx, enum SqlDataType buffer_type, void* buffer, size_t buffer_len, uint32* out_length, int8* out_is_null) -{ - if( self == NULL ) - return SQL_ERROR; - - if( buffer_type == SQLDT_STRING || buffer_type == SQLDT_ENUM ) - { - if( buffer_len < 1 ) - { - ShowDebug("SqlStmt_BindColumn: buffer_len(%d) is too small, no room for the nul-terminator\n", buffer_len); - return SQL_ERROR; - } - --buffer_len;// nul-terminator - } - if( !self->bind_columns ) - {// initialize the bindings - size_t i; - size_t cols; - - cols = SqlStmt_NumColumns(self); - if( self->max_columns < cols ) - { - self->max_columns = cols; - RECREATE(self->columns, MYSQL_BIND, cols); - RECREATE(self->column_lengths, s_column_length, cols); - } - memset(self->columns, 0, cols*sizeof(MYSQL_BIND)); - memset(self->column_lengths, 0, cols*sizeof(s_column_length)); - for( i = 0; i < cols; ++i ) - self->columns[i].buffer_type = MYSQL_TYPE_NULL; - self->bind_columns = true; - } - if( idx < self->max_columns ) - { - self->column_lengths[idx].out_length = out_length; - return Sql_P_BindSqlDataType(self->columns+idx, buffer_type, buffer, buffer_len, &self->column_lengths[idx].length, out_is_null); - } - else - { - return SQL_SUCCESS;// out of range - ignore - } +int SqlStmt_BindColumn(SqlStmt *self, size_t idx, enum SqlDataType buffer_type, void *buffer, size_t buffer_len, uint32 *out_length, int8 *out_is_null) +{ + if (self == NULL) + return SQL_ERROR; + + if (buffer_type == SQLDT_STRING || buffer_type == SQLDT_ENUM) { + if (buffer_len < 1) { + ShowDebug("SqlStmt_BindColumn: buffer_len(%d) is too small, no room for the nul-terminator\n", buffer_len); + return SQL_ERROR; + } + --buffer_len;// nul-terminator + } + if (!self->bind_columns) { + // initialize the bindings + size_t i; + size_t cols; + + cols = SqlStmt_NumColumns(self); + if (self->max_columns < cols) { + self->max_columns = cols; + RECREATE(self->columns, MYSQL_BIND, cols); + RECREATE(self->column_lengths, s_column_length, cols); + } + memset(self->columns, 0, cols*sizeof(MYSQL_BIND)); + memset(self->column_lengths, 0, cols*sizeof(s_column_length)); + for (i = 0; i < cols; ++i) + self->columns[i].buffer_type = MYSQL_TYPE_NULL; + self->bind_columns = true; + } + if (idx < self->max_columns) { + self->column_lengths[idx].out_length = out_length; + return Sql_P_BindSqlDataType(self->columns+idx, buffer_type, buffer, buffer_len, &self->column_lengths[idx].length, out_is_null); + } else { + return SQL_SUCCESS;// out of range - ignore + } } /// Returns the number of rows in the result. -uint64 SqlStmt_NumRows(SqlStmt* self) +uint64 SqlStmt_NumRows(SqlStmt *self) { - if( self ) - return (uint64)mysql_stmt_num_rows(self->stmt); - else - return 0; + if (self) + return (uint64)mysql_stmt_num_rows(self->stmt); + else + return 0; } /// Fetches the next row. -int SqlStmt_NextRow(SqlStmt* self) -{ - int err; - size_t i; - size_t cols; - MYSQL_BIND* column; - unsigned long length; - - if( self == NULL ) - return SQL_ERROR; - - // bind columns - if( self->bind_columns && mysql_stmt_bind_result(self->stmt, self->columns) ) - err = 1;// error binding columns - else - err = mysql_stmt_fetch(self->stmt);// fetch row - - // check for errors - if( err == MYSQL_NO_DATA ) - return SQL_NO_DATA; +int SqlStmt_NextRow(SqlStmt *self) +{ + int err; + size_t i; + size_t cols; + MYSQL_BIND *column; + unsigned long length; + + if (self == NULL) + return SQL_ERROR; + + // bind columns + if (self->bind_columns && mysql_stmt_bind_result(self->stmt, self->columns)) + err = 1;// error binding columns + else + err = mysql_stmt_fetch(self->stmt);// fetch row + + // check for errors + if (err == MYSQL_NO_DATA) + return SQL_NO_DATA; #if defined(MYSQL_DATA_TRUNCATED) - // MySQL 5.0/5.1 defines and returns MYSQL_DATA_TRUNCATED [FlavioJS] - if( err == MYSQL_DATA_TRUNCATED ) - { - my_bool truncated; - - if( !self->bind_columns ) - { - ShowSQL("DB error - data truncated (unknown source, columns are not bound)\n"); - return SQL_ERROR; - } - - // find truncated column - cols = SqlStmt_NumColumns(self); - for( i = 0; i < cols; ++i ) - { - column = &self->columns[i]; - column->error = &truncated; - mysql_stmt_fetch_column(self->stmt, column, (unsigned int)i, 0); - column->error = NULL; - if( truncated ) - {// report truncated column - SqlStmt_P_ShowDebugTruncatedColumn(self, i); - return SQL_ERROR; - } - } - ShowSQL("DB error - data truncated (unknown source)\n"); - return SQL_ERROR; - } + // MySQL 5.0/5.1 defines and returns MYSQL_DATA_TRUNCATED [FlavioJS] + if (err == MYSQL_DATA_TRUNCATED) { + my_bool truncated; + + if (!self->bind_columns) { + ShowSQL("DB error - data truncated (unknown source, columns are not bound)\n"); + return SQL_ERROR; + } + + // find truncated column + cols = SqlStmt_NumColumns(self); + for (i = 0; i < cols; ++i) { + column = &self->columns[i]; + column->error = &truncated; + mysql_stmt_fetch_column(self->stmt, column, (unsigned int)i, 0); + column->error = NULL; + if (truncated) { + // report truncated column + SqlStmt_P_ShowDebugTruncatedColumn(self, i); + return SQL_ERROR; + } + } + ShowSQL("DB error - data truncated (unknown source)\n"); + return SQL_ERROR; + } #endif - if( err ) - { - ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); - return SQL_ERROR; - } - - // propagate column lengths and clear unused parts of string/enum/blob buffers - cols = SqlStmt_NumColumns(self); - for( i = 0; i < cols; ++i ) - { - length = self->column_lengths[i].length; - column = &self->columns[i]; + if (err) { + ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt)); + return SQL_ERROR; + } + + // propagate column lengths and clear unused parts of string/enum/blob buffers + cols = SqlStmt_NumColumns(self); + for (i = 0; i < cols; ++i) { + length = self->column_lengths[i].length; + column = &self->columns[i]; #if !defined(MYSQL_DATA_TRUNCATED) - // MySQL 4.1/(below?) returns success even if data is truncated, so we test truncation manually [FlavioJS] - if( column->buffer_length < length ) - {// report truncated column - if( column->buffer_type == MYSQL_TYPE_STRING || column->buffer_type == MYSQL_TYPE_BLOB ) - {// string/enum/blob column - SqlStmt_P_ShowDebugTruncatedColumn(self, i); - return SQL_ERROR; - } - // FIXME numeric types and null [FlavioJS] - } + // MySQL 4.1/(below?) returns success even if data is truncated, so we test truncation manually [FlavioJS] + if (column->buffer_length < length) { + // report truncated column + if (column->buffer_type == MYSQL_TYPE_STRING || column->buffer_type == MYSQL_TYPE_BLOB) { + // string/enum/blob column + SqlStmt_P_ShowDebugTruncatedColumn(self, i); + return SQL_ERROR; + } + // FIXME numeric types and null [FlavioJS] + } #endif - if( self->column_lengths[i].out_length ) - *self->column_lengths[i].out_length = (uint32)length; - if( column->buffer_type == MYSQL_TYPE_STRING ) - {// clear unused part of the string/enum buffer (and nul-terminate) - memset((char*)column->buffer + length, 0, column->buffer_length - length + 1); - } - else if( column->buffer_type == MYSQL_TYPE_BLOB && length < column->buffer_length ) - {// clear unused part of the blob buffer - memset((char*)column->buffer + length, 0, column->buffer_length - length); - } - } + if (self->column_lengths[i].out_length) + *self->column_lengths[i].out_length = (uint32)length; + if (column->buffer_type == MYSQL_TYPE_STRING) { + // clear unused part of the string/enum buffer (and nul-terminate) + memset((char *)column->buffer + length, 0, column->buffer_length - length + 1); + } else if (column->buffer_type == MYSQL_TYPE_BLOB && length < column->buffer_length) { + // clear unused part of the blob buffer + memset((char *)column->buffer + length, 0, column->buffer_length - length); + } + } - return SQL_SUCCESS; + return SQL_SUCCESS; } /// Frees the result of the statement execution. -void SqlStmt_FreeResult(SqlStmt* self) +void SqlStmt_FreeResult(SqlStmt *self) { - if( self ) - mysql_stmt_free_result(self->stmt); + if (self) + mysql_stmt_free_result(self->stmt); } /// Shows debug information (with statement). -void SqlStmt_ShowDebug_(SqlStmt* self, const char* debug_file, const unsigned long debug_line) +void SqlStmt_ShowDebug_(SqlStmt *self, const char *debug_file, const unsigned long debug_line) { - if( self == NULL ) - ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); - else if( StringBuf_Length(&self->buf) > 0 ) - ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); - else - ShowDebug("at %s:%lu\n", debug_file, debug_line); + if (self == NULL) + ShowDebug("at %s:%lu - self is NULL\n", debug_file, debug_line); + else if (StringBuf_Length(&self->buf) > 0) + ShowDebug("at %s:%lu - %s\n", debug_file, debug_line, StringBuf_Value(&self->buf)); + else + ShowDebug("at %s:%lu\n", debug_file, debug_line); } /// Frees a SqlStmt returned by SqlStmt_Malloc. -void SqlStmt_Free(SqlStmt* self) -{ - if( self ) - { - SqlStmt_FreeResult(self); - StringBuf_Destroy(&self->buf); - mysql_stmt_close(self->stmt); - if( self->params ) - aFree(self->params); - if( self->columns ) - { - aFree(self->columns); - aFree(self->column_lengths); - } - aFree(self); - } +void SqlStmt_Free(SqlStmt *self) +{ + if (self) { + SqlStmt_FreeResult(self); + StringBuf_Destroy(&self->buf); + mysql_stmt_close(self->stmt); + if (self->params) + aFree(self->params); + if (self->columns) { + aFree(self->columns); + aFree(self->column_lengths); + } + aFree(self); + } } diff --git a/src/common/sql.h b/src/common/sql.h index 898e2c778..4534061e0 100644 --- a/src/common/sql.h +++ b/src/common/sql.h @@ -21,39 +21,38 @@ /// Data type identifier. /// String, enum and blob data types need the buffer length specified. -enum SqlDataType -{ - SQLDT_NULL, - // fixed size - SQLDT_INT8, - SQLDT_INT16, - SQLDT_INT32, - SQLDT_INT64, - SQLDT_UINT8, - SQLDT_UINT16, - SQLDT_UINT32, - SQLDT_UINT64, - // platform dependent size - SQLDT_CHAR, - SQLDT_SHORT, - SQLDT_INT, - SQLDT_LONG, - SQLDT_LONGLONG, - SQLDT_UCHAR, - SQLDT_USHORT, - SQLDT_UINT, - SQLDT_ULONG, - SQLDT_ULONGLONG, - // floating point - SQLDT_FLOAT, - SQLDT_DOUBLE, - // other - SQLDT_STRING, - SQLDT_ENUM, - // Note: An ENUM is a string with restricted values. When an invalid value - // is inserted, it is saved as an empty string (numerical value 0). - SQLDT_BLOB, - SQLDT_LASTID +enum SqlDataType { + SQLDT_NULL, + // fixed size + SQLDT_INT8, + SQLDT_INT16, + SQLDT_INT32, + SQLDT_INT64, + SQLDT_UINT8, + SQLDT_UINT16, + SQLDT_UINT32, + SQLDT_UINT64, + // platform dependent size + SQLDT_CHAR, + SQLDT_SHORT, + SQLDT_INT, + SQLDT_LONG, + SQLDT_LONGLONG, + SQLDT_UCHAR, + SQLDT_USHORT, + SQLDT_UINT, + SQLDT_ULONG, + SQLDT_ULONGLONG, + // floating point + SQLDT_FLOAT, + SQLDT_DOUBLE, + // other + SQLDT_STRING, + SQLDT_ENUM, + // Note: An ENUM is a string with restricted values. When an invalid value + // is inserted, it is saved as an empty string (numerical value 0). + SQLDT_BLOB, + SQLDT_LASTID }; struct Sql;// Sql handle (private access) @@ -65,14 +64,14 @@ typedef struct SqlStmt SqlStmt; /// Allocates and initializes a new Sql handle. -struct Sql* Sql_Malloc(void); +struct Sql *Sql_Malloc(void); /// Establishes a connection. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_Connect(Sql* self, const char* user, const char* passwd, const char* host, uint16 port, const char* db); +int Sql_Connect(Sql *self, const char *user, const char *passwd, const char *host, uint16 port, const char *db); @@ -80,7 +79,7 @@ int Sql_Connect(Sql* self, const char* user, const char* passwd, const char* hos /// Retrieves the timeout of the connection. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_GetTimeout(Sql* self, uint32* out_timeout); +int Sql_GetTimeout(Sql *self, uint32 *out_timeout); @@ -88,7 +87,7 @@ int Sql_GetTimeout(Sql* self, uint32* out_timeout); /// Retrieves the name of the columns of a table into out_buf, with the separator after each name. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_GetColumnNames(Sql* self, const char* table, char* out_buf, size_t buf_len, char sep); +int Sql_GetColumnNames(Sql *self, const char *table, char *out_buf, size_t buf_len, char sep); @@ -96,14 +95,14 @@ int Sql_GetColumnNames(Sql* self, const char* table, char* out_buf, size_t buf_l /// Changes the encoding of the connection. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_SetEncoding(Sql* self, const char* encoding); +int Sql_SetEncoding(Sql *self, const char *encoding); /// Pings the connection. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_Ping(Sql* self); +int Sql_Ping(Sql *self); @@ -111,7 +110,7 @@ int Sql_Ping(Sql* self); /// The output buffer must be at least strlen(from)*2+1 in size. /// /// @return The size of the escaped string -size_t Sql_EscapeString(Sql* self, char* out_to, const char* from); +size_t Sql_EscapeString(Sql *self, char *out_to, const char *from); @@ -119,7 +118,7 @@ size_t Sql_EscapeString(Sql* self, char* out_to, const char* from); /// The output buffer must be at least from_len*2+1 in size. /// /// @return The size of the escaped string -size_t Sql_EscapeStringLen(Sql* self, char* out_to, const char* from, size_t from_len); +size_t Sql_EscapeStringLen(Sql *self, char *out_to, const char *from, size_t from_len); @@ -128,7 +127,7 @@ size_t Sql_EscapeStringLen(Sql* self, char* out_to, const char* from, size_t fro /// The query is constructed as if it was sprintf. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_Query(Sql* self, const char* query, ...); +int Sql_Query(Sql *self, const char *query, ...); @@ -137,7 +136,7 @@ int Sql_Query(Sql* self, const char* query, ...); /// The query is constructed as if it was svprintf. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_QueryV(Sql* self, const char* query, va_list args); +int Sql_QueryV(Sql *self, const char *query, va_list args); @@ -146,28 +145,28 @@ int Sql_QueryV(Sql* self, const char* query, va_list args); /// The query is used directly. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_QueryStr(Sql* self, const char* query); +int Sql_QueryStr(Sql *self, const char *query); /// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE query. /// /// @return Value of the auto-increment column -uint64 Sql_LastInsertId(Sql* self); +uint64 Sql_LastInsertId(Sql *self); /// Returns the number of columns in each row of the result. /// /// @return Number of columns -uint32 Sql_NumColumns(Sql* self); +uint32 Sql_NumColumns(Sql *self); /// Returns the number of rows in the result. /// /// @return Number of rows -uint64 Sql_NumRows(Sql* self); +uint64 Sql_NumRows(Sql *self); @@ -175,7 +174,7 @@ uint64 Sql_NumRows(Sql* self); /// The data of the previous row is no longer valid. /// /// @return SQL_SUCCESS, SQL_ERROR or SQL_NO_DATA -int Sql_NextRow(Sql* self); +int Sql_NextRow(Sql *self); @@ -183,12 +182,12 @@ int Sql_NextRow(Sql* self); /// The data remains valid until the next row is fetched or the result is freed. /// /// @return SQL_SUCCESS or SQL_ERROR -int Sql_GetData(Sql* self, size_t col, char** out_buf, size_t* out_len); +int Sql_GetData(Sql *self, size_t col, char **out_buf, size_t *out_len); /// Frees the result of the query. -void Sql_FreeResult(Sql* self); +void Sql_FreeResult(Sql *self); @@ -198,22 +197,22 @@ void Sql_FreeResult(Sql* self); #define Sql_ShowDebug(self) Sql_ShowDebug_(self, __FILE__, __LINE__) #endif /// Shows debug information (last query). -void Sql_ShowDebug_(Sql* self, const char* debug_file, const unsigned long debug_line); +void Sql_ShowDebug_(Sql *self, const char *debug_file, const unsigned long debug_line); /// Frees a Sql handle returned by Sql_Malloc. -void Sql_Free(Sql* self); +void Sql_Free(Sql *self); /////////////////////////////////////////////////////////////////////////////// // Prepared Statements /////////////////////////////////////////////////////////////////////////////// -// Parameters are placed in the statement by embedding question mark ('?') +// Parameters are placed in the statement by embedding question mark ('?') // characters into the query at the appropriate positions. // The markers are legal only in places where they represent data. -// The markers cannot be inside quotes. Quotes will be added automatically +// The markers cannot be inside quotes. Quotes will be added automatically // when they are required. // // example queries with parameters: @@ -227,7 +226,7 @@ void Sql_Free(Sql* self); /// Queries in Sql and SqlStmt are independent and don't affect each other. /// /// @return SqlStmt handle or NULL if an error occured -struct SqlStmt* SqlStmt_Malloc(Sql* sql); +struct SqlStmt *SqlStmt_Malloc(Sql *sql); @@ -236,7 +235,7 @@ struct SqlStmt* SqlStmt_Malloc(Sql* sql); /// The query is constructed as if it was sprintf. /// /// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_Prepare(SqlStmt* self, const char* query, ...); +int SqlStmt_Prepare(SqlStmt *self, const char *query, ...); @@ -245,7 +244,7 @@ int SqlStmt_Prepare(SqlStmt* self, const char* query, ...); /// The query is constructed as if it was svprintf. /// /// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args); +int SqlStmt_PrepareV(SqlStmt *self, const char *query, va_list args); @@ -254,14 +253,14 @@ int SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args); /// The query is used directly. /// /// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_PrepareStr(SqlStmt* self, const char* query); +int SqlStmt_PrepareStr(SqlStmt *self, const char *query); /// Returns the number of parameters in the prepared statement. /// /// @return Number or paramenters -size_t SqlStmt_NumParams(SqlStmt* self); +size_t SqlStmt_NumParams(SqlStmt *self); @@ -270,7 +269,7 @@ size_t SqlStmt_NumParams(SqlStmt* self); /// All parameters should have bindings. /// /// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_BindParam(SqlStmt* self, size_t idx, SqlDataType buffer_type, void* buffer, size_t buffer_len); +int SqlStmt_BindParam(SqlStmt *self, size_t idx, SqlDataType buffer_type, void *buffer, size_t buffer_len); @@ -278,38 +277,38 @@ int SqlStmt_BindParam(SqlStmt* self, size_t idx, SqlDataType buffer_type, void* /// Any previous result is freed and all column bindings are removed. /// /// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_Execute(SqlStmt* self); +int SqlStmt_Execute(SqlStmt *self); /// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE statement. /// /// @return Value of the auto-increment column -uint64 SqlStmt_LastInsertId(SqlStmt* self); +uint64 SqlStmt_LastInsertId(SqlStmt *self); /// Returns the number of columns in each row of the result. /// /// @return Number of columns -size_t SqlStmt_NumColumns(SqlStmt* self); +size_t SqlStmt_NumColumns(SqlStmt *self); /// Binds the result of a column to a buffer. /// The buffer will be filled with data when the next row is fetched. -/// For string/enum buffer types there has to be enough space for the data +/// For string/enum buffer types there has to be enough space for the data /// and the nul-terminator (an extra byte). /// /// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_BindColumn(SqlStmt* self, size_t idx, SqlDataType buffer_type, void* buffer, size_t buffer_len, uint32* out_length, int8* out_is_null); +int SqlStmt_BindColumn(SqlStmt *self, size_t idx, SqlDataType buffer_type, void *buffer, size_t buffer_len, uint32 *out_length, int8 *out_is_null); /// Returns the number of rows in the result. /// /// @return Number of rows -uint64 SqlStmt_NumRows(SqlStmt* self); +uint64 SqlStmt_NumRows(SqlStmt *self); @@ -317,12 +316,12 @@ uint64 SqlStmt_NumRows(SqlStmt* self); /// All column bindings will be filled with data. /// /// @return SQL_SUCCESS, SQL_ERROR or SQL_NO_DATA -int SqlStmt_NextRow(SqlStmt* self); +int SqlStmt_NextRow(SqlStmt *self); /// Frees the result of the statement execution. -void SqlStmt_FreeResult(SqlStmt* self); +void SqlStmt_FreeResult(SqlStmt *self); @@ -332,12 +331,12 @@ void SqlStmt_FreeResult(SqlStmt* self); #define SqlStmt_ShowDebug(self) SqlStmt_ShowDebug_(self, __FILE__, __LINE__) #endif /// Shows debug information (with statement). -void SqlStmt_ShowDebug_(SqlStmt* self, const char* debug_file, const unsigned long debug_line); +void SqlStmt_ShowDebug_(SqlStmt *self, const char *debug_file, const unsigned long debug_line); /// Frees a SqlStmt returned by SqlStmt_Malloc. -void SqlStmt_Free(SqlStmt* self); +void SqlStmt_Free(SqlStmt *self); diff --git a/src/common/strlib.c b/src/common/strlib.c index dfacbf136..89aac3b40 100644 --- a/src/common/strlib.c +++ b/src/common/strlib.c @@ -14,360 +14,348 @@ #define J_MAX_MALLOC_SIZE 65535 // escapes a string in-place (' -> \' , \ -> \\ , % -> _) -char* jstrescape (char* pt) +char *jstrescape(char *pt) { - //copy from here - char *ptr; - int i = 0, j = 0; - - //copy string to temporary - CREATE(ptr, char, J_MAX_MALLOC_SIZE); - strcpy(ptr,pt); - - while (ptr[i] != '\0') { - switch (ptr[i]) { - case '\'': - pt[j++] = '\\'; - pt[j++] = ptr[i++]; - break; - case '\\': - pt[j++] = '\\'; - pt[j++] = ptr[i++]; - break; - case '%': - pt[j++] = '_'; i++; - break; - default: - pt[j++] = ptr[i++]; - } - } - pt[j++] = '\0'; - aFree(ptr); - return pt; + //copy from here + char *ptr; + int i = 0, j = 0; + + //copy string to temporary + CREATE(ptr, char, J_MAX_MALLOC_SIZE); + strcpy(ptr,pt); + + while (ptr[i] != '\0') { + switch (ptr[i]) { + case '\'': + pt[j++] = '\\'; + pt[j++] = ptr[i++]; + break; + case '\\': + pt[j++] = '\\'; + pt[j++] = ptr[i++]; + break; + case '%': + pt[j++] = '_'; + i++; + break; + default: + pt[j++] = ptr[i++]; + } + } + pt[j++] = '\0'; + aFree(ptr); + return pt; } // escapes a string into a provided buffer -char* jstrescapecpy (char* pt, const char* spt) +char *jstrescapecpy(char *pt, const char *spt) { - //copy from here - //WARNING: Target string pt should be able to hold strlen(spt)*2, as each time - //a escape character is found, the target's final length increases! [Skotlex] - int i =0, j=0; - - if (!spt) { //Return an empty string [Skotlex] - pt[0] = '\0'; - return &pt[0]; - } - - while (spt[i] != '\0') { - switch (spt[i]) { - case '\'': - pt[j++] = '\\'; - pt[j++] = spt[i++]; - break; - case '\\': - pt[j++] = '\\'; - pt[j++] = spt[i++]; - break; - case '%': - pt[j++] = '_'; i++; - break; - default: - pt[j++] = spt[i++]; - } - } - pt[j++] = '\0'; - return &pt[0]; + //copy from here + //WARNING: Target string pt should be able to hold strlen(spt)*2, as each time + //a escape character is found, the target's final length increases! [Skotlex] + int i =0, j=0; + + if (!spt) { //Return an empty string [Skotlex] + pt[0] = '\0'; + return &pt[0]; + } + + while (spt[i] != '\0') { + switch (spt[i]) { + case '\'': + pt[j++] = '\\'; + pt[j++] = spt[i++]; + break; + case '\\': + pt[j++] = '\\'; + pt[j++] = spt[i++]; + break; + case '%': + pt[j++] = '_'; + i++; + break; + default: + pt[j++] = spt[i++]; + } + } + pt[j++] = '\0'; + return &pt[0]; } // escapes exactly 'size' bytes of a string into a provided buffer -int jmemescapecpy (char* pt, const char* spt, int size) +int jmemescapecpy(char *pt, const char *spt, int size) { - //copy from here - int i =0, j=0; - - while (i < size) { - switch (spt[i]) { - case '\'': - pt[j++] = '\\'; - pt[j++] = spt[i++]; - break; - case '\\': - pt[j++] = '\\'; - pt[j++] = spt[i++]; - break; - case '%': - pt[j++] = '_'; i++; - break; - default: - pt[j++] = spt[i++]; - } - } - // copy size is 0 ~ (j-1) - return j; + //copy from here + int i =0, j=0; + + while (i < size) { + switch (spt[i]) { + case '\'': + pt[j++] = '\\'; + pt[j++] = spt[i++]; + break; + case '\\': + pt[j++] = '\\'; + pt[j++] = spt[i++]; + break; + case '%': + pt[j++] = '_'; + i++; + break; + default: + pt[j++] = spt[i++]; + } + } + // copy size is 0 ~ (j-1) + return j; } // Function to suppress control characters in a string. -int remove_control_chars(char* str) +int remove_control_chars(char *str) { - int i; - int change = 0; + int i; + int change = 0; - for(i = 0; str[i]; i++) { - if (ISCNTRL(str[i])) { - str[i] = '_'; - change = 1; - } - } + for (i = 0; str[i]; i++) { + if (ISCNTRL(str[i])) { + str[i] = '_'; + change = 1; + } + } - return change; + return change; } // Removes characters identified by ISSPACE from the start and end of the string // NOTE: make sure the string is not const!! -char* trim(char* str) +char *trim(char *str) { - size_t start; - size_t end; - - if( str == NULL ) - return str; - - // get start position - for( start = 0; str[start] && ISSPACE(str[start]); ++start ) - ; - // get end position - for( end = strlen(str); start < end && str[end-1] && ISSPACE(str[end-1]); --end ) - ; - // trim - if( start == end ) - *str = '\0';// empty string - else - {// move string with nul terminator - str[end] = '\0'; - memmove(str,str+start,end-start+1); - } - return str; + size_t start; + size_t end; + + if (str == NULL) + return str; + + // get start position + for (start = 0; str[start] && ISSPACE(str[start]); ++start) + ; + // get end position + for (end = strlen(str); start < end && str[end-1] && ISSPACE(str[end-1]); --end) + ; + // trim + if (start == end) + *str = '\0';// empty string + else { + // move string with nul terminator + str[end] = '\0'; + memmove(str,str+start,end-start+1); + } + return str; } // Converts one or more consecutive occurences of the delimiters into a single space // and removes such occurences from the beginning and end of string // NOTE: make sure the string is not const!! -char* normalize_name(char* str,const char* delims) +char *normalize_name(char *str,const char *delims) { - char* in = str; - char* out = str; - int put_space = 0; - - if( str == NULL || delims == NULL ) - return str; - - // trim start of string - while( *in && strchr(delims,*in) ) - ++in; - while( *in ) - { - if( put_space ) - {// replace trim characters with a single space - *out = ' '; - ++out; - } - // copy non trim characters - while( *in && !strchr(delims,*in) ) - { - *out = *in; - ++out; - ++in; - } - // skip trim characters - while( *in && strchr(delims,*in) ) - ++in; - put_space = 1; - } - *out = '\0'; - return str; + char *in = str; + char *out = str; + int put_space = 0; + + if (str == NULL || delims == NULL) + return str; + + // trim start of string + while (*in && strchr(delims,*in)) + ++in; + while (*in) { + if (put_space) { + // replace trim characters with a single space + *out = ' '; + ++out; + } + // copy non trim characters + while (*in && !strchr(delims,*in)) { + *out = *in; + ++out; + ++in; + } + // skip trim characters + while (*in && strchr(delims,*in)) + ++in; + put_space = 1; + } + *out = '\0'; + return str; } -//stristr: Case insensitive version of strstr, code taken from +//stristr: Case insensitive version of strstr, code taken from //http://www.daniweb.com/code/snippet313.html, Dave Sinkula // -const char* stristr(const char* haystack, const char* needle) +const char *stristr(const char *haystack, const char *needle) { - if ( !*needle ) - { - return haystack; - } - for ( ; *haystack; ++haystack ) - { - if ( TOUPPER(*haystack) == TOUPPER(*needle) ) - { - // matched starting char -- loop through remaining chars - const char *h, *n; - for ( h = haystack, n = needle; *h && *n; ++h, ++n ) - { - if ( TOUPPER(*h) != TOUPPER(*n) ) - { - break; - } - } - if ( !*n ) // matched all of 'needle' to null termination - { - return haystack; // return the start of the match - } - } - } - return 0; + if (!*needle) { + return haystack; + } + for (; *haystack; ++haystack) { + if (TOUPPER(*haystack) == TOUPPER(*needle)) { + // matched starting char -- loop through remaining chars + const char *h, *n; + for (h = haystack, n = needle; *h && *n; ++h, ++n) { + if (TOUPPER(*h) != TOUPPER(*n)) { + break; + } + } + if (!*n) { // matched all of 'needle' to null termination + return haystack; // return the start of the match + } + } + } + return 0; } #ifdef __WIN32 -char* _strtok_r(char *s1, const char *s2, char **lasts) +char *_strtok_r(char *s1, const char *s2, char **lasts) { - char *ret; - - if (s1 == NULL) - s1 = *lasts; - while(*s1 && strchr(s2, *s1)) - ++s1; - if(*s1 == '\0') - return NULL; - ret = s1; - while(*s1 && !strchr(s2, *s1)) - ++s1; - if(*s1) - *s1++ = '\0'; - *lasts = s1; - return ret; + char *ret; + + if (s1 == NULL) + s1 = *lasts; + while (*s1 && strchr(s2, *s1)) + ++s1; + if (*s1 == '\0') + return NULL; + ret = s1; + while (*s1 && !strchr(s2, *s1)) + ++s1; + if (*s1) + *s1++ = '\0'; + *lasts = s1; + return ret; } #endif #if !(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN) /* Find the length of STRING, but scan at most MAXLEN characters. If no '\0' terminator is found in that many characters, return MAXLEN. */ -size_t strnlen (const char* string, size_t maxlen) +size_t strnlen(const char *string, size_t maxlen) { - const char* end = (const char*)memchr(string, '\0', maxlen); - return end ? (size_t) (end - string) : maxlen; + const char *end = (const char *)memchr(string, '\0', maxlen); + return end ? (size_t)(end - string) : maxlen; } #endif #if defined(WIN32) && defined(_MSC_VER) && _MSC_VER <= 1200 -uint64 strtoull(const char* str, char** endptr, int base) +uint64 strtoull(const char *str, char **endptr, int base) { - uint64 result; - int count; - int n; - - if( base == 0 ) - { - if( str[0] == '0' && (str[1] == 'x' || str[1] == 'X') ) - base = 16; - else - if( str[0] == '0' ) - base = 8; - else - base = 10; - } - - if( base == 8 ) - count = sscanf(str, "%I64o%n", &result, &n); - else - if( base == 10 ) - count = sscanf(str, "%I64u%n", &result, &n); - else - if( base == 16 ) - count = sscanf(str, "%I64x%n", &result, &n); - else - count = 0; // fail - - if( count < 1 ) - { - errno = EINVAL; - result = 0; - n = 0; - } - - if( endptr ) - *endptr = (char*)str + n; - - return result; + uint64 result; + int count; + int n; + + if (base == 0) { + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) + base = 16; + else if (str[0] == '0') + base = 8; + else + base = 10; + } + + if (base == 8) + count = sscanf(str, "%I64o%n", &result, &n); + else if (base == 10) + count = sscanf(str, "%I64u%n", &result, &n); + else if (base == 16) + count = sscanf(str, "%I64x%n", &result, &n); + else + count = 0; // fail + + if (count < 1) { + errno = EINVAL; + result = 0; + n = 0; + } + + if (endptr) + *endptr = (char *)str + n; + + return result; } #endif //---------------------------------------------------- // E-mail check: return 0 (not correct) or 1 (valid). //---------------------------------------------------- -int e_mail_check(char* email) +int e_mail_check(char *email) { - char ch; - char* last_arobas; - size_t len = strlen(email); + char ch; + char *last_arobas; + size_t len = strlen(email); - // athena limits - if (len < 3 || len > 39) - return 0; + // athena limits + if (len < 3 || len > 39) + return 0; - // part of RFC limits (official reference of e-mail description) - if (strchr(email, '@') == NULL || email[len-1] == '@') - return 0; + // part of RFC limits (official reference of e-mail description) + if (strchr(email, '@') == NULL || email[len-1] == '@') + return 0; - if (email[len-1] == '.') - return 0; + if (email[len-1] == '.') + return 0; - last_arobas = strrchr(email, '@'); + last_arobas = strrchr(email, '@'); - if (strstr(last_arobas, "@.") != NULL || strstr(last_arobas, "..") != NULL) - return 0; + if (strstr(last_arobas, "@.") != NULL || strstr(last_arobas, "..") != NULL) + return 0; - for(ch = 1; ch < 32; ch++) - if (strchr(last_arobas, ch) != NULL) - return 0; + for (ch = 1; ch < 32; ch++) + if (strchr(last_arobas, ch) != NULL) + return 0; - if (strchr(last_arobas, ' ') != NULL || strchr(last_arobas, ';') != NULL) - return 0; + if (strchr(last_arobas, ' ') != NULL || strchr(last_arobas, ';') != NULL) + return 0; - // all correct - return 1; + // all correct + return 1; } //-------------------------------------------------- // Return numerical value of a switch configuration // on/off, english, fran軋is, deutsch, espaol //-------------------------------------------------- -int config_switch(const char* str) +int config_switch(const char *str) { - if (strcmpi(str, "on") == 0 || strcmpi(str, "yes") == 0 || strcmpi(str, "oui") == 0 || strcmpi(str, "ja") == 0 || strcmpi(str, "si") == 0) - return 1; - if (strcmpi(str, "off") == 0 || strcmpi(str, "no") == 0 || strcmpi(str, "non") == 0 || strcmpi(str, "nein") == 0) - return 0; + if (strcmpi(str, "on") == 0 || strcmpi(str, "yes") == 0 || strcmpi(str, "oui") == 0 || strcmpi(str, "ja") == 0 || strcmpi(str, "si") == 0) + return 1; + if (strcmpi(str, "off") == 0 || strcmpi(str, "no") == 0 || strcmpi(str, "non") == 0 || strcmpi(str, "nein") == 0) + return 0; - return (int)strtol(str, NULL, 0); + return (int)strtol(str, NULL, 0); } /// strncpy that always nul-terminates the string -char* safestrncpy(char* dst, const char* src, size_t n) +char *safestrncpy(char *dst, const char *src, size_t n) { - if( n > 0 ) - { - char* d = dst; - const char* s = src; - d[--n] = '\0';/* nul-terminate string */ - for( ; n > 0; --n ) - { - if( (*d++ = *s++) == '\0' ) - {/* nul-pad remaining bytes */ - while( --n > 0 ) - *d++ = '\0'; - break; - } - } - } - return dst; + if (n > 0) { + char *d = dst; + const char *s = src; + d[--n] = '\0';/* nul-terminate string */ + for (; n > 0; --n) { + if ((*d++ = *s++) == '\0') { + /* nul-pad remaining bytes */ + while (--n > 0) + *d++ = '\0'; + break; + } + } + } + return dst; } /// doesn't crash on null pointer -size_t safestrnlen(const char* string, size_t maxlen) +size_t safestrnlen(const char *string, size_t maxlen) { - return ( string != NULL ) ? strnlen(string, maxlen) : 0; + return (string != NULL) ? strnlen(string, maxlen) : 0; } /// Works like snprintf, but always nul-terminates the buffer. @@ -379,41 +367,40 @@ size_t safestrnlen(const char* string, size_t maxlen) /// @param fmt Format string /// @param ... Format arguments /// @return The size of the string or -1 if the buffer is too small -int safesnprintf(char* buf, size_t sz, const char* fmt, ...) +int safesnprintf(char *buf, size_t sz, const char *fmt, ...) { - va_list ap; - int ret; - - va_start(ap,fmt); - ret = vsnprintf(buf, sz, fmt, ap); - va_end(ap); - if( ret < 0 || (size_t)ret >= sz ) - {// overflow - buf[sz-1] = '\0';// always nul-terminate - return -1; - } - return ret; + va_list ap; + int ret; + + va_start(ap,fmt); + ret = vsnprintf(buf, sz, fmt, ap); + va_end(ap); + if (ret < 0 || (size_t)ret >= sz) { + // overflow + buf[sz-1] = '\0';// always nul-terminate + return -1; + } + return ret; } /// Returns the line of the target position in the string. /// Lines start at 1. -int strline(const char* str, size_t pos) +int strline(const char *str, size_t pos) { - const char* target; - int line; - - if( str == NULL || pos == 0 ) - return 1; - - target = str+pos; - for( line = 1; ; ++line ) - { - str = strchr(str, '\n'); - if( str == NULL || target <= str ) - break;// found target line - ++str;// skip newline - } - return line; + const char *target; + int line; + + if (str == NULL || pos == 0) + return 1; + + target = str+pos; + for (line = 1; ; ++line) { + str = strchr(str, '\n'); + if (str == NULL || target <= str) + break;// found target line + ++str;// skip newline + } + return line; } /// Produces the hexadecimal representation of the given input. @@ -423,19 +410,18 @@ int strline(const char* str, size_t pos) /// @param output Output string /// @param input Binary input buffer /// @param count Number of bytes to convert -bool bin2hex(char* output, unsigned char* input, size_t count) +bool bin2hex(char *output, unsigned char *input, size_t count) { - char toHex[] = "0123456789abcdef"; - size_t i; - - for( i = 0; i < count; ++i ) - { - *output++ = toHex[(*input & 0xF0) >> 4]; - *output++ = toHex[(*input & 0x0F) >> 0]; - ++input; - } - *output = '\0'; - return true; + char toHex[] = "0123456789abcdef"; + size_t i; + + for (i = 0; i < count; ++i) { + *output++ = toHex[(*input & 0xF0) >> 4]; + *output++ = toHex[(*input & 0x0F) >> 0]; + ++input; + } + *output = '\0'; + return true; } @@ -446,146 +432,134 @@ bool bin2hex(char* output, unsigned char* input, size_t count) /// /// @param sv Parse state /// @return 1 if a field was parsed, 0 if already done, -1 on error. -int sv_parse_next(struct s_svstate* sv) +int sv_parse_next(struct s_svstate *sv) { - enum { - START_OF_FIELD, - PARSING_FIELD, - PARSING_C_ESCAPE, - END_OF_FIELD, - TERMINATE, - END - } state; - const char* str; - int len; - enum e_svopt opt; - char delim; - int i; - - if( sv == NULL ) - return -1;// error - - str = sv->str; - len = sv->len; - opt = sv->opt; - delim = sv->delim; - - // check opt - if( delim == '\n' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_LF)) ) - { - ShowError("sv_parse_next: delimiter '\\n' is not compatible with options SV_TERMINATE_LF or SV_TERMINATE_CRLF.\n"); - return -1;// error - } - if( delim == '\r' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_CR)) ) - { - ShowError("sv_parse_next: delimiter '\\r' is not compatible with options SV_TERMINATE_CR or SV_TERMINATE_CRLF.\n"); - return -1;// error - } - - if( sv->done || str == NULL ) - { - sv->done = true; - return 0;// nothing to parse - } + enum { + START_OF_FIELD, + PARSING_FIELD, + PARSING_C_ESCAPE, + END_OF_FIELD, + TERMINATE, + END + } state; + const char *str; + int len; + enum e_svopt opt; + char delim; + int i; + + if (sv == NULL) + return -1;// error + + str = sv->str; + len = sv->len; + opt = sv->opt; + delim = sv->delim; + + // check opt + if (delim == '\n' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_LF))) { + ShowError("sv_parse_next: delimiter '\\n' is not compatible with options SV_TERMINATE_LF or SV_TERMINATE_CRLF.\n"); + return -1;// error + } + if (delim == '\r' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_CR))) { + ShowError("sv_parse_next: delimiter '\\r' is not compatible with options SV_TERMINATE_CR or SV_TERMINATE_CRLF.\n"); + return -1;// error + } + + if (sv->done || str == NULL) { + sv->done = true; + return 0;// nothing to parse + } #define IS_END() ( i >= len ) #define IS_DELIM() ( str[i] == delim ) #define IS_TERMINATOR() ( \ - ((opt&SV_TERMINATE_LF) && str[i] == '\n') || \ - ((opt&SV_TERMINATE_CR) && str[i] == '\r') || \ - ((opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n') ) + ((opt&SV_TERMINATE_LF) && str[i] == '\n') || \ + ((opt&SV_TERMINATE_CR) && str[i] == '\r') || \ + ((opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n') ) #define IS_C_ESCAPE() ( (opt&SV_ESCAPE_C) && str[i] == '\\' ) #define SET_FIELD_START() sv->start = i #define SET_FIELD_END() sv->end = i - i = sv->off; - state = START_OF_FIELD; - while( state != END ) - { - switch( state ) - { - case START_OF_FIELD:// record start of field and start parsing it - SET_FIELD_START(); - state = PARSING_FIELD; - break; - - case PARSING_FIELD:// skip field character - if( IS_END() || IS_DELIM() || IS_TERMINATOR() ) - state = END_OF_FIELD; - else if( IS_C_ESCAPE() ) - state = PARSING_C_ESCAPE; - else - ++i;// normal character - break; - - case PARSING_C_ESCAPE:// skip escape sequence (validates it too) - { - ++i;// '\\' - if( IS_END() ) - { - ShowError("sv_parse_next: empty escape sequence\n"); - return -1; - } - if( str[i] == 'x' ) - {// hex escape - ++i;// 'x' - if( IS_END() || !ISXDIGIT(str[i]) ) - { - ShowError("sv_parse_next: \\x with no following hex digits\n"); - return -1; - } - do{ - ++i;// hex digit - }while( !IS_END() && ISXDIGIT(str[i])); - } - else if( str[i] == '0' || str[i] == '1' || str[i] == '2' ) - {// octal escape - ++i;// octal digit - if( !IS_END() && str[i] >= '0' && str[i] <= '7' ) - ++i;// octal digit - if( !IS_END() && str[i] >= '0' && str[i] <= '7' ) - ++i;// octal digit - } - else if( strchr(SV_ESCAPE_C_SUPPORTED, str[i]) ) - {// supported escape character - ++i; - } - else - { - ShowError("sv_parse_next: unknown escape sequence \\%c\n", str[i]); - return -1; - } - state = PARSING_FIELD; - break; - } - - case END_OF_FIELD:// record end of field and stop - SET_FIELD_END(); - state = END; - if( IS_END() ) - ;// nothing else - else if( IS_DELIM() ) - ++i;// delim - else if( IS_TERMINATOR() ) - state = TERMINATE; - break; - - case TERMINATE: + i = sv->off; + state = START_OF_FIELD; + while (state != END) { + switch (state) { + case START_OF_FIELD:// record start of field and start parsing it + SET_FIELD_START(); + state = PARSING_FIELD; + break; + + case PARSING_FIELD:// skip field character + if (IS_END() || IS_DELIM() || IS_TERMINATOR()) + state = END_OF_FIELD; + else if (IS_C_ESCAPE()) + state = PARSING_C_ESCAPE; + else + ++i;// normal character + break; + + case PARSING_C_ESCAPE: { // skip escape sequence (validates it too) + ++i;// '\\' + if (IS_END()) { + ShowError("sv_parse_next: empty escape sequence\n"); + return -1; + } + if (str[i] == 'x') { + // hex escape + ++i;// 'x' + if (IS_END() || !ISXDIGIT(str[i])) { + ShowError("sv_parse_next: \\x with no following hex digits\n"); + return -1; + } + do { + ++i;// hex digit + } while (!IS_END() && ISXDIGIT(str[i])); + } else if (str[i] == '0' || str[i] == '1' || str[i] == '2') { + // octal escape + ++i;// octal digit + if (!IS_END() && str[i] >= '0' && str[i] <= '7') + ++i;// octal digit + if (!IS_END() && str[i] >= '0' && str[i] <= '7') + ++i;// octal digit + } else if (strchr(SV_ESCAPE_C_SUPPORTED, str[i])) { + // supported escape character + ++i; + } else { + ShowError("sv_parse_next: unknown escape sequence \\%c\n", str[i]); + return -1; + } + state = PARSING_FIELD; + break; + } + + case END_OF_FIELD:// record end of field and stop + SET_FIELD_END(); + state = END; + if (IS_END()) + ;// nothing else + else if (IS_DELIM()) + ++i;// delim + else if (IS_TERMINATOR()) + state = TERMINATE; + break; + + case TERMINATE: #if 0 - // skip line terminator - if( (opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n' ) - i += 2;// CRLF - else - ++i;// CR or LF + // skip line terminator + if ((opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n') + i += 2;// CRLF + else + ++i;// CR or LF #endif - sv->done = true; - state = END; - break; - } - } - if( IS_END() ) - sv->done = true; - sv->off = i; + sv->done = true; + state = END; + break; + } + } + if (IS_END()) + sv->done = true; + sv->off = i; #undef IS_END #undef IS_DELIM @@ -594,7 +568,7 @@ int sv_parse_next(struct s_svstate* sv) #undef SET_FIELD_START #undef SET_FIELD_END - return 1; + return 1; } @@ -603,13 +577,13 @@ int sv_parse_next(struct s_svstate* sv) /// out_pos[0] and out_pos[1] are the start and end of line. /// Other position pairs are the start and end of fields. /// Returns the number of fields found or -1 if an error occurs. -/// +/// /// out_pos can be NULL. /// If a line terminator is found, the end position is placed there. -/// out_pos[2] and out_pos[3] for the first field, out_pos[4] and out_pos[5] +/// out_pos[2] and out_pos[3] for the first field, out_pos[4] and out_pos[5] /// for the seconds field and so on. /// Unfilled positions are set to -1. -/// +/// /// @param str String to parse /// @param len Length of the string /// @param startoff Where to start parsing @@ -618,35 +592,34 @@ int sv_parse_next(struct s_svstate* sv) /// @param npos Size of the pos array /// @param opt Options that determine the parsing behaviour /// @return Number of fields found in the string or -1 if an error occured -int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, int npos, enum e_svopt opt) +int sv_parse(const char *str, int len, int startoff, char delim, int *out_pos, int npos, enum e_svopt opt) { - struct s_svstate sv; - int count; - - // initialize - if( out_pos == NULL ) npos = 0; - for( count = 0; count < npos; ++count ) - out_pos[count] = -1; - sv.str = str; - sv.len = len; - sv.off = startoff; - sv.opt = opt; - sv.delim = delim; - sv.done = false; - - // parse - count = 0; - if( npos > 0 ) out_pos[0] = startoff; - while( !sv.done ) - { - ++count; - if( sv_parse_next(&sv) <= 0 ) - return -1;// error - if( npos > count*2 ) out_pos[count*2] = sv.start; - if( npos > count*2+1 ) out_pos[count*2+1] = sv.end; - } - if( npos > 1 ) out_pos[1] = sv.off; - return count; + struct s_svstate sv; + int count; + + // initialize + if (out_pos == NULL) npos = 0; + for (count = 0; count < npos; ++count) + out_pos[count] = -1; + sv.str = str; + sv.len = len; + sv.off = startoff; + sv.opt = opt; + sv.delim = delim; + sv.done = false; + + // parse + count = 0; + if (npos > 0) out_pos[0] = startoff; + while (!sv.done) { + ++count; + if (sv_parse_next(&sv) <= 0) + return -1;// error + if (npos > count*2) out_pos[count*2] = sv.start; + if (npos > count*2+1) out_pos[count*2+1] = sv.end; + } + if (npos > 1) out_pos[1] = sv.off; + return count; } /// Splits a delim-separated string. @@ -655,11 +628,11 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i /// out_fields[0] is the start of the next line. /// Other entries are the start of fields (nul-teminated). /// Returns the number of fields found or -1 if an error occurs. -/// +/// /// out_fields can be NULL. /// Fields that don't fit in out_fields are not nul-terminated. /// Extra entries in out_fields are filled with the end of the last field (empty string). -/// +/// /// @param str String to parse /// @param len Length of the string /// @param startoff Where to start parsing @@ -668,75 +641,64 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i /// @param nfields Size of the field array /// @param opt Options that determine the parsing behaviour /// @return Number of fields found in the string or -1 if an error occured -int sv_split(char* str, int len, int startoff, char delim, char** out_fields, int nfields, enum e_svopt opt) +int sv_split(char *str, int len, int startoff, char delim, char **out_fields, int nfields, enum e_svopt opt) { - int pos[1024]; - int i; - int done; - char* end; - int ret = sv_parse(str, len, startoff, delim, pos, ARRAYLENGTH(pos), opt); - - if( ret == -1 || out_fields == NULL || nfields <= 0 ) - return ret; // nothing to do - - // next line - end = str + pos[1]; - if( end[0] == '\0' ) - { - *out_fields = end; - } - else if( (opt&SV_TERMINATE_LF) && end[0] == '\n' ) - { - if( !(opt&SV_KEEP_TERMINATOR) ) - end[0] = '\0'; - *out_fields = end + 1; - } - else if( (opt&SV_TERMINATE_CRLF) && end[0] == '\r' && end[1] == '\n' ) - { - if( !(opt&SV_KEEP_TERMINATOR) ) - end[0] = end[1] = '\0'; - *out_fields = end + 2; - } - else if( (opt&SV_TERMINATE_CR) && end[0] == '\r' ) - { - if( !(opt&SV_KEEP_TERMINATOR) ) - end[0] = '\0'; - *out_fields = end + 1; - } - else - { - ShowError("sv_split: unknown line delimiter 0x02%x.\n", (unsigned char)end[0]); - return -1;// error - } - ++out_fields; - --nfields; - - // fields - i = 2; - done = 0; - while( done < ret && nfields > 0 ) - { - if( i < ARRAYLENGTH(pos) ) - {// split field - *out_fields = str + pos[i]; - end = str + pos[i+1]; - *end = '\0'; - // next field - i += 2; - ++done; - ++out_fields; - --nfields; - } - else - {// get more fields - sv_parse(str, len, pos[i-1] + 1, delim, pos, ARRAYLENGTH(pos), opt); - i = 2; - } - } - // remaining fields - for( i = 0; i < nfields; ++i ) - out_fields[i] = end; - return ret; + int pos[1024]; + int i; + int done; + char *end; + int ret = sv_parse(str, len, startoff, delim, pos, ARRAYLENGTH(pos), opt); + + if (ret == -1 || out_fields == NULL || nfields <= 0) + return ret; // nothing to do + + // next line + end = str + pos[1]; + if (end[0] == '\0') { + *out_fields = end; + } else if ((opt&SV_TERMINATE_LF) && end[0] == '\n') { + if (!(opt&SV_KEEP_TERMINATOR)) + end[0] = '\0'; + *out_fields = end + 1; + } else if ((opt&SV_TERMINATE_CRLF) && end[0] == '\r' && end[1] == '\n') { + if (!(opt&SV_KEEP_TERMINATOR)) + end[0] = end[1] = '\0'; + *out_fields = end + 2; + } else if ((opt&SV_TERMINATE_CR) && end[0] == '\r') { + if (!(opt&SV_KEEP_TERMINATOR)) + end[0] = '\0'; + *out_fields = end + 1; + } else { + ShowError("sv_split: unknown line delimiter 0x02%x.\n", (unsigned char)end[0]); + return -1;// error + } + ++out_fields; + --nfields; + + // fields + i = 2; + done = 0; + while (done < ret && nfields > 0) { + if (i < ARRAYLENGTH(pos)) { + // split field + *out_fields = str + pos[i]; + end = str + pos[i+1]; + *end = '\0'; + // next field + i += 2; + ++done; + ++out_fields; + --nfields; + } else { + // get more fields + sv_parse(str, len, pos[i-1] + 1, delim, pos, ARRAYLENGTH(pos), opt); + i = 2; + } + } + // remaining fields + for (i = 0; i < nfields; ++i) + out_fields[i] = end; + return ret; } /// Escapes src to out_dest according to the format of the C compiler. @@ -748,69 +710,77 @@ int sv_split(char* str, int len, int startoff, char delim, char** out_fields, in /// @param len Length of the source string /// @param escapes Extra characters to be escaped /// @return Length of the escaped string -size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* escapes) +size_t sv_escape_c(char *out_dest, const char *src, size_t len, const char *escapes) { - size_t i; - size_t j; - - if( out_dest == NULL ) - return 0;// nothing to do - if( src == NULL ) - {// nothing to escape - *out_dest = 0; - return 0; - } - if( escapes == NULL ) - escapes = ""; - - for( i = 0, j = 0; i < len; ++i ) - { - switch( src[i] ) - { - case '\0':// octal 0 - out_dest[j++] = '\\'; - out_dest[j++] = '0'; - out_dest[j++] = '0'; - out_dest[j++] = '0'; - break; - case '\r':// carriage return - out_dest[j++] = '\\'; - out_dest[j++] = 'r'; - break; - case '\n':// line feed - out_dest[j++] = '\\'; - out_dest[j++] = 'n'; - break; - case '\\':// escape character - out_dest[j++] = '\\'; - out_dest[j++] = '\\'; - break; - default: - if( strchr(escapes,src[i]) ) - {// escape - out_dest[j++] = '\\'; - switch( src[i] ) - { - case '\a': out_dest[j++] = 'a'; break; - case '\b': out_dest[j++] = 'b'; break; - case '\t': out_dest[j++] = 't'; break; - case '\v': out_dest[j++] = 'v'; break; - case '\f': out_dest[j++] = 'f'; break; - case '\?': out_dest[j++] = '?'; break; - default:// to octal - out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0700)>>6)); - out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0070)>>3)); - out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0007) )); - break; - } - } - else - out_dest[j++] = src[i]; - break; - } - } - out_dest[j] = 0; - return j; + size_t i; + size_t j; + + if (out_dest == NULL) + return 0;// nothing to do + if (src == NULL) { + // nothing to escape + *out_dest = 0; + return 0; + } + if (escapes == NULL) + escapes = ""; + + for (i = 0, j = 0; i < len; ++i) { + switch (src[i]) { + case '\0':// octal 0 + out_dest[j++] = '\\'; + out_dest[j++] = '0'; + out_dest[j++] = '0'; + out_dest[j++] = '0'; + break; + case '\r':// carriage return + out_dest[j++] = '\\'; + out_dest[j++] = 'r'; + break; + case '\n':// line feed + out_dest[j++] = '\\'; + out_dest[j++] = 'n'; + break; + case '\\':// escape character + out_dest[j++] = '\\'; + out_dest[j++] = '\\'; + break; + default: + if (strchr(escapes,src[i])) { + // escape + out_dest[j++] = '\\'; + switch (src[i]) { + case '\a': + out_dest[j++] = 'a'; + break; + case '\b': + out_dest[j++] = 'b'; + break; + case '\t': + out_dest[j++] = 't'; + break; + case '\v': + out_dest[j++] = 'v'; + break; + case '\f': + out_dest[j++] = 'f'; + break; + case '\?': + out_dest[j++] = '?'; + break; + default:// to octal + out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0700)>>6)); + out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0070)>>3)); + out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0007))); + break; + } + } else + out_dest[j++] = src[i]; + break; + } + } + out_dest[j] = 0; + return j; } /// Unescapes src to out_dest according to the format of the C compiler. @@ -821,129 +791,135 @@ size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* esca /// @param src Source string /// @param len Length of the source string /// @return Length of the escaped string -size_t sv_unescape_c(char* out_dest, const char* src, size_t len) +size_t sv_unescape_c(char *out_dest, const char *src, size_t len) { - static unsigned char low2hex[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x0? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x1? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x2? - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,// 0x3? - 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x4? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x5? - 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x6? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x7? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x8? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x9? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xA? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xB? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xC? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xD? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xE? - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 0xF? - }; - size_t i; - size_t j; - - for( i = 0, j = 0; i < len; ) - { - if( src[i] == '\\' ) - { - ++i;// '\\' - if( i >= len ) - ShowWarning("sv_unescape_c: empty escape sequence\n"); - else if( src[i] == 'x' ) - {// hex escape sequence - unsigned char c = 0; - unsigned char inrange = 1; - - ++i;// 'x' - if( i >= len || !ISXDIGIT(src[i]) ) - { - ShowWarning("sv_unescape_c: \\x with no following hex digits\n"); - continue; - } - do{ - if( c > 0x0F && inrange ) - { - ShowWarning("sv_unescape_c: hex escape sequence out of range\n"); - inrange = 0; - } - c = (c<<4)|low2hex[(unsigned char)src[i]];// hex digit - ++i; - }while( i < len && ISXDIGIT(src[i]) ); - out_dest[j++] = (char)c; - } - else if( src[i] == '0' || src[i] == '1' || src[i] == '2' || src[i] == '3' ) - {// octal escape sequence (255=0377) - unsigned char c = src[i]-'0'; - ++i;// '0', '1', '2' or '3' - if( i < len && src[i] >= '0' && src[i] <= '7' ) - { - c = (c<<3)|(src[i]-'0'); - ++i;// octal digit - } - if( i < len && src[i] >= '0' && src[i] <= '7' ) - { - c = (c<<3)|(src[i]-'0'); - ++i;// octal digit - } - out_dest[j++] = (char)c; - } - else - {// other escape sequence - if( strchr(SV_ESCAPE_C_SUPPORTED, src[i]) == NULL ) - ShowWarning("sv_unescape_c: unknown escape sequence \\%c\n", src[i]); - switch( src[i] ) - { - case 'a': out_dest[j++] = '\a'; break; - case 'b': out_dest[j++] = '\b'; break; - case 't': out_dest[j++] = '\t'; break; - case 'n': out_dest[j++] = '\n'; break; - case 'v': out_dest[j++] = '\v'; break; - case 'f': out_dest[j++] = '\f'; break; - case 'r': out_dest[j++] = '\r'; break; - case '?': out_dest[j++] = '\?'; break; - default: out_dest[j++] = src[i]; break; - } - ++i;// escaped character - } - } - else - out_dest[j++] = src[i++];// normal character - } - out_dest[j] = 0; - return j; + static unsigned char low2hex[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x0? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x1? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x2? + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,// 0x3? + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x4? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x5? + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x6? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x7? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x8? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0x9? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xA? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xB? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xC? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xD? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0xE? + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 0xF? + }; + size_t i; + size_t j; + + for (i = 0, j = 0; i < len;) { + if (src[i] == '\\') { + ++i;// '\\' + if (i >= len) + ShowWarning("sv_unescape_c: empty escape sequence\n"); + else if (src[i] == 'x') { + // hex escape sequence + unsigned char c = 0; + unsigned char inrange = 1; + + ++i;// 'x' + if (i >= len || !ISXDIGIT(src[i])) { + ShowWarning("sv_unescape_c: \\x with no following hex digits\n"); + continue; + } + do { + if (c > 0x0F && inrange) { + ShowWarning("sv_unescape_c: hex escape sequence out of range\n"); + inrange = 0; + } + c = (c<<4)|low2hex[(unsigned char)src[i]];// hex digit + ++i; + } while (i < len && ISXDIGIT(src[i])); + out_dest[j++] = (char)c; + } else if (src[i] == '0' || src[i] == '1' || src[i] == '2' || src[i] == '3') { + // octal escape sequence (255=0377) + unsigned char c = src[i]-'0'; + ++i;// '0', '1', '2' or '3' + if (i < len && src[i] >= '0' && src[i] <= '7') { + c = (c<<3)|(src[i]-'0'); + ++i;// octal digit + } + if (i < len && src[i] >= '0' && src[i] <= '7') { + c = (c<<3)|(src[i]-'0'); + ++i;// octal digit + } + out_dest[j++] = (char)c; + } else { + // other escape sequence + if (strchr(SV_ESCAPE_C_SUPPORTED, src[i]) == NULL) + ShowWarning("sv_unescape_c: unknown escape sequence \\%c\n", src[i]); + switch (src[i]) { + case 'a': + out_dest[j++] = '\a'; + break; + case 'b': + out_dest[j++] = '\b'; + break; + case 't': + out_dest[j++] = '\t'; + break; + case 'n': + out_dest[j++] = '\n'; + break; + case 'v': + out_dest[j++] = '\v'; + break; + case 'f': + out_dest[j++] = '\f'; + break; + case 'r': + out_dest[j++] = '\r'; + break; + case '?': + out_dest[j++] = '\?'; + break; + default: + out_dest[j++] = src[i]; + break; + } + ++i;// escaped character + } + } else + out_dest[j++] = src[i++];// normal character + } + out_dest[j] = 0; + return j; } /// Skips a C escape sequence (starting with '\\'). -const char* skip_escaped_c(const char* p) +const char *skip_escaped_c(const char *p) { - if( p && *p == '\\' ) - { - ++p; - switch( *p ) - { - case 'x':// hexadecimal - ++p; - while( ISXDIGIT(*p) ) - ++p; - break; - case '0': - case '1': - case '2': - case '3':// octal - ++p; - if( *p >= '0' && *p <= '7' ) - ++p; - if( *p >= '0' && *p <= '7' ) - ++p; - break; - default: - if( *p && strchr(SV_ESCAPE_C_SUPPORTED, *p) ) - ++p; - } - } - return p; + if (p && *p == '\\') { + ++p; + switch (*p) { + case 'x':// hexadecimal + ++p; + while (ISXDIGIT(*p)) + ++p; + break; + case '0': + case '1': + case '2': + case '3':// octal + ++p; + if (*p >= '0' && *p <= '7') + ++p; + if (*p >= '0' && *p <= '7') + ++p; + break; + default: + if (*p && strchr(SV_ESCAPE_C_SUPPORTED, *p)) + ++p; + } + } + return p; } @@ -958,78 +934,72 @@ const char* skip_escaped_c(const char* p) /// @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)) +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; // buffer for fields ([0] is reserved) - int columns, fields_length; - char path[1024], line[1024]; - char* match; - - snprintf(path, sizeof(path), "%s/%s", directory, filename); - - // open file - fp = fopen(path, "r"); - if( fp == NULL ) - { - ShowError("sv_readdb: can't read %s\n", path); - return false; - } - - // allocate enough memory for the maximum requested amount of columns plus the reserved one - fields_length = maxcols+1; - fields = (char**)aMalloc(fields_length*sizeof(char*)); - - // process rows one by one - while( fgets(line, sizeof(line), fp) ) - { - lines++; - - if( ( match = strstr(line, "//") ) != NULL ) - {// strip comments - match[0] = 0; - } - - //TODO: strip trailing whitespace - if( line[0] == '\0' || line[0] == '\n' || line[0] == '\r') - continue; - - columns = sv_split(line, strlen(line), 0, delim, fields, fields_length, (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF)); - - 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++; - } - - aFree(fields); - fclose(fp); - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, path); - - return true; + FILE *fp; + int lines = 0; + int entries = 0; + char **fields; // buffer for fields ([0] is reserved) + int columns, fields_length; + char path[1024], line[1024]; + char *match; + + snprintf(path, sizeof(path), "%s/%s", directory, filename); + + // open file + fp = fopen(path, "r"); + if (fp == NULL) { + ShowError("sv_readdb: can't read %s\n", path); + return false; + } + + // allocate enough memory for the maximum requested amount of columns plus the reserved one + fields_length = maxcols+1; + fields = (char **)aMalloc(fields_length*sizeof(char *)); + + // process rows one by one + while (fgets(line, sizeof(line), fp)) { + lines++; + + if ((match = strstr(line, "//")) != NULL) { + // strip comments + match[0] = 0; + } + + //TODO: strip trailing whitespace + if (line[0] == '\0' || line[0] == '\n' || line[0] == '\r') + continue; + + columns = sv_split(line, strlen(line), 0, delim, fields, fields_length, (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF)); + + 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++; + } + + aFree(fields); + fclose(fp); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, path); + + return true; } @@ -1039,129 +1009,126 @@ bool sv_readdb(const char* directory, const char* filename, char delim, int minc // @author MouseJstr (original) /// Allocates a StringBuf -StringBuf* StringBuf_Malloc() +StringBuf *StringBuf_Malloc() { - StringBuf* self; - CREATE(self, StringBuf, 1); - StringBuf_Init(self); - return self; + StringBuf *self; + CREATE(self, StringBuf, 1); + StringBuf_Init(self); + return self; } /// Initializes a previously allocated StringBuf -void StringBuf_Init(StringBuf* self) +void StringBuf_Init(StringBuf *self) { - self->max_ = 1024; - self->ptr_ = self->buf_ = (char*)aMalloc(self->max_ + 1); + self->max_ = 1024; + self->ptr_ = self->buf_ = (char *)aMalloc(self->max_ + 1); } /// Appends the result of printf to the StringBuf -int StringBuf_Printf(StringBuf* self, const char* fmt, ...) +int StringBuf_Printf(StringBuf *self, const char *fmt, ...) { - int len; - va_list ap; + int len; + va_list ap; - va_start(ap, fmt); - len = StringBuf_Vprintf(self, fmt, ap); - va_end(ap); + va_start(ap, fmt); + len = StringBuf_Vprintf(self, fmt, ap); + va_end(ap); - return len; + return len; } /// Appends the result of vprintf to the StringBuf -int StringBuf_Vprintf(StringBuf* self, const char* fmt, va_list ap) +int StringBuf_Vprintf(StringBuf *self, const char *fmt, va_list ap) { - int n, size, off; - - for(;;) - { - va_list apcopy; - /* Try to print in the allocated space. */ - size = self->max_ - (self->ptr_ - self->buf_); - va_copy(apcopy, ap); - n = vsnprintf(self->ptr_, size, fmt, apcopy); - va_end(apcopy); - /* If that worked, return the length. */ - if( n > -1 && n < size ) - { - self->ptr_ += n; - return (int)(self->ptr_ - self->buf_); - } - /* Else try again with more space. */ - self->max_ *= 2; // twice the old size - off = (int)(self->ptr_ - self->buf_); - self->buf_ = (char*)aRealloc(self->buf_, self->max_ + 1); - self->ptr_ = self->buf_ + off; - } + int n, size, off; + + for (;;) { + va_list apcopy; + /* Try to print in the allocated space. */ + size = self->max_ - (self->ptr_ - self->buf_); + va_copy(apcopy, ap); + n = vsnprintf(self->ptr_, size, fmt, apcopy); + va_end(apcopy); + /* If that worked, return the length. */ + if (n > -1 && n < size) { + self->ptr_ += n; + return (int)(self->ptr_ - self->buf_); + } + /* Else try again with more space. */ + self->max_ *= 2; // twice the old size + off = (int)(self->ptr_ - self->buf_); + self->buf_ = (char *)aRealloc(self->buf_, self->max_ + 1); + self->ptr_ = self->buf_ + off; + } } /// Appends the contents of another StringBuf to the StringBuf -int StringBuf_Append(StringBuf* self, const StringBuf* sbuf) +int StringBuf_Append(StringBuf *self, const StringBuf *sbuf) { - int available = self->max_ - (self->ptr_ - self->buf_); - int needed = (int)(sbuf->ptr_ - sbuf->buf_); - - if( needed >= available ) - { - int off = (int)(self->ptr_ - self->buf_); - self->max_ += needed; - self->buf_ = (char*)aRealloc(self->buf_, self->max_ + 1); - self->ptr_ = self->buf_ + off; - } - - memcpy(self->ptr_, sbuf->buf_, needed); - self->ptr_ += needed; - return (int)(self->ptr_ - self->buf_); + int available = self->max_ - (self->ptr_ - self->buf_); + int needed = (int)(sbuf->ptr_ - sbuf->buf_); + + if (needed >= available) { + int off = (int)(self->ptr_ - self->buf_); + self->max_ += needed; + self->buf_ = (char *)aRealloc(self->buf_, self->max_ + 1); + self->ptr_ = self->buf_ + off; + } + + memcpy(self->ptr_, sbuf->buf_, needed); + self->ptr_ += needed; + return (int)(self->ptr_ - self->buf_); } // Appends str to the StringBuf -int StringBuf_AppendStr(StringBuf* self, const char* str) +int StringBuf_AppendStr(StringBuf *self, const char *str) { - int available = self->max_ - (self->ptr_ - self->buf_); - int needed = (int)strlen(str); - - if( needed >= available ) - {// not enough space, expand the buffer (minimum expansion = 1024) - int off = (int)(self->ptr_ - self->buf_); - self->max_ += max(needed, 1024); - self->buf_ = (char*)aRealloc(self->buf_, self->max_ + 1); - self->ptr_ = self->buf_ + off; - } - - memcpy(self->ptr_, str, needed); - self->ptr_ += needed; - return (int)(self->ptr_ - self->buf_); + int available = self->max_ - (self->ptr_ - self->buf_); + int needed = (int)strlen(str); + + if (needed >= available) { + // not enough space, expand the buffer (minimum expansion = 1024) + int off = (int)(self->ptr_ - self->buf_); + self->max_ += max(needed, 1024); + self->buf_ = (char *)aRealloc(self->buf_, self->max_ + 1); + self->ptr_ = self->buf_ + off; + } + + memcpy(self->ptr_, str, needed); + self->ptr_ += needed; + return (int)(self->ptr_ - self->buf_); } // Returns the length of the data in the Stringbuf -int StringBuf_Length(StringBuf* self) +int StringBuf_Length(StringBuf *self) { - return (int)(self->ptr_ - self->buf_); + return (int)(self->ptr_ - self->buf_); } /// Returns the data in the StringBuf -char* StringBuf_Value(StringBuf* self) +char *StringBuf_Value(StringBuf *self) { - *self->ptr_ = '\0'; - return self->buf_; + *self->ptr_ = '\0'; + return self->buf_; } /// Clears the contents of the StringBuf -void StringBuf_Clear(StringBuf* self) +void StringBuf_Clear(StringBuf *self) { - self->ptr_ = self->buf_; + self->ptr_ = self->buf_; } /// Destroys the StringBuf -void StringBuf_Destroy(StringBuf* self) +void StringBuf_Destroy(StringBuf *self) { - aFree(self->buf_); - self->ptr_ = self->buf_ = 0; - self->max_ = 0; + aFree(self->buf_); + self->ptr_ = self->buf_ = 0; + self->max_ = 0; } // Frees a StringBuf returned by StringBuf_Malloc -void StringBuf_Free(StringBuf* self) +void StringBuf_Free(StringBuf *self) { - StringBuf_Destroy(self); - aFree(self); + StringBuf_Destroy(self); + aFree(self); } diff --git a/src/common/strlib.h b/src/common/strlib.h index bbc2c6105..ae4f688c2 100644 --- a/src/common/strlib.h +++ b/src/common/strlib.h @@ -11,66 +11,65 @@ #include #undef __USE_GNU -char* jstrescape (char* pt); -char* jstrescapecpy (char* pt, const char* spt); -int jmemescapecpy (char* pt, const char* spt, int size); +char *jstrescape(char *pt); +char *jstrescapecpy(char *pt, const char *spt); +int jmemescapecpy(char *pt, const char *spt, int size); -int remove_control_chars(char* str); -char* trim(char* str); -char* normalize_name(char* str,const char* delims); +int remove_control_chars(char *str); +char *trim(char *str); +char *normalize_name(char *str,const char *delims); const char *stristr(const char *haystack, const char *needle); #ifdef WIN32 #define HAVE_STRTOK_R #define strtok_r(s,delim,save_ptr) _strtok_r((s),(delim),(save_ptr)) -char* _strtok_r(char* s1, const char* s2, char** lasts); +char *_strtok_r(char *s1, const char *s2, char **lasts); #endif #if !(defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400) && !defined(HAVE_STRNLEN) -size_t strnlen (const char* string, size_t maxlen); +size_t strnlen(const char *string, size_t maxlen); #endif #if defined(WIN32) && defined(_MSC_VER) && _MSC_VER <= 1200 -uint64 strtoull(const char* str, char** endptr, int base); +uint64 strtoull(const char *str, char **endptr, int base); #endif -int e_mail_check(char* email); -int config_switch(const char* str); +int e_mail_check(char *email); +int config_switch(const char *str); /// strncpy that always nul-terminates the string -char* safestrncpy(char* dst, const char* src, size_t n); +char *safestrncpy(char *dst, const char *src, size_t n); /// doesn't crash on null pointer -size_t safestrnlen(const char* string, size_t maxlen); +size_t safestrnlen(const char *string, size_t maxlen); /// Works like snprintf, but always nul-terminates the buffer. /// Returns the size of the string (without nul-terminator) /// or -1 if the buffer is too small. -int safesnprintf(char* buf, size_t sz, const char* fmt, ...); +int safesnprintf(char *buf, size_t sz, const char *fmt, ...); /// Returns the line of the target position in the string. /// Lines start at 1. -int strline(const char* str, size_t pos); +int strline(const char *str, size_t pos); /// Produces the hexadecimal representation of the given input. /// The output buffer must be at least count*2+1 in size. /// Returns true on success, false on failure. -bool bin2hex(char* output, unsigned char* input, size_t count); +bool bin2hex(char *output, unsigned char *input, size_t count); /// Bitfield determining the behaviour of sv_parse and sv_split. -typedef enum e_svopt -{ - // default: no escapes and no line terminator - SV_NOESCAPE_NOTERMINATE = 0, - // Escapes according to the C compiler. - SV_ESCAPE_C = 1, - // Line terminators - SV_TERMINATE_LF = 2, - SV_TERMINATE_CRLF = 4, - SV_TERMINATE_CR = 8, - // If sv_split keeps the end of line terminator, instead of replacing with '\0' - SV_KEEP_TERMINATOR = 16 +typedef enum e_svopt { + // default: no escapes and no line terminator + SV_NOESCAPE_NOTERMINATE = 0, + // Escapes according to the C compiler. + SV_ESCAPE_C = 1, + // Line terminators + SV_TERMINATE_LF = 2, + SV_TERMINATE_CRLF = 4, + SV_TERMINATE_CR = 8, + // If sv_split keeps the end of line terminator, instead of replacing with '\0' + SV_KEEP_TERMINATOR = 16 } e_svopt; /// Other escape sequences supported by the C compiler. @@ -78,16 +77,15 @@ typedef enum e_svopt /// Parse state. /// The field is [start,end[ -struct s_svstate -{ - const char* str; //< string to parse - int len; //< string length - int off; //< current offset in the string - int start; //< where the field starts - int end; //< where the field ends - enum e_svopt opt; //< parse options - char delim; //< field delimiter - bool done; //< if all the text has been parsed +struct s_svstate { + const char *str; //< string to parse + int len; //< string length + int off; //< current offset in the string + int start; //< where the field starts + int end; //< where the field ends + enum e_svopt opt; //< parse options + char delim; //< field delimiter + bool done; //< if all the text has been parsed }; /// Parses a single field in a delim-separated string. @@ -95,14 +93,14 @@ struct s_svstate /// /// @param sv Parse state /// @return 1 if a field was parsed, 0 if done, -1 on error. -int sv_parse_next(struct s_svstate* sv); +int sv_parse_next(struct s_svstate *sv); /// Parses a delim-separated string. /// Starts parsing at startoff and fills the pos array with position pairs. /// out_pos[0] and out_pos[1] are the start and end of line. /// Other position pairs are the start and end of fields. /// Returns the number of fields found or -1 if an error occurs. -int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, int npos, enum e_svopt opt); +int sv_parse(const char *str, int len, int startoff, char delim, int *out_pos, int npos, enum e_svopt opt); /// Splits a delim-separated string. /// WARNING: this function modifies the input string @@ -110,46 +108,45 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i /// out_fields[0] is the start of the next line. /// Other entries are the start of fields (nul-teminated). /// Returns the number of fields found or -1 if an error occurs. -int sv_split(char* str, int len, int startoff, char delim, char** out_fields, int nfields, enum e_svopt opt); +int sv_split(char *str, int len, int startoff, char delim, char **out_fields, int nfields, enum e_svopt opt); /// Escapes src to out_dest according to the format of the C compiler. /// Returns the length of the escaped string. /// out_dest should be len*4+1 in size. -size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* escapes); +size_t sv_escape_c(char *out_dest, const char *src, size_t len, const char *escapes); /// Unescapes src to out_dest according to the format of the C compiler. /// Returns the length of the unescaped string. /// 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); +size_t sv_unescape_c(char *out_dest, const char *src, size_t len); /// Skips a C escape sequence (starting with '\\'). -const char* skip_escaped_c(const char* p); +const char *skip_escaped_c(const char *p); /// 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)); +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 -struct StringBuf -{ - char *buf_; - char *ptr_; - unsigned int max_; +struct StringBuf { + char *buf_; + char *ptr_; + unsigned int max_; }; typedef struct StringBuf StringBuf; -StringBuf* StringBuf_Malloc(void); -void StringBuf_Init(StringBuf* self); -int StringBuf_Printf(StringBuf* self, const char* fmt, ...); -int StringBuf_Vprintf(StringBuf* self, const char* fmt, va_list args); -int StringBuf_Append(StringBuf* self, const StringBuf *sbuf); -int StringBuf_AppendStr(StringBuf* self, const char* str); -int StringBuf_Length(StringBuf* self); -char* StringBuf_Value(StringBuf* self); -void StringBuf_Clear(StringBuf* self); -void StringBuf_Destroy(StringBuf* self); -void StringBuf_Free(StringBuf* self); +StringBuf *StringBuf_Malloc(void); +void StringBuf_Init(StringBuf *self); +int StringBuf_Printf(StringBuf *self, const char *fmt, ...); +int StringBuf_Vprintf(StringBuf *self, const char *fmt, va_list args); +int StringBuf_Append(StringBuf *self, const StringBuf *sbuf); +int StringBuf_AppendStr(StringBuf *self, const char *str); +int StringBuf_Length(StringBuf *self); +char *StringBuf_Value(StringBuf *self); +void StringBuf_Clear(StringBuf *self); +void StringBuf_Destroy(StringBuf *self); +void StringBuf_Free(StringBuf *self); #endif /* _STRLIB_H_ */ diff --git a/src/common/thread.c b/src/common/thread.c index 315b310b2..610ee394c 100644 --- a/src/common/thread.c +++ b/src/common/thread.c @@ -9,7 +9,7 @@ #ifdef WIN32 #include "../common/winapi.h" #define getpagesize() 4096 // @TODO: implement this properly (GetSystemInfo .. dwPageSize..). (Atm as on all supported win platforms its 4k its static.) -#define __thread __declspec( thread ) +#define __thread __declspec( thread ) #else #include #include @@ -25,25 +25,25 @@ #include "thread.h" // When Compiling using MSC (on win32..) we know we have support in any case! -#ifdef _MSC_VER -#define HAS_TLS +#ifdef _MSC_VER +#define HAS_TLS #endif #define RA_THREADS_MAX 64 struct rAthread { - unsigned int myID; - - RATHREAD_PRIO prio; - rAthreadProc proc; - void *param; - - #ifdef WIN32 - HANDLE hThread; - #else - pthread_t hThread; - #endif + unsigned int myID; + + RATHREAD_PRIO prio; + rAthreadProc proc; + void *param; + +#ifdef WIN32 + HANDLE hThread; +#else + pthread_t hThread; +#endif }; @@ -57,95 +57,100 @@ __thread int g_rathread_ID = -1; /// static struct rAthread l_threads[RA_THREADS_MAX]; -void rathread_init(){ - register unsigned int i; - memset(&l_threads, 0x00, RA_THREADS_MAX * sizeof(struct rAthread) ); - - for(i = 0; i < RA_THREADS_MAX; i++){ - l_threads[i].myID = i; - } +void rathread_init() +{ + register unsigned int i; + memset(&l_threads, 0x00, RA_THREADS_MAX * sizeof(struct rAthread)); + + for (i = 0; i < RA_THREADS_MAX; i++) { + l_threads[i].myID = i; + } - // now lets init thread id 0, which represnts the main thread + // now lets init thread id 0, which represnts the main thread #ifdef HAS_TLS - g_rathread_ID = 0; + g_rathread_ID = 0; #endif - l_threads[0].prio = RAT_PRIO_NORMAL; - l_threads[0].proc = (rAthreadProc)0xDEADCAFE; + l_threads[0].prio = RAT_PRIO_NORMAL; + l_threads[0].proc = (rAthreadProc)0xDEADCAFE; }//end: rathread_init() -void rathread_final(){ - register unsigned int i; - - // Unterminated Threads Left? - // Should'nt happen .. - // Kill 'em all! - // - for(i = 1; i < RA_THREADS_MAX; i++){ - if(l_threads[i].proc != NULL){ - ShowWarning("rAthread_final: unterminated Thread (tid %u entryPoint %p) - forcing to terminate (kill)\n", i, l_threads[i].proc); - rathread_destroy(&l_threads[i]); - } - } - - +void rathread_final() +{ + register unsigned int i; + + // Unterminated Threads Left? + // Should'nt happen .. + // Kill 'em all! + // + for (i = 1; i < RA_THREADS_MAX; i++) { + if (l_threads[i].proc != NULL) { + ShowWarning("rAthread_final: unterminated Thread (tid %u entryPoint %p) - forcing to terminate (kill)\n", i, l_threads[i].proc); + rathread_destroy(&l_threads[i]); + } + } + + }//end: rathread_final() // gets called whenever a thread terminated .. -static void rat_thread_terminated( rAthread handle ){ +static void rat_thread_terminated(rAthread handle) +{ - int id_backup = handle->myID; + int id_backup = handle->myID; - // Simply set all members to 0 (except the id) - memset(handle, 0x00, sizeof(struct rAthread)); - - handle->myID = id_backup; // done ;) + // Simply set all members to 0 (except the id) + memset(handle, 0x00, sizeof(struct rAthread)); + + handle->myID = id_backup; // done ;) }//end: rat_thread_terminated() #ifdef WIN32 -DWORD WINAPI _raThreadMainRedirector(LPVOID p){ +DWORD WINAPI _raThreadMainRedirector(LPVOID p) +{ #else -static void *_raThreadMainRedirector( void *p ){ - sigset_t set; // on Posix Thread platforms +static void *_raThreadMainRedirector(void *p) +{ + sigset_t set; // on Posix Thread platforms #endif - void *ret; - - // Update myID @ TLS to right id. + void *ret; + + // Update myID @ TLS to right id. #ifdef HAS_TLS - g_rathread_ID = ((rAthread)p)->myID; + g_rathread_ID = ((rAthread)p)->myID; #endif #ifndef WIN32 - // When using posix threads - // the threads inherits the Signal mask from the thread which's spawned - // this thread - // so we've to block everything we dont care about. - sigemptyset(&set); - sigaddset(&set, SIGINT); - sigaddset(&set, SIGTERM); - sigaddset(&set, SIGPIPE); - - pthread_sigmask(SIG_BLOCK, &set, NULL); - + // When using posix threads + // the threads inherits the Signal mask from the thread which's spawned + // this thread + // so we've to block everything we dont care about. + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGTERM); + sigaddset(&set, SIGPIPE); + + pthread_sigmask(SIG_BLOCK, &set, NULL); + #endif - ret = ((rAthread)p)->proc( ((rAthread)p)->param ) ; + ret = ((rAthread)p)->proc(((rAthread)p)->param) ; -#ifdef WIN32 - CloseHandle( ((rAthread)p)->hThread ); +#ifdef WIN32 + CloseHandle(((rAthread)p)->hThread); #endif - rat_thread_terminated( (rAthread)p ); + rat_thread_terminated((rAthread)p); #ifdef WIN32 - return (DWORD)ret; + return (DWORD)ret; #else - return ret; + return ret; #endif }//end: _raThreadMainRedirector() @@ -155,163 +160,172 @@ static void *_raThreadMainRedirector( void *p ){ /// /// API Level -/// -rAthread rathread_create( rAthreadProc entryPoint, void *param ){ - return rathread_createEx( entryPoint, param, (1<<23) /*8MB*/, RAT_PRIO_NORMAL ); +/// +rAthread rathread_create(rAthreadProc entryPoint, void *param) +{ + return rathread_createEx(entryPoint, param, (1<<23) /*8MB*/, RAT_PRIO_NORMAL); }//end: rathread_create() -rAthread rathread_createEx( rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio ){ +rAthread rathread_createEx(rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio) +{ #ifndef WIN32 - pthread_attr_t attr; + pthread_attr_t attr; #endif - size_t tmp; - unsigned int i; - rAthread handle = NULL; - - - // given stacksize aligned to systems pagesize? - tmp = szStack % getpagesize(); - if(tmp != 0) - szStack += tmp; - - - // Get a free Thread Slot. - for(i = 0; i < RA_THREADS_MAX; i++){ - if(l_threads[i].proc == NULL){ - handle = &l_threads[i]; - break; - } - } - - if(handle == NULL){ - ShowError("rAthread: cannot create new thread (entryPoint: %p) - no free thread slot found!", entryPoint); - return NULL; - } - - - - handle->proc = entryPoint; - handle->param = param; + size_t tmp; + unsigned int i; + rAthread handle = NULL; + + + // given stacksize aligned to systems pagesize? + tmp = szStack % getpagesize(); + if (tmp != 0) + szStack += tmp; + + + // Get a free Thread Slot. + for (i = 0; i < RA_THREADS_MAX; i++) { + if (l_threads[i].proc == NULL) { + handle = &l_threads[i]; + break; + } + } + + if (handle == NULL) { + ShowError("rAthread: cannot create new thread (entryPoint: %p) - no free thread slot found!", entryPoint); + return NULL; + } + + + + handle->proc = entryPoint; + handle->param = param; #ifdef WIN32 - handle->hThread = CreateThread(NULL, szStack, _raThreadMainRedirector, (void*)handle, 0, NULL); + handle->hThread = CreateThread(NULL, szStack, _raThreadMainRedirector, (void *)handle, 0, NULL); #else - pthread_attr_init(&attr); - pthread_attr_setstacksize(&attr, szStack); - - if(pthread_create(&handle->hThread, &attr, _raThreadMainRedirector, (void*)handle) != 0){ - handle->proc = NULL; - handle->param = NULL; - return NULL; - } - pthread_attr_destroy(&attr); + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, szStack); + + if (pthread_create(&handle->hThread, &attr, _raThreadMainRedirector, (void *)handle) != 0) { + handle->proc = NULL; + handle->param = NULL; + return NULL; + } + pthread_attr_destroy(&attr); #endif - rathread_prio_set( handle, prio ); - - return handle; + rathread_prio_set(handle, prio); + + return handle; }//end: rathread_createEx -void rathread_destroy ( rAthread handle ){ +void rathread_destroy(rAthread handle) +{ #ifdef WIN32 - if( TerminateThread(handle->hThread, 0) != FALSE){ - CloseHandle(handle->hThread); - rat_thread_terminated(handle); - } + if (TerminateThread(handle->hThread, 0) != FALSE) { + CloseHandle(handle->hThread); + rat_thread_terminated(handle); + } #else - if( pthread_cancel( handle->hThread ) == 0){ - - // We have to join it, otherwise pthread wont re-cycle its internal ressources assoc. with this thread. - // - pthread_join( handle->hThread, NULL ); - - // Tell our manager to release ressources ;) - rat_thread_terminated(handle); - } + if (pthread_cancel(handle->hThread) == 0) { + + // We have to join it, otherwise pthread wont re-cycle its internal ressources assoc. with this thread. + // + pthread_join(handle->hThread, NULL); + + // Tell our manager to release ressources ;) + rat_thread_terminated(handle); + } #endif }//end: rathread_destroy() -rAthread rathread_self( ){ +rAthread rathread_self() +{ #ifdef HAS_TLS - rAthread handle = &l_threads[g_rathread_ID]; - - if(handle->proc != NULL) // entry point set, so its used! - return handle; + rAthread handle = &l_threads[g_rathread_ID]; + + if (handle->proc != NULL) // entry point set, so its used! + return handle; #else - // .. so no tls means we have to search the thread by its api-handle .. - int i; - - #ifdef WIN32 - HANDLE hSelf; - hSelf = GetCurrent = GetCurrentThread(); - #else - pthread_t hSelf; - hSelf = pthread_self(); - #endif - - for(i = 0; i < RA_THREADS_MAX; i++){ - if(l_threads[i].hThread == hSelf && l_threads[i].proc != NULL) - return &l_threads[i]; - } - + // .. so no tls means we have to search the thread by its api-handle .. + int i; + +#ifdef WIN32 + HANDLE hSelf; + hSelf = GetCurrent = GetCurrentThread(); +#else + pthread_t hSelf; + hSelf = pthread_self(); +#endif + + for (i = 0; i < RA_THREADS_MAX; i++) { + if (l_threads[i].hThread == hSelf && l_threads[i].proc != NULL) + return &l_threads[i]; + } + #endif - - return NULL; + + return NULL; }//end: rathread_self() -int rathread_get_tid(){ +int rathread_get_tid() +{ -#ifdef HAS_TLS - return g_rathread_ID; +#ifdef HAS_TLS + return g_rathread_ID; #else - // todo - #ifdef WIN32 - return (int)GetCurrentThreadId(); - #else - return (intptr_t)pthread_self(); - #endif - + // todo +#ifdef WIN32 + return (int)GetCurrentThreadId(); +#else + return (intptr_t)pthread_self(); +#endif + #endif - + }//end: rathread_get_tid() -bool rathread_wait( rAthread handle, void* *out_exitCode ){ - - // Hint: - // no thread data cleanup routine call here! - // its managed by the callProxy itself.. - // +bool rathread_wait(rAthread handle, void* *out_exitCode) +{ + + // Hint: + // no thread data cleanup routine call here! + // its managed by the callProxy itself.. + // #ifdef WIN32 - WaitForSingleObject(handle->hThread, INFINITE); - return true; + WaitForSingleObject(handle->hThread, INFINITE); + return true; #else - if(pthread_join(handle->hThread, out_exitCode) == 0) - return true; - return false; + if (pthread_join(handle->hThread, out_exitCode) == 0) + return true; + return false; #endif }//end: rathread_wait() -void rathread_prio_set( rAthread handle, RATHREAD_PRIO prio ){ - handle->prio = RAT_PRIO_NORMAL; - //@TODO +void rathread_prio_set(rAthread handle, RATHREAD_PRIO prio) +{ + handle->prio = RAT_PRIO_NORMAL; + //@TODO }//end: rathread_prio_set() -RATHREAD_PRIO rathread_prio_get( rAthread handle){ - return handle->prio; +RATHREAD_PRIO rathread_prio_get(rAthread handle) +{ + return handle->prio; }//end: rathread_prio_get() -void rathread_yield(){ -#ifdef WIN32 - SwitchToThread(); +void rathread_yield() +{ +#ifdef WIN32 + SwitchToThread(); #else - sched_yield(); -#endif + sched_yield(); +#endif }//end: rathread_yield() diff --git a/src/common/thread.h b/src/common/thread.h index a5a66e954..cfbfe689f 100644 --- a/src/common/thread.h +++ b/src/common/thread.h @@ -1,19 +1,19 @@ // Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#pragma once +#pragma once #ifndef _rA_THREAD_H_ #define _rA_THREAD_H_ #include "../common/cbasetypes.h" typedef struct rAthread *rAthread; -typedef void* (*rAthreadProc)(void*); +typedef void *(*rAthreadProc)(void *); typedef enum RATHREAD_PRIO { - RAT_PRIO_LOW = 0, - RAT_PRIO_NORMAL, - RAT_PRIO_HIGH + RAT_PRIO_LOW = 0, + RAT_PRIO_NORMAL, + RAT_PRIO_HIGH } RATHREAD_PRIO; @@ -22,51 +22,51 @@ typedef enum RATHREAD_PRIO { * * @param entyPoint - entryProc, * @param param - general purpose parameter, would be given as parameter to the thread's entrypoint. - * + * * @return not NULL if success */ -rAthread rathread_create( rAthreadProc entryPoint, void *param ); +rAthread rathread_create(rAthreadProc entryPoint, void *param); -/** +/** * Creates a new Thread (with more creation options) * * @param entyPoint - entryProc, * @param param - general purpose parameter, would be given as parameter to the thread's entrypoint - * @param szStack - stack Size in bytes + * @param szStack - stack Size in bytes * @param prio - Priority of the Thread @ OS Scheduler.. * * @return not NULL if success */ -rAthread rathread_createEx( rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio ); +rAthread rathread_createEx(rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio); /** * Destroys the given Thread immediatly * - * @note The Handle gets invalid after call! dont use it afterwards. + * @note The Handle gets invalid after call! dont use it afterwards. * * @param handle - thread to destroy. */ -void rathread_destroy ( rAthread handle ); +void rathread_destroy(rAthread handle); -/** +/** * Returns the thread handle of the thread calling this function - * + * * @note this wont work @ programms main thread - * @note the underlying implementation might not perform very well, cache the value received! - * + * @note the underlying implementation might not perform very well, cache the value received! + * * @return not NULL if success */ -rAthread rathread_self( ); +rAthread rathread_self(); /** - * Returns own thrad id (TID) + * Returns own thrad id (TID) * - * @note this is an unique identifier for the calling thread, and - * depends on platfrom / compiler, and may not be the systems Thread ID! + * @note this is an unique identifier for the calling thread, and + * depends on platfrom / compiler, and may not be the systems Thread ID! * * @return -1 when fails, otherwise >= 0 */ @@ -74,39 +74,39 @@ int rathread_get_tid(); /** - * Waits for the given thread to terminate + * Waits for the given thread to terminate * * @param handle - thread to wait (join) for * @param out_Exitcode - [OPTIONAL] - if given => Exitcode (value) of the given thread - if it's terminated - * + * * @return true - if the given thread has been terminated. */ -bool rathread_wait( rAthread handle, void* *out_exitCode ); +bool rathread_wait(rAthread handle, void* *out_exitCode); -/** +/** * Sets the given PRIORITY @ OS Task Scheduler - * + * * @param handle - thread to set prio for * @param rio - the priority (RAT_PRIO_LOW ... ) */ -void rathread_prio_set( rAthread handle, RATHREAD_PRIO prio ); +void rathread_prio_set(rAthread handle, RATHREAD_PRIO prio); -/** +/** * Gets the current Prio of the given trhead * * @param handle - the thread to get the prio for. */ -RATHREAD_PRIO rathread_prio_get( rAthread handle); +RATHREAD_PRIO rathread_prio_get(rAthread handle); /** * Tells the OS scheduler to yield the execution of the calling thread - * + * * @note: this will not "pause" the thread, - * it just allows the OS to spent the remaining time - * of the slice to another thread. + * it just allows the OS to spent the remaining time + * of the slice to another thread. */ void rathread_yield(); diff --git a/src/common/timer.c b/src/common/timer.c index c239a9d70..bb2458233 100644 --- a/src/common/timer.c +++ b/src/common/timer.c @@ -26,12 +26,12 @@ #define TIMER_MAX_INTERVAL 1000 // timers (array) -static struct TimerData* timer_data = NULL; +static struct TimerData *timer_data = NULL; static int timer_data_max = 0; static int timer_data_num = 0; // free timers (array) -static int* free_timer_list = NULL; +static int *free_timer_list = NULL; static int free_timer_list_max = 0; static int free_timer_list_pos = 0; @@ -53,85 +53,87 @@ time_t start_time; /*---------------------------- - * Timer debugging + * Timer debugging *----------------------------*/ struct timer_func_list { - struct timer_func_list* next; - TimerFunc func; - char* name; + struct timer_func_list *next; + TimerFunc func; + char *name; } *tfl_root = NULL; /// Sets the name of a timer function. -int add_timer_func_list(TimerFunc func, char* name) +int add_timer_func_list(TimerFunc func, char *name) { - struct timer_func_list* tfl; - - if (name) { - for( tfl=tfl_root; tfl != NULL; tfl=tfl->next ) - {// check suspicious cases - if( func == tfl->func ) - ShowWarning("add_timer_func_list: duplicating function %p(%s) as %s.\n",tfl->func,tfl->name,name); - else if( strcmp(name,tfl->name) == 0 ) - ShowWarning("add_timer_func_list: function %p has the same name as %p(%s)\n",func,tfl->func,tfl->name); - } - CREATE(tfl,struct timer_func_list,1); - tfl->next = tfl_root; - tfl->func = func; - tfl->name = aStrdup(name); - tfl_root = tfl; - } - return 0; + struct timer_func_list *tfl; + + if (name) { + for (tfl=tfl_root; tfl != NULL; tfl=tfl->next) { + // check suspicious cases + if (func == tfl->func) + ShowWarning("add_timer_func_list: duplicating function %p(%s) as %s.\n",tfl->func,tfl->name,name); + else if (strcmp(name,tfl->name) == 0) + ShowWarning("add_timer_func_list: function %p has the same name as %p(%s)\n",func,tfl->func,tfl->name); + } + CREATE(tfl,struct timer_func_list,1); + tfl->next = tfl_root; + tfl->func = func; + tfl->name = aStrdup(name); + tfl_root = tfl; + } + return 0; } /// Returns the name of the timer function. -char* search_timer_func_list(TimerFunc func) +char *search_timer_func_list(TimerFunc func) { - struct timer_func_list* tfl; + struct timer_func_list *tfl; - for( tfl=tfl_root; tfl != NULL; tfl=tfl->next ) - if (func == tfl->func) - return tfl->name; + for (tfl=tfl_root; tfl != NULL; tfl=tfl->next) + if (func == tfl->func) + return tfl->name; - return "unknown timer function"; + return "unknown timer function"; } /*---------------------------- - * Get tick time + * Get tick time *----------------------------*/ #if defined(ENABLE_RDTSC) static uint64 RDTSC_BEGINTICK = 0, RDTSC_CLOCK = 0; -static __inline uint64 _rdtsc(){ - register union{ - uint64 qw; - uint32 dw[2]; - } t; +static __inline uint64 _rdtsc() +{ + register union { + uint64 qw; + uint32 dw[2]; + } t; + + asm volatile("rdtsc":"=a"(t.dw[0]), "=d"(t.dw[1])); - asm volatile("rdtsc":"=a"(t.dw[0]), "=d"(t.dw[1]) ); - - return t.qw; + return t.qw; } -static void rdtsc_calibrate(){ - uint64 t1, t2; - int32 i; - - ShowStatus("Calibrating Timer Source, please wait... "); - - RDTSC_CLOCK = 0; - - for(i = 0; i < 5; i++){ - t1 = _rdtsc(); - usleep(1000000); //1000 MS - t2 = _rdtsc(); - RDTSC_CLOCK += (t2 - t1) / 1000; - } - RDTSC_CLOCK /= 5; - - RDTSC_BEGINTICK = _rdtsc(); - - ShowMessage(" done. (Frequency: %u Mhz)\n", (uint32)(RDTSC_CLOCK/1000) ); +static void rdtsc_calibrate() +{ + uint64 t1, t2; + int32 i; + + ShowStatus("Calibrating Timer Source, please wait... "); + + RDTSC_CLOCK = 0; + + for (i = 0; i < 5; i++) { + t1 = _rdtsc(); + usleep(1000000); //1000 MS + t2 = _rdtsc(); + RDTSC_CLOCK += (t2 - t1) / 1000; + } + RDTSC_CLOCK /= 5; + + RDTSC_BEGINTICK = _rdtsc(); + + ShowMessage(" done. (Frequency: %u Mhz)\n", (uint32)(RDTSC_CLOCK/1000)); } #endif @@ -140,19 +142,19 @@ static void rdtsc_calibrate(){ static unsigned int tick(void) { #if defined(WIN32) - return GetTickCount(); + return GetTickCount(); #elif defined(ENABLE_RDTSC) - // - return (unsigned int)((_rdtsc() - RDTSC_BEGINTICK) / RDTSC_CLOCK); - // + // + return (unsigned int)((_rdtsc() - RDTSC_BEGINTICK) / RDTSC_CLOCK); + // #elif defined(HAVE_MONOTONIC_CLOCK) - struct timespec tval; - clock_gettime(CLOCK_MONOTONIC, &tval); - return tval.tv_sec * 1000 + tval.tv_nsec / 1000000; + struct timespec tval; + clock_gettime(CLOCK_MONOTONIC, &tval); + return tval.tv_sec * 1000 + tval.tv_nsec / 1000000; #else - struct timeval tval; - gettimeofday(&tval, NULL); - return tval.tv_sec * 1000 + tval.tv_usec / 1000; + struct timeval tval; + gettimeofday(&tval, NULL); + return tval.tv_sec * 1000 + tval.tv_usec / 1000; #endif } @@ -165,14 +167,14 @@ static int gettick_count = 1; unsigned int gettick_nocache(void) { - gettick_count = TICK_CACHE; - gettick_cache = tick(); - return gettick_cache; + gettick_count = TICK_CACHE; + gettick_cache = tick(); + return gettick_cache; } unsigned int gettick(void) { - return ( --gettick_count == 0 ) ? gettick_nocache() : gettick_cache; + return (--gettick_count == 0) ? gettick_nocache() : gettick_cache; } ////////////////////////////// #else @@ -180,110 +182,108 @@ unsigned int gettick(void) // tick doesn't get cached unsigned int gettick_nocache(void) { - return tick(); + return tick(); } unsigned int gettick(void) { - return tick(); + return tick(); } ////////////////////////////////////////////////////////////////////////// #endif ////////////////////////////////////////////////////////////////////////// /*====================================== - * CORE : Timer Heap + * CORE : Timer Heap *--------------------------------------*/ /// Adds a timer to the timer_heap static void push_timer_heap(int tid) { - BHEAP_ENSURE(timer_heap, 1, 256); - BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP); + BHEAP_ENSURE(timer_heap, 1, 256); + BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP); } /*========================== - * Timer Management + * Timer Management *--------------------------*/ /// Returns a free timer id. static int acquire_timer(void) { - int tid; - - // select a free timer - if (free_timer_list_pos) { - do { - tid = free_timer_list[--free_timer_list_pos]; - } while(tid >= timer_data_num && free_timer_list_pos > 0); - } else - tid = timer_data_num; - - // check available space - if( tid >= timer_data_num ) - for (tid = timer_data_num; tid < timer_data_max && timer_data[tid].type; tid++); - if (tid >= timer_data_num && tid >= timer_data_max) - {// expand timer array - timer_data_max += 256; - if( timer_data ) - RECREATE(timer_data, struct TimerData, timer_data_max); - else - CREATE(timer_data, struct TimerData, timer_data_max); - memset(timer_data + (timer_data_max - 256), 0, sizeof(struct TimerData)*256); - } - - if( tid >= timer_data_num ) - timer_data_num = tid + 1; - - return tid; + int tid; + + // select a free timer + if (free_timer_list_pos) { + do { + tid = free_timer_list[--free_timer_list_pos]; + } while (tid >= timer_data_num && free_timer_list_pos > 0); + } else + tid = timer_data_num; + + // check available space + if (tid >= timer_data_num) + for (tid = timer_data_num; tid < timer_data_max && timer_data[tid].type; tid++); + if (tid >= timer_data_num && tid >= timer_data_max) { + // expand timer array + timer_data_max += 256; + if (timer_data) + RECREATE(timer_data, struct TimerData, timer_data_max); + else + CREATE(timer_data, struct TimerData, timer_data_max); + memset(timer_data + (timer_data_max - 256), 0, sizeof(struct TimerData)*256); + } + + if (tid >= timer_data_num) + timer_data_num = tid + 1; + + return tid; } /// Starts a new timer that is deleted once it expires (single-use). /// Returns the timer's id. int add_timer(unsigned int tick, TimerFunc func, int id, intptr_t data) { - int tid; - - tid = acquire_timer(); - timer_data[tid].tick = tick; - timer_data[tid].func = func; - timer_data[tid].id = id; - timer_data[tid].data = data; - timer_data[tid].type = TIMER_ONCE_AUTODEL; - timer_data[tid].interval = 1000; - push_timer_heap(tid); - - return tid; + int tid; + + tid = acquire_timer(); + timer_data[tid].tick = tick; + timer_data[tid].func = func; + timer_data[tid].id = id; + timer_data[tid].data = data; + timer_data[tid].type = TIMER_ONCE_AUTODEL; + timer_data[tid].interval = 1000; + push_timer_heap(tid); + + return tid; } /// Starts a new timer that automatically restarts itself (infinite loop until manually removed). /// Returns the timer's id, or INVALID_TIMER if it fails. int add_timer_interval(unsigned int tick, TimerFunc func, int id, intptr_t data, int interval) { - int tid; - - if( interval < 1 ) - { - ShowError("add_timer_interval: invalid interval (tick=%u %p[%s] id=%d data=%d diff_tick=%d)\n", tick, func, search_timer_func_list(func), id, data, DIFF_TICK(tick, gettick())); - return INVALID_TIMER; - } - - tid = acquire_timer(); - timer_data[tid].tick = tick; - timer_data[tid].func = func; - timer_data[tid].id = id; - timer_data[tid].data = data; - timer_data[tid].type = TIMER_INTERVAL; - timer_data[tid].interval = interval; - push_timer_heap(tid); - - return tid; + int tid; + + if (interval < 1) { + ShowError("add_timer_interval: invalid interval (tick=%u %p[%s] id=%d data=%d diff_tick=%d)\n", tick, func, search_timer_func_list(func), id, data, DIFF_TICK(tick, gettick())); + return INVALID_TIMER; + } + + tid = acquire_timer(); + timer_data[tid].tick = tick; + timer_data[tid].func = func; + timer_data[tid].id = id; + timer_data[tid].data = data; + timer_data[tid].type = TIMER_INTERVAL; + timer_data[tid].interval = interval; + push_timer_heap(tid); + + return tid; } /// Retrieves internal timer data -const struct TimerData* get_timer(int tid) -{ - return ( tid >= 0 && tid < timer_data_num ) ? &timer_data[tid] : NULL; +const struct TimerData *get_timer(int tid) { + return (tid >= 0 && tid < timer_data_num) ? &timer_data[tid] : NULL; } /// Marks a timer specified by 'id' for immediate deletion once it expires. @@ -291,142 +291,135 @@ const struct TimerData* get_timer(int tid) /// Returns 0 on success, < 0 on failure. int delete_timer(int tid, TimerFunc func) { - if( tid < 0 || tid >= timer_data_num ) - { - ShowError("delete_timer error : no such timer %d (%p(%s))\n", tid, func, search_timer_func_list(func)); - return -1; - } - if( timer_data[tid].func != func ) - { - ShowError("delete_timer error : function mismatch %p(%s) != %p(%s)\n", timer_data[tid].func, search_timer_func_list(timer_data[tid].func), func, search_timer_func_list(func)); - return -2; - } - - timer_data[tid].func = NULL; - timer_data[tid].type = TIMER_ONCE_AUTODEL; - - return 0; + if (tid < 0 || tid >= timer_data_num) { + ShowError("delete_timer error : no such timer %d (%p(%s))\n", tid, func, search_timer_func_list(func)); + return -1; + } + if (timer_data[tid].func != func) { + ShowError("delete_timer error : function mismatch %p(%s) != %p(%s)\n", timer_data[tid].func, search_timer_func_list(timer_data[tid].func), func, search_timer_func_list(func)); + return -2; + } + + timer_data[tid].func = NULL; + timer_data[tid].type = TIMER_ONCE_AUTODEL; + + return 0; } /// Adjusts a timer's expiration time. /// Returns the new tick value, or -1 if it fails. int addtick_timer(int tid, unsigned int tick) { - return settick_timer(tid, timer_data[tid].tick+tick); + return settick_timer(tid, timer_data[tid].tick+tick); } /// Modifies a timer's expiration time (an alternative to deleting a timer and starting a new one). /// Returns the new tick value, or -1 if it fails. int settick_timer(int tid, unsigned int tick) { - size_t i; - - // search timer position - ARR_FIND(0, BHEAP_LENGTH(timer_heap), i, BHEAP_DATA(timer_heap)[i] == tid); - if( i == BHEAP_LENGTH(timer_heap) ) - { - ShowError("settick_timer: no such timer %d (%p(%s))\n", tid, timer_data[tid].func, search_timer_func_list(timer_data[tid].func)); - return -1; - } - - if( (int)tick == -1 ) - tick = 0;// add 1ms to avoid the error value -1 - - if( timer_data[tid].tick == tick ) - return (int)tick;// nothing to do, already in propper position - - // pop and push adjusted timer - BHEAP_POPINDEX(timer_heap, i, DIFFTICK_MINTOPCMP); - timer_data[tid].tick = tick; - BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP); - return (int)tick; + size_t i; + + // search timer position + ARR_FIND(0, BHEAP_LENGTH(timer_heap), i, BHEAP_DATA(timer_heap)[i] == tid); + if (i == BHEAP_LENGTH(timer_heap)) { + ShowError("settick_timer: no such timer %d (%p(%s))\n", tid, timer_data[tid].func, search_timer_func_list(timer_data[tid].func)); + return -1; + } + + if ((int)tick == -1) + tick = 0;// add 1ms to avoid the error value -1 + + if (timer_data[tid].tick == tick) + return (int)tick;// nothing to do, already in propper position + + // pop and push adjusted timer + BHEAP_POPINDEX(timer_heap, i, DIFFTICK_MINTOPCMP); + timer_data[tid].tick = tick; + BHEAP_PUSH(timer_heap, tid, DIFFTICK_MINTOPCMP); + return (int)tick; } /// Executes all expired timers. /// Returns the value of the smallest non-expired timer (or 1 second if there aren't any). int do_timer(unsigned int tick) { - int diff = TIMER_MAX_INTERVAL; // return value - - // process all timers one by one - while( BHEAP_LENGTH(timer_heap) ) - { - int tid = BHEAP_PEEK(timer_heap);// top element in heap (smallest tick) - - diff = DIFF_TICK(timer_data[tid].tick, tick); - if( diff > 0 ) - break; // no more expired timers to process - - // remove timer - BHEAP_POP(timer_heap, DIFFTICK_MINTOPCMP); - timer_data[tid].type |= TIMER_REMOVE_HEAP; - - if( timer_data[tid].func ) - { - if( diff < -1000 ) - // timer was delayed for more than 1 second, use current tick instead - timer_data[tid].func(tid, tick, timer_data[tid].id, timer_data[tid].data); - else - timer_data[tid].func(tid, timer_data[tid].tick, timer_data[tid].id, timer_data[tid].data); - } - - // in the case the function didn't change anything... - if( timer_data[tid].type & TIMER_REMOVE_HEAP ) - { - timer_data[tid].type &= ~TIMER_REMOVE_HEAP; - - switch( timer_data[tid].type ) - { - default: - case TIMER_ONCE_AUTODEL: - timer_data[tid].type = 0; - if (free_timer_list_pos >= free_timer_list_max) { - free_timer_list_max += 256; - RECREATE(free_timer_list,int,free_timer_list_max); - memset(free_timer_list + (free_timer_list_max - 256), 0, 256 * sizeof(int)); - } - free_timer_list[free_timer_list_pos++] = tid; - break; - case TIMER_INTERVAL: - if( DIFF_TICK(timer_data[tid].tick, tick) < -1000 ) - timer_data[tid].tick = tick + timer_data[tid].interval; - else - timer_data[tid].tick += timer_data[tid].interval; - push_timer_heap(tid); - break; - } - } - } - - return cap_value(diff, TIMER_MIN_INTERVAL, TIMER_MAX_INTERVAL); + int diff = TIMER_MAX_INTERVAL; // return value + + // process all timers one by one + while (BHEAP_LENGTH(timer_heap)) { + int tid = BHEAP_PEEK(timer_heap);// top element in heap (smallest tick) + + diff = DIFF_TICK(timer_data[tid].tick, tick); + if (diff > 0) + break; // no more expired timers to process + + // remove timer + BHEAP_POP(timer_heap, DIFFTICK_MINTOPCMP); + timer_data[tid].type |= TIMER_REMOVE_HEAP; + + if (timer_data[tid].func) { + if (diff < -1000) + // timer was delayed for more than 1 second, use current tick instead + timer_data[tid].func(tid, tick, timer_data[tid].id, timer_data[tid].data); + else + timer_data[tid].func(tid, timer_data[tid].tick, timer_data[tid].id, timer_data[tid].data); + } + + // in the case the function didn't change anything... + if (timer_data[tid].type & TIMER_REMOVE_HEAP) { + timer_data[tid].type &= ~TIMER_REMOVE_HEAP; + + switch (timer_data[tid].type) { + default: + case TIMER_ONCE_AUTODEL: + timer_data[tid].type = 0; + if (free_timer_list_pos >= free_timer_list_max) { + free_timer_list_max += 256; + RECREATE(free_timer_list,int,free_timer_list_max); + memset(free_timer_list + (free_timer_list_max - 256), 0, 256 * sizeof(int)); + } + free_timer_list[free_timer_list_pos++] = tid; + break; + case TIMER_INTERVAL: + if (DIFF_TICK(timer_data[tid].tick, tick) < -1000) + timer_data[tid].tick = tick + timer_data[tid].interval; + else + timer_data[tid].tick += timer_data[tid].interval; + push_timer_heap(tid); + break; + } + } + } + + return cap_value(diff, TIMER_MIN_INTERVAL, TIMER_MAX_INTERVAL); } unsigned long get_uptime(void) { - return (unsigned long)difftime(time(NULL), start_time); + return (unsigned long)difftime(time(NULL), start_time); } void timer_init(void) { #if defined(ENABLE_RDTSC) - rdtsc_calibrate(); + rdtsc_calibrate(); #endif - time(&start_time); + time(&start_time); } void timer_final(void) { - struct timer_func_list *tfl; - struct timer_func_list *next; - - for( tfl=tfl_root; tfl != NULL; tfl = next ) { - next = tfl->next; // copy next pointer - aFree(tfl->name); // free structures - aFree(tfl); - } - - if (timer_data) aFree(timer_data); - BHEAP_CLEAR(timer_heap); - if (free_timer_list) aFree(free_timer_list); + struct timer_func_list *tfl; + struct timer_func_list *next; + + for (tfl=tfl_root; tfl != NULL; tfl = next) { + next = tfl->next; // copy next pointer + aFree(tfl->name); // free structures + aFree(tfl); + } + + if (timer_data) aFree(timer_data); + BHEAP_CLEAR(timer_heap); + if (free_timer_list) aFree(free_timer_list); } diff --git a/src/common/timer.h b/src/common/timer.h index d45c73d12..9b46927d8 100644 --- a/src/common/timer.h +++ b/src/common/timer.h @@ -1,8 +1,8 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _TIMER_H_ -#define _TIMER_H_ +#ifndef _TIMER_H_ +#define _TIMER_H_ #include "../common/cbasetypes.h" @@ -12,9 +12,9 @@ // timer flags enum { - TIMER_ONCE_AUTODEL = 0x01, - TIMER_INTERVAL = 0x02, - TIMER_REMOVE_HEAP = 0x10, + TIMER_ONCE_AUTODEL = 0x01, + TIMER_INTERVAL = 0x02, + TIMER_REMOVE_HEAP = 0x10, }; // Struct declaration @@ -22,15 +22,15 @@ enum { typedef int (*TimerFunc)(int tid, unsigned int tick, int id, intptr_t data); struct TimerData { - unsigned int tick; - TimerFunc func; - int type; - int interval; - int heap_pos; - - // general-purpose storage - int id; - intptr_t data; + unsigned int tick; + TimerFunc func; + int type; + int interval; + int heap_pos; + + // general-purpose storage + int id; + intptr_t data; }; // Function prototype declaration @@ -40,13 +40,13 @@ unsigned int gettick_nocache(void); int add_timer(unsigned int tick, TimerFunc func, int id, intptr_t data); int add_timer_interval(unsigned int tick, TimerFunc func, int id, intptr_t data, int interval); -const struct TimerData* get_timer(int tid); +const struct TimerData *get_timer(int tid); int delete_timer(int tid, TimerFunc func); int addtick_timer(int tid, unsigned int tick); int settick_timer(int tid, unsigned int tick); -int add_timer_func_list(TimerFunc func, char* name); +int add_timer_func_list(TimerFunc func, char *name); unsigned long get_uptime(void); diff --git a/src/common/utils.c b/src/common/utils.c index 296df7e70..9d090f594 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -15,269 +15,262 @@ #include // floor() #ifdef WIN32 - #include "../common/winapi.h" - #ifndef F_OK - #define F_OK 0x0 - #endif /* F_OK */ +#include "../common/winapi.h" +#ifndef F_OK +#define F_OK 0x0 +#endif /* F_OK */ #else - #include - #include - #include +#include +#include +#include #endif /// Dumps given buffer into file pointed to by a handle. -void WriteDump(FILE* fp, const void* buffer, size_t length) +void WriteDump(FILE *fp, const void *buffer, size_t length) { - size_t i; - char hex[48+1], ascii[16+1]; - - fprintf(fp, "--- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F 0123456789ABCDEF\n"); - ascii[16] = 0; - - for( i = 0; i < length; i++ ) - { - char c = RBUFB(buffer,i); - - ascii[i%16] = ISCNTRL(c) ? '.' : c; - sprintf(hex+(i%16)*3, "%02X ", RBUFB(buffer,i)); - - if( (i%16) == 15 ) - { - fprintf(fp, "%03X %s %s\n", (unsigned int)(i/16), hex, ascii); - } - } - - if( (i%16) != 0 ) - { - ascii[i%16] = 0; - fprintf(fp, "%03X %-48s %-16s\n", (unsigned int)(i/16), hex, ascii); - } + size_t i; + char hex[48+1], ascii[16+1]; + + fprintf(fp, "--- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F 0123456789ABCDEF\n"); + ascii[16] = 0; + + for (i = 0; i < length; i++) { + char c = RBUFB(buffer,i); + + ascii[i%16] = ISCNTRL(c) ? '.' : c; + sprintf(hex+(i%16)*3, "%02X ", RBUFB(buffer,i)); + + if ((i%16) == 15) { + fprintf(fp, "%03X %s %s\n", (unsigned int)(i/16), hex, ascii); + } + } + + if ((i%16) != 0) { + ascii[i%16] = 0; + fprintf(fp, "%03X %-48s %-16s\n", (unsigned int)(i/16), hex, ascii); + } } /// Dumps given buffer on the console. -void ShowDump(const void* buffer, size_t length) +void ShowDump(const void *buffer, size_t length) { - size_t i; - char hex[48+1], ascii[16+1]; - - ShowDebug("--- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F 0123456789ABCDEF\n"); - ascii[16] = 0; - - for( i = 0; i < length; i++ ) - { - char c = RBUFB(buffer,i); - - ascii[i%16] = ISCNTRL(c) ? '.' : c; - sprintf(hex+(i%16)*3, "%02X ", RBUFB(buffer,i)); - - if( (i%16) == 15 ) - { - ShowDebug("%03X %s %s\n", i/16, hex, ascii); - } - } - - if( (i%16) != 0 ) - { - ascii[i%16] = 0; - ShowDebug("%03X %-48s %-16s\n", i/16, hex, ascii); - } + size_t i; + char hex[48+1], ascii[16+1]; + + ShowDebug("--- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F 0123456789ABCDEF\n"); + ascii[16] = 0; + + for (i = 0; i < length; i++) { + char c = RBUFB(buffer,i); + + ascii[i%16] = ISCNTRL(c) ? '.' : c; + sprintf(hex+(i%16)*3, "%02X ", RBUFB(buffer,i)); + + if ((i%16) == 15) { + ShowDebug("%03X %s %s\n", i/16, hex, ascii); + } + } + + if ((i%16) != 0) { + ascii[i%16] = 0; + ShowDebug("%03X %-48s %-16s\n", i/16, hex, ascii); + } } #ifdef WIN32 -static char* checkpath(char *path, const char *srcpath) -{ // just make sure the char*path is not const - char *p=path; - if(NULL!=path && NULL!=srcpath) - while(*srcpath) { - if (*srcpath=='/') { - *p++ = '\\'; - srcpath++; - } - else - *p++ = *srcpath++; - } - *p = *srcpath; //EOS - return path; +static char *checkpath(char *path, const char *srcpath) +{ + // just make sure the char*path is not const + char *p=path; + if (NULL!=path && NULL!=srcpath) + while (*srcpath) { + if (*srcpath=='/') { + *p++ = '\\'; + srcpath++; + } else + *p++ = *srcpath++; + } + *p = *srcpath; //EOS + return path; } -void findfile(const char *p, const char *pat, void (func)(const char*)) +void findfile(const char *p, const char *pat, void (func)(const char *)) { - WIN32_FIND_DATAA FindFileData; - HANDLE hFind; - char tmppath[MAX_PATH+1]; - - const char *path = (p ==NULL)? "." : p; - const char *pattern = (pat==NULL)? "" : pat; - - checkpath(tmppath,path); - if( PATHSEP != tmppath[strlen(tmppath)-1]) - strcat(tmppath, "\\*"); - else - strcat(tmppath, "*"); - - hFind = FindFirstFileA(tmppath, &FindFileData); - if (hFind != INVALID_HANDLE_VALUE) - { - do - { - if (strcmp(FindFileData.cFileName, ".") == 0) - continue; - if (strcmp(FindFileData.cFileName, "..") == 0) - continue; - - sprintf(tmppath,"%s%c%s",path,PATHSEP,FindFileData.cFileName); - - if (FindFileData.cFileName && strstr(FindFileData.cFileName, pattern)) { - func( tmppath ); - } - - - if( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) - { - findfile(tmppath, pat, func); - } - }while (FindNextFileA(hFind, &FindFileData) != 0); - FindClose(hFind); - } - return; + WIN32_FIND_DATAA FindFileData; + HANDLE hFind; + char tmppath[MAX_PATH+1]; + + const char *path = (p ==NULL)? "." : p; + const char *pattern = (pat==NULL)? "" : pat; + + checkpath(tmppath,path); + if (PATHSEP != tmppath[strlen(tmppath)-1]) + strcat(tmppath, "\\*"); + else + strcat(tmppath, "*"); + + hFind = FindFirstFileA(tmppath, &FindFileData); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (strcmp(FindFileData.cFileName, ".") == 0) + continue; + if (strcmp(FindFileData.cFileName, "..") == 0) + continue; + + sprintf(tmppath,"%s%c%s",path,PATHSEP,FindFileData.cFileName); + + if (FindFileData.cFileName && strstr(FindFileData.cFileName, pattern)) { + func(tmppath); + } + + + if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + findfile(tmppath, pat, func); + } + } while (FindNextFileA(hFind, &FindFileData) != 0); + FindClose(hFind); + } + return; } #else #define MAX_DIR_PATH 2048 -static char* checkpath(char *path, const char*srcpath) -{ // just make sure the char*path is not const - char *p=path; - if(NULL!=path && NULL!=srcpath) - while(*srcpath) { - if (*srcpath=='\\') { - *p++ = '/'; - srcpath++; - } - else - *p++ = *srcpath++; - } - *p = *srcpath; //EOS - return path; +static char *checkpath(char *path, const char *srcpath) +{ + // just make sure the char*path is not const + char *p=path; + if (NULL!=path && NULL!=srcpath) + while (*srcpath) { + if (*srcpath=='\\') { + *p++ = '/'; + srcpath++; + } else + *p++ = *srcpath++; + } + *p = *srcpath; //EOS + return path; } -void findfile(const char *p, const char *pat, void (func)(const char*)) +void findfile(const char *p, const char *pat, void (func)(const char *)) { - DIR* dir; // pointer to the scanned directory. - struct dirent* entry; // pointer to one directory entry. - struct stat dir_stat; // used by stat(). - char tmppath[MAX_DIR_PATH+1]; - char path[MAX_DIR_PATH+1]= "."; - const char *pattern = (pat==NULL)? "" : pat; - if(p!=NULL) strcpy(path,p); - - // open the directory for reading - dir = opendir( checkpath(path, path) ); - if (!dir) { - ShowError("Cannot read directory '%s'\n", path); - return; - } - - // scan the directory, traversing each sub-directory - // matching the pattern for each file name. - while ((entry = readdir(dir))) { - // skip the "." and ".." entries. - if (strcmp(entry->d_name, ".") == 0) - continue; - if (strcmp(entry->d_name, "..") == 0) - continue; - - sprintf(tmppath,"%s%c%s",path, PATHSEP, entry->d_name); - - // check if the pattern matchs. - if (entry->d_name && strstr(entry->d_name, pattern)) { - func( tmppath ); - } - // check if it is a directory. - if (stat(tmppath, &dir_stat) == -1) { - ShowError("stat error %s\n': ", tmppath); - continue; - } - // is this a directory? - if (S_ISDIR(dir_stat.st_mode)) { - // decent recursivly - findfile(tmppath, pat, func); - } - }//end while - - closedir(dir); + DIR *dir; // pointer to the scanned directory. + struct dirent *entry; // pointer to one directory entry. + struct stat dir_stat; // used by stat(). + char tmppath[MAX_DIR_PATH+1]; + char path[MAX_DIR_PATH+1]= "."; + const char *pattern = (pat==NULL)? "" : pat; + if (p!=NULL) strcpy(path,p); + + // open the directory for reading + dir = opendir(checkpath(path, path)); + if (!dir) { + ShowError("Cannot read directory '%s'\n", path); + return; + } + + // scan the directory, traversing each sub-directory + // matching the pattern for each file name. + while ((entry = readdir(dir))) { + // skip the "." and ".." entries. + if (strcmp(entry->d_name, ".") == 0) + continue; + if (strcmp(entry->d_name, "..") == 0) + continue; + + sprintf(tmppath,"%s%c%s",path, PATHSEP, entry->d_name); + + // check if the pattern matchs. + if (entry->d_name && strstr(entry->d_name, pattern)) { + func(tmppath); + } + // check if it is a directory. + if (stat(tmppath, &dir_stat) == -1) { + ShowError("stat error %s\n': ", tmppath); + continue; + } + // is this a directory? + if (S_ISDIR(dir_stat.st_mode)) { + // decent recursivly + findfile(tmppath, pat, func); + } + }//end while + + closedir(dir); } #endif -bool exists(const char* filename) +bool exists(const char *filename) { - return !access(filename, F_OK); + return !access(filename, F_OK); } uint8 GetByte(uint32 val, int idx) { - switch( idx ) - { - case 0: return (uint8)( (val & 0x000000FF) ); - case 1: return (uint8)( (val & 0x0000FF00) >> 0x08 ); - case 2: return (uint8)( (val & 0x00FF0000) >> 0x10 ); - case 3: return (uint8)( (val & 0xFF000000) >> 0x18 ); - default: + switch (idx) { + case 0: + return (uint8)((val & 0x000000FF)); + case 1: + return (uint8)((val & 0x0000FF00) >> 0x08); + case 2: + return (uint8)((val & 0x00FF0000) >> 0x10); + case 3: + return (uint8)((val & 0xFF000000) >> 0x18); + default: #if defined(DEBUG) - ShowDebug("GetByte: invalid index (idx=%d)\n", idx); + ShowDebug("GetByte: invalid index (idx=%d)\n", idx); #endif - return 0; - } + return 0; + } } uint16 GetWord(uint32 val, int idx) { - switch( idx ) - { - case 0: return (uint16)( (val & 0x0000FFFF) ); - case 1: return (uint16)( (val & 0xFFFF0000) >> 0x10 ); - default: + switch (idx) { + case 0: + return (uint16)((val & 0x0000FFFF)); + case 1: + return (uint16)((val & 0xFFFF0000) >> 0x10); + default: #if defined(DEBUG) - ShowDebug("GetWord: invalid index (idx=%d)\n", idx); + ShowDebug("GetWord: invalid index (idx=%d)\n", idx); #endif - return 0; - } + return 0; + } } uint16 MakeWord(uint8 byte0, uint8 byte1) { - return byte0 | (byte1 << 0x08); + return byte0 | (byte1 << 0x08); } uint32 MakeDWord(uint16 word0, uint16 word1) { - return - ( (uint32)(word0 ) )| - ( (uint32)(word1 << 0x10) ); + return + ((uint32)(word0))| + ((uint32)(word1 << 0x10)); } /// calculates the value of A / B, in percent (rounded down) unsigned int get_percentage(const unsigned int A, const unsigned int B) { - double result; + double result; - if( B == 0 ) - { - ShowError("get_percentage(): divison by zero! (A=%u,B=%u)\n", A, B); - return ~0U; - } + if (B == 0) { + ShowError("get_percentage(): divison by zero! (A=%u,B=%u)\n", A, B); + return ~0U; + } - result = 100 * ((double)A / (double)B); + result = 100 * ((double)A / (double)B); - if( result > UINT_MAX ) - { - ShowError("get_percentage(): result percentage too high! (A=%u,B=%u,result=%g)\n", A, B, result); - return UINT_MAX; - } + if (result > UINT_MAX) { + ShowError("get_percentage(): result percentage too high! (A=%u,B=%u,result=%g)\n", A, B, result); + return UINT_MAX; + } - return (unsigned int)floor(result); + return (unsigned int)floor(result); } diff --git a/src/common/utils.h b/src/common/utils.h index 8e39f2655..7f68e484e 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -8,11 +8,11 @@ #include // FILE* // generate a hex dump of the first 'length' bytes of 'buffer' -void WriteDump(FILE* fp, const void* buffer, size_t length); -void ShowDump(const void* buffer, size_t length); +void WriteDump(FILE *fp, const void *buffer, size_t length); +void ShowDump(const void *buffer, size_t length); -void findfile(const char *p, const char *pat, void (func)(const char*)); -bool exists(const char* filename); +void findfile(const char *p, const char *pat, void (func)(const char *)); +bool exists(const char *filename); //Caps values to min/max #define cap_value(a, min, max) ((a >= max) ? max : (a <= min) ? min : a) diff --git a/src/common/winapi.h b/src/common/winapi.h index 7ce555049..dfb7d4588 100644 --- a/src/common/winapi.h +++ b/src/common/winapi.h @@ -2,12 +2,12 @@ #define STRICT -#define NTDDI_VERSION NTDDI_WIN2K +#define NTDDI_VERSION NTDDI_WIN2K #define _WIN32_WINNT 0x0500 #define WINVER 0x0500 -#define _WIN32_IE 0x0600 +#define _WIN32_IE 0x0600 #define WIN32_LEAN_AND_MEAN -#define NOCOMM +#define NOCOMM #define NOKANJI #define NOHELP #define NOMCX diff --git a/src/config/const.h b/src/config/const.h index 5fb74e22e..11477e75f 100644 --- a/src/config/const.h +++ b/src/config/const.h @@ -13,85 +13,85 @@ */ /** - * "Sane Checks" to save you from compiling with cool bugs + * "Sane Checks" to save you from compiling with cool bugs **/ #if SECURE_NPCTIMEOUT_INTERVAL <= 0 - #error SECURE_NPCTIMEOUT_INTERVAL should be at least 1 (1s) +#error SECURE_NPCTIMEOUT_INTERVAL should be at least 1 (1s) #endif #if SECURE_NPCTIMEOUT < 0 - #error SECURE_NPCTIMEOUT cannot be lower than 0 +#error SECURE_NPCTIMEOUT cannot be lower than 0 #endif /** * Path within the /db folder to (non-)renewal specific db files **/ #ifdef RENEWAL - #define DBPATH "re/" +#define DBPATH "re/" #else - #define DBPATH "pre-re/" +#define DBPATH "pre-re/" #endif /** * DefType **/ #ifdef RENEWAL - typedef short defType; - #define DEFTYPE_MIN SHRT_MIN - #define DEFTYPE_MAX SHRT_MAX +typedef short defType; +#define DEFTYPE_MIN SHRT_MIN +#define DEFTYPE_MAX SHRT_MAX #else - typedef signed char defType; - #define DEFTYPE_MIN CHAR_MIN - #define DEFTYPE_MAX CHAR_MAX +typedef signed char defType; +#define DEFTYPE_MIN CHAR_MIN +#define DEFTYPE_MAX CHAR_MAX #endif /* pointer size fix which fixes several gcc warnings */ #ifdef __64BIT__ - #define __64BPRTSIZE(y) (intptr)y +#define __64BPRTSIZE(y) (intptr)y #else - #define __64BPRTSIZE(y) y +#define __64BPRTSIZE(y) y #endif /* ATCMD_FUNC(mobinfo) HIT and FLEE calculations */ #ifdef RENEWAL - #define MOB_FLEE(mob) ( mob->lv + mob->status.agi + mob->status.luk/5 + 100 ) - #define MOB_HIT(mob) ( mob->lv + mob->status.dex + mob->status.luk/3 + 175 ) +#define MOB_FLEE(mob) ( mob->lv + mob->status.agi + mob->status.luk/5 + 100 ) +#define MOB_HIT(mob) ( mob->lv + mob->status.dex + mob->status.luk/3 + 175 ) #else - #define MOB_FLEE(mob) ( mob->lv + mob->status.agi ) - #define MOB_HIT(mob) ( mob->lv + mob->status.dex ) +#define MOB_FLEE(mob) ( mob->lv + mob->status.agi ) +#define MOB_HIT(mob) ( mob->lv + mob->status.dex ) #endif /* Renewal's dmg level modifier, used as a macro for a easy way to turn off. */ #ifdef RENEWAL_LVDMG - #define RE_LVL_DMOD(val) \ - if( status_get_lv(src) > 100 && val > 0 ) \ - skillratio = skillratio * status_get_lv(src) / val; - #define RE_LVL_MDMOD(val) \ - if( status_get_lv(src) > 100 && val > 0) \ - md.damage = md.damage * status_get_lv(src) / val; - /* ranger traps special */ - #define RE_LVL_TMDMOD() \ - if( status_get_lv(src) > 100 ) \ - md.damage = md.damage * 150 / 100 + md.damage * status_get_lv(src) / 100; +#define RE_LVL_DMOD(val) \ + if( status_get_lv(src) > 100 && val > 0 ) \ + skillratio = skillratio * status_get_lv(src) / val; +#define RE_LVL_MDMOD(val) \ + if( status_get_lv(src) > 100 && val > 0) \ + md.damage = md.damage * status_get_lv(src) / val; +/* ranger traps special */ +#define RE_LVL_TMDMOD() \ + if( status_get_lv(src) > 100 ) \ + md.damage = md.damage * 150 / 100 + md.damage * status_get_lv(src) / 100; #else - #define RE_LVL_DMOD(val) - #define RE_LVL_MDMOD(val) - #define RE_LVL_TMDMOD() +#define RE_LVL_DMOD(val) +#define RE_LVL_MDMOD(val) +#define RE_LVL_TMDMOD() #endif /* Feb 1st 2012 */ #if PACKETVER >= 20120201 - #define NEW_CARTS - #define MAX_CARTS 9 +#define NEW_CARTS +#define MAX_CARTS 9 #else - #define MAX_CARTS 5 +#define MAX_CARTS 5 #endif // Renewal variable cast time reduction #ifdef RENEWAL_CAST - #define VARCAST_REDUCTION(val){ \ - if( (varcast_r += val) != 0 && varcast_r >= 0 ) \ - time = time * (1 - (float)min(val, 100) / 100); \ - } +#define VARCAST_REDUCTION(val){ \ + if( (varcast_r += val) != 0 && varcast_r >= 0 ) \ + time = time * (1 - (float)min(val, 100) / 100); \ + } #endif /** * End of File diff --git a/src/login/account.h b/src/login/account.h index 1b567be70..22e31d799 100644 --- a/src/login/account.h +++ b/src/login/account.h @@ -12,144 +12,141 @@ typedef struct AccountDBIterator AccountDBIterator; // standard engines -AccountDB* account_db_sql(void); +AccountDB *account_db_sql(void); // extra engines (will probably use the other txt functions) #define ACCOUNTDB_CONSTRUCTOR_(engine) account_db_##engine #define ACCOUNTDB_CONSTRUCTOR(engine) ACCOUNTDB_CONSTRUCTOR_(engine) #ifdef ACCOUNTDB_ENGINE_0 -AccountDB* ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_0)(void); +AccountDB *ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_0)(void); #endif #ifdef ACCOUNTDB_ENGINE_1 -AccountDB* ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_1)(void); +AccountDB *ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_1)(void); #endif #ifdef ACCOUNTDB_ENGINE_2 -AccountDB* ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_2)(void); +AccountDB *ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_2)(void); #endif #ifdef ACCOUNTDB_ENGINE_3 -AccountDB* ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_3)(void); +AccountDB *ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_3)(void); #endif #ifdef ACCOUNTDB_ENGINE_4 -AccountDB* ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_4)(void); +AccountDB *ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_4)(void); #endif -struct mmo_account -{ - int account_id; - char userid[NAME_LENGTH]; - char pass[32+1]; // 23+1 for plaintext, 32+1 for md5-ed passwords - char sex; // gender (M/F/S) - char email[40]; // e-mail (by default: a@a.com) - int group_id; // player group id - unsigned int state; // packet 0x006a value + 1 (0: compte OK) - time_t unban_time; // (timestamp): ban time limit of the account (0 = no ban) - time_t expiration_time; // (timestamp): validity limit of the account (0 = unlimited) - unsigned int logincount;// number of successful auth attempts - char lastlogin[24]; // date+time of last successful login - char last_ip[16]; // save of last IP of connection - char birthdate[10+1]; // assigned birth date (format: YYYY-MM-DD, default: 0000-00-00) - int account_reg2_num; - struct global_reg account_reg2[ACCOUNT_REG2_NUM]; // account script variables (stored on login server) +struct mmo_account { + int account_id; + char userid[NAME_LENGTH]; + char pass[32+1]; // 23+1 for plaintext, 32+1 for md5-ed passwords + char sex; // gender (M/F/S) + char email[40]; // e-mail (by default: a@a.com) + int group_id; // player group id + unsigned int state; // packet 0x006a value + 1 (0: compte OK) + time_t unban_time; // (timestamp): ban time limit of the account (0 = no ban) + time_t expiration_time; // (timestamp): validity limit of the account (0 = unlimited) + unsigned int logincount;// number of successful auth attempts + char lastlogin[24]; // date+time of last successful login + char last_ip[16]; // save of last IP of connection + char birthdate[10+1]; // assigned birth date (format: YYYY-MM-DD, default: 0000-00-00) + int account_reg2_num; + struct global_reg account_reg2[ACCOUNT_REG2_NUM]; // account script variables (stored on login server) }; -struct AccountDBIterator -{ - /// Destroys this iterator, releasing all allocated memory (including itself). - /// - /// @param self Iterator - void (*destroy)(AccountDBIterator* self); +struct AccountDBIterator { + /// Destroys this iterator, releasing all allocated memory (including itself). + /// + /// @param self Iterator + void (*destroy)(AccountDBIterator *self); - /// Fetches the next account in the database. - /// Fills acc with the account data. - /// @param self Iterator - /// @param acc Account data - /// @return true if successful - bool (*next)(AccountDBIterator* self, struct mmo_account* acc); + /// Fetches the next account in the database. + /// Fills acc with the account data. + /// @param self Iterator + /// @param acc Account data + /// @return true if successful + bool (*next)(AccountDBIterator *self, struct mmo_account *acc); }; -struct AccountDB -{ - /// Initializes this database, making it ready for use. - /// Call this after setting the properties. - /// - /// @param self Database - /// @return true if successful - bool (*init)(AccountDB* self); - - /// Destroys this database, releasing all allocated memory (including itself). - /// - /// @param self Database - void (*destroy)(AccountDB* self); - - /// Gets a property from this database. - /// These read-only properties must be implemented: - /// "engine.name" -> "txt", "sql", ... - /// "engine.version" -> internal version - /// "engine.comment" -> anything (suggestion: description or specs of the engine) - /// - /// @param self Database - /// @param key Property name - /// @param buf Buffer for the value - /// @param buflen Buffer length - /// @return true if successful - bool (*get_property)(AccountDB* self, const char* key, char* buf, size_t buflen); - - /// Sets a property in this database. - /// - /// @param self Database - /// @param key Property name - /// @param value Property value - /// @return true if successful - bool (*set_property)(AccountDB* self, const char* key, const char* value); - - /// Creates a new account in this database. - /// If acc->account_id is not -1, the provided value will be used. - /// Otherwise the account_id will be auto-generated and written to acc->account_id. - /// - /// @param self Database - /// @param acc Account data - /// @return true if successful - bool (*create)(AccountDB* self, struct mmo_account* acc); - - /// Removes an account from this database. - /// - /// @param self Database - /// @param account_id Account id - /// @return true if successful - bool (*remove)(AccountDB* self, const int account_id); - - /// Modifies the data of an existing account. - /// Uses acc->account_id to identify the account. - /// - /// @param self Database - /// @param acc Account data - /// @return true if successful - bool (*save)(AccountDB* self, const struct mmo_account* acc); - - /// Finds an account with account_id and copies it to acc. - /// - /// @param self Database - /// @param acc Pointer that receives the account data - /// @param account_id Target account id - /// @return true if successful - bool (*load_num)(AccountDB* self, struct mmo_account* acc, const int account_id); - - /// Finds an account with userid and copies it to acc. - /// - /// @param self Database - /// @param acc Pointer that receives the account data - /// @param userid Target username - /// @return true if successful - bool (*load_str)(AccountDB* self, struct mmo_account* acc, const char* userid); - - /// Returns a new forward iterator. - /// - /// @param self Database - /// @return Iterator - AccountDBIterator* (*iterator)(AccountDB* self); +struct AccountDB { + /// Initializes this database, making it ready for use. + /// Call this after setting the properties. + /// + /// @param self Database + /// @return true if successful + bool (*init)(AccountDB *self); + + /// Destroys this database, releasing all allocated memory (including itself). + /// + /// @param self Database + void (*destroy)(AccountDB *self); + + /// Gets a property from this database. + /// These read-only properties must be implemented: + /// "engine.name" -> "txt", "sql", ... + /// "engine.version" -> internal version + /// "engine.comment" -> anything (suggestion: description or specs of the engine) + /// + /// @param self Database + /// @param key Property name + /// @param buf Buffer for the value + /// @param buflen Buffer length + /// @return true if successful + bool (*get_property)(AccountDB *self, const char *key, char *buf, size_t buflen); + + /// Sets a property in this database. + /// + /// @param self Database + /// @param key Property name + /// @param value Property value + /// @return true if successful + bool (*set_property)(AccountDB *self, const char *key, const char *value); + + /// Creates a new account in this database. + /// If acc->account_id is not -1, the provided value will be used. + /// Otherwise the account_id will be auto-generated and written to acc->account_id. + /// + /// @param self Database + /// @param acc Account data + /// @return true if successful + bool (*create)(AccountDB *self, struct mmo_account *acc); + + /// Removes an account from this database. + /// + /// @param self Database + /// @param account_id Account id + /// @return true if successful + bool (*remove)(AccountDB *self, const int account_id); + + /// Modifies the data of an existing account. + /// Uses acc->account_id to identify the account. + /// + /// @param self Database + /// @param acc Account data + /// @return true if successful + bool (*save)(AccountDB *self, const struct mmo_account *acc); + + /// Finds an account with account_id and copies it to acc. + /// + /// @param self Database + /// @param acc Pointer that receives the account data + /// @param account_id Target account id + /// @return true if successful + bool (*load_num)(AccountDB *self, struct mmo_account *acc, const int account_id); + + /// Finds an account with userid and copies it to acc. + /// + /// @param self Database + /// @param acc Pointer that receives the account data + /// @param userid Target username + /// @return true if successful + bool (*load_str)(AccountDB *self, struct mmo_account *acc, const char *userid); + + /// Returns a new forward iterator. + /// + /// @param self Database + /// @return Iterator + AccountDBIterator *(*iterator)(AccountDB *self); }; diff --git a/src/login/account_sql.c b/src/login/account_sql.c index 5073941e2..6e56d4688 100644 --- a/src/login/account_sql.c +++ b/src/login/account_sql.c @@ -15,98 +15,96 @@ #define ACCOUNT_SQL_DB_VERSION 20110114 /// internal structure -typedef struct AccountDB_SQL -{ - AccountDB vtable; // public interface - - Sql* accounts; // SQL accounts storage - - // global sql settings - char global_db_hostname[32]; - uint16 global_db_port; - char global_db_username[32]; - char global_db_password[32]; - char global_db_database[32]; - char global_codepage[32]; - // local sql settings - char db_hostname[32]; - uint16 db_port; - char db_username[32]; - char db_password[32]; - char db_database[32]; - char codepage[32]; - // other settings - bool case_sensitive; - char account_db[32]; - char accreg_db[32]; +typedef struct AccountDB_SQL { + AccountDB vtable; // public interface + + Sql *accounts; // SQL accounts storage + + // global sql settings + char global_db_hostname[32]; + uint16 global_db_port; + char global_db_username[32]; + char global_db_password[32]; + char global_db_database[32]; + char global_codepage[32]; + // local sql settings + char db_hostname[32]; + uint16 db_port; + char db_username[32]; + char db_password[32]; + char db_database[32]; + char codepage[32]; + // other settings + bool case_sensitive; + char account_db[32]; + char accreg_db[32]; } AccountDB_SQL; /// internal structure -typedef struct AccountDBIterator_SQL -{ - AccountDBIterator vtable; // public interface +typedef struct AccountDBIterator_SQL { + AccountDBIterator vtable; // public interface - AccountDB_SQL* db; - int last_account_id; + AccountDB_SQL *db; + int last_account_id; } AccountDBIterator_SQL; /// internal functions -static bool account_db_sql_init(AccountDB* self); -static void account_db_sql_destroy(AccountDB* self); -static bool account_db_sql_get_property(AccountDB* self, const char* key, char* buf, size_t buflen); -static bool account_db_sql_set_property(AccountDB* self, const char* option, const char* value); -static bool account_db_sql_create(AccountDB* self, struct mmo_account* acc); -static bool account_db_sql_remove(AccountDB* self, const int account_id); -static bool account_db_sql_save(AccountDB* self, const struct mmo_account* acc); -static bool account_db_sql_load_num(AccountDB* self, struct mmo_account* acc, const int account_id); -static bool account_db_sql_load_str(AccountDB* self, struct mmo_account* acc, const char* userid); -static AccountDBIterator* account_db_sql_iterator(AccountDB* self); -static void account_db_sql_iter_destroy(AccountDBIterator* self); -static bool account_db_sql_iter_next(AccountDBIterator* self, struct mmo_account* acc); - -static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int account_id); -static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, bool is_new); +static bool account_db_sql_init(AccountDB *self); +static void account_db_sql_destroy(AccountDB *self); +static bool account_db_sql_get_property(AccountDB *self, const char *key, char *buf, size_t buflen); +static bool account_db_sql_set_property(AccountDB *self, const char *option, const char *value); +static bool account_db_sql_create(AccountDB *self, struct mmo_account *acc); +static bool account_db_sql_remove(AccountDB *self, const int account_id); +static bool account_db_sql_save(AccountDB *self, const struct mmo_account *acc); +static bool account_db_sql_load_num(AccountDB *self, struct mmo_account *acc, const int account_id); +static bool account_db_sql_load_str(AccountDB *self, struct mmo_account *acc, const char *userid); +static AccountDBIterator *account_db_sql_iterator(AccountDB *self); +static void account_db_sql_iter_destroy(AccountDBIterator *self); +static bool account_db_sql_iter_next(AccountDBIterator *self, struct mmo_account *acc); + +static bool mmo_auth_fromsql(AccountDB_SQL *db, struct mmo_account *acc, int account_id); +static bool mmo_auth_tosql(AccountDB_SQL *db, const struct mmo_account *acc, bool is_new); /// public constructor -AccountDB* account_db_sql(void) +AccountDB *account_db_sql(void) { - AccountDB_SQL* db = (AccountDB_SQL*)aCalloc(1, sizeof(AccountDB_SQL)); - - // set up the vtable - db->vtable.init = &account_db_sql_init; - db->vtable.destroy = &account_db_sql_destroy; - db->vtable.get_property = &account_db_sql_get_property; - db->vtable.set_property = &account_db_sql_set_property; - db->vtable.save = &account_db_sql_save; - db->vtable.create = &account_db_sql_create; - db->vtable.remove = &account_db_sql_remove; - db->vtable.load_num = &account_db_sql_load_num; - db->vtable.load_str = &account_db_sql_load_str; - db->vtable.iterator = &account_db_sql_iterator; - - // initialize to default values - db->accounts = NULL; - // global sql settings - safestrncpy(db->global_db_hostname, "127.0.0.1", sizeof(db->global_db_hostname)); - db->global_db_port = 3306; - safestrncpy(db->global_db_username, "ragnarok", sizeof(db->global_db_username)); - safestrncpy(db->global_db_password, "ragnarok", sizeof(db->global_db_password)); - safestrncpy(db->global_db_database, "ragnarok", sizeof(db->global_db_database)); - safestrncpy(db->global_codepage, "", sizeof(db->global_codepage)); - // local sql settings - safestrncpy(db->db_hostname, "", sizeof(db->db_hostname)); - db->db_port = 3306; - safestrncpy(db->db_username, "", sizeof(db->db_username)); - safestrncpy(db->db_password, "", sizeof(db->db_password)); - safestrncpy(db->db_database, "", sizeof(db->db_database)); - safestrncpy(db->codepage, "", sizeof(db->codepage)); - // other settings - db->case_sensitive = false; - safestrncpy(db->account_db, "login", sizeof(db->account_db)); - safestrncpy(db->accreg_db, "global_reg_value", sizeof(db->accreg_db)); - - return &db->vtable; + AccountDB_SQL *db = (AccountDB_SQL *)aCalloc(1, sizeof(AccountDB_SQL)); + + // set up the vtable + db->vtable.init = &account_db_sql_init; + db->vtable.destroy = &account_db_sql_destroy; + db->vtable.get_property = &account_db_sql_get_property; + db->vtable.set_property = &account_db_sql_set_property; + db->vtable.save = &account_db_sql_save; + db->vtable.create = &account_db_sql_create; + db->vtable.remove = &account_db_sql_remove; + db->vtable.load_num = &account_db_sql_load_num; + db->vtable.load_str = &account_db_sql_load_str; + db->vtable.iterator = &account_db_sql_iterator; + + // initialize to default values + db->accounts = NULL; + // global sql settings + safestrncpy(db->global_db_hostname, "127.0.0.1", sizeof(db->global_db_hostname)); + db->global_db_port = 3306; + safestrncpy(db->global_db_username, "ragnarok", sizeof(db->global_db_username)); + safestrncpy(db->global_db_password, "ragnarok", sizeof(db->global_db_password)); + safestrncpy(db->global_db_database, "ragnarok", sizeof(db->global_db_database)); + safestrncpy(db->global_codepage, "", sizeof(db->global_codepage)); + // local sql settings + safestrncpy(db->db_hostname, "", sizeof(db->db_hostname)); + db->db_port = 3306; + safestrncpy(db->db_username, "", sizeof(db->db_username)); + safestrncpy(db->db_password, "", sizeof(db->db_password)); + safestrncpy(db->db_database, "", sizeof(db->db_database)); + safestrncpy(db->codepage, "", sizeof(db->codepage)); + // other settings + db->case_sensitive = false; + safestrncpy(db->account_db, "login", sizeof(db->account_db)); + safestrncpy(db->accreg_db, "global_reg_value", sizeof(db->accreg_db)); + + return &db->vtable; } @@ -114,567 +112,532 @@ AccountDB* account_db_sql(void) /// establishes database connection -static bool account_db_sql_init(AccountDB* self) +static bool account_db_sql_init(AccountDB *self) { - AccountDB_SQL* db = (AccountDB_SQL*)self; - Sql* sql_handle; - const char* username; - const char* password; - const char* hostname; - uint16 port; - const char* database; - const char* codepage; - - db->accounts = Sql_Malloc(); - sql_handle = db->accounts; - - if( db->db_hostname[0] != '\0' ) - {// local settings - username = db->db_username; - password = db->db_password; - hostname = db->db_hostname; - port = db->db_port; - database = db->db_database; - codepage = db->codepage; - } - else - {// global settings - username = db->global_db_username; - password = db->global_db_password; - hostname = db->global_db_hostname; - port = db->global_db_port; - database = db->global_db_database; - codepage = db->global_codepage; - } - - if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) ) - { - Sql_ShowDebug(sql_handle); - Sql_Free(db->accounts); - db->accounts = NULL; - return false; - } - - if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) ) - Sql_ShowDebug(sql_handle); - - return true; + AccountDB_SQL *db = (AccountDB_SQL *)self; + Sql *sql_handle; + const char *username; + const char *password; + const char *hostname; + uint16 port; + const char *database; + const char *codepage; + + db->accounts = Sql_Malloc(); + sql_handle = db->accounts; + + if (db->db_hostname[0] != '\0') { + // local settings + username = db->db_username; + password = db->db_password; + hostname = db->db_hostname; + port = db->db_port; + database = db->db_database; + codepage = db->codepage; + } else { + // global settings + username = db->global_db_username; + password = db->global_db_password; + hostname = db->global_db_hostname; + port = db->global_db_port; + database = db->global_db_database; + codepage = db->global_codepage; + } + + if (SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database)) { + Sql_ShowDebug(sql_handle); + Sql_Free(db->accounts); + db->accounts = NULL; + return false; + } + + if (codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage)) + Sql_ShowDebug(sql_handle); + + return true; } /// disconnects from database -static void account_db_sql_destroy(AccountDB* self) +static void account_db_sql_destroy(AccountDB *self) { - AccountDB_SQL* db = (AccountDB_SQL*)self; + AccountDB_SQL *db = (AccountDB_SQL *)self; - Sql_Free(db->accounts); - db->accounts = NULL; - aFree(db); + Sql_Free(db->accounts); + db->accounts = NULL; + aFree(db); } /// Gets a property from this database. -static bool account_db_sql_get_property(AccountDB* self, const char* key, char* buf, size_t buflen) +static bool account_db_sql_get_property(AccountDB *self, const char *key, char *buf, size_t buflen) { - AccountDB_SQL* db = (AccountDB_SQL*)self; - const char* signature; - - signature = "engine."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "name") == 0 ) - safesnprintf(buf, buflen, "sql"); - else - if( strcmpi(key, "version") == 0 ) - safesnprintf(buf, buflen, "%d", ACCOUNT_SQL_DB_VERSION); - else - if( strcmpi(key, "comment") == 0 ) - safesnprintf(buf, buflen, "SQL Account Database"); - else - return false;// not found - return true; - } - - signature = "sql."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safesnprintf(buf, buflen, "%s", db->global_db_hostname); - else - if( strcmpi(key, "db_port") == 0 ) - safesnprintf(buf, buflen, "%d", db->global_db_port); - else - if( strcmpi(key, "db_username") == 0 ) - safesnprintf(buf, buflen, "%s", db->global_db_username); - else - if( strcmpi(key, "db_password") == 0 ) - safesnprintf(buf, buflen, "%s", db->global_db_password); - else - if( strcmpi(key, "db_database") == 0 ) - safesnprintf(buf, buflen, "%s", db->global_db_database); - else - if( strcmpi(key, "codepage") == 0 ) - safesnprintf(buf, buflen, "%s", db->global_codepage); - else - return false;// not found - return true; - } - - signature = "account.sql."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safesnprintf(buf, buflen, "%s", db->db_hostname); - else - if( strcmpi(key, "db_port") == 0 ) - safesnprintf(buf, buflen, "%d", db->db_port); - else - if( strcmpi(key, "db_username") == 0 ) - safesnprintf(buf, buflen, "%s", db->db_username); - else - if( strcmpi(key, "db_password") == 0 ) - safesnprintf(buf, buflen, "%s", db->db_password); - else - if( strcmpi(key, "db_database") == 0 ) - safesnprintf(buf, buflen, "%s", db->db_database); - else - if( strcmpi(key, "codepage") == 0 ) - safesnprintf(buf, buflen, "%s", db->codepage); - else - if( strcmpi(key, "case_sensitive") == 0 ) - safesnprintf(buf, buflen, "%d", (db->case_sensitive ? 1 : 0)); - else - if( strcmpi(key, "account_db") == 0 ) - safesnprintf(buf, buflen, "%s", db->account_db); - else - if( strcmpi(key, "accreg_db") == 0 ) - safesnprintf(buf, buflen, "%s", db->accreg_db); - else - return false;// not found - return true; - } - - return false;// not found + AccountDB_SQL *db = (AccountDB_SQL *)self; + const char *signature; + + signature = "engine."; + if (strncmpi(key, signature, strlen(signature)) == 0) { + key += strlen(signature); + if (strcmpi(key, "name") == 0) + safesnprintf(buf, buflen, "sql"); + else if (strcmpi(key, "version") == 0) + safesnprintf(buf, buflen, "%d", ACCOUNT_SQL_DB_VERSION); + else if (strcmpi(key, "comment") == 0) + safesnprintf(buf, buflen, "SQL Account Database"); + else + return false;// not found + return true; + } + + signature = "sql."; + if (strncmpi(key, signature, strlen(signature)) == 0) { + key += strlen(signature); + if (strcmpi(key, "db_hostname") == 0) + safesnprintf(buf, buflen, "%s", db->global_db_hostname); + else if (strcmpi(key, "db_port") == 0) + safesnprintf(buf, buflen, "%d", db->global_db_port); + else if (strcmpi(key, "db_username") == 0) + safesnprintf(buf, buflen, "%s", db->global_db_username); + else if (strcmpi(key, "db_password") == 0) + safesnprintf(buf, buflen, "%s", db->global_db_password); + else if (strcmpi(key, "db_database") == 0) + safesnprintf(buf, buflen, "%s", db->global_db_database); + else if (strcmpi(key, "codepage") == 0) + safesnprintf(buf, buflen, "%s", db->global_codepage); + else + return false;// not found + return true; + } + + signature = "account.sql."; + if (strncmpi(key, signature, strlen(signature)) == 0) { + key += strlen(signature); + if (strcmpi(key, "db_hostname") == 0) + safesnprintf(buf, buflen, "%s", db->db_hostname); + else if (strcmpi(key, "db_port") == 0) + safesnprintf(buf, buflen, "%d", db->db_port); + else if (strcmpi(key, "db_username") == 0) + safesnprintf(buf, buflen, "%s", db->db_username); + else if (strcmpi(key, "db_password") == 0) + safesnprintf(buf, buflen, "%s", db->db_password); + else if (strcmpi(key, "db_database") == 0) + safesnprintf(buf, buflen, "%s", db->db_database); + else if (strcmpi(key, "codepage") == 0) + safesnprintf(buf, buflen, "%s", db->codepage); + else if (strcmpi(key, "case_sensitive") == 0) + safesnprintf(buf, buflen, "%d", (db->case_sensitive ? 1 : 0)); + else if (strcmpi(key, "account_db") == 0) + safesnprintf(buf, buflen, "%s", db->account_db); + else if (strcmpi(key, "accreg_db") == 0) + safesnprintf(buf, buflen, "%s", db->accreg_db); + else + return false;// not found + return true; + } + + return false;// not found } /// if the option is supported, adjusts the internal state -static bool account_db_sql_set_property(AccountDB* self, const char* key, const char* value) +static bool account_db_sql_set_property(AccountDB *self, const char *key, const char *value) { - AccountDB_SQL* db = (AccountDB_SQL*)self; - const char* signature; - - - signature = "sql."; - if( strncmp(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safestrncpy(db->global_db_hostname, value, sizeof(db->global_db_hostname)); - else - if( strcmpi(key, "db_port") == 0 ) - db->global_db_port = (uint16)strtoul(value, NULL, 10); - else - if( strcmpi(key, "db_username") == 0 ) - safestrncpy(db->global_db_username, value, sizeof(db->global_db_username)); - else - if( strcmpi(key, "db_password") == 0 ) - safestrncpy(db->global_db_password, value, sizeof(db->global_db_password)); - else - if( strcmpi(key, "db_database") == 0 ) - safestrncpy(db->global_db_database, value, sizeof(db->global_db_database)); - else - if( strcmpi(key, "codepage") == 0 ) - safestrncpy(db->global_codepage, value, sizeof(db->global_codepage)); - else - return false;// not found - return true; - } - - signature = "account.sql."; - if( strncmp(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safestrncpy(db->db_hostname, value, sizeof(db->db_hostname)); - else - if( strcmpi(key, "db_port") == 0 ) - db->db_port = (uint16)strtoul(value, NULL, 10); - else - if( strcmpi(key, "db_username") == 0 ) - safestrncpy(db->db_username, value, sizeof(db->db_username)); - else - if( strcmpi(key, "db_password") == 0 ) - safestrncpy(db->db_password, value, sizeof(db->db_password)); - else - if( strcmpi(key, "db_database") == 0 ) - safestrncpy(db->db_database, value, sizeof(db->db_database)); - else - if( strcmpi(key, "codepage") == 0 ) - safestrncpy(db->codepage, value, sizeof(db->codepage)); - else - if( strcmpi(key, "case_sensitive") == 0 ) - db->case_sensitive = config_switch(value); - else - if( strcmpi(key, "account_db") == 0 ) - safestrncpy(db->account_db, value, sizeof(db->account_db)); - else - if( strcmpi(key, "accreg_db") == 0 ) - safestrncpy(db->accreg_db, value, sizeof(db->accreg_db)); - else - return false;// not found - return true; - } - - return false;// not found + AccountDB_SQL *db = (AccountDB_SQL *)self; + const char *signature; + + + signature = "sql."; + if (strncmp(key, signature, strlen(signature)) == 0) { + key += strlen(signature); + if (strcmpi(key, "db_hostname") == 0) + safestrncpy(db->global_db_hostname, value, sizeof(db->global_db_hostname)); + else if (strcmpi(key, "db_port") == 0) + db->global_db_port = (uint16)strtoul(value, NULL, 10); + else if (strcmpi(key, "db_username") == 0) + safestrncpy(db->global_db_username, value, sizeof(db->global_db_username)); + else if (strcmpi(key, "db_password") == 0) + safestrncpy(db->global_db_password, value, sizeof(db->global_db_password)); + else if (strcmpi(key, "db_database") == 0) + safestrncpy(db->global_db_database, value, sizeof(db->global_db_database)); + else if (strcmpi(key, "codepage") == 0) + safestrncpy(db->global_codepage, value, sizeof(db->global_codepage)); + else + return false;// not found + return true; + } + + signature = "account.sql."; + if (strncmp(key, signature, strlen(signature)) == 0) { + key += strlen(signature); + if (strcmpi(key, "db_hostname") == 0) + safestrncpy(db->db_hostname, value, sizeof(db->db_hostname)); + else if (strcmpi(key, "db_port") == 0) + db->db_port = (uint16)strtoul(value, NULL, 10); + else if (strcmpi(key, "db_username") == 0) + safestrncpy(db->db_username, value, sizeof(db->db_username)); + else if (strcmpi(key, "db_password") == 0) + safestrncpy(db->db_password, value, sizeof(db->db_password)); + else if (strcmpi(key, "db_database") == 0) + safestrncpy(db->db_database, value, sizeof(db->db_database)); + else if (strcmpi(key, "codepage") == 0) + safestrncpy(db->codepage, value, sizeof(db->codepage)); + else if (strcmpi(key, "case_sensitive") == 0) + db->case_sensitive = config_switch(value); + else if (strcmpi(key, "account_db") == 0) + safestrncpy(db->account_db, value, sizeof(db->account_db)); + else if (strcmpi(key, "accreg_db") == 0) + safestrncpy(db->accreg_db, value, sizeof(db->accreg_db)); + else + return false;// not found + return true; + } + + return false;// not found } /// create a new account entry /// If acc->account_id is -1, the account id will be auto-generated, /// and its value will be written to acc->account_id if everything succeeds. -static bool account_db_sql_create(AccountDB* self, struct mmo_account* acc) +static bool account_db_sql_create(AccountDB *self, struct mmo_account *acc) { - AccountDB_SQL* db = (AccountDB_SQL*)self; - Sql* sql_handle = db->accounts; - - // decide on the account id to assign - int account_id; - if( acc->account_id != -1 ) - {// caller specifies it manually - account_id = acc->account_id; - } - else - {// ask the database - char* data; - size_t len; - - if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT MAX(`account_id`)+1 FROM `%s`", db->account_db) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_ShowDebug(sql_handle); - Sql_FreeResult(sql_handle); - return false; - } - - Sql_GetData(sql_handle, 0, &data, &len); - account_id = ( data != NULL ) ? atoi(data) : 0; - Sql_FreeResult(sql_handle); - - if( account_id < START_ACCOUNT_NUM ) - account_id = START_ACCOUNT_NUM; - - } - - // zero value is prohibited - if( account_id == 0 ) - return false; - - // absolute maximum - if( account_id > END_ACCOUNT_NUM ) - return false; - - // insert the data into the database - acc->account_id = account_id; - return mmo_auth_tosql(db, acc, true); + AccountDB_SQL *db = (AccountDB_SQL *)self; + Sql *sql_handle = db->accounts; + + // decide on the account id to assign + int account_id; + if (acc->account_id != -1) { + // caller specifies it manually + account_id = acc->account_id; + } else { + // ask the database + char *data; + size_t len; + + if (SQL_SUCCESS != Sql_Query(sql_handle, "SELECT MAX(`account_id`)+1 FROM `%s`", db->account_db)) { + Sql_ShowDebug(sql_handle); + return false; + } + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { + Sql_ShowDebug(sql_handle); + Sql_FreeResult(sql_handle); + return false; + } + + Sql_GetData(sql_handle, 0, &data, &len); + account_id = (data != NULL) ? atoi(data) : 0; + Sql_FreeResult(sql_handle); + + if (account_id < START_ACCOUNT_NUM) + account_id = START_ACCOUNT_NUM; + + } + + // zero value is prohibited + if (account_id == 0) + return false; + + // absolute maximum + if (account_id > END_ACCOUNT_NUM) + return false; + + // insert the data into the database + acc->account_id = account_id; + return mmo_auth_tosql(db, acc, true); } /// delete an existing account entry + its regs -static bool account_db_sql_remove(AccountDB* self, const int account_id) +static bool account_db_sql_remove(AccountDB *self, const int account_id) { - AccountDB_SQL* db = (AccountDB_SQL*)self; - Sql* sql_handle = db->accounts; - bool result = false; + AccountDB_SQL *db = (AccountDB_SQL *)self; + Sql *sql_handle = db->accounts; + bool result = false; - if( SQL_SUCCESS != Sql_QueryStr(sql_handle, "START TRANSACTION") - || SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->account_db, account_id) - || SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->accreg_db, account_id) ) - Sql_ShowDebug(sql_handle); - else - result = true; + if (SQL_SUCCESS != Sql_QueryStr(sql_handle, "START TRANSACTION") + || SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->account_db, account_id) + || SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = %d", db->accreg_db, account_id)) + Sql_ShowDebug(sql_handle); + else + result = true; - result &= ( SQL_SUCCESS == Sql_QueryStr(sql_handle, (result == true) ? "COMMIT" : "ROLLBACK") ); + result &= (SQL_SUCCESS == Sql_QueryStr(sql_handle, (result == true) ? "COMMIT" : "ROLLBACK")); - return result; + return result; } /// update an existing account with the provided new data (both account and regs) -static bool account_db_sql_save(AccountDB* self, const struct mmo_account* acc) +static bool account_db_sql_save(AccountDB *self, const struct mmo_account *acc) { - AccountDB_SQL* db = (AccountDB_SQL*)self; - return mmo_auth_tosql(db, acc, false); + AccountDB_SQL *db = (AccountDB_SQL *)self; + return mmo_auth_tosql(db, acc, false); } /// retrieve data from db and store it in the provided data structure -static bool account_db_sql_load_num(AccountDB* self, struct mmo_account* acc, const int account_id) +static bool account_db_sql_load_num(AccountDB *self, struct mmo_account *acc, const int account_id) { - AccountDB_SQL* db = (AccountDB_SQL*)self; - return mmo_auth_fromsql(db, acc, account_id); + AccountDB_SQL *db = (AccountDB_SQL *)self; + return mmo_auth_fromsql(db, acc, account_id); } /// retrieve data from db and store it in the provided data structure -static bool account_db_sql_load_str(AccountDB* self, struct mmo_account* acc, const char* userid) +static bool account_db_sql_load_str(AccountDB *self, struct mmo_account *acc, const char *userid) { - AccountDB_SQL* db = (AccountDB_SQL*)self; - Sql* sql_handle = db->accounts; - char esc_userid[2*NAME_LENGTH+1]; - int account_id; - char* data; - - Sql_EscapeString(sql_handle, esc_userid, userid); - - // get the list of account IDs for this user ID - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `userid`= %s '%s'", - db->account_db, (db->case_sensitive ? "BINARY" : ""), esc_userid) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - if( Sql_NumRows(sql_handle) > 1 ) - {// serious problem - duplicit account - ShowError("account_db_sql_load_str: multiple accounts found when retrieving data for account '%s'!\n", userid); - Sql_FreeResult(sql_handle); - return false; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - {// no such entry - Sql_FreeResult(sql_handle); - return false; - } - - Sql_GetData(sql_handle, 0, &data, NULL); - account_id = atoi(data); - - return account_db_sql_load_num(self, acc, account_id); + AccountDB_SQL *db = (AccountDB_SQL *)self; + Sql *sql_handle = db->accounts; + char esc_userid[2*NAME_LENGTH+1]; + int account_id; + char *data; + + Sql_EscapeString(sql_handle, esc_userid, userid); + + // get the list of account IDs for this user ID + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `userid`= %s '%s'", + db->account_db, (db->case_sensitive ? "BINARY" : ""), esc_userid)) { + Sql_ShowDebug(sql_handle); + return false; + } + + if (Sql_NumRows(sql_handle) > 1) { + // serious problem - duplicit account + ShowError("account_db_sql_load_str: multiple accounts found when retrieving data for account '%s'!\n", userid); + Sql_FreeResult(sql_handle); + return false; + } + + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { + // no such entry + Sql_FreeResult(sql_handle); + return false; + } + + Sql_GetData(sql_handle, 0, &data, NULL); + account_id = atoi(data); + + return account_db_sql_load_num(self, acc, account_id); } /// Returns a new forward iterator. -static AccountDBIterator* account_db_sql_iterator(AccountDB* self) +static AccountDBIterator *account_db_sql_iterator(AccountDB *self) { - AccountDB_SQL* db = (AccountDB_SQL*)self; - AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)aCalloc(1, sizeof(AccountDBIterator_SQL)); + AccountDB_SQL *db = (AccountDB_SQL *)self; + AccountDBIterator_SQL *iter = (AccountDBIterator_SQL *)aCalloc(1, sizeof(AccountDBIterator_SQL)); - // set up the vtable - iter->vtable.destroy = &account_db_sql_iter_destroy; - iter->vtable.next = &account_db_sql_iter_next; + // set up the vtable + iter->vtable.destroy = &account_db_sql_iter_destroy; + iter->vtable.next = &account_db_sql_iter_next; - // fill data - iter->db = db; - iter->last_account_id = -1; + // fill data + iter->db = db; + iter->last_account_id = -1; - return &iter->vtable; + return &iter->vtable; } /// Destroys this iterator, releasing all allocated memory (including itself). -static void account_db_sql_iter_destroy(AccountDBIterator* self) +static void account_db_sql_iter_destroy(AccountDBIterator *self) { - AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)self; - aFree(iter); + AccountDBIterator_SQL *iter = (AccountDBIterator_SQL *)self; + aFree(iter); } /// Fetches the next account in the database. -static bool account_db_sql_iter_next(AccountDBIterator* self, struct mmo_account* acc) +static bool account_db_sql_iter_next(AccountDBIterator *self, struct mmo_account *acc) { - AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)self; - AccountDB_SQL* db = (AccountDB_SQL*)iter->db; - Sql* sql_handle = db->accounts; - int account_id; - char* data; - - // get next account ID - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `account_id` > '%d' ORDER BY `account_id` ASC LIMIT 1", - db->account_db, iter->last_account_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - if( SQL_SUCCESS == Sql_NextRow(sql_handle) && - SQL_SUCCESS == Sql_GetData(sql_handle, 0, &data, NULL) && - data != NULL ) - {// get account data - account_id = atoi(data); - if( mmo_auth_fromsql(db, acc, account_id) ) - { - iter->last_account_id = account_id; - Sql_FreeResult(sql_handle); - return true; - } - } - Sql_FreeResult(sql_handle); - return false; + AccountDBIterator_SQL *iter = (AccountDBIterator_SQL *)self; + AccountDB_SQL *db = (AccountDB_SQL *)iter->db; + Sql *sql_handle = db->accounts; + int account_id; + char *data; + + // get next account ID + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `account_id` > '%d' ORDER BY `account_id` ASC LIMIT 1", + db->account_db, iter->last_account_id)) { + Sql_ShowDebug(sql_handle); + return false; + } + + if (SQL_SUCCESS == Sql_NextRow(sql_handle) && + SQL_SUCCESS == Sql_GetData(sql_handle, 0, &data, NULL) && + data != NULL) { + // get account data + account_id = atoi(data); + if (mmo_auth_fromsql(db, acc, account_id)) { + iter->last_account_id = account_id; + Sql_FreeResult(sql_handle); + return true; + } + } + Sql_FreeResult(sql_handle); + return false; } -static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int account_id) +static bool mmo_auth_fromsql(AccountDB_SQL *db, struct mmo_account *acc, int account_id) { - Sql* sql_handle = db->accounts; - char* data; - int i = 0; - - // retrieve login entry for the specified account - if( SQL_ERROR == Sql_Query(sql_handle, - "SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`group_id`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate` FROM `%s` WHERE `account_id` = %d", - db->account_db, account_id ) - ) { - Sql_ShowDebug(sql_handle); - return false; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - {// no such entry - Sql_FreeResult(sql_handle); - return false; - } - - Sql_GetData(sql_handle, 0, &data, NULL); acc->account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(acc->userid, data, sizeof(acc->userid)); - Sql_GetData(sql_handle, 2, &data, NULL); safestrncpy(acc->pass, data, sizeof(acc->pass)); - Sql_GetData(sql_handle, 3, &data, NULL); acc->sex = data[0]; - Sql_GetData(sql_handle, 4, &data, NULL); safestrncpy(acc->email, data, sizeof(acc->email)); - Sql_GetData(sql_handle, 5, &data, NULL); acc->group_id = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); acc->state = strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 7, &data, NULL); acc->unban_time = atol(data); - Sql_GetData(sql_handle, 8, &data, NULL); acc->expiration_time = atol(data); - Sql_GetData(sql_handle, 9, &data, NULL); acc->logincount = strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 10, &data, NULL); safestrncpy(acc->lastlogin, data, sizeof(acc->lastlogin)); - Sql_GetData(sql_handle, 11, &data, NULL); safestrncpy(acc->last_ip, data, sizeof(acc->last_ip)); - Sql_GetData(sql_handle, 12, &data, NULL); safestrncpy(acc->birthdate, data, sizeof(acc->birthdate)); - - Sql_FreeResult(sql_handle); - - - // retrieve account regs for the specified user - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`,`value` FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - acc->account_reg2_num = (int)Sql_NumRows(sql_handle); - - while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - Sql_GetData(sql_handle, 0, &data, NULL); safestrncpy(acc->account_reg2[i].str, data, sizeof(acc->account_reg2[i].str)); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(acc->account_reg2[i].value, data, sizeof(acc->account_reg2[i].value)); - ++i; - } - Sql_FreeResult(sql_handle); - - if( i != acc->account_reg2_num ) - return false; - - return true; + Sql *sql_handle = db->accounts; + char *data; + int i = 0; + + // retrieve login entry for the specified account + if (SQL_ERROR == Sql_Query(sql_handle, + "SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`group_id`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate` FROM `%s` WHERE `account_id` = %d", + db->account_db, account_id) + ) { + Sql_ShowDebug(sql_handle); + return false; + } + + if (SQL_SUCCESS != Sql_NextRow(sql_handle)) { + // no such entry + Sql_FreeResult(sql_handle); + return false; + } + + Sql_GetData(sql_handle, 0, &data, NULL); + acc->account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); + safestrncpy(acc->userid, data, sizeof(acc->userid)); + Sql_GetData(sql_handle, 2, &data, NULL); + safestrncpy(acc->pass, data, sizeof(acc->pass)); + Sql_GetData(sql_handle, 3, &data, NULL); + acc->sex = data[0]; + Sql_GetData(sql_handle, 4, &data, NULL); + safestrncpy(acc->email, data, sizeof(acc->email)); + Sql_GetData(sql_handle, 5, &data, NULL); + acc->group_id = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); + acc->state = strtoul(data, NULL, 10); + Sql_GetData(sql_handle, 7, &data, NULL); + acc->unban_time = atol(data); + Sql_GetData(sql_handle, 8, &data, NULL); + acc->expiration_time = atol(data); + Sql_GetData(sql_handle, 9, &data, NULL); + acc->logincount = strtoul(data, NULL, 10); + Sql_GetData(sql_handle, 10, &data, NULL); + safestrncpy(acc->lastlogin, data, sizeof(acc->lastlogin)); + Sql_GetData(sql_handle, 11, &data, NULL); + safestrncpy(acc->last_ip, data, sizeof(acc->last_ip)); + Sql_GetData(sql_handle, 12, &data, NULL); + safestrncpy(acc->birthdate, data, sizeof(acc->birthdate)); + + Sql_FreeResult(sql_handle); + + + // retrieve account regs for the specified user + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`,`value` FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id)) { + Sql_ShowDebug(sql_handle); + return false; + } + + acc->account_reg2_num = (int)Sql_NumRows(sql_handle); + + while (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + char *data; + Sql_GetData(sql_handle, 0, &data, NULL); + safestrncpy(acc->account_reg2[i].str, data, sizeof(acc->account_reg2[i].str)); + Sql_GetData(sql_handle, 1, &data, NULL); + safestrncpy(acc->account_reg2[i].value, data, sizeof(acc->account_reg2[i].value)); + ++i; + } + Sql_FreeResult(sql_handle); + + if (i != acc->account_reg2_num) + return false; + + return true; } -static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, bool is_new) +static bool mmo_auth_tosql(AccountDB_SQL *db, const struct mmo_account *acc, bool is_new) { - Sql* sql_handle = db->accounts; - SqlStmt* stmt = SqlStmt_Malloc(sql_handle); - bool result = false; - int i; - - // try - do - { - - if( SQL_SUCCESS != Sql_QueryStr(sql_handle, "START TRANSACTION") ) - { - Sql_ShowDebug(sql_handle); - break; - } - - if( is_new ) - {// insert into account table - if( SQL_SUCCESS != SqlStmt_Prepare(stmt, - "INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - db->account_db) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, (void*)&acc->account_id, sizeof(acc->account_id)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->userid, strlen(acc->userid)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, (void*)acc->pass, strlen(acc->pass)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_ENUM, (void*)&acc->sex, sizeof(acc->sex)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_STRING, (void*)&acc->email, strlen(acc->email)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_INT, (void*)&acc->group_id, sizeof(acc->group_id)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_UINT, (void*)&acc->state, sizeof(acc->state)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void*)&acc->unban_time, sizeof(acc->unban_time)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_INT, (void*)&acc->expiration_time, sizeof(acc->expiration_time)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 9, SQLDT_UINT, (void*)&acc->logincount, sizeof(acc->logincount)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void*)&acc->lastlogin, strlen(acc->lastlogin)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void*)&acc->last_ip, strlen(acc->last_ip)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 12, SQLDT_STRING, (void*)&acc->birthdate, strlen(acc->birthdate)) - || SQL_SUCCESS != SqlStmt_Execute(stmt) - ) { - SqlStmt_ShowDebug(stmt); - break; - } - } - else - {// update account table - if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=? WHERE `account_id` = '%d'", db->account_db, acc->account_id) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void*)acc->userid, strlen(acc->userid)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->pass, strlen(acc->pass)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_ENUM, (void*)&acc->sex, sizeof(acc->sex)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, (void*)acc->email, strlen(acc->email)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_INT, (void*)&acc->group_id, sizeof(acc->group_id)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_UINT, (void*)&acc->state, sizeof(acc->state)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_LONG, (void*)&acc->unban_time, sizeof(acc->unban_time)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void*)&acc->expiration_time, sizeof(acc->expiration_time)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_UINT, (void*)&acc->logincount, sizeof(acc->logincount)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 9, SQLDT_STRING, (void*)&acc->lastlogin, strlen(acc->lastlogin)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void*)&acc->last_ip, strlen(acc->last_ip)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void*)&acc->birthdate, strlen(acc->birthdate)) - || SQL_SUCCESS != SqlStmt_Execute(stmt) - ) { - SqlStmt_ShowDebug(stmt); - break; - } - } - - // remove old account regs - if( SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id) ) - { - Sql_ShowDebug(sql_handle); - break; - } - // insert new account regs - if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "INSERT INTO `%s` (`type`, `account_id`, `str`, `value`) VALUES ( 1 , '%d' , ? , ? );", db->accreg_db, acc->account_id) ) - { - SqlStmt_ShowDebug(stmt); - break; - } - for( i = 0; i < acc->account_reg2_num; ++i ) - { - if( SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void*)acc->account_reg2[i].str, strlen(acc->account_reg2[i].str)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->account_reg2[i].value, strlen(acc->account_reg2[i].value)) - || SQL_SUCCESS != SqlStmt_Execute(stmt) - ) { - SqlStmt_ShowDebug(stmt); - break; - } - } - if( i < acc->account_reg2_num ) - { - result = false; - break; - } - - // if we got this far, everything was successful - result = true; - - } while(0); - // finally - - result &= ( SQL_SUCCESS == Sql_QueryStr(sql_handle, (result == true) ? "COMMIT" : "ROLLBACK") ); - SqlStmt_Free(stmt); - - return result; + Sql *sql_handle = db->accounts; + SqlStmt *stmt = SqlStmt_Malloc(sql_handle); + bool result = false; + int i; + + // try + do { + + if (SQL_SUCCESS != Sql_QueryStr(sql_handle, "START TRANSACTION")) { + Sql_ShowDebug(sql_handle); + break; + } + + if (is_new) { + // insert into account table + if (SQL_SUCCESS != SqlStmt_Prepare(stmt, + "INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + db->account_db) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, (void *)&acc->account_id, sizeof(acc->account_id)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void *)acc->userid, strlen(acc->userid)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, (void *)acc->pass, strlen(acc->pass)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_ENUM, (void *)&acc->sex, sizeof(acc->sex)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_STRING, (void *)&acc->email, strlen(acc->email)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_INT, (void *)&acc->group_id, sizeof(acc->group_id)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_UINT, (void *)&acc->state, sizeof(acc->state)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void *)&acc->unban_time, sizeof(acc->unban_time)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_INT, (void *)&acc->expiration_time, sizeof(acc->expiration_time)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 9, SQLDT_UINT, (void *)&acc->logincount, sizeof(acc->logincount)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void *)&acc->lastlogin, strlen(acc->lastlogin)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void *)&acc->last_ip, strlen(acc->last_ip)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 12, SQLDT_STRING, (void *)&acc->birthdate, strlen(acc->birthdate)) + || SQL_SUCCESS != SqlStmt_Execute(stmt) + ) { + SqlStmt_ShowDebug(stmt); + break; + } + } else { + // update account table + if (SQL_SUCCESS != SqlStmt_Prepare(stmt, "UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=? WHERE `account_id` = '%d'", db->account_db, acc->account_id) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void *)acc->userid, strlen(acc->userid)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void *)acc->pass, strlen(acc->pass)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_ENUM, (void *)&acc->sex, sizeof(acc->sex)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, (void *)acc->email, strlen(acc->email)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_INT, (void *)&acc->group_id, sizeof(acc->group_id)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_UINT, (void *)&acc->state, sizeof(acc->state)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_LONG, (void *)&acc->unban_time, sizeof(acc->unban_time)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void *)&acc->expiration_time, sizeof(acc->expiration_time)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_UINT, (void *)&acc->logincount, sizeof(acc->logincount)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 9, SQLDT_STRING, (void *)&acc->lastlogin, strlen(acc->lastlogin)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void *)&acc->last_ip, strlen(acc->last_ip)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void *)&acc->birthdate, strlen(acc->birthdate)) + || SQL_SUCCESS != SqlStmt_Execute(stmt) + ) { + SqlStmt_ShowDebug(stmt); + break; + } + } + + // remove old account regs + if (SQL_SUCCESS != Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`='1' AND `account_id`='%d'", db->accreg_db, acc->account_id)) { + Sql_ShowDebug(sql_handle); + break; + } + // insert new account regs + if (SQL_SUCCESS != SqlStmt_Prepare(stmt, "INSERT INTO `%s` (`type`, `account_id`, `str`, `value`) VALUES ( 1 , '%d' , ? , ? );", db->accreg_db, acc->account_id)) { + SqlStmt_ShowDebug(stmt); + break; + } + for (i = 0; i < acc->account_reg2_num; ++i) { + if (SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void *)acc->account_reg2[i].str, strlen(acc->account_reg2[i].str)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void *)acc->account_reg2[i].value, strlen(acc->account_reg2[i].value)) + || SQL_SUCCESS != SqlStmt_Execute(stmt) + ) { + SqlStmt_ShowDebug(stmt); + break; + } + } + if (i < acc->account_reg2_num) { + result = false; + break; + } + + // if we got this far, everything was successful + result = true; + + } while (0); + // finally + + result &= (SQL_SUCCESS == Sql_QueryStr(sql_handle, (result == true) ? "COMMIT" : "ROLLBACK")); + SqlStmt_Free(stmt); + + return result; } diff --git a/src/login/ipban.h b/src/login/ipban.h index b2a1a7d9e..6adc40483 100644 --- a/src/login/ipban.h +++ b/src/login/ipban.h @@ -19,7 +19,7 @@ bool ipban_check(uint32 ip); void ipban_log(uint32 ip); // parses configuration option -bool ipban_config_read(const char* key, const char* value); +bool ipban_config_read(const char *key, const char *value); #endif // __IPBAN_H_INCLUDED__ diff --git a/src/login/ipban_sql.c b/src/login/ipban_sql.c index c75a1f956..eec9a98be 100644 --- a/src/login/ipban_sql.c +++ b/src/login/ipban_sql.c @@ -31,7 +31,7 @@ static char ipban_codepage[32] = ""; static char ipban_table[32] = "ipbanlist"; // globals -static Sql* sql_handle = NULL; +static Sql *sql_handle = NULL; static int cleanup_timer_id = INVALID_TIMER; static bool ipban_inited = false; @@ -41,218 +41,196 @@ int ipban_cleanup(int tid, unsigned int tick, int id, intptr_t data); // initialize void ipban_init(void) { - const char* username; - const char* password; - const char* hostname; - uint16 port; - const char* database; - const char* codepage; - - ipban_inited = true; - - if( !login_config.ipban ) - return;// ipban disabled - - if( ipban_db_hostname[0] != '\0' ) - {// local settings - username = ipban_db_username; - password = ipban_db_password; - hostname = ipban_db_hostname; - port = ipban_db_port; - database = ipban_db_database; - codepage = ipban_codepage; - } - else - {// global settings - username = global_db_username; - password = global_db_password; - hostname = global_db_hostname; - port = global_db_port; - database = global_db_database; - codepage = global_codepage; - } - - // establish connections - sql_handle = Sql_Malloc(); - if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) ) - { - Sql_ShowDebug(sql_handle); - Sql_Free(sql_handle); - exit(EXIT_FAILURE); - } - if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) ) - Sql_ShowDebug(sql_handle); - - if( login_config.ipban_cleanup_interval > 0 ) - { // set up periodic cleanup of connection history and active bans - add_timer_func_list(ipban_cleanup, "ipban_cleanup"); - cleanup_timer_id = add_timer_interval(gettick()+10, ipban_cleanup, 0, 0, login_config.ipban_cleanup_interval*1000); - } else // make sure it gets cleaned up on login-server start regardless of interval-based cleanups - ipban_cleanup(0,0,0,0); + const char *username; + const char *password; + const char *hostname; + uint16 port; + const char *database; + const char *codepage; + + ipban_inited = true; + + if (!login_config.ipban) + return;// ipban disabled + + if (ipban_db_hostname[0] != '\0') { + // local settings + username = ipban_db_username; + password = ipban_db_password; + hostname = ipban_db_hostname; + port = ipban_db_port; + database = ipban_db_database; + codepage = ipban_codepage; + } else { + // global settings + username = global_db_username; + password = global_db_password; + hostname = global_db_hostname; + port = global_db_port; + database = global_db_database; + codepage = global_codepage; + } + + // establish connections + sql_handle = Sql_Malloc(); + if (SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database)) { + Sql_ShowDebug(sql_handle); + Sql_Free(sql_handle); + exit(EXIT_FAILURE); + } + if (codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage)) + Sql_ShowDebug(sql_handle); + + if (login_config.ipban_cleanup_interval > 0) { + // set up periodic cleanup of connection history and active bans + add_timer_func_list(ipban_cleanup, "ipban_cleanup"); + cleanup_timer_id = add_timer_interval(gettick()+10, ipban_cleanup, 0, 0, login_config.ipban_cleanup_interval*1000); + } else // make sure it gets cleaned up on login-server start regardless of interval-based cleanups + ipban_cleanup(0,0,0,0); } // finalize void ipban_final(void) { - if( !login_config.ipban ) - return;// ipban disabled - - if( login_config.ipban_cleanup_interval > 0 ) - // release data - delete_timer(cleanup_timer_id, ipban_cleanup); - - ipban_cleanup(0,0,0,0); // always clean up on login-server stop - - // close connections - Sql_Free(sql_handle); - sql_handle = NULL; + if (!login_config.ipban) + return;// ipban disabled + + if (login_config.ipban_cleanup_interval > 0) + // release data + delete_timer(cleanup_timer_id, ipban_cleanup); + + ipban_cleanup(0,0,0,0); // always clean up on login-server stop + + // close connections + Sql_Free(sql_handle); + sql_handle = NULL; } // load configuration options -bool ipban_config_read(const char* key, const char* value) +bool ipban_config_read(const char *key, const char *value) { - const char* signature; - - if( ipban_inited ) - return false;// settings can only be changed before init - - signature = "sql."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safestrncpy(global_db_hostname, value, sizeof(global_db_hostname)); - else - if( strcmpi(key, "db_port") == 0 ) - global_db_port = (uint16)strtoul(value, NULL, 10); - else - if( strcmpi(key, "db_username") == 0 ) - safestrncpy(global_db_username, value, sizeof(global_db_username)); - else - if( strcmpi(key, "db_password") == 0 ) - safestrncpy(global_db_password, value, sizeof(global_db_password)); - else - if( strcmpi(key, "db_database") == 0 ) - safestrncpy(global_db_database, value, sizeof(global_db_database)); - else - if( strcmpi(key, "codepage") == 0 ) - safestrncpy(global_codepage, value, sizeof(global_codepage)); - else - return false;// not found - return true; - } - - signature = "ipban.sql."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safestrncpy(ipban_db_hostname, value, sizeof(ipban_db_hostname)); - else - if( strcmpi(key, "db_port") == 0 ) - ipban_db_port = (uint16)strtoul(value, NULL, 10); - else - if( strcmpi(key, "db_username") == 0 ) - safestrncpy(ipban_db_username, value, sizeof(ipban_db_username)); - else - if( strcmpi(key, "db_password") == 0 ) - safestrncpy(ipban_db_password, value, sizeof(ipban_db_password)); - else - if( strcmpi(key, "db_database") == 0 ) - safestrncpy(ipban_db_database, value, sizeof(ipban_db_database)); - else - if( strcmpi(key, "codepage") == 0 ) - safestrncpy(ipban_codepage, value, sizeof(ipban_codepage)); - else - if( strcmpi(key, "ipban_table") == 0 ) - safestrncpy(ipban_table, value, sizeof(ipban_table)); - else - return false;// not found - return true; - } - - signature = "ipban."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "enable") == 0 ) - login_config.ipban = (bool)config_switch(value); - else - if( strcmpi(key, "dynamic_pass_failure_ban") == 0 ) - login_config.dynamic_pass_failure_ban = (bool)config_switch(value); - else - if( strcmpi(key, "dynamic_pass_failure_ban_interval") == 0 ) - login_config.dynamic_pass_failure_ban_interval = atoi(value); - else - if( strcmpi(key, "dynamic_pass_failure_ban_limit") == 0 ) - login_config.dynamic_pass_failure_ban_limit = atoi(value); - else - if( strcmpi(key, "dynamic_pass_failure_ban_duration") == 0 ) - login_config.dynamic_pass_failure_ban_duration = atoi(value); - else - return false;// not found - return true; - } - - return false;// not found + const char *signature; + + if (ipban_inited) + return false;// settings can only be changed before init + + signature = "sql."; + if (strncmpi(key, signature, strlen(signature)) == 0) { + key += strlen(signature); + if (strcmpi(key, "db_hostname") == 0) + safestrncpy(global_db_hostname, value, sizeof(global_db_hostname)); + else if (strcmpi(key, "db_port") == 0) + global_db_port = (uint16)strtoul(value, NULL, 10); + else if (strcmpi(key, "db_username") == 0) + safestrncpy(global_db_username, value, sizeof(global_db_username)); + else if (strcmpi(key, "db_password") == 0) + safestrncpy(global_db_password, value, sizeof(global_db_password)); + else if (strcmpi(key, "db_database") == 0) + safestrncpy(global_db_database, value, sizeof(global_db_database)); + else if (strcmpi(key, "codepage") == 0) + safestrncpy(global_codepage, value, sizeof(global_codepage)); + else + return false;// not found + return true; + } + + signature = "ipban.sql."; + if (strncmpi(key, signature, strlen(signature)) == 0) { + key += strlen(signature); + if (strcmpi(key, "db_hostname") == 0) + safestrncpy(ipban_db_hostname, value, sizeof(ipban_db_hostname)); + else if (strcmpi(key, "db_port") == 0) + ipban_db_port = (uint16)strtoul(value, NULL, 10); + else if (strcmpi(key, "db_username") == 0) + safestrncpy(ipban_db_username, value, sizeof(ipban_db_username)); + else if (strcmpi(key, "db_password") == 0) + safestrncpy(ipban_db_password, value, sizeof(ipban_db_password)); + else if (strcmpi(key, "db_database") == 0) + safestrncpy(ipban_db_database, value, sizeof(ipban_db_database)); + else if (strcmpi(key, "codepage") == 0) + safestrncpy(ipban_codepage, value, sizeof(ipban_codepage)); + else if (strcmpi(key, "ipban_table") == 0) + safestrncpy(ipban_table, value, sizeof(ipban_table)); + else + return false;// not found + return true; + } + + signature = "ipban."; + if (strncmpi(key, signature, strlen(signature)) == 0) { + key += strlen(signature); + if (strcmpi(key, "enable") == 0) + login_config.ipban = (bool)config_switch(value); + else if (strcmpi(key, "dynamic_pass_failure_ban") == 0) + login_config.dynamic_pass_failure_ban = (bool)config_switch(value); + else if (strcmpi(key, "dynamic_pass_failure_ban_interval") == 0) + login_config.dynamic_pass_failure_ban_interval = atoi(value); + else if (strcmpi(key, "dynamic_pass_failure_ban_limit") == 0) + login_config.dynamic_pass_failure_ban_limit = atoi(value); + else if (strcmpi(key, "dynamic_pass_failure_ban_duration") == 0) + login_config.dynamic_pass_failure_ban_duration = atoi(value); + else + return false;// not found + return true; + } + + return false;// not found } // check ip against active bans list bool ipban_check(uint32 ip) { - uint8* p = (uint8*)&ip; - char* data = NULL; - int matches; + uint8 *p = (uint8 *)&ip; + char *data = NULL; + int matches; - if( !login_config.ipban ) - return false;// ipban disabled + if (!login_config.ipban) + return false;// ipban disabled - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT count(*) FROM `%s` WHERE `rtime` > NOW() AND (`list` = '%u.*.*.*' OR `list` = '%u.%u.*.*' OR `list` = '%u.%u.%u.*' OR `list` = '%u.%u.%u.%u')", - ipban_table, p[3], p[3], p[2], p[3], p[2], p[1], p[3], p[2], p[1], p[0]) ) - { - Sql_ShowDebug(sql_handle); - // close connection because we can't verify their connectivity. - return true; - } + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT count(*) FROM `%s` WHERE `rtime` > NOW() AND (`list` = '%u.*.*.*' OR `list` = '%u.%u.*.*' OR `list` = '%u.%u.%u.*' OR `list` = '%u.%u.%u.%u')", + ipban_table, p[3], p[3], p[2], p[3], p[2], p[1], p[3], p[2], p[1], p[0])) { + Sql_ShowDebug(sql_handle); + // close connection because we can't verify their connectivity. + return true; + } - if( SQL_ERROR == Sql_NextRow(sql_handle) ) - return true;// Shouldn't happen, but just in case... + if (SQL_ERROR == Sql_NextRow(sql_handle)) + return true;// Shouldn't happen, but just in case... - Sql_GetData(sql_handle, 0, &data, NULL); - matches = atoi(data); - Sql_FreeResult(sql_handle); + Sql_GetData(sql_handle, 0, &data, NULL); + matches = atoi(data); + Sql_FreeResult(sql_handle); - return( matches > 0 ); + return(matches > 0); } // log failed attempt void ipban_log(uint32 ip) { - unsigned long failures; + unsigned long failures; - if( !login_config.ipban ) - return;// ipban disabled + if (!login_config.ipban) + return;// ipban disabled - failures = loginlog_failedattempts(ip, login_config.dynamic_pass_failure_ban_interval);// how many times failed account? in one ip. + failures = loginlog_failedattempts(ip, login_config.dynamic_pass_failure_ban_interval);// how many times failed account? in one ip. - // if over the limit, add a temporary ban entry - if( failures >= login_config.dynamic_pass_failure_ban_limit ) - { - uint8* p = (uint8*)&ip; - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`list`,`btime`,`rtime`,`reason`) VALUES ('%u.%u.%u.*', NOW() , NOW() + INTERVAL %d MINUTE ,'Password error ban')", - ipban_table, p[3], p[2], p[1], login_config.dynamic_pass_failure_ban_duration) ) - Sql_ShowDebug(sql_handle); - } + // if over the limit, add a temporary ban entry + if (failures >= login_config.dynamic_pass_failure_ban_limit) { + uint8 *p = (uint8 *)&ip; + if (SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`list`,`btime`,`rtime`,`reason`) VALUES ('%u.%u.%u.*', NOW() , NOW() + INTERVAL %d MINUTE ,'Password error ban')", + ipban_table, p[3], p[2], p[1], login_config.dynamic_pass_failure_ban_duration)) + Sql_ShowDebug(sql_handle); + } } // remove expired bans int ipban_cleanup(int tid, unsigned int tick, int id, intptr_t data) { - if( !login_config.ipban ) - return 0;// ipban disabled + if (!login_config.ipban) + return 0;// ipban disabled - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `ipbanlist` WHERE `rtime` <= NOW()") ) - Sql_ShowDebug(sql_handle); + if (SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `ipbanlist` WHERE `rtime` <= NOW()")) + Sql_ShowDebug(sql_handle); - return 0; + return 0; } diff --git a/src/login/login.c b/src/login/login.c index e079dbaf2..1f63463d5 100644 --- a/src/login/login.c +++ b/src/login/login.c @@ -25,31 +25,31 @@ int login_fd; // login server socket struct mmo_char_server server[MAX_SERVERS]; // char server data // Account engines available -static struct{ - AccountDB* (*constructor)(void); - AccountDB* db; +static struct { + AccountDB *(*constructor)(void); + AccountDB *db; } account_engines[] = { - {account_db_sql, NULL}, + {account_db_sql, NULL}, #ifdef ACCOUNTDB_ENGINE_0 - {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_0), NULL}, + {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_0), NULL}, #endif #ifdef ACCOUNTDB_ENGINE_1 - {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_1), NULL}, + {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_1), NULL}, #endif #ifdef ACCOUNTDB_ENGINE_2 - {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_2), NULL}, + {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_2), NULL}, #endif #ifdef ACCOUNTDB_ENGINE_3 - {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_3), NULL}, + {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_3), NULL}, #endif #ifdef ACCOUNTDB_ENGINE_4 - {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_4), NULL}, + {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_4), NULL}, #endif - // end of structure - {NULL, NULL} + // end of structure + {NULL, NULL} }; // account database -AccountDB* accounts = NULL; +AccountDB *accounts = NULL; //Account registration flood protection [Kevin] int allowed_regs = 1; @@ -57,14 +57,14 @@ int time_allowed = 10; //in seconds // Advanced subnet check [LuzZza] struct s_subnet { - uint32 mask; - uint32 char_ip; - uint32 map_ip; + uint32 mask; + uint32 char_ip; + uint32 map_ip; } subnet[16]; int subnet_count = 0; -int mmo_auth_new(const char* userid, const char* pass, const char sex, const char* last_ip); +int mmo_auth_new(const char *userid, const char *pass, const char sex, const char *last_ip); //----------------------------------------------------- // Auth database @@ -73,16 +73,16 @@ int mmo_auth_new(const char* userid, const char* pass, const char sex, const cha struct auth_node { - int account_id; - uint32 login_id1; - uint32 login_id2; - uint32 ip; - char sex; - uint32 version; - uint8 clienttype; + int account_id; + uint32 login_id1; + uint32 login_id2; + uint32 ip; + char sex; + uint32 version; + uint8 clienttype; }; -static DBMap* auth_db; // int account_id -> struct auth_node* +static DBMap *auth_db; // int account_id -> struct auth_node* //----------------------------------------------------- @@ -90,12 +90,12 @@ static DBMap* auth_db; // int account_id -> struct auth_node* //----------------------------------------------------- struct online_login_data { - int account_id; - int waiting_disconnect; - int char_server; + int account_id; + int waiting_disconnect; + int char_server; }; -static DBMap* online_db; // int account_id -> struct online_login_data* +static DBMap *online_db; // int account_id -> struct online_login_data* static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data); /** @@ -103,49 +103,46 @@ static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t */ static DBData create_online_user(DBKey key, va_list args) { - struct online_login_data* p; - CREATE(p, struct online_login_data, 1); - p->account_id = key.i; - p->char_server = -1; - p->waiting_disconnect = INVALID_TIMER; - return db_ptr2data(p); + struct online_login_data *p; + CREATE(p, struct online_login_data, 1); + p->account_id = key.i; + p->char_server = -1; + p->waiting_disconnect = INVALID_TIMER; + return db_ptr2data(p); } -struct online_login_data* add_online_user(int char_server, int account_id) -{ - struct online_login_data* p; - p = idb_ensure(online_db, account_id, create_online_user); - p->char_server = char_server; - if( p->waiting_disconnect != INVALID_TIMER ) - { - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - p->waiting_disconnect = INVALID_TIMER; - } - return p; +struct online_login_data *add_online_user(int char_server, int account_id) { + struct online_login_data *p; + p = idb_ensure(online_db, account_id, create_online_user); + p->char_server = char_server; + if (p->waiting_disconnect != INVALID_TIMER) { + delete_timer(p->waiting_disconnect, waiting_disconnect_timer); + p->waiting_disconnect = INVALID_TIMER; + } + return p; } void remove_online_user(int account_id) { - struct online_login_data* p; - p = (struct online_login_data*)idb_get(online_db, account_id); - if( p == NULL ) - return; - if( p->waiting_disconnect != INVALID_TIMER ) - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - - idb_remove(online_db, account_id); + struct online_login_data *p; + p = (struct online_login_data *)idb_get(online_db, account_id); + if (p == NULL) + return; + if (p->waiting_disconnect != INVALID_TIMER) + delete_timer(p->waiting_disconnect, waiting_disconnect_timer); + + idb_remove(online_db, account_id); } static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data) { - struct online_login_data* p = (struct online_login_data*)idb_get(online_db, id); - if( p != NULL && p->waiting_disconnect == tid && p->account_id == id ) - { - p->waiting_disconnect = INVALID_TIMER; - remove_online_user(id); - idb_remove(auth_db, id); - } - return 0; + struct online_login_data *p = (struct online_login_data *)idb_get(online_db, id); + if (p != NULL && p->waiting_disconnect == tid && p->account_id == id) { + p->waiting_disconnect = INVALID_TIMER; + remove_online_user(id); + idb_remove(auth_db, id); + } + return 0; } /** @@ -153,20 +150,17 @@ static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t */ static int online_db_setoffline(DBKey key, DBData *data, va_list ap) { - struct online_login_data* p = db_data2ptr(data); - int server = va_arg(ap, int); - if( server == -1 ) - { - p->char_server = -1; - if( p->waiting_disconnect != INVALID_TIMER ) - { - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - p->waiting_disconnect = INVALID_TIMER; - } - } - else if( p->char_server == server ) - p->char_server = -2; //Char server disconnected. - return 0; + struct online_login_data *p = db_data2ptr(data); + int server = va_arg(ap, int); + if (server == -1) { + p->char_server = -1; + if (p->waiting_disconnect != INVALID_TIMER) { + delete_timer(p->waiting_disconnect, waiting_disconnect_timer); + p->waiting_disconnect = INVALID_TIMER; + } + } else if (p->char_server == server) + p->char_server = -2; //Char server disconnected. + return 0; } /** @@ -174,75 +168,72 @@ static int online_db_setoffline(DBKey key, DBData *data, va_list ap) */ static int online_data_cleanup_sub(DBKey key, DBData *data, va_list ap) { - struct online_login_data *character= db_data2ptr(data); - if (character->char_server == -2) //Unknown server.. set them offline - remove_online_user(character->account_id); - return 0; + struct online_login_data *character= db_data2ptr(data); + if (character->char_server == -2) //Unknown server.. set them offline + remove_online_user(character->account_id); + return 0; } static int online_data_cleanup(int tid, unsigned int tick, int id, intptr_t data) { - online_db->foreach(online_db, online_data_cleanup_sub); - return 0; -} + online_db->foreach(online_db, online_data_cleanup_sub); + return 0; +} //-------------------------------------------------------------------- // Packet send to all char-servers, except one (wos: without our self) //-------------------------------------------------------------------- -int charif_sendallwos(int sfd, uint8* buf, size_t len) +int charif_sendallwos(int sfd, uint8 *buf, size_t len) { - int i, c; - - for( i = 0, c = 0; i < ARRAYLENGTH(server); ++i ) - { - int fd = server[i].fd; - if( session_isValid(fd) && fd != sfd ) - { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - ++c; - } - } - - return c; + int i, c; + + for (i = 0, c = 0; i < ARRAYLENGTH(server); ++i) { + int fd = server[i].fd; + if (session_isValid(fd) && fd != sfd) { + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + ++c; + } + } + + return c; } /// Initializes a server structure. void chrif_server_init(int id) { - memset(&server[id], 0, sizeof(server[id])); - server[id].fd = -1; + memset(&server[id], 0, sizeof(server[id])); + server[id].fd = -1; } /// Destroys a server structure. void chrif_server_destroy(int id) { - if( server[id].fd != -1 ) - { - do_close(server[id].fd); - server[id].fd = -1; - } + if (server[id].fd != -1) { + do_close(server[id].fd); + server[id].fd = -1; + } } /// Resets all the data related to a server. void chrif_server_reset(int id) { - online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char server to offline. - chrif_server_destroy(id); - chrif_server_init(id); + online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char server to offline. + chrif_server_destroy(id); + chrif_server_init(id); } /// Called when the connection to Char Server is disconnected. void chrif_on_disconnect(int id) { - ShowStatus("Char-server '%s' has disconnected.\n", server[id].name); - chrif_server_reset(id); + ShowStatus("Char-server '%s' has disconnected.\n", server[id].name); + chrif_server_reset(id); } @@ -251,52 +242,49 @@ void chrif_on_disconnect(int id) //----------------------------------------------------- static int sync_ip_addresses(int tid, unsigned int tick, int id, intptr_t data) { - uint8 buf[2]; - ShowInfo("IP Sync in progress...\n"); - WBUFW(buf,0) = 0x2735; - charif_sendallwos(-1, buf, 2); - return 0; + uint8 buf[2]; + ShowInfo("IP Sync in progress...\n"); + WBUFW(buf,0) = 0x2735; + charif_sendallwos(-1, buf, 2); + return 0; } //----------------------------------------------------- // encrypted/unencrypted password check (from eApp) //----------------------------------------------------- -bool check_encrypted(const char* str1, const char* str2, const char* passwd) +bool check_encrypted(const char *str1, const char *str2, const char *passwd) { - char tmpstr[64+1], md5str[32+1]; + char tmpstr[64+1], md5str[32+1]; - safesnprintf(tmpstr, sizeof(tmpstr), "%s%s", str1, str2); - MD5_String(tmpstr, md5str); + safesnprintf(tmpstr, sizeof(tmpstr), "%s%s", str1, str2); + MD5_String(tmpstr, md5str); - return (0==strcmp(passwd, md5str)); + return (0==strcmp(passwd, md5str)); } -bool check_password(const char* md5key, int passwdenc, const char* passwd, const char* refpass) +bool check_password(const char *md5key, int passwdenc, const char *passwd, const char *refpass) { - if(passwdenc == 0) - { - return (0==strcmp(passwd, refpass)); - } - else - { - // password mode set to 1 -> md5(md5key, refpass) enable with - // password mode set to 2 -> md5(refpass, md5key) enable with - - return ((passwdenc&0x01) && check_encrypted(md5key, refpass, passwd)) || - ((passwdenc&0x02) && check_encrypted(refpass, md5key, passwd)); - } + if (passwdenc == 0) { + return (0==strcmp(passwd, refpass)); + } else { + // password mode set to 1 -> md5(md5key, refpass) enable with + // password mode set to 2 -> md5(refpass, md5key) enable with + + return ((passwdenc&0x01) && check_encrypted(md5key, refpass, passwd)) || + ((passwdenc&0x02) && check_encrypted(refpass, md5key, passwd)); + } } //----------------------------------------------------- // custom timestamp formatting (from eApp) //----------------------------------------------------- -const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format) +const char *timestamp2string(char *str, size_t size, time_t timestamp, const char *format) { - size_t len = strftime(str, size, format, localtime(×tamp)); - memset(str + len, '\0', size - len); - return str; + size_t len = strftime(str, size, format, localtime(×tamp)); + memset(str + len, '\0', size - len); + return str; } @@ -305,9 +293,9 @@ const char* timestamp2string(char* str, size_t size, time_t timestamp, const cha //-------------------------------------------- int lan_subnetcheck(uint32 ip) { - int i; - ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) ); - return ( i < subnet_count ) ? subnet[i].char_ip : 0; + int i; + ARR_FIND(0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask)); + return (i < subnet_count) ? subnet[i].char_ip : 0; } //---------------------------------- @@ -315,99 +303,89 @@ int lan_subnetcheck(uint32 ip) //---------------------------------- int login_lan_config_read(const char *lancfgName) { - FILE *fp; - int line_num = 0; - char line[1024], w1[64], w2[64], w3[64], w4[64]; - - if((fp = fopen(lancfgName, "r")) == NULL) { - ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName); - return 1; - } - - while(fgets(line, sizeof(line), fp)) - { - line_num++; - if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n') - continue; - - if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) - { - ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num); - continue; - } - - if( strcmpi(w1, "subnet") == 0 ) - { - subnet[subnet_count].mask = str2ip(w2); - subnet[subnet_count].char_ip = str2ip(w3); - subnet[subnet_count].map_ip = str2ip(w4); - - if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) ) - { - ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4); - continue; - } - - subnet_count++; - } - } - - if( subnet_count > 1 ) /* only useful if there is more than 1 available */ - ShowStatus("Read information about %d subnetworks.\n", subnet_count); - - fclose(fp); - return 0; + FILE *fp; + int line_num = 0; + char line[1024], w1[64], w2[64], w3[64], w4[64]; + + if ((fp = fopen(lancfgName, "r")) == NULL) { + ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName); + return 1; + } + + while (fgets(line, sizeof(line), fp)) { + line_num++; + if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n') + continue; + + if (sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) { + ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num); + continue; + } + + if (strcmpi(w1, "subnet") == 0) { + subnet[subnet_count].mask = str2ip(w2); + subnet[subnet_count].char_ip = str2ip(w3); + subnet[subnet_count].map_ip = str2ip(w4); + + if ((subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask)) { + ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4); + continue; + } + + subnet_count++; + } + } + + if (subnet_count > 1) /* only useful if there is more than 1 available */ + ShowStatus("Read information about %d subnetworks.\n", subnet_count); + + fclose(fp); + return 0; } //----------------------- // Console Command Parser [Wizputer] //----------------------- -int parse_console(const char* command) +int parse_console(const char *command) { - ShowNotice("Console command: %s\n", command); - - if( strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 || strcmpi("end", command) == 0 ) - runflag = 0; - else if( strcmpi("alive", command) == 0 || strcmpi("status", command) == 0 ) - ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); - else if( strcmpi("help", command) == 0 ) - { - ShowInfo("To shutdown the server:\n"); - ShowInfo(" 'shutdown|exit|quit|end'\n"); - ShowInfo("To know if server is alive:\n"); - ShowInfo(" 'alive|status'\n"); - ShowInfo("To create a new account:\n"); - ShowInfo(" 'create'\n"); - } - else - {// commands with parameters - char cmd[128], params[256]; - - if( sscanf(command, "%127s %255[^\r\n]", cmd, params) < 2 ) - { - return 0; - } - - if( strcmpi(cmd, "create") == 0 ) - { - char username[NAME_LENGTH], password[NAME_LENGTH], sex; - - if( sscanf(params, "%23s %23s %c", username, password, &sex) < 3 || strnlen(username, sizeof(username)) < 4 || strnlen(password, sizeof(password)) < 1 ) - { - ShowWarning("Console: Invalid parameters for '%s'. Usage: %s \n", cmd, cmd); - return 0; - } - - if( mmo_auth_new(username, password, TOUPPER(sex), "0.0.0.0") != -1 ) - { - ShowError("Console: Account creation failed.\n"); - return 0; - } - ShowStatus("Console: Account '%s' created successfully.\n", username); - } - } - - return 0; + ShowNotice("Console command: %s\n", command); + + if (strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 || strcmpi("end", command) == 0) + runflag = 0; + else if (strcmpi("alive", command) == 0 || strcmpi("status", command) == 0) + ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); + else if (strcmpi("help", command) == 0) { + ShowInfo("To shutdown the server:\n"); + ShowInfo(" 'shutdown|exit|quit|end'\n"); + ShowInfo("To know if server is alive:\n"); + ShowInfo(" 'alive|status'\n"); + ShowInfo("To create a new account:\n"); + ShowInfo(" 'create'\n"); + } else { + // commands with parameters + char cmd[128], params[256]; + + if (sscanf(command, "%127s %255[^\r\n]", cmd, params) < 2) { + return 0; + } + + if (strcmpi(cmd, "create") == 0) { + char username[NAME_LENGTH], password[NAME_LENGTH], sex; + + if (sscanf(params, "%23s %23s %c", username, password, &sex) < 3 || strnlen(username, sizeof(username)) < 4 || strnlen(password, sizeof(password)) < 1) { + ShowWarning("Console: Invalid parameters for '%s'. Usage: %s \n", cmd, cmd); + return 0; + } + + if (mmo_auth_new(username, password, TOUPPER(sex), "0.0.0.0") != -1) { + ShowError("Console: Account creation failed.\n"); + return 0; + } + ShowStatus("Console: Account '%s' created successfully.\n", username); + } + } + + return 0; } @@ -416,880 +394,898 @@ int parse_console(const char* command) //-------------------------------- int parse_fromchar(int fd) { - int j, id; - uint32 ipl; - char ip[16]; - - ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd ); - if( id == ARRAYLENGTH(server) ) - {// not a char server - ShowDebug("parse_fromchar: Disconnecting invalid session #%d (is not a char-server)\n", fd); - set_eof(fd); - do_close(fd); - return 0; - } - - if( session[fd]->flag.eof ) - { - do_close(fd); - server[id].fd = -1; - chrif_on_disconnect(id); - return 0; - } - - ipl = server[id].ip; - ip2str(ipl, ip); - - while( RFIFOREST(fd) >= 2 ) - { - uint16 command = RFIFOW(fd,0); - - switch( command ) - { - - case 0x2712: // request from char-server to authenticate an account - if( RFIFOREST(fd) < 23 ) - return 0; - { - struct auth_node* node; - - int account_id = RFIFOL(fd,2); - uint32 login_id1 = RFIFOL(fd,6); - uint32 login_id2 = RFIFOL(fd,10); - uint8 sex = RFIFOB(fd,14); - //uint32 ip_ = ntohl(RFIFOL(fd,15)); - int request_id = RFIFOL(fd,19); - RFIFOSKIP(fd,23); - - node = (struct auth_node*)idb_get(auth_db, account_id); - if( runflag == LOGINSERVER_ST_RUNNING && - node != NULL && - node->account_id == account_id && - node->login_id1 == login_id1 && - node->login_id2 == login_id2 && - node->sex == sex_num2str(sex) /*&& - node->ip == ip_*/ ) - {// found - //ShowStatus("Char-server '%s': authentication of the account %d accepted (ip: %s).\n", server[id].name, account_id, ip); - - // send ack - WFIFOHEAD(fd,25); - WFIFOW(fd,0) = 0x2713; - WFIFOL(fd,2) = account_id; - WFIFOL(fd,6) = login_id1; - WFIFOL(fd,10) = login_id2; - WFIFOB(fd,14) = sex; - WFIFOB(fd,15) = 0;// ok - WFIFOL(fd,16) = request_id; - WFIFOL(fd,20) = node->version; - WFIFOB(fd,24) = node->clienttype; - WFIFOSET(fd,25); - - // each auth entry can only be used once - idb_remove(auth_db, account_id); - } - else - {// authentication not found - ShowStatus("Char-server '%s': authentication of the account %d REFUSED (ip: %s).\n", server[id].name, account_id, ip); - WFIFOHEAD(fd,25); - WFIFOW(fd,0) = 0x2713; - WFIFOL(fd,2) = account_id; - WFIFOL(fd,6) = login_id1; - WFIFOL(fd,10) = login_id2; - WFIFOB(fd,14) = sex; - WFIFOB(fd,15) = 1;// auth failed - WFIFOL(fd,16) = request_id; - WFIFOL(fd,20) = 0; - WFIFOB(fd,24) = 0; - WFIFOSET(fd,25); - } - } - break; - - case 0x2714: - if( RFIFOREST(fd) < 6 ) - return 0; - { - int users = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - // how many users on world? (update) - if( server[id].users != users ) - { - ShowStatus("set users %s : %d\n", server[id].name, users); - - server[id].users = users; - } - } - break; - - case 0x2715: // request from char server to change e-email from default "a@a.com" - if (RFIFOREST(fd) < 46) - return 0; - { - struct mmo_account acc; - char email[40]; - - int account_id = RFIFOL(fd,2); - safestrncpy(email, (char*)RFIFOP(fd,6), 40); remove_control_chars(email); - RFIFOSKIP(fd,46); - - if( e_mail_check(email) == 0 ) - ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - e-mail is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip); - else - if( !accounts->load_num(accounts, &acc, account_id) || strcmp(acc.email, "a@a.com") == 0 || acc.email[0] == '\0' ) - ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - account doesn't exist or e-mail of account isn't default e-mail (account: %d, ip: %s).\n", server[id].name, account_id, ip); - else { - memcpy(acc.email, email, 40); - ShowNotice("Char-server '%s': Create an e-mail on an account with a default e-mail (account: %d, new e-mail: %s, ip: %s).\n", server[id].name, account_id, email, ip); - // Save - accounts->save(accounts, &acc); - } - } - break; - - case 0x2716: // request account data - if( RFIFOREST(fd) < 6 ) - return 0; - { - struct mmo_account acc; - time_t expiration_time = 0; - char email[40] = ""; - int group_id = 0; - char birthdate[10+1] = ""; - - int account_id = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - if( !accounts->load_num(accounts, &acc, account_id) ) - ShowNotice("Char-server '%s': account %d NOT found (ip: %s).\n", server[id].name, account_id, ip); - else - { - safestrncpy(email, acc.email, sizeof(email)); - expiration_time = acc.expiration_time; - group_id = acc.group_id; - safestrncpy(birthdate, acc.birthdate, sizeof(birthdate)); - } - - WFIFOHEAD(fd,62); - WFIFOW(fd,0) = 0x2717; - WFIFOL(fd,2) = account_id; - safestrncpy((char*)WFIFOP(fd,6), email, 40); - WFIFOL(fd,46) = (uint32)expiration_time; - WFIFOB(fd,50) = group_id; - safestrncpy((char*)WFIFOP(fd,51), birthdate, 10+1); - WFIFOSET(fd,62); - } - break; - - case 0x2719: // ping request from charserver - RFIFOSKIP(fd,2); - - WFIFOHEAD(fd,2); - WFIFOW(fd,0) = 0x2718; - WFIFOSET(fd,2); - break; - - // Map server send information to change an email of an account via char-server - case 0x2722: // 0x2722 .L .40B .40B - if (RFIFOREST(fd) < 86) - return 0; - { - struct mmo_account acc; - char actual_email[40]; - char new_email[40]; - - int account_id = RFIFOL(fd,2); - safestrncpy(actual_email, (char*)RFIFOP(fd,6), 40); - safestrncpy(new_email, (char*)RFIFOP(fd,46), 40); - RFIFOSKIP(fd, 86); - - if( e_mail_check(actual_email) == 0 ) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual email is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip); - else - if( e_mail_check(new_email) == 0 ) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a invalid new e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip); - else - if( strcmpi(new_email, "a@a.com") == 0 ) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a default e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip); - else - if( !accounts->load_num(accounts, &acc, account_id) ) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but account doesn't exist (account: %d, ip: %s).\n", server[id].name, account_id, ip); - else - if( strcmpi(acc.email, actual_email) != 0 ) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual e-mail is incorrect (account: %d (%s), actual e-mail: %s, proposed e-mail: %s, ip: %s).\n", server[id].name, account_id, acc.userid, acc.email, actual_email, ip); - else { - safestrncpy(acc.email, new_email, 40); - ShowNotice("Char-server '%s': Modify an e-mail on an account (@email GM command) (account: %d (%s), new e-mail: %s, ip: %s).\n", server[id].name, account_id, acc.userid, new_email, ip); - // Save - accounts->save(accounts, &acc); - } - } - break; - - case 0x2724: // Receiving an account state update request from a map-server (relayed via char-server) - if (RFIFOREST(fd) < 10) - return 0; - { - struct mmo_account acc; - - int account_id = RFIFOL(fd,2); - unsigned int state = RFIFOL(fd,6); - RFIFOSKIP(fd,10); - - if( !accounts->load_num(accounts, &acc, account_id) ) - ShowNotice("Char-server '%s': Error of Status change (account: %d not found, suggested status %d, ip: %s).\n", server[id].name, account_id, state, ip); - else - if( acc.state == state ) - ShowNotice("Char-server '%s': Error of Status change - actual status is already the good status (account: %d, status %d, ip: %s).\n", server[id].name, account_id, state, ip); - else { - ShowNotice("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", server[id].name, account_id, state, ip); - - acc.state = state; - // Save - accounts->save(accounts, &acc); - - // notify other servers - if (state != 0) { - uint8 buf[11]; - WBUFW(buf,0) = 0x2731; - WBUFL(buf,2) = account_id; - WBUFB(buf,6) = 0; // 0: change of state, 1: ban - WBUFL(buf,7) = state; // status or final date of a banishment - charif_sendallwos(-1, buf, 11); - } - } - } - break; - - case 0x2725: // Receiving of map-server via char-server a ban request - if (RFIFOREST(fd) < 18) - return 0; - { - struct mmo_account acc; - - int account_id = RFIFOL(fd,2); - int year = (short)RFIFOW(fd,6); - int month = (short)RFIFOW(fd,8); - int mday = (short)RFIFOW(fd,10); - int hour = (short)RFIFOW(fd,12); - int min = (short)RFIFOW(fd,14); - int sec = (short)RFIFOW(fd,16); - RFIFOSKIP(fd,18); - - if( !accounts->load_num(accounts, &acc, account_id) ) - ShowNotice("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); - else - { - time_t timestamp; - struct tm *tmtime; - if (acc.unban_time == 0 || acc.unban_time < time(NULL)) - timestamp = time(NULL); // new ban - else - timestamp = acc.unban_time; // add to existing ban - tmtime = localtime(×tamp); - tmtime->tm_year = tmtime->tm_year + year; - tmtime->tm_mon = tmtime->tm_mon + month; - tmtime->tm_mday = tmtime->tm_mday + mday; - tmtime->tm_hour = tmtime->tm_hour + hour; - tmtime->tm_min = tmtime->tm_min + min; - tmtime->tm_sec = tmtime->tm_sec + sec; - timestamp = mktime(tmtime); - if (timestamp == -1) - ShowNotice("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", server[id].name, account_id, ip); - else - if( timestamp <= time(NULL) || timestamp == 0 ) - ShowNotice("Char-server '%s': Error of ban request (account: %d, new date unbans the account, ip: %s).\n", server[id].name, account_id, ip); - else - { - uint8 buf[11]; - char tmpstr[24]; - timestamp2string(tmpstr, sizeof(tmpstr), timestamp, login_config.date_format); - ShowNotice("Char-server '%s': Ban request (account: %d, new final date of banishment: %d (%s), ip: %s).\n", server[id].name, account_id, timestamp, tmpstr, ip); - - acc.unban_time = timestamp; - - // Save - accounts->save(accounts, &acc); - - WBUFW(buf,0) = 0x2731; - WBUFL(buf,2) = account_id; - WBUFB(buf,6) = 1; // 0: change of status, 1: ban - WBUFL(buf,7) = (uint32)timestamp; // status or final date of a banishment - charif_sendallwos(-1, buf, 11); - } - } - } - break; - - case 0x2727: // Change of sex (sex is reversed) - if( RFIFOREST(fd) < 6 ) - return 0; - { - struct mmo_account acc; - - int account_id = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - if( !accounts->load_num(accounts, &acc, account_id) ) - ShowNotice("Char-server '%s': Error of sex change (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); - else - if( acc.sex == 'S' ) - ShowNotice("Char-server '%s': Error of sex change - account to change is a Server account (account: %d, ip: %s).\n", server[id].name, account_id, ip); - else - { - unsigned char buf[7]; - char sex = ( acc.sex == 'M' ) ? 'F' : 'M'; //Change gender - - ShowNotice("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", server[id].name, account_id, sex, ip); - - acc.sex = sex; - // Save - accounts->save(accounts, &acc); - - // announce to other servers - WBUFW(buf,0) = 0x2723; - WBUFL(buf,2) = account_id; - WBUFB(buf,6) = sex_str2num(sex); - charif_sendallwos(-1, buf, 7); - } - } - break; - - case 0x2728: // We receive account_reg2 from a char-server, and we send them to other map-servers. - if( RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2) ) - return 0; - { - struct mmo_account acc; - - int account_id = RFIFOL(fd,4); - - if( !accounts->load_num(accounts, &acc, account_id) ) - ShowStatus("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); - else - { - int len; - int p; - ShowNotice("char-server '%s': receiving (from the char-server) of account_reg2 (account: %d, ip: %s).\n", server[id].name, account_id, ip); - for( j = 0, p = 13; j < ACCOUNT_REG2_NUM && p < RFIFOW(fd,2); ++j ) - { - sscanf((char*)RFIFOP(fd,p), "%31c%n", acc.account_reg2[j].str, &len); - acc.account_reg2[j].str[len]='\0'; - p +=len+1; //+1 to skip the '\0' between strings. - sscanf((char*)RFIFOP(fd,p), "%255c%n", acc.account_reg2[j].value, &len); - acc.account_reg2[j].value[len]='\0'; - p +=len+1; - remove_control_chars(acc.account_reg2[j].str); - remove_control_chars(acc.account_reg2[j].value); - } - acc.account_reg2_num = j; - - // Save - accounts->save(accounts, &acc); - - // Sending information towards the other char-servers. - RFIFOW(fd,0) = 0x2729;// reusing read buffer - charif_sendallwos(fd, RFIFOP(fd,0), RFIFOW(fd,2)); - } - RFIFOSKIP(fd,RFIFOW(fd,2)); - } - break; - - case 0x272a: // Receiving of map-server via char-server an unban request - if( RFIFOREST(fd) < 6 ) - return 0; - { - struct mmo_account acc; - - int account_id = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - if( !accounts->load_num(accounts, &acc, account_id) ) - ShowNotice("Char-server '%s': Error of UnBan request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); - else - if( acc.unban_time == 0 ) - ShowNotice("Char-server '%s': Error of UnBan request (account: %d, no change for unban date, ip: %s).\n", server[id].name, account_id, ip); - else - { - ShowNotice("Char-server '%s': UnBan request (account: %d, ip: %s).\n", server[id].name, account_id, ip); - acc.unban_time = 0; - accounts->save(accounts, &acc); - } - } - break; - - case 0x272b: // Set account_id to online [Wizputer] - if( RFIFOREST(fd) < 6 ) - return 0; - add_online_user(id, RFIFOL(fd,2)); - RFIFOSKIP(fd,6); - break; - - case 0x272c: // Set account_id to offline [Wizputer] - if( RFIFOREST(fd) < 6 ) - return 0; - remove_online_user(RFIFOL(fd,2)); - RFIFOSKIP(fd,6); - break; - - case 0x272d: // Receive list of all online accounts. [Skotlex] - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { - struct online_login_data *p; - int aid; - uint32 i, users; - online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char-server offline first - users = RFIFOW(fd,4); - for (i = 0; i < users; i++) { - aid = RFIFOL(fd,6+i*4); - p = idb_ensure(online_db, aid, create_online_user); - p->char_server = id; - if (p->waiting_disconnect != INVALID_TIMER) - { - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - p->waiting_disconnect = INVALID_TIMER; - } - } - } - RFIFOSKIP(fd,RFIFOW(fd,2)); - break; - - case 0x272e: //Request account_reg2 for a character. - if (RFIFOREST(fd) < 10) - return 0; - { - struct mmo_account acc; - size_t off; - - int account_id = RFIFOL(fd,2); - int char_id = RFIFOL(fd,6); - RFIFOSKIP(fd,10); - - WFIFOHEAD(fd,ACCOUNT_REG2_NUM*sizeof(struct global_reg)); - WFIFOW(fd,0) = 0x2729; - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = char_id; - WFIFOB(fd,12) = 1; //Type 1 for Account2 registry - - off = 13; - if( accounts->load_num(accounts, &acc, account_id) ) - { - for( j = 0; j < acc.account_reg2_num; j++ ) - { - if( acc.account_reg2[j].str[0] != '\0' ) - { - off += sprintf((char*)WFIFOP(fd,off), "%s", acc.account_reg2[j].str)+1; //We add 1 to consider the '\0' in place. - off += sprintf((char*)WFIFOP(fd,off), "%s", acc.account_reg2[j].value)+1; - } - } - } - - WFIFOW(fd,2) = (uint16)off; - WFIFOSET(fd,WFIFOW(fd,2)); - } - break; - - case 0x2736: // WAN IP update from char-server - if( RFIFOREST(fd) < 6 ) - return 0; - server[id].ip = ntohl(RFIFOL(fd,2)); - ShowInfo("Updated IP of Server #%d to %d.%d.%d.%d.\n",id, CONVIP(server[id].ip)); - RFIFOSKIP(fd,6); - break; - - case 0x2737: //Request to set all offline. - ShowInfo("Setting accounts from char-server %d offline.\n", id); - online_db->foreach(online_db, online_db_setoffline, id); - RFIFOSKIP(fd,2); - break; - - default: - ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", command); - set_eof(fd); - return 0; - } // switch - } // while - - return 0; + int j, id; + uint32 ipl; + char ip[16]; + + ARR_FIND(0, ARRAYLENGTH(server), id, server[id].fd == fd); + if (id == ARRAYLENGTH(server)) { + // not a char server + ShowDebug("parse_fromchar: Disconnecting invalid session #%d (is not a char-server)\n", fd); + set_eof(fd); + do_close(fd); + return 0; + } + + if (session[fd]->flag.eof) { + do_close(fd); + server[id].fd = -1; + chrif_on_disconnect(id); + return 0; + } + + ipl = server[id].ip; + ip2str(ipl, ip); + + while (RFIFOREST(fd) >= 2) { + uint16 command = RFIFOW(fd,0); + + switch (command) { + + case 0x2712: // request from char-server to authenticate an account + if (RFIFOREST(fd) < 23) + return 0; + { + struct auth_node *node; + + int account_id = RFIFOL(fd,2); + uint32 login_id1 = RFIFOL(fd,6); + uint32 login_id2 = RFIFOL(fd,10); + uint8 sex = RFIFOB(fd,14); + //uint32 ip_ = ntohl(RFIFOL(fd,15)); + int request_id = RFIFOL(fd,19); + RFIFOSKIP(fd,23); + + node = (struct auth_node *)idb_get(auth_db, account_id); + if (runflag == LOGINSERVER_ST_RUNNING && + node != NULL && + node->account_id == account_id && + node->login_id1 == login_id1 && + node->login_id2 == login_id2 && + node->sex == sex_num2str(sex) /*&& + node->ip == ip_*/) { + // found + //ShowStatus("Char-server '%s': authentication of the account %d accepted (ip: %s).\n", server[id].name, account_id, ip); + + // send ack + WFIFOHEAD(fd,25); + WFIFOW(fd,0) = 0x2713; + WFIFOL(fd,2) = account_id; + WFIFOL(fd,6) = login_id1; + WFIFOL(fd,10) = login_id2; + WFIFOB(fd,14) = sex; + WFIFOB(fd,15) = 0;// ok + WFIFOL(fd,16) = request_id; + WFIFOL(fd,20) = node->version; + WFIFOB(fd,24) = node->clienttype; + WFIFOSET(fd,25); + + // each auth entry can only be used once + idb_remove(auth_db, account_id); + } else { + // authentication not found + ShowStatus("Char-server '%s': authentication of the account %d REFUSED (ip: %s).\n", server[id].name, account_id, ip); + WFIFOHEAD(fd,25); + WFIFOW(fd,0) = 0x2713; + WFIFOL(fd,2) = account_id; + WFIFOL(fd,6) = login_id1; + WFIFOL(fd,10) = login_id2; + WFIFOB(fd,14) = sex; + WFIFOB(fd,15) = 1;// auth failed + WFIFOL(fd,16) = request_id; + WFIFOL(fd,20) = 0; + WFIFOB(fd,24) = 0; + WFIFOSET(fd,25); + } + } + break; + + case 0x2714: + if (RFIFOREST(fd) < 6) + return 0; + { + int users = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + // how many users on world? (update) + if (server[id].users != users) { + ShowStatus("set users %s : %d\n", server[id].name, users); + + server[id].users = users; + } + } + break; + + case 0x2715: // request from char server to change e-email from default "a@a.com" + if (RFIFOREST(fd) < 46) + return 0; + { + struct mmo_account acc; + char email[40]; + + int account_id = RFIFOL(fd,2); + safestrncpy(email, (char *)RFIFOP(fd,6), 40); + remove_control_chars(email); + RFIFOSKIP(fd,46); + + if (e_mail_check(email) == 0) + ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - e-mail is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip); + else if (!accounts->load_num(accounts, &acc, account_id) || strcmp(acc.email, "a@a.com") == 0 || acc.email[0] == '\0') + ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - account doesn't exist or e-mail of account isn't default e-mail (account: %d, ip: %s).\n", server[id].name, account_id, ip); + else { + memcpy(acc.email, email, 40); + ShowNotice("Char-server '%s': Create an e-mail on an account with a default e-mail (account: %d, new e-mail: %s, ip: %s).\n", server[id].name, account_id, email, ip); + // Save + accounts->save(accounts, &acc); + } + } + break; + + case 0x2716: // request account data + if (RFIFOREST(fd) < 6) + return 0; + { + struct mmo_account acc; + time_t expiration_time = 0; + char email[40] = ""; + int group_id = 0; + char birthdate[10+1] = ""; + + int account_id = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + if (!accounts->load_num(accounts, &acc, account_id)) + ShowNotice("Char-server '%s': account %d NOT found (ip: %s).\n", server[id].name, account_id, ip); + else { + safestrncpy(email, acc.email, sizeof(email)); + expiration_time = acc.expiration_time; + group_id = acc.group_id; + safestrncpy(birthdate, acc.birthdate, sizeof(birthdate)); + } + + WFIFOHEAD(fd,62); + WFIFOW(fd,0) = 0x2717; + WFIFOL(fd,2) = account_id; + safestrncpy((char *)WFIFOP(fd,6), email, 40); + WFIFOL(fd,46) = (uint32)expiration_time; + WFIFOB(fd,50) = group_id; + safestrncpy((char *)WFIFOP(fd,51), birthdate, 10+1); + WFIFOSET(fd,62); + } + break; + + case 0x2719: // ping request from charserver + RFIFOSKIP(fd,2); + + WFIFOHEAD(fd,2); + WFIFOW(fd,0) = 0x2718; + WFIFOSET(fd,2); + break; + + // Map server send information to change an email of an account via char-server + case 0x2722: // 0x2722 .L .40B .40B + if (RFIFOREST(fd) < 86) + return 0; + { + struct mmo_account acc; + char actual_email[40]; + char new_email[40]; + + int account_id = RFIFOL(fd,2); + safestrncpy(actual_email, (char *)RFIFOP(fd,6), 40); + safestrncpy(new_email, (char *)RFIFOP(fd,46), 40); + RFIFOSKIP(fd, 86); + + if (e_mail_check(actual_email) == 0) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual email is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip); + else if (e_mail_check(new_email) == 0) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a invalid new e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip); + else if (strcmpi(new_email, "a@a.com") == 0) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a default e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip); + else if (!accounts->load_num(accounts, &acc, account_id)) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but account doesn't exist (account: %d, ip: %s).\n", server[id].name, account_id, ip); + else if (strcmpi(acc.email, actual_email) != 0) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual e-mail is incorrect (account: %d (%s), actual e-mail: %s, proposed e-mail: %s, ip: %s).\n", server[id].name, account_id, acc.userid, acc.email, actual_email, ip); + else { + safestrncpy(acc.email, new_email, 40); + ShowNotice("Char-server '%s': Modify an e-mail on an account (@email GM command) (account: %d (%s), new e-mail: %s, ip: %s).\n", server[id].name, account_id, acc.userid, new_email, ip); + // Save + accounts->save(accounts, &acc); + } + } + break; + + case 0x2724: // Receiving an account state update request from a map-server (relayed via char-server) + if (RFIFOREST(fd) < 10) + return 0; + { + struct mmo_account acc; + + int account_id = RFIFOL(fd,2); + unsigned int state = RFIFOL(fd,6); + RFIFOSKIP(fd,10); + + if (!accounts->load_num(accounts, &acc, account_id)) + ShowNotice("Char-server '%s': Error of Status change (account: %d not found, suggested status %d, ip: %s).\n", server[id].name, account_id, state, ip); + else if (acc.state == state) + ShowNotice("Char-server '%s': Error of Status change - actual status is already the good status (account: %d, status %d, ip: %s).\n", server[id].name, account_id, state, ip); + else { + ShowNotice("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", server[id].name, account_id, state, ip); + + acc.state = state; + // Save + accounts->save(accounts, &acc); + + // notify other servers + if (state != 0) { + uint8 buf[11]; + WBUFW(buf,0) = 0x2731; + WBUFL(buf,2) = account_id; + WBUFB(buf,6) = 0; // 0: change of state, 1: ban + WBUFL(buf,7) = state; // status or final date of a banishment + charif_sendallwos(-1, buf, 11); + } + } + } + break; + + case 0x2725: // Receiving of map-server via char-server a ban request + if (RFIFOREST(fd) < 18) + return 0; + { + struct mmo_account acc; + + int account_id = RFIFOL(fd,2); + int year = (short)RFIFOW(fd,6); + int month = (short)RFIFOW(fd,8); + int mday = (short)RFIFOW(fd,10); + int hour = (short)RFIFOW(fd,12); + int min = (short)RFIFOW(fd,14); + int sec = (short)RFIFOW(fd,16); + RFIFOSKIP(fd,18); + + if (!accounts->load_num(accounts, &acc, account_id)) + ShowNotice("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); + else { + time_t timestamp; + struct tm *tmtime; + if (acc.unban_time == 0 || acc.unban_time < time(NULL)) + timestamp = time(NULL); // new ban + else + timestamp = acc.unban_time; // add to existing ban + tmtime = localtime(×tamp); + tmtime->tm_year = tmtime->tm_year + year; + tmtime->tm_mon = tmtime->tm_mon + month; + tmtime->tm_mday = tmtime->tm_mday + mday; + tmtime->tm_hour = tmtime->tm_hour + hour; + tmtime->tm_min = tmtime->tm_min + min; + tmtime->tm_sec = tmtime->tm_sec + sec; + timestamp = mktime(tmtime); + if (timestamp == -1) + ShowNotice("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", server[id].name, account_id, ip); + else if (timestamp <= time(NULL) || timestamp == 0) + ShowNotice("Char-server '%s': Error of ban request (account: %d, new date unbans the account, ip: %s).\n", server[id].name, account_id, ip); + else { + uint8 buf[11]; + char tmpstr[24]; + timestamp2string(tmpstr, sizeof(tmpstr), timestamp, login_config.date_format); + ShowNotice("Char-server '%s': Ban request (account: %d, new final date of banishment: %d (%s), ip: %s).\n", server[id].name, account_id, timestamp, tmpstr, ip); + + acc.unban_time = timestamp; + + // Save + accounts->save(accounts, &acc); + + WBUFW(buf,0) = 0x2731; + WBUFL(buf,2) = account_id; + WBUFB(buf,6) = 1; // 0: change of status, 1: ban + WBUFL(buf,7) = (uint32)timestamp; // status or final date of a banishment + charif_sendallwos(-1, buf, 11); + } + } + } + break; + + case 0x2727: // Change of sex (sex is reversed) + if (RFIFOREST(fd) < 6) + return 0; + { + struct mmo_account acc; + + int account_id = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + if (!accounts->load_num(accounts, &acc, account_id)) + ShowNotice("Char-server '%s': Error of sex change (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); + else if (acc.sex == 'S') + ShowNotice("Char-server '%s': Error of sex change - account to change is a Server account (account: %d, ip: %s).\n", server[id].name, account_id, ip); + else { + unsigned char buf[7]; + char sex = (acc.sex == 'M') ? 'F' : 'M'; //Change gender + + ShowNotice("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", server[id].name, account_id, sex, ip); + + acc.sex = sex; + // Save + accounts->save(accounts, &acc); + + // announce to other servers + WBUFW(buf,0) = 0x2723; + WBUFL(buf,2) = account_id; + WBUFB(buf,6) = sex_str2num(sex); + charif_sendallwos(-1, buf, 7); + } + } + break; + + case 0x2728: // We receive account_reg2 from a char-server, and we send them to other map-servers. + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + { + struct mmo_account acc; + + int account_id = RFIFOL(fd,4); + + if (!accounts->load_num(accounts, &acc, account_id)) + ShowStatus("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); + else { + int len; + int p; + ShowNotice("char-server '%s': receiving (from the char-server) of account_reg2 (account: %d, ip: %s).\n", server[id].name, account_id, ip); + for (j = 0, p = 13; j < ACCOUNT_REG2_NUM && p < RFIFOW(fd,2); ++j) { + sscanf((char *)RFIFOP(fd,p), "%31c%n", acc.account_reg2[j].str, &len); + acc.account_reg2[j].str[len]='\0'; + p +=len+1; //+1 to skip the '\0' between strings. + sscanf((char *)RFIFOP(fd,p), "%255c%n", acc.account_reg2[j].value, &len); + acc.account_reg2[j].value[len]='\0'; + p +=len+1; + remove_control_chars(acc.account_reg2[j].str); + remove_control_chars(acc.account_reg2[j].value); + } + acc.account_reg2_num = j; + + // Save + accounts->save(accounts, &acc); + + // Sending information towards the other char-servers. + RFIFOW(fd,0) = 0x2729;// reusing read buffer + charif_sendallwos(fd, RFIFOP(fd,0), RFIFOW(fd,2)); + } + RFIFOSKIP(fd,RFIFOW(fd,2)); + } + break; + + case 0x272a: // Receiving of map-server via char-server an unban request + if (RFIFOREST(fd) < 6) + return 0; + { + struct mmo_account acc; + + int account_id = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + if (!accounts->load_num(accounts, &acc, account_id)) + ShowNotice("Char-server '%s': Error of UnBan request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); + else if (acc.unban_time == 0) + ShowNotice("Char-server '%s': Error of UnBan request (account: %d, no change for unban date, ip: %s).\n", server[id].name, account_id, ip); + else { + ShowNotice("Char-server '%s': UnBan request (account: %d, ip: %s).\n", server[id].name, account_id, ip); + acc.unban_time = 0; + accounts->save(accounts, &acc); + } + } + break; + + case 0x272b: // Set account_id to online [Wizputer] + if (RFIFOREST(fd) < 6) + return 0; + add_online_user(id, RFIFOL(fd,2)); + RFIFOSKIP(fd,6); + break; + + case 0x272c: // Set account_id to offline [Wizputer] + if (RFIFOREST(fd) < 6) + return 0; + remove_online_user(RFIFOL(fd,2)); + RFIFOSKIP(fd,6); + break; + + case 0x272d: // Receive list of all online accounts. [Skotlex] + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + { + struct online_login_data *p; + int aid; + uint32 i, users; + online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char-server offline first + users = RFIFOW(fd,4); + for (i = 0; i < users; i++) { + aid = RFIFOL(fd,6+i*4); + p = idb_ensure(online_db, aid, create_online_user); + p->char_server = id; + if (p->waiting_disconnect != INVALID_TIMER) { + delete_timer(p->waiting_disconnect, waiting_disconnect_timer); + p->waiting_disconnect = INVALID_TIMER; + } + } + } + RFIFOSKIP(fd,RFIFOW(fd,2)); + break; + + case 0x272e: //Request account_reg2 for a character. + if (RFIFOREST(fd) < 10) + return 0; + { + struct mmo_account acc; + size_t off; + + int account_id = RFIFOL(fd,2); + int char_id = RFIFOL(fd,6); + RFIFOSKIP(fd,10); + + WFIFOHEAD(fd,ACCOUNT_REG2_NUM*sizeof(struct global_reg)); + WFIFOW(fd,0) = 0x2729; + WFIFOL(fd,4) = account_id; + WFIFOL(fd,8) = char_id; + WFIFOB(fd,12) = 1; //Type 1 for Account2 registry + + off = 13; + if (accounts->load_num(accounts, &acc, account_id)) { + for (j = 0; j < acc.account_reg2_num; j++) { + if (acc.account_reg2[j].str[0] != '\0') { + off += sprintf((char *)WFIFOP(fd,off), "%s", acc.account_reg2[j].str)+1; //We add 1 to consider the '\0' in place. + off += sprintf((char *)WFIFOP(fd,off), "%s", acc.account_reg2[j].value)+1; + } + } + } + + WFIFOW(fd,2) = (uint16)off; + WFIFOSET(fd,WFIFOW(fd,2)); + } + break; + + case 0x2736: // WAN IP update from char-server + if (RFIFOREST(fd) < 6) + return 0; + server[id].ip = ntohl(RFIFOL(fd,2)); + ShowInfo("Updated IP of Server #%d to %d.%d.%d.%d.\n",id, CONVIP(server[id].ip)); + RFIFOSKIP(fd,6); + break; + + case 0x2737: //Request to set all offline. + ShowInfo("Setting accounts from char-server %d offline.\n", id); + online_db->foreach(online_db, online_db_setoffline, id); + RFIFOSKIP(fd,2); + break; + + default: + ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", command); + set_eof(fd); + return 0; + } // switch + } // while + + return 0; } //------------------------------------- // Make new account //------------------------------------- -int mmo_auth_new(const char* userid, const char* pass, const char sex, const char* last_ip) { - static int num_regs = 0; // registration counter - static unsigned int new_reg_tick = 0; - unsigned int tick = gettick(); - struct mmo_account acc; - - //Account Registration Flood Protection by [Kevin] - if( new_reg_tick == 0 ) - new_reg_tick = gettick(); - if( DIFF_TICK(tick, new_reg_tick) < 0 && num_regs >= allowed_regs ) { - ShowNotice("Account registration denied (registration limit exceeded)\n"); - return 3; - } - - if( login_config.new_acc_length_limit && ( strlen(userid) < 4 || strlen(pass) < 4 ) ) - return 1; - - // check for invalid inputs - if( sex != 'M' && sex != 'F' ) - return 0; // 0 = Unregistered ID - - // check if the account doesn't exist already - if( accounts->load_str(accounts, &acc, userid) ) { - ShowNotice("Attempt of creation of an already existant account (account: %s_%c, pass: %s, received pass: %s)\n", userid, sex, acc.pass, pass); - return 1; // 1 = Incorrect Password - } - - memset(&acc, '\0', sizeof(acc)); - acc.account_id = -1; // assigned by account db - safestrncpy(acc.userid, userid, sizeof(acc.userid)); - safestrncpy(acc.pass, pass, sizeof(acc.pass)); - acc.sex = sex; - safestrncpy(acc.email, "a@a.com", sizeof(acc.email)); - acc.expiration_time = ( login_config.start_limited_time != -1 ) ? time(NULL) + login_config.start_limited_time : 0; - safestrncpy(acc.lastlogin, "0000-00-00 00:00:00", sizeof(acc.lastlogin)); - safestrncpy(acc.last_ip, last_ip, sizeof(acc.last_ip)); - safestrncpy(acc.birthdate, "0000-00-00", sizeof(acc.birthdate)); - - if( !accounts->create(accounts, &acc) ) - return 0; - - ShowNotice("Account creation (account %s, id: %d, pass: %s, sex: %c)\n", acc.userid, acc.account_id, acc.pass, acc.sex); - - if( DIFF_TICK(tick, new_reg_tick) > 0 ) {// Update the registration check. - num_regs = 0; - new_reg_tick = tick + time_allowed*1000; - } - ++num_regs; - - return -1; +int mmo_auth_new(const char *userid, const char *pass, const char sex, const char *last_ip) +{ + static int num_regs = 0; // registration counter + static unsigned int new_reg_tick = 0; + unsigned int tick = gettick(); + struct mmo_account acc; + + //Account Registration Flood Protection by [Kevin] + if (new_reg_tick == 0) + new_reg_tick = gettick(); + if (DIFF_TICK(tick, new_reg_tick) < 0 && num_regs >= allowed_regs) { + ShowNotice("Account registration denied (registration limit exceeded)\n"); + return 3; + } + + if (login_config.new_acc_length_limit && (strlen(userid) < 4 || strlen(pass) < 4)) + return 1; + + // check for invalid inputs + if (sex != 'M' && sex != 'F') + return 0; // 0 = Unregistered ID + + // check if the account doesn't exist already + if (accounts->load_str(accounts, &acc, userid)) { + ShowNotice("Attempt of creation of an already existant account (account: %s_%c, pass: %s, received pass: %s)\n", userid, sex, acc.pass, pass); + return 1; // 1 = Incorrect Password + } + + memset(&acc, '\0', sizeof(acc)); + acc.account_id = -1; // assigned by account db + safestrncpy(acc.userid, userid, sizeof(acc.userid)); + safestrncpy(acc.pass, pass, sizeof(acc.pass)); + acc.sex = sex; + safestrncpy(acc.email, "a@a.com", sizeof(acc.email)); + acc.expiration_time = (login_config.start_limited_time != -1) ? time(NULL) + login_config.start_limited_time : 0; + safestrncpy(acc.lastlogin, "0000-00-00 00:00:00", sizeof(acc.lastlogin)); + safestrncpy(acc.last_ip, last_ip, sizeof(acc.last_ip)); + safestrncpy(acc.birthdate, "0000-00-00", sizeof(acc.birthdate)); + + if (!accounts->create(accounts, &acc)) + return 0; + + ShowNotice("Account creation (account %s, id: %d, pass: %s, sex: %c)\n", acc.userid, acc.account_id, acc.pass, acc.sex); + + if (DIFF_TICK(tick, new_reg_tick) > 0) { // Update the registration check. + num_regs = 0; + new_reg_tick = tick + time_allowed*1000; + } + ++num_regs; + + return -1; } //----------------------------------------------------- // Check/authentication of a connection //----------------------------------------------------- -int mmo_auth(struct login_session_data* sd, bool isServer) { - struct mmo_account acc; - int len; - - char ip[16]; - ip2str(session[sd->fd]->client_addr, ip); - - // DNS Blacklist check - if( login_config.use_dnsbl ) { - char r_ip[16]; - char ip_dnsbl[256]; - char* dnsbl_serv; - uint8* sin_addr = (uint8*)&session[sd->fd]->client_addr; - - sprintf(r_ip, "%u.%u.%u.%u", sin_addr[0], sin_addr[1], sin_addr[2], sin_addr[3]); - - for( dnsbl_serv = strtok(login_config.dnsbl_servs,","); dnsbl_serv != NULL; dnsbl_serv = strtok(NULL,",") ) { - sprintf(ip_dnsbl, "%s.%s", r_ip, trim(dnsbl_serv)); - if( host2ip(ip_dnsbl) ) { - ShowInfo("DNSBL: (%s) Blacklisted. User Kicked.\n", r_ip); - return 3; - } - } - - } - - //Client Version check - if( login_config.check_client_version && sd->version != login_config.client_version_to_connect ) - return 5; - - len = strnlen(sd->userid, NAME_LENGTH); - - // Account creation with _M/_F - if( login_config.new_account_flag ) { - if( len > 2 && strnlen(sd->passwd, NAME_LENGTH) > 0 && // valid user and password lengths - sd->passwdenc == 0 && // unencoded password - sd->userid[len-2] == '_' && memchr("FfMm", sd->userid[len-1], 4) ) // _M/_F suffix - { - int result; - - // remove the _M/_F suffix - len -= 2; - sd->userid[len] = '\0'; - - result = mmo_auth_new(sd->userid, sd->passwd, TOUPPER(sd->userid[len+1]), ip); - if( result != -1 ) - return result;// Failed to make account. [Skotlex]. - } - } - - if( !accounts->load_str(accounts, &acc, sd->userid) ) { - ShowNotice("Unknown account (account: %s, received pass: %s, ip: %s)\n", sd->userid, sd->passwd, ip); - return 0; // 0 = Unregistered ID - } - - if( !check_password(sd->md5key, sd->passwdenc, sd->passwd, acc.pass) ) { - ShowNotice("Invalid password (account: '%s', pass: '%s', received pass: '%s', ip: %s)\n", sd->userid, acc.pass, sd->passwd, ip); - return 1; // 1 = Incorrect Password - } - - if( acc.expiration_time != 0 && acc.expiration_time < time(NULL) ) { - ShowNotice("Connection refused (account: %s, pass: %s, expired ID, ip: %s)\n", sd->userid, sd->passwd, ip); - return 2; // 2 = This ID is expired - } - - if( acc.unban_time != 0 && acc.unban_time > time(NULL) ) { - char tmpstr[24]; - timestamp2string(tmpstr, sizeof(tmpstr), acc.unban_time, login_config.date_format); - ShowNotice("Connection refused (account: %s, pass: %s, banned until %s, ip: %s)\n", sd->userid, sd->passwd, tmpstr, ip); - return 6; // 6 = Your are Prohibited to log in until %s - } - - if( acc.state != 0 ) { - ShowNotice("Connection refused (account: %s, pass: %s, state: %d, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip); - return acc.state - 1; - } - - if( login_config.client_hash_check && !isServer ) { - struct client_hash_node *node = login_config.client_hash_nodes; - bool match = false; - - if( !sd->has_client_hash ) { - ShowNotice("Client doesn't sent client hash (account: %s, pass: %s, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip); - return 5; - } - - while( node ) { - if( node->group_id <= acc.group_id && memcmp(node->hash, sd->client_hash, 16) == 0 ) { - match = true; - break; - } - - node = node->next; - } - - if( !match ) { - char smd5[33]; - int i; - - for( i = 0; i < 16; i++ ) - sprintf(&smd5[i * 2], "%02x", sd->client_hash[i]); - - ShowNotice("Invalid client hash (account: %s, pass: %s, sent md5: %d, ip: %s)\n", sd->userid, sd->passwd, smd5, ip); - return 5; - } - } - - ShowNotice("Authentication accepted (account: %s, id: %d, ip: %s)\n", sd->userid, acc.account_id, ip); - - // update session data - sd->account_id = acc.account_id; - sd->login_id1 = rnd(); - sd->login_id2 = rnd(); - safestrncpy(sd->lastlogin, acc.lastlogin, sizeof(sd->lastlogin)); - sd->sex = acc.sex; - sd->group_id = acc.group_id; - - // update account data - timestamp2string(acc.lastlogin, sizeof(acc.lastlogin), time(NULL), "%Y-%m-%d %H:%M:%S"); - safestrncpy(acc.last_ip, ip, sizeof(acc.last_ip)); - acc.unban_time = 0; - acc.logincount++; - - accounts->save(accounts, &acc); - - if( sd->sex != 'S' && sd->account_id < START_ACCOUNT_NUM ) - ShowWarning("Account %s has account id %d! Account IDs must be over %d to work properly!\n", sd->userid, sd->account_id, START_ACCOUNT_NUM); - - return -1; // account OK +int mmo_auth(struct login_session_data *sd, bool isServer) +{ + struct mmo_account acc; + int len; + + char ip[16]; + ip2str(session[sd->fd]->client_addr, ip); + + // DNS Blacklist check + if (login_config.use_dnsbl) { + char r_ip[16]; + char ip_dnsbl[256]; + char *dnsbl_serv; + uint8 *sin_addr = (uint8 *)&session[sd->fd]->client_addr; + + sprintf(r_ip, "%u.%u.%u.%u", sin_addr[0], sin_addr[1], sin_addr[2], sin_addr[3]); + + for (dnsbl_serv = strtok(login_config.dnsbl_servs,","); dnsbl_serv != NULL; dnsbl_serv = strtok(NULL,",")) { + sprintf(ip_dnsbl, "%s.%s", r_ip, trim(dnsbl_serv)); + if (host2ip(ip_dnsbl)) { + ShowInfo("DNSBL: (%s) Blacklisted. User Kicked.\n", r_ip); + return 3; + } + } + + } + + //Client Version check + if (login_config.check_client_version && sd->version != login_config.client_version_to_connect) + return 5; + + len = strnlen(sd->userid, NAME_LENGTH); + + // Account creation with _M/_F + if (login_config.new_account_flag) { + if (len > 2 && strnlen(sd->passwd, NAME_LENGTH) > 0 && // valid user and password lengths + sd->passwdenc == 0 && // unencoded password + sd->userid[len-2] == '_' && memchr("FfMm", sd->userid[len-1], 4)) { // _M/_F suffix + int result; + + // remove the _M/_F suffix + len -= 2; + sd->userid[len] = '\0'; + + result = mmo_auth_new(sd->userid, sd->passwd, TOUPPER(sd->userid[len+1]), ip); + if (result != -1) + return result;// Failed to make account. [Skotlex]. + } + } + + if (!accounts->load_str(accounts, &acc, sd->userid)) { + ShowNotice("Unknown account (account: %s, received pass: %s, ip: %s)\n", sd->userid, sd->passwd, ip); + return 0; // 0 = Unregistered ID + } + + if (!check_password(sd->md5key, sd->passwdenc, sd->passwd, acc.pass)) { + ShowNotice("Invalid password (account: '%s', pass: '%s', received pass: '%s', ip: %s)\n", sd->userid, acc.pass, sd->passwd, ip); + return 1; // 1 = Incorrect Password + } + + if (acc.expiration_time != 0 && acc.expiration_time < time(NULL)) { + ShowNotice("Connection refused (account: %s, pass: %s, expired ID, ip: %s)\n", sd->userid, sd->passwd, ip); + return 2; // 2 = This ID is expired + } + + if (acc.unban_time != 0 && acc.unban_time > time(NULL)) { + char tmpstr[24]; + timestamp2string(tmpstr, sizeof(tmpstr), acc.unban_time, login_config.date_format); + ShowNotice("Connection refused (account: %s, pass: %s, banned until %s, ip: %s)\n", sd->userid, sd->passwd, tmpstr, ip); + return 6; // 6 = Your are Prohibited to log in until %s + } + + if (acc.state != 0) { + ShowNotice("Connection refused (account: %s, pass: %s, state: %d, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip); + return acc.state - 1; + } + + if (login_config.client_hash_check && !isServer) { + struct client_hash_node *node = login_config.client_hash_nodes; + bool match = false; + + if (!sd->has_client_hash) { + ShowNotice("Client doesn't sent client hash (account: %s, pass: %s, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip); + return 5; + } + + while (node) { + if (node->group_id <= acc.group_id && memcmp(node->hash, sd->client_hash, 16) == 0) { + match = true; + break; + } + + node = node->next; + } + + if (!match) { + char smd5[33]; + int i; + + for (i = 0; i < 16; i++) + sprintf(&smd5[i * 2], "%02x", sd->client_hash[i]); + + ShowNotice("Invalid client hash (account: %s, pass: %s, sent md5: %d, ip: %s)\n", sd->userid, sd->passwd, smd5, ip); + return 5; + } + } + + ShowNotice("Authentication accepted (account: %s, id: %d, ip: %s)\n", sd->userid, acc.account_id, ip); + + // update session data + sd->account_id = acc.account_id; + sd->login_id1 = rnd(); + sd->login_id2 = rnd(); + safestrncpy(sd->lastlogin, acc.lastlogin, sizeof(sd->lastlogin)); + sd->sex = acc.sex; + sd->group_id = acc.group_id; + + // update account data + timestamp2string(acc.lastlogin, sizeof(acc.lastlogin), time(NULL), "%Y-%m-%d %H:%M:%S"); + safestrncpy(acc.last_ip, ip, sizeof(acc.last_ip)); + acc.unban_time = 0; + acc.logincount++; + + accounts->save(accounts, &acc); + + if (sd->sex != 'S' && sd->account_id < START_ACCOUNT_NUM) + ShowWarning("Account %s has account id %d! Account IDs must be over %d to work properly!\n", sd->userid, sd->account_id, START_ACCOUNT_NUM); + + return -1; // account OK } -void login_auth_ok(struct login_session_data* sd) +void login_auth_ok(struct login_session_data *sd) { - int fd = sd->fd; - uint32 ip = session[fd]->client_addr; - - uint8 server_num, n; - uint32 subnet_char_ip; - struct auth_node* node; - int i; - - if( runflag != LOGINSERVER_ST_RUNNING ) - { - // players can only login while running - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1;// server closed - WFIFOSET(fd,3); - return; - } - - if( login_config.group_id_to_connect >= 0 && sd->group_id != login_config.group_id_to_connect ) { - ShowStatus("Connection refused: the required group id for connection is %d (account: %s, group: %d).\n", login_config.group_id_to_connect, sd->userid, sd->group_id); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - return; - } else if( login_config.min_group_id_to_connect >= 0 && login_config.group_id_to_connect == -1 && sd->group_id < login_config.min_group_id_to_connect ) { - ShowStatus("Connection refused: the minium group id required for connection is %d (account: %s, group: %d).\n", login_config.min_group_id_to_connect, sd->userid, sd->group_id); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - return; - } - - server_num = 0; - for( i = 0; i < ARRAYLENGTH(server); ++i ) - if( session_isActive(server[i].fd) ) - server_num++; - - if( server_num == 0 ) - {// if no char-server, don't send void list of servers, just disconnect the player with proper message - ShowStatus("Connection refused: there is no char-server online (account: %s).\n", sd->userid); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - return; - } - - { - struct online_login_data* data = (struct online_login_data*)idb_get(online_db, sd->account_id); - if( data ) - {// account is already marked as online! - if( data->char_server > -1 ) - {// Request char servers to kick this account out. [Skotlex] - uint8 buf[6]; - ShowNotice("User '%s' is already online - Rejected.\n", sd->userid); - WBUFW(buf,0) = 0x2734; - WBUFL(buf,2) = sd->account_id; - charif_sendallwos(-1, buf, 6); - if( data->waiting_disconnect == INVALID_TIMER ) - data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0); - - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 8; // 08 = Server still recognizes your last login - WFIFOSET(fd,3); - return; - } - else - if( data->char_server == -1 ) - {// client has authed but did not access char-server yet - // wipe previous session - idb_remove(auth_db, sd->account_id); - remove_online_user(sd->account_id); - data = NULL; - } - } - } - - login_log(ip, sd->userid, 100, "login ok"); - ShowStatus("Connection of the account '%s' accepted.\n", sd->userid); - - WFIFOHEAD(fd,47+32*server_num); - WFIFOW(fd,0) = 0x69; - WFIFOW(fd,2) = 47+32*server_num; - WFIFOL(fd,4) = sd->login_id1; - WFIFOL(fd,8) = sd->account_id; - WFIFOL(fd,12) = sd->login_id2; - WFIFOL(fd,16) = 0; // in old version, that was for ip (not more used) - //memcpy(WFIFOP(fd,20), sd->lastlogin, 24); // in old version, that was for name (not more used) - memset(WFIFOP(fd,20), 0, 24); - WFIFOW(fd,44) = 0; // unknown - WFIFOB(fd,46) = sex_str2num(sd->sex); - for( i = 0, n = 0; i < ARRAYLENGTH(server); ++i ) - { - if( !session_isValid(server[i].fd) ) - continue; - - subnet_char_ip = lan_subnetcheck(ip); // Advanced subnet check [LuzZza] - WFIFOL(fd,47+n*32) = htonl((subnet_char_ip) ? subnet_char_ip : server[i].ip); - WFIFOW(fd,47+n*32+4) = ntows(htons(server[i].port)); // [!] LE byte order here [!] - memcpy(WFIFOP(fd,47+n*32+6), server[i].name, 20); - WFIFOW(fd,47+n*32+26) = server[i].users; - WFIFOW(fd,47+n*32+28) = server[i].type; - WFIFOW(fd,47+n*32+30) = server[i].new_; - n++; - } - WFIFOSET(fd,47+32*server_num); - - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = sd->account_id; - node->login_id1 = sd->login_id1; - node->login_id2 = sd->login_id2; - node->sex = sd->sex; - node->ip = ip; - node->version = sd->version; - node->clienttype = sd->clienttype; - idb_put(auth_db, sd->account_id, node); - - { - struct online_login_data* data; - - // mark client as 'online' - data = add_online_user(-1, sd->account_id); - - // schedule deletion of this node - data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0); - } + int fd = sd->fd; + uint32 ip = session[fd]->client_addr; + + uint8 server_num, n; + uint32 subnet_char_ip; + struct auth_node *node; + int i; + + if (runflag != LOGINSERVER_ST_RUNNING) { + // players can only login while running + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1;// server closed + WFIFOSET(fd,3); + return; + } + + if (login_config.group_id_to_connect >= 0 && sd->group_id != login_config.group_id_to_connect) { + ShowStatus("Connection refused: the required group id for connection is %d (account: %s, group: %d).\n", login_config.group_id_to_connect, sd->userid, sd->group_id); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + return; + } else if (login_config.min_group_id_to_connect >= 0 && login_config.group_id_to_connect == -1 && sd->group_id < login_config.min_group_id_to_connect) { + ShowStatus("Connection refused: the minium group id required for connection is %d (account: %s, group: %d).\n", login_config.min_group_id_to_connect, sd->userid, sd->group_id); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + return; + } + + server_num = 0; + for (i = 0; i < ARRAYLENGTH(server); ++i) + if (session_isActive(server[i].fd)) + server_num++; + + if (server_num == 0) { + // if no char-server, don't send void list of servers, just disconnect the player with proper message + ShowStatus("Connection refused: there is no char-server online (account: %s).\n", sd->userid); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + return; + } + + { + struct online_login_data *data = (struct online_login_data *)idb_get(online_db, sd->account_id); + if (data) { + // account is already marked as online! + if (data->char_server > -1) { + // Request char servers to kick this account out. [Skotlex] + uint8 buf[6]; + ShowNotice("User '%s' is already online - Rejected.\n", sd->userid); + WBUFW(buf,0) = 0x2734; + WBUFL(buf,2) = sd->account_id; + charif_sendallwos(-1, buf, 6); + if (data->waiting_disconnect == INVALID_TIMER) + data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0); + + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 8; // 08 = Server still recognizes your last login + WFIFOSET(fd,3); + return; + } else if (data->char_server == -1) { + // client has authed but did not access char-server yet + // wipe previous session + idb_remove(auth_db, sd->account_id); + remove_online_user(sd->account_id); + data = NULL; + } + } + } + + login_log(ip, sd->userid, 100, "login ok"); + ShowStatus("Connection of the account '%s' accepted.\n", sd->userid); + + WFIFOHEAD(fd,47+32*server_num); + WFIFOW(fd,0) = 0x69; + WFIFOW(fd,2) = 47+32*server_num; + WFIFOL(fd,4) = sd->login_id1; + WFIFOL(fd,8) = sd->account_id; + WFIFOL(fd,12) = sd->login_id2; + WFIFOL(fd,16) = 0; // in old version, that was for ip (not more used) + //memcpy(WFIFOP(fd,20), sd->lastlogin, 24); // in old version, that was for name (not more used) + memset(WFIFOP(fd,20), 0, 24); + WFIFOW(fd,44) = 0; // unknown + WFIFOB(fd,46) = sex_str2num(sd->sex); + for (i = 0, n = 0; i < ARRAYLENGTH(server); ++i) { + if (!session_isValid(server[i].fd)) + continue; + + subnet_char_ip = lan_subnetcheck(ip); // Advanced subnet check [LuzZza] + WFIFOL(fd,47+n*32) = htonl((subnet_char_ip) ? subnet_char_ip : server[i].ip); + WFIFOW(fd,47+n*32+4) = ntows(htons(server[i].port)); // [!] LE byte order here [!] + memcpy(WFIFOP(fd,47+n*32+6), server[i].name, 20); + WFIFOW(fd,47+n*32+26) = server[i].users; + WFIFOW(fd,47+n*32+28) = server[i].type; + WFIFOW(fd,47+n*32+30) = server[i].new_; + n++; + } + WFIFOSET(fd,47+32*server_num); + + // create temporary auth entry + CREATE(node, struct auth_node, 1); + node->account_id = sd->account_id; + node->login_id1 = sd->login_id1; + node->login_id2 = sd->login_id2; + node->sex = sd->sex; + node->ip = ip; + node->version = sd->version; + node->clienttype = sd->clienttype; + idb_put(auth_db, sd->account_id, node); + + { + struct online_login_data *data; + + // mark client as 'online' + data = add_online_user(-1, sd->account_id); + + // schedule deletion of this node + data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0); + } } -void login_auth_failed(struct login_session_data* sd, int result) +void login_auth_failed(struct login_session_data *sd, int result) { - int fd = sd->fd; - uint32 ip = session[fd]->client_addr; - - if (login_config.log_login) - { - const char* error; - switch( result ) { - case 0: error = "Unregistered ID."; break; // 0 = Unregistered ID - case 1: error = "Incorrect Password."; break; // 1 = Incorrect Password - case 2: error = "Account Expired."; break; // 2 = This ID is expired - case 3: error = "Rejected from server."; break; // 3 = Rejected from Server - case 4: error = "Blocked by GM."; break; // 4 = You have been blocked by the GM Team - case 5: error = "Not latest game EXE."; break; // 5 = Your Game's EXE file is not the latest version - case 6: error = "Banned."; break; // 6 = Your are Prohibited to log in until %s - case 7: error = "Server Over-population."; break; // 7 = Server is jammed due to over populated - case 8: error = "Account limit from company"; break; // 8 = No more accounts may be connected from this company - case 9: error = "Ban by DBA"; break; // 9 = MSI_REFUSE_BAN_BY_DBA - case 10: error = "Email not confirmed"; break; // 10 = MSI_REFUSE_EMAIL_NOT_CONFIRMED - case 11: error = "Ban by GM"; break; // 11 = MSI_REFUSE_BAN_BY_GM - case 12: error = "Working in DB"; break; // 12 = MSI_REFUSE_TEMP_BAN_FOR_DBWORK - case 13: error = "Self Lock"; break; // 13 = MSI_REFUSE_SELF_LOCK - case 14: error = "Not Permitted Group"; break; // 14 = MSI_REFUSE_NOT_PERMITTED_GROUP - case 15: error = "Not Permitted Group"; break; // 15 = MSI_REFUSE_NOT_PERMITTED_GROUP - case 99: error = "Account gone."; break; // 99 = This ID has been totally erased - case 100: error = "Login info remains."; break; // 100 = Login information remains at %s - case 101: error = "Hacking investigation."; break; // 101 = Account has been locked for a hacking investigation. Please contact the GM Team for more information - case 102: error = "Bug investigation."; break; // 102 = This account has been temporarily prohibited from login due to a bug-related investigation - case 103: error = "Deleting char."; break; // 103 = This character is being deleted. Login is temporarily unavailable for the time being - case 104: error = "Deleting spouse char."; break; // 104 = This character is being deleted. Login is temporarily unavailable for the time being - default : error = "Unknown Error."; break; - } - - login_log(ip, sd->userid, result, error); - } - - if( result == 1 && login_config.dynamic_pass_failure_ban ) - ipban_log(ip); // log failed password attempt - - WFIFOHEAD(fd,23); - WFIFOW(fd,0) = 0x6a; - WFIFOB(fd,2) = (uint8)result; - if( result != 6 ) - memset(WFIFOP(fd,3), '\0', 20); - else - {// 6 = Your are Prohibited to log in until %s - struct mmo_account acc; - time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0; - timestamp2string((char*)WFIFOP(fd,3), 20, unban_time, login_config.date_format); - } - WFIFOSET(fd,23); + int fd = sd->fd; + uint32 ip = session[fd]->client_addr; + + if (login_config.log_login) { + const char *error; + switch (result) { + case 0: + error = "Unregistered ID."; + break; // 0 = Unregistered ID + case 1: + error = "Incorrect Password."; + break; // 1 = Incorrect Password + case 2: + error = "Account Expired."; + break; // 2 = This ID is expired + case 3: + error = "Rejected from server."; + break; // 3 = Rejected from Server + case 4: + error = "Blocked by GM."; + break; // 4 = You have been blocked by the GM Team + case 5: + error = "Not latest game EXE."; + break; // 5 = Your Game's EXE file is not the latest version + case 6: + error = "Banned."; + break; // 6 = Your are Prohibited to log in until %s + case 7: + error = "Server Over-population."; + break; // 7 = Server is jammed due to over populated + case 8: + error = "Account limit from company"; + break; // 8 = No more accounts may be connected from this company + case 9: + error = "Ban by DBA"; + break; // 9 = MSI_REFUSE_BAN_BY_DBA + case 10: + error = "Email not confirmed"; + break; // 10 = MSI_REFUSE_EMAIL_NOT_CONFIRMED + case 11: + error = "Ban by GM"; + break; // 11 = MSI_REFUSE_BAN_BY_GM + case 12: + error = "Working in DB"; + break; // 12 = MSI_REFUSE_TEMP_BAN_FOR_DBWORK + case 13: + error = "Self Lock"; + break; // 13 = MSI_REFUSE_SELF_LOCK + case 14: + error = "Not Permitted Group"; + break; // 14 = MSI_REFUSE_NOT_PERMITTED_GROUP + case 15: + error = "Not Permitted Group"; + break; // 15 = MSI_REFUSE_NOT_PERMITTED_GROUP + case 99: + error = "Account gone."; + break; // 99 = This ID has been totally erased + case 100: + error = "Login info remains."; + break; // 100 = Login information remains at %s + case 101: + error = "Hacking investigation."; + break; // 101 = Account has been locked for a hacking investigation. Please contact the GM Team for more information + case 102: + error = "Bug investigation."; + break; // 102 = This account has been temporarily prohibited from login due to a bug-related investigation + case 103: + error = "Deleting char."; + break; // 103 = This character is being deleted. Login is temporarily unavailable for the time being + case 104: + error = "Deleting spouse char."; + break; // 104 = This character is being deleted. Login is temporarily unavailable for the time being + default : + error = "Unknown Error."; + break; + } + + login_log(ip, sd->userid, result, error); + } + + if (result == 1 && login_config.dynamic_pass_failure_ban) + ipban_log(ip); // log failed password attempt + + WFIFOHEAD(fd,23); + WFIFOW(fd,0) = 0x6a; + WFIFOB(fd,2) = (uint8)result; + if (result != 6) + memset(WFIFOP(fd,3), '\0', 20); + else { + // 6 = Your are Prohibited to log in until %s + struct mmo_account acc; + time_t unban_time = (accounts->load_str(accounts, &acc, sd->userid)) ? acc.unban_time : 0; + timestamp2string((char *)WFIFOP(fd,3), 20, unban_time, login_config.date_format); + } + WFIFOSET(fd,23); } @@ -1298,428 +1294,400 @@ void login_auth_failed(struct login_session_data* sd, int result) //---------------------------------------------------------------------------------------- int parse_login(int fd) { - struct login_session_data* sd = (struct login_session_data*)session[fd]->session_data; - int result; - - char ip[16]; - uint32 ipl = session[fd]->client_addr; - ip2str(ipl, ip); - - if( session[fd]->flag.eof ) - { - ShowInfo("Closed connection from '"CL_WHITE"%s"CL_RESET"'.\n", ip); - do_close(fd); - return 0; - } - - if( sd == NULL ) - { - // Perform ip-ban check - if( login_config.ipban && ipban_check(ipl) ) - { - ShowStatus("Connection refused: IP isn't authorised (deny/allow, ip: %s).\n", ip); - login_log(ipl, "unknown", -3, "ip banned"); - WFIFOHEAD(fd,23); - WFIFOW(fd,0) = 0x6a; - WFIFOB(fd,2) = 3; // 3 = Rejected from Server - WFIFOSET(fd,23); - set_eof(fd); - return 0; - } - - // create a session for this new connection - CREATE(session[fd]->session_data, struct login_session_data, 1); - sd = (struct login_session_data*)session[fd]->session_data; - sd->fd = fd; - } - - while( RFIFOREST(fd) >= 2 ) - { - uint16 command = RFIFOW(fd,0); - - switch( command ) - { - - case 0x0200: // New alive packet: structure: 0x200 .24B. used to verify if client is always alive. - if (RFIFOREST(fd) < 26) - return 0; - RFIFOSKIP(fd,26); - break; - - // client md5 hash (binary) - case 0x0204: // S 0204 .16B (kRO 2004-05-31aSakexe langtype 0 and 6) - if (RFIFOREST(fd) < 18) - return 0; - - sd->has_client_hash = 1; - memcpy(sd->client_hash, RFIFOP(fd, 2), 16); - - RFIFOSKIP(fd,18); - break; - - // request client login (raw password) - case 0x0064: // S 0064 .L .24B .24B .B - case 0x0277: // S 0277 .L .24B .24B .B .16B .13B - case 0x02b0: // S 02b0 .L .24B .24B .B .16B .13B .B - // request client login (md5-hashed password) - case 0x01dd: // S 01dd .L .24B .16B .B - case 0x01fa: // S 01fa .L .24B .16B .B .B(index of the connection in the clientinfo file (+10 if the command-line contains "pc")) - case 0x027c: // S 027c .L .24B .16B .B .13B(junk) - case 0x0825: // S 0825 .W .L .B .24B .27B .17B .15B .(packetsize - 0x5C)B - { - size_t packet_len = RFIFOREST(fd); - - if( (command == 0x0064 && packet_len < 55) - || (command == 0x0277 && packet_len < 84) - || (command == 0x02b0 && packet_len < 85) - || (command == 0x01dd && packet_len < 47) - || (command == 0x01fa && packet_len < 48) - || (command == 0x027c && packet_len < 60) - || (command == 0x0825 && (packet_len < 4 || packet_len < RFIFOW(fd, 2))) ) - return 0; - } - { - uint32 version; - char username[NAME_LENGTH]; - char password[NAME_LENGTH]; - unsigned char passhash[16]; - uint8 clienttype; - bool israwpass = (command==0x0064 || command==0x0277 || command==0x02b0 || command == 0x0825); - - // Shinryo: For the time being, just use token as password. - if(command == 0x0825) - { - char *accname = (char *)RFIFOP(fd, 9); - char *token = (char *)RFIFOP(fd, 0x5C); - size_t uAccLen = strlen(accname); - size_t uTokenLen = RFIFOREST(fd) - 0x5C; - - version = RFIFOL(fd,4); - - if(uAccLen > NAME_LENGTH - 1 || uAccLen <= 0 || uTokenLen > NAME_LENGTH - 1 || uTokenLen <= 0) - { - login_auth_failed(sd, 3); - return 0; - } - - safestrncpy(username, accname, uAccLen + 1); - safestrncpy(password, token, uTokenLen + 1); - clienttype = RFIFOB(fd, 8); - } - else - { - version = RFIFOL(fd,2); - safestrncpy(username, (const char*)RFIFOP(fd,6), NAME_LENGTH); - if( israwpass ) - { - safestrncpy(password, (const char*)RFIFOP(fd,30), NAME_LENGTH); - clienttype = RFIFOB(fd,54); - } - else - { - memcpy(passhash, RFIFOP(fd,30), 16); - clienttype = RFIFOB(fd,46); - } - } - RFIFOSKIP(fd,RFIFOREST(fd)); // assume no other packet was sent - - sd->clienttype = clienttype; - sd->version = version; - safestrncpy(sd->userid, username, NAME_LENGTH); - if( israwpass ) - { - ShowStatus("Request for connection of %s (ip: %s).\n", sd->userid, ip); - safestrncpy(sd->passwd, password, NAME_LENGTH); - if( login_config.use_md5_passwds ) - MD5_String(sd->passwd, sd->passwd); - sd->passwdenc = 0; - } - else - { - ShowStatus("Request for connection (passwdenc mode) of %s (ip: %s).\n", sd->userid, ip); - bin2hex(sd->passwd, passhash, 16); // raw binary data here! - sd->passwdenc = PASSWORDENC; - } - - if( sd->passwdenc != 0 && login_config.use_md5_passwds ) - { - login_auth_failed(sd, 3); // send "rejected from server" - return 0; - } - - result = mmo_auth(sd, false); - - if( result == -1 ) - login_auth_ok(sd); - else - login_auth_failed(sd, result); - } - break; - - case 0x01db: // Sending request of the coding key - RFIFOSKIP(fd,2); - { - memset(sd->md5key, '\0', sizeof(sd->md5key)); - sd->md5keylen = (uint16)(12 + rnd() % 4); - MD5_Salt(sd->md5keylen, sd->md5key); - - WFIFOHEAD(fd,4 + sd->md5keylen); - WFIFOW(fd,0) = 0x01dc; - WFIFOW(fd,2) = 4 + sd->md5keylen; - memcpy(WFIFOP(fd,4), sd->md5key, sd->md5keylen); - WFIFOSET(fd,WFIFOW(fd,2)); - } - break; - - case 0x2710: // Connection request of a char-server - if (RFIFOREST(fd) < 86) - return 0; - { - char server_name[20]; - char message[256]; - uint32 server_ip; - uint16 server_port; - uint16 type; - uint16 new_; - - safestrncpy(sd->userid, (char*)RFIFOP(fd,2), NAME_LENGTH); - safestrncpy(sd->passwd, (char*)RFIFOP(fd,26), NAME_LENGTH); - if( login_config.use_md5_passwds ) - MD5_String(sd->passwd, sd->passwd); - sd->passwdenc = 0; - sd->version = login_config.client_version_to_connect; // hack to skip version check - server_ip = ntohl(RFIFOL(fd,54)); - server_port = ntohs(RFIFOW(fd,58)); - safestrncpy(server_name, (char*)RFIFOP(fd,60), 20); - type = RFIFOW(fd,82); - new_ = RFIFOW(fd,84); - RFIFOSKIP(fd,86); - - ShowInfo("Connection request of the char-server '%s' @ %u.%u.%u.%u:%u (account: '%s', pass: '%s', ip: '%s')\n", server_name, CONVIP(server_ip), server_port, sd->userid, sd->passwd, ip); - sprintf(message, "charserver - %s@%u.%u.%u.%u:%u", server_name, CONVIP(server_ip), server_port); - login_log(session[fd]->client_addr, sd->userid, 100, message); - - result = mmo_auth(sd, true); - if( runflag == LOGINSERVER_ST_RUNNING && - result == -1 && - sd->sex == 'S' && - sd->account_id >= 0 && sd->account_id < ARRAYLENGTH(server) && - !session_isValid(server[sd->account_id].fd) ) - { - ShowStatus("Connection of the char-server '%s' accepted.\n", server_name); - safestrncpy(server[sd->account_id].name, server_name, sizeof(server[sd->account_id].name)); - server[sd->account_id].fd = fd; - server[sd->account_id].ip = server_ip; - server[sd->account_id].port = server_port; - server[sd->account_id].users = 0; - server[sd->account_id].type = type; - server[sd->account_id].new_ = new_; - - session[fd]->func_parse = parse_fromchar; - session[fd]->flag.server = 1; - realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); - - // send connection success - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x2711; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - } - else - { - ShowNotice("Connection of the char-server '%s' REFUSED.\n", server_name); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x2711; - WFIFOB(fd,2) = 3; - WFIFOSET(fd,3); - } - } - return 0; // processing will continue elsewhere - - default: - ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command); - set_eof(fd); - return 0; - } - } - - return 0; + struct login_session_data *sd = (struct login_session_data *)session[fd]->session_data; + int result; + + char ip[16]; + uint32 ipl = session[fd]->client_addr; + ip2str(ipl, ip); + + if (session[fd]->flag.eof) { + ShowInfo("Closed connection from '"CL_WHITE"%s"CL_RESET"'.\n", ip); + do_close(fd); + return 0; + } + + if (sd == NULL) { + // Perform ip-ban check + if (login_config.ipban && ipban_check(ipl)) { + ShowStatus("Connection refused: IP isn't authorised (deny/allow, ip: %s).\n", ip); + login_log(ipl, "unknown", -3, "ip banned"); + WFIFOHEAD(fd,23); + WFIFOW(fd,0) = 0x6a; + WFIFOB(fd,2) = 3; // 3 = Rejected from Server + WFIFOSET(fd,23); + set_eof(fd); + return 0; + } + + // create a session for this new connection + CREATE(session[fd]->session_data, struct login_session_data, 1); + sd = (struct login_session_data *)session[fd]->session_data; + sd->fd = fd; + } + + while (RFIFOREST(fd) >= 2) { + uint16 command = RFIFOW(fd,0); + + switch (command) { + + case 0x0200: // New alive packet: structure: 0x200 .24B. used to verify if client is always alive. + if (RFIFOREST(fd) < 26) + return 0; + RFIFOSKIP(fd,26); + break; + + // client md5 hash (binary) + case 0x0204: // S 0204 .16B (kRO 2004-05-31aSakexe langtype 0 and 6) + if (RFIFOREST(fd) < 18) + return 0; + + sd->has_client_hash = 1; + memcpy(sd->client_hash, RFIFOP(fd, 2), 16); + + RFIFOSKIP(fd,18); + break; + + // request client login (raw password) + case 0x0064: // S 0064 .L .24B .24B .B + case 0x0277: // S 0277 .L .24B .24B .B .16B .13B + case 0x02b0: // S 02b0 .L .24B .24B .B .16B .13B .B + // request client login (md5-hashed password) + case 0x01dd: // S 01dd .L .24B .16B .B + case 0x01fa: // S 01fa .L .24B .16B .B .B(index of the connection in the clientinfo file (+10 if the command-line contains "pc")) + case 0x027c: // S 027c .L .24B .16B .B .13B(junk) + case 0x0825: { // S 0825 .W .L .B .24B .27B .17B .15B .(packetsize - 0x5C)B + size_t packet_len = RFIFOREST(fd); + + if ((command == 0x0064 && packet_len < 55) + || (command == 0x0277 && packet_len < 84) + || (command == 0x02b0 && packet_len < 85) + || (command == 0x01dd && packet_len < 47) + || (command == 0x01fa && packet_len < 48) + || (command == 0x027c && packet_len < 60) + || (command == 0x0825 && (packet_len < 4 || packet_len < RFIFOW(fd, 2)))) + return 0; + } + { + uint32 version; + char username[NAME_LENGTH]; + char password[NAME_LENGTH]; + unsigned char passhash[16]; + uint8 clienttype; + bool israwpass = (command==0x0064 || command==0x0277 || command==0x02b0 || command == 0x0825); + + // Shinryo: For the time being, just use token as password. + if (command == 0x0825) { + char *accname = (char *)RFIFOP(fd, 9); + char *token = (char *)RFIFOP(fd, 0x5C); + size_t uAccLen = strlen(accname); + size_t uTokenLen = RFIFOREST(fd) - 0x5C; + + version = RFIFOL(fd,4); + + if (uAccLen > NAME_LENGTH - 1 || uAccLen <= 0 || uTokenLen > NAME_LENGTH - 1 || uTokenLen <= 0) { + login_auth_failed(sd, 3); + return 0; + } + + safestrncpy(username, accname, uAccLen + 1); + safestrncpy(password, token, uTokenLen + 1); + clienttype = RFIFOB(fd, 8); + } else { + version = RFIFOL(fd,2); + safestrncpy(username, (const char *)RFIFOP(fd,6), NAME_LENGTH); + if (israwpass) { + safestrncpy(password, (const char *)RFIFOP(fd,30), NAME_LENGTH); + clienttype = RFIFOB(fd,54); + } else { + memcpy(passhash, RFIFOP(fd,30), 16); + clienttype = RFIFOB(fd,46); + } + } + RFIFOSKIP(fd,RFIFOREST(fd)); // assume no other packet was sent + + sd->clienttype = clienttype; + sd->version = version; + safestrncpy(sd->userid, username, NAME_LENGTH); + if (israwpass) { + ShowStatus("Request for connection of %s (ip: %s).\n", sd->userid, ip); + safestrncpy(sd->passwd, password, NAME_LENGTH); + if (login_config.use_md5_passwds) + MD5_String(sd->passwd, sd->passwd); + sd->passwdenc = 0; + } else { + ShowStatus("Request for connection (passwdenc mode) of %s (ip: %s).\n", sd->userid, ip); + bin2hex(sd->passwd, passhash, 16); // raw binary data here! + sd->passwdenc = PASSWORDENC; + } + + if (sd->passwdenc != 0 && login_config.use_md5_passwds) { + login_auth_failed(sd, 3); // send "rejected from server" + return 0; + } + + result = mmo_auth(sd, false); + + if (result == -1) + login_auth_ok(sd); + else + login_auth_failed(sd, result); + } + break; + + case 0x01db: // Sending request of the coding key + RFIFOSKIP(fd,2); + { + memset(sd->md5key, '\0', sizeof(sd->md5key)); + sd->md5keylen = (uint16)(12 + rnd() % 4); + MD5_Salt(sd->md5keylen, sd->md5key); + + WFIFOHEAD(fd,4 + sd->md5keylen); + WFIFOW(fd,0) = 0x01dc; + WFIFOW(fd,2) = 4 + sd->md5keylen; + memcpy(WFIFOP(fd,4), sd->md5key, sd->md5keylen); + WFIFOSET(fd,WFIFOW(fd,2)); + } + break; + + case 0x2710: // Connection request of a char-server + if (RFIFOREST(fd) < 86) + return 0; + { + char server_name[20]; + char message[256]; + uint32 server_ip; + uint16 server_port; + uint16 type; + uint16 new_; + + safestrncpy(sd->userid, (char *)RFIFOP(fd,2), NAME_LENGTH); + safestrncpy(sd->passwd, (char *)RFIFOP(fd,26), NAME_LENGTH); + if (login_config.use_md5_passwds) + MD5_String(sd->passwd, sd->passwd); + sd->passwdenc = 0; + sd->version = login_config.client_version_to_connect; // hack to skip version check + server_ip = ntohl(RFIFOL(fd,54)); + server_port = ntohs(RFIFOW(fd,58)); + safestrncpy(server_name, (char *)RFIFOP(fd,60), 20); + type = RFIFOW(fd,82); + new_ = RFIFOW(fd,84); + RFIFOSKIP(fd,86); + + ShowInfo("Connection request of the char-server '%s' @ %u.%u.%u.%u:%u (account: '%s', pass: '%s', ip: '%s')\n", server_name, CONVIP(server_ip), server_port, sd->userid, sd->passwd, ip); + sprintf(message, "charserver - %s@%u.%u.%u.%u:%u", server_name, CONVIP(server_ip), server_port); + login_log(session[fd]->client_addr, sd->userid, 100, message); + + result = mmo_auth(sd, true); + if (runflag == LOGINSERVER_ST_RUNNING && + result == -1 && + sd->sex == 'S' && + sd->account_id >= 0 && sd->account_id < ARRAYLENGTH(server) && + !session_isValid(server[sd->account_id].fd)) { + ShowStatus("Connection of the char-server '%s' accepted.\n", server_name); + safestrncpy(server[sd->account_id].name, server_name, sizeof(server[sd->account_id].name)); + server[sd->account_id].fd = fd; + server[sd->account_id].ip = server_ip; + server[sd->account_id].port = server_port; + server[sd->account_id].users = 0; + server[sd->account_id].type = type; + server[sd->account_id].new_ = new_; + + session[fd]->func_parse = parse_fromchar; + session[fd]->flag.server = 1; + realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); + + // send connection success + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x2711; + WFIFOB(fd,2) = 0; + WFIFOSET(fd,3); + } else { + ShowNotice("Connection of the char-server '%s' REFUSED.\n", server_name); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x2711; + WFIFOB(fd,2) = 3; + WFIFOSET(fd,3); + } + } + return 0; // processing will continue elsewhere + + default: + ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command); + set_eof(fd); + return 0; + } + } + + return 0; } void login_set_defaults() { - login_config.login_ip = INADDR_ANY; - login_config.login_port = 6900; - login_config.ipban_cleanup_interval = 60; - login_config.ip_sync_interval = 0; - login_config.log_login = true; - safestrncpy(login_config.date_format, "%Y-%m-%d %H:%M:%S", sizeof(login_config.date_format)); - login_config.console = false; - login_config.new_account_flag = true; - login_config.new_acc_length_limit = true; - login_config.use_md5_passwds = false; - login_config.group_id_to_connect = -1; - login_config.min_group_id_to_connect = -1; - login_config.check_client_version = false; - login_config.client_version_to_connect = 20; - - login_config.ipban = true; - login_config.dynamic_pass_failure_ban = true; - login_config.dynamic_pass_failure_ban_interval = 5; - login_config.dynamic_pass_failure_ban_limit = 7; - login_config.dynamic_pass_failure_ban_duration = 5; - login_config.use_dnsbl = false; - safestrncpy(login_config.dnsbl_servs, "", sizeof(login_config.dnsbl_servs)); - safestrncpy(login_config.account_engine, "auto", sizeof(login_config.account_engine)); - - login_config.client_hash_check = 0; - login_config.client_hash_nodes = NULL; + login_config.login_ip = INADDR_ANY; + login_config.login_port = 6900; + login_config.ipban_cleanup_interval = 60; + login_config.ip_sync_interval = 0; + login_config.log_login = true; + safestrncpy(login_config.date_format, "%Y-%m-%d %H:%M:%S", sizeof(login_config.date_format)); + login_config.console = false; + login_config.new_account_flag = true; + login_config.new_acc_length_limit = true; + login_config.use_md5_passwds = false; + login_config.group_id_to_connect = -1; + login_config.min_group_id_to_connect = -1; + login_config.check_client_version = false; + login_config.client_version_to_connect = 20; + + login_config.ipban = true; + login_config.dynamic_pass_failure_ban = true; + login_config.dynamic_pass_failure_ban_interval = 5; + login_config.dynamic_pass_failure_ban_limit = 7; + login_config.dynamic_pass_failure_ban_duration = 5; + login_config.use_dnsbl = false; + safestrncpy(login_config.dnsbl_servs, "", sizeof(login_config.dnsbl_servs)); + safestrncpy(login_config.account_engine, "auto", sizeof(login_config.account_engine)); + + login_config.client_hash_check = 0; + login_config.client_hash_nodes = NULL; } //----------------------------------- // Reading main configuration file //----------------------------------- -int login_config_read(const char* cfgName) +int login_config_read(const char *cfgName) { - char line[1024], w1[1024], w2[1024]; - FILE* fp = fopen(cfgName, "r"); - if (fp == NULL) { - ShowError("Configuration file (%s) not found.\n", cfgName); - return 1; - } - while(fgets(line, sizeof(line), fp)) { - if (line[0] == '/' && line[1] == '/') - continue; - - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) < 2) - continue; - - if(!strcmpi(w1,"timestamp_format")) - strncpy(timestamp_format, w2, 20); - else if(!strcmpi(w1,"stdout_with_ansisequence")) - stdout_with_ansisequence = config_switch(w2); - else if(!strcmpi(w1,"console_silent")) { - msg_silent = atoi(w2); - if( msg_silent ) /* only bother if we actually have this enabled */ - ShowInfo("Console Silent Setting: %d\n", atoi(w2)); - } - else if( !strcmpi(w1, "bind_ip") ) { - char ip_str[16]; - login_config.login_ip = host2ip(w2); - if( login_config.login_ip ) - ShowStatus("Login server binding IP address : %s -> %s\n", w2, ip2str(login_config.login_ip, ip_str)); - } - else if( !strcmpi(w1, "login_port") ) { - login_config.login_port = (uint16)atoi(w2); - } - else if(!strcmpi(w1, "log_login")) - login_config.log_login = (bool)config_switch(w2); - - else if(!strcmpi(w1, "new_account")) - login_config.new_account_flag = (bool)config_switch(w2); - else if(!strcmpi(w1, "new_acc_length_limit")) - login_config.new_acc_length_limit = (bool)config_switch(w2); - else if(!strcmpi(w1, "start_limited_time")) - login_config.start_limited_time = atoi(w2); - else if(!strcmpi(w1, "check_client_version")) - login_config.check_client_version = (bool)config_switch(w2); - else if(!strcmpi(w1, "client_version_to_connect")) - login_config.client_version_to_connect = strtoul(w2, NULL, 10); - else if(!strcmpi(w1, "use_MD5_passwords")) - login_config.use_md5_passwds = (bool)config_switch(w2); - else if(!strcmpi(w1, "group_id_to_connect")) - login_config.group_id_to_connect = atoi(w2); - else if(!strcmpi(w1, "min_group_id_to_connect")) - login_config.min_group_id_to_connect = atoi(w2); - else if(!strcmpi(w1, "date_format")) - safestrncpy(login_config.date_format, w2, sizeof(login_config.date_format)); - else if(!strcmpi(w1, "console")) - login_config.console = (bool)config_switch(w2); - else if(!strcmpi(w1, "allowed_regs")) //account flood protection system - allowed_regs = atoi(w2); - else if(!strcmpi(w1, "time_allowed")) - time_allowed = atoi(w2); - else if(!strcmpi(w1, "use_dnsbl")) - login_config.use_dnsbl = (bool)config_switch(w2); - else if(!strcmpi(w1, "dnsbl_servers")) - safestrncpy(login_config.dnsbl_servs, w2, sizeof(login_config.dnsbl_servs)); - else if(!strcmpi(w1, "ipban_cleanup_interval")) - login_config.ipban_cleanup_interval = (unsigned int)atoi(w2); - else if(!strcmpi(w1, "ip_sync_interval")) - login_config.ip_sync_interval = (unsigned int)1000*60*atoi(w2); //w2 comes in minutes. - else if(!strcmpi(w1, "client_hash_check")) - login_config.client_hash_check = config_switch(w2); - else if(!strcmpi(w1, "client_hash")) { - int group = 0; - char md5[33]; - int i; - - if (sscanf(w2, "%d, %32s", &group, md5) == 2) { - struct client_hash_node *nnode; - CREATE(nnode, struct client_hash_node, 1); - - for (i = 0; i < 32; i += 2) { - char buf[3]; - unsigned int byte; - - memcpy(buf, &md5[i], 2); - buf[2] = 0; - - sscanf(buf, "%x", &byte); - nnode->hash[i / 2] = (uint8)(byte & 0xFF); - } - - nnode->group_id = group; - nnode->next = login_config.client_hash_nodes; - - login_config.client_hash_nodes = nnode; - } - } - else if(!strcmpi(w1, "import")) - login_config_read(w2); - else - if(!strcmpi(w1, "account.engine")) - safestrncpy(login_config.account_engine, w2, sizeof(login_config.account_engine)); - else - {// try the account engines - int i; - for( i = 0; account_engines[i].constructor; ++i ) - { - AccountDB* db = account_engines[i].db; - if( db && db->set_property(db, w1, w2) ) - break; - } - // try others - ipban_config_read(w1, w2); - loginlog_config_read(w1, w2); - } - } - fclose(fp); - ShowInfo("Finished reading %s.\n", cfgName); - return 0; + char line[1024], w1[1024], w2[1024]; + FILE *fp = fopen(cfgName, "r"); + if (fp == NULL) { + ShowError("Configuration file (%s) not found.\n", cfgName); + return 1; + } + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') + continue; + + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) < 2) + continue; + + if (!strcmpi(w1,"timestamp_format")) + strncpy(timestamp_format, w2, 20); + else if (!strcmpi(w1,"stdout_with_ansisequence")) + stdout_with_ansisequence = config_switch(w2); + else if (!strcmpi(w1,"console_silent")) { + msg_silent = atoi(w2); + if (msg_silent) /* only bother if we actually have this enabled */ + ShowInfo("Console Silent Setting: %d\n", atoi(w2)); + } else if (!strcmpi(w1, "bind_ip")) { + char ip_str[16]; + login_config.login_ip = host2ip(w2); + if (login_config.login_ip) + ShowStatus("Login server binding IP address : %s -> %s\n", w2, ip2str(login_config.login_ip, ip_str)); + } else if (!strcmpi(w1, "login_port")) { + login_config.login_port = (uint16)atoi(w2); + } else if (!strcmpi(w1, "log_login")) + login_config.log_login = (bool)config_switch(w2); + + else if (!strcmpi(w1, "new_account")) + login_config.new_account_flag = (bool)config_switch(w2); + else if (!strcmpi(w1, "new_acc_length_limit")) + login_config.new_acc_length_limit = (bool)config_switch(w2); + else if (!strcmpi(w1, "start_limited_time")) + login_config.start_limited_time = atoi(w2); + else if (!strcmpi(w1, "check_client_version")) + login_config.check_client_version = (bool)config_switch(w2); + else if (!strcmpi(w1, "client_version_to_connect")) + login_config.client_version_to_connect = strtoul(w2, NULL, 10); + else if (!strcmpi(w1, "use_MD5_passwords")) + login_config.use_md5_passwds = (bool)config_switch(w2); + else if (!strcmpi(w1, "group_id_to_connect")) + login_config.group_id_to_connect = atoi(w2); + else if (!strcmpi(w1, "min_group_id_to_connect")) + login_config.min_group_id_to_connect = atoi(w2); + else if (!strcmpi(w1, "date_format")) + safestrncpy(login_config.date_format, w2, sizeof(login_config.date_format)); + else if (!strcmpi(w1, "console")) + login_config.console = (bool)config_switch(w2); + else if (!strcmpi(w1, "allowed_regs")) //account flood protection system + allowed_regs = atoi(w2); + else if (!strcmpi(w1, "time_allowed")) + time_allowed = atoi(w2); + else if (!strcmpi(w1, "use_dnsbl")) + login_config.use_dnsbl = (bool)config_switch(w2); + else if (!strcmpi(w1, "dnsbl_servers")) + safestrncpy(login_config.dnsbl_servs, w2, sizeof(login_config.dnsbl_servs)); + else if (!strcmpi(w1, "ipban_cleanup_interval")) + login_config.ipban_cleanup_interval = (unsigned int)atoi(w2); + else if (!strcmpi(w1, "ip_sync_interval")) + login_config.ip_sync_interval = (unsigned int)1000*60*atoi(w2); //w2 comes in minutes. + else if (!strcmpi(w1, "client_hash_check")) + login_config.client_hash_check = config_switch(w2); + else if (!strcmpi(w1, "client_hash")) { + int group = 0; + char md5[33]; + int i; + + if (sscanf(w2, "%d, %32s", &group, md5) == 2) { + struct client_hash_node *nnode; + CREATE(nnode, struct client_hash_node, 1); + + for (i = 0; i < 32; i += 2) { + char buf[3]; + unsigned int byte; + + memcpy(buf, &md5[i], 2); + buf[2] = 0; + + sscanf(buf, "%x", &byte); + nnode->hash[i / 2] = (uint8)(byte & 0xFF); + } + + nnode->group_id = group; + nnode->next = login_config.client_hash_nodes; + + login_config.client_hash_nodes = nnode; + } + } else if (!strcmpi(w1, "import")) + login_config_read(w2); + else if (!strcmpi(w1, "account.engine")) + safestrncpy(login_config.account_engine, w2, sizeof(login_config.account_engine)); + else { + // try the account engines + int i; + for (i = 0; account_engines[i].constructor; ++i) { + AccountDB *db = account_engines[i].db; + if (db && db->set_property(db, w1, w2)) + break; + } + // try others + ipban_config_read(w1, w2); + loginlog_config_read(w1, w2); + } + } + fclose(fp); + ShowInfo("Finished reading %s.\n", cfgName); + return 0; } /// Get the engine selected in the config settings. /// Updates the config setting with the selected engine if 'auto'. -static AccountDB* get_account_engine(void) +static AccountDB *get_account_engine(void) { - int i; - bool get_first = (strcmp(login_config.account_engine,"auto") == 0); - - for( i = 0; account_engines[i].constructor; ++i ) - { - char name[sizeof(login_config.account_engine)]; - AccountDB* db = account_engines[i].db; - if( db && db->get_property(db, "engine.name", name, sizeof(name)) && - (get_first || strcmp(name, login_config.account_engine) == 0) ) - { - if( get_first ) - safestrncpy(login_config.account_engine, name, sizeof(login_config.account_engine)); - return db; - } - } - return NULL; + int i; + bool get_first = (strcmp(login_config.account_engine,"auto") == 0); + + for (i = 0; account_engines[i].constructor; ++i) { + char name[sizeof(login_config.account_engine)]; + AccountDB *db = account_engines[i].db; + if (db && db->get_property(db, "engine.name", name, sizeof(name)) && + (get_first || strcmp(name, login_config.account_engine) == 0)) { + if (get_first) + safestrncpy(login_config.account_engine, name, sizeof(login_config.account_engine)); + return db; + } + } + return NULL; } //-------------------------------------- @@ -1727,47 +1695,44 @@ static AccountDB* get_account_engine(void) //-------------------------------------- void do_final(void) { - int i; - struct client_hash_node *hn = login_config.client_hash_nodes; - - while (hn) - { - struct client_hash_node *tmp = hn; - hn = hn->next; - aFree(tmp); - } - - login_log(0, "login server", 100, "login server shutdown"); - ShowStatus("Terminating...\n"); - - if( login_config.log_login ) - loginlog_final(); - - ipban_final(); - - for( i = 0; account_engines[i].constructor; ++i ) - {// destroy all account engines - AccountDB* db = account_engines[i].db; - if( db ) - { - db->destroy(db); - account_engines[i].db = NULL; - } - } - accounts = NULL; // destroyed in account_engines - online_db->destroy(online_db, NULL); - auth_db->destroy(auth_db, NULL); - - for( i = 0; i < ARRAYLENGTH(server); ++i ) - chrif_server_destroy(i); - - if( login_fd != -1 ) - { - do_close(login_fd); - login_fd = -1; - } - - ShowStatus("Finished.\n"); + int i; + struct client_hash_node *hn = login_config.client_hash_nodes; + + while (hn) { + struct client_hash_node *tmp = hn; + hn = hn->next; + aFree(tmp); + } + + login_log(0, "login server", 100, "login server shutdown"); + ShowStatus("Terminating...\n"); + + if (login_config.log_login) + loginlog_final(); + + ipban_final(); + + for (i = 0; account_engines[i].constructor; ++i) { + // destroy all account engines + AccountDB *db = account_engines[i].db; + if (db) { + db->destroy(db); + account_engines[i].db = NULL; + } + } + accounts = NULL; // destroyed in account_engines + online_db->destroy(online_db, NULL); + auth_db->destroy(auth_db, NULL); + + for (i = 0; i < ARRAYLENGTH(server); ++i) + chrif_server_destroy(i); + + if (login_fd != -1) { + do_close(login_fd); + login_fd = -1; + } + + ShowStatus("Finished.\n"); } //------------------------------ @@ -1780,104 +1745,101 @@ void do_abort(void) void set_server_type(void) { - SERVER_TYPE = ATHENA_SERVER_LOGIN; + SERVER_TYPE = ATHENA_SERVER_LOGIN; } /// Called when a terminate signal is received. void do_shutdown(void) { - if( runflag != LOGINSERVER_ST_SHUTDOWN ) - { - int id; - runflag = LOGINSERVER_ST_SHUTDOWN; - ShowStatus("Shutting down...\n"); - // TODO proper shutdown procedure; kick all characters, wait for acks, ... [FlavioJS] - for( id = 0; id < ARRAYLENGTH(server); ++id ) - chrif_server_reset(id); - flush_fifos(); - runflag = CORE_ST_STOP; - } + if (runflag != LOGINSERVER_ST_SHUTDOWN) { + int id; + runflag = LOGINSERVER_ST_SHUTDOWN; + ShowStatus("Shutting down...\n"); + // TODO proper shutdown procedure; kick all characters, wait for acks, ... [FlavioJS] + for (id = 0; id < ARRAYLENGTH(server); ++id) + chrif_server_reset(id); + flush_fifos(); + runflag = CORE_ST_STOP; + } } //------------------------------ // Login server initialization //------------------------------ -int do_init(int argc, char** argv) +int do_init(int argc, char **argv) { - int i; - - // intialize engines (to accept config settings) - for( i = 0; account_engines[i].constructor; ++i ) - account_engines[i].db = account_engines[i].constructor(); - - // read login-server configuration - login_set_defaults(); - login_config_read((argc > 1) ? argv[1] : LOGIN_CONF_NAME); - login_lan_config_read((argc > 2) ? argv[2] : LAN_CONF_NAME); - - rnd_init(); - - for( i = 0; i < ARRAYLENGTH(server); ++i ) - chrif_server_init(i); - - // initialize logging - if( login_config.log_login ) - loginlog_init(); - - // initialize static and dynamic ipban system - ipban_init(); - - // Online user database init - online_db = idb_alloc(DB_OPT_RELEASE_DATA); - add_timer_func_list(waiting_disconnect_timer, "waiting_disconnect_timer"); - - // Interserver auth init - auth_db = idb_alloc(DB_OPT_RELEASE_DATA); - - // set default parser as parse_login function - set_defaultparse(parse_login); - - // every 10 minutes cleanup online account db. - add_timer_func_list(online_data_cleanup, "online_data_cleanup"); - add_timer_interval(gettick() + 600*1000, online_data_cleanup, 0, 0, 600*1000); - - // add timer to detect ip address change and perform update - if (login_config.ip_sync_interval) { - add_timer_func_list(sync_ip_addresses, "sync_ip_addresses"); - add_timer_interval(gettick() + login_config.ip_sync_interval, sync_ip_addresses, 0, 0, login_config.ip_sync_interval); - } - - // Account database init - accounts = get_account_engine(); - if( accounts == NULL ) { - ShowFatalError("do_init: account engine '%s' not found.\n", login_config.account_engine); - exit(EXIT_FAILURE); - } else { - - if(!accounts->init(accounts)) { - ShowFatalError("do_init: Failed to initialize account engine '%s'.\n", login_config.account_engine); - exit(EXIT_FAILURE); - } - } - - if( login_config.console ) - { - //##TODO invoke a CONSOLE_START plugin event - } - - // server port open & binding - login_fd = make_listen_bind(login_config.login_ip, login_config.login_port); - - if( runflag != CORE_ST_STOP ) - { - shutdown_callback = do_shutdown; - runflag = LOGINSERVER_ST_RUNNING; - } - - ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %u).\n\n", login_config.login_port); - login_log(0, "login server", 100, "login server started"); - - return 0; + int i; + + // intialize engines (to accept config settings) + for (i = 0; account_engines[i].constructor; ++i) + account_engines[i].db = account_engines[i].constructor(); + + // read login-server configuration + login_set_defaults(); + login_config_read((argc > 1) ? argv[1] : LOGIN_CONF_NAME); + login_lan_config_read((argc > 2) ? argv[2] : LAN_CONF_NAME); + + rnd_init(); + + for (i = 0; i < ARRAYLENGTH(server); ++i) + chrif_server_init(i); + + // initialize logging + if (login_config.log_login) + loginlog_init(); + + // initialize static and dynamic ipban system + ipban_init(); + + // Online user database init + online_db = idb_alloc(DB_OPT_RELEASE_DATA); + add_timer_func_list(waiting_disconnect_timer, "waiting_disconnect_timer"); + + // Interserver auth init + auth_db = idb_alloc(DB_OPT_RELEASE_DATA); + + // set default parser as parse_login function + set_defaultparse(parse_login); + + // every 10 minutes cleanup online account db. + add_timer_func_list(online_data_cleanup, "online_data_cleanup"); + add_timer_interval(gettick() + 600*1000, online_data_cleanup, 0, 0, 600*1000); + + // add timer to detect ip address change and perform update + if (login_config.ip_sync_interval) { + add_timer_func_list(sync_ip_addresses, "sync_ip_addresses"); + add_timer_interval(gettick() + login_config.ip_sync_interval, sync_ip_addresses, 0, 0, login_config.ip_sync_interval); + } + + // Account database init + accounts = get_account_engine(); + if (accounts == NULL) { + ShowFatalError("do_init: account engine '%s' not found.\n", login_config.account_engine); + exit(EXIT_FAILURE); + } else { + + if (!accounts->init(accounts)) { + ShowFatalError("do_init: Failed to initialize account engine '%s'.\n", login_config.account_engine); + exit(EXIT_FAILURE); + } + } + + if (login_config.console) { + //##TODO invoke a CONSOLE_START plugin event + } + + // server port open & binding + login_fd = make_listen_bind(login_config.login_ip, login_config.login_port); + + if (runflag != CORE_ST_STOP) { + shutdown_callback = do_shutdown; + runflag = LOGINSERVER_ST_RUNNING; + } + + ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %u).\n\n", login_config.login_port); + login_log(0, "login server", 100, "login server started"); + + return 0; } diff --git a/src/login/login.h b/src/login/login.h index bedf5e179..97335aa89 100644 --- a/src/login/login.h +++ b/src/login/login.h @@ -7,11 +7,10 @@ #include "../common/mmo.h" // NAME_LENGTH,SEX_* #include "../common/core.h" // CORE_ST_LAST -enum E_LOGINSERVER_ST -{ - LOGINSERVER_ST_RUNNING = CORE_ST_LAST, - LOGINSERVER_ST_SHUTDOWN, - LOGINSERVER_ST_LAST +enum E_LOGINSERVER_ST { + LOGINSERVER_ST_RUNNING = CORE_ST_LAST, + LOGINSERVER_ST_SHUTDOWN, + LOGINSERVER_ST_LAST }; #define LOGIN_CONF_NAME "conf/login_athena.conf" @@ -21,74 +20,74 @@ enum E_LOGINSERVER_ST #define PASSWORDENC 3 struct login_session_data { - int account_id; - long login_id1; - long login_id2; - char sex;// 'F','M','S' - - char userid[NAME_LENGTH]; - char passwd[32+1]; // 23+1 for plaintext, 32+1 for md5-ed passwords - int passwdenc; - char md5key[20]; - uint16 md5keylen; - - char lastlogin[24]; - uint8 group_id; - uint8 clienttype; - uint32 version; - - uint8 client_hash[16]; - int has_client_hash; - - int fd; + int account_id; + long login_id1; + long login_id2; + char sex;// 'F','M','S' + + char userid[NAME_LENGTH]; + char passwd[32+1]; // 23+1 for plaintext, 32+1 for md5-ed passwords + int passwdenc; + char md5key[20]; + uint16 md5keylen; + + char lastlogin[24]; + uint8 group_id; + uint8 clienttype; + uint32 version; + + uint8 client_hash[16]; + int has_client_hash; + + int fd; }; struct mmo_char_server { - char name[20]; - int fd; - uint32 ip; - uint16 port; - uint16 users; // user count on this server - uint16 type; // 0=normal, 1=maintenance, 2=over 18, 3=paying, 4=P2P - uint16 new_; // should display as 'new'? + char name[20]; + int fd; + uint32 ip; + uint16 port; + uint16 users; // user count on this server + uint16 type; // 0=normal, 1=maintenance, 2=over 18, 3=paying, 4=P2P + uint16 new_; // should display as 'new'? }; struct client_hash_node { - int group_id; - uint8 hash[16]; - struct client_hash_node *next; + int group_id; + uint8 hash[16]; + struct client_hash_node *next; }; struct Login_Config { - uint32 login_ip; // the address to bind to - uint16 login_port; // the port to bind to - unsigned int ipban_cleanup_interval; // interval (in seconds) to clean up expired IP bans - unsigned int ip_sync_interval; // interval (in minutes) to execute a DNS/IP update (for dynamic IPs) - bool log_login; // whether to log login server actions or not - char date_format[32]; // date format used in messages - bool console; // console input system enabled? - bool new_account_flag,new_acc_length_limit; // autoregistration via _M/_F ? / if yes minimum length is 4? - int start_limited_time; // new account expiration time (-1: unlimited) - bool use_md5_passwds; // work with password hashes instead of plaintext passwords? - int group_id_to_connect; // required group id to connect - int min_group_id_to_connect; // minimum group id to connect - bool check_client_version; // check the clientversion set in the clientinfo ? - uint32 client_version_to_connect; // the client version needed to connect (if checking is enabled) - - bool ipban; // perform IP blocking (via contents of `ipbanlist`) ? - bool dynamic_pass_failure_ban; // automatic IP blocking due to failed login attemps ? - unsigned int dynamic_pass_failure_ban_interval; // how far to scan the loginlog for password failures - unsigned int dynamic_pass_failure_ban_limit; // number of failures needed to trigger the ipban - unsigned int dynamic_pass_failure_ban_duration; // duration of the ipban - bool use_dnsbl; // dns blacklist blocking ? - char dnsbl_servs[1024]; // comma-separated list of dnsbl servers - - char account_engine[256]; // name of the engine to use (defaults to auto, for the first available engine) - - int client_hash_check; // flags for checking client md5 - struct client_hash_node *client_hash_nodes; // linked list containg md5 hash for each gm group + uint32 login_ip; // the address to bind to + uint16 login_port; // the port to bind to + unsigned int ipban_cleanup_interval; // interval (in seconds) to clean up expired IP bans + unsigned int ip_sync_interval; // interval (in minutes) to execute a DNS/IP update (for dynamic IPs) + bool log_login; // whether to log login server actions or not + char date_format[32]; // date format used in messages + bool console; // console input system enabled? + bool new_account_flag,new_acc_length_limit; // autoregistration via _M/_F ? / if yes minimum length is 4? + int start_limited_time; // new account expiration time (-1: unlimited) + bool use_md5_passwds; // work with password hashes instead of plaintext passwords? + int group_id_to_connect; // required group id to connect + int min_group_id_to_connect; // minimum group id to connect + bool check_client_version; // check the clientversion set in the clientinfo ? + uint32 client_version_to_connect; // the client version needed to connect (if checking is enabled) + + bool ipban; // perform IP blocking (via contents of `ipbanlist`) ? + bool dynamic_pass_failure_ban; // automatic IP blocking due to failed login attemps ? + unsigned int dynamic_pass_failure_ban_interval; // how far to scan the loginlog for password failures + unsigned int dynamic_pass_failure_ban_limit; // number of failures needed to trigger the ipban + unsigned int dynamic_pass_failure_ban_duration; // duration of the ipban + bool use_dnsbl; // dns blacklist blocking ? + char dnsbl_servs[1024]; // comma-separated list of dnsbl servers + + char account_engine[256]; // name of the engine to use (defaults to auto, for the first available engine) + + int client_hash_check; // flags for checking client md5 + struct client_hash_node *client_hash_nodes; // linked list containg md5 hash for each gm group }; #define sex_num2str(num) ( (num == SEX_FEMALE ) ? 'F' : (num == SEX_MALE ) ? 'M' : 'S' ) diff --git a/src/login/loginlog.h b/src/login/loginlog.h index a1ffaae85..63621c50a 100644 --- a/src/login/loginlog.h +++ b/src/login/loginlog.h @@ -6,10 +6,10 @@ unsigned long loginlog_failedattempts(uint32 ip, unsigned int minutes); -void login_log(uint32 ip, const char* username, int rcode, const char* message); +void login_log(uint32 ip, const char *username, int rcode, const char *message); bool loginlog_init(void); bool loginlog_final(void); -bool loginlog_config_read(const char* w1, const char* w2); +bool loginlog_config_read(const char *w1, const char *w2); #endif // __LOGINLOG_H_INCLUDED__ diff --git a/src/login/loginlog_sql.c b/src/login/loginlog_sql.c index d61172697..2d8a17528 100644 --- a/src/login/loginlog_sql.c +++ b/src/login/loginlog_sql.c @@ -25,160 +25,145 @@ static char log_db_database[32] = ""; static char log_codepage[32] = ""; static char log_login_db[256] = "loginlog"; -static Sql* sql_handle = NULL; +static Sql *sql_handle = NULL; static bool enabled = false; // Returns the number of failed login attemps by the ip in the last minutes. unsigned long loginlog_failedattempts(uint32 ip, unsigned int minutes) { - unsigned long failures = 0; - - if( !enabled ) - return 0; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT count(*) FROM `%s` WHERE `ip` = '%s' AND `rcode` = '1' AND `time` > NOW() - INTERVAL %d MINUTE", - log_login_db, ip2str(ip,NULL), minutes) )// how many times failed account? in one ip. - Sql_ShowDebug(sql_handle); - - if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - Sql_GetData(sql_handle, 0, &data, NULL); - failures = strtoul(data, NULL, 10); - Sql_FreeResult(sql_handle); - } - return failures; + unsigned long failures = 0; + + if (!enabled) + return 0; + + if (SQL_ERROR == Sql_Query(sql_handle, "SELECT count(*) FROM `%s` WHERE `ip` = '%s' AND `rcode` = '1' AND `time` > NOW() - INTERVAL %d MINUTE", + log_login_db, ip2str(ip,NULL), minutes)) // how many times failed account? in one ip. + Sql_ShowDebug(sql_handle); + + if (SQL_SUCCESS == Sql_NextRow(sql_handle)) { + char *data; + Sql_GetData(sql_handle, 0, &data, NULL); + failures = strtoul(data, NULL, 10); + Sql_FreeResult(sql_handle); + } + return failures; } /*============================================= * Records an event in the login log *---------------------------------------------*/ -void login_log(uint32 ip, const char* username, int rcode, const char* message) +void login_log(uint32 ip, const char *username, int rcode, const char *message) { - char esc_username[NAME_LENGTH*2+1]; - char esc_message[255*2+1]; - int retcode; + char esc_username[NAME_LENGTH*2+1]; + char esc_message[255*2+1]; + int retcode; - if( !enabled ) - return; + if (!enabled) + return; - Sql_EscapeStringLen(sql_handle, esc_username, username, strnlen(username, NAME_LENGTH)); - Sql_EscapeStringLen(sql_handle, esc_message, message, strnlen(message, 255)); + Sql_EscapeStringLen(sql_handle, esc_username, username, strnlen(username, NAME_LENGTH)); + Sql_EscapeStringLen(sql_handle, esc_message, message, strnlen(message, 255)); - retcode = Sql_Query(sql_handle, - "INSERT INTO `%s`(`time`,`ip`,`user`,`rcode`,`log`) VALUES (NOW(), '%s', '%s', '%d', '%s')", - log_login_db, ip2str(ip,NULL), esc_username, rcode, esc_message); + retcode = Sql_Query(sql_handle, + "INSERT INTO `%s`(`time`,`ip`,`user`,`rcode`,`log`) VALUES (NOW(), '%s', '%s', '%d', '%s')", + log_login_db, ip2str(ip,NULL), esc_username, rcode, esc_message); - if( retcode != SQL_SUCCESS ) - Sql_ShowDebug(sql_handle); + if (retcode != SQL_SUCCESS) + Sql_ShowDebug(sql_handle); } bool loginlog_init(void) { - const char* username; - const char* password; - const char* hostname; - uint16 port; - const char* database; - const char* codepage; - - if( log_db_hostname[0] != '\0' ) - {// local settings - username = log_db_username; - password = log_db_password; - hostname = log_db_hostname; - port = log_db_port; - database = log_db_database; - codepage = log_codepage; - } - else - {// global settings - username = global_db_username; - password = global_db_password; - hostname = global_db_hostname; - port = global_db_port; - database = global_db_database; - codepage = global_codepage; - } - - sql_handle = Sql_Malloc(); - - if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) ) - { - Sql_ShowDebug(sql_handle); - Sql_Free(sql_handle); - exit(EXIT_FAILURE); - } - - if( codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage) ) - Sql_ShowDebug(sql_handle); - - enabled = true; - - return true; + const char *username; + const char *password; + const char *hostname; + uint16 port; + const char *database; + const char *codepage; + + if (log_db_hostname[0] != '\0') { + // local settings + username = log_db_username; + password = log_db_password; + hostname = log_db_hostname; + port = log_db_port; + database = log_db_database; + codepage = log_codepage; + } else { + // global settings + username = global_db_username; + password = global_db_password; + hostname = global_db_hostname; + port = global_db_port; + database = global_db_database; + codepage = global_codepage; + } + + sql_handle = Sql_Malloc(); + + if (SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database)) { + Sql_ShowDebug(sql_handle); + Sql_Free(sql_handle); + exit(EXIT_FAILURE); + } + + if (codepage[0] != '\0' && SQL_ERROR == Sql_SetEncoding(sql_handle, codepage)) + Sql_ShowDebug(sql_handle); + + enabled = true; + + return true; } bool loginlog_final(void) { - Sql_Free(sql_handle); - sql_handle = NULL; - return true; + Sql_Free(sql_handle); + sql_handle = NULL; + return true; } -bool loginlog_config_read(const char* key, const char* value) +bool loginlog_config_read(const char *key, const char *value) { - const char* signature; - - signature = "sql."; - if( strncmpi(key, signature, strlen(signature)) == 0 ) - { - key += strlen(signature); - if( strcmpi(key, "db_hostname") == 0 ) - safestrncpy(global_db_hostname, value, sizeof(global_db_hostname)); - else - if( strcmpi(key, "db_port") == 0 ) - global_db_port = (uint16)strtoul(value, NULL, 10); - else - if( strcmpi(key, "db_username") == 0 ) - safestrncpy(global_db_username, value, sizeof(global_db_username)); - else - if( strcmpi(key, "db_password") == 0 ) - safestrncpy(global_db_password, value, sizeof(global_db_password)); - else - if( strcmpi(key, "db_database") == 0 ) - safestrncpy(global_db_database, value, sizeof(global_db_database)); - else - if( strcmpi(key, "codepage") == 0 ) - safestrncpy(global_codepage, value, sizeof(global_codepage)); - else - return false;// not found - return true; - } - - if( strcmpi(key, "log_db_ip") == 0 ) - safestrncpy(log_db_hostname, value, sizeof(log_db_hostname)); - else - if( strcmpi(key, "log_db_port") == 0 ) - log_db_port = (uint16)strtoul(value, NULL, 10); - else - if( strcmpi(key, "log_db_id") == 0 ) - safestrncpy(log_db_username, value, sizeof(log_db_username)); - else - if( strcmpi(key, "log_db_pw") == 0 ) - safestrncpy(log_db_password, value, sizeof(log_db_password)); - else - if( strcmpi(key, "log_db_db") == 0 ) - safestrncpy(log_db_database, value, sizeof(log_db_database)); - else - if( strcmpi(key, "log_codepage") == 0 ) - safestrncpy(log_codepage, value, sizeof(log_codepage)); - else - if( strcmpi(key, "log_login_db") == 0 ) - safestrncpy(log_login_db, value, sizeof(log_login_db)); - else - return false; - - return true; + const char *signature; + + signature = "sql."; + if (strncmpi(key, signature, strlen(signature)) == 0) { + key += strlen(signature); + if (strcmpi(key, "db_hostname") == 0) + safestrncpy(global_db_hostname, value, sizeof(global_db_hostname)); + else if (strcmpi(key, "db_port") == 0) + global_db_port = (uint16)strtoul(value, NULL, 10); + else if (strcmpi(key, "db_username") == 0) + safestrncpy(global_db_username, value, sizeof(global_db_username)); + else if (strcmpi(key, "db_password") == 0) + safestrncpy(global_db_password, value, sizeof(global_db_password)); + else if (strcmpi(key, "db_database") == 0) + safestrncpy(global_db_database, value, sizeof(global_db_database)); + else if (strcmpi(key, "codepage") == 0) + safestrncpy(global_codepage, value, sizeof(global_codepage)); + else + return false;// not found + return true; + } + + if (strcmpi(key, "log_db_ip") == 0) + safestrncpy(log_db_hostname, value, sizeof(log_db_hostname)); + else if (strcmpi(key, "log_db_port") == 0) + log_db_port = (uint16)strtoul(value, NULL, 10); + else if (strcmpi(key, "log_db_id") == 0) + safestrncpy(log_db_username, value, sizeof(log_db_username)); + else if (strcmpi(key, "log_db_pw") == 0) + safestrncpy(log_db_password, value, sizeof(log_db_password)); + else if (strcmpi(key, "log_db_db") == 0) + safestrncpy(log_db_database, value, sizeof(log_db_database)); + else if (strcmpi(key, "log_codepage") == 0) + safestrncpy(log_codepage, value, sizeof(log_codepage)); + else if (strcmpi(key, "log_login_db") == 0) + safestrncpy(log_login_db, value, sizeof(log_login_db)); + else + return false; + + return true; } diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 394f4fb11..33a389db9 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -61,100 +61,97 @@ typedef struct AliasInfo AliasInfo; int atcmd_binding_count = 0; struct AtCommandInfo { - char command[ATCOMMAND_LENGTH]; - AtCommandFunc func; - char* at_groups;/* quick @commands "can-use" lookup */ - char* char_groups;/* quick @charcommands "can-use" lookup */ + char command[ATCOMMAND_LENGTH]; + AtCommandFunc func; + char *at_groups;/* quick @commands "can-use" lookup */ + char *char_groups;/* quick @charcommands "can-use" lookup */ }; struct AliasInfo { - AtCommandInfo *command; - char alias[ATCOMMAND_LENGTH]; + AtCommandInfo *command; + char alias[ATCOMMAND_LENGTH]; }; char atcommand_symbol = '@'; // first char of the commands char charcommand_symbol = '#'; -static char* msg_table[MAX_MSG]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others) -static DBMap* atcommand_db = NULL; //name -> AtCommandInfo -static DBMap* atcommand_alias_db = NULL; //alias -> AtCommandInfo +static char *msg_table[MAX_MSG]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others) +static DBMap *atcommand_db = NULL; //name -> AtCommandInfo +static DBMap *atcommand_alias_db = NULL; //alias -> AtCommandInfo static config_t atcommand_config; static char atcmd_output[CHAT_SIZE_MAX]; static char atcmd_player_name[NAME_LENGTH]; -static AtCommandInfo* get_atcommandinfo_byname(const char *name); // @help -static const char* atcommand_checkalias(const char *aliasname); // @help -static void atcommand_get_suggestions(struct map_session_data* sd, const char *name, bool atcommand); // @help +static AtCommandInfo *get_atcommandinfo_byname(const char *name); // @help +static const char *atcommand_checkalias(const char *aliasname); // @help +static void atcommand_get_suggestions(struct map_session_data *sd, const char *name, bool atcommand); // @help // @commands (script-based) -struct atcmd_binding_data* get_atcommandbind_byname(const char* name) { - int i = 0; +struct atcmd_binding_data *get_atcommandbind_byname(const char *name) { + int i = 0; - if( *name == atcommand_symbol || *name == charcommand_symbol ) - name++; // for backwards compatibility + if (*name == atcommand_symbol || *name == charcommand_symbol) + name++; // for backwards compatibility - ARR_FIND( 0, atcmd_binding_count, i, strcmp(atcmd_binding[i]->command, name) == 0 ); + ARR_FIND(0, atcmd_binding_count, i, strcmp(atcmd_binding[i]->command, name) == 0); - return ( i < atcmd_binding_count ) ? atcmd_binding[i] : NULL; + return (i < atcmd_binding_count) ? atcmd_binding[i] : NULL; } //----------------------------------------------------------- // Return the message string of the specified number by [Yor] //----------------------------------------------------------- -const char* msg_txt(int msg_number) +const char *msg_txt(int msg_number) { - if (msg_number >= 0 && msg_number < MAX_MSG && - msg_table[msg_number] != NULL && msg_table[msg_number][0] != '\0') - return msg_table[msg_number]; + if (msg_number >= 0 && msg_number < MAX_MSG && + msg_table[msg_number] != NULL && msg_table[msg_number][0] != '\0') + return msg_table[msg_number]; - return "??"; + return "??"; } /*========================================== * Read Message Data *------------------------------------------*/ -int msg_config_read(const char* cfgName) +int msg_config_read(const char *cfgName) { - int msg_number; - char line[1024], w1[1024], w2[1024]; - FILE *fp; - static int called = 1; + int msg_number; + char line[1024], w1[1024], w2[1024]; + FILE *fp; + static int called = 1; - if ((fp = fopen(cfgName, "r")) == NULL) { - ShowError("Messages file not found: %s\n", cfgName); - return 1; - } + if ((fp = fopen(cfgName, "r")) == NULL) { + ShowError("Messages file not found: %s\n", cfgName); + return 1; + } - if ((--called) == 0) - memset(msg_table, 0, sizeof(msg_table[0]) * MAX_MSG); + if ((--called) == 0) + memset(msg_table, 0, sizeof(msg_table[0]) * MAX_MSG); - while(fgets(line, sizeof(line), fp)) - { - if (line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') + continue; + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; - if (strcmpi(w1, "import") == 0) - msg_config_read(w2); - else - { - msg_number = atoi(w1); - if (msg_number >= 0 && msg_number < MAX_MSG) - { - if (msg_table[msg_number] != NULL) - aFree(msg_table[msg_number]); - msg_table[msg_number] = (char *)aMalloc((strlen(w2) + 1)*sizeof (char)); - strcpy(msg_table[msg_number],w2); - } - } - } + if (strcmpi(w1, "import") == 0) + msg_config_read(w2); + else { + msg_number = atoi(w1); + if (msg_number >= 0 && msg_number < MAX_MSG) { + if (msg_table[msg_number] != NULL) + aFree(msg_table[msg_number]); + msg_table[msg_number] = (char *)aMalloc((strlen(w2) + 1)*sizeof(char)); + strcpy(msg_table[msg_number],w2); + } + } + } - fclose(fp); + fclose(fp); - return 0; + return 0; } /*========================================== @@ -162,9 +159,9 @@ int msg_config_read(const char* cfgName) *------------------------------------------*/ void do_final_msg(void) { - int i; - for (i = 0; i < MAX_MSG; i++) - aFree(msg_table[i]); + int i; + for (i = 0; i < MAX_MSG; i++) + aFree(msg_table[i]); } /** @@ -173,34 +170,34 @@ void do_final_msg(void) * @param name the name of the command to retrieve help information for * @return the string associated with the command, or NULL */ -static const char* atcommand_help_string(const char* command) +static const char *atcommand_help_string(const char *command) { - const char* str = NULL; - config_setting_t* info; + const char *str = NULL; + config_setting_t *info; - if( *command == atcommand_symbol || *command == charcommand_symbol ) - {// remove the prefix symbol for the raw name of the command - command ++; - } + if (*command == atcommand_symbol || *command == charcommand_symbol) { + // remove the prefix symbol for the raw name of the command + command ++; + } - // convert alias to the real command name - command = atcommand_checkalias(command); + // convert alias to the real command name + command = atcommand_checkalias(command); - // attept to find the first default help command - info = config_lookup(&atcommand_config, "help"); + // attept to find the first default help command + info = config_lookup(&atcommand_config, "help"); - if( info == NULL ) - {// failed to find the help property in the configuration file - return NULL; - } + if (info == NULL) { + // failed to find the help property in the configuration file + return NULL; + } - if( !config_setting_lookup_string( info, command, &str ) ) - {// failed to find the matching help string - return NULL; - } + if (!config_setting_lookup_string(info, command, &str)) { + // failed to find the matching help string + return NULL; + } - // push the result from the method - return str; + // push the result from the method + return str; } @@ -209,228 +206,243 @@ static const char* atcommand_help_string(const char* command) *------------------------------------------*/ ACMD_FUNC(send) { - int len=0,off,end,type; - long num; + int len=0,off,end,type; + long num; - // read message type as hex number (without the 0x) - if(!message || !*message || - !((sscanf(message, "len %x", &type)==1 && (len=1)) - || sscanf(message, "%x", &type)==1) ) - { - int i; - for (i = 900; i <= 903; ++i) - clif_displaymessage(fd, msg_txt(i)); - return -1; - } + // read message type as hex number (without the 0x) + if (!message || !*message || + !((sscanf(message, "len %x", &type)==1 && (len=1)) + || sscanf(message, "%x", &type)==1)) { + int i; + for (i = 900; i <= 903; ++i) + clif_displaymessage(fd, msg_txt(i)); + return -1; + } #define PARSE_ERROR(error,p) \ - {\ - clif_displaymessage(fd, (error));\ - sprintf(atcmd_output, ">%s", (p));\ - clif_displaymessage(fd, atcmd_output);\ - } -//define PARSE_ERROR + {\ + clif_displaymessage(fd, (error));\ + sprintf(atcmd_output, ">%s", (p));\ + clif_displaymessage(fd, atcmd_output);\ + } + //define PARSE_ERROR #define CHECK_EOS(p) \ - if(*(p) == 0){\ - clif_displaymessage(fd, "Unexpected end of string");\ - return -1;\ - } -//define CHECK_EOS + if(*(p) == 0){\ + clif_displaymessage(fd, "Unexpected end of string");\ + return -1;\ + } + //define CHECK_EOS #define SKIP_VALUE(p) \ - {\ - while(*(p) && !ISSPACE(*(p))) ++(p); /* non-space */\ - while(*(p) && ISSPACE(*(p))) ++(p); /* space */\ - } -//define SKIP_VALUE + {\ + while(*(p) && !ISSPACE(*(p))) ++(p); /* non-space */\ + while(*(p) && ISSPACE(*(p))) ++(p); /* space */\ + } + //define SKIP_VALUE #define GET_VALUE(p,num) \ - {\ - if(sscanf((p), "x%lx", &(num)) < 1 && sscanf((p), "%ld ", &(num)) < 1){\ - PARSE_ERROR("Invalid number in:",(p));\ - return -1;\ - }\ - } -//define GET_VALUE - - if (type > 0 && type < MAX_PACKET_DB) { - - if(len) - {// show packet length - sprintf(atcmd_output, msg_txt(904), type, packet_db[sd->packet_ver][type].len); // Packet 0x%x length: %d - clif_displaymessage(fd, atcmd_output); - return 0; - } - - len=packet_db[sd->packet_ver][type].len; - off=2; - if(len == 0) - {// unknown packet - ERROR - sprintf(atcmd_output, msg_txt(905), type); // Unknown packet: 0x%x - clif_displaymessage(fd, atcmd_output); - return -1; - } else if(len == -1) - {// dynamic packet - len=SHRT_MAX-4; // maximum length - off=4; - } - WFIFOHEAD(fd, len); - WFIFOW(fd,0)=TOW(type); - - // parse packet contents - SKIP_VALUE(message); - while(*message != 0 && off < len){ - if(ISDIGIT(*message) || *message == '-' || *message == '+') - {// default (byte) - GET_VALUE(message,num); - WFIFOB(fd,off)=TOB(num); - ++off; - } else if(TOUPPER(*message) == 'B') - {// byte - ++message; - GET_VALUE(message,num); - WFIFOB(fd,off)=TOB(num); - ++off; - } else if(TOUPPER(*message) == 'W') - {// word (2 bytes) - ++message; - GET_VALUE(message,num); - WFIFOW(fd,off)=TOW(num); - off+=2; - } else if(TOUPPER(*message) == 'L') - {// long word (4 bytes) - ++message; - GET_VALUE(message,num); - WFIFOL(fd,off)=TOL(num); - off+=4; - } else if(TOUPPER(*message) == 'S') - {// string - escapes are valid - // get string length - num <= 0 means not fixed length (default) - ++message; - if(*message == '"'){ - num=0; - } else { - GET_VALUE(message,num); - while(*message != '"') - {// find start of string - if(*message == 0 || ISSPACE(*message)){ - PARSE_ERROR(msg_txt(906),message); // Not a string: - return -1; - } - ++message; - } - } - - // parse string - ++message; - CHECK_EOS(message); - end=(num<=0? 0: min(off+((int)num),len)); - for(; *message != '"' && (off < end || end == 0); ++off){ - if(*message == '\\'){ - ++message; - CHECK_EOS(message); - switch(*message){ - case 'a': num=0x07; break; // Bell - case 'b': num=0x08; break; // Backspace - case 't': num=0x09; break; // Horizontal tab - case 'n': num=0x0A; break; // Line feed - case 'v': num=0x0B; break; // Vertical tab - case 'f': num=0x0C; break; // Form feed - case 'r': num=0x0D; break; // Carriage return - case 'e': num=0x1B; break; // Escape - default: num=*message; break; - case 'x': // Hexadecimal - { - ++message; - CHECK_EOS(message); - if(!ISXDIGIT(*message)){ - PARSE_ERROR(msg_txt(907),message); // Not a hexadecimal digit: - return -1; - } - num=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10); - if(ISXDIGIT(*message)){ - ++message; - CHECK_EOS(message); - num<<=8; - num+=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10); - } - WFIFOB(fd,off)=TOB(num); - ++message; - CHECK_EOS(message); - continue; - } - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': // Octal - { - num=*message-'0'; // 1st octal digit - ++message; - CHECK_EOS(message); - if(ISDIGIT(*message) && *message < '8'){ - num<<=3; - num+=*message-'0'; // 2nd octal digit - ++message; - CHECK_EOS(message); - if(ISDIGIT(*message) && *message < '8'){ - num<<=3; - num+=*message-'0'; // 3rd octal digit - ++message; - CHECK_EOS(message); - } - } - WFIFOB(fd,off)=TOB(num); - continue; - } - } - } else - num=*message; - WFIFOB(fd,off)=TOB(num); - ++message; - CHECK_EOS(message); - }//for - while(*message != '"') - {// ignore extra characters - ++message; - CHECK_EOS(message); - } - - // terminate the string - if(off < end) - {// fill the rest with 0's - memset(WFIFOP(fd,off),0,end-off); - off=end; - } - } else - {// unknown - PARSE_ERROR(msg_txt(908),message); // Unknown type of value in: - return -1; - } - SKIP_VALUE(message); - } - - if(packet_db[sd->packet_ver][type].len == -1) - {// send dynamic packet - WFIFOW(fd,2)=TOW(off); - WFIFOSET(fd,off); - } else - {// send static packet - if(off < len) - memset(WFIFOP(fd,off),0,len-off); - WFIFOSET(fd,len); - } - } else { - clif_displaymessage(fd, msg_txt(259)); // Invalid packet - return -1; - } - sprintf (atcmd_output, msg_txt(258), type, type); // Sent packet 0x%x (%d) - clif_displaymessage(fd, atcmd_output); - return 0; + {\ + if(sscanf((p), "x%lx", &(num)) < 1 && sscanf((p), "%ld ", &(num)) < 1){\ + PARSE_ERROR("Invalid number in:",(p));\ + return -1;\ + }\ + } + //define GET_VALUE + + if (type > 0 && type < MAX_PACKET_DB) { + + if (len) { + // show packet length + sprintf(atcmd_output, msg_txt(904), type, packet_db[sd->packet_ver][type].len); // Packet 0x%x length: %d + clif_displaymessage(fd, atcmd_output); + return 0; + } + + len=packet_db[sd->packet_ver][type].len; + off=2; + if (len == 0) { + // unknown packet - ERROR + sprintf(atcmd_output, msg_txt(905), type); // Unknown packet: 0x%x + clif_displaymessage(fd, atcmd_output); + return -1; + } else if (len == -1) { + // dynamic packet + len=SHRT_MAX-4; // maximum length + off=4; + } + WFIFOHEAD(fd, len); + WFIFOW(fd,0)=TOW(type); + + // parse packet contents + SKIP_VALUE(message); + while (*message != 0 && off < len) { + if (ISDIGIT(*message) || *message == '-' || *message == '+') { + // default (byte) + GET_VALUE(message,num); + WFIFOB(fd,off)=TOB(num); + ++off; + } else if (TOUPPER(*message) == 'B') { + // byte + ++message; + GET_VALUE(message,num); + WFIFOB(fd,off)=TOB(num); + ++off; + } else if (TOUPPER(*message) == 'W') { + // word (2 bytes) + ++message; + GET_VALUE(message,num); + WFIFOW(fd,off)=TOW(num); + off+=2; + } else if (TOUPPER(*message) == 'L') { + // long word (4 bytes) + ++message; + GET_VALUE(message,num); + WFIFOL(fd,off)=TOL(num); + off+=4; + } else if (TOUPPER(*message) == 'S') { + // string - escapes are valid + // get string length - num <= 0 means not fixed length (default) + ++message; + if (*message == '"') { + num=0; + } else { + GET_VALUE(message,num); + while (*message != '"') { + // find start of string + if (*message == 0 || ISSPACE(*message)) { + PARSE_ERROR(msg_txt(906),message); // Not a string: + return -1; + } + ++message; + } + } + + // parse string + ++message; + CHECK_EOS(message); + end=(num<=0? 0: min(off+((int)num),len)); + for (; *message != '"' && (off < end || end == 0); ++off) { + if (*message == '\\') { + ++message; + CHECK_EOS(message); + switch (*message) { + case 'a': + num=0x07; + break; // Bell + case 'b': + num=0x08; + break; // Backspace + case 't': + num=0x09; + break; // Horizontal tab + case 'n': + num=0x0A; + break; // Line feed + case 'v': + num=0x0B; + break; // Vertical tab + case 'f': + num=0x0C; + break; // Form feed + case 'r': + num=0x0D; + break; // Carriage return + case 'e': + num=0x1B; + break; // Escape + default: + num=*message; + break; + case 'x': { // Hexadecimal + ++message; + CHECK_EOS(message); + if (!ISXDIGIT(*message)) { + PARSE_ERROR(msg_txt(907),message); // Not a hexadecimal digit: + return -1; + } + num=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10); + if (ISXDIGIT(*message)) { + ++message; + CHECK_EOS(message); + num<<=8; + num+=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10); + } + WFIFOB(fd,off)=TOB(num); + ++message; + CHECK_EOS(message); + continue; + } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': { // Octal + num=*message-'0'; // 1st octal digit + ++message; + CHECK_EOS(message); + if (ISDIGIT(*message) && *message < '8') { + num<<=3; + num+=*message-'0'; // 2nd octal digit + ++message; + CHECK_EOS(message); + if (ISDIGIT(*message) && *message < '8') { + num<<=3; + num+=*message-'0'; // 3rd octal digit + ++message; + CHECK_EOS(message); + } + } + WFIFOB(fd,off)=TOB(num); + continue; + } + } + } else + num=*message; + WFIFOB(fd,off)=TOB(num); + ++message; + CHECK_EOS(message); + }//for + while (*message != '"') { + // ignore extra characters + ++message; + CHECK_EOS(message); + } + + // terminate the string + if (off < end) { + // fill the rest with 0's + memset(WFIFOP(fd,off),0,end-off); + off=end; + } + } else { + // unknown + PARSE_ERROR(msg_txt(908),message); // Unknown type of value in: + return -1; + } + SKIP_VALUE(message); + } + + if (packet_db[sd->packet_ver][type].len == -1) { + // send dynamic packet + WFIFOW(fd,2)=TOW(off); + WFIFOSET(fd,off); + } else { + // send static packet + if (off < len) + memset(WFIFOP(fd,off),0,len-off); + WFIFOSET(fd,len); + } + } else { + clif_displaymessage(fd, msg_txt(259)); // Invalid packet + return -1; + } + sprintf(atcmd_output, msg_txt(258), type, type); // Sent packet 0x%x (%d) + clif_displaymessage(fd, atcmd_output); + return 0; #undef PARSE_ERROR #undef CHECK_EOS #undef SKIP_VALUE @@ -442,53 +454,53 @@ ACMD_FUNC(send) *------------------------------------------*/ ACMD_FUNC(mapmove) { - char map_name[MAP_NAME_LENGTH_EXT]; - unsigned short mapindex; - short x = 0, y = 0; - int m = -1; + char map_name[MAP_NAME_LENGTH_EXT]; + unsigned short mapindex; + short x = 0, y = 0; + int m = -1; - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - memset(map_name, '\0', sizeof(map_name)); + memset(map_name, '\0', sizeof(map_name)); - if (!message || !*message || - (sscanf(message, "%15s %hd %hd", map_name, &x, &y) < 3 && - sscanf(message, "%15[^,],%hd,%hd", map_name, &x, &y) < 1)) { + if (!message || !*message || + (sscanf(message, "%15s %hd %hd", map_name, &x, &y) < 3 && + sscanf(message, "%15[^,],%hd,%hd", map_name, &x, &y) < 1)) { - clif_displaymessage(fd, msg_txt(909)); // Please enter a map (usage: @warp/@rura/@mapmove ). - return -1; - } + clif_displaymessage(fd, msg_txt(909)); // Please enter a map (usage: @warp/@rura/@mapmove ). + return -1; + } - mapindex = mapindex_name2id(map_name); - if (mapindex) - m = map_mapindex2mapid(mapindex); + mapindex = mapindex_name2id(map_name); + if (mapindex) + m = map_mapindex2mapid(mapindex); - if (!mapindex) { // m < 0 means on different server! [Kevin] - clif_displaymessage(fd, msg_txt(1)); // Map not found. - return -1; - } + if (!mapindex) { // m < 0 means on different server! [Kevin] + clif_displaymessage(fd, msg_txt(1)); // Map not found. + return -1; + } - if ((x || y) && map_getcell(m, x, y, CELL_CHKNOPASS)) - { //This is to prevent the pc_setpos call from printing an error. - clif_displaymessage(fd, msg_txt(2)); - if (!map_search_freecell(NULL, m, &x, &y, 10, 10, 1)) - x = y = 0; //Invalid cell, use random spot. - } - if (map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(247)); - return -1; - } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(248)); - return -1; - } - if (pc_setpos(sd, mapindex, x, y, CLR_TELEPORT) != 0) { - clif_displaymessage(fd, msg_txt(1)); // Map not found. - return -1; - } + if ((x || y) && map_getcell(m, x, y, CELL_CHKNOPASS)) { + //This is to prevent the pc_setpos call from printing an error. + clif_displaymessage(fd, msg_txt(2)); + if (!map_search_freecell(NULL, m, &x, &y, 10, 10, 1)) + x = y = 0; //Invalid cell, use random spot. + } + if (map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(247)); + return -1; + } + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(248)); + return -1; + } + if (pc_setpos(sd, mapindex, x, y, CLR_TELEPORT) != 0) { + clif_displaymessage(fd, msg_txt(1)); // Map not found. + return -1; + } - clif_displaymessage(fd, msg_txt(0)); // Warped. - return 0; + clif_displaymessage(fd, msg_txt(0)); // Warped. + return 0; } /*========================================== @@ -496,29 +508,29 @@ ACMD_FUNC(mapmove) *------------------------------------------*/ ACMD_FUNC(where) { - struct map_session_data* pl_sd; + struct map_session_data *pl_sd; - nullpo_retr(-1, sd); - memset(atcmd_player_name, '\0', sizeof atcmd_player_name); + nullpo_retr(-1, sd); + memset(atcmd_player_name, '\0', sizeof atcmd_player_name); - if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) { - clif_displaymessage(fd, msg_txt(910)); // Please enter a player name (usage: @where ). - return -1; - } + if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) { + clif_displaymessage(fd, msg_txt(910)); // Please enter a player name (usage: @where ). + return -1; + } - pl_sd = map_nick2sd(atcmd_player_name); - if (pl_sd == NULL || - strncmp(pl_sd->status.name, atcmd_player_name, NAME_LENGTH) != 0 || - (pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc_get_group_level(pl_sd) > pc_get_group_level(sd) && !pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) - ) { - clif_displaymessage(fd, msg_txt(3)); // Character not found. - return -1; - } + pl_sd = map_nick2sd(atcmd_player_name); + if (pl_sd == NULL || + strncmp(pl_sd->status.name, atcmd_player_name, NAME_LENGTH) != 0 || + (pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc_get_group_level(pl_sd) > pc_get_group_level(sd) && !pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) + ) { + clif_displaymessage(fd, msg_txt(3)); // Character not found. + return -1; + } - snprintf(atcmd_output, sizeof atcmd_output, "%s %s %d %d", pl_sd->status.name, mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); - clif_displaymessage(fd, atcmd_output); + snprintf(atcmd_output, sizeof atcmd_output, "%s %s %d %d", pl_sd->status.name, mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); + clif_displaymessage(fd, atcmd_output); - return 0; + return 0; } /*========================================== @@ -526,44 +538,40 @@ ACMD_FUNC(where) *------------------------------------------*/ ACMD_FUNC(jumpto) { - struct map_session_data *pl_sd = NULL; + struct map_session_data *pl_sd = NULL; - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (!message || !*message) { - clif_displaymessage(fd, msg_txt(911)); // Please enter a player name (usage: @jumpto/@warpto/@goto ). - return -1; - } + if (!message || !*message) { + clif_displaymessage(fd, msg_txt(911)); // Please enter a player name (usage: @jumpto/@warpto/@goto ). + return -1; + } - if((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL) - { - clif_displaymessage(fd, msg_txt(3)); // Character not found. - return -1; - } + if ((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL) { + clif_displaymessage(fd, msg_txt(3)); // Character not found. + return -1; + } - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) - { - clif_displaymessage(fd, msg_txt(247)); // You are not authorized to warp to this map. - return -1; - } + if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(247)); // You are not authorized to warp to this map. + return -1; + } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) - { - clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. - return -1; - } + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. + return -1; + } - if( pc_isdead(sd) ) - { - clif_displaymessage(fd, msg_txt(664)); - return -1; - } + if (pc_isdead(sd)) { + clif_displaymessage(fd, msg_txt(664)); + return -1; + } - pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT); - sprintf(atcmd_output, msg_txt(4), pl_sd->status.name); // Jumped to %s - clif_displaymessage(fd, atcmd_output); + pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT); + sprintf(atcmd_output, msg_txt(4), pl_sd->status.name); // Jumped to %s + clif_displaymessage(fd, atcmd_output); - return 0; + return 0; } /*========================================== @@ -571,36 +579,35 @@ ACMD_FUNC(jumpto) *------------------------------------------*/ ACMD_FUNC(jump) { - short x = 0, y = 0; + short x = 0, y = 0; - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - sscanf(message, "%hd %hd", &x, &y); + sscanf(message, "%hd %hd", &x, &y); - if (map[sd->bl.m].flag.noteleport && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. - return -1; - } + if (map[sd->bl.m].flag.noteleport && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. + return -1; + } - if( pc_isdead(sd) ) - { - clif_displaymessage(fd, msg_txt(664)); - return -1; - } + if (pc_isdead(sd)) { + clif_displaymessage(fd, msg_txt(664)); + return -1; + } - if ((x || y) && map_getcell(sd->bl.m, x, y, CELL_CHKNOPASS)) - { //This is to prevent the pc_setpos call from printing an error. - clif_displaymessage(fd, msg_txt(2)); - if (!map_search_freecell(NULL, sd->bl.m, &x, &y, 10, 10, 1)) - x = y = 0; //Invalid cell, use random spot. - } + if ((x || y) && map_getcell(sd->bl.m, x, y, CELL_CHKNOPASS)) { + //This is to prevent the pc_setpos call from printing an error. + clif_displaymessage(fd, msg_txt(2)); + if (!map_search_freecell(NULL, sd->bl.m, &x, &y, 10, 10, 1)) + x = y = 0; //Invalid cell, use random spot. + } - pc_setpos(sd, sd->mapindex, x, y, CLR_TELEPORT); - sprintf(atcmd_output, msg_txt(5), sd->bl.x, sd->bl.y); // Jumped to %d %d - clif_displaymessage(fd, atcmd_output); - return 0; + pc_setpos(sd, sd->mapindex, x, y, CLR_TELEPORT); + sprintf(atcmd_output, msg_txt(5), sd->bl.x, sd->bl.y); // Jumped to %d %d + clif_displaymessage(fd, atcmd_output); + return 0; } /*========================================== @@ -609,101 +616,101 @@ ACMD_FUNC(jump) *------------------------------------------*/ ACMD_FUNC(who) { - struct map_session_data *pl_sd = NULL; - struct s_mapiterator *iter = NULL; - char map_name[MAP_NAME_LENGTH_EXT] = ""; - char player_name[NAME_LENGTH] = ""; - int count = 0; - int level = 0; - StringBuf buf; - /** - * 1 = @who : Player name, [Title], [Party name], [Guild name] - * 2 = @who2 : Player name, [Title], BLvl, JLvl, Job - * 3 = @who3 : [CID/AID] Player name [Title], Map, X, Y - */ - int display_type = 1; - int map_id = -1; - - nullpo_retr(-1, sd); - - if (strstr(command, "map") != NULL) { - if (sscanf(message, "%15s %23s", map_name, player_name) < 1 || (map_id = map_mapname2mapid(map_name)) < 0) - map_id = sd->bl.m; - } else { - sscanf(message, "%23s", player_name); - } - - if (strstr(command, "2") != NULL) - display_type = 2; - else if (strstr(command, "3") != NULL) - display_type = 3; - - level = pc_get_group_level(sd); - StringBuf_Init(&buf); - - iter = mapit_getallusers(); - for (pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter)) { - if (!((pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) || (pl_sd->sc.option & OPTION_INVISIBLE)) && pc_get_group_level(pl_sd) > level)) { // you can look only lower or same level - if (stristr(pl_sd->status.name, player_name) == NULL // search with no case sensitive - || (map_id >= 0 && pl_sd->bl.m != map_id)) - continue; - switch (display_type) { - case 2: { - StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " - if (pc_get_group_id(pl_sd) > 0) // Player title, if exists - StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " - StringBuf_Printf(&buf, msg_txt(347), pl_sd->status.base_level, pl_sd->status.job_level, - job_name(pl_sd->status.class_)); // "| Lv:%d/%d | Job: %s" - break; - } - case 3: { - if (pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) - StringBuf_Printf(&buf, msg_txt(912), pl_sd->status.char_id, pl_sd->status.account_id); // "(CID:%d/AID:%d) " - StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " - if (pc_get_group_id(pl_sd) > 0) // Player title, if exists - StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " - StringBuf_Printf(&buf, msg_txt(348), mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); // "| Location: %s %d %d" - break; - } - default: { - struct party_data *p = party_search(pl_sd->status.party_id); - struct guild *g = guild_search(pl_sd->status.guild_id); - - StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " - if (pc_get_group_id(pl_sd) > 0) // Player title, if exists - StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " - if (p != NULL) - StringBuf_Printf(&buf, msg_txt(345), p->party.name); // " | Party: '%s'" - if (g != NULL) - StringBuf_Printf(&buf, msg_txt(346), g->name); // " | Guild: '%s'" - break; - } - } - clif_displaymessage(fd, StringBuf_Value(&buf)); - StringBuf_Clear(&buf); - count++; - } - } - mapit_free(iter); - - if (map_id < 0) { - if (count == 0) - StringBuf_Printf(&buf, msg_txt(28)); // No player found. - else if (count == 1) - StringBuf_Printf(&buf, msg_txt(29)); // 1 player found. - else - StringBuf_Printf(&buf, msg_txt(30), count); // %d players found. - } else { - if (count == 0) - StringBuf_Printf(&buf, msg_txt(54), map[map_id].name); // No player found in map '%s'. - else if (count == 1) - StringBuf_Printf(&buf, msg_txt(55), map[map_id].name); // 1 player found in map '%s'. - else - StringBuf_Printf(&buf, msg_txt(56), count, map[map_id].name); // %d players found in map '%s'. - } - clif_displaymessage(fd, StringBuf_Value(&buf)); - StringBuf_Destroy(&buf); - return 0; + struct map_session_data *pl_sd = NULL; + struct s_mapiterator *iter = NULL; + char map_name[MAP_NAME_LENGTH_EXT] = ""; + char player_name[NAME_LENGTH] = ""; + int count = 0; + int level = 0; + StringBuf buf; + /** + * 1 = @who : Player name, [Title], [Party name], [Guild name] + * 2 = @who2 : Player name, [Title], BLvl, JLvl, Job + * 3 = @who3 : [CID/AID] Player name [Title], Map, X, Y + */ + int display_type = 1; + int map_id = -1; + + nullpo_retr(-1, sd); + + if (strstr(command, "map") != NULL) { + if (sscanf(message, "%15s %23s", map_name, player_name) < 1 || (map_id = map_mapname2mapid(map_name)) < 0) + map_id = sd->bl.m; + } else { + sscanf(message, "%23s", player_name); + } + + if (strstr(command, "2") != NULL) + display_type = 2; + else if (strstr(command, "3") != NULL) + display_type = 3; + + level = pc_get_group_level(sd); + StringBuf_Init(&buf); + + iter = mapit_getallusers(); + for (pl_sd = (TBL_PC *)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC *)mapit_next(iter)) { + if (!((pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) || (pl_sd->sc.option & OPTION_INVISIBLE)) && pc_get_group_level(pl_sd) > level)) { // you can look only lower or same level + if (stristr(pl_sd->status.name, player_name) == NULL // search with no case sensitive + || (map_id >= 0 && pl_sd->bl.m != map_id)) + continue; + switch (display_type) { + case 2: { + StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " + if (pc_get_group_id(pl_sd) > 0) // Player title, if exists + StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " + StringBuf_Printf(&buf, msg_txt(347), pl_sd->status.base_level, pl_sd->status.job_level, + job_name(pl_sd->status.class_)); // "| Lv:%d/%d | Job: %s" + break; + } + case 3: { + if (pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) + StringBuf_Printf(&buf, msg_txt(912), pl_sd->status.char_id, pl_sd->status.account_id); // "(CID:%d/AID:%d) " + StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " + if (pc_get_group_id(pl_sd) > 0) // Player title, if exists + StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " + StringBuf_Printf(&buf, msg_txt(348), mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); // "| Location: %s %d %d" + break; + } + default: { + struct party_data *p = party_search(pl_sd->status.party_id); + struct guild *g = guild_search(pl_sd->status.guild_id); + + StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " + if (pc_get_group_id(pl_sd) > 0) // Player title, if exists + StringBuf_Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " + if (p != NULL) + StringBuf_Printf(&buf, msg_txt(345), p->party.name); // " | Party: '%s'" + if (g != NULL) + StringBuf_Printf(&buf, msg_txt(346), g->name); // " | Guild: '%s'" + break; + } + } + clif_displaymessage(fd, StringBuf_Value(&buf)); + StringBuf_Clear(&buf); + count++; + } + } + mapit_free(iter); + + if (map_id < 0) { + if (count == 0) + StringBuf_Printf(&buf, msg_txt(28)); // No player found. + else if (count == 1) + StringBuf_Printf(&buf, msg_txt(29)); // 1 player found. + else + StringBuf_Printf(&buf, msg_txt(30), count); // %d players found. + } else { + if (count == 0) + StringBuf_Printf(&buf, msg_txt(54), map[map_id].name); // No player found in map '%s'. + else if (count == 1) + StringBuf_Printf(&buf, msg_txt(55), map[map_id].name); // 1 player found in map '%s'. + else + StringBuf_Printf(&buf, msg_txt(56), count, map[map_id].name); // %d players found in map '%s'. + } + clif_displaymessage(fd, StringBuf_Value(&buf)); + StringBuf_Destroy(&buf); + return 0; } /*========================================== @@ -711,85 +718,83 @@ ACMD_FUNC(who) *------------------------------------------*/ ACMD_FUNC(whogm) { - struct map_session_data* pl_sd; - struct s_mapiterator* iter; - int j, count; - int pl_level, level; - char match_text[CHAT_SIZE_MAX]; - char player_name[NAME_LENGTH]; - struct guild *g; - struct party_data *p; - - nullpo_retr(-1, sd); - - memset(atcmd_output, '\0', sizeof(atcmd_output)); - memset(match_text, '\0', sizeof(match_text)); - memset(player_name, '\0', sizeof(player_name)); - - if (sscanf(message, "%199[^\n]", match_text) < 1) - strcpy(match_text, ""); - for (j = 0; match_text[j]; j++) - match_text[j] = TOLOWER(match_text[j]); - - count = 0; - level = pc_get_group_level(sd); - - iter = mapit_getallusers(); - for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) ) - { - pl_level = pc_get_group_level(pl_sd); - if (!pl_level) - continue; - - if (match_text[0]) - { - memcpy(player_name, pl_sd->status.name, NAME_LENGTH); - for (j = 0; player_name[j]; j++) - player_name[j] = TOLOWER(player_name[j]); - // search with no case sensitive - if (strstr(player_name, match_text) == NULL) - continue; - } - if (pl_level > level) { - if (pl_sd->sc.option & OPTION_INVISIBLE) - continue; - sprintf(atcmd_output, msg_txt(913), pl_sd->status.name); // Name: %s (GM) - clif_displaymessage(fd, atcmd_output); - count++; - continue; - } - - sprintf(atcmd_output, msg_txt(914), // Name: %s (GM:%d) | Location: %s %d %d - pl_sd->status.name, pl_level, - mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); - clif_displaymessage(fd, atcmd_output); - - sprintf(atcmd_output, msg_txt(915), // BLvl: %d | Job: %s (Lvl: %d) - pl_sd->status.base_level, - job_name(pl_sd->status.class_), pl_sd->status.job_level); - clif_displaymessage(fd, atcmd_output); - - p = party_search(pl_sd->status.party_id); - g = guild_search(pl_sd->status.guild_id); - - sprintf(atcmd_output,msg_txt(916), // Party: '%s' | Guild: '%s' - p?p->party.name:msg_txt(917), g?g->name:msg_txt(917)); // None. - - clif_displaymessage(fd, atcmd_output); - count++; - } - mapit_free(iter); - - if (count == 0) - clif_displaymessage(fd, msg_txt(150)); // No GM found. - else if (count == 1) - clif_displaymessage(fd, msg_txt(151)); // 1 GM found. - else { - sprintf(atcmd_output, msg_txt(152), count); // %d GMs found. - clif_displaymessage(fd, atcmd_output); - } - - return 0; + struct map_session_data *pl_sd; + struct s_mapiterator *iter; + int j, count; + int pl_level, level; + char match_text[CHAT_SIZE_MAX]; + char player_name[NAME_LENGTH]; + struct guild *g; + struct party_data *p; + + nullpo_retr(-1, sd); + + memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(match_text, '\0', sizeof(match_text)); + memset(player_name, '\0', sizeof(player_name)); + + if (sscanf(message, "%199[^\n]", match_text) < 1) + strcpy(match_text, ""); + for (j = 0; match_text[j]; j++) + match_text[j] = TOLOWER(match_text[j]); + + count = 0; + level = pc_get_group_level(sd); + + iter = mapit_getallusers(); + for (pl_sd = (TBL_PC *)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC *)mapit_next(iter)) { + pl_level = pc_get_group_level(pl_sd); + if (!pl_level) + continue; + + if (match_text[0]) { + memcpy(player_name, pl_sd->status.name, NAME_LENGTH); + for (j = 0; player_name[j]; j++) + player_name[j] = TOLOWER(player_name[j]); + // search with no case sensitive + if (strstr(player_name, match_text) == NULL) + continue; + } + if (pl_level > level) { + if (pl_sd->sc.option & OPTION_INVISIBLE) + continue; + sprintf(atcmd_output, msg_txt(913), pl_sd->status.name); // Name: %s (GM) + clif_displaymessage(fd, atcmd_output); + count++; + continue; + } + + sprintf(atcmd_output, msg_txt(914), // Name: %s (GM:%d) | Location: %s %d %d + pl_sd->status.name, pl_level, + mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); + clif_displaymessage(fd, atcmd_output); + + sprintf(atcmd_output, msg_txt(915), // BLvl: %d | Job: %s (Lvl: %d) + pl_sd->status.base_level, + job_name(pl_sd->status.class_), pl_sd->status.job_level); + clif_displaymessage(fd, atcmd_output); + + p = party_search(pl_sd->status.party_id); + g = guild_search(pl_sd->status.guild_id); + + sprintf(atcmd_output,msg_txt(916), // Party: '%s' | Guild: '%s' + p?p->party.name:msg_txt(917), g?g->name:msg_txt(917)); // None. + + clif_displaymessage(fd, atcmd_output); + count++; + } + mapit_free(iter); + + if (count == 0) + clif_displaymessage(fd, msg_txt(150)); // No GM found. + else if (count == 1) + clif_displaymessage(fd, msg_txt(151)); // 1 GM found. + else { + sprintf(atcmd_output, msg_txt(152), count); // %d GMs found. + clif_displaymessage(fd, atcmd_output); + } + + return 0; } /*========================================== @@ -797,17 +802,17 @@ ACMD_FUNC(whogm) *------------------------------------------*/ ACMD_FUNC(save) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - pc_setsavepoint(sd, sd->mapindex, sd->bl.x, sd->bl.y); - if (sd->status.pet_id > 0 && sd->pd) - intif_save_petdata(sd->status.account_id, &sd->pd->pet); + pc_setsavepoint(sd, sd->mapindex, sd->bl.x, sd->bl.y); + if (sd->status.pet_id > 0 && sd->pd) + intif_save_petdata(sd->status.account_id, &sd->pd->pet); - chrif_save(sd,0); + chrif_save(sd,0); - clif_displaymessage(fd, msg_txt(6)); // Your save point has been changed. + clif_displaymessage(fd, msg_txt(6)); // Your save point has been changed. - return 0; + return 0; } /*========================================== @@ -815,24 +820,24 @@ ACMD_FUNC(save) *------------------------------------------*/ ACMD_FUNC(load) { - int m; + int m; - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - m = map_mapindex2mapid(sd->status.save_point.map); - if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(249)); // You are not authorized to warp to your save map. - return -1; - } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. - return -1; - } + m = map_mapindex2mapid(sd->status.save_point.map); + if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(249)); // You are not authorized to warp to your save map. + return -1; + } + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. + return -1; + } - pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_OUTSIGHT); - clif_displaymessage(fd, msg_txt(7)); // Warping to save point.. + pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_OUTSIGHT); + clif_displaymessage(fd, msg_txt(7)); // Warping to save point.. - return 0; + return 0; } /*========================================== @@ -840,22 +845,22 @@ ACMD_FUNC(load) *------------------------------------------*/ ACMD_FUNC(speed) { - int speed; + int speed; - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!message || !*message || sscanf(message, "%d", &speed) < 1) { - sprintf(atcmd_output, msg_txt(918), MIN_WALK_SPEED, MAX_WALK_SPEED); // Please enter a speed value (usage: @speed <%d-%d>). - clif_displaymessage(fd, atcmd_output); - return -1; - } + if (!message || !*message || sscanf(message, "%d", &speed) < 1) { + sprintf(atcmd_output, msg_txt(918), MIN_WALK_SPEED, MAX_WALK_SPEED); // Please enter a speed value (usage: @speed <%d-%d>). + clif_displaymessage(fd, atcmd_output); + return -1; + } - sd->base_status.speed = cap_value(speed, MIN_WALK_SPEED, MAX_WALK_SPEED); - status_calc_bl(&sd->bl, SCB_SPEED); - clif_displaymessage(fd, msg_txt(8)); // Speed changed. - return 0; + sd->base_status.speed = cap_value(speed, MIN_WALK_SPEED, MAX_WALK_SPEED); + status_calc_bl(&sd->bl, SCB_SPEED); + clif_displaymessage(fd, msg_txt(8)); // Speed changed. + return 0; } /*========================================== @@ -863,20 +868,20 @@ ACMD_FUNC(speed) *------------------------------------------*/ ACMD_FUNC(storage) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading || sd->state.storage_flag) - return -1; + if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading || sd->state.storage_flag) + return -1; - if (storage_storageopen(sd) == 1) - { //Already open. - clif_displaymessage(fd, msg_txt(250)); - return -1; - } + if (storage_storageopen(sd) == 1) { + //Already open. + clif_displaymessage(fd, msg_txt(250)); + return -1; + } - clif_displaymessage(fd, msg_txt(919)); // Storage opened. + clif_displaymessage(fd, msg_txt(919)); // Storage opened. - return 0; + return 0; } @@ -885,29 +890,29 @@ ACMD_FUNC(storage) *------------------------------------------*/ ACMD_FUNC(guildstorage) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (!sd->status.guild_id) { - clif_displaymessage(fd, msg_txt(252)); - return -1; - } + if (!sd->status.guild_id) { + clif_displaymessage(fd, msg_txt(252)); + return -1; + } - if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading) - return -1; + if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading) + return -1; - if (sd->state.storage_flag == 1) { - clif_displaymessage(fd, msg_txt(250)); - return -1; - } + if (sd->state.storage_flag == 1) { + clif_displaymessage(fd, msg_txt(250)); + return -1; + } - if (sd->state.storage_flag == 2) { - clif_displaymessage(fd, msg_txt(251)); - return -1; - } + if (sd->state.storage_flag == 2) { + clif_displaymessage(fd, msg_txt(251)); + return -1; + } - storage_guild_storageopen(sd); - clif_displaymessage(fd, msg_txt(920)); // Guild storage opened. - return 0; + storage_guild_storageopen(sd); + clif_displaymessage(fd, msg_txt(920)); // Guild storage opened. + return 0; } /*========================================== @@ -915,34 +920,34 @@ ACMD_FUNC(guildstorage) *------------------------------------------*/ ACMD_FUNC(option) { - int param1 = 0, param2 = 0, param3 = 0; - nullpo_retr(-1, sd); + int param1 = 0, param2 = 0, param3 = 0; + nullpo_retr(-1, sd); - if (!message || !*message || sscanf(message, "%d %d %d", ¶m1, ¶m2, ¶m3) < 1 || param1 < 0 || param2 < 0 || param3 < 0) - {// failed to match the parameters so inform the user of the options - const char* text = NULL; + if (!message || !*message || sscanf(message, "%d %d %d", ¶m1, ¶m2, ¶m3) < 1 || param1 < 0 || param2 < 0 || param3 < 0) { + // failed to match the parameters so inform the user of the options + const char *text = NULL; - // attempt to find the setting information for this command - text = atcommand_help_string( command ); + // attempt to find the setting information for this command + text = atcommand_help_string(command); - // notify the user of the requirement to enter an option - clif_displaymessage(fd, msg_txt(921)); // Please enter at least one option. + // notify the user of the requirement to enter an option + clif_displaymessage(fd, msg_txt(921)); // Please enter at least one option. - if( text ) - {// send the help text associated with this command - clif_displaymessage( fd, text ); - } + if (text) { + // send the help text associated with this command + clif_displaymessage(fd, text); + } - return -1; - } + return -1; + } - sd->sc.opt1 = param1; - sd->sc.opt2 = param2; - pc_setoption(sd, param3); + sd->sc.opt1 = param1; + sd->sc.opt2 = param2; + pc_setoption(sd, param3); - clif_displaymessage(fd, msg_txt(9)); // Options changed. + clif_displaymessage(fd, msg_txt(9)); // Options changed. - return 0; + return 0; } /*========================================== @@ -950,41 +955,41 @@ ACMD_FUNC(option) *------------------------------------------*/ ACMD_FUNC(hide) { - nullpo_retr(-1, sd); - if (sd->sc.option & OPTION_INVISIBLE) { - sd->sc.option &= ~OPTION_INVISIBLE; - if (sd->disguise) - status_set_viewdata(&sd->bl, sd->disguise); - else - status_set_viewdata(&sd->bl, sd->status.class_); - clif_displaymessage(fd, msg_txt(10)); // Invisible: Off + nullpo_retr(-1, sd); + if (sd->sc.option & OPTION_INVISIBLE) { + sd->sc.option &= ~OPTION_INVISIBLE; + if (sd->disguise) + status_set_viewdata(&sd->bl, sd->disguise); + else + status_set_viewdata(&sd->bl, sd->status.class_); + clif_displaymessage(fd, msg_txt(10)); // Invisible: Off - // increment the number of pvp players on the map - map[sd->bl.m].users_pvp++; + // increment the number of pvp players on the map + map[sd->bl.m].users_pvp++; - if( map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank ) - {// register the player for ranking calculations - sd->pvp_timer = add_timer( gettick() + 200, pc_calc_pvprank_timer, sd->bl.id, 0 ); - } - //bugreport:2266 - map_foreachinmovearea(clif_insight, &sd->bl, AREA_SIZE, sd->bl.x, sd->bl.y, BL_ALL, &sd->bl); - } else { - sd->sc.option |= OPTION_INVISIBLE; - sd->vd.class_ = INVISIBLE_CLASS; - clif_displaymessage(fd, msg_txt(11)); // Invisible: On + if (map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank) { + // register the player for ranking calculations + sd->pvp_timer = add_timer(gettick() + 200, pc_calc_pvprank_timer, sd->bl.id, 0); + } + //bugreport:2266 + map_foreachinmovearea(clif_insight, &sd->bl, AREA_SIZE, sd->bl.x, sd->bl.y, BL_ALL, &sd->bl); + } else { + sd->sc.option |= OPTION_INVISIBLE; + sd->vd.class_ = INVISIBLE_CLASS; + clif_displaymessage(fd, msg_txt(11)); // Invisible: On - // decrement the number of pvp players on the map - map[sd->bl.m].users_pvp--; + // decrement the number of pvp players on the map + map[sd->bl.m].users_pvp--; - if( map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank && sd->pvp_timer != INVALID_TIMER ) - {// unregister the player for ranking - delete_timer( sd->pvp_timer, pc_calc_pvprank_timer ); - sd->pvp_timer = INVALID_TIMER; - } - } - clif_changeoption(&sd->bl); + if (map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank && sd->pvp_timer != INVALID_TIMER) { + // unregister the player for ranking + delete_timer(sd->pvp_timer, pc_calc_pvprank_timer); + sd->pvp_timer = INVALID_TIMER; + } + } + clif_changeoption(&sd->bl); - return 0; + return 0; } /*========================================== @@ -992,183 +997,185 @@ ACMD_FUNC(hide) *------------------------------------------*/ ACMD_FUNC(jobchange) { - //FIXME: redundancy, potentially wrong code, should use job_name() or similar instead of hardcoding the table [ultramage] - int job = 0, upper = 0; - const char* text; - nullpo_retr(-1, sd); - - if (!message || !*message || sscanf(message, "%d %d", &job, &upper) < 1) - { - int i, found = 0; - const struct { char name[24]; int id; } jobs[] = { - { "novice", 0 }, - { "swordman", 1 }, - { "swordsman", 1 }, - { "magician", 2 }, - { "mage", 2 }, - { "archer", 3 }, - { "acolyte", 4 }, - { "merchant", 5 }, - { "thief", 6 }, - { "knight", 7 }, - { "priest", 8 }, - { "priestess", 8 }, - { "wizard", 9 }, - { "blacksmith", 10 }, - { "hunter", 11 }, - { "assassin", 12 }, - { "crusader", 14 }, - { "monk", 15 }, - { "sage", 16 }, - { "rogue", 17 }, - { "alchemist", 18 }, - { "bard", 19 }, - { "dancer", 20 }, - { "super novice", 23 }, - { "supernovice", 23 }, - { "gunslinger", 24 }, - { "gunner", 24 }, - { "ninja", 25 }, - { "novice high", 4001 }, - { "high novice", 4001 }, - { "swordman high", 4002 }, - { "swordsman high", 4002 }, - { "magician high", 4003 }, - { "mage high", 4003 }, - { "archer high", 4004 }, - { "acolyte high", 4005 }, - { "merchant high", 4006 }, - { "thief high", 4007 }, - { "lord knight", 4008 }, - { "high priest", 4009 }, - { "high priestess", 4009 }, - { "high wizard", 4010 }, - { "whitesmith", 4011 }, - { "sniper", 4012 }, - { "assassin cross", 4013 }, - { "paladin", 4015 }, - { "champion", 4016 }, - { "professor", 4017 }, - { "stalker", 4018 }, - { "creator", 4019 }, - { "clown", 4020 }, - { "gypsy", 4021 }, - { "baby novice", 4023 }, - { "baby swordman", 4024 }, - { "baby swordsman", 4024 }, - { "baby magician", 4025 }, - { "baby mage", 4025 }, - { "baby archer", 4026 }, - { "baby acolyte", 4027 }, - { "baby merchant", 4028 }, - { "baby thief", 4029 }, - { "baby knight", 4030 }, - { "baby priest", 4031 }, - { "baby priestess", 4031 }, - { "baby wizard", 4032 }, - { "baby blacksmith",4033 }, - { "baby hunter", 4034 }, - { "baby assassin", 4035 }, - { "baby crusader", 4037 }, - { "baby monk", 4038 }, - { "baby sage", 4039 }, - { "baby rogue", 4040 }, - { "baby alchemist", 4041 }, - { "baby bard", 4042 }, - { "baby dancer", 4043 }, - { "super baby", 4045 }, - { "taekwon", 4046 }, - { "taekwon boy", 4046 }, - { "taekwon girl", 4046 }, - { "star gladiator", 4047 }, - { "soul linker", 4049 }, - { "gangsi", 4050 }, - { "bongun", 4050 }, - { "munak", 4050 }, - { "death knight", 4051 }, - { "dark collector", 4052 }, - { "rune knight", 4054 }, - { "warlock", 4055 }, - { "ranger", 4056 }, - { "arch bishop", 4057 }, - { "mechanic", 4058 }, - { "guillotine", 4059 }, - { "rune knight2", 4060 }, - { "warlock2", 4061 }, - { "ranger2", 4062 }, - { "arch bishop2", 4063 }, - { "mechanic2", 4064 }, - { "guillotine2", 4065 }, - { "royal guard", 4066 }, - { "sorcerer", 4067 }, - { "minstrel", 4068 }, - { "wanderer", 4069 }, - { "sura", 4070 }, - { "genetic", 4071 }, - { "shadow chaser", 4072 }, - { "royal guard2", 4073 }, - { "sorcerer2", 4074 }, - { "minstrel2", 4075 }, - { "wanderer2", 4076 }, - { "sura2", 4077 }, - { "genetic2", 4078 }, - { "shadow chaser2", 4079 }, - { "baby rune", 4096 }, - { "baby warlock", 4097 }, - { "baby ranger", 4098 }, - { "baby bishop", 4099 }, - { "baby mechanic", 4100 }, - { "baby cross", 4101 }, - { "baby guard", 4102 }, - { "baby sorcerer", 4103 }, - { "baby minstrel", 4104 }, - { "baby wanderer", 4105 }, - { "baby sura", 4106 }, - { "baby genetic", 4107 }, - { "baby chaser", 4108 }, - { "super novice e", 4190 }, - { "super baby e", 4191 }, - { "kagerou", 4211 }, - { "oboro", 4212 }, - }; - - for (i=0; i < ARRAYLENGTH(jobs); i++) { - if (strncmpi(message, jobs[i].name, 16) == 0) { - job = jobs[i].id; - upper = 0; - found = 1; - break; - } - } - - if (!found) { - text = atcommand_help_string(command); - if (text) clif_displaymessage(fd, text); - return -1; - } - } - - if (job == 13 || job == 21 || job == 22 || job == 26 || job == 27 || job == 4014 || job == 4022 || job == 4036 || job == 4044 || job == 4048 - || (job >= JOB_RUNE_KNIGHT2 && job <= JOB_MECHANIC_T2) || (job >= JOB_BABY_RUNE2 && job <= JOB_BABY_MECHANIC2) - ) // Deny direct transformation into dummy jobs - {clif_displaymessage(fd, msg_txt(923)); //"You can not change to this job by command." - return 0;} - - if (pcdb_checkid(job)) - { - if (pc_jobchange(sd, job, upper) == 0) - clif_displaymessage(fd, msg_txt(12)); // Your job has been changed. - else { - clif_displaymessage(fd, msg_txt(155)); // You are unable to change your job. - return -1; - } - } else { - text = atcommand_help_string(command); - if (text) clif_displaymessage(fd, text); - return -1; - } - - return 0; + //FIXME: redundancy, potentially wrong code, should use job_name() or similar instead of hardcoding the table [ultramage] + int job = 0, upper = 0; + const char *text; + nullpo_retr(-1, sd); + + if (!message || !*message || sscanf(message, "%d %d", &job, &upper) < 1) { + int i, found = 0; + const struct { + char name[24]; + int id; + } jobs[] = { + { "novice", 0 }, + { "swordman", 1 }, + { "swordsman", 1 }, + { "magician", 2 }, + { "mage", 2 }, + { "archer", 3 }, + { "acolyte", 4 }, + { "merchant", 5 }, + { "thief", 6 }, + { "knight", 7 }, + { "priest", 8 }, + { "priestess", 8 }, + { "wizard", 9 }, + { "blacksmith", 10 }, + { "hunter", 11 }, + { "assassin", 12 }, + { "crusader", 14 }, + { "monk", 15 }, + { "sage", 16 }, + { "rogue", 17 }, + { "alchemist", 18 }, + { "bard", 19 }, + { "dancer", 20 }, + { "super novice", 23 }, + { "supernovice", 23 }, + { "gunslinger", 24 }, + { "gunner", 24 }, + { "ninja", 25 }, + { "novice high", 4001 }, + { "high novice", 4001 }, + { "swordman high", 4002 }, + { "swordsman high", 4002 }, + { "magician high", 4003 }, + { "mage high", 4003 }, + { "archer high", 4004 }, + { "acolyte high", 4005 }, + { "merchant high", 4006 }, + { "thief high", 4007 }, + { "lord knight", 4008 }, + { "high priest", 4009 }, + { "high priestess", 4009 }, + { "high wizard", 4010 }, + { "whitesmith", 4011 }, + { "sniper", 4012 }, + { "assassin cross", 4013 }, + { "paladin", 4015 }, + { "champion", 4016 }, + { "professor", 4017 }, + { "stalker", 4018 }, + { "creator", 4019 }, + { "clown", 4020 }, + { "gypsy", 4021 }, + { "baby novice", 4023 }, + { "baby swordman", 4024 }, + { "baby swordsman", 4024 }, + { "baby magician", 4025 }, + { "baby mage", 4025 }, + { "baby archer", 4026 }, + { "baby acolyte", 4027 }, + { "baby merchant", 4028 }, + { "baby thief", 4029 }, + { "baby knight", 4030 }, + { "baby priest", 4031 }, + { "baby priestess", 4031 }, + { "baby wizard", 4032 }, + { "baby blacksmith",4033 }, + { "baby hunter", 4034 }, + { "baby assassin", 4035 }, + { "baby crusader", 4037 }, + { "baby monk", 4038 }, + { "baby sage", 4039 }, + { "baby rogue", 4040 }, + { "baby alchemist", 4041 }, + { "baby bard", 4042 }, + { "baby dancer", 4043 }, + { "super baby", 4045 }, + { "taekwon", 4046 }, + { "taekwon boy", 4046 }, + { "taekwon girl", 4046 }, + { "star gladiator", 4047 }, + { "soul linker", 4049 }, + { "gangsi", 4050 }, + { "bongun", 4050 }, + { "munak", 4050 }, + { "death knight", 4051 }, + { "dark collector", 4052 }, + { "rune knight", 4054 }, + { "warlock", 4055 }, + { "ranger", 4056 }, + { "arch bishop", 4057 }, + { "mechanic", 4058 }, + { "guillotine", 4059 }, + { "rune knight2", 4060 }, + { "warlock2", 4061 }, + { "ranger2", 4062 }, + { "arch bishop2", 4063 }, + { "mechanic2", 4064 }, + { "guillotine2", 4065 }, + { "royal guard", 4066 }, + { "sorcerer", 4067 }, + { "minstrel", 4068 }, + { "wanderer", 4069 }, + { "sura", 4070 }, + { "genetic", 4071 }, + { "shadow chaser", 4072 }, + { "royal guard2", 4073 }, + { "sorcerer2", 4074 }, + { "minstrel2", 4075 }, + { "wanderer2", 4076 }, + { "sura2", 4077 }, + { "genetic2", 4078 }, + { "shadow chaser2", 4079 }, + { "baby rune", 4096 }, + { "baby warlock", 4097 }, + { "baby ranger", 4098 }, + { "baby bishop", 4099 }, + { "baby mechanic", 4100 }, + { "baby cross", 4101 }, + { "baby guard", 4102 }, + { "baby sorcerer", 4103 }, + { "baby minstrel", 4104 }, + { "baby wanderer", 4105 }, + { "baby sura", 4106 }, + { "baby genetic", 4107 }, + { "baby chaser", 4108 }, + { "super novice e", 4190 }, + { "super baby e", 4191 }, + { "kagerou", 4211 }, + { "oboro", 4212 }, + }; + + for (i=0; i < ARRAYLENGTH(jobs); i++) { + if (strncmpi(message, jobs[i].name, 16) == 0) { + job = jobs[i].id; + upper = 0; + found = 1; + break; + } + } + + if (!found) { + text = atcommand_help_string(command); + if (text) clif_displaymessage(fd, text); + return -1; + } + } + + if (job == 13 || job == 21 || job == 22 || job == 26 || job == 27 || job == 4014 || job == 4022 || job == 4036 || job == 4044 || job == 4048 + || (job >= JOB_RUNE_KNIGHT2 && job <= JOB_MECHANIC_T2) || (job >= JOB_BABY_RUNE2 && job <= JOB_BABY_MECHANIC2) + ) { // Deny direct transformation into dummy jobs + clif_displaymessage(fd, msg_txt(923)); //"You can not change to this job by command." + return 0; + } + + if (pcdb_checkid(job)) { + if (pc_jobchange(sd, job, upper) == 0) + clif_displaymessage(fd, msg_txt(12)); // Your job has been changed. + else { + clif_displaymessage(fd, msg_txt(155)); // You are unable to change your job. + return -1; + } + } else { + text = atcommand_help_string(command); + if (text) clif_displaymessage(fd, text); + return -1; + } + + return 0; } /*========================================== @@ -1176,12 +1183,12 @@ ACMD_FUNC(jobchange) *------------------------------------------*/ ACMD_FUNC(kill) { - nullpo_retr(-1, sd); - status_kill(&sd->bl); - clif_displaymessage(sd->fd, msg_txt(13)); // A pity! You've died. - if (fd != sd->fd) - clif_displaymessage(fd, msg_txt(14)); // Character killed. - return 0; + nullpo_retr(-1, sd); + status_kill(&sd->bl); + clif_displaymessage(sd->fd, msg_txt(13)); // A pity! You've died. + if (fd != sd->fd) + clif_displaymessage(fd, msg_txt(14)); // Character killed. + return 0; } /*========================================== @@ -1189,15 +1196,14 @@ ACMD_FUNC(kill) *------------------------------------------*/ ACMD_FUNC(alive) { - nullpo_retr(-1, sd); - if (!status_revive(&sd->bl, 100, 100)) - { - clif_displaymessage(fd, msg_txt(667)); - return -1; - } - clif_skill_nodamage(&sd->bl,&sd->bl,ALL_RESURRECTION,4,1); - clif_displaymessage(fd, msg_txt(16)); // You've been revived! It's a miracle! - return 0; + nullpo_retr(-1, sd); + if (!status_revive(&sd->bl, 100, 100)) { + clif_displaymessage(fd, msg_txt(667)); + return -1; + } + clif_skill_nodamage(&sd->bl,&sd->bl,ALL_RESURRECTION,4,1); + clif_displaymessage(fd, msg_txt(16)); // You've been revived! It's a miracle! + return 0; } /*========================================== @@ -1205,35 +1211,35 @@ ACMD_FUNC(alive) *------------------------------------------*/ ACMD_FUNC(kami) { - unsigned long color=0; - nullpo_retr(-1, sd); + unsigned long color=0; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if(*(command + 5) != 'c' && *(command + 5) != 'C') { - if (!message || !*message) { - clif_displaymessage(fd, msg_txt(980)); // Please enter a message (usage: @kami ). - return -1; - } + if (*(command + 5) != 'c' && *(command + 5) != 'C') { + if (!message || !*message) { + clif_displaymessage(fd, msg_txt(980)); // Please enter a message (usage: @kami ). + return -1; + } - sscanf(message, "%199[^\n]", atcmd_output); - if (strstr(command, "l") != NULL) - clif_broadcast(&sd->bl, atcmd_output, strlen(atcmd_output) + 1, 0, ALL_SAMEMAP); - else - intif_broadcast(atcmd_output, strlen(atcmd_output) + 1, (*(command + 5) == 'b' || *(command + 5) == 'B') ? 0x10 : 0); - } else { - if(!message || !*message || (sscanf(message, "%lx %199[^\n]", &color, atcmd_output) < 2)) { - clif_displaymessage(fd, msg_txt(981)); // Please enter color and message (usage: @kamic ). - return -1; - } + sscanf(message, "%199[^\n]", atcmd_output); + if (strstr(command, "l") != NULL) + clif_broadcast(&sd->bl, atcmd_output, strlen(atcmd_output) + 1, 0, ALL_SAMEMAP); + else + intif_broadcast(atcmd_output, strlen(atcmd_output) + 1, (*(command + 5) == 'b' || *(command + 5) == 'B') ? 0x10 : 0); + } else { + if (!message || !*message || (sscanf(message, "%lx %199[^\n]", &color, atcmd_output) < 2)) { + clif_displaymessage(fd, msg_txt(981)); // Please enter color and message (usage: @kamic ). + return -1; + } - if(color > 0xFFFFFF) { - clif_displaymessage(fd, msg_txt(982)); // Invalid color. - return -1; - } - intif_broadcast2(atcmd_output, strlen(atcmd_output) + 1, color, 0x190, 12, 0, 0); - } - return 0; + if (color > 0xFFFFFF) { + clif_displaymessage(fd, msg_txt(982)); // Invalid color. + return -1; + } + intif_broadcast2(atcmd_output, strlen(atcmd_output) + 1, color, 0x190, 12, 0, 0); + } + return 0; } /*========================================== @@ -1241,57 +1247,57 @@ ACMD_FUNC(kami) *------------------------------------------*/ ACMD_FUNC(heal) { - int hp = 0, sp = 0; // [Valaris] thanks to fov - nullpo_retr(-1, sd); - - sscanf(message, "%d %d", &hp, &sp); - - // some overflow checks - if( hp == INT_MIN ) hp++; - if( sp == INT_MIN ) sp++; - - if ( hp == 0 && sp == 0 ) { - if (!status_percent_heal(&sd->bl, 100, 100)) - clif_displaymessage(fd, msg_txt(157)); // HP and SP have already been recovered. - else - clif_displaymessage(fd, msg_txt(17)); // HP, SP recovered. - return 0; - } - - if ( hp > 0 && sp >= 0 ) { - if(!status_heal(&sd->bl, hp, sp, 0)) - clif_displaymessage(fd, msg_txt(157)); // HP and SP are already with the good value. - else - clif_displaymessage(fd, msg_txt(17)); // HP, SP recovered. - return 0; - } - - if ( hp < 0 && sp <= 0 ) { - status_damage(NULL, &sd->bl, -hp, -sp, 0, 0); - clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0, 4, 0); - clif_displaymessage(fd, msg_txt(156)); // HP or/and SP modified. - return 0; - } - - //Opposing signs. - if ( hp ) { - if (hp > 0) - status_heal(&sd->bl, hp, 0, 0); - else { - status_damage(NULL, &sd->bl, -hp, 0, 0, 0); - clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0, 4, 0); - } - } - - if ( sp ) { - if (sp > 0) - status_heal(&sd->bl, 0, sp, 0); - else - status_damage(NULL, &sd->bl, 0, -sp, 0, 0); - } - - clif_displaymessage(fd, msg_txt(156)); // HP or/and SP modified. - return 0; + int hp = 0, sp = 0; // [Valaris] thanks to fov + nullpo_retr(-1, sd); + + sscanf(message, "%d %d", &hp, &sp); + + // some overflow checks + if (hp == INT_MIN) hp++; + if (sp == INT_MIN) sp++; + + if (hp == 0 && sp == 0) { + if (!status_percent_heal(&sd->bl, 100, 100)) + clif_displaymessage(fd, msg_txt(157)); // HP and SP have already been recovered. + else + clif_displaymessage(fd, msg_txt(17)); // HP, SP recovered. + return 0; + } + + if (hp > 0 && sp >= 0) { + if (!status_heal(&sd->bl, hp, sp, 0)) + clif_displaymessage(fd, msg_txt(157)); // HP and SP are already with the good value. + else + clif_displaymessage(fd, msg_txt(17)); // HP, SP recovered. + return 0; + } + + if (hp < 0 && sp <= 0) { + status_damage(NULL, &sd->bl, -hp, -sp, 0, 0); + clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0, 4, 0); + clif_displaymessage(fd, msg_txt(156)); // HP or/and SP modified. + return 0; + } + + //Opposing signs. + if (hp) { + if (hp > 0) + status_heal(&sd->bl, hp, 0, 0); + else { + status_damage(NULL, &sd->bl, -hp, 0, 0, 0); + clif_damage(&sd->bl,&sd->bl, gettick(), 0, 0, -hp, 0, 4, 0); + } + } + + if (sp) { + if (sp > 0) + status_heal(&sd->bl, 0, sp, 0); + else + status_damage(NULL, &sd->bl, 0, -sp, 0, 0); + } + + clif_displaymessage(fd, msg_txt(156)); // HP or/and SP modified. + return 0; } /*========================================== @@ -1299,54 +1305,53 @@ ACMD_FUNC(heal) *------------------------------------------*/ ACMD_FUNC(item) { - char item_name[100]; - int number = 0, item_id, flag = 0; - struct item item_tmp; - struct item_data *item_data; - int get_count, i; - nullpo_retr(-1, sd); - - memset(item_name, '\0', sizeof(item_name)); - - if (!message || !*message || ( - sscanf(message, "\"%99[^\"]\" %d", item_name, &number) < 1 && - sscanf(message, "%99s %d", item_name, &number) < 1 - )) { - clif_displaymessage(fd, msg_txt(983)); // Please enter an item name or ID (usage: @item ). - return -1; - } - - if (number <= 0) - number = 1; - - if ((item_data = itemdb_searchname(item_name)) == NULL && - (item_data = itemdb_exists(atoi(item_name))) == NULL) - { - clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name. - return -1; - } - - item_id = item_data->nameid; - get_count = number; - //Check if it's stackable. - if (!itemdb_isstackable2(item_data)) - get_count = 1; - - for (i = 0; i < number; i += get_count) { - // if not pet egg - if (!pet_create_egg(sd, item_id)) { - memset(&item_tmp, 0, sizeof(item_tmp)); - item_tmp.nameid = item_id; - item_tmp.identify = 1; - - if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) - clif_additem(sd, 0, 0, flag); - } - } - - if (flag == 0) - clif_displaymessage(fd, msg_txt(18)); // Item created. - return 0; + char item_name[100]; + int number = 0, item_id, flag = 0; + struct item item_tmp; + struct item_data *item_data; + int get_count, i; + nullpo_retr(-1, sd); + + memset(item_name, '\0', sizeof(item_name)); + + if (!message || !*message || ( + sscanf(message, "\"%99[^\"]\" %d", item_name, &number) < 1 && + sscanf(message, "%99s %d", item_name, &number) < 1 + )) { + clif_displaymessage(fd, msg_txt(983)); // Please enter an item name or ID (usage: @item ). + return -1; + } + + if (number <= 0) + number = 1; + + if ((item_data = itemdb_searchname(item_name)) == NULL && + (item_data = itemdb_exists(atoi(item_name))) == NULL) { + clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name. + return -1; + } + + item_id = item_data->nameid; + get_count = number; + //Check if it's stackable. + if (!itemdb_isstackable2(item_data)) + get_count = 1; + + for (i = 0; i < number; i += get_count) { + // if not pet egg + if (!pet_create_egg(sd, item_id)) { + memset(&item_tmp, 0, sizeof(item_tmp)); + item_tmp.nameid = item_id; + item_tmp.identify = 1; + + if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) + clif_additem(sd, 0, 0, flag); + } + } + + if (flag == 0) + clif_displaymessage(fd, msg_txt(18)); // Item created. + return 0; } /*========================================== @@ -1354,76 +1359,76 @@ ACMD_FUNC(item) *------------------------------------------*/ ACMD_FUNC(item2) { - struct item item_tmp; - struct item_data *item_data; - char item_name[100]; - int item_id, number = 0; - int identify = 0, refine = 0, attr = 0; - int c1 = 0, c2 = 0, c3 = 0, c4 = 0; - int flag = 0; - int loop, get_count, i; - nullpo_retr(-1, sd); - - memset(item_name, '\0', sizeof(item_name)); - - if (!message || !*message || ( - sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 && - sscanf(message, "%99s %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 - )) { - clif_displaymessage(fd, msg_txt(984)); // Please enter all parameters (usage: @item2 - clif_displaymessage(fd, msg_txt(985)); // ). - return -1; - } - - if (number <= 0) - number = 1; - - item_id = 0; - if ((item_data = itemdb_searchname(item_name)) != NULL || - (item_data = itemdb_exists(atoi(item_name))) != NULL) - item_id = item_data->nameid; - - if (item_id > 500) { - loop = 1; - get_count = number; - if (item_data->type == IT_WEAPON || item_data->type == IT_ARMOR || - item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) { - loop = number; - get_count = 1; - if (item_data->type == IT_PETEGG) { - identify = 1; - refine = 0; - } - if (item_data->type == IT_PETARMOR) - refine = 0; - if (refine > MAX_REFINE) - refine = MAX_REFINE; - } else { - identify = 1; - refine = attr = 0; - } - for (i = 0; i < loop; i++) { - memset(&item_tmp, 0, sizeof(item_tmp)); - item_tmp.nameid = item_id; - item_tmp.identify = identify; - item_tmp.refine = refine; - item_tmp.attribute = attr; - item_tmp.card[0] = c1; - item_tmp.card[1] = c2; - item_tmp.card[2] = c3; - item_tmp.card[3] = c4; - if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) - clif_additem(sd, 0, 0, flag); - } - - if (flag == 0) - clif_displaymessage(fd, msg_txt(18)); // Item created. - } else { - clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name. - return -1; - } - - return 0; + struct item item_tmp; + struct item_data *item_data; + char item_name[100]; + int item_id, number = 0; + int identify = 0, refine = 0, attr = 0; + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + int flag = 0; + int loop, get_count, i; + nullpo_retr(-1, sd); + + memset(item_name, '\0', sizeof(item_name)); + + if (!message || !*message || ( + sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 && + sscanf(message, "%99s %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 + )) { + clif_displaymessage(fd, msg_txt(984)); // Please enter all parameters (usage: @item2 + clif_displaymessage(fd, msg_txt(985)); // ). + return -1; + } + + if (number <= 0) + number = 1; + + item_id = 0; + if ((item_data = itemdb_searchname(item_name)) != NULL || + (item_data = itemdb_exists(atoi(item_name))) != NULL) + item_id = item_data->nameid; + + if (item_id > 500) { + loop = 1; + get_count = number; + if (item_data->type == IT_WEAPON || item_data->type == IT_ARMOR || + item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) { + loop = number; + get_count = 1; + if (item_data->type == IT_PETEGG) { + identify = 1; + refine = 0; + } + if (item_data->type == IT_PETARMOR) + refine = 0; + if (refine > MAX_REFINE) + refine = MAX_REFINE; + } else { + identify = 1; + refine = attr = 0; + } + for (i = 0; i < loop; i++) { + memset(&item_tmp, 0, sizeof(item_tmp)); + item_tmp.nameid = item_id; + item_tmp.identify = identify; + item_tmp.refine = refine; + item_tmp.attribute = attr; + item_tmp.card[0] = c1; + item_tmp.card[1] = c2; + item_tmp.card[2] = c3; + item_tmp.card[3] = c4; + if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) + clif_additem(sd, 0, 0, flag); + } + + if (flag == 0) + clif_displaymessage(fd, msg_txt(18)); // Item created. + } else { + clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name. + return -1; + } + + return 0; } /*========================================== @@ -1431,17 +1436,17 @@ ACMD_FUNC(item2) *------------------------------------------*/ ACMD_FUNC(itemreset) { - int i; - nullpo_retr(-1, sd); + int i; + nullpo_retr(-1, sd); - for (i = 0; i < MAX_INVENTORY; i++) { - if (sd->status.inventory[i].amount && sd->status.inventory[i].equip == 0) { - pc_delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_COMMAND); - } - } - clif_displaymessage(fd, msg_txt(20)); // All of your items have been removed. + for (i = 0; i < MAX_INVENTORY; i++) { + if (sd->status.inventory[i].amount && sd->status.inventory[i].equip == 0) { + pc_delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_COMMAND); + } + } + clif_displaymessage(fd, msg_txt(20)); // All of your items have been removed. - return 0; + return 0; } /*========================================== @@ -1449,59 +1454,59 @@ ACMD_FUNC(itemreset) *------------------------------------------*/ ACMD_FUNC(baselevelup) { - int level=0, i=0, status_point=0; - nullpo_retr(-1, sd); - level = atoi(message); - - if (!message || !*message || !level) { - clif_displaymessage(fd, msg_txt(986)); // Please enter a level adjustment (usage: @lvup/@blevel/@baselvlup ). - return -1; - } - - if (level > 0) { - if (sd->status.base_level >= pc_maxbaselv(sd)) { // check for max level by Valaris - clif_displaymessage(fd, msg_txt(47)); // Base level can't go any higher. - return -1; - } // End Addition - if ((unsigned int)level > pc_maxbaselv(sd) || (unsigned int)level > pc_maxbaselv(sd) - sd->status.base_level) // fix positiv overflow - level = pc_maxbaselv(sd) - sd->status.base_level; - for (i = 0; i < level; i++) - status_point += pc_gets_status_point(sd->status.base_level + i); - - sd->status.status_point += status_point; - sd->status.base_level += (unsigned int)level; - status_percent_heal(&sd->bl, 100, 100); - clif_misceffect(&sd->bl, 0); - clif_displaymessage(fd, msg_txt(21)); // Base level raised. - } else { - if (sd->status.base_level == 1) { - clif_displaymessage(fd, msg_txt(158)); // Base level can't go any lower. - return -1; - } - level*=-1; - if ((unsigned int)level >= sd->status.base_level) - level = sd->status.base_level-1; - for (i = 0; i > -level; i--) - status_point += pc_gets_status_point(sd->status.base_level + i - 1); - if (sd->status.status_point < status_point) - pc_resetstate(sd); - if (sd->status.status_point < status_point) - sd->status.status_point = 0; - else - sd->status.status_point -= status_point; - sd->status.base_level -= (unsigned int)level; - clif_displaymessage(fd, msg_txt(22)); // Base level lowered. - } - sd->status.base_exp = 0; - clif_updatestatus(sd, SP_STATUSPOINT); - clif_updatestatus(sd, SP_BASELEVEL); - clif_updatestatus(sd, SP_BASEEXP); - clif_updatestatus(sd, SP_NEXTBASEEXP); - status_calc_pc(sd, 0); - pc_baselevelchanged(sd); - if(sd->status.party_id) - party_send_levelup(sd); - return 0; + int level=0, i=0, status_point=0; + nullpo_retr(-1, sd); + level = atoi(message); + + if (!message || !*message || !level) { + clif_displaymessage(fd, msg_txt(986)); // Please enter a level adjustment (usage: @lvup/@blevel/@baselvlup ). + return -1; + } + + if (level > 0) { + if (sd->status.base_level >= pc_maxbaselv(sd)) { // check for max level by Valaris + clif_displaymessage(fd, msg_txt(47)); // Base level can't go any higher. + return -1; + } // End Addition + if ((unsigned int)level > pc_maxbaselv(sd) || (unsigned int)level > pc_maxbaselv(sd) - sd->status.base_level) // fix positiv overflow + level = pc_maxbaselv(sd) - sd->status.base_level; + for (i = 0; i < level; i++) + status_point += pc_gets_status_point(sd->status.base_level + i); + + sd->status.status_point += status_point; + sd->status.base_level += (unsigned int)level; + status_percent_heal(&sd->bl, 100, 100); + clif_misceffect(&sd->bl, 0); + clif_displaymessage(fd, msg_txt(21)); // Base level raised. + } else { + if (sd->status.base_level == 1) { + clif_displaymessage(fd, msg_txt(158)); // Base level can't go any lower. + return -1; + } + level*=-1; + if ((unsigned int)level >= sd->status.base_level) + level = sd->status.base_level-1; + for (i = 0; i > -level; i--) + status_point += pc_gets_status_point(sd->status.base_level + i - 1); + if (sd->status.status_point < status_point) + pc_resetstate(sd); + if (sd->status.status_point < status_point) + sd->status.status_point = 0; + else + sd->status.status_point -= status_point; + sd->status.base_level -= (unsigned int)level; + clif_displaymessage(fd, msg_txt(22)); // Base level lowered. + } + sd->status.base_exp = 0; + clif_updatestatus(sd, SP_STATUSPOINT); + clif_updatestatus(sd, SP_BASELEVEL); + clif_updatestatus(sd, SP_BASEEXP); + clif_updatestatus(sd, SP_NEXTBASEEXP); + status_calc_pc(sd, 0); + pc_baselevelchanged(sd); + if (sd->status.party_id) + party_send_levelup(sd); + return 0; } /*========================================== @@ -1509,51 +1514,51 @@ ACMD_FUNC(baselevelup) *------------------------------------------*/ ACMD_FUNC(joblevelup) { - int level=0; - nullpo_retr(-1, sd); - - level = atoi(message); - - if (!message || !*message || !level) { - clif_displaymessage(fd, msg_txt(987)); // Please enter a level adjustment (usage: @joblvup/@jlevel/@joblvlup ). - return -1; - } - if (level > 0) { - if (sd->status.job_level >= pc_maxjoblv(sd)) { - clif_displaymessage(fd, msg_txt(23)); // Job level can't go any higher. - return -1; - } - if ((unsigned int)level > pc_maxjoblv(sd) || (unsigned int)level > pc_maxjoblv(sd) - sd->status.job_level) // fix positiv overflow - level = pc_maxjoblv(sd) - sd->status.job_level; - sd->status.job_level += (unsigned int)level; - sd->status.skill_point += level; - clif_misceffect(&sd->bl, 1); - clif_displaymessage(fd, msg_txt(24)); // Job level raised. - } else { - if (sd->status.job_level == 1) { - clif_displaymessage(fd, msg_txt(159)); // Job level can't go any lower. - return -1; - } - level *=-1; - if ((unsigned int)level >= sd->status.job_level) // fix negativ overflow - level = sd->status.job_level-1; - sd->status.job_level -= (unsigned int)level; - if (sd->status.skill_point < level) - pc_resetskill(sd,0); //Reset skills since we need to substract more points. - if (sd->status.skill_point < level) - sd->status.skill_point = 0; - else - sd->status.skill_point -= level; - clif_displaymessage(fd, msg_txt(25)); // Job level lowered. - } - sd->status.job_exp = 0; - clif_updatestatus(sd, SP_JOBLEVEL); - clif_updatestatus(sd, SP_JOBEXP); - clif_updatestatus(sd, SP_NEXTJOBEXP); - clif_updatestatus(sd, SP_SKILLPOINT); - status_calc_pc(sd, 0); - - return 0; + int level=0; + nullpo_retr(-1, sd); + + level = atoi(message); + + if (!message || !*message || !level) { + clif_displaymessage(fd, msg_txt(987)); // Please enter a level adjustment (usage: @joblvup/@jlevel/@joblvlup ). + return -1; + } + if (level > 0) { + if (sd->status.job_level >= pc_maxjoblv(sd)) { + clif_displaymessage(fd, msg_txt(23)); // Job level can't go any higher. + return -1; + } + if ((unsigned int)level > pc_maxjoblv(sd) || (unsigned int)level > pc_maxjoblv(sd) - sd->status.job_level) // fix positiv overflow + level = pc_maxjoblv(sd) - sd->status.job_level; + sd->status.job_level += (unsigned int)level; + sd->status.skill_point += level; + clif_misceffect(&sd->bl, 1); + clif_displaymessage(fd, msg_txt(24)); // Job level raised. + } else { + if (sd->status.job_level == 1) { + clif_displaymessage(fd, msg_txt(159)); // Job level can't go any lower. + return -1; + } + level *=-1; + if ((unsigned int)level >= sd->status.job_level) // fix negativ overflow + level = sd->status.job_level-1; + sd->status.job_level -= (unsigned int)level; + if (sd->status.skill_point < level) + pc_resetskill(sd,0); //Reset skills since we need to substract more points. + if (sd->status.skill_point < level) + sd->status.skill_point = 0; + else + sd->status.skill_point -= level; + clif_displaymessage(fd, msg_txt(25)); // Job level lowered. + } + sd->status.job_exp = 0; + clif_updatestatus(sd, SP_JOBLEVEL); + clif_updatestatus(sd, SP_JOBEXP); + clif_updatestatus(sd, SP_NEXTJOBEXP); + clif_updatestatus(sd, SP_SKILLPOINT); + status_calc_pc(sd, 0); + + return 0; } /*========================================== @@ -1561,116 +1566,116 @@ ACMD_FUNC(joblevelup) *------------------------------------------*/ ACMD_FUNC(help) { - config_setting_t *help; - const char *text = NULL; - const char *command_name = NULL; - char *default_command = "help"; - - nullpo_retr(-1, sd); - - help = config_lookup(&atcommand_config, "help"); - if (help == NULL) { - clif_displaymessage(fd, msg_txt(27)); // "Commands help is not available." - return -1; - } - - if (!message || !*message) { - command_name = default_command; // If no command_name specified, display help for @help. - } else { - if (*message == atcommand_symbol || *message == charcommand_symbol) - ++message; - command_name = atcommand_checkalias(message); - } - - if (!pc_can_use_command(sd, command_name, COMMAND_ATCOMMAND)) { - sprintf(atcmd_output, msg_txt(153), message); // "%s is Unknown Command" - clif_displaymessage(fd, atcmd_output); - atcommand_get_suggestions(sd, command_name, true); - return -1; - } - - if (!config_setting_lookup_string(help, command_name, &text)) { - sprintf(atcmd_output, msg_txt(988), atcommand_symbol, command_name); // There is no help for %c%s. - clif_displaymessage(fd, atcmd_output); - atcommand_get_suggestions(sd, command_name, true); - return -1; - } - - sprintf(atcmd_output, msg_txt(989), atcommand_symbol, command_name); // Help for command %c%s: - clif_displaymessage(fd, atcmd_output); - - { // Display aliases - DBIterator* iter; - AtCommandInfo *command_info; - AliasInfo *alias_info = NULL; - StringBuf buf; - bool has_aliases = false; - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, msg_txt(990)); // Available aliases: - command_info = get_atcommandinfo_byname(command_name); - iter = db_iterator(atcommand_alias_db); - for (alias_info = dbi_first(iter); dbi_exists(iter); alias_info = dbi_next(iter)) { - if (alias_info->command == command_info) { - StringBuf_Printf(&buf, " %s", alias_info->alias); - has_aliases = true; - } - } - dbi_destroy(iter); - if (has_aliases) - clif_displaymessage(fd, StringBuf_Value(&buf)); - StringBuf_Destroy(&buf); - } - - // Display help contents - clif_displaymessage(fd, text); - return 0; + config_setting_t *help; + const char *text = NULL; + const char *command_name = NULL; + char *default_command = "help"; + + nullpo_retr(-1, sd); + + help = config_lookup(&atcommand_config, "help"); + if (help == NULL) { + clif_displaymessage(fd, msg_txt(27)); // "Commands help is not available." + return -1; + } + + if (!message || !*message) { + command_name = default_command; // If no command_name specified, display help for @help. + } else { + if (*message == atcommand_symbol || *message == charcommand_symbol) + ++message; + command_name = atcommand_checkalias(message); + } + + if (!pc_can_use_command(sd, command_name, COMMAND_ATCOMMAND)) { + sprintf(atcmd_output, msg_txt(153), message); // "%s is Unknown Command" + clif_displaymessage(fd, atcmd_output); + atcommand_get_suggestions(sd, command_name, true); + return -1; + } + + if (!config_setting_lookup_string(help, command_name, &text)) { + sprintf(atcmd_output, msg_txt(988), atcommand_symbol, command_name); // There is no help for %c%s. + clif_displaymessage(fd, atcmd_output); + atcommand_get_suggestions(sd, command_name, true); + return -1; + } + + sprintf(atcmd_output, msg_txt(989), atcommand_symbol, command_name); // Help for command %c%s: + clif_displaymessage(fd, atcmd_output); + + { + // Display aliases + DBIterator *iter; + AtCommandInfo *command_info; + AliasInfo *alias_info = NULL; + StringBuf buf; + bool has_aliases = false; + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, msg_txt(990)); // Available aliases: + command_info = get_atcommandinfo_byname(command_name); + iter = db_iterator(atcommand_alias_db); + for (alias_info = dbi_first(iter); dbi_exists(iter); alias_info = dbi_next(iter)) { + if (alias_info->command == command_info) { + StringBuf_Printf(&buf, " %s", alias_info->alias); + has_aliases = true; + } + } + dbi_destroy(iter); + if (has_aliases) + clif_displaymessage(fd, StringBuf_Value(&buf)); + StringBuf_Destroy(&buf); + } + + // Display help contents + clif_displaymessage(fd, text); + return 0; } // helper function, used in foreach calls to stop auto-attack timers // parameter: '0' - everyone, 'id' - only those attacking someone with that id static int atcommand_stopattack(struct block_list *bl,va_list ap) { - struct unit_data *ud = unit_bl2ud(bl); - int id = va_arg(ap, int); - if (ud && ud->attacktimer != INVALID_TIMER && (!id || id == ud->target)) - { - unit_stop_attack(bl); - return 1; - } - return 0; + struct unit_data *ud = unit_bl2ud(bl); + int id = va_arg(ap, int); + if (ud && ud->attacktimer != INVALID_TIMER && (!id || id == ud->target)) { + unit_stop_attack(bl); + return 1; + } + return 0; } /*========================================== * *------------------------------------------*/ static int atcommand_pvpoff_sub(struct block_list *bl,va_list ap) { - TBL_PC* sd = (TBL_PC*)bl; - clif_pvpset(sd, 0, 0, 2); - if (sd->pvp_timer != INVALID_TIMER) { - delete_timer(sd->pvp_timer, pc_calc_pvprank_timer); - sd->pvp_timer = INVALID_TIMER; - } - return 0; + TBL_PC *sd = (TBL_PC *)bl; + clif_pvpset(sd, 0, 0, 2); + if (sd->pvp_timer != INVALID_TIMER) { + delete_timer(sd->pvp_timer, pc_calc_pvprank_timer); + sd->pvp_timer = INVALID_TIMER; + } + return 0; } ACMD_FUNC(pvpoff) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (!map[sd->bl.m].flag.pvp) { - clif_displaymessage(fd, msg_txt(160)); // PvP is already Off. - return -1; - } + if (!map[sd->bl.m].flag.pvp) { + clif_displaymessage(fd, msg_txt(160)); // PvP is already Off. + return -1; + } - map[sd->bl.m].flag.pvp = 0; + map[sd->bl.m].flag.pvp = 0; - if (!battle_config.pk_mode) - clif_map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING); - map_foreachinmap(atcommand_pvpoff_sub,sd->bl.m, BL_PC); - map_foreachinmap(atcommand_stopattack,sd->bl.m, BL_CHAR, 0); - clif_displaymessage(fd, msg_txt(31)); // PvP: Off. - return 0; + if (!battle_config.pk_mode) + clif_map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING); + map_foreachinmap(atcommand_pvpoff_sub,sd->bl.m, BL_PC); + map_foreachinmap(atcommand_stopattack,sd->bl.m, BL_CHAR, 0); + clif_displaymessage(fd, msg_txt(31)); // PvP: Off. + return 0; } /*========================================== @@ -1678,38 +1683,38 @@ ACMD_FUNC(pvpoff) *------------------------------------------*/ static int atcommand_pvpon_sub(struct block_list *bl,va_list ap) { - TBL_PC* sd = (TBL_PC*)bl; - if (sd->pvp_timer == INVALID_TIMER) { - sd->pvp_timer = add_timer(gettick() + 200, pc_calc_pvprank_timer, sd->bl.id, 0); - sd->pvp_rank = 0; - sd->pvp_lastusers = 0; - sd->pvp_point = 5; - sd->pvp_won = 0; - sd->pvp_lost = 0; - } - return 0; + TBL_PC *sd = (TBL_PC *)bl; + if (sd->pvp_timer == INVALID_TIMER) { + sd->pvp_timer = add_timer(gettick() + 200, pc_calc_pvprank_timer, sd->bl.id, 0); + sd->pvp_rank = 0; + sd->pvp_lastusers = 0; + sd->pvp_point = 5; + sd->pvp_won = 0; + sd->pvp_lost = 0; + } + return 0; } ACMD_FUNC(pvpon) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (map[sd->bl.m].flag.pvp) { - clif_displaymessage(fd, msg_txt(161)); // PvP is already On. - return -1; - } + if (map[sd->bl.m].flag.pvp) { + clif_displaymessage(fd, msg_txt(161)); // PvP is already On. + return -1; + } - map[sd->bl.m].flag.pvp = 1; + map[sd->bl.m].flag.pvp = 1; - if (!battle_config.pk_mode) - {// display pvp circle and rank - clif_map_property_mapall(sd->bl.m, MAPPROPERTY_FREEPVPZONE); - map_foreachinmap(atcommand_pvpon_sub,sd->bl.m, BL_PC); - } + if (!battle_config.pk_mode) { + // display pvp circle and rank + clif_map_property_mapall(sd->bl.m, MAPPROPERTY_FREEPVPZONE); + map_foreachinmap(atcommand_pvpon_sub,sd->bl.m, BL_PC); + } - clif_displaymessage(fd, msg_txt(32)); // PvP: On. + clif_displaymessage(fd, msg_txt(32)); // PvP: On. - return 0; + return 0; } /*========================================== @@ -1717,19 +1722,19 @@ ACMD_FUNC(pvpon) *------------------------------------------*/ ACMD_FUNC(gvgoff) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (!map[sd->bl.m].flag.gvg) { - clif_displaymessage(fd, msg_txt(162)); // GvG is already Off. - return -1; - } + if (!map[sd->bl.m].flag.gvg) { + clif_displaymessage(fd, msg_txt(162)); // GvG is already Off. + return -1; + } - map[sd->bl.m].flag.gvg = 0; - clif_map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING); - map_foreachinmap(atcommand_stopattack,sd->bl.m, BL_CHAR, 0); - clif_displaymessage(fd, msg_txt(33)); // GvG: Off. + map[sd->bl.m].flag.gvg = 0; + clif_map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING); + map_foreachinmap(atcommand_stopattack,sd->bl.m, BL_CHAR, 0); + clif_displaymessage(fd, msg_txt(33)); // GvG: Off. - return 0; + return 0; } /*========================================== @@ -1737,18 +1742,18 @@ ACMD_FUNC(gvgoff) *------------------------------------------*/ ACMD_FUNC(gvgon) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (map[sd->bl.m].flag.gvg) { - clif_displaymessage(fd, msg_txt(163)); // GvG is already On. - return -1; - } + if (map[sd->bl.m].flag.gvg) { + clif_displaymessage(fd, msg_txt(163)); // GvG is already On. + return -1; + } - map[sd->bl.m].flag.gvg = 1; - clif_map_property_mapall(sd->bl.m, MAPPROPERTY_AGITZONE); - clif_displaymessage(fd, msg_txt(34)); // GvG: On. + map[sd->bl.m].flag.gvg = 1; + clif_map_property_mapall(sd->bl.m, MAPPROPERTY_AGITZONE); + clif_displaymessage(fd, msg_txt(34)); // GvG: On. - return 0; + return 0; } /*========================================== @@ -1756,31 +1761,31 @@ ACMD_FUNC(gvgon) *------------------------------------------*/ ACMD_FUNC(model) { - int hair_style = 0, hair_color = 0, cloth_color = 0; - nullpo_retr(-1, sd); + int hair_style = 0, hair_color = 0, cloth_color = 0; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!message || !*message || sscanf(message, "%d %d %d", &hair_style, &hair_color, &cloth_color) < 1) { - sprintf(atcmd_output, msg_txt(991), // Please enter at least one value (usage: @model ). - MIN_HAIR_STYLE, MAX_HAIR_STYLE, MIN_HAIR_COLOR, MAX_HAIR_COLOR, MIN_CLOTH_COLOR, MAX_CLOTH_COLOR); - clif_displaymessage(fd, atcmd_output); - return -1; - } + if (!message || !*message || sscanf(message, "%d %d %d", &hair_style, &hair_color, &cloth_color) < 1) { + sprintf(atcmd_output, msg_txt(991), // Please enter at least one value (usage: @model ). + MIN_HAIR_STYLE, MAX_HAIR_STYLE, MIN_HAIR_COLOR, MAX_HAIR_COLOR, MIN_CLOTH_COLOR, MAX_CLOTH_COLOR); + clif_displaymessage(fd, atcmd_output); + return -1; + } - if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE && - hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR && - cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) { - pc_changelook(sd, LOOK_HAIR, hair_style); - pc_changelook(sd, LOOK_HAIR_COLOR, hair_color); - pc_changelook(sd, LOOK_CLOTHES_COLOR, cloth_color); - clif_displaymessage(fd, msg_txt(36)); // Appearence changed. - } else { - clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. - return -1; - } + if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE && + hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR && + cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) { + pc_changelook(sd, LOOK_HAIR, hair_style); + pc_changelook(sd, LOOK_HAIR_COLOR, hair_color); + pc_changelook(sd, LOOK_CLOTHES_COLOR, cloth_color); + clif_displaymessage(fd, msg_txt(36)); // Appearence changed. + } else { + clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. + return -1; + } - return 0; + return 0; } /*========================================== @@ -1788,26 +1793,26 @@ ACMD_FUNC(model) *------------------------------------------*/ ACMD_FUNC(dye) { - int cloth_color = 0; - nullpo_retr(-1, sd); + int cloth_color = 0; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!message || !*message || sscanf(message, "%d", &cloth_color) < 1) { - sprintf(atcmd_output, msg_txt(992), MIN_CLOTH_COLOR, MAX_CLOTH_COLOR); // Please enter a clothes color (usage: @dye/@ccolor ). - clif_displaymessage(fd, atcmd_output); - return -1; - } + if (!message || !*message || sscanf(message, "%d", &cloth_color) < 1) { + sprintf(atcmd_output, msg_txt(992), MIN_CLOTH_COLOR, MAX_CLOTH_COLOR); // Please enter a clothes color (usage: @dye/@ccolor ). + clif_displaymessage(fd, atcmd_output); + return -1; + } - if (cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) { - pc_changelook(sd, LOOK_CLOTHES_COLOR, cloth_color); - clif_displaymessage(fd, msg_txt(36)); // Appearence changed. - } else { - clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. - return -1; - } + if (cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) { + pc_changelook(sd, LOOK_CLOTHES_COLOR, cloth_color); + clif_displaymessage(fd, msg_txt(36)); // Appearence changed. + } else { + clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. + return -1; + } - return 0; + return 0; } /*========================================== @@ -1815,26 +1820,26 @@ ACMD_FUNC(dye) *------------------------------------------*/ ACMD_FUNC(hair_style) { - int hair_style = 0; - nullpo_retr(-1, sd); + int hair_style = 0; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!message || !*message || sscanf(message, "%d", &hair_style) < 1) { - sprintf(atcmd_output, msg_txt(993), MIN_HAIR_STYLE, MAX_HAIR_STYLE); // Please enter a hair style (usage: @hairstyle/@hstyle ). - clif_displaymessage(fd, atcmd_output); - return -1; - } + if (!message || !*message || sscanf(message, "%d", &hair_style) < 1) { + sprintf(atcmd_output, msg_txt(993), MIN_HAIR_STYLE, MAX_HAIR_STYLE); // Please enter a hair style (usage: @hairstyle/@hstyle ). + clif_displaymessage(fd, atcmd_output); + return -1; + } - if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE) { - pc_changelook(sd, LOOK_HAIR, hair_style); - clif_displaymessage(fd, msg_txt(36)); // Appearence changed. - } else { - clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. - return -1; - } + if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE) { + pc_changelook(sd, LOOK_HAIR, hair_style); + clif_displaymessage(fd, msg_txt(36)); // Appearence changed. + } else { + clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. + return -1; + } - return 0; + return 0; } /*========================================== @@ -1842,26 +1847,26 @@ ACMD_FUNC(hair_style) *------------------------------------------*/ ACMD_FUNC(hair_color) { - int hair_color = 0; - nullpo_retr(-1, sd); + int hair_color = 0; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!message || !*message || sscanf(message, "%d", &hair_color) < 1) { - sprintf(atcmd_output, msg_txt(994), MIN_HAIR_COLOR, MAX_HAIR_COLOR); // Please enter a hair color (usage: @haircolor/@hcolor ). - clif_displaymessage(fd, atcmd_output); - return -1; - } + if (!message || !*message || sscanf(message, "%d", &hair_color) < 1) { + sprintf(atcmd_output, msg_txt(994), MIN_HAIR_COLOR, MAX_HAIR_COLOR); // Please enter a hair color (usage: @haircolor/@hcolor ). + clif_displaymessage(fd, atcmd_output); + return -1; + } - if (hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR) { - pc_changelook(sd, LOOK_HAIR_COLOR, hair_color); - clif_displaymessage(fd, msg_txt(36)); // Appearence changed. - } else { - clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. - return -1; - } + if (hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR) { + pc_changelook(sd, LOOK_HAIR_COLOR, hair_color); + clif_displaymessage(fd, msg_txt(36)); // Appearence changed. + } else { + clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. + return -1; + } - return 0; + return 0; } /*========================================== @@ -1869,199 +1874,198 @@ ACMD_FUNC(hair_color) *------------------------------------------*/ ACMD_FUNC(go) { - int i; - int town; - char map_name[MAP_NAME_LENGTH]; - int m; - - const struct { - char map[MAP_NAME_LENGTH]; - int x, y; - } data[] = { - { MAP_PRONTERA, 156, 191 }, // 0=Prontera - { MAP_MORROC, 156, 93 }, // 1=Morroc - { MAP_GEFFEN, 119, 59 }, // 2=Geffen - { MAP_PAYON, 162, 233 }, // 3=Payon - { MAP_ALBERTA, 192, 147 }, // 4=Alberta + int i; + int town; + char map_name[MAP_NAME_LENGTH]; + int m; + + const struct { + char map[MAP_NAME_LENGTH]; + int x, y; + } data[] = { + { MAP_PRONTERA, 156, 191 }, // 0=Prontera + { MAP_MORROC, 156, 93 }, // 1=Morroc + { MAP_GEFFEN, 119, 59 }, // 2=Geffen + { MAP_PAYON, 162, 233 }, // 3=Payon + { MAP_ALBERTA, 192, 147 }, // 4=Alberta #ifdef RENEWAL - { MAP_IZLUDE, 128, 146 }, // 5=Izlude (Renewal) + { MAP_IZLUDE, 128, 146 }, // 5=Izlude (Renewal) #else - { MAP_IZLUDE, 128, 114 }, // 5=Izlude + { MAP_IZLUDE, 128, 114 }, // 5=Izlude #endif - { MAP_ALDEBARAN, 140, 131 }, // 6=Al de Baran - { MAP_LUTIE, 147, 134 }, // 7=Lutie - { MAP_COMODO, 209, 143 }, // 8=Comodo - { MAP_YUNO, 157, 51 }, // 9=Yuno - { MAP_AMATSU, 198, 84 }, // 10=Amatsu - { MAP_GONRYUN, 160, 120 }, // 11=Gonryun - { MAP_UMBALA, 89, 157 }, // 12=Umbala - { MAP_NIFLHEIM, 21, 153 }, // 13=Niflheim - { MAP_LOUYANG, 217, 40 }, // 14=Louyang - { MAP_NOVICE, 53, 111 }, // 15=Training Grounds - { MAP_JAIL, 23, 61 }, // 16=Prison - { MAP_JAWAII, 249, 127 }, // 17=Jawaii - { MAP_AYOTHAYA, 151, 117 }, // 18=Ayothaya - { MAP_EINBROCH, 64, 200 }, // 19=Einbroch - { MAP_LIGHTHALZEN, 158, 92 }, // 20=Lighthalzen - { MAP_EINBECH, 70, 95 }, // 21=Einbech - { MAP_HUGEL, 96, 145 }, // 22=Hugel - { MAP_RACHEL, 130, 110 }, // 23=Rachel - { MAP_VEINS, 216, 123 }, // 24=Veins - { MAP_MOSCOVIA, 223, 184 }, // 25=Moscovia - { MAP_MIDCAMP, 180, 240 }, // 26=Midgard Camp - { MAP_MANUK, 282, 138 }, // 27=Manuk - { MAP_SPLENDIDE, 197, 176 }, // 28=Splendide - { MAP_BRASILIS, 182, 239 }, // 29=Brasilis - { MAP_DICASTES, 198, 187 }, // 30=El Dicastes - { MAP_MORA, 44, 151 }, // 31=Mora - { MAP_DEWATA, 200, 180 }, // 32=Dewata - { MAP_MALANGDO, 140, 114 }, // 33=Malangdo Island - { MAP_MALAYA, 242, 211 }, // 34=Malaya Port - { MAP_ECLAGE, 110, 39 }, // 35=Eclage - }; - - nullpo_retr(-1, sd); - - if( map[sd->bl.m].flag.nogo && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE) ) { - clif_displaymessage(sd->fd,msg_txt(995)); // You cannot use @go on this map. - return 0; - } - - memset(map_name, '\0', sizeof(map_name)); - memset(atcmd_output, '\0', sizeof(atcmd_output)); - - // get the number - town = atoi(message); - - if (!message || !*message || sscanf(message, "%11s", map_name) < 1 || town < 0 || town >= ARRAYLENGTH(data)) - {// no value matched so send the list of locations - const char* text; - - // attempt to find the text help string - text = atcommand_help_string( command ); - - clif_displaymessage(fd, msg_txt(38)); // Invalid location number, or name. - - if( text ) - {// send the text to the client - clif_displaymessage( fd, text ); - } - - return -1; - } - - // get possible name of the city - map_name[MAP_NAME_LENGTH-1] = '\0'; - for (i = 0; map_name[i]; i++) - map_name[i] = TOLOWER(map_name[i]); - // try to identify the map name - if (strncmp(map_name, "prontera", 3) == 0) { - town = 0; - } else if (strncmp(map_name, "morocc", 4) == 0 || - strncmp(map_name, "morroc", 4) == 0) { - town = 1; - } else if (strncmp(map_name, "geffen", 3) == 0) { - town = 2; - } else if (strncmp(map_name, "payon", 3) == 0) { - town = 3; - } else if (strncmp(map_name, "alberta", 3) == 0) { - town = 4; - } else if (strncmp(map_name, "izlude", 3) == 0) { - town = 5; - } else if (strncmp(map_name, "aldebaran", 3) == 0) { - town = 6; - } else if (strncmp(map_name, "lutie", 3) == 0 || - strcmp(map_name, "christmas") == 0 || - strncmp(map_name, "xmas", 3) == 0 || - strncmp(map_name, "x-mas", 3) == 0) { - town = 7; - } else if (strncmp(map_name, "comodo", 3) == 0) { - town = 8; - } else if (strncmp(map_name, "juno", 3) == 0 || - strncmp(map_name, "yuno", 3) == 0) { - town = 9; - } else if (strncmp(map_name, "amatsu", 3) == 0) { - town = 10; - } else if (strncmp(map_name, "kunlun", 3) == 0 || - strncmp(map_name, "gonryun", 3) == 0) { - town = 11; - } else if (strncmp(map_name, "umbala", 3) == 0) { - town = 12; - } else if (strncmp(map_name, "niflheim", 3) == 0) { - town = 13; - } else if (strncmp(map_name, "louyang", 3) == 0) { - town = 14; - } else if (strncmp(map_name, "new_1-1", 3) == 0 || - strncmp(map_name, "startpoint", 3) == 0 || - strncmp(map_name, "beginning", 3) == 0) { - town = 15; - } else if (strncmp(map_name, "sec_pri", 3) == 0 || - strncmp(map_name, "prison", 3) == 0 || - strncmp(map_name, "jail", 3) == 0) { - town = 16; - } else if (strncmp(map_name, "jawaii", 3) == 0) { - town = 17; - } else if (strncmp(map_name, "ayothaya", 3) == 0) { - town = 18; - } else if (strncmp(map_name, "einbroch", 5) == 0) { - town = 19; - } else if (strncmp(map_name, "lighthalzen", 3) == 0) { - town = 20; - } else if (strncmp(map_name, "einbech", 5) == 0) { - town = 21; - } else if (strncmp(map_name, "hugel", 3) == 0) { - town = 22; - } else if (strncmp(map_name, "rachel", 3) == 0) { - town = 23; - } else if (strncmp(map_name, "veins", 3) == 0) { - town = 24; - } else if (strncmp(map_name, "moscovia", 3) == 0) { - town = 25; - } else if (strncmp(map_name, "mid_camp", 3) == 0) { - town = 26; - } else if (strncmp(map_name, "manuk", 3) == 0) { - town = 27; - } else if (strncmp(map_name, "splendide", 3) == 0) { - town = 28; - } else if (strncmp(map_name, "brasilis", 3) == 0) { - town = 29; - } else if (strncmp(map_name, "dicastes01", 3) == 0) { - town = 30; - } else if (strcmp(map_name, "mora") == 0) { - town = 31; - } else if (strncmp(map_name, "dewata", 3) == 0) { - town = 32; - } else if (strncmp(map_name, "malangdo", 5) == 0) { - town = 33; - } else if (strncmp(map_name, "malaya", 5) == 0) { - town = 34; - } else if (strncmp(map_name, "eclage", 3) == 0) { - town = 35; - } - - if (town >= 0 && town < ARRAYLENGTH(data)) - { - m = map_mapname2mapid(data[town].map); - if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(247)); - return -1; - } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(248)); - return -1; - } - if (pc_setpos(sd, mapindex_name2id(data[town].map), data[town].x, data[town].y, CLR_TELEPORT) == 0) { - clif_displaymessage(fd, msg_txt(0)); // Warped. - } else { - clif_displaymessage(fd, msg_txt(1)); // Map not found. - return -1; - } - } else { // if you arrive here, you have an error in town variable when reading of names - clif_displaymessage(fd, msg_txt(38)); // Invalid location number or name. - return -1; - } - - return 0; + { MAP_ALDEBARAN, 140, 131 }, // 6=Al de Baran + { MAP_LUTIE, 147, 134 }, // 7=Lutie + { MAP_COMODO, 209, 143 }, // 8=Comodo + { MAP_YUNO, 157, 51 }, // 9=Yuno + { MAP_AMATSU, 198, 84 }, // 10=Amatsu + { MAP_GONRYUN, 160, 120 }, // 11=Gonryun + { MAP_UMBALA, 89, 157 }, // 12=Umbala + { MAP_NIFLHEIM, 21, 153 }, // 13=Niflheim + { MAP_LOUYANG, 217, 40 }, // 14=Louyang + { MAP_NOVICE, 53, 111 }, // 15=Training Grounds + { MAP_JAIL, 23, 61 }, // 16=Prison + { MAP_JAWAII, 249, 127 }, // 17=Jawaii + { MAP_AYOTHAYA, 151, 117 }, // 18=Ayothaya + { MAP_EINBROCH, 64, 200 }, // 19=Einbroch + { MAP_LIGHTHALZEN, 158, 92 }, // 20=Lighthalzen + { MAP_EINBECH, 70, 95 }, // 21=Einbech + { MAP_HUGEL, 96, 145 }, // 22=Hugel + { MAP_RACHEL, 130, 110 }, // 23=Rachel + { MAP_VEINS, 216, 123 }, // 24=Veins + { MAP_MOSCOVIA, 223, 184 }, // 25=Moscovia + { MAP_MIDCAMP, 180, 240 }, // 26=Midgard Camp + { MAP_MANUK, 282, 138 }, // 27=Manuk + { MAP_SPLENDIDE, 197, 176 }, // 28=Splendide + { MAP_BRASILIS, 182, 239 }, // 29=Brasilis + { MAP_DICASTES, 198, 187 }, // 30=El Dicastes + { MAP_MORA, 44, 151 }, // 31=Mora + { MAP_DEWATA, 200, 180 }, // 32=Dewata + { MAP_MALANGDO, 140, 114 }, // 33=Malangdo Island + { MAP_MALAYA, 242, 211 }, // 34=Malaya Port + { MAP_ECLAGE, 110, 39 }, // 35=Eclage + }; + + nullpo_retr(-1, sd); + + if (map[sd->bl.m].flag.nogo && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(sd->fd,msg_txt(995)); // You cannot use @go on this map. + return 0; + } + + memset(map_name, '\0', sizeof(map_name)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); + + // get the number + town = atoi(message); + + if (!message || !*message || sscanf(message, "%11s", map_name) < 1 || town < 0 || town >= ARRAYLENGTH(data)) { + // no value matched so send the list of locations + const char *text; + + // attempt to find the text help string + text = atcommand_help_string(command); + + clif_displaymessage(fd, msg_txt(38)); // Invalid location number, or name. + + if (text) { + // send the text to the client + clif_displaymessage(fd, text); + } + + return -1; + } + + // get possible name of the city + map_name[MAP_NAME_LENGTH-1] = '\0'; + for (i = 0; map_name[i]; i++) + map_name[i] = TOLOWER(map_name[i]); + // try to identify the map name + if (strncmp(map_name, "prontera", 3) == 0) { + town = 0; + } else if (strncmp(map_name, "morocc", 4) == 0 || + strncmp(map_name, "morroc", 4) == 0) { + town = 1; + } else if (strncmp(map_name, "geffen", 3) == 0) { + town = 2; + } else if (strncmp(map_name, "payon", 3) == 0) { + town = 3; + } else if (strncmp(map_name, "alberta", 3) == 0) { + town = 4; + } else if (strncmp(map_name, "izlude", 3) == 0) { + town = 5; + } else if (strncmp(map_name, "aldebaran", 3) == 0) { + town = 6; + } else if (strncmp(map_name, "lutie", 3) == 0 || + strcmp(map_name, "christmas") == 0 || + strncmp(map_name, "xmas", 3) == 0 || + strncmp(map_name, "x-mas", 3) == 0) { + town = 7; + } else if (strncmp(map_name, "comodo", 3) == 0) { + town = 8; + } else if (strncmp(map_name, "juno", 3) == 0 || + strncmp(map_name, "yuno", 3) == 0) { + town = 9; + } else if (strncmp(map_name, "amatsu", 3) == 0) { + town = 10; + } else if (strncmp(map_name, "kunlun", 3) == 0 || + strncmp(map_name, "gonryun", 3) == 0) { + town = 11; + } else if (strncmp(map_name, "umbala", 3) == 0) { + town = 12; + } else if (strncmp(map_name, "niflheim", 3) == 0) { + town = 13; + } else if (strncmp(map_name, "louyang", 3) == 0) { + town = 14; + } else if (strncmp(map_name, "new_1-1", 3) == 0 || + strncmp(map_name, "startpoint", 3) == 0 || + strncmp(map_name, "beginning", 3) == 0) { + town = 15; + } else if (strncmp(map_name, "sec_pri", 3) == 0 || + strncmp(map_name, "prison", 3) == 0 || + strncmp(map_name, "jail", 3) == 0) { + town = 16; + } else if (strncmp(map_name, "jawaii", 3) == 0) { + town = 17; + } else if (strncmp(map_name, "ayothaya", 3) == 0) { + town = 18; + } else if (strncmp(map_name, "einbroch", 5) == 0) { + town = 19; + } else if (strncmp(map_name, "lighthalzen", 3) == 0) { + town = 20; + } else if (strncmp(map_name, "einbech", 5) == 0) { + town = 21; + } else if (strncmp(map_name, "hugel", 3) == 0) { + town = 22; + } else if (strncmp(map_name, "rachel", 3) == 0) { + town = 23; + } else if (strncmp(map_name, "veins", 3) == 0) { + town = 24; + } else if (strncmp(map_name, "moscovia", 3) == 0) { + town = 25; + } else if (strncmp(map_name, "mid_camp", 3) == 0) { + town = 26; + } else if (strncmp(map_name, "manuk", 3) == 0) { + town = 27; + } else if (strncmp(map_name, "splendide", 3) == 0) { + town = 28; + } else if (strncmp(map_name, "brasilis", 3) == 0) { + town = 29; + } else if (strncmp(map_name, "dicastes01", 3) == 0) { + town = 30; + } else if (strcmp(map_name, "mora") == 0) { + town = 31; + } else if (strncmp(map_name, "dewata", 3) == 0) { + town = 32; + } else if (strncmp(map_name, "malangdo", 5) == 0) { + town = 33; + } else if (strncmp(map_name, "malaya", 5) == 0) { + town = 34; + } else if (strncmp(map_name, "eclage", 3) == 0) { + town = 35; + } + + if (town >= 0 && town < ARRAYLENGTH(data)) { + m = map_mapname2mapid(data[town].map); + if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(247)); + return -1; + } + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(248)); + return -1; + } + if (pc_setpos(sd, mapindex_name2id(data[town].map), data[town].x, data[town].y, CLR_TELEPORT) == 0) { + clif_displaymessage(fd, msg_txt(0)); // Warped. + } else { + clif_displaymessage(fd, msg_txt(1)); // Map not found. + return -1; + } + } else { // if you arrive here, you have an error in town variable when reading of names + clif_displaymessage(fd, msg_txt(38)); // Invalid location number or name. + return -1; + } + + return 0; } /*========================================== @@ -2069,96 +2073,96 @@ ACMD_FUNC(go) *------------------------------------------*/ ACMD_FUNC(monster) { - char name[NAME_LENGTH]; - char monster[NAME_LENGTH]; - char eventname[EVENT_NAME_LENGTH] = ""; - int mob_id; - int number = 0; - int count; - int i, k, range; - short mx, my; - unsigned int size; - nullpo_retr(-1, sd); - - memset(name, '\0', sizeof(name)); - memset(monster, '\0', sizeof(monster)); - memset(atcmd_output, '\0', sizeof(atcmd_output)); - - if (!message || !*message) { - clif_displaymessage(fd, msg_txt(80)); // Give the display name or monster name/id please. - return -1; - } - if (sscanf(message, "\"%23[^\"]\" %23s %d", name, monster, &number) > 1 || - sscanf(message, "%23s \"%23[^\"]\" %d", monster, name, &number) > 1) { - //All data can be left as it is. - } else if ((count=sscanf(message, "%23s %d %23s", monster, &number, name)) > 1) { - //Here, it is possible name was not given and we are using monster for it. - if (count < 3) //Blank mob's name. - name[0] = '\0'; - } else if (sscanf(message, "%23s %23s %d", name, monster, &number) > 1) { - //All data can be left as it is. - } else if (sscanf(message, "%23s", monster) > 0) { - //As before, name may be already filled. - name[0] = '\0'; - } else { - clif_displaymessage(fd, msg_txt(80)); // Give a display name and monster name/id please. - return -1; - } - - if ((mob_id = mobdb_searchname(monster)) == 0) // check name first (to avoid possible name begining by a number) - mob_id = mobdb_checkid(atoi(monster)); - - if (mob_id == 0) { - clif_displaymessage(fd, msg_txt(40)); // Invalid monster ID or name. - return -1; - } - - if (mob_id == MOBID_EMPERIUM) { - clif_displaymessage(fd, msg_txt(83)); // Monster 'Emperium' cannot be spawned. - return -1; - } - - if (number <= 0) - number = 1; - - if( !name[0] ) - strcpy(name, "--ja--"); - - // If value of atcommand_spawn_quantity_limit directive is greater than or equal to 1 and quantity of monsters is greater than value of the directive - if (battle_config.atc_spawn_quantity_limit && number > battle_config.atc_spawn_quantity_limit) - number = battle_config.atc_spawn_quantity_limit; - - if (strcmp(command+1, "monstersmall") == 0) - size = SZ_MEDIUM; // This is just gorgeous [mkbu95] - else if (strcmp(command+1, "monsterbig") == 0) - size = SZ_BIG; - else - size = SZ_SMALL; - - if (battle_config.etc_log) - ShowInfo("%s monster='%s' name='%s' id=%d count=%d (%d,%d)\n", command, monster, name, mob_id, number, sd->bl.x, sd->bl.y); - - count = 0; - range = (int)sqrt((float)number) +2; // calculation of an odd number (+ 4 area around) - for (i = 0; i < number; i++) { - map_search_freecell(&sd->bl, 0, &mx, &my, range, range, 0); - k = mob_once_spawn(sd, sd->bl.m, mx, my, name, mob_id, 1, eventname, size, AI_NONE); - count += (k != 0) ? 1 : 0; - } - - if (count != 0) - if (number == count) - clif_displaymessage(fd, msg_txt(39)); // All monster summoned! - else { - sprintf(atcmd_output, msg_txt(240), count); // %d monster(s) summoned! - clif_displaymessage(fd, atcmd_output); - } - else { - clif_displaymessage(fd, msg_txt(40)); // Invalid monster ID or name. - return -1; - } - - return 0; + char name[NAME_LENGTH]; + char monster[NAME_LENGTH]; + char eventname[EVENT_NAME_LENGTH] = ""; + int mob_id; + int number = 0; + int count; + int i, k, range; + short mx, my; + unsigned int size; + nullpo_retr(-1, sd); + + memset(name, '\0', sizeof(name)); + memset(monster, '\0', sizeof(monster)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); + + if (!message || !*message) { + clif_displaymessage(fd, msg_txt(80)); // Give the display name or monster name/id please. + return -1; + } + if (sscanf(message, "\"%23[^\"]\" %23s %d", name, monster, &number) > 1 || + sscanf(message, "%23s \"%23[^\"]\" %d", monster, name, &number) > 1) { + //All data can be left as it is. + } else if ((count=sscanf(message, "%23s %d %23s", monster, &number, name)) > 1) { + //Here, it is possible name was not given and we are using monster for it. + if (count < 3) //Blank mob's name. + name[0] = '\0'; + } else if (sscanf(message, "%23s %23s %d", name, monster, &number) > 1) { + //All data can be left as it is. + } else if (sscanf(message, "%23s", monster) > 0) { + //As before, name may be already filled. + name[0] = '\0'; + } else { + clif_displaymessage(fd, msg_txt(80)); // Give a display name and monster name/id please. + return -1; + } + + if ((mob_id = mobdb_searchname(monster)) == 0) // check name first (to avoid possible name begining by a number) + mob_id = mobdb_checkid(atoi(monster)); + + if (mob_id == 0) { + clif_displaymessage(fd, msg_txt(40)); // Invalid monster ID or name. + return -1; + } + + if (mob_id == MOBID_EMPERIUM) { + clif_displaymessage(fd, msg_txt(83)); // Monster 'Emperium' cannot be spawned. + return -1; + } + + if (number <= 0) + number = 1; + + if (!name[0]) + strcpy(name, "--ja--"); + + // If value of atcommand_spawn_quantity_limit directive is greater than or equal to 1 and quantity of monsters is greater than value of the directive + if (battle_config.atc_spawn_quantity_limit && number > battle_config.atc_spawn_quantity_limit) + number = battle_config.atc_spawn_quantity_limit; + + if (strcmp(command+1, "monstersmall") == 0) + size = SZ_MEDIUM; // This is just gorgeous [mkbu95] + else if (strcmp(command+1, "monsterbig") == 0) + size = SZ_BIG; + else + size = SZ_SMALL; + + if (battle_config.etc_log) + ShowInfo("%s monster='%s' name='%s' id=%d count=%d (%d,%d)\n", command, monster, name, mob_id, number, sd->bl.x, sd->bl.y); + + count = 0; + range = (int)sqrt((float)number) +2; // calculation of an odd number (+ 4 area around) + for (i = 0; i < number; i++) { + map_search_freecell(&sd->bl, 0, &mx, &my, range, range, 0); + k = mob_once_spawn(sd, sd->bl.m, mx, my, name, mob_id, 1, eventname, size, AI_NONE); + count += (k != 0) ? 1 : 0; + } + + if (count != 0) + if (number == count) + clif_displaymessage(fd, msg_txt(39)); // All monster summoned! + else { + sprintf(atcmd_output, msg_txt(240), count); // %d monster(s) summoned! + clif_displaymessage(fd, atcmd_output); + } + else { + clif_displaymessage(fd, msg_txt(40)); // Invalid monster ID or name. + return -1; + } + + return 0; } /*========================================== @@ -2166,44 +2170,44 @@ ACMD_FUNC(monster) *------------------------------------------*/ static int atkillmonster_sub(struct block_list *bl, va_list ap) { - struct mob_data *md; - int flag; + struct mob_data *md; + int flag; - nullpo_ret(md=(struct mob_data *)bl); - flag = va_arg(ap, int); + nullpo_ret(md=(struct mob_data *)bl); + flag = va_arg(ap, int); - if (md->guardian_data) - return 0; //Do not touch WoE mobs! + if (md->guardian_data) + return 0; //Do not touch WoE mobs! - if (flag) - status_zap(bl,md->status.hp, 0); - else - status_kill(bl); - return 1; + if (flag) + status_zap(bl,md->status.hp, 0); + else + status_kill(bl); + return 1; } ACMD_FUNC(killmonster) { - int map_id, drop_flag; - char map_name[MAP_NAME_LENGTH_EXT]; - nullpo_retr(-1, sd); + int map_id, drop_flag; + char map_name[MAP_NAME_LENGTH_EXT]; + nullpo_retr(-1, sd); - memset(map_name, '\0', sizeof(map_name)); + memset(map_name, '\0', sizeof(map_name)); - if (!message || !*message || sscanf(message, "%15s", map_name) < 1) - map_id = sd->bl.m; - else { - if ((map_id = map_mapname2mapid(map_name)) < 0) - map_id = sd->bl.m; - } + if (!message || !*message || sscanf(message, "%15s", map_name) < 1) + map_id = sd->bl.m; + else { + if ((map_id = map_mapname2mapid(map_name)) < 0) + map_id = sd->bl.m; + } - drop_flag = strcmp(command+1, "killmonster2"); + drop_flag = strcmp(command+1, "killmonster2"); - map_foreachinmap(atkillmonster_sub, map_id, BL_MOB, -drop_flag); + map_foreachinmap(atkillmonster_sub, map_id, BL_MOB, -drop_flag); - clif_displaymessage(fd, msg_txt(165)); // All monsters killed! + clif_displaymessage(fd, msg_txt(165)); // All monsters killed! - return 0; + return 0; } /*========================================== @@ -2211,77 +2215,77 @@ ACMD_FUNC(killmonster) *------------------------------------------*/ ACMD_FUNC(refine) { - int i,j, position = 0, refine = 0, current_position, final_refine; - int count; - nullpo_retr(-1, sd); - - memset(atcmd_output, '\0', sizeof(atcmd_output)); - - if (!message || !*message || sscanf(message, "%d %d", &position, &refine) < 2) { - clif_displaymessage(fd, msg_txt(996)); // Please enter a position and an amount (usage: @refine <+/- amount>). - sprintf(atcmd_output, msg_txt(997), EQP_HEAD_LOW); // %d: Lower Headgear - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(998), EQP_HAND_R); // %d: Right Hand - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(999), EQP_GARMENT); // %d: Garment - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1000), EQP_ACC_L); // %d: Left Accessory - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1001), EQP_ARMOR); // %d: Body Armor - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1002), EQP_HAND_L); // %d: Left Hand - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1003), EQP_SHOES); // %d: Shoes - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1004), EQP_ACC_R); // %d: Right Accessory - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1005), EQP_HEAD_TOP); // %d: Top Headgear - clif_displaymessage(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1006), EQP_HEAD_MID); // %d: Mid Headgear - clif_displaymessage(fd, atcmd_output); - return -1; - } - - refine = cap_value(refine, -MAX_REFINE, MAX_REFINE); - - count = 0; - for (j = 0; j < EQI_MAX-1; j++) { - if ((i = sd->equip_index[j]) < 0) - continue; - if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == i) - continue; - if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == i) - continue; - if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == i || sd->equip_index[EQI_HEAD_LOW] == i)) - continue; - - if(position && !(sd->status.inventory[i].equip & position)) - continue; - - final_refine = cap_value(sd->status.inventory[i].refine + refine, 0, MAX_REFINE); - if (sd->status.inventory[i].refine != final_refine) { - sd->status.inventory[i].refine = final_refine; - current_position = sd->status.inventory[i].equip; - pc_unequipitem(sd, i, 3); - clif_refine(fd, 0, i, sd->status.inventory[i].refine); - clif_delitem(sd, i, 1, 3); - clif_additem(sd, i, 1, 0); - pc_equipitem(sd, i, current_position); - clif_misceffect(&sd->bl, 3); - count++; - } - } - - if (count == 0) - clif_displaymessage(fd, msg_txt(166)); // No item has been refined. - else if (count == 1) - clif_displaymessage(fd, msg_txt(167)); // 1 item has been refined. - else { - sprintf(atcmd_output, msg_txt(168), count); // %d items have been refined. - clif_displaymessage(fd, atcmd_output); - } - - return 0; + int i,j, position = 0, refine = 0, current_position, final_refine; + int count; + nullpo_retr(-1, sd); + + memset(atcmd_output, '\0', sizeof(atcmd_output)); + + if (!message || !*message || sscanf(message, "%d %d", &position, &refine) < 2) { + clif_displaymessage(fd, msg_txt(996)); // Please enter a position and an amount (usage: @refine <+/- amount>). + sprintf(atcmd_output, msg_txt(997), EQP_HEAD_LOW); // %d: Lower Headgear + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(998), EQP_HAND_R); // %d: Right Hand + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(999), EQP_GARMENT); // %d: Garment + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1000), EQP_ACC_L); // %d: Left Accessory + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1001), EQP_ARMOR); // %d: Body Armor + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1002), EQP_HAND_L); // %d: Left Hand + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1003), EQP_SHOES); // %d: Shoes + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1004), EQP_ACC_R); // %d: Right Accessory + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1005), EQP_HEAD_TOP); // %d: Top Headgear + clif_displaymessage(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1006), EQP_HEAD_MID); // %d: Mid Headgear + clif_displaymessage(fd, atcmd_output); + return -1; + } + + refine = cap_value(refine, -MAX_REFINE, MAX_REFINE); + + count = 0; + for (j = 0; j < EQI_MAX-1; j++) { + if ((i = sd->equip_index[j]) < 0) + continue; + if (j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == i) + continue; + if (j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == i) + continue; + if (j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == i || sd->equip_index[EQI_HEAD_LOW] == i)) + continue; + + if (position && !(sd->status.inventory[i].equip & position)) + continue; + + final_refine = cap_value(sd->status.inventory[i].refine + refine, 0, MAX_REFINE); + if (sd->status.inventory[i].refine != final_refine) { + sd->status.inventory[i].refine = final_refine; + current_position = sd->status.inventory[i].equip; + pc_unequipitem(sd, i, 3); + clif_refine(fd, 0, i, sd->status.inventory[i].refine); + clif_delitem(sd, i, 1, 3); + clif_additem(sd, i, 1, 0); + pc_equipitem(sd, i, current_position); + clif_misceffect(&sd->bl, 3); + count++; + } + } + + if (count == 0) + clif_displaymessage(fd, msg_txt(166)); // No item has been refined. + else if (count == 1) + clif_displaymessage(fd, msg_txt(167)); // 1 item has been refined. + else { + sprintf(atcmd_output, msg_txt(168), count); // %d items have been refined. + clif_displaymessage(fd, atcmd_output); + } + + return 0; } /*========================================== @@ -2289,58 +2293,58 @@ ACMD_FUNC(refine) *------------------------------------------*/ ACMD_FUNC(produce) { - char item_name[100]; - int item_id, attribute = 0, star = 0; - int flag = 0; - struct item_data *item_data; - struct item tmp_item; - nullpo_retr(-1, sd); - - memset(atcmd_output, '\0', sizeof(atcmd_output)); - memset(item_name, '\0', sizeof(item_name)); - - if (!message || !*message || ( - sscanf(message, "\"%99[^\"]\" %d %d", item_name, &attribute, &star) < 1 && - sscanf(message, "%99s %d %d", item_name, &attribute, &star) < 1 - )) { - clif_displaymessage(fd, msg_txt(1007)); // Please enter at least one item name/ID (usage: @produce <# of very's>). - return -1; - } - - if ( (item_data = itemdb_searchname(item_name)) == NULL && - (item_data = itemdb_exists(atoi(item_name))) == NULL ) { - clif_displaymessage(fd, msg_txt(170)); //This item is not an equipment. - return -1; - } - - item_id = item_data->nameid; - - if (itemdb_isequip2(item_data)) { - if (attribute < MIN_ATTRIBUTE || attribute > MAX_ATTRIBUTE) - attribute = ATTRIBUTE_NORMAL; - if (star < MIN_STAR || star > MAX_STAR) - star = 0; - memset(&tmp_item, 0, sizeof tmp_item); - tmp_item.nameid = item_id; - tmp_item.amount = 1; - tmp_item.identify = 1; - tmp_item.card[0] = CARD0_FORGE; - tmp_item.card[1] = item_data->type==IT_WEAPON? - ((star*5) << 8) + attribute:0; - tmp_item.card[2] = GetWord(sd->status.char_id, 0); - tmp_item.card[3] = GetWord(sd->status.char_id, 1); - clif_produceeffect(sd, 0, item_id); - clif_misceffect(&sd->bl, 3); - - if ((flag = pc_additem(sd, &tmp_item, 1, LOG_TYPE_COMMAND))) - clif_additem(sd, 0, 0, flag); - } else { - sprintf(atcmd_output, msg_txt(169), item_id, item_data->name); // The item (%d: '%s') is not equipable. - clif_displaymessage(fd, atcmd_output); - return -1; - } - - return 0; + char item_name[100]; + int item_id, attribute = 0, star = 0; + int flag = 0; + struct item_data *item_data; + struct item tmp_item; + nullpo_retr(-1, sd); + + memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(item_name, '\0', sizeof(item_name)); + + if (!message || !*message || ( + sscanf(message, "\"%99[^\"]\" %d %d", item_name, &attribute, &star) < 1 && + sscanf(message, "%99s %d %d", item_name, &attribute, &star) < 1 + )) { + clif_displaymessage(fd, msg_txt(1007)); // Please enter at least one item name/ID (usage: @produce <# of very's>). + return -1; + } + + if ((item_data = itemdb_searchname(item_name)) == NULL && + (item_data = itemdb_exists(atoi(item_name))) == NULL) { + clif_displaymessage(fd, msg_txt(170)); //This item is not an equipment. + return -1; + } + + item_id = item_data->nameid; + + if (itemdb_isequip2(item_data)) { + if (attribute < MIN_ATTRIBUTE || attribute > MAX_ATTRIBUTE) + attribute = ATTRIBUTE_NORMAL; + if (star < MIN_STAR || star > MAX_STAR) + star = 0; + memset(&tmp_item, 0, sizeof tmp_item); + tmp_item.nameid = item_id; + tmp_item.amount = 1; + tmp_item.identify = 1; + tmp_item.card[0] = CARD0_FORGE; + tmp_item.card[1] = item_data->type==IT_WEAPON? + ((star*5) << 8) + attribute:0; + tmp_item.card[2] = GetWord(sd->status.char_id, 0); + tmp_item.card[3] = GetWord(sd->status.char_id, 1); + clif_produceeffect(sd, 0, item_id); + clif_misceffect(&sd->bl, 3); + + if ((flag = pc_additem(sd, &tmp_item, 1, LOG_TYPE_COMMAND))) + clif_additem(sd, 0, 0, flag); + } else { + sprintf(atcmd_output, msg_txt(169), item_id, item_data->name); // The item (%d: '%s') is not equipable. + clif_displaymessage(fd, atcmd_output); + return -1; + } + + return 0; } /*========================================== @@ -2348,35 +2352,32 @@ ACMD_FUNC(produce) *------------------------------------------*/ ACMD_FUNC(memo) { - int position = 0; - nullpo_retr(-1, sd); + int position = 0; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - if( !message || !*message || sscanf(message, "%d", &position) < 1 ) - { - int i; - clif_displaymessage(sd->fd, msg_txt(668)); - for( i = 0; i < MAX_MEMOPOINTS; i++ ) - { - if( sd->status.memo_point[i].map ) - sprintf(atcmd_output, "%d - %s (%d,%d)", i, mapindex_id2name(sd->status.memo_point[i].map), sd->status.memo_point[i].x, sd->status.memo_point[i].y); - else - sprintf(atcmd_output, msg_txt(171), i); // %d - void - clif_displaymessage(sd->fd, atcmd_output); - } - return 0; - } + if (!message || !*message || sscanf(message, "%d", &position) < 1) { + int i; + clif_displaymessage(sd->fd, msg_txt(668)); + for (i = 0; i < MAX_MEMOPOINTS; i++) { + if (sd->status.memo_point[i].map) + sprintf(atcmd_output, "%d - %s (%d,%d)", i, mapindex_id2name(sd->status.memo_point[i].map), sd->status.memo_point[i].x, sd->status.memo_point[i].y); + else + sprintf(atcmd_output, msg_txt(171), i); // %d - void + clif_displaymessage(sd->fd, atcmd_output); + } + return 0; + } - if( position < 0 || position >= MAX_MEMOPOINTS ) - { - sprintf(atcmd_output, msg_txt(1008), 0, MAX_MEMOPOINTS-1); // Please enter a valid position (usage: @memo ). - clif_displaymessage(fd, atcmd_output); - return -1; - } + if (position < 0 || position >= MAX_MEMOPOINTS) { + sprintf(atcmd_output, msg_txt(1008), 0, MAX_MEMOPOINTS-1); // Please enter a valid position (usage: @memo ). + clif_displaymessage(fd, atcmd_output); + return -1; + } - pc_memo(sd, position); - return 0; + pc_memo(sd, position); + return 0; } /*========================================== @@ -2384,24 +2385,24 @@ ACMD_FUNC(memo) *------------------------------------------*/ ACMD_FUNC(gat) { - int y; - nullpo_retr(-1, sd); + int y; + nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); + memset(atcmd_output, '\0', sizeof(atcmd_output)); - for (y = 2; y >= -2; y--) { - sprintf(atcmd_output, "%s (x= %d, y= %d) %02X %02X %02X %02X %02X", - map[sd->bl.m].name, sd->bl.x - 2, sd->bl.y + y, - map_getcell(sd->bl.m, sd->bl.x - 2, sd->bl.y + y, CELL_GETTYPE), - map_getcell(sd->bl.m, sd->bl.x - 1, sd->bl.y + y, CELL_GETTYPE), - map_getcell(sd->bl.m, sd->bl.x, sd->bl.y + y, CELL_GETTYPE), - map_getcell(sd->bl.m, sd->bl.x + 1, sd->bl.y + y, CELL_GETTYPE), - map_getcell(sd->bl.m, sd->bl.x + 2, sd->bl.y + y, CELL_GETTYPE)); + for (y = 2; y >= -2; y--) { + sprintf(atcmd_output, "%s (x= %d, y= %d) %02X %02X %02X %02X %02X", + map[sd->bl.m].name, sd->bl.x - 2, sd->bl.y + y, + map_getcell(sd->bl.m, sd->bl.x - 2, sd->bl.y + y, CELL_GETTYPE), + map_getcell(sd->bl.m, sd->bl.x - 1, sd->bl.y + y, CELL_GETTYPE), + map_getcell(sd->bl.m, sd->bl.x, sd->bl.y + y, CELL_GETTYPE), + map_getcell(sd->bl.m, sd->bl.x + 1, sd->bl.y + y, CELL_GETTYPE), + map_getcell(sd->bl.m, sd->bl.x + 2, sd->bl.y + y, CELL_GETTYPE)); - clif_displaymessage(fd, atcmd_output); - } + clif_displaymessage(fd, atcmd_output); + } - return 0; + return 0; } /*========================================== @@ -2409,19 +2410,19 @@ ACMD_FUNC(gat) *------------------------------------------*/ ACMD_FUNC(displaystatus) { - int i, type, flag, tick, val1 = 0, val2 = 0, val3 = 0; - nullpo_retr(-1, sd); + int i, type, flag, tick, val1 = 0, val2 = 0, val3 = 0; + nullpo_retr(-1, sd); - if (!message || !*message || (i = sscanf(message, "%d %d %d %d %d %d", &type, &flag, &tick, &val1, &val2, &val3)) < 1) { - clif_displaymessage(fd, msg_txt(1009)); // Please enter a status type/flag (usage: @displaystatus { { {}}}). - return -1; - } - if (i < 2) flag = 1; - if (i < 3) tick = 0; + if (!message || !*message || (i = sscanf(message, "%d %d %d %d %d %d", &type, &flag, &tick, &val1, &val2, &val3)) < 1) { + clif_displaymessage(fd, msg_txt(1009)); // Please enter a status type/flag (usage: @displaystatus { { {}}}). + return -1; + } + if (i < 2) flag = 1; + if (i < 3) tick = 0; - clif_status_change(&sd->bl, type, flag, tick, val1, val2, val3); + clif_status_change(&sd->bl, type, flag, tick, val1, val2, val3); - return 0; + return 0; } /*========================================== @@ -2429,47 +2430,39 @@ ACMD_FUNC(displaystatus) *------------------------------------------*/ ACMD_FUNC(statuspoint) { - int point; - unsigned int new_status_point; - - if (!message || !*message || (point = atoi(message)) == 0) { - clif_displaymessage(fd, msg_txt(1010)); // Please enter a number (usage: @stpoint ). - return -1; - } - - if(point < 0) - { - if(sd->status.status_point < (unsigned int)(-point)) - { - new_status_point = 0; - } - else - { - new_status_point = sd->status.status_point + point; - } - } - else if(UINT_MAX - sd->status.status_point < (unsigned int)point) - { - new_status_point = UINT_MAX; - } - else - { - new_status_point = sd->status.status_point + point; - } - - if (new_status_point != sd->status.status_point) { - sd->status.status_point = new_status_point; - clif_updatestatus(sd, SP_STATUSPOINT); - clif_displaymessage(fd, msg_txt(174)); // Number of status points changed. - } else { - if (point < 0) - clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. - else - clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. - return -1; - } - - return 0; + int point; + unsigned int new_status_point; + + if (!message || !*message || (point = atoi(message)) == 0) { + clif_displaymessage(fd, msg_txt(1010)); // Please enter a number (usage: @stpoint ). + return -1; + } + + if (point < 0) { + if (sd->status.status_point < (unsigned int)(-point)) { + new_status_point = 0; + } else { + new_status_point = sd->status.status_point + point; + } + } else if (UINT_MAX - sd->status.status_point < (unsigned int)point) { + new_status_point = UINT_MAX; + } else { + new_status_point = sd->status.status_point + point; + } + + if (new_status_point != sd->status.status_point) { + sd->status.status_point = new_status_point; + clif_updatestatus(sd, SP_STATUSPOINT); + clif_displaymessage(fd, msg_txt(174)); // Number of status points changed. + } else { + if (point < 0) + clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. + else + clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. + return -1; + } + + return 0; } /*========================================== @@ -2477,48 +2470,40 @@ ACMD_FUNC(statuspoint) *------------------------------------------*/ ACMD_FUNC(skillpoint) { - int point; - unsigned int new_skill_point; - nullpo_retr(-1, sd); - - if (!message || !*message || (point = atoi(message)) == 0) { - clif_displaymessage(fd, msg_txt(1011)); // Please enter a number (usage: @skpoint ). - return -1; - } - - if(point < 0) - { - if(sd->status.skill_point < (unsigned int)(-point)) - { - new_skill_point = 0; - } - else - { - new_skill_point = sd->status.skill_point + point; - } - } - else if(UINT_MAX - sd->status.skill_point < (unsigned int)point) - { - new_skill_point = UINT_MAX; - } - else - { - new_skill_point = sd->status.skill_point + point; - } - - if (new_skill_point != sd->status.skill_point) { - sd->status.skill_point = new_skill_point; - clif_updatestatus(sd, SP_SKILLPOINT); - clif_displaymessage(fd, msg_txt(175)); // Number of skill points changed. - } else { - if (point < 0) - clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. - else - clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. - return -1; - } - - return 0; + int point; + unsigned int new_skill_point; + nullpo_retr(-1, sd); + + if (!message || !*message || (point = atoi(message)) == 0) { + clif_displaymessage(fd, msg_txt(1011)); // Please enter a number (usage: @skpoint ). + return -1; + } + + if (point < 0) { + if (sd->status.skill_point < (unsigned int)(-point)) { + new_skill_point = 0; + } else { + new_skill_point = sd->status.skill_point + point; + } + } else if (UINT_MAX - sd->status.skill_point < (unsigned int)point) { + new_skill_point = UINT_MAX; + } else { + new_skill_point = sd->status.skill_point + point; + } + + if (new_skill_point != sd->status.skill_point) { + sd->status.skill_point = new_skill_point; + clif_updatestatus(sd, SP_SKILLPOINT); + clif_displaymessage(fd, msg_txt(175)); // Number of skill points changed. + } else { + if (point < 0) + clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. + else + clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. + return -1; + } + + return 0; } /*========================================== @@ -2526,25 +2511,24 @@ ACMD_FUNC(skillpoint) *------------------------------------------*/ ACMD_FUNC(zeny) { - int zeny=0, ret=-1; - nullpo_retr(-1, sd); + int zeny=0, ret=-1; + nullpo_retr(-1, sd); - if (!message || !*message || (zeny = atoi(message)) == 0) { - clif_displaymessage(fd, msg_txt(1012)); // Please enter an amount (usage: @zeny ). - return -1; - } + if (!message || !*message || (zeny = atoi(message)) == 0) { + clif_displaymessage(fd, msg_txt(1012)); // Please enter an amount (usage: @zeny ). + return -1; + } - if(zeny > 0){ - if((ret=pc_getzeny(sd,zeny,LOG_TYPE_COMMAND,NULL)) == 1) - clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. - } - else { - if( sd->status.zeny < -zeny ) zeny = -sd->status.zeny; - if((ret=pc_payzeny(sd,-zeny,LOG_TYPE_COMMAND,NULL)) == 1) - clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. - } - if(!ret) clif_displaymessage(fd, msg_txt(176)); //ret=0 mean cmd success - return 0; + if (zeny > 0) { + if ((ret=pc_getzeny(sd,zeny,LOG_TYPE_COMMAND,NULL)) == 1) + clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. + } else { + if (sd->status.zeny < -zeny) zeny = -sd->status.zeny; + if ((ret=pc_payzeny(sd,-zeny,LOG_TYPE_COMMAND,NULL)) == 1) + clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. + } + if (!ret) clif_displaymessage(fd, msg_txt(176)); //ret=0 mean cmd success + return 0; } /*========================================== @@ -2552,61 +2536,61 @@ ACMD_FUNC(zeny) *------------------------------------------*/ ACMD_FUNC(param) { - int i, value = 0, new_value, max; - const char* param[] = { "str", "agi", "vit", "int", "dex", "luk" }; - short* status[6]; - //we don't use direct initialization because it isn't part of the c standard. - nullpo_retr(-1, sd); - - memset(atcmd_output, '\0', sizeof(atcmd_output)); - - if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0) { - clif_displaymessage(fd, msg_txt(1013)); // Please enter a valid value (usage: @str/@agi/@vit/@int/@dex/@luk <+/-adjustment>). - return -1; - } - - ARR_FIND( 0, ARRAYLENGTH(param), i, strcmpi(command+1, param[i]) == 0 ); - - if( i == ARRAYLENGTH(param) || i > MAX_STATUS_TYPE) { // normally impossible... - clif_displaymessage(fd, msg_txt(1013)); // Please enter a valid value (usage: @str/@agi/@vit/@int/@dex/@luk <+/-adjustment>). - return -1; - } - - status[0] = &sd->status.str; - status[1] = &sd->status.agi; - status[2] = &sd->status.vit; - status[3] = &sd->status.int_; - status[4] = &sd->status.dex; - status[5] = &sd->status.luk; - - if( battle_config.atcommand_max_stat_bypass ) - max = SHRT_MAX; - else - max = pc_maxparameter(sd); - - if(value < 0 && *status[i] <= -value) { - new_value = 1; - } else if(max - *status[i] < value) { - new_value = max; - } else { - new_value = *status[i] + value; - } - - if (new_value != *status[i]) { - *status[i] = new_value; - clif_updatestatus(sd, SP_STR + i); - clif_updatestatus(sd, SP_USTR + i); - status_calc_pc(sd, 0); - clif_displaymessage(fd, msg_txt(42)); // Stat changed. - } else { - if (value < 0) - clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. - else - clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. - return -1; - } - - return 0; + int i, value = 0, new_value, max; + const char *param[] = { "str", "agi", "vit", "int", "dex", "luk" }; + short *status[6]; + //we don't use direct initialization because it isn't part of the c standard. + nullpo_retr(-1, sd); + + memset(atcmd_output, '\0', sizeof(atcmd_output)); + + if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0) { + clif_displaymessage(fd, msg_txt(1013)); // Please enter a valid value (usage: @str/@agi/@vit/@int/@dex/@luk <+/-adjustment>). + return -1; + } + + ARR_FIND(0, ARRAYLENGTH(param), i, strcmpi(command+1, param[i]) == 0); + + if (i == ARRAYLENGTH(param) || i > MAX_STATUS_TYPE) { // normally impossible... + clif_displaymessage(fd, msg_txt(1013)); // Please enter a valid value (usage: @str/@agi/@vit/@int/@dex/@luk <+/-adjustment>). + return -1; + } + + status[0] = &sd->status.str; + status[1] = &sd->status.agi; + status[2] = &sd->status.vit; + status[3] = &sd->status.int_; + status[4] = &sd->status.dex; + status[5] = &sd->status.luk; + + if (battle_config.atcommand_max_stat_bypass) + max = SHRT_MAX; + else + max = pc_maxparameter(sd); + + if (value < 0 && *status[i] <= -value) { + new_value = 1; + } else if (max - *status[i] < value) { + new_value = max; + } else { + new_value = *status[i] + value; + } + + if (new_value != *status[i]) { + *status[i] = new_value; + clif_updatestatus(sd, SP_STR + i); + clif_updatestatus(sd, SP_USTR + i); + status_calc_pc(sd, 0); + clif_displaymessage(fd, msg_txt(42)); // Stat changed. + } else { + if (value < 0) + clif_displaymessage(fd, msg_txt(41)); // Unable to decrease the number/value. + else + clif_displaymessage(fd, msg_txt(149)); // Unable to increase the number/value. + return -1; + } + + return 0; } /*========================================== @@ -2614,58 +2598,58 @@ ACMD_FUNC(param) *------------------------------------------*/ ACMD_FUNC(stat_all) { - int index, count, value, max, new_value; - short* status[6]; - //we don't use direct initialization because it isn't part of the c standard. - nullpo_retr(-1, sd); - - status[0] = &sd->status.str; - status[1] = &sd->status.agi; - status[2] = &sd->status.vit; - status[3] = &sd->status.int_; - status[4] = &sd->status.dex; - status[5] = &sd->status.luk; - - if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0) { - value = pc_maxparameter(sd); - max = pc_maxparameter(sd); - } else { - if( battle_config.atcommand_max_stat_bypass ) - max = SHRT_MAX; - else - max = pc_maxparameter(sd); - } - - count = 0; - for (index = 0; index < ARRAYLENGTH(status); index++) { - - if (value > 0 && *status[index] > max - value) - new_value = max; - else if (value < 0 && *status[index] <= -value) - new_value = 1; - else - new_value = *status[index] +value; - - if (new_value != (int)*status[index]) { - *status[index] = new_value; - clif_updatestatus(sd, SP_STR + index); - clif_updatestatus(sd, SP_USTR + index); - count++; - } - } - - if (count > 0) { // if at least 1 stat modified - status_calc_pc(sd, 0); - clif_displaymessage(fd, msg_txt(84)); // All stats changed! - } else { - if (value < 0) - clif_displaymessage(fd, msg_txt(177)); // You cannot decrease that stat anymore. - else - clif_displaymessage(fd, msg_txt(178)); // You cannot increase that stat anymore. - return -1; - } - - return 0; + int index, count, value, max, new_value; + short *status[6]; + //we don't use direct initialization because it isn't part of the c standard. + nullpo_retr(-1, sd); + + status[0] = &sd->status.str; + status[1] = &sd->status.agi; + status[2] = &sd->status.vit; + status[3] = &sd->status.int_; + status[4] = &sd->status.dex; + status[5] = &sd->status.luk; + + if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0) { + value = pc_maxparameter(sd); + max = pc_maxparameter(sd); + } else { + if (battle_config.atcommand_max_stat_bypass) + max = SHRT_MAX; + else + max = pc_maxparameter(sd); + } + + count = 0; + for (index = 0; index < ARRAYLENGTH(status); index++) { + + if (value > 0 && *status[index] > max - value) + new_value = max; + else if (value < 0 && *status[index] <= -value) + new_value = 1; + else + new_value = *status[index] +value; + + if (new_value != (int)*status[index]) { + *status[index] = new_value; + clif_updatestatus(sd, SP_STR + index); + clif_updatestatus(sd, SP_USTR + index); + count++; + } + } + + if (count > 0) { // if at least 1 stat modified + status_calc_pc(sd, 0); + clif_displaymessage(fd, msg_txt(84)); // All stats changed! + } else { + if (value < 0) + clif_displaymessage(fd, msg_txt(177)); // You cannot decrease that stat anymore. + else + clif_displaymessage(fd, msg_txt(178)); // You cannot increase that stat anymore. + return -1; + } + + return 0; } /*========================================== @@ -2673,40 +2657,40 @@ ACMD_FUNC(stat_all) *------------------------------------------*/ ACMD_FUNC(guildlevelup) { - int level = 0; - short added_level; - struct guild *guild_info; - nullpo_retr(-1, sd); + int level = 0; + short added_level; + struct guild *guild_info; + nullpo_retr(-1, sd); - if (!message || !*message || sscanf(message, "%d", &level) < 1 || level == 0) { - clif_displaymessage(fd, msg_txt(1014)); // Please enter a valid level (usage: @guildlvup/@guildlvlup <# of levels>). - return -1; - } + if (!message || !*message || sscanf(message, "%d", &level) < 1 || level == 0) { + clif_displaymessage(fd, msg_txt(1014)); // Please enter a valid level (usage: @guildlvup/@guildlvlup <# of levels>). + return -1; + } - if (sd->status.guild_id <= 0 || (guild_info = guild_search(sd->status.guild_id)) == NULL) { - clif_displaymessage(fd, msg_txt(43)); // You're not in a guild. - return -1; - } - //if (strcmp(sd->status.name, guild_info->master) != 0) { - // clif_displaymessage(fd, msg_txt(44)); // You're not the master of your guild. - // return -1; - //} + if (sd->status.guild_id <= 0 || (guild_info = guild_search(sd->status.guild_id)) == NULL) { + clif_displaymessage(fd, msg_txt(43)); // You're not in a guild. + return -1; + } + //if (strcmp(sd->status.name, guild_info->master) != 0) { + // clif_displaymessage(fd, msg_txt(44)); // You're not the master of your guild. + // return -1; + //} - added_level = (short)level; - if (level > 0 && (level > MAX_GUILDLEVEL || added_level > ((short)MAX_GUILDLEVEL - guild_info->guild_lv))) // fix positiv overflow - added_level = (short)MAX_GUILDLEVEL - guild_info->guild_lv; - else if (level < 0 && (level < -MAX_GUILDLEVEL || added_level < (1 - guild_info->guild_lv))) // fix negativ overflow - added_level = 1 - guild_info->guild_lv; + added_level = (short)level; + if (level > 0 && (level > MAX_GUILDLEVEL || added_level > ((short)MAX_GUILDLEVEL - guild_info->guild_lv))) // fix positiv overflow + added_level = (short)MAX_GUILDLEVEL - guild_info->guild_lv; + else if (level < 0 && (level < -MAX_GUILDLEVEL || added_level < (1 - guild_info->guild_lv))) // fix negativ overflow + added_level = 1 - guild_info->guild_lv; - if (added_level != 0) { - intif_guild_change_basicinfo(guild_info->guild_id, GBI_GUILDLV, &added_level, sizeof(added_level)); - clif_displaymessage(fd, msg_txt(179)); // Guild level changed. - } else { - clif_displaymessage(fd, msg_txt(45)); // Guild level change failed. - return -1; - } + if (added_level != 0) { + intif_guild_change_basicinfo(guild_info->guild_id, GBI_GUILDLV, &added_level, sizeof(added_level)); + clif_displaymessage(fd, msg_txt(179)); // Guild level changed. + } else { + clif_displaymessage(fd, msg_txt(45)); // Guild level change failed. + return -1; + } - return 0; + return 0; } /*========================================== @@ -2714,39 +2698,38 @@ ACMD_FUNC(guildlevelup) *------------------------------------------*/ ACMD_FUNC(makeegg) { - struct item_data *item_data; - int id, pet_id; - nullpo_retr(-1, sd); - - if (!message || !*message) { - clif_displaymessage(fd, msg_txt(1015)); // Please enter a monster/egg name/ID (usage: @makeegg ). - return -1; - } - - if ((item_data = itemdb_searchname(message)) != NULL) // for egg name - id = item_data->nameid; - else - if ((id = mobdb_searchname(message)) != 0) // for monster name - ; - else - id = atoi(message); - - pet_id = search_petDB_index(id, PET_CLASS); - if (pet_id < 0) - pet_id = search_petDB_index(id, PET_EGG); - if (pet_id >= 0) { - sd->catch_target_class = pet_db[pet_id].class_; - intif_create_pet( - sd->status.account_id, sd->status.char_id, - (short)pet_db[pet_id].class_, (short)mob_db(pet_db[pet_id].class_)->lv, - (short)pet_db[pet_id].EggID, 0, (short)pet_db[pet_id].intimate, - 100, 0, 1, pet_db[pet_id].jname); - } else { - clif_displaymessage(fd, msg_txt(180)); // The monster/egg name/id doesn't exist. - return -1; - } - - return 0; + struct item_data *item_data; + int id, pet_id; + nullpo_retr(-1, sd); + + if (!message || !*message) { + clif_displaymessage(fd, msg_txt(1015)); // Please enter a monster/egg name/ID (usage: @makeegg ). + return -1; + } + + if ((item_data = itemdb_searchname(message)) != NULL) // for egg name + id = item_data->nameid; + else if ((id = mobdb_searchname(message)) != 0) // for monster name + ; + else + id = atoi(message); + + pet_id = search_petDB_index(id, PET_CLASS); + if (pet_id < 0) + pet_id = search_petDB_index(id, PET_EGG); + if (pet_id >= 0) { + sd->catch_target_class = pet_db[pet_id].class_; + intif_create_pet( + sd->status.account_id, sd->status.char_id, + (short)pet_db[pet_id].class_, (short)mob_db(pet_db[pet_id].class_)->lv, + (short)pet_db[pet_id].EggID, 0, (short)pet_db[pet_id].intimate, + 100, 0, 1, pet_db[pet_id].jname); + } else { + clif_displaymessage(fd, msg_txt(180)); // The monster/egg name/id doesn't exist. + return -1; + } + + return 0; } /*========================================== @@ -2754,15 +2737,15 @@ ACMD_FUNC(makeegg) *------------------------------------------*/ ACMD_FUNC(hatch) { - nullpo_retr(-1, sd); - if (sd->status.pet_id <= 0) - clif_sendegg(sd); - else { - clif_displaymessage(fd, msg_txt(181)); // You already have a pet. - return -1; - } + nullpo_retr(-1, sd); + if (sd->status.pet_id <= 0) + clif_sendegg(sd); + else { + clif_displaymessage(fd, msg_txt(181)); // You already have a pet. + return -1; + } - return 0; + return 0; } /*========================================== @@ -2770,36 +2753,35 @@ ACMD_FUNC(hatch) *------------------------------------------*/ ACMD_FUNC(petfriendly) { - int friendly; - struct pet_data *pd; - nullpo_retr(-1, sd); + int friendly; + struct pet_data *pd; + nullpo_retr(-1, sd); - if (!message || !*message || (friendly = atoi(message)) < 0) { - clif_displaymessage(fd, msg_txt(1016)); // Please enter a valid value (usage: @petfriendly <0-1000>). - return -1; - } + if (!message || !*message || (friendly = atoi(message)) < 0) { + clif_displaymessage(fd, msg_txt(1016)); // Please enter a valid value (usage: @petfriendly <0-1000>). + return -1; + } - pd = sd->pd; - if (!pd) { - clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet. - return -1; - } + pd = sd->pd; + if (!pd) { + clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet. + return -1; + } - if (friendly < 0 || friendly > 1000) - { - clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. - return -1; - } + if (friendly < 0 || friendly > 1000) { + clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. + return -1; + } - if (friendly == pd->pet.intimate) { - clif_displaymessage(fd, msg_txt(183)); // Pet intimacy is already at maximum. - return -1; - } + if (friendly == pd->pet.intimate) { + clif_displaymessage(fd, msg_txt(183)); // Pet intimacy is already at maximum. + return -1; + } - pet_set_intimate(pd, friendly); - clif_send_petstatus(sd); - clif_displaymessage(fd, msg_txt(182)); // Pet intimacy changed. - return 0; + pet_set_intimate(pd, friendly); + clif_send_petstatus(sd); + clif_displaymessage(fd, msg_txt(182)); // Pet intimacy changed. + return 0; } /*========================================== @@ -2807,34 +2789,34 @@ ACMD_FUNC(petfriendly) *------------------------------------------*/ ACMD_FUNC(pethungry) { - int hungry; - struct pet_data *pd; - nullpo_retr(-1, sd); + int hungry; + struct pet_data *pd; + nullpo_retr(-1, sd); - if (!message || !*message || (hungry = atoi(message)) < 0) { - clif_displaymessage(fd, msg_txt(1017)); // Please enter a valid number (usage: @pethungry <0-100>). - return -1; - } + if (!message || !*message || (hungry = atoi(message)) < 0) { + clif_displaymessage(fd, msg_txt(1017)); // Please enter a valid number (usage: @pethungry <0-100>). + return -1; + } - pd = sd->pd; - if (!sd->status.pet_id || !pd) { - clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet. - return -1; - } - if (hungry < 0 || hungry > 100) { - clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. - return -1; - } - if (hungry == pd->pet.hungry) { - clif_displaymessage(fd, msg_txt(186)); // Pet hunger is already at maximum. - return -1; - } + pd = sd->pd; + if (!sd->status.pet_id || !pd) { + clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet. + return -1; + } + if (hungry < 0 || hungry > 100) { + clif_displaymessage(fd, msg_txt(37)); // An invalid number was specified. + return -1; + } + if (hungry == pd->pet.hungry) { + clif_displaymessage(fd, msg_txt(186)); // Pet hunger is already at maximum. + return -1; + } - pd->pet.hungry = hungry; - clif_send_petstatus(sd); - clif_displaymessage(fd, msg_txt(185)); // Pet hunger changed. + pd->pet.hungry = hungry; + clif_send_petstatus(sd); + clif_displaymessage(fd, msg_txt(185)); // Pet hunger changed. - return 0; + return 0; } /*========================================== @@ -2842,64 +2824,63 @@ ACMD_FUNC(pethungry) *------------------------------------------*/ ACMD_FUNC(petrename) { - struct pet_data *pd; - nullpo_retr(-1, sd); - if (!sd->status.pet_id || !sd->pd) { - clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet. - return -1; - } - pd = sd->pd; - if (!pd->pet.rename_flag) { - clif_displaymessage(fd, msg_txt(188)); // You can already rename your pet. - return -1; - } + struct pet_data *pd; + nullpo_retr(-1, sd); + if (!sd->status.pet_id || !sd->pd) { + clif_displaymessage(fd, msg_txt(184)); // Sorry, but you have no pet. + return -1; + } + pd = sd->pd; + if (!pd->pet.rename_flag) { + clif_displaymessage(fd, msg_txt(188)); // You can already rename your pet. + return -1; + } - pd->pet.rename_flag = 0; - intif_save_petdata(sd->status.account_id, &pd->pet); - clif_send_petstatus(sd); - clif_displaymessage(fd, msg_txt(187)); // You can now rename your pet. + pd->pet.rename_flag = 0; + intif_save_petdata(sd->status.account_id, &pd->pet); + clif_send_petstatus(sd); + clif_displaymessage(fd, msg_txt(187)); // You can now rename your pet. - return 0; + return 0; } /*========================================== * *------------------------------------------*/ -ACMD_FUNC(recall) { - struct map_session_data *pl_sd = NULL; +ACMD_FUNC(recall) +{ + struct map_session_data *pl_sd = NULL; - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - if (!message || !*message) { - clif_displaymessage(fd, msg_txt(1018)); // Please enter a player name (usage: @recall ). - return -1; - } + if (!message || !*message) { + clif_displaymessage(fd, msg_txt(1018)); // Please enter a player name (usage: @recall ). + return -1; + } - if((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL) - { - clif_displaymessage(fd, msg_txt(3)); // Character not found. - return -1; - } + if ((pl_sd=map_nick2sd((char *)message)) == NULL && (pl_sd=map_charid2sd(atoi(message))) == NULL) { + clif_displaymessage(fd, msg_txt(3)); // Character not found. + return -1; + } - if ( pc_get_group_level(sd) < pc_get_group_level(pl_sd) ) - { - clif_displaymessage(fd, msg_txt(81)); // Your GM level doesn't authorize you to preform this action on the specified player. - return -1; - } + if (pc_get_group_level(sd) < pc_get_group_level(pl_sd)) { + clif_displaymessage(fd, msg_txt(81)); // Your GM level doesn't authorize you to preform this action on the specified player. + return -1; + } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(1019)); // You are not authorized to warp someone to this map. - return -1; - } - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif_displaymessage(fd, msg_txt(1020)); // You are not authorized to warp this player from their map. - return -1; - } - pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN); - sprintf(atcmd_output, msg_txt(46), pl_sd->status.name); // %s recalled! - clif_displaymessage(fd, atcmd_output); + if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(1019)); // You are not authorized to warp someone to this map. + return -1; + } + if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif_displaymessage(fd, msg_txt(1020)); // You are not authorized to warp this player from their map. + return -1; + } + pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN); + sprintf(atcmd_output, msg_txt(46), pl_sd->status.name); // %s recalled! + clif_displaymessage(fd, atcmd_output); - return 0; + return 0; } /*========================================== @@ -2908,19 +2889,19 @@ ACMD_FUNC(recall) { *------------------------------------------*/ ACMD_FUNC(char_block) { - nullpo_retr(-1, sd); + nullpo_retr(-1, sd); - memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); + memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); - if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) { - clif_displaymessage(fd, msg_txt(1021)); // Please enter a player name (usage: @charblock/@block ). - return -1; - } + if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) { + clif_displaymessage(fd, msg_txt(1021)); // Please enter a player name (usage: @charblock/@block ). + return -1; + } - chrif_char_ask_name(sd->status.account_id, atcmd_player_name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block - clif_displaymessage(fd, msg_txt(88)); // Character name sent to char-server to ask it. + chrif_char_ask_name(sd->status.account_id, atcmd_player_name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block + clif_displaymessage(fd, msg_txt(88)); // Character name sent to char-server to ask it. - return 0; + return 0; } /*========================================== @@ -2940,84 +2921,84 @@ ACMD_FUNC(char_block) *------------------------------------------*/ ACMD_FUNC(char_ban) { - char * modif_p; - int year, month, day, hour, minute, second, value; - time_t timestamp; - struct tm *tmtime; - nullpo_retr(-1, sd); - - memset(atcmd_output, '\0', sizeof(atcmd_output)); - memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); - - if (!message || !*message || sscanf(message, "%s %23[^\n]", atcmd_output, atcmd_player_name) < 2) { - clif_displaymessage(fd, msg_txt(1022)); // Please enter ban time and a player name (usage: @charban/@ban/@banish/@charbanish