* Created a better structure for status changes with intervals and integrated the status changes Stone, Poison, Deadly Poison, Bleeding, Magic Mushroom, Burning, Pyrexia, Leech's End and Toxin into the new structure -- The exact remaining duration of these status changes will now be stored -- The correct duration is reloaded when logging back in, you can't avoid a single tick be re-logging -- It will now show the correct duration on the icon of the status change after re-logging, no longer negative values -- The durations are now accurately transferred when using Deadly Infect -- These status changes now use unified code, which makes it much easier to integrate more status changes into this structure with low risk of breaking something * Removed all the status change specific logging of damage and integrated it into the normal logging behavior -- The following skills deal "No source" damage: Stone, Poison, Deadly Poison, Bleeding, Coma, Magic Mushroom -- The following skills deal "Self" damage: Burning, Pyrexia, Leech's End, Toxin -- "No source" will neither be logged nor contribute to the total damage, your exp share doesn't increase from the damage, but it also won't cause the monster to give less EXP, it won't break freeze or similar status changes, it won't make you stand up, it won't make you stop moving, it won't prevent you from logging out -- "Self" damage will now be logged and contribute to the total damage, it makes monster give the exp tap bonus, but also makes monsters give less exp the more "self damage" they've taken, it will break freeze and similar status changes, it will make you stand up properly now, it will make you flinch and stop moving, it will prevent you from logging out, but angry type monsters will not lose their aggressive bit from it and it will not cause monsters to use their rude-attack skill -- Monsters will now use their rude-attack skill on the first rude-attack as long as the damage does not come from self -- When a monster takes damage from a status change, its HP meter will now be updated * Burning now has an interval of 3s and a minimum duration of 10s * Pyrexia now causes blind for Pyrexia's duration instead of just 30s * Ground Drift's poison base duration is now 60s in pre-re (follow-up to e7150ee) * Fixed a bug where the minimum duration failed to apply when the received duration was below 1ms * map_foreachindir and map_foreachinshootarea will now properly print their function names in case of an error * Updated documentation (transferring source ID is no longer required, remaining tick should now always be in val4) If this breaks anything, please report asap.
This commit is contained in:
parent
0f5b6db813
commit
a6f73a6227
@ -859,7 +859,7 @@
|
|||||||
//-- GS_FULLBUSTER
|
//-- GS_FULLBUSTER
|
||||||
519,0,1200:1400:1600:1800:2000:2200:2400:2600:2800:3000,0,0,10000,0
|
519,0,1200:1400:1600:1800:2000:2200:2400:2600:2800:3000,0,0,10000,0
|
||||||
//-- GS_GROUNDDRIFT (Upkeep2 times are duration of: Stun(lv1), Blind(lv2), Poison(lv3) and Freeze(lv4))
|
//-- GS_GROUNDDRIFT (Upkeep2 times are duration of: Stun(lv1), Blind(lv2), Poison(lv3) and Freeze(lv4))
|
||||||
521,2000,0,0,3000:6000:9000:12000:15000:18000:21000:24000:27000:30000,5000:30000:30000:12000,0
|
521,2000,0,0,3000:6000:9000:12000:15000:18000:21000:24000:27000:30000,5000:30000:60000:12000,0
|
||||||
//==========================================
|
//==========================================
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,9 +25,9 @@
|
|||||||
SC_STONE ()
|
SC_STONE ()
|
||||||
desc: DEF -50%; if HP>25% lose 1% HP/5 sec; MDEF +25%; change element to Earth Lv 1; ignore Steal & Lex Aeterna; can't move/attack/pick item/use item/use skill/sit/logout
|
desc: DEF -50%; if HP>25% lose 1% HP/5 sec; MDEF +25%; change element to Earth Lv 1; ignore Steal & Lex Aeterna; can't move/attack/pick item/use item/use skill/sit/logout
|
||||||
val1:
|
val1:
|
||||||
val2: Caster's object ID (for mob_log_damage)
|
val2: Caster's object ID
|
||||||
val3: Tick
|
val3: Incubation time
|
||||||
val4: Petrifying tick
|
val4: Remaining tick
|
||||||
|
|
||||||
SC_FREEZE ()
|
SC_FREEZE ()
|
||||||
desc: DEF -50%; FLEE = 0; MDEF +25%; ignore Steal, Lex Aeterna, Storm Gust, Falling Ice Pillar; change element to Water Lv 1; can't move/attack/pick item/use item/sit/logout
|
desc: DEF -50%; FLEE = 0; MDEF +25%; ignore Steal, Lex Aeterna, Storm Gust, Falling Ice Pillar; change element to Water Lv 1; can't move/attack/pick item/use item/sit/logout
|
||||||
@ -44,9 +44,9 @@ SC_SLEEP ()
|
|||||||
SC_POISON ()
|
SC_POISON ()
|
||||||
desc: DEF -25%; if HP>25% lose 1.5% + 2 HP/sec; SP Regeneration is disabled
|
desc: DEF -25%; if HP>25% lose 1.5% + 2 HP/sec; SP Regeneration is disabled
|
||||||
val1: Skill Level
|
val1: Skill Level
|
||||||
val2: Caster's object ID (for mob_log_damage)
|
val2: Caster's object ID
|
||||||
val3: Tick
|
val3:
|
||||||
val4: HP Damage
|
val4: Remaining tick
|
||||||
|
|
||||||
SC_CURSE ()
|
SC_CURSE ()
|
||||||
desc: ATK-25%; LUK = 0; Movement speed -300
|
desc: ATK-25%; LUK = 0; Movement speed -300
|
||||||
@ -69,14 +69,14 @@ SC_BLEEDING (SI_BLEEDING)
|
|||||||
val1: Skill Level
|
val1: Skill Level
|
||||||
val2: Caster's object ID (for mob_log_damage)
|
val2: Caster's object ID (for mob_log_damage)
|
||||||
val3:
|
val3:
|
||||||
val4: Tick
|
val4: Remaining tick
|
||||||
|
|
||||||
SC_DPOISON ()
|
SC_DPOISON ()
|
||||||
desc: DEF -25%; if HP>25% lose 10/15% HP/sec
|
desc: DEF -25%; if HP>25% lose 10/15% HP/sec
|
||||||
val1: Skill Level
|
val1: Skill Level
|
||||||
val2: Caster's object ID (for mob_log_damage)
|
val2: Caster's object ID (for mob_log_damage)
|
||||||
val3: Tick
|
val3:
|
||||||
val4: HP Damage
|
val4: Remaining tick
|
||||||
|
|
||||||
SC_PROVOKE (SI_PROVOKE)
|
SC_PROVOKE (SI_PROVOKE)
|
||||||
desc: Decrease DEF by (5+(5*Skill Lv))%; Increase ATK by (2+(3*Skill lv))%
|
desc: Decrease DEF by (5+(5*Skill Lv))%; Increase ATK by (2+(3*Skill lv))%
|
||||||
@ -1283,7 +1283,7 @@ SC_BURNING (SI_BURNT)
|
|||||||
val1: Skill Level
|
val1: Skill Level
|
||||||
val2: 1000
|
val2: 1000
|
||||||
val3: Caster's object ID (for mob_log_damage)
|
val3: Caster's object ID (for mob_log_damage)
|
||||||
val4: Tick
|
val4: Remaining tick
|
||||||
|
|
||||||
SC_FREEZING ()
|
SC_FREEZING ()
|
||||||
desc:
|
desc:
|
||||||
@ -1519,9 +1519,9 @@ SC_ROLLINGCUTTER ()
|
|||||||
SC_TOXIN (SI_TOXIN)
|
SC_TOXIN (SI_TOXIN)
|
||||||
desc: Inflict damage, which causes the affected entity to flinch every 10 seconds; This will interrupt the skill casting, even if protected against it
|
desc: Inflict damage, which causes the affected entity to flinch every 10 seconds; This will interrupt the skill casting, even if protected against it
|
||||||
val1: GC_WEAPONRESEARCH Skill Level
|
val1: GC_WEAPONRESEARCH Skill Level
|
||||||
val2: Caster's object ID (for mob_log_damage)
|
val2: Caster's object ID
|
||||||
val3:
|
val3:
|
||||||
val4: Tick
|
val4: Remaining tick
|
||||||
|
|
||||||
SC_PARALYSE (SI_PARALYSE)
|
SC_PARALYSE (SI_PARALYSE)
|
||||||
desc: Decrease both ASPD and Flee Rate by 10% and halve Movement Speed, which does not stack with Decrease AGI, Quagmire, Marsh Of Abyss or Freezing status
|
desc: Decrease both ASPD and Flee Rate by 10% and halve Movement Speed, which does not stack with Decrease AGI, Quagmire, Marsh Of Abyss or Freezing status
|
||||||
@ -1540,9 +1540,9 @@ SC_VENOMBLEED (SI_VENOMBLEED)
|
|||||||
SC_MAGICMUSHROOM (SI_MAGICMUSHROOM)
|
SC_MAGICMUSHROOM (SI_MAGICMUSHROOM)
|
||||||
desc: Force the affected entity to use /heh emote, to randomly use skills and drain 3% of Max HP every 4 seconds
|
desc: Force the affected entity to use /heh emote, to randomly use skills and drain 3% of Max HP every 4 seconds
|
||||||
val1: GC_WEAPONRESEARCH Skill Level
|
val1: GC_WEAPONRESEARCH Skill Level
|
||||||
val2: Caster's object ID (for mob_log_damage)
|
val2: Caster's object ID
|
||||||
val3:
|
val3:
|
||||||
val4: Tick
|
val4: Remaining tick
|
||||||
|
|
||||||
SC_DEATHHURT (SI_DEATHHURT)
|
SC_DEATHHURT (SI_DEATHHURT)
|
||||||
desc: Drop the healing effectiveness by 20%; This effect stacks with Critical Wounds
|
desc: Drop the healing effectiveness by 20%; This effect stacks with Critical Wounds
|
||||||
@ -1556,7 +1556,7 @@ SC_PYREXIA (SI_PYREXIA)
|
|||||||
val1: GC_WEAPONRESEARCH Skill Level
|
val1: GC_WEAPONRESEARCH Skill Level
|
||||||
val2:
|
val2:
|
||||||
val3:
|
val3:
|
||||||
val4: Tick
|
val4: Remaining tick
|
||||||
|
|
||||||
SC_OBLIVIONCURSE (SI_OBLIVIONCURSE)
|
SC_OBLIVIONCURSE (SI_OBLIVIONCURSE)
|
||||||
desc: Force the affected entity to use /? emote, block SP Recovery and cause Oblivion status; There is a chance (100% - (Target INT * 0.8)%) of being inflicted, with a minimum of 5%
|
desc: Force the affected entity to use /? emote, block SP Recovery and cause Oblivion status; There is a chance (100% - (Target INT * 0.8)%) of being inflicted, with a minimum of 5%
|
||||||
@ -1568,9 +1568,9 @@ SC_OBLIVIONCURSE (SI_OBLIVIONCURSE)
|
|||||||
SC_LEECHESEND (SI_LEECHESEND)
|
SC_LEECHESEND (SI_LEECHESEND)
|
||||||
desc: Drain (Target VIT * (SkillLv - 3)) + (Target HP / 100) HP each second
|
desc: Drain (Target VIT * (SkillLv - 3)) + (Target HP / 100) HP each second
|
||||||
val1: GC_WEAPONRESEARCH Skill Level
|
val1: GC_WEAPONRESEARCH Skill Level
|
||||||
val2: Caster's object ID (for mob_log_damage)
|
val2: Caster's object ID
|
||||||
val3:
|
val3:
|
||||||
val4: Tick
|
val4: Remaining tick
|
||||||
|
|
||||||
SC_REFLECTDAMAGE ()
|
SC_REFLECTDAMAGE ()
|
||||||
desc:
|
desc:
|
||||||
|
@ -795,7 +795,7 @@ int map_foreachinshootarea(int(*func)(struct block_list*, va_list), int16 m, int
|
|||||||
bl_list[bl_list_count++] = bl;
|
bl_list[bl_list_count++] = bl;
|
||||||
|
|
||||||
if (bl_list_count >= BL_LIST_MAX)
|
if (bl_list_count >= BL_LIST_MAX)
|
||||||
ShowWarning("map_foreachinarea: block count too many!\n");
|
ShowWarning("map_foreachinshootarea: block count too many!\n");
|
||||||
|
|
||||||
map_freeblock_lock();
|
map_freeblock_lock();
|
||||||
|
|
||||||
@ -1423,7 +1423,7 @@ int map_foreachindir(int(*func)(struct block_list*, va_list), int16 m, int16 x0,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( bl_list_count >= BL_LIST_MAX )
|
if( bl_list_count >= BL_LIST_MAX )
|
||||||
ShowWarning("map_foreachinpath: block count too many!\n");
|
ShowWarning("map_foreachindir: block count too many!\n");
|
||||||
|
|
||||||
map_freeblock_lock();
|
map_freeblock_lock();
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
#define MOB_LAZYMOVEPERC(md) (md->state.spotted?1000:0)
|
#define MOB_LAZYMOVEPERC(md) (md->state.spotted?1000:0)
|
||||||
#define MOB_MAX_DELAY (24*3600*1000)
|
#define MOB_MAX_DELAY (24*3600*1000)
|
||||||
#define MAX_MINCHASE 30 //Max minimum chase value to use for mobs.
|
#define MAX_MINCHASE 30 //Max minimum chase value to use for mobs.
|
||||||
#define RUDE_ATTACKED_COUNT 2 //After how many rude-attacks should the skill be used?
|
#define RUDE_ATTACKED_COUNT 1 //After how many rude-attacks should the skill be used?
|
||||||
#define MAX_MOB_CHAT 50 //Max Skill's messages
|
#define MAX_MOB_CHAT 50 //Max Skill's messages
|
||||||
|
|
||||||
// On official servers, monsters will only seek targets that are closer to walk to than their
|
// On official servers, monsters will only seek targets that are closer to walk to than their
|
||||||
@ -1565,7 +1565,8 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick)
|
|||||||
)
|
)
|
||||||
) )
|
) )
|
||||||
{ // Rude attacked
|
{ // Rude attacked
|
||||||
if (md->state.attacked_count++ >= RUDE_ATTACKED_COUNT
|
if (abl->id != md->bl.id //Self damage does not cause rude attack
|
||||||
|
&& md->state.attacked_count++ >= RUDE_ATTACKED_COUNT
|
||||||
&& !mobskill_use(md, tick, MSC_RUDEATTACKED) && can_move
|
&& !mobskill_use(md, tick, MSC_RUDEATTACKED) && can_move
|
||||||
&& !tbl && unit_escape(&md->bl, abl, rnd()%10 +1))
|
&& !tbl && unit_escape(&md->bl, abl, rnd()%10 +1))
|
||||||
{ //Escaped.
|
{ //Escaped.
|
||||||
@ -2041,8 +2042,6 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
|
|||||||
return; //Do nothing for absorbed damage.
|
return; //Do nothing for absorbed damage.
|
||||||
if( !damage && !(src->type&DEFAULT_ENEMY_TYPE(md)) )
|
if( !damage && !(src->type&DEFAULT_ENEMY_TYPE(md)) )
|
||||||
return; //Do not log non-damaging effects from non-enemies.
|
return; //Do not log non-damaging effects from non-enemies.
|
||||||
if( src->id == md->bl.id )
|
|
||||||
return; //Do not log self-damage.
|
|
||||||
|
|
||||||
switch( src->type )
|
switch( src->type )
|
||||||
{
|
{
|
||||||
@ -2116,6 +2115,12 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
|
|||||||
md->attacked_id = src->id;
|
md->attacked_id = src->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Self damage increases tap bonus
|
||||||
|
if (!char_id && src->id == md->bl.id) {
|
||||||
|
char_id = src->id;
|
||||||
|
flag = MDLF_SELF;
|
||||||
|
}
|
||||||
|
|
||||||
if( char_id )
|
if( char_id )
|
||||||
{ //Log damage...
|
{ //Log damage...
|
||||||
int i,minpos;
|
int i,minpos;
|
||||||
@ -2154,28 +2159,24 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
|
|||||||
//Call when a mob has received damage.
|
//Call when a mob has received damage.
|
||||||
void mob_damage(struct mob_data *md, struct block_list *src, int damage)
|
void mob_damage(struct mob_data *md, struct block_list *src, int damage)
|
||||||
{
|
{
|
||||||
if (damage > 0) { //Store total damage...
|
if (src && damage > 0) { //Store total damage...
|
||||||
if (UINT_MAX - (unsigned int)damage > md->tdmg)
|
if (UINT_MAX - (unsigned int)damage > md->tdmg)
|
||||||
md->tdmg+=damage;
|
md->tdmg += damage;
|
||||||
else if (md->tdmg == UINT_MAX)
|
else if (md->tdmg == UINT_MAX)
|
||||||
damage = 0; //Stop recording damage once the cap has been reached.
|
damage = 0; //Stop recording damage once the cap has been reached.
|
||||||
else { //Cap damage log...
|
else { //Cap damage log...
|
||||||
damage = (int)(UINT_MAX - md->tdmg);
|
damage = (int)(UINT_MAX - md->tdmg);
|
||||||
md->tdmg = UINT_MAX;
|
md->tdmg = UINT_MAX;
|
||||||
}
|
}
|
||||||
if (md->state.aggressive) //No longer aggressive, change to retaliate AI.
|
if ((src != &md->bl) && md->state.aggressive) //No longer aggressive, change to retaliate AI.
|
||||||
md->state.aggressive = 0;
|
md->state.aggressive = 0;
|
||||||
//Log damage
|
//Log damage
|
||||||
if (src)
|
mob_log_damage(md, src, damage);
|
||||||
mob_log_damage(md, src, damage);
|
|
||||||
md->dmgtick = gettick();
|
md->dmgtick = gettick();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (battle_config.show_mob_info&3)
|
if (battle_config.show_mob_info&3)
|
||||||
clif_charnameack (0, &md->bl);
|
clif_charnameack(0, &md->bl);
|
||||||
|
|
||||||
if (!src)
|
|
||||||
return;
|
|
||||||
|
|
||||||
#if PACKETVER >= 20120404
|
#if PACKETVER >= 20120404
|
||||||
if( battle_config.monster_hp_bars_info){
|
if( battle_config.monster_hp_bars_info){
|
||||||
@ -2188,6 +2189,9 @@ void mob_damage(struct mob_data *md, struct block_list *src, int damage)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (!src)
|
||||||
|
return;
|
||||||
|
|
||||||
if( md->special_state.ai == AI_SPHERE ) {//LOne WOlf explained that ANYONE can trigger the marine countdown skill. [Skotlex]
|
if( md->special_state.ai == AI_SPHERE ) {//LOne WOlf explained that ANYONE can trigger the marine countdown skill. [Skotlex]
|
||||||
md->state.alchemist = 1;
|
md->state.alchemist = 1;
|
||||||
mobskill_use(md, gettick(), MSC_ALCHEMIST);
|
mobskill_use(md, gettick(), MSC_ALCHEMIST);
|
||||||
@ -2241,18 +2245,23 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
|
|||||||
// filter out entries not eligible for exp distribution
|
// filter out entries not eligible for exp distribution
|
||||||
memset(tmpsd,0,sizeof(tmpsd));
|
memset(tmpsd,0,sizeof(tmpsd));
|
||||||
for(i = 0, count = 0, mvp_damage = 0; i < DAMAGELOG_SIZE && md->dmglog[i].id; i++) {
|
for(i = 0, count = 0, mvp_damage = 0; i < DAMAGELOG_SIZE && md->dmglog[i].id; i++) {
|
||||||
struct map_session_data* tsd = map_charid2sd(md->dmglog[i].id);
|
struct map_session_data* tsd = NULL;
|
||||||
|
if (md->dmglog[i].flag == MDLF_SELF) {
|
||||||
if(tsd == NULL)
|
//Self damage counts as exp tap
|
||||||
|
count++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
tsd = map_charid2sd(md->dmglog[i].id);
|
||||||
|
if (tsd == NULL)
|
||||||
continue; // skip empty entries
|
continue; // skip empty entries
|
||||||
if(tsd->bl.m != m)
|
if (tsd->bl.m != m)
|
||||||
continue; // skip players not on this map
|
continue; // skip players not on this map
|
||||||
count++; //Only logged into same map chars are counted for the total.
|
count++; //Only logged into same map chars are counted for the total.
|
||||||
if (pc_isdead(tsd))
|
if (pc_isdead(tsd))
|
||||||
continue; // skip dead players
|
continue; // skip dead players
|
||||||
if(md->dmglog[i].flag == MDLF_HOMUN && !hom_is_active(tsd->hd))
|
if (md->dmglog[i].flag == MDLF_HOMUN && !hom_is_active(tsd->hd))
|
||||||
continue; // skip homunc's share if inactive
|
continue; // skip homunc's share if inactive
|
||||||
if( md->dmglog[i].flag == MDLF_PET && (!tsd->status.pet_id || !tsd->pd) )
|
if (md->dmglog[i].flag == MDLF_PET && (!tsd->status.pet_id || !tsd->pd))
|
||||||
continue; // skip pet's share if inactive
|
continue; // skip pet's share if inactive
|
||||||
|
|
||||||
if(md->dmglog[i].dmg > mvp_damage) {
|
if(md->dmglog[i].dmg > mvp_damage) {
|
||||||
|
@ -61,6 +61,7 @@ enum MobDamageLogFlag
|
|||||||
MDLF_NORMAL = 0,
|
MDLF_NORMAL = 0,
|
||||||
MDLF_HOMUN,
|
MDLF_HOMUN,
|
||||||
MDLF_PET,
|
MDLF_PET,
|
||||||
|
MDLF_SELF
|
||||||
};
|
};
|
||||||
|
|
||||||
enum size {
|
enum size {
|
||||||
|
@ -7312,7 +7312,7 @@ void pc_damage(struct map_session_data *sd,struct block_list *src,unsigned int h
|
|||||||
if (hp) clif_updatestatus(sd,SP_HP);
|
if (hp) clif_updatestatus(sd,SP_HP);
|
||||||
else return;
|
else return;
|
||||||
|
|
||||||
if( !src || src == &sd->bl )
|
if (!src)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( pc_issit(sd) ) {
|
if( pc_issit(sd) ) {
|
||||||
|
@ -7053,7 +7053,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (sc_start4(src,bl,type,(skill_lv*4+20)+brate,
|
if (sc_start4(src,bl,type,(skill_lv*4+20)+brate,
|
||||||
skill_lv, src->id, 0, skill_get_time(skill_id, skill_lv),
|
skill_lv, src->id, skill_get_time(skill_id, skill_lv), 0,
|
||||||
skill_get_time2(skill_id,skill_lv)))
|
skill_get_time2(skill_id,skill_lv)))
|
||||||
clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
|
clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
|
||||||
else if(sd) {
|
else if(sd) {
|
||||||
@ -13412,7 +13412,7 @@ int skill_unit_onplace_timer(struct skill_unit *unit, struct block_list *bl, uns
|
|||||||
|
|
||||||
case UNT_VENOMDUST:
|
case UNT_VENOMDUST:
|
||||||
if(tsc && !tsc->data[type])
|
if(tsc && !tsc->data[type])
|
||||||
status_change_start(ss, bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill_get_time2(sg->skill_id,sg->skill_lv),SCSTART_NONE);
|
status_change_start(ss,bl,type,10000,sg->skill_lv,sg->src_id,0,0,skill_get_time2(sg->skill_id,sg->skill_lv),SCSTART_NONE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UNT_LANDMINE:
|
case UNT_LANDMINE:
|
||||||
|
468
src/map/status.c
468
src/map/status.c
@ -7304,6 +7304,34 @@ void status_change_init(struct block_list *bl)
|
|||||||
memset(sc, 0, sizeof (struct status_change));
|
memset(sc, 0, sizeof (struct status_change));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*========================================== [Playtester]
|
||||||
|
* Returns the interval for status changes that iterate multiple times
|
||||||
|
* through the timer (e.g. those that deal damage in regular intervals)
|
||||||
|
* @param type: Status change (SC_*)
|
||||||
|
*------------------------------------------*/
|
||||||
|
int status_get_sc_interval(enum sc_type type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case SC_POISON:
|
||||||
|
case SC_DPOISON:
|
||||||
|
case SC_LEECHESEND:
|
||||||
|
return 1000;
|
||||||
|
case SC_BURNING:
|
||||||
|
case SC_PYREXIA:
|
||||||
|
return 3000;
|
||||||
|
case SC_MAGICMUSHROOM:
|
||||||
|
return 4000;
|
||||||
|
case SC_STONE:
|
||||||
|
return 5000;
|
||||||
|
case SC_BLEEDING:
|
||||||
|
case SC_TOXIN:
|
||||||
|
return 10000;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies SC defense to a given status change
|
* Applies SC defense to a given status change
|
||||||
* This function also determines whether or not the status change will be applied
|
* This function also determines whether or not the status change will be applied
|
||||||
@ -7606,13 +7634,9 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ
|
|||||||
if (!(rnd()%10000 < rate))
|
if (!(rnd()%10000 < rate))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Even if a status change doesn't have a duration, it should still trigger
|
|
||||||
if (tick < 1)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
// Duration cannot be reduced
|
// Duration cannot be reduced
|
||||||
if (flag&SCSTART_NOTICKDEF)
|
if (flag&SCSTART_NOTICKDEF)
|
||||||
return tick;
|
return max(tick, 1);
|
||||||
|
|
||||||
tick -= tick*tick_def/10000;
|
tick -= tick*tick_def/10000;
|
||||||
tick -= tick_def2;
|
tick -= tick_def2;
|
||||||
@ -7620,7 +7644,6 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ
|
|||||||
// Minimum durations
|
// Minimum durations
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SC_ANKLE:
|
case SC_ANKLE:
|
||||||
case SC_BURNING:
|
|
||||||
case SC_MARSHOFABYSS:
|
case SC_MARSHOFABYSS:
|
||||||
case SC_DEEPSLEEP:
|
case SC_DEEPSLEEP:
|
||||||
tick = max(tick, 5000); // Minimum duration 5s
|
tick = max(tick, 5000); // Minimum duration 5s
|
||||||
@ -7628,6 +7651,7 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ
|
|||||||
case SC_FREEZING:
|
case SC_FREEZING:
|
||||||
tick = max(tick, 6000); // Minimum duration 6s
|
tick = max(tick, 6000); // Minimum duration 6s
|
||||||
break;
|
break;
|
||||||
|
case SC_BURNING:
|
||||||
case SC_STASIS:
|
case SC_STASIS:
|
||||||
tick = max(tick, 10000); // Minimum duration 10s
|
tick = max(tick, 10000); // Minimum duration 10s
|
||||||
break;
|
break;
|
||||||
@ -8935,10 +8959,9 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SC_STONE:
|
case SC_STONE:
|
||||||
val4 = max(val4, 100); // Incubation time
|
val3 = max(val3, 100); // Incubation time
|
||||||
val3 = (tick-val4)/100; // Petrified timer iterations
|
val4 = max(tick-val3, 100); // Petrify time
|
||||||
if(val3 < 1) val3 = 1;
|
tick = val3;
|
||||||
tick = val4;
|
|
||||||
calc_flag = 0; // Actual status changes take effect on petrified state.
|
calc_flag = 0; // Actual status changes take effect on petrified state.
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -8948,34 +8971,30 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|||||||
int diff = status->max_hp*(bl->type==BL_PC?10:15)/100;
|
int diff = status->max_hp*(bl->type==BL_PC?10:15)/100;
|
||||||
if (status->hp - diff < status->max_hp>>2)
|
if (status->hp - diff < status->max_hp>>2)
|
||||||
diff = status->hp - (status->max_hp>>2);
|
diff = status->hp - (status->max_hp>>2);
|
||||||
if( val2 && bl->type == BL_MOB ) {
|
|
||||||
struct block_list* src2 = map_id2bl(val2);
|
|
||||||
if( src2 )
|
|
||||||
mob_log_damage((TBL_MOB*)bl,src2,diff);
|
|
||||||
}
|
|
||||||
status_zap(bl, diff, 0);
|
status_zap(bl, diff, 0);
|
||||||
}
|
}
|
||||||
case SC_POISON:
|
|
||||||
// Fall through
|
// Fall through
|
||||||
val3 = tick/1000; // Damage iterations
|
case SC_POISON:
|
||||||
if(val3 < 1) val3 = 1;
|
case SC_BLEEDING:
|
||||||
tick_time = 1000; // [GodLesZ] tick time
|
case SC_BURNING:
|
||||||
// val4: HP damage
|
case SC_TOXIN:
|
||||||
if (bl->type == BL_PC)
|
case SC_MAGICMUSHROOM:
|
||||||
val4 = (type == SC_DPOISON) ? 2 + status->max_hp/50 : 2 + status->max_hp*3/200;
|
case SC_LEECHESEND:
|
||||||
else
|
tick_time = status_get_sc_interval(type);
|
||||||
val4 = (type == SC_DPOISON) ? 2 + status->max_hp/100 : 2 + status->max_hp/200;
|
val4 = tick-tick_time; // Remaining time
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SC_PYREXIA:
|
||||||
|
//Causes blind for duration of pyrexia, unreducable and unavoidable, but can be healed with e.g. green potion
|
||||||
|
status_change_start(src,bl,SC_BLIND,10000,val1,0,0,0,tick,SCSTART_NOAVOID|SCSTART_NOTICKDEF|SCSTART_NORATEDEF);
|
||||||
|
tick_time = status_get_sc_interval(type);
|
||||||
|
val4 = tick-tick_time; // Remaining time
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SC_CONFUSION:
|
case SC_CONFUSION:
|
||||||
if (!val4)
|
if (!val4)
|
||||||
clif_emotion(bl,E_WHAT);
|
clif_emotion(bl,E_WHAT);
|
||||||
break;
|
break;
|
||||||
case SC_BLEEDING:
|
|
||||||
val4 = tick/10000;
|
|
||||||
if (!val4) val4 = 1;
|
|
||||||
tick_time = 10000; // [GodLesZ] tick time
|
|
||||||
break;
|
|
||||||
case SC_S_LIFEPOTION:
|
case SC_S_LIFEPOTION:
|
||||||
case SC_L_LIFEPOTION:
|
case SC_L_LIFEPOTION:
|
||||||
if( val1 == 0 ) return 0;
|
if( val1 == 0 ) return 0;
|
||||||
@ -9219,11 +9238,6 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|||||||
}
|
}
|
||||||
|
|
||||||
case SC_COMA: // Coma. Sends a char to 1HP. If val2, do not zap sp
|
case SC_COMA: // Coma. Sends a char to 1HP. If val2, do not zap sp
|
||||||
if( val3 && bl->type == BL_MOB ) {
|
|
||||||
struct block_list* src2 = map_id2bl(val3);
|
|
||||||
if( src2 )
|
|
||||||
mob_log_damage((TBL_MOB*)bl,src2,status->hp - 1);
|
|
||||||
}
|
|
||||||
status_zap(bl, status->hp-1, val2?0:status->sp);
|
status_zap(bl, status->hp-1, val2?0:status->sp);
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
break;
|
||||||
@ -9561,10 +9575,6 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|||||||
val4 = tick / 1000;
|
val4 = tick / 1000;
|
||||||
tick_time = 1000; // [GodLesZ] tick time
|
tick_time = 1000; // [GodLesZ] tick time
|
||||||
break;
|
break;
|
||||||
case SC_BURNING:
|
|
||||||
val4 = tick / 2000; // Total Ticks to Burn!!
|
|
||||||
tick_time = 2000; // [GodLesZ] tick time
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Rune Knight */
|
/* Rune Knight */
|
||||||
case SC_DEATHBOUND:
|
case SC_DEATHBOUND:
|
||||||
@ -9598,23 +9608,6 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|||||||
val4 = tick / 5000;
|
val4 = tick / 5000;
|
||||||
tick_time = 5000; // [GodLesZ] tick time
|
tick_time = 5000; // [GodLesZ] tick time
|
||||||
break;
|
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:
|
|
||||||
status_change_start(src,bl,SC_BLIND,10000,val1,0,0,0,30000,SCSTART_NOAVOID|SCSTART_NOTICKDEF|SCSTART_NORATEDEF); // Blind status that last for 30 seconds
|
|
||||||
val4 = tick / 3000;
|
|
||||||
tick_time = 3000; // [GodLesZ] tick time
|
|
||||||
break;
|
|
||||||
case SC_LEECHESEND:
|
|
||||||
val4 = tick / 1000;
|
|
||||||
tick_time = 1000; // [GodLesZ] tick time
|
|
||||||
break;
|
|
||||||
case SC_OBLIVIONCURSE:
|
case SC_OBLIVIONCURSE:
|
||||||
val4 = tick / 3000;
|
val4 = tick / 3000;
|
||||||
tick_time = 3000; // [GodLesZ] tick time
|
tick_time = 3000; // [GodLesZ] tick time
|
||||||
@ -10331,6 +10324,21 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|||||||
clif_changelook(bl,LOOK_CLOTHES_COLOR,vd->cloth_color);
|
clif_changelook(bl,LOOK_CLOTHES_COLOR,vd->cloth_color);
|
||||||
clif_changelook(bl,LOOK_BODY2,0);
|
clif_changelook(bl,LOOK_BODY2,0);
|
||||||
break;
|
break;
|
||||||
|
case SC_STONE:
|
||||||
|
if (val3 > 0)
|
||||||
|
break; //Incubation time still active
|
||||||
|
//Fall through
|
||||||
|
case SC_POISON:
|
||||||
|
case SC_DPOISON:
|
||||||
|
case SC_BLEEDING:
|
||||||
|
case SC_BURNING:
|
||||||
|
case SC_TOXIN:
|
||||||
|
case SC_MAGICMUSHROOM:
|
||||||
|
case SC_PYREXIA:
|
||||||
|
case SC_LEECHESEND:
|
||||||
|
tick_time = tick;
|
||||||
|
tick = tick_time + max(val4,0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values that must be set regardless of flag&4 e.g. val_flag [Ind]
|
// Values that must be set regardless of flag&4 e.g. val_flag [Ind]
|
||||||
@ -10500,7 +10508,12 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
|||||||
opt_flag = 1;
|
opt_flag = 1;
|
||||||
switch(type) {
|
switch(type) {
|
||||||
// OPT1
|
// OPT1
|
||||||
case SC_STONE: sc->opt1 = OPT1_STONEWAIT; break;
|
case SC_STONE:
|
||||||
|
if (val3 > 0)
|
||||||
|
sc->opt1 = OPT1_STONEWAIT;
|
||||||
|
else
|
||||||
|
sc->opt1 = OPT1_STONE;
|
||||||
|
break;
|
||||||
case SC_FREEZE: sc->opt1 = OPT1_FREEZE; break;
|
case SC_FREEZE: sc->opt1 = OPT1_FREEZE; break;
|
||||||
case SC_STUN: sc->opt1 = OPT1_STUN; break;
|
case SC_STUN: sc->opt1 = OPT1_STUN; break;
|
||||||
case SC_DEEPSLEEP: opt_flag = 0;
|
case SC_DEEPSLEEP: opt_flag = 0;
|
||||||
@ -11018,7 +11031,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
|
|||||||
// delays status change ending so that a skill that sets opt1 fails to
|
// delays status change ending so that a skill that sets opt1 fails to
|
||||||
// trigger when it also removed one
|
// trigger when it also removed one
|
||||||
case SC_STONE:
|
case SC_STONE:
|
||||||
sce->val3 = 0; // Petrify time counter.
|
sce->val4 = -1; // Petrify time
|
||||||
case SC_FREEZE:
|
case SC_FREEZE:
|
||||||
case SC_STUN:
|
case SC_STUN:
|
||||||
case SC_SLEEP:
|
case SC_SLEEP:
|
||||||
@ -11743,6 +11756,8 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
|
|||||||
struct status_data *status;
|
struct status_data *status;
|
||||||
struct status_change *sc;
|
struct status_change *sc;
|
||||||
struct status_change_entry *sce;
|
struct status_change_entry *sce;
|
||||||
|
int interval = status_get_sc_interval(type);
|
||||||
|
bool dounlock = false;
|
||||||
|
|
||||||
bl = map_id2bl(id);
|
bl = map_id2bl(id);
|
||||||
if(!bl) {
|
if(!bl) {
|
||||||
@ -11837,8 +11852,8 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SC_STONE:
|
case SC_STONE:
|
||||||
if(sc->opt1 == OPT1_STONEWAIT && sce->val3) {
|
if (sc->opt1 == OPT1_STONEWAIT && sce->val4) {
|
||||||
sce->val4 = 0;
|
sce->val3 = 0; //Incubation time used up
|
||||||
unit_stop_attack(bl);
|
unit_stop_attack(bl);
|
||||||
if (sc->data[SC_DANCING]) {
|
if (sc->data[SC_DANCING]) {
|
||||||
unit_stop_walking(bl, 1);
|
unit_stop_walking(bl, 1);
|
||||||
@ -11847,45 +11862,117 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
|
|||||||
status_change_end(bl, SC_AETERNA, INVALID_TIMER);
|
status_change_end(bl, SC_AETERNA, INVALID_TIMER);
|
||||||
sc->opt1 = OPT1_STONE;
|
sc->opt1 = OPT1_STONE;
|
||||||
clif_changeoption(bl);
|
clif_changeoption(bl);
|
||||||
sc_timer_next(100+tick,status_change_timer, bl->id, data );
|
sc_timer_next(min(sce->val4, interval) + tick, status_change_timer, bl->id, data);
|
||||||
|
sce->val4 -= interval; //Remaining time
|
||||||
status_calc_bl(bl, StatusChangeFlagTable[type]);
|
status_calc_bl(bl, StatusChangeFlagTable[type]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (++(sce->val4)%50 == 0 && status->hp > status->max_hp/4) {
|
if (sce->val4 >= 0 && !(sce->val3) && status->hp > status->max_hp / 4) {
|
||||||
if (sce->val2 && bl->type == BL_MOB) {
|
|
||||||
struct block_list *src = map_id2bl(sce->val2);
|
|
||||||
|
|
||||||
if (src)
|
|
||||||
mob_log_damage((TBL_MOB*)bl, src, apply_rate(status->hp, 1));
|
|
||||||
}
|
|
||||||
status_percent_damage(NULL, bl, 1, 0, false);
|
status_percent_damage(NULL, bl, 1, 0, false);
|
||||||
}
|
}
|
||||||
if(--(sce->val3) > 0) {
|
|
||||||
sc_timer_next(100+tick,status_change_timer, bl->id, data );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SC_POISON:
|
case SC_POISON:
|
||||||
case SC_DPOISON:
|
case SC_DPOISON:
|
||||||
if (--(sce->val3) > 0) {
|
if (sce->val4 >= 0 && !sc->data[SC_SLOWPOISON]) {
|
||||||
if (!sc->data[SC_SLOWPOISON]) {
|
int64 damage = 0;
|
||||||
if( sce->val2 && bl->type == BL_MOB ) {
|
if (sd)
|
||||||
struct block_list* src = map_id2bl(sce->val2);
|
damage = (type == SC_DPOISON) ? 2 + status->max_hp / 50 : 2 + status->max_hp * 3 / 200;
|
||||||
if( src )
|
else
|
||||||
mob_log_damage((TBL_MOB*)bl,src,sce->val4);
|
damage = (type == SC_DPOISON) ? 2 + status->max_hp / 100 : 2 + status->max_hp / 200;
|
||||||
}
|
if (status->hp > max(status->max_hp / 4, damage)) // Stop damaging after 25% HP left.
|
||||||
|
status_zap(bl, damage, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SC_BLEEDING:
|
||||||
|
if (sce->val4 >= 0) {
|
||||||
|
int64 damage = rnd() % 600 + 200;
|
||||||
|
if (!sd && damage >= status->hp)
|
||||||
|
damage = status->hp - 1; // No deadly damage for monsters
|
||||||
|
map_freeblock_lock();
|
||||||
|
dounlock = true;
|
||||||
|
status_zap(bl, damage, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SC_BURNING:
|
||||||
|
if (sce->val4 >= 0) {
|
||||||
|
int64 damage = 1000 + (3 * status->max_hp) / 100; // Deals fixed (1000 + 3%*MaxHP)
|
||||||
|
map_freeblock_lock();
|
||||||
|
dounlock = true;
|
||||||
|
status_fix_damage(bl, bl, damage, clif_damage(bl, bl, tick, 0, 1, damage, 1, DMG_NORMAL, 0));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SC_TOXIN:
|
||||||
|
if (sce->val4 >= 0) { // Damage is every 10 seconds including 3%sp drain.
|
||||||
|
map_freeblock_lock();
|
||||||
|
dounlock = true;
|
||||||
|
status_damage(bl, bl, 1, status->max_sp * 3 / 100, clif_damage(bl, bl, tick, status->amotion, status->dmotion + 500, 1, 1, DMG_NORMAL, 0), 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SC_MAGICMUSHROOM:
|
||||||
|
if (sce->val4 >= 0) {
|
||||||
|
bool flag = 0;
|
||||||
|
int64 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();
|
map_freeblock_lock();
|
||||||
if(status->hp >= max(status->max_hp>>2, sce->val4)) // Stop damaging after 25% HP left.
|
status_zap(bl, damage, 0);
|
||||||
status_zap(bl, sce->val4, 0);
|
flag = !sc->data[type]; // Killed? Should not
|
||||||
if (sc->data[type]) { // Check if the status still last ( can be dead since then ).
|
|
||||||
sc_timer_next(1000 + tick, status_change_timer, bl->id, data );
|
|
||||||
}
|
|
||||||
map_freeblock_unlock();
|
map_freeblock_unlock();
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!flag) { // Random Skill Cast
|
||||||
|
if (skill_magicmushroom_count && sd && !pc_issit(sd)) { // Can't cast if sit
|
||||||
|
int mushroom_skill_id = 0, checked = 0, checked_max = MAX_SKILL_MAGICMUSHROOM_DB * 3;
|
||||||
|
unit_stop_attack(bl);
|
||||||
|
unit_skillcastcancel(bl, 1);
|
||||||
|
do {
|
||||||
|
int i = rnd() % MAX_SKILL_MAGICMUSHROOM_DB;
|
||||||
|
mushroom_skill_id = skill_magicmushroom_db[i].skill_id;
|
||||||
|
} while (checked++ < checked_max && mushroom_skill_id == 0);
|
||||||
|
|
||||||
|
if (!skill_get_index(mushroom_skill_id))
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (skill_get_casttype(mushroom_skill_id)) { // Magic Mushroom skills are buffs or area damage
|
||||||
|
case CAST_GROUND:
|
||||||
|
skill_castend_pos2(bl, bl->x, bl->y, mushroom_skill_id, 1, tick, 0);
|
||||||
|
break;
|
||||||
|
case CAST_NODAMAGE:
|
||||||
|
skill_castend_nodamage_id(bl, bl, mushroom_skill_id, 1, tick, 0);
|
||||||
|
break;
|
||||||
|
case CAST_DAMAGE:
|
||||||
|
skill_castend_damage_id(bl, bl, mushroom_skill_id, 1, tick, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clif_emotion(bl, E_HEH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SC_PYREXIA:
|
||||||
|
if (sce->val4 >= 0) {
|
||||||
|
map_freeblock_lock();
|
||||||
|
dounlock = true;
|
||||||
|
status_fix_damage(bl, bl, 100, clif_damage(bl, bl, tick, status->amotion, status->dmotion + 500, 100, 1, DMG_NORMAL, 0));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SC_LEECHESEND:
|
||||||
|
if (sce->val4 >= 0) {
|
||||||
|
int64 damage = status->vit * (sce->val1 - 3) + status->max_hp / 100; // {Target VIT x (New Poison Research Skill Level - 3)} + (Target HP/100)
|
||||||
|
map_freeblock_lock();
|
||||||
|
dounlock = true;
|
||||||
|
status_fix_damage(bl, bl, damage, clif_damage(bl, bl, tick, status->amotion, status->dmotion + 500, damage, 1, DMG_NORMAL, 0));
|
||||||
|
unit_skillcastcancel(bl, 2);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SC_TENSIONRELAX:
|
case SC_TENSIONRELAX:
|
||||||
@ -11906,26 +11993,6 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SC_BLEEDING:
|
|
||||||
if (--(sce->val4) >= 0) {
|
|
||||||
int hp = rnd()%600 + 200;
|
|
||||||
struct block_list* src = map_id2bl(sce->val2);
|
|
||||||
if( src && bl && bl->type == BL_MOB )
|
|
||||||
mob_log_damage( (TBL_MOB*)bl, src, sd || hp < status->hp ? hp : status->hp - 1 );
|
|
||||||
map_freeblock_lock();
|
|
||||||
status_fix_damage(src, bl, sd||hp<status->hp?hp:status->hp-1, 1);
|
|
||||||
if( sc->data[type] ) {
|
|
||||||
if( status->hp == 1 ) {
|
|
||||||
map_freeblock_unlock();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sc_timer_next(10000 + tick, status_change_timer, bl->id, data);
|
|
||||||
}
|
|
||||||
map_freeblock_unlock();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SC_S_LIFEPOTION:
|
case SC_S_LIFEPOTION:
|
||||||
case SC_L_LIFEPOTION:
|
case SC_L_LIFEPOTION:
|
||||||
if( sd && --(sce->val4) >= 0 ) {
|
if( sd && --(sce->val4) >= 0 ) {
|
||||||
@ -12083,114 +12150,6 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SC_PYREXIA:
|
|
||||||
if( --(sce->val4) >= 0 ) {
|
|
||||||
map_freeblock_lock();
|
|
||||||
clif_damage(bl,bl,tick,status_get_amotion(bl),status_get_dmotion(bl)+500,100,0,DMG_NORMAL,0);
|
|
||||||
status_fix_damage(NULL,bl,100,0);
|
|
||||||
if( sc->data[type] ) {
|
|
||||||
sc_timer_next(3000+tick,status_change_timer,bl->id,data);
|
|
||||||
}
|
|
||||||
map_freeblock_unlock();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SC_LEECHESEND:
|
|
||||||
if( --(sce->val4) >= 0 ) {
|
|
||||||
int damage = status->vit * (sce->val1 - 3) + status->max_hp / 100; // {Target VIT x (New Poison Research Skill Level - 3)} + (Target HP/100)
|
|
||||||
|
|
||||||
if (sce->val2 && bl->type == BL_MOB) {
|
|
||||||
struct block_list *src2 = map_id2bl(sce->val2);
|
|
||||||
|
|
||||||
if (src2)
|
|
||||||
mob_log_damage((TBL_MOB*)bl, src2, damage);
|
|
||||||
}
|
|
||||||
map_freeblock_lock();
|
|
||||||
status_damage(bl, bl, damage, 0, clif_damage(bl,bl,tick,status_get_amotion(bl),status_get_dmotion(bl)+500,damage,1,DMG_NORMAL,0), 0);
|
|
||||||
unit_skillcastcancel(bl, 2);
|
|
||||||
if (sc->data[type]) {
|
|
||||||
sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
|
|
||||||
}
|
|
||||||
map_freeblock_unlock();
|
|
||||||
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 (sce->val2 && bl->type == BL_MOB) {
|
|
||||||
struct block_list *src2 = map_id2bl(sce->val2);
|
|
||||||
|
|
||||||
if (src2)
|
|
||||||
mob_log_damage((TBL_MOB*)bl, src2, damage);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !flag ) { // Random Skill Cast
|
|
||||||
if (skill_magicmushroom_count && sd && !pc_issit(sd)) { // Can't cast if sit
|
|
||||||
int mushroom_skill_id = 0, checked = 0, checked_max = MAX_SKILL_MAGICMUSHROOM_DB * 3;
|
|
||||||
unit_stop_attack(bl);
|
|
||||||
unit_skillcastcancel(bl,1);
|
|
||||||
do {
|
|
||||||
int i = rnd() % MAX_SKILL_MAGICMUSHROOM_DB;
|
|
||||||
mushroom_skill_id = skill_magicmushroom_db[i].skill_id;
|
|
||||||
}
|
|
||||||
while( checked++ < checked_max && mushroom_skill_id == 0 );
|
|
||||||
|
|
||||||
if (!skill_get_index(mushroom_skill_id))
|
|
||||||
break;
|
|
||||||
|
|
||||||
switch( skill_get_casttype(mushroom_skill_id) ) { // Magic Mushroom skills are buffs or area damage
|
|
||||||
case CAST_GROUND:
|
|
||||||
skill_castend_pos2(bl,bl->x,bl->y,mushroom_skill_id,1,tick,0);
|
|
||||||
break;
|
|
||||||
case CAST_NODAMAGE:
|
|
||||||
skill_castend_nodamage_id(bl,bl,mushroom_skill_id,1,tick,0);
|
|
||||||
break;
|
|
||||||
case CAST_DAMAGE:
|
|
||||||
skill_castend_damage_id(bl,bl,mushroom_skill_id,1,tick,0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clif_emotion(bl,E_HEH);
|
|
||||||
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.
|
|
||||||
if (sce->val2 && bl->type == BL_MOB) {
|
|
||||||
struct block_list *src2 = map_id2bl(sce->val2);
|
|
||||||
|
|
||||||
if (src2)
|
|
||||||
mob_log_damage((TBL_MOB*)bl, src2, 1);
|
|
||||||
}
|
|
||||||
map_freeblock_lock();
|
|
||||||
clif_damage(bl,bl,tick,status_get_amotion(bl),1,1,0,DMG_NORMAL,0);
|
|
||||||
status_damage(NULL, bl, 1, status->max_sp * 3 / 100, 0, 0); // Cancel dmg only if cancelable
|
|
||||||
if( sc->data[type] ) {
|
|
||||||
sc_timer_next(10000 + tick, status_change_timer, bl->id, data );
|
|
||||||
}
|
|
||||||
map_freeblock_unlock();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SC_OBLIVIONCURSE:
|
case SC_OBLIVIONCURSE:
|
||||||
if( --(sce->val4) >= 0 ) {
|
if( --(sce->val4) >= 0 ) {
|
||||||
clif_emotion(bl,E_WHAT);
|
clif_emotion(bl,E_WHAT);
|
||||||
@ -12225,24 +12184,6 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SC_BURNING:
|
|
||||||
if( --(sce->val4) >= 0 ) {
|
|
||||||
struct block_list *src = map_id2bl(sce->val3);
|
|
||||||
int damage = 1000 + 3 * status_get_max_hp(bl) / 100; // Deals fixed (1000 + 3%*MaxHP)
|
|
||||||
|
|
||||||
if (src && bl->type == BL_MOB)
|
|
||||||
mob_log_damage((TBL_MOB*)bl, src, damage);
|
|
||||||
map_freeblock_lock();
|
|
||||||
clif_damage(bl,bl,tick,0,0,damage,1,DMG_MULTI_HIT_ENDURE,0); // Damage is like endure effect with no walk delay
|
|
||||||
status_damage(src, bl, damage, 0, 0, 1);
|
|
||||||
if( sc->data[type]) { // Target still lives. [LimitLine]
|
|
||||||
sc_timer_next(2000 + tick, status_change_timer, bl->id, data);
|
|
||||||
}
|
|
||||||
map_freeblock_unlock();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SC_FEAR:
|
case SC_FEAR:
|
||||||
if( --(sce->val4) >= 0 ) {
|
if( --(sce->val4) >= 0 ) {
|
||||||
if( sce->val2 > 0 )
|
if( sce->val2 > 0 )
|
||||||
@ -12657,8 +12598,19 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default for all non-handled control paths is to end the status
|
// If status has an interval and there is at least 100ms remaining time, wait for next interval
|
||||||
|
if(interval > 0 && sc->data[type] && sce->val4 >= 100) {
|
||||||
|
sc_timer_next(min(sce->val4,interval)+tick, status_change_timer, bl->id, data);
|
||||||
|
sce->val4 -= interval;
|
||||||
|
if (dounlock)
|
||||||
|
map_freeblock_unlock();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dounlock)
|
||||||
|
map_freeblock_unlock();
|
||||||
|
|
||||||
|
// Default for all non-handled control paths is to end the status
|
||||||
return status_change_end( bl,type,tid );
|
return status_change_end( bl,type,tid );
|
||||||
#undef sc_timer_next
|
#undef sc_timer_next
|
||||||
}
|
}
|
||||||
@ -12965,7 +12917,7 @@ int status_change_spread(struct block_list *src, struct block_list *bl, bool typ
|
|||||||
{
|
{
|
||||||
int i, flag = 0;
|
int i, flag = 0;
|
||||||
struct status_change *sc = status_get_sc(src);
|
struct status_change *sc = status_get_sc(src);
|
||||||
const struct TimerData *timer;
|
const struct TimerData *timer = NULL;
|
||||||
unsigned int tick;
|
unsigned int tick;
|
||||||
struct status_change_data data;
|
struct status_change_data data;
|
||||||
|
|
||||||
@ -12981,6 +12933,11 @@ int status_change_spread(struct block_list *src, struct block_list *bl, bool typ
|
|||||||
for( i = SC_COMMON_MIN; i < SC_MAX; i++ ) {
|
for( i = SC_COMMON_MIN; i < SC_MAX; i++ ) {
|
||||||
if( !sc->data[i] || i == SC_COMMON_MAX )
|
if( !sc->data[i] || i == SC_COMMON_MAX )
|
||||||
continue;
|
continue;
|
||||||
|
if (sc->data[i]->timer != INVALID_TIMER) {
|
||||||
|
timer = get_timer(sc->data[i]->timer);
|
||||||
|
if (timer == NULL || timer->func != status_change_timer || DIFF_TICK(timer->tick, tick) < 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
switch( i ) {
|
switch( i ) {
|
||||||
// Debuffs that can be spread.
|
// Debuffs that can be spread.
|
||||||
@ -13009,45 +12966,30 @@ int status_change_spread(struct block_list *src, struct block_list *bl, bool typ
|
|||||||
//case SC_BITE:
|
//case SC_BITE:
|
||||||
case SC_FREEZING:
|
case SC_FREEZING:
|
||||||
case SC_VENOMBLEED:
|
case SC_VENOMBLEED:
|
||||||
if( sc->data[i]->timer != INVALID_TIMER ) {
|
if (sc->data[i]->timer != INVALID_TIMER)
|
||||||
timer = get_timer(sc->data[i]->timer);
|
data.tick = DIFF_TICK(timer->tick, tick);
|
||||||
if (timer == NULL || timer->func != status_change_timer || DIFF_TICK(timer->tick,tick) < 0)
|
else
|
||||||
continue;
|
|
||||||
data.tick = DIFF_TICK(timer->tick,tick);
|
|
||||||
} else
|
|
||||||
data.tick = INVALID_TIMER;
|
data.tick = INVALID_TIMER;
|
||||||
break;
|
break;
|
||||||
// Special cases
|
// Special cases
|
||||||
case SC_POISON:
|
case SC_TOXIN:
|
||||||
case SC_DPOISON:
|
case SC_MAGICMUSHROOM:
|
||||||
data.tick = sc->data[i]->val3 * 1000;
|
case SC_PYREXIA:
|
||||||
break;
|
|
||||||
case SC_LEECHESEND:
|
case SC_LEECHESEND:
|
||||||
if (type)
|
if (type)
|
||||||
continue;
|
continue;
|
||||||
|
case SC_POISON:
|
||||||
|
case SC_DPOISON:
|
||||||
|
case SC_BLEEDING:
|
||||||
|
case SC_BURNING:
|
||||||
|
if (sc->data[i]->timer != INVALID_TIMER)
|
||||||
|
data.tick = DIFF_TICK(timer->tick, tick) + sc->data[i]->val4;
|
||||||
|
else
|
||||||
|
data.tick = INVALID_TIMER;
|
||||||
|
break;
|
||||||
case SC_FEAR:
|
case SC_FEAR:
|
||||||
data.tick = sc->data[i]->val4 * 1000;
|
data.tick = sc->data[i]->val4 * 1000;
|
||||||
break;
|
break;
|
||||||
case SC_BURNING:
|
|
||||||
data.tick = sc->data[i]->val4 * 2000;
|
|
||||||
break;
|
|
||||||
case SC_PYREXIA:
|
|
||||||
if (type)
|
|
||||||
continue;
|
|
||||||
//case SC_OBLIVIONCURSE: // Players are not affected by Oblivion Curse.
|
|
||||||
data.tick = sc->data[i]->val4 * 3000;
|
|
||||||
break;
|
|
||||||
case SC_MAGICMUSHROOM:
|
|
||||||
if (type)
|
|
||||||
continue;
|
|
||||||
data.tick = sc->data[i]->val4 * 4000;
|
|
||||||
break;
|
|
||||||
case SC_TOXIN:
|
|
||||||
if (type)
|
|
||||||
continue;
|
|
||||||
case SC_BLEEDING:
|
|
||||||
data.tick = sc->data[i]->val4 * 10000;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2150,6 +2150,7 @@ struct status_change *status_get_sc(struct block_list *bl);
|
|||||||
int status_isdead(struct block_list *bl);
|
int status_isdead(struct block_list *bl);
|
||||||
int status_isimmune(struct block_list *bl);
|
int status_isimmune(struct block_list *bl);
|
||||||
|
|
||||||
|
int status_get_sc_interval(enum sc_type type);
|
||||||
int status_get_sc_def(struct block_list *src,struct block_list *bl, enum sc_type type, int rate, int tick, unsigned char flag);
|
int status_get_sc_def(struct block_list *src,struct block_list *bl, enum sc_type type, int rate, int tick, unsigned char flag);
|
||||||
//Short version, receives rate in 1->100 range, and does not uses a flag setting.
|
//Short version, receives rate in 1->100 range, and does not uses a flag setting.
|
||||||
#define sc_start(src, bl, type, rate, val1, tick) status_change_start(src,bl,type,100*(rate),val1,0,0,0,tick,SCSTART_NONE)
|
#define sc_start(src, bl, type, rate, val1, tick) status_change_start(src,bl,type,100*(rate),val1,0,0,0,tick,SCSTART_NONE)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user