diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/map/atcommand.c | 16 | ||||
-rw-r--r-- | src/map/itemdb.h | 2 | ||||
-rw-r--r-- | src/map/map.c | 2 | ||||
-rw-r--r-- | src/map/pc.c | 2 | ||||
-rw-r--r-- | src/map/pc.h | 1 | ||||
-rw-r--r-- | src/map/script.c | 54 | ||||
-rw-r--r-- | src/map/skill.c | 49 | ||||
-rw-r--r-- | src/map/status.c | 83 | ||||
-rw-r--r-- | src/map/status.h | 1 |
9 files changed, 101 insertions, 109 deletions
diff --git a/src/map/atcommand.c b/src/map/atcommand.c index d414d565d..c2599d68d 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -416,7 +416,7 @@ ACMD_FUNC(mapmove) { char map_name[MAP_NAME_LENGTH_EXT]; unsigned short mapindex; - int x = 0, y = 0; + short x = 0, y = 0; int m = -1; nullpo_retr(-1, sd); @@ -424,8 +424,8 @@ ACMD_FUNC(mapmove) memset(map_name, '\0', sizeof(map_name)); if (!message || !*message || - (sscanf(message, "%15s %d %d", map_name, &x, &y) < 3 && - sscanf(message, "%15[^,],%d,%d", map_name, &x, &y) < 1)) { + (sscanf(message, "%15s %hd %hd", map_name, &x, &y) < 3 && + sscanf(message, "%15[^,],%hd,%hd", map_name, &x, &y) < 1)) { clif_displaymessage(fd, "Please, enter a map (usage: @warp/@rura/@mapmove <mapname> <x> <y>)."); return -1; @@ -443,7 +443,8 @@ ACMD_FUNC(mapmove) 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)); - x = y = 0; //Invalid cell, use random spot. + if (!map_search_freecell(NULL, m, &x, &y, 10, 10, 1)) + x = y = 0; //Invalid cell, use random spot. } if (map[m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) { clif_displaymessage(fd, msg_txt(247)); @@ -548,13 +549,13 @@ ACMD_FUNC(jumpto) *------------------------------------------*/ ACMD_FUNC(jump) { - int x = 0, y = 0; + short x = 0, y = 0; nullpo_retr(-1, sd); memset(atcmd_output, '\0', sizeof(atcmd_output)); - sscanf(message, "%d %d", &x, &y); + sscanf(message, "%hd %hd", &x, &y); if (map[sd->bl.m].flag.noteleport && battle_config.any_warp_GM_min_level > pc_isGM(sd)) { clif_displaymessage(fd, msg_txt(248)); // You are not authorized to warp from your current map. @@ -570,7 +571,8 @@ ACMD_FUNC(jump) 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)); - x = y = 0; //Invalid cell, use random spot. + 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); diff --git a/src/map/itemdb.h b/src/map/itemdb.h index 463061175..5b54acd67 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -114,7 +114,7 @@ int itemdb_searchrandomid(int flags); #define itemdb_value_buy(n) itemdb_search(n)->value_buy #define itemdb_value_sell(n) itemdb_search(n)->value_sell -#define itemdb_canrefine(n) itemdb_search(n)->flag.no_refine +#define itemdb_canrefine(n) (!itemdb_search(n)->flag.no_refine) //Item trade restrictions [Skotlex] int itemdb_isdropable_sub(struct item_data *, int, int); int itemdb_cantrade_sub(struct item_data*, int, int); diff --git a/src/map/map.c b/src/map/map.c index bc9465781..559cab96d 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -2305,7 +2305,7 @@ int map_random_dir(struct block_list *bl, short *x, short *y) if (dist < 1) dist =1; do { - j = rand()%8; //Pick a random direction + j = 1 + 2*(rand()%4); //Pick a random diagonal direction segment = 1+(rand()%dist); //Pick a random interval from the whole vector in that direction xi = bl->x + segment*dirx[j]; segment = (short)sqrt((float)(dist2 - segment*segment)); //The complement of the previously picked segment diff --git a/src/map/pc.c b/src/map/pc.c index fda41107b..30bde19df 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -7168,7 +7168,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) pos = pc_equippoint(sd,n); //With a few exceptions, item should go in all specified slots. if(battle_config.battle_log) - ShowInfo("equip %d(%d) %x:%x\n",sd->status.inventory[n].nameid,n,id->equip,req_pos); + ShowInfo("equip %d(%d) %x:%x\n",sd->status.inventory[n].nameid,n,id?id->equip:0,req_pos); if(!pc_isequip(sd,n) || !(pos&req_pos) || sd->status.inventory[n].equip != 0 || sd->status.inventory[n].attribute==1 ) { // [Valaris] clif_equipitemack(sd,n,0,0); // fail return 0; diff --git a/src/map/pc.h b/src/map/pc.h index da7052fe8..17450bf19 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -10,7 +10,6 @@ #include "buyingstore.h" // struct s_buyingstore #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 "searchstore.h" // struct s_search_store_info #include "status.h" // OPTION_*, struct weapon_atk diff --git a/src/map/script.c b/src/map/script.c index 632dc0e14..c61b6d184 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -4559,7 +4559,7 @@ BUILDIN_FUNC(warpparty) struct party_data* p; int type; int mapindex; - int i, j; + int i; const char* str = script_getstr(st,2); int x = script_getnum(st,3); @@ -4579,9 +4579,27 @@ BUILDIN_FUNC(warpparty) : ( strcmp(str,"Leader")==0 ) ? 3 : 4; - if( type == 2 && ( sd = script_rid2sd(st) ) == NULL ) - {// "SavePoint" uses save point of the currently attached player - return 0; + switch (type) + { + case 3: + for(i = 0; i < MAX_PARTY && !p->party.member[i].leader; i++); + if (i == MAX_PARTY || !p->data[i].sd) //Leader not found / not online + return 0; + pl_sd = p->data[i].sd; + mapindex = pl_sd->mapindex; + x = pl_sd->bl.x; + y = pl_sd->bl.y; + break; + case 4: + mapindex = mapindex_name2id(str); + break; + case 2: + //"SavePoint" uses save point of the currently attached player + if (( sd = script_rid2sd(st) ) == NULL ) + return 0; + default: + mapindex = 0; + break; } for (i = 0; i < MAX_PARTY; i++) @@ -4610,25 +4628,9 @@ BUILDIN_FUNC(warpparty) 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++); - if (j == MAX_PARTY || !p->data[j].sd) //Leader not found / not online - return 0; - mapindex = p->data[j].sd->mapindex; - x = p->data[j].sd->bl.x; - y = p->data[j].sd->bl.y; - for (j = 0; j < MAX_PARTY; j++) - { - pl_sd = p->data[j].sd; - if (!pl_sd) - continue; - if(map[pl_sd->bl.m].flag.noreturn || map[pl_sd->bl.m].flag.nowarp) - continue; - 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,CLR_TELEPORT); + pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT); break; } } @@ -6574,6 +6576,9 @@ BUILDIN_FUNC(strnpcinfo) case 3: // unique name name = aStrdup(nd->exname); break; + case 4: // map name + name = aStrdup(map[nd->bl.m].name); + break; } if(name) @@ -13452,8 +13457,11 @@ BUILDIN_FUNC(unitwarp) map = map_mapname2mapid(script_getstr(st, 3)); x = (short)script_getnum(st,4); y = (short)script_getnum(st,5); - - bl = map_id2bl(unit_id); + + if (!unit_id) //Warp the script's runner + bl = map_id2bl(st->rid); + else + bl = map_id2bl(unit_id); if( map >= 0 && bl != NULL ) script_pushint(st, unit_warp(bl,map,x,y,CLR_OUTSIGHT)); else diff --git a/src/map/skill.c b/src/map/skill.c index d33d35d6e..15be872f1 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -268,8 +268,8 @@ int skill_get_range2 (struct block_list *bl, int id, int lv) int skill_calc_heal(struct block_list *src, struct block_list *target, int skill_id, int skill_lv, bool heal) { int skill, hp; - struct map_session_data *sd = map_id2sd(src->id); - struct map_session_data *tsd = map_id2sd(target->id); + struct map_session_data *sd = BL_CAST(BL_PC, src); + struct map_session_data *tsd = BL_CAST(BL_PC, target); struct status_change* sc; switch( skill_id ) @@ -1008,8 +1008,9 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int tbl = (sd->autospell[i].id < 0) ? src : bl; - if( !battle_check_range(src, tbl, skill_get_range2(src, skill,skilllv) + (skill == RG_CLOSECONFINE?0:1)) && battle_config.autospell_check_range ) - continue; // If autospell_check_range is yes, fail the autocast. + if( battle_config.autospell_check_range && + !battle_check_range(src, tbl, skill_get_range2(src, skill,skilllv) + (skill == RG_CLOSECONFINE?0:1)) ) + continue; if (skill == AS_SONICBLOW) pc_stop_attack(sd); //Special case, Sonic Blow autospell should stop the player attacking. @@ -1113,7 +1114,8 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, int s continue; tbl = (sd->autospell3[i].id < 0) ? &sd->bl : bl; - if( !battle_check_range(&sd->bl, tbl, skill_get_range2(&sd->bl, skill,skilllv) + (skill == RG_CLOSECONFINE?0:1)) && battle_config.autospell_check_range ) + if( battle_config.autospell_check_range && + !battle_check_range(&sd->bl, tbl, skill_get_range2(&sd->bl, skill,skilllv) + (skill == RG_CLOSECONFINE?0:1)) ) continue; sd->state.autocast = 1; @@ -1640,13 +1642,10 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds //Spirit of Wizard blocks Kaite's reflection if( type == 2 && sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_WIZARD ) - { //Consume one Fragment per hit of the casted skill. Val3 is the skill id and val4 is the ID of the damage src. - //This should account for ground spells (and single target spells will be completed on castend_id) [Skotlex] - type = pc_search_inventory (tsd, 7321); - if (type >= 0) - pc_delitem(tsd, type, 1, 0, 1); - + { //Consume one Fragment per hit of the casted skill? [Skotlex] + type = tsd?pc_search_inventory (tsd, 7321):0; if (type >= 0) { + if ( tsd ) pc_delitem(tsd, type, 1, 0, 1); dmg.damage = dmg.damage2 = 0; dmg.dmg_lv = ATK_MISS; sc->data[SC_SPIRIT]->val3 = skillid; @@ -3266,7 +3265,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in break; { int per = 0, sper = 0; - if (status_get_sc(bl)->data[SC_HELLPOWER]) + if (tsc && tsc->data[SC_HELLPOWER]) break; if (map[bl->m].flag.pvp && dstsd && dstsd->pvp_point < 0) @@ -3310,7 +3309,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case AL_CRUCIS: if (flag&1) - sc_start(bl,type, 23+skilllv*4 +status_get_lv(src) -status_get_lv(bl), skilllv,60000); + sc_start(bl,type, 23+skilllv*4 +status_get_lv(src) -status_get_lv(bl), 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); @@ -3395,7 +3394,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in break; heal = status_percent_heal(bl, 100, 0); clif_skill_nodamage(NULL, bl, AL_HEAL, heal, 1); - if( skillid == NPC_ALLHEAL && dstmd ) + if( dstmd ) { // Reset Damage Logs memset(dstmd->dmglog, 0, sizeof(dstmd->dmglog)); dstmd->tdmg = 0; @@ -3857,7 +3856,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in mer->devotion_flag = 1; // Mercenary Devoting Owner clif_skill_nodamage(src, bl, skillid, skilllv, - sc_start4(bl, type, 100, src->id, i, skill_get_range2(src,skillid,skilllv), skill_get_time2(skillid, skilllv), 1000)); + sc_start4(bl, type, 100, src->id, i, skill_get_range2(src,skillid,skilllv),0, skill_get_time2(skillid, skilllv))); clif_devotion(src, NULL); } break; @@ -6194,7 +6193,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk case SA_VIOLENTGALE: { //Does not consumes if the skill is already active. [Skotlex] struct skill_unit_group *sg; - if ((sg= skill_locate_element_field(&sd->bl)) != NULL && ( sg->skill_id == SA_VOLCANO || sg->skill_id == SA_DELUGE || sg->skill_id == SA_VIOLENTGALE )) + if ((sg= skill_locate_element_field(src)) != NULL && ( sg->skill_id == SA_VOLCANO || sg->skill_id == SA_DELUGE || sg->skill_id == SA_VIOLENTGALE )) { if (sg->limit - DIFF_TICK(gettick(), sg->tick) > 0) { @@ -8200,7 +8199,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh require = skill_get_requirement(sd,skill,lv); //Can only update state when weapon/arrow info is checked. - if (require.weapon) sd->state.arrow_atk = require.ammo?1:0; + sd->state.arrow_atk = require.ammo?1:0; // perform skill-specific checks (and actions) switch( skill ) @@ -8834,9 +8833,11 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, short req.weapon = skill_db[j].weapon; - req.ammo = skill_db[j].ammo; req.ammo_qty = skill_db[j].ammo_qty[lv-1]; - if (req.weapon && !req.ammo && skill && skill_isammotype(sd, skill)) + if (req.ammo_qty) + req.ammo = skill_db[j].ammo; + + if (!req.ammo && skill && skill_isammotype(sd, skill)) { //Assume this skill is using the weapon, therefore it requires arrows. req.ammo = 0xFFFFFFFF; //Enable use on all ammo types. req.ammo_qty = 1; @@ -11650,9 +11651,9 @@ static bool skill_parse_row_requiredb(char* split[], int columns, int current) for( j = 0; j < 32; j++ ) { int l = atoi(p); - if( l == 99 ) // magic value? + if( l == 99 ) // Any weapon { - skill_db[i].weapon = 0xffffffff; + skill_db[i].weapon = 0; break; } else @@ -11668,12 +11669,12 @@ static bool skill_parse_row_requiredb(char* split[], int columns, int current) for( j = 0; j < 32; j++ ) { int l = atoi(p); - if( l == 99 ) // magic value? + if( l == 99 ) // Any ammo type { - skill_db[i].ammo = 0xffffffff; + skill_db[i].ammo = 0xFFFFFFFF; break; } - else if( l ) // 0 not allowed? + else if( l ) // 0 stands for no requirement skill_db[i].ammo |= 1<<l; p = strchr(p,':'); if( !p ) diff --git a/src/map/status.c b/src/map/status.c index 37dad30b9..69f6757d0 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -656,7 +656,7 @@ int status_charge(struct block_list* bl, int hp, int sp) //If flag&1, damage is passive and does not triggers cancelling status changes. //If flag&2, fail if target does not has enough to substract. //If flag&4, if killed, mob must not give exp/loot. -//If flag&8, sp loss on dead target. +//flag will be set to &8 when damaging sp of a dead character int status_damage(struct block_list *src,struct block_list *target,int hp, int sp, int walkdelay, int flag) { struct status_data *status; @@ -666,18 +666,15 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s sp = 0; //Not a valid SP target. if (hp < 0) { //Assume absorbed damage. - status_heal(target, cap_value(-hp, INT_MIN, INT_MAX), 0, 1); + status_heal(target, -hp, 0, 1); hp = 0; } if (sp < 0) { - status_heal(target, 0, cap_value(-sp, INT_MIN, INT_MAX), 1); + status_heal(target, 0, -sp, 1); sp = 0; } - if (!hp && !sp) - return 0; - if (target->type == BL_SKILL) return skill_unit_ondamaged((struct skill_unit *)target, src, hp, gettick()); @@ -685,6 +682,19 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s if( status == &dummy_status ) return 0; + if ((unsigned int)hp >= status->hp) { + if (flag&2) return 0; + hp = status->hp; + } + + if ((unsigned int)sp > status->sp) { + if (flag&2) return 0; + sp = status->sp; + } + + if (!hp && !sp) + return 0; + if( !status->hp ) flag |= 8; @@ -694,10 +704,10 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s // return 0; //Cannot damage a bl not on a map, except when "charging" hp/sp sc = status_get_sc(target); - if( battle_config.invincible_nodamage && src && sc && sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] ) + if( hp && battle_config.invincible_nodamage && src && sc && sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] ) hp = 1; - if( hp && !(flag&(1|8)) ) { + if( hp && !(flag&1) ) { if( sc ) { struct status_change_entry *sce; if (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) @@ -731,16 +741,6 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s unit_skillcastcancel(target, 2); } - if ((unsigned int)hp >= status->hp) { - if (flag&2) return 0; - hp = status->hp; - } - - if ((unsigned int)sp > status->sp) { - if (flag&2) return 0; - sp = status->sp; - } - status->hp-= hp; status->sp-= sp; @@ -761,7 +761,7 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s case BL_MER: mercenary_damage((TBL_MER*)target,src,hp,sp); break; } - if( status->hp || flag&8 ) + if( status->hp || (flag&8) ) { //Still lives or has been dead before this damage. if (walkdelay) unit_set_walkdelay(target, gettick(), walkdelay, 0); @@ -805,11 +805,11 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s } } - if( !(flag&8) && sc && sc->data[SC_KAIZEL] ) + if( sc && sc->data[SC_KAIZEL] ) { //flag&8 = disable Kaizel int time = skill_get_time2(SL_KAIZEL,sc->data[SC_KAIZEL]->val1); //Look for Osiris Card's bonus effect on the character and revive 100% or revive normally - if ( target->type == BL_PC && BL_CAST(BL_PC,target)->special_state.restart_full_recover == 1 ) + if ( target->type == BL_PC && BL_CAST(BL_PC,target)->special_state.restart_full_recover ) status_revive(target, 100, 100); else status_revive(target, sc->data[SC_KAIZEL]->val2, 0); @@ -869,7 +869,7 @@ int status_heal(struct block_list *bl,int hp,int sp, int flag) sc = NULL; if (hp < 0) { - status_damage(NULL, bl, cap_value(-hp, INT_MIN, INT_MAX), 0, 0, 1); + status_damage(NULL, bl, -hp, 0, 0, 1); hp = 0; } @@ -882,7 +882,7 @@ int status_heal(struct block_list *bl,int hp,int sp, int flag) } if(sp < 0) { - status_damage(NULL, bl, 0, cap_value(-sp, INT_MIN, INT_MAX), 0, 1); + status_damage(NULL, bl, 0, -sp, 0, 1); sp = 0; } @@ -1510,24 +1510,14 @@ int status_calc_mob_(struct mob_data* md, bool first) gc=guild_mapname2gc(map[md->bl.m].name); if (!gc) ShowError("status_calc_mob: No castle set at map %s\n", map[md->bl.m].name); - else { - if(gc->castle_id > 23) { - if(md->class_ == MOBID_EMPERIUM) { - status->max_hp += 1000 * gc->defense; - status->max_sp += 200 * gc->defense; - status->hp = status->max_hp; - status->sp = status->max_sp; - status->def += (gc->defense+2)/3; - status->mdef += (gc->defense+2)/3; - } - }else{ - status->max_hp += 1000 * gc->defense; - status->max_sp += 200 * gc->defense; - status->hp = status->max_hp; - status->sp = status->max_sp; - status->def += (gc->defense+2)/3; - status->mdef += (gc->defense+2)/3; - } + else + if(gc->castle_id < 24 || md->class_ == MOBID_EMPERIUM) { + status->max_hp += 1000 * gc->defense; + status->max_sp += 200 * gc->defense; + status->hp = status->max_hp; + status->sp = status->max_sp; + status->def += (gc->defense+2)/3; + status->mdef += (gc->defense+2)/3; } if(md->class_ != MOBID_EMPERIUM) { status->batk += status->batk * 10*md->guardian_data->guardup_lv/100; @@ -2693,7 +2683,7 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str if ( sc->data[SC_DANCING] || ( - (((TBL_PC*)bl)->class_&MAPID_UPPERMASK) == MAPID_MONK && + (bl->type == BL_PC && ((TBL_PC*)bl)->class_&MAPID_UPPERMASK) == MAPID_MONK && (sc->data[SC_EXTREMITYFIST] || (sc->data[SC_EXPLOSIONSPIRITS] && (!sc->data[SC_SPIRIT] || sc->data[SC_SPIRIT]->val2 != SL_MONK))) ) || sc->data[SC_MAXIMIZEPOWER] @@ -7250,15 +7240,6 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) } break; - case SC_DEVOTION: - //FIXME: use normal status duration instead of a looping timer - if( (sce->val4 -= 1000) > 0 ) - { - sc_timer_next(1000+tick, status_change_timer, bl->id, data); - return 0; - } - break; - case SC_BERSERK: // 5% every 10 seconds [DracoRPG] if( --( sce->val3 ) > 0 && status_charge(bl, sce->val2, 0) && status->hp > 100 ) diff --git a/src/map/status.h b/src/map/status.h index abaeff75e..c7ad8a9cf 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -8,6 +8,7 @@ struct block_list; struct mob_data; struct pet_data; struct homun_data; +struct mercenary_data; struct status_change; //Use this to refer the max refinery level [Skotlex] |