diff --git a/conf/battle/skill.conf b/conf/battle/skill.conf index 1fbacfb68c..51f92a9fbb 100644 --- a/conf/battle/skill.conf +++ b/conf/battle/skill.conf @@ -118,11 +118,11 @@ skill_nofootset: 1 // Default on official servers: 1 (for players) gvg_traps_target_all: 1 -// Hunter's traps visibility setting: -// 1: (Official) Many of Hunter's traps are invisible at all times. -// But any player who see the Hunter laying the trap will be able to see the trap until they move out of sight of it. -// Although, invisible traps can be revealed through Hunter's Detecting skill. -traps_setting: 1 +// Traps visibility setting (trap with UF_HIDDEN_TRAP flag): +// 0 = Always visible +// 1 = Enable invisibility in versus maps (GVG/PVP/BG) +// 2 = Enable invisibility in all maps +traps_setting: 0 // Restrictions applied to the Alchemist's Summon Flora skill (add as necessary) // 1: Enable players to damage the floras outside of versus grounds. diff --git a/db/pre-re/skill_unit_db.txt b/db/pre-re/skill_unit_db.txt index ec83ae701f..dd8161308b 100644 --- a/db/pre-re/skill_unit_db.txt +++ b/db/pre-re/skill_unit_db.txt @@ -23,6 +23,7 @@ // 0x04000(UF_REM_CRAZYWEED) Removed if be overlapped by GN_CRAZYWEED // 0x08000(UF_REM_FIRERAIN) Removed if be overlapped by RL_FIRE_RAIN // 0x10000(UF_KNOCKBACK_GROUP) Knock back a whole skill group (by default, skill unit is knocked back each unit) +// 0x20000(UF_HIDDEN_TRAP) Hidden trap, see 'traps_setting' skill config to enable this flag // Example: 0x006 = 0x002+0x004 -> Cannot be stacked nor cast near targets // // Notes: diff --git a/db/re/skill_unit_db.txt b/db/re/skill_unit_db.txt index 30dbe76ed6..2fc4d17aa5 100644 --- a/db/re/skill_unit_db.txt +++ b/db/re/skill_unit_db.txt @@ -23,6 +23,7 @@ // 0x04000(UF_REM_CRAZYWEED) Removed if be overlapped by GN_CRAZYWEED // 0x08000(UF_REM_FIRERAIN) Removed if be overlapped by RL_FIRE_RAIN // 0x10000(UF_KNOCKBACK_GROUP) Knock back a whole skill group (by default, skill unit is knocked back each unit) +// 0x20000(UF_HIDDEN_TRAP) Hidden trap, see 'traps_setting' skill config to enable this flag // Example: 0x006 = 0x002+0x004 -> Cannot be stacked nor cast near targets // // Notes: @@ -46,16 +47,16 @@ 89,0x86, , 4, 1, 450,enemy, 0x018 //WZ_STORMGUST 91,0x86, , 2, 0,1000,enemy, 0x010 //WZ_HEAVENDRIVE 92,0x8e, , 2, 0, -1,enemy, 0x8010 //WZ_QUAGMIRE -115,0x90, , 0, 1,1000,enemy, 0x8006 //HT_SKIDTRAP -116,0x93, , 0, 1,1000,enemy, 0x8006 //HT_LANDMINE -117,0x91, , 0, 1,1000,enemy, 0x9006 //HT_ANKLESNARE -118,0x94, , 0, 1,1000,enemy, 0x8006 //HT_SHOCKWAVE -119,0x95, , 0, 1,1000,enemy, 0x8006 //HT_SANDMAN -120,0x96, , 0, 1,1000,enemy, 0x8006 //HT_FLASHER -121,0x97, , 0, 1,1000,enemy, 0x8006 //HT_FREEZINGTRAP +115,0x90, , 0, 1,1000,enemy, 0x28006 //HT_SKIDTRAP +116,0x93, , 0, 1,1000,enemy, 0x28006 //HT_LANDMINE +117,0x91, , 0, 1,1000,enemy, 0x29006 //HT_ANKLESNARE +118,0x94, , 0, 1,1000,enemy, 0x28006 //HT_SHOCKWAVE +119,0x95, , 0, 1,1000,enemy, 0x28006 //HT_SANDMAN +120,0x96, , 0, 1,1000,enemy, 0x28006 //HT_FLASHER +121,0x97, , 0, 1,1000,enemy, 0x28006 //HT_FREEZINGTRAP 122,0x8f, , 0, 1,1000,enemy, 0x8006 //HT_BLASTMINE 123,0x98, , 0, 1,1000,enemy, 0x8006 //HT_CLAYMORETRAP -125,0x99, , 0, 1,1000,all, 0x8000 //HT_TALKIEBOX +125,0x99, , 0, 1,1000,all, 0x28000 //HT_TALKIEBOX 140,0x92, , -1, 1,1000,enemy, 0x8000 //AS_VENOMDUST 220,0xb0, , 0, 0, -1,all, 0x8002 //RG_GRAFFITI 229,0xb1, , 0, 1, 500,enemy, 0x006 //AM_DEMONSTRATION diff --git a/src/map/battle.c b/src/map/battle.c index d8f9ff2305..853bf01cc2 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -7732,7 +7732,7 @@ static const struct _battle_data { { "player_damage_delay_rate", &battle_config.pc_damage_delay_rate, 100, 0, INT_MAX, }, { "defunit_not_enemy", &battle_config.defnotenemy, 0, 0, 1, }, { "gvg_traps_target_all", &battle_config.vs_traps_bctall, BL_PC, BL_NUL, BL_ALL, }, - { "traps_setting", &battle_config.traps_setting, 0, 0, 1, }, + { "traps_setting", &battle_config.traps_setting, 0, 0, 2, }, { "summon_flora_setting", &battle_config.summon_flora, 1|2, 0, 1|2, }, { "clear_skills_on_death", &battle_config.clear_unit_ondeath, BL_NUL, BL_NUL, BL_ALL, }, { "clear_skills_on_warp", &battle_config.clear_unit_onwarp, BL_ALL, BL_NUL, BL_ALL, }, diff --git a/src/map/clif.c b/src/map/clif.c index 230128c882..c33c2976f6 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -4878,7 +4878,7 @@ static void clif_graffiti(struct block_list *bl, struct skill_unit *unit, enum s /// 08c7 .W L .L .W .W .B .W .B (ZC_SKILL_ENTRY3) /// 099f .W L .L .W .W .L .W .B (ZC_SKILL_ENTRY4) /// 09ca .W L .L .W .W .L .B .B .B (ZC_SKILL_ENTRY5) -void clif_getareachar_skillunit(struct block_list *bl, struct skill_unit *unit, enum send_target target, uint8 flag) { +void clif_getareachar_skillunit(struct block_list *bl, struct skill_unit *unit, enum send_target target, bool visible) { int header = 0, unit_id = 0, pos = 0, fd = 0, len = -1; unsigned char buf[128]; @@ -4898,23 +4898,8 @@ void clif_getareachar_skillunit(struct block_list *bl, struct skill_unit *unit, else unit_id = unit->group->unit_id; - if (flag && battle_config.traps_setting&1) { - switch(unit->group->skill_id) { - case HT_ANKLESNARE: - if (!map_flag_vs(((TBL_PC*)bl)->bl.m)) - break; - case HT_SKIDTRAP: - case MA_SKIDTRAP: - case HT_SHOCKWAVE: - case HT_SANDMAN: - case MA_SANDMAN: - case HT_FLASHER: - case HT_FREEZINGTRAP: - case MA_FREEZINGTRAP: - unit_id = UNT_DUMMYSKILL; // Use invisible unit id for Hunter's traps - break; - } - } + if (!visible) + unit_id = UNT_DUMMYSKILL; // Hack to makes hidden trap really hidden! #if PACKETVER >= 3 if (unit_id == UNT_GRAFFITI) { // Graffiti [Valaris] @@ -4948,22 +4933,22 @@ void clif_getareachar_skillunit(struct block_list *bl, struct skill_unit *unit, switch (header) { case 0x011f: WBUFB(buf,pos+14) = unit_id; - WBUFB(buf,pos+15) = 1; + WBUFB(buf,pos+15) = visible; break; case 0x08c7: WBUFB(buf,pos+14) = unit_id; WBUFW(buf,pos+15) = unit->range; - WBUFB(buf,pos+17) = 1; + WBUFB(buf,pos+17) = visible; break; case 0x099f: WBUFL(buf,pos+14) = unit_id; WBUFW(buf,pos+18) = unit->range; - WBUFB(buf,pos+20) = 1; + WBUFB(buf,pos+20) = visible; break; case 0x09ca: WBUFL(buf,pos+14) = unit_id; WBUFB(buf,pos+18) = (unsigned char)unit->range; - WBUFB(buf,pos+19) = 1; + WBUFB(buf,pos+19) = visible; WBUFB(buf,pos+20) = (unsigned char)unit->group->skill_lv; break; } @@ -5039,7 +5024,7 @@ static int clif_getareachar(struct block_list* bl,va_list ap) clif_getareachar_item(sd,(struct flooritem_data*) bl); break; case BL_SKILL: - clif_getareachar_skillunit(&sd->bl, (TBL_SKILL*)bl, SELF, 1); + skill_getareachar_skillunit_visibilty_single((TBL_SKILL*)bl, &sd->bl); break; default: if(&sd->bl == bl) @@ -5127,7 +5112,7 @@ 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->bl, (TBL_SKILL*)bl, SELF, 1); + skill_getareachar_skillunit_visibilty_single((TBL_SKILL*)bl, &tsd->bl); break; default: clif_getareachar_unit(tsd,bl); diff --git a/src/map/clif.h b/src/map/clif.h index c7de7b21b1..b7fd4fdbe6 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -631,7 +631,7 @@ void clif_cooking_list(struct map_session_data *sd, int trigger, uint16 skill_id void clif_produceeffect(struct map_session_data* sd,int flag, unsigned short nameid); -void clif_getareachar_skillunit(struct block_list *bl, struct skill_unit *unit, enum send_target target, uint8 flag); +void clif_getareachar_skillunit(struct block_list *bl, struct skill_unit *unit, enum send_target target, bool visible); void clif_skill_delunit(struct skill_unit *unit); void clif_skillunit_update(struct block_list* bl); diff --git a/src/map/skill.c b/src/map/skill.c index 8f20a2ea81..0b66007040 100755 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -4224,20 +4224,39 @@ static int skill_active_reverberation(struct block_list *bl, va_list ap) { return 1; } +/** + * Reveal hidden trap + **/ 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. + if (su->alive && su->group && su->hidden && skill_get_inf2(su->group->skill_id)&INF2_TRAP) { //Change look is not good enough, the client ignores it as an actual trap still. [Skotlex] //clif_changetraplook(bl, su->group->unit_id); - clif_getareachar_skillunit(&su->bl, su, AREA, 0); + + su->hidden = false; + skill_getareachar_skillunit_visibilty(su, AREA); return 1; } return 0; } +/** + * Attempt to reaveal trap in area + * @param src Skill caster + * @param range Affected range + * @param x + * @param y + * TODO: Remove hardcode usages for this function + **/ +void skill_reveal_trap_inarea(struct block_list *src, int range, int x, int y) { + if (!battle_config.traps_setting) + return; + nullpo_retv(src); + map_foreachinarea(skill_reveal_trap, src->m, x-range, y-range, x+range, y+range, BL_SKILL); +} + /*========================================== * * @@ -6529,11 +6548,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case AC_CONCENTRATION: { + int splash = skill_get_splash(skill_id, skill_lv); clif_skill_nodamage(src,bl,skill_id,skill_lv, sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv))); + skill_reveal_trap_inarea(src, splash, src->x, src->y); map_foreachinrange( status_change_timer_sub, src, - skill_get_splash(skill_id, skill_lv), BL_CHAR, - src,NULL,type,tick); + splash, BL_CHAR, src, NULL, type, tick); } break; @@ -11363,9 +11383,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui map_foreachinarea( status_change_timer_sub, src->m, x-i, y-i, x+i,y+i,BL_CHAR, src,NULL,SC_SIGHT,tick); - if(battle_config.traps_setting&1) - map_foreachinarea(skill_reveal_trap, src->m, x-i, y-i, x+i, y+i, BL_SKILL); - break; + skill_reveal_trap_inarea(src, i, x, y); break; case SR_RIDEINLIGHTNING: @@ -12242,7 +12260,7 @@ static int skill_dance_overlap_sub(struct block_list* bl, va_list ap) else //Remove dissonance target->val2 &= ~UF_ENSEMBLE; - clif_getareachar_skillunit(&target->bl, target, AREA, 0); //Update look of affected cell. + skill_getareachar_skillunit_visibilty(target, AREA); return 1; } @@ -12350,6 +12368,7 @@ struct skill_unit_group *skill_unitsetting(struct block_list *src, uint16 skill_ struct status_change *sc; int active_flag = 1; int subunt = 0; + bool hidden = false; nullpo_retr(NULL, src); @@ -12363,6 +12382,7 @@ struct skill_unit_group *skill_unitsetting(struct block_list *src, uint16 skill_ sd = BL_CAST(BL_PC, src); status = status_get_status_data(src); sc = status_get_sc(src); // for traps, firewall and fogwall - celest + hidden = (unit_flag&UF_HIDDEN_TRAP && (battle_config.traps_setting == 2 || (battle_config.traps_setting == 1 && map_flag_vs(src->m)))); switch( skill_id ) { case MH_STEINWAND: @@ -12822,7 +12842,7 @@ struct skill_unit_group *skill_unitsetting(struct block_list *src, uint16 skill_ if( !alive ) continue; - nullpo_retr(NULL, (unit = skill_initunit(group,i,ux,uy,unit_val1,unit_val2))); + nullpo_retr(NULL, (unit = skill_initunit(group,i,ux,uy,unit_val1,unit_val2,hidden))); unit->limit = limit; unit->range = range; @@ -17250,6 +17270,77 @@ bool skill_check_camouflage(struct block_list *bl, struct status_change_entry *s return wall; } +/** + * Process skill unit visibilty for single BL in area + * @param bl + * @param ap + * @author [Cydh] + **/ +int skill_getareachar_skillunit_visibilty_sub(struct block_list *bl, va_list ap) { + struct skill_unit *su = NULL; + struct block_list *src = NULL; + unsigned int party1 = 0; + bool visible = true; + + nullpo_ret(bl); + nullpo_ret((su = va_arg(ap, struct skill_unit*))); + nullpo_ret((src = va_arg(ap, struct block_list*))); + party1 = va_arg(ap, unsigned int); + + if (src != bl) { + unsigned int party2 = status_get_party_id(bl); + if (!party1 || !party2 || party1 != party2) + visible = false; + } + + clif_getareachar_skillunit(bl, su, SELF, visible); + return 1; +} + +/** + * Check for skill unit visibilty in area on + * - skill first placement + * - skill moved (knocked back, moved dance) + * @param su Skill unit + * @param target Affected target for this visibility @see enum send_target + * @author [Cydh] + **/ +void skill_getareachar_skillunit_visibilty(struct skill_unit *su, enum send_target target) { + nullpo_retv(su); + + if (!su->hidden) // It's not hidden, just do this! + clif_getareachar_skillunit(&su->bl, su, target, true); + else { + struct block_list *src = battle_get_master(&su->bl); + map_foreachinarea(skill_getareachar_skillunit_visibilty_sub, su->bl.m, su->bl.x-AREA_SIZE, su->bl.y-AREA_SIZE, + su->bl.x+AREA_SIZE, su->bl.y+AREA_SIZE, BL_PC, su, src, status_get_party_id(src)); + } +} + +/** + * Check for skill unit visibilty on single BL on insight/spawn action + * @param su Skill unit + * @param bl Block list + * @author [Cydh] + **/ +void skill_getareachar_skillunit_visibilty_single(struct skill_unit *su, struct block_list *bl) { + bool visible = true; + struct block_list *src = NULL; + + nullpo_retv(bl); + nullpo_retv(su); + nullpo_retv((src = battle_get_master(&su->bl))); + + if (su->hidden && src != bl) { + unsigned int party1 = status_get_party_id(src); + unsigned int party2 = status_get_party_id(bl); + if (!party1 || !party2 || party1 != party2) + visible = false; + } + + clif_getareachar_skillunit(bl, su, SELF, visible); +} + /** * Initialize new skill unit for skill unit group. * Overall, Skill Unit makes skill unit group which each group holds their cell datas (skill unit) @@ -17260,7 +17351,7 @@ bool skill_check_camouflage(struct block_list *bl, struct status_change_entry *s * @param val1 * @param val2 */ -struct skill_unit *skill_initunit(struct skill_unit_group *group, int idx, int x, int y, int val1, int val2) +struct skill_unit *skill_initunit(struct skill_unit_group *group, int idx, int x, int y, int val1, int val2, bool hidden) { struct skill_unit *unit; @@ -17283,6 +17374,7 @@ struct skill_unit *skill_initunit(struct skill_unit_group *group, int idx, int x unit->alive = 1; unit->val1 = val1; unit->val2 = val2; + unit->hidden = hidden; // Stores new skill unit idb_put(skillunit_db, unit->bl.id, unit); @@ -17312,7 +17404,7 @@ struct skill_unit *skill_initunit(struct skill_unit_group *group, int idx, int x break; } - clif_getareachar_skillunit(&unit->bl, unit, AREA, 0); + skill_getareachar_skillunit_visibilty(unit, AREA); return unit; } @@ -18163,7 +18255,7 @@ void skill_unit_move_unit(struct block_list *bl, int dx, int dy) { map_moveblock(bl, dx, dy, tick); map_foreachincell(skill_unit_effect,bl->m,bl->x,bl->y,su->group->bl_flag,bl,tick,1); - clif_getareachar_skillunit(bl, su, AREA, 0); + skill_getareachar_skillunit_visibilty(su, AREA); return; } @@ -18257,7 +18349,7 @@ void skill_unit_move_unit_group(struct skill_unit_group *group, int16 m, int16 d if (!(m_flag[i]&0x2)) { //We only moved the cell in 0-1 if (group->state.song_dance&0x1) //Check for dissonance effect. skill_dance_overlap(unit1, 1); - clif_getareachar_skillunit(&unit1->bl, unit1, AREA, 0); + skill_getareachar_skillunit_visibilty(unit1, AREA); map_foreachincell(skill_unit_effect,unit1->bl.m,unit1->bl.x,unit1->bl.y,group->bl_flag,&unit1->bl,tick,1); } } diff --git a/src/map/skill.h b/src/map/skill.h index 82d850e4c1..b82ba33330 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -295,7 +295,9 @@ struct skill_unit { struct skill_unit_group *group; /// Skill group reference int limit; int val1, val2; - short alive, range; + short range; + unsigned alive : 1; + unsigned hidden : 1; }; #define MAX_SKILLUNITGROUPTICKSET 25 @@ -323,6 +325,7 @@ enum e_skill_unit_flag { UF_REM_CRAZYWEED = 0x04000, // removed by Crazyweed UF_REM_FIRERAIN = 0x08000, // removed by Fire Rain UF_KNOCKBACK_GROUP = 0x10000, // knockback skill unit with its group instead of single unit + UF_HIDDEN_TRAP = 0x20000, // Hidden trap [Cydh] }; /// Create Database item @@ -435,7 +438,7 @@ int skill_strip_equip(struct block_list *src,struct block_list *bl, unsigned sho // Skills unit struct skill_unit_group *skill_id2group(int group_id); struct skill_unit_group *skill_unitsetting(struct block_list* src, uint16 skill_id, uint16 skill_lv, 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); +struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int x, int y, int val1, int val2, bool hidden); int skill_delunit(struct skill_unit *unit); struct skill_unit_group *skill_initunitgroup(struct block_list* src, int count, uint16 skill_id, uint16 skill_lv, int unit_id, int limit, int interval); int skill_delunitgroup_(struct skill_unit_group *group, const char* file, int line, const char* func); @@ -445,6 +448,10 @@ int skill_clear_group(struct block_list *bl, int flag); void ext_skill_unit_onplace(struct skill_unit *unit, struct block_list *bl, unsigned int tick); int64 skill_unit_ondamaged(struct skill_unit *unit,int64 damage); +// Skill unit visibility [Cydh] +void skill_getareachar_skillunit_visibilty(struct skill_unit *su, enum send_target target); +void skill_getareachar_skillunit_visibilty_single(struct skill_unit *su, struct block_list *bl); + int skill_castfix(struct block_list *bl, uint16 skill_id, uint16 skill_lv); int skill_castfix_sc(struct block_list *bl, double time, uint8 flag); #ifdef RENEWAL_CAST @@ -2077,6 +2084,8 @@ bool skill_is_combo(uint16 skill_id); void skill_combo_toogle_inf(struct block_list* bl, uint16 skill_id, int inf); void skill_combo(struct block_list* src,struct block_list *dsrc, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int tick); +void skill_reveal_trap_inarea(struct block_list *src, int range, int x, int y); + #ifdef ADJUST_SKILL_DAMAGE /// Skill Damage target enum e_skill_damage_caster { diff --git a/src/map/status.c b/src/map/status.c index 75c90b5fbe..1d7278873f 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -11834,8 +11834,10 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) if(sce->val4%2) sce->val4--; map_foreachinrange( status_change_timer_sub, bl, sce->val3, BL_CHAR|BL_SKILL, bl, sce, type, tick); - } else + } else { map_foreachinrange( status_change_timer_sub, bl, sce->val3, BL_CHAR, bl, sce, type, tick); + skill_reveal_trap_inarea(bl, sce->val3, bl->x, bl->y); + } if( --(sce->val2)>0 ) { sce->val4 += 20; // Use for Shadow Form 2 seconds checking.