From a7b8fd4a5d33de75ae61796f21ccb11f14b9a19d Mon Sep 17 00:00:00 2001 From: aleos89 Date: Fri, 6 Nov 2015 10:55:00 -0500 Subject: [PATCH] Bug Fixes * Fixes #696 - Fixed an issue with ammo type fail message for bows and guns. * Fixes #708 - Fixed Neutral Barrier and Stealth Field not staying with the player through warp portals on the same map. Thanks to @exneval. * Added the new Pile Bunker S/P/T items to the Pile Bunker skill equipment check. * Updated Exeed Break damage formula. * Added a check for skill_require_db parsing to skip requirements on invalid item IDs. --- db/pre-re/skill_require_db.txt | 2 +- db/pre-re/skill_unit_db.txt | 2 +- db/re/skill_require_db.txt | 2 +- db/re/skill_unit_db.txt | 2 +- src/map/battle.c | 4 +-- src/map/skill.c | 62 ++++++++++++++++++++++++---------- src/map/status.c | 26 ++++++++------ src/map/unit.c | 2 ++ 8 files changed, 67 insertions(+), 35 deletions(-) diff --git a/db/pre-re/skill_require_db.txt b/db/pre-re/skill_require_db.txt index ac6feabc0f..19f1ba04f4 100644 --- a/db/pre-re/skill_require_db.txt +++ b/db/pre-re/skill_require_db.txt @@ -680,7 +680,7 @@ //**** // 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,0,0 //NC_BOOSTKNUCKLE -2257,0,0,50,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,0,1549 //NC_PILEBUNKER +2257,0,0,50,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,0,1549:16030:16031:16032 //NC_PILEBUNKER 2258,0,0,2:4:6,0,0,0,99,0,0,mado,0,0,6145,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_VULCANARM 2259,0,0,20,0,0,0,99,0,0,mado,0,0,2139,0,6146,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_FLAMELAUNCHER 2260,0,0,20,0,0,0,99,0,0,mado,0,0,6146,1,6147,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_COLDSLOWER diff --git a/db/pre-re/skill_unit_db.txt b/db/pre-re/skill_unit_db.txt index 08365305c5..44fa2b47d3 100644 --- a/db/pre-re/skill_unit_db.txt +++ b/db/pre-re/skill_unit_db.txt @@ -123,7 +123,7 @@ 2254,0xd7, , 0, 1,1000,enemy, 0x8002 //RA_ICEBOUNDTRAP 2273,0xe2, , 2, 0, -1,all, 0x000 //NC_NEUTRALBARRIER -2274,0xe3, , 2, 0, -1,friend,0x000 //NC_STEALTHFIELD +2274,0xe3, , 2, 0, -1,ally, 0x000 //NC_STEALTHFIELD 2299,0xcc, , 0, 1,1000,all, 0x8006 //SC_MANHOLE 2300,0xcd, , 0, 0,1000,all, 0xC006 //SC_DIMENSIONDOOR diff --git a/db/re/skill_require_db.txt b/db/re/skill_require_db.txt index d8aa6eed70..1cf2402862 100644 --- a/db/re/skill_require_db.txt +++ b/db/re/skill_require_db.txt @@ -680,7 +680,7 @@ //**** // 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,0,0 //NC_BOOSTKNUCKLE -2257,0,0,50,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,0,1549 //NC_PILEBUNKER +2257,0,0,50,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,0,1549:16030:16031:16032 //NC_PILEBUNKER 2258,0,0,2:4:6,0,0,0,99,0,0,mado,0,0,6145,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_VULCANARM 2259,0,0,20,0,0,0,99,0,0,mado,0,0,2139,0,6146,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_FLAMELAUNCHER 2260,0,0,20,0,0,0,99,0,0,mado,0,0,6146,1,6147,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //NC_COLDSLOWER diff --git a/db/re/skill_unit_db.txt b/db/re/skill_unit_db.txt index 962c846e3f..4a1a3f98fc 100644 --- a/db/re/skill_unit_db.txt +++ b/db/re/skill_unit_db.txt @@ -125,7 +125,7 @@ 2254,0xd7, , 0, 1,1000,enemy, 0x8002 //RA_ICEBOUNDTRAP 2273,0xe2, , 2, 0, -1,all, 0x000 //NC_NEUTRALBARRIER -2274,0xe3, , 2, 0, -1,friend,0x000 //NC_STEALTHFIELD +2274,0xe3, , 2, 0, -1,ally, 0x000 //NC_STEALTHFIELD 2299,0xcc, , 0, 1,1000,all, 0x8006 //SC_MANHOLE 2300,0xcd, , 0, 0,1000,all, 0xC006 //SC_DIMENSIONDOOR diff --git a/src/map/battle.c b/src/map/battle.c index b4fed245e3..d38c866ca9 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -6909,7 +6909,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t { short index = sd->equip_index[EQI_AMMO]; if (index < 0) { - if (sd->weapontype1 > W_KATAR || sd->weapontype1 < W_HUUMA) + if (sd->weapontype1 > W_KATAR && sd->weapontype1 < W_HUUMA) clif_skill_fail(sd,0,USESKILL_FAIL_NEED_MORE_BULLET,0); else clif_arrow_fail(sd,0); @@ -7054,7 +7054,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t if( sc && sc->count ) { if (sc->data[SC_EXEEDBREAK]) { - wd.damage *= sc->data[SC_EXEEDBREAK]->val1 / 100; + wd.damage *= sc->data[SC_EXEEDBREAK]->val2 / 100; status_change_end(src, SC_EXEEDBREAK, INVALID_TIMER); } if( sc->data[SC_SPELLFIST] ) { diff --git a/src/map/skill.c b/src/map/skill.c index 0f7cab3d77..f4bc3a759b 100755 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -12910,12 +12910,16 @@ static int skill_unit_onplace(struct skill_unit *unit, struct block_list *bl, un case UNT_STEALTHFIELD: if( bl->id == sg->src_id ) - break; // Dont work on Self (video shows that) - case UNT_NEUTRALBARRIER: + break; // Doesn't work on self (video shows that) if (!sce) sc_start(ss, bl,type,100,sg->skill_lv,sg->limit); break; + case UNT_NEUTRALBARRIER: + if (!sce) + status_change_start(ss, bl, type, 10000, sg->skill_lv, 0, 0, 0, sg->limit, SCSTART_NOICON); + break; + case UNT_GD_LEADERSHIP: case UNT_GD_GLORYWOUNDS: case UNT_GD_SOULCOLD: @@ -17470,6 +17474,8 @@ int skill_delunitgroup_(struct skill_unit_group *group, const char* file, int li case DC_DONTFORGETME: case DC_FORTUNEKISS: case DC_SERVICEFORYOU: + case NC_NEUTRALBARRIER: + case NC_STEALTHFIELD: skill_usave_add(((TBL_PC*)src), group->skill_id, group->skill_lv); break; } @@ -19441,33 +19447,42 @@ int skill_blockmerc_start(struct mercenary_data *md, uint16 skill_id, int tick) } /** * Adds a new skill unit entry for this player to recast after map load + * @param sd: Player + * @param skill_id: Skill ID to save + * @param skill_lv: Skill level to save */ -void skill_usave_add(struct map_session_data * sd, uint16 skill_id, uint16 skill_lv) { - struct skill_usave * sus = NULL; +void skill_usave_add(struct map_session_data *sd, uint16 skill_id, uint16 skill_lv) +{ + struct skill_usave *sus = NULL; - if( idb_exists(skillusave_db,sd->status.char_id) ) { + if (idb_exists(skillusave_db,sd->status.char_id)) idb_remove(skillusave_db,sd->status.char_id); - } CREATE(sus, struct skill_usave, 1); idb_put(skillusave_db, sd->status.char_id, sus); sus->skill_id = skill_id; sus->skill_lv = skill_lv; - - return; } -void skill_usave_trigger(struct map_session_data *sd) { - struct skill_usave * sus = NULL; - if( ! (sus = (struct skill_usave *)idb_get(skillusave_db,sd->status.char_id)) ) +/** + * Loads saved skill unit entries for this player after map load + * @param sd: Player + */ +void skill_usave_trigger(struct map_session_data *sd) +{ + struct skill_usave *sus = NULL; + struct skill_unit_group *group = NULL; + + if (!(sus = idb_get(skillusave_db,sd->status.char_id))) return; - skill_unitsetting(&sd->bl,sus->skill_id,sus->skill_lv,sd->bl.x,sd->bl.y,0); - idb_remove(skillusave_db,sd->status.char_id); - - return; + if ((group = skill_unitsetting(&sd->bl, sus->skill_id, sus->skill_lv, sd->bl.x, sd->bl.y, 0))) + if (sus->skill_id == NC_NEUTRALBARRIER || sus->skill_id == NC_STEALTHFIELD ) + sc_start2(&sd->bl, &sd->bl, (sus->skill_id == NC_NEUTRALBARRIER ? SC_NEUTRALBARRIER_MASTER : SC_STEALTHFIELD_MASTER), 100, sus->skill_lv, group->group_id, skill_get_time(sus->skill_id, sus->skill_lv)); + idb_remove(skillusave_db, sd->status.char_id); } + /* * */ @@ -20150,7 +20165,7 @@ static bool skill_parse_row_skilldb(char* split[], int columns, int current) } /** - * Split string to int by constanta value (const.txt) or atoi() + * Split string to int by constant value (const.txt) or atoi() * @param *str: String input * @param *val: Temporary storage * @param *delim: Delimiter (for multiple value support) @@ -20164,6 +20179,7 @@ uint8 skill_split_atoi2(char *str, int *val, const char *delim, int min_value, u while (p != NULL) { int n = min_value; + trim(p); if (ISDIGIT(p[0])) // If using numeric @@ -20200,7 +20216,7 @@ static void skill_destroy_requirement(uint16 idx) { /** * Read skill requirement from skill_require_db.txt - * Structure: skill_id,HPCost,MaxHPTrigger,SPCost,HPRateCost,SPRateCost,ZenyCost,RequiredWeapons,RequiredAmmoTypes,RequiredAmmoAmount,RequiredState,RequiredStatuss,SpiritSphereCost,RequiredItemID1,RequiredItemAmount1,RequiredItemID2,RequiredItemAmount2,RequiredItemID3,RequiredItemAmount3,RequiredItemID4,RequiredItemAmount4,RequiredItemID5,RequiredItemAmount5,RequiredItemID6,RequiredItemAmount6,RequiredItemID7,RequiredItemAmount7,RequiredItemID8,RequiredItemAmount8,RequiredItemID9,RequiredItemAmount9,RequiredItemID10,RequiredItemAmount10 + * Structure: skill_id,HPCost,MaxHPTrigger,SPCost,HPRateCost,SPRateCost,ZenyCost,RequiredWeapons,RequiredAmmoTypes,RequiredAmmoAmount,RequiredState,RequiredStatuses,SpiritSphereCost,RequiredItemID1,RequiredItemAmount1,RequiredItemID2,RequiredItemAmount2,RequiredItemID3,RequiredItemAmount3,RequiredItemID4,RequiredItemAmount4,RequiredItemID5,RequiredItemAmount5,RequiredItemID6,RequiredItemAmount6,RequiredItemID7,RequiredItemAmount7,RequiredItemID8,RequiredItemAmount8,RequiredItemID9,RequiredItemAmount9,RequiredItemID10,RequiredItemAmount10,RequiredEquipment */ static bool skill_parse_row_requiredb(char* split[], int columns, int current) { @@ -20269,6 +20285,7 @@ static bool skill_parse_row_requiredb(char* split[], int columns, int current) trim(split[11]); if (split[11][0] != '\0' || atoi(split[11])) { int require[MAX_SKILL_STATUS_REQUIRE]; + if ((skill_db[idx]->require.status_count = skill_split_atoi2(split[11], require, ":", SC_STONE, ARRAYLENGTH(require)))) { CREATE(skill_db[idx]->require.status, enum sc_type, skill_db[idx]->require.status_count); for (i = 0; i < skill_db[idx]->require.status_count; i++) @@ -20279,16 +20296,25 @@ static bool skill_parse_row_requiredb(char* split[], int columns, int current) skill_split_atoi(split[12],skill_db[idx]->require.spiritball); for( i = 0; i < MAX_SKILL_ITEM_REQUIRE; i++ ) { + if (atoi(split[13 + 2 * i]) > 0 && !itemdb_exists(atoi(split[13 + 2 * i]))) { + ShowError("skill_parse_row_requiredb: Invalid item %d for skill %d.\n", atoi(split[13 + 2 * i]), atoi(split[0])); + return false; + } skill_db[idx]->require.itemid[i] = atoi(split[13+ 2*i]); skill_db[idx]->require.amount[i] = atoi(split[14+ 2*i]); } //Equipped Item requirements. - //NOTE: We don't check the item is exist or not here trim(split[33]); if (split[33][0] != '\0' || atoi(split[33])) { int require[MAX_SKILL_EQUIP_REQUIRE]; + if ((skill_db[idx]->require.eqItem_count = skill_split_atoi2(split[33], require, ":", 500, ARRAYLENGTH(require)))) { + if (require[i] > 0 && !itemdb_exists(require[i])) { + ShowError("skill_parse_row_requiredb: Invalid item %d for skill %d.\n", require[i], atoi(split[0])); + return false; + } + CREATE(skill_db[idx]->require.eqItem, uint16, skill_db[idx]->require.eqItem_count); for (i = 0; i < skill_db[idx]->require.eqItem_count; i++) skill_db[idx]->require.eqItem[i] = require[i]; diff --git a/src/map/status.c b/src/map/status.c index 08a5b46721..79c4fa8679 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -1166,6 +1166,7 @@ void initChangeTables(void) StatusDisplayType[SC_SPHERE_4] = true; StatusDisplayType[SC_SPHERE_5] = true; StatusDisplayType[SC_CAMOUFLAGE] = true; + StatusDisplayType[SC_STEALTHFIELD] = true; StatusDisplayType[SC_DUPLELIGHT] = true; StatusDisplayType[SC_ORATIO] = true; StatusDisplayType[SC_FREEZING] = true; @@ -6168,7 +6169,7 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha if( sc->data[SC_CAMOUFLAGE] && (sc->data[SC_CAMOUFLAGE]->val3&1) == 0 ) val = max( val, sc->data[SC_CAMOUFLAGE]->val1 < 3 ? 0 : 25 * (5 - sc->data[SC_CAMOUFLAGE]->val1) ); if( sc->data[SC_STEALTHFIELD] ) - val = max( val, sc->data[SC_STEALTHFIELD]->val2 ); + val = max( val, 20 ); if( sc->data[SC__LAZINESS] ) val = max( val, 25 ); if( sc->data[SC_BANDING_DEFENCE] ) @@ -9823,14 +9824,14 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty tick_time = 10000; // [GodLesZ] tick time break; case SC_EXEEDBREAK: - val1 = 100 * val1; + val2 = 150 * val1; if (sd) { // Players short index = sd->equip_index[EQI_HAND_R]; if (index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON) - val1 += 10 * sd->status.job_level + sd->inventory_data[index]->weight / 10 * sd->inventory_data[index]->wlv * status_get_lv(bl) / 100; + val2 += 15 * sd->status.job_level + sd->inventory_data[index]->weight / 10 * sd->inventory_data[index]->wlv * status_get_lv(bl) / 100; } else // Monster - val1 += 500; + val2 += 750; break; case SC_PRESTIGE: val2 = (status->int_ + status->luk) * val1 / 20 * status_get_lv(bl) / 200 + val1; // Chance to evade magic damage. @@ -10162,12 +10163,12 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty break; case SC_STEALTHFIELD: - val2 = 30; // Speed reduction + tick_time = tick; + tick = -1; break; case SC_STEALTHFIELD_MASTER: - val3 = 3; // Reduces SP 3% - tick_time = 3000; - val4 = tick/tick_time; + tick_time = val3 = 2000 + 1000 * val1; + val4 = tick / tick_time; break; case SC_VACUUM_EXTREME: // Suck target at n second, only if the n second is lower than the duration @@ -10392,6 +10393,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_CHASEWALK: case SC_WEIGHT90: case SC_CAMOUFLAGE: + case SC_STEALTHFIELD: case SC_VOICEOFSIREN: case SC_HEAT_BARREL_AFTER: case SC_WEDDING: @@ -10531,6 +10533,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC__INVISIBILITY: sc->option |= OPTION_CLOAK; case SC_CAMOUFLAGE: + case SC_STEALTHFIELD: opt_flag = 2; break; case SC_CHASEWALK: @@ -11426,6 +11429,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const case SC__INVISIBILITY: sc->option &= ~OPTION_CLOAK; case SC_CAMOUFLAGE: + case SC_STEALTHFIELD: opt_flag |= 2; break; case SC_CHASEWALK: @@ -12506,10 +12510,10 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) break; case SC_STEALTHFIELD_MASTER: if (--(sce->val4) >= 0) { - int sp = (status->max_sp * sce->val3) / 100; - if (!status_charge(bl,0,sp)) + if (!status_charge(bl, 0, status->max_sp * 3 / 100)) break; - sc_timer_next(3000 + tick, status_change_timer, bl->id, data); + sc_timer_next(sce->val3 + tick, status_change_timer, bl->id, data); + return 0; } break; case SC_VACUUM_EXTREME: diff --git a/src/map/unit.c b/src/map/unit.c index 698b41c722..80e4f31ddf 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -2860,6 +2860,8 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, status_change_end(bl, SC_STOP, INVALID_TIMER); status_change_end(bl, SC_WUGDASH, INVALID_TIMER); status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); + status_change_end(bl, SC_NEUTRALBARRIER_MASTER, INVALID_TIMER); + status_change_end(bl, SC_STEALTHFIELD_MASTER, INVALID_TIMER); status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); status_change_end(bl, SC__MANHOLE, INVALID_TIMER); status_change_end(bl, SC_VACUUM_EXTREME, INVALID_TIMER);