Merge pull request #986 from rathena/feature/pk_traps_setting

Trap Invisibility, Fixes #892
* Changed `traps_setting` config values.
  * 0 = Always visible (default)
  * 1 = Enable invisibility in versus maps (GVG/PVP/BG)
  * 2 = Enable invisibility in all maps
* Added skill unit flag `UF_HIDDEN_TRAP = 0x20000` for trap invisibility. By default, there are (renewal) Hunter traps with this flag:
  * HT_SKIDTRAP
  * HT_LANDMINE
  * HT_ANKLESNARE
  * HT_SHOCKWAVE
  * HT_SANDMAN
  * HT_FLASHER
  * HT_FREEZINGTRAP
  * HT_TALKIEBOX
* Added some skills and effects that can reveal hidden traps. By default, Detect, Sight, Ruwach, and Improve Concentration can reveal hidden traps.
This commit is contained in:
Cydh Ramdh
2016-03-17 05:45:27 +01:00
9 changed files with 146 additions and 56 deletions

View File

@@ -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.

View File

@@ -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:

View File

@@ -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

View File

@@ -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, },

View File

@@ -4878,7 +4878,7 @@ static void clif_graffiti(struct block_list *bl, struct skill_unit *unit, enum s
/// 08c7 <lenght>.W <id> L <creator id>.L <x>.W <y>.W <unit id>.B <range>.W <visible>.B (ZC_SKILL_ENTRY3)
/// 099f <lenght>.W <id> L <creator id>.L <x>.W <y>.W <unit id>.L <range>.W <visible>.B (ZC_SKILL_ENTRY4)
/// 09ca <lenght>.W <id> L <creator id>.L <x>.W <y>.W <unit id>.L <range>.B <visible>.B <skill level>.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);

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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 {

View File

@@ -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.