summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichieru <Michieru@users.noreply.github.com>2014-11-24 14:48:59 +0100
committerMichieru <Michieru@users.noreply.github.com>2014-11-24 14:48:59 +0100
commit0623d4ff87906d9ea0aee7bf612da2d1afdee1cd (patch)
tree65c704a8ca804f3bcfe8375c488a62acef14510b
parent308570a239a7211aed068c3855d15c7d16f3d3b4 (diff)
downloadhercules-0623d4ff87906d9ea0aee7bf612da2d1afdee1cd.tar.gz
hercules-0623d4ff87906d9ea0aee7bf612da2d1afdee1cd.tar.bz2
hercules-0623d4ff87906d9ea0aee7bf612da2d1afdee1cd.tar.xz
hercules-0623d4ff87906d9ea0aee7bf612da2d1afdee1cd.zip
* 1st Transcendent Spirit, monster position lag fixes
- 1st Transcendent Spirit will now work as on official servers (#116) * The max total stat that is granted by the skill is now BaseLevel-10 with a maximum of 50 instead of always 50 * It will now work as Marionette Control and calculate the bonus at cast time rather than overwrite all existing bonuses * Agi Up and Blessing will now cancel the soul link - Fixed various problems that caused position lags on the client (#118) * Added a define ACTIVEPATHSEARCH in mob.c; if active (default and official), monsters will only grab targets if the walk path to the target is shorter or equal their search range; search range depends on whether the monster is moving or not (range2 for standing monsters and range3 for walking monsters); this requires a lot of CPU load, if it causes trouble, just comment the define for old behavior * Fixed a bug that made monsters display "irregular movement with position lag" continuously when a status change ended that changed their walk speed * OFFICIAL_WALKPATH now also applies to monsters * If the path search fails while a unit is already moving, we will now issue of fixpos packet so that the unit does not only stop moving on the server, but also on the client * Direction fixes - Updated the config setting attack_direction_change from 15 to 0 (official value); that means that a unit's direction will no longer change when it attacks; knock-back effects from e.g. Firewall will depend on the last direction the target walked into instead (bugreport:1322) - Ensured that the default direction of a monster is always "north", so that immobile monsters will now always be knocked back to the south by e.g. Firewall on default settings, unless a skill like e.g. Backstab changes their direction (bugreport:1322) - Fixed a bug that stopped characters server-sided and caused position lag when closing a skill menu * Magnum Break damage fixed - Targets two cells away will now only take 100%+10%*level damage (#108)
-rw-r--r--conf/battle/battle.conf7
-rw-r--r--db/pre-re/skill_db.txt4
-rw-r--r--db/re/skill_db.txt4
-rw-r--r--db/re/skill_unit_db.txt2
-rw-r--r--src/map/battle.c9
-rw-r--r--src/map/mob.c10
-rw-r--r--src/map/mob.h9
-rw-r--r--src/map/skill.c11
-rw-r--r--src/map/status.c67
-rw-r--r--src/map/unit.c25
10 files changed, 113 insertions, 35 deletions
diff --git a/conf/battle/battle.conf b/conf/battle/battle.conf
index 2e84a23e5..42d9a7262 100644
--- a/conf/battle/battle.conf
+++ b/conf/battle/battle.conf
@@ -103,7 +103,12 @@ weapon_defense_type: 0
magic_defense_type: 0
// Change attacker's direction to face opponent on every attack? (Note 3)
-attack_direction_change: 15
+// NOTE: On official servers knockback of some skills like Firewall is always based on the
+// last direction walked. Even when attacking in a completely different direction, the
+// knockback direction won't change, so e.g. if you walk north and then attack an enemy to
+// the south you will still be knocked back to the south by Firewall. Immobile monsters
+// will always be knocked back to the south as their default direction is north.
+attack_direction_change: 0
// For those who is set, their innate attack element is "not elemental"
// (100% versus on all defense-elements) (Note 3)
diff --git a/db/pre-re/skill_db.txt b/db/pre-re/skill_db.txt
index 4c085b8df..371833d98 100644
--- a/db/pre-re/skill_db.txt
+++ b/db/pre-re/skill_db.txt
@@ -124,7 +124,7 @@
77,5,6,1,6,0x28,0,10,1,yes,0,0,0,magic,0, PR_TURNUNDEAD,Turn Undead
78,9,6,1,0,0x1,0,1,0,yes,0,0,0,magic,0, PR_LEXAETERNA,Lex Aeterna
79,9,8,2,6,0,0,10,1:2:3:4:5:6:7:8:9:10,yes,0,0,0,magic,0, PR_MAGNUS,Magnus Exorcismus
-80,9,8,2,3,0x20,1:1:1:1:1:2:2:2:2:2:2,10,3:4:5:6:7:8:9:10:11:12:12,yes,0,0x80,5,magic,0, WZ_FIREPILLAR,Fire Pillar
+80,9,8,2,3,0x20,1:1:1:1:1:2:2:2:2:2:2,10,-3:-4:-5:-6:-7:-8:-9:-10:-11:-12:-12,yes,0,0x80,5,magic,0, WZ_FIREPILLAR,Fire Pillar
81,0,6,4,3,0,3,10,1,yes,0,0,0,magic,5, WZ_SIGHTRASHER,Sightrasher
83,9,8,2,3,0,3:3:3:3:3:3:3:3:3:3:14,10,1:1:2:2:3:3:4:4:5:5:15,yes,0,0,0,magic,0, WZ_METEOR,Meteor Storm
84,9,8,1,4,0,0,10,3:4:5:6:7:8:9:10:11:12,yes,0,0,0,magic,2:3:3:4:4:5:5:6:6:7, WZ_JUPITEL,Jupitel Thunder
@@ -578,7 +578,7 @@
532,0,6,4,0,0x1,0,10,1,yes,0,0,0,magic,0, NJ_BUNSINJYUTSU,Mirror Image
533,0,0,0,0,0,0,10,0,no,0,0,0,none,0, NJ_NINPOU,Spirit of the Blade
534,9,8,1,3,0,0,10,1:2:3:4:5:6:7:8:9:10,yes,0,0,0,magic,0, NJ_KOUENKA,Crimson Fire Petal
-535,0,8,4,3,0,0,10,1,yes,0,0,0,magic,1, NJ_KAENSIN,Crimson Fire Formation
+535,0,8,4,3,0,0,10,1,yes,0,0,0,magic,0, NJ_KAENSIN,Crimson Fire Formation
536,9,8,1,3,0x2,2,5,3,yes,0,0,0,magic,0, NJ_BAKUENRYU,Raging Fire Dragon
537,9,8,1,1,0,0,10,3:4:5:6:7:8:9:10:11:12,yes,0,0,0,magic,0, NJ_HYOUSENSOU,Spear of Ice
538,9,6,2,1,0x1,0,10,1,yes,0,0,0,magic,0, NJ_SUITON,Hidden Water
diff --git a/db/re/skill_db.txt b/db/re/skill_db.txt
index ebaf3ab6c..df1cf5c52 100644
--- a/db/re/skill_db.txt
+++ b/db/re/skill_db.txt
@@ -124,7 +124,7 @@
77,5,6,1,6,0x28,0,10,1,yes,0,0,0,magic,0, PR_TURNUNDEAD,Turn Undead
78,9,6,1,0,0x1,0,1,0,yes,0,0,0,magic,0, PR_LEXAETERNA,Lex Aeterna
79,9,8,2,6,0,0,10,1:2:3:4:5:6:7:8:9:10,yes,0,0,0,magic,0, PR_MAGNUS,Magnus Exorcismus
-80,9,8,2,3,0x20,1:1:1:1:1:2:2:2:2:2:2,10,3:4:5:6:7:8:9:10:11:12:12,yes,0,0,5,magic,0, WZ_FIREPILLAR,Fire Pillar
+80,9,8,2,3,0x20,1:1:1:1:1:2:2:2:2:2:2,10,-3:-4:-5:-6:-7:-8:-9:-10:-11:-12:-12,yes,0,0,5,magic,0, WZ_FIREPILLAR,Fire Pillar
81,0,6,4,3,0,3,10,1,yes,0,0,0,magic,5, WZ_SIGHTRASHER,Sightrasher
83,9,8,2,3,0,3:3:3:3:3:3:3:3:3:3:14,10,1:1:2:2:3:3:4:4:5:5:15,yes,0,0,0,magic,0, WZ_METEOR,Meteor Storm
84,9,8,1,4,0,0,10,3:4:5:6:7:8:9:10:11:12,yes,0,0,0,magic,2:3:3:4:4:5:5:6:6:7, WZ_JUPITEL,Jupitel Thunder
@@ -578,7 +578,7 @@
532,0,6,4,0,0x1,0,10,1,yes,0,0,0,magic,0, NJ_BUNSINJYUTSU,Mirror Image
533,0,0,0,0,0,0,10,0,no,0,0,0,none,0, NJ_NINPOU,Spirit of the Blade
534,9,8,1,3,0,0,10,1:2:3:4:5:6:7:8:9:10,yes,0,0,0,magic,0, NJ_KOUENKA,Crimson Fire Petal
-535,0,8,4,3,0,0,10,1,yes,0,0,0,magic,1, NJ_KAENSIN,Crimson Fire Formation
+535,0,8,4,3,0,0,10,1,yes,0,0,0,magic,0, NJ_KAENSIN,Crimson Fire Formation
536,9,8,1,3,0x2,2,5,3,yes,0,0,0,magic,0, NJ_BAKUENRYU,Raging Fire Dragon
537,9,8,1,1,0,0,10,3:4:5:6:7:8:9:10:11:12,yes,0,0,0,magic,0, NJ_HYOUSENSOU,Spear of Ice
538,9,6,2,1,0x1,0,10,1,yes,0,0,0,magic,0, NJ_SUITON,Hidden Water
diff --git a/db/re/skill_unit_db.txt b/db/re/skill_unit_db.txt
index 87afd2da2..f0f359bcc 100644
--- a/db/re/skill_unit_db.txt
+++ b/db/re/skill_unit_db.txt
@@ -52,7 +52,7 @@
125,0x99, , 0, 1,1000,all, 0x000 //HT_TALKIEBOX
140,0x92, , -1, 1,1000,enemy, 0x000 //AS_VENOMDUST
220,0xb0, , 0, 0, -1,all, 0x002 //RG_GRAFFITI
-229,0xb1, , 0, 1,1000,enemy, 0x006 //AM_DEMONSTRATION
+229,0xb1, , 0, 1, 500,enemy, 0x006 //AM_DEMONSTRATION
254,0x86, , -1, 0, 300,enemy, 0x010 //CR_GRANDCROSS
285,0x9a, , 3, 0, -1,all, 0x010 //SA_VOLCANO
286,0x9b, , 3, 0, -1,all, 0x010 //SA_DELUGE
diff --git a/src/map/battle.c b/src/map/battle.c
index 1563553d4..5a17c8d90 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -1463,9 +1463,9 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block
break;
case WZ_FIREPILLAR:
if (skill_lv > 10)
- skillratio += 100;
+ skillratio += 2300; //200% MATK each hit
else
- skillratio -= 80;
+ skillratio += -60 + 20*skill_lv; //20% MATK each hit
break;
case WZ_SIGHTRASHER:
skillratio += 20 * skill_lv;
@@ -3384,11 +3384,10 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
switch(skill_id) {
case MG_FIREWALL:
- case NJ_KAENSIN:
- ad.dmotion = 0; //No flinch animation.
if ( tstatus->def_ele == ELE_FIRE || battle->check_undead(tstatus->race, tstatus->def_ele) )
ad.blewcount = 0; //No knockback
break;
+ case NJ_KAENSIN:
case PR_SANCTUARY:
ad.dmotion = 0; //No flinch animation.
break;
@@ -3495,7 +3494,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
}
//Constant/misc additions from skills
if (skill_id == WZ_FIREPILLAR)
- MATK_ADD(50);
+ MATK_ADD(100+50*skill_lv);
if( sd && ( sd->status.class_ == JOB_ARCH_BISHOP_T || sd->status.class_ == JOB_ARCH_BISHOP ) &&
(i=pc->checkskill(sd,AB_EUCHARISTICA)) > 0 &&
(tstatus->race == RC_DEMON || tstatus->def_ele == ELE_DARK) )
diff --git a/src/map/mob.c b/src/map/mob.c
index 28e70c5c0..cb22f71c0 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -941,6 +941,7 @@ int mob_spawn (struct mob_data *md)
md->move_fail_count = 0;
md->ud.state.attack_continue = 0;
md->ud.target_to = 0;
+ md->ud.dir = 0;
if( md->spawn_timer != INVALID_TIMER )
{
timer->delete(md->spawn_timer, mob->delayspawn);
@@ -1080,6 +1081,15 @@ int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap)
((*target) == NULL || !check_distance_bl(&md->bl, *target, dist)) &&
battle->check_range(&md->bl,bl,md->db->range2)
) { //Pick closest target?
+#ifdef ACTIVEPATHSEARCH
+ struct walkpath_data wpd;
+ if (!path->search(&wpd, md->bl.m, md->bl.x, md->bl.y, bl->x, bl->y, 0, CELL_CHKNOPASS)) // Count walk path cells
+ return 0;
+ //Standing monsters use range2, walking monsters use range3
+ if ((md->ud.walktimer == INVALID_TIMER && wpd.path_len > md->db->range2)
+ || (md->ud.walktimer != INVALID_TIMER && wpd.path_len > md->db->range3))
+ return 0;
+#endif
(*target) = bl;
md->target_id=bl->id;
md->min_chase= dist + md->db->range3;
diff --git a/src/map/mob.h b/src/map/mob.h
index c61d29103..f79b33804 100644
--- a/src/map/mob.h
+++ b/src/map/mob.h
@@ -42,6 +42,15 @@
#define MAX_MOB_CHAT 250 //Max Skill's messages
+// On official servers, monsters will only seek targets that are closer to walk to than their
+// search range. The search range is affected depending on if the monster is walking or not.
+// On some maps there can be a quite long path for just walking two cells in a direction and
+// the client does not support displaying walk paths that are longer than 14 cells, so this
+// option reduces position lag in such situation. But doing a complex search for every possible
+// target, might be CPU intensive.
+// Disable this to make monsters not do any path search when looking for a target (old behavior).
+#define ACTIVEPATHSEARCH
+
//Mob skill states.
enum MobSkillState {
MSS_ANY = -1,
diff --git a/src/map/skill.c b/src/map/skill.c
index 938b36419..8c452252a 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -3762,8 +3762,6 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
case NPC_SPLASHATTACK:
flag |= SD_PREAMBLE; // a fake packet will be sent for the first target to be hit
case AS_SPLASHER:
- case SM_MAGNUM:
- case MS_MAGNUM:
case HT_BLITZBEAT:
case AC_SHOWER:
case MA_SHOWER:
@@ -3873,6 +3871,14 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1
}
break;
+ case SM_MAGNUM:
+ case MS_MAGNUM:
+ if( flag&1 ) {
+ //Damage depends on distance, so add it to flag if it is > 1
+ skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag|distance_bl(src, bl));
+ }
+ break;
+
case KN_BRANDISHSPEAR:
case ML_BRANDISH:
//Coded apart for it needs the flag passed to the damage calculation.
@@ -9900,7 +9906,6 @@ int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char
}
pc_stop_attack(sd);
- pc_stop_walking(sd,0);
if(battle_config.skill_log && battle_config.skill_log&BL_PC)
ShowInfo("PC %d skill castend skill =%d map=%s\n",sd->bl.id,skill_id,mapname);
diff --git a/src/map/status.c b/src/map/status.c
index e2eede490..1a726a415 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -3639,6 +3639,21 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) {
if (!bst || !st)
return;
+ /** [Playtester]
+ * This needs to be done even if there is currently no status change active, because
+ * we need to update the speed on the client when the last status change ends.
+ **/
+ if(flag&SCB_SPEED) {
+ struct unit_data *ud = unit->bl2ud(bl);
+ /** [Skotlex]
+ * Re-walk to adjust speed (we do not check if walktimer != INVALID_TIMER
+ * because if you step on something while walking, the moment this
+ * piece of code triggers the walk-timer is set on INVALID_TIMER)
+ **/
+ if (ud)
+ ud->state.change_walk_target = ud->state.speed_changed = 1;
+ }
+
if((!(bl->type&BL_REGEN)) && (!sc || !sc->count)) { //No difference.
status_cpy(st, bst);
return;
@@ -3815,16 +3830,9 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) {
}
if(flag&SCB_SPEED) {
- struct unit_data *ud = unit->bl2ud(bl);
st->speed = status->calc_speed(bl, sc, bst->speed);
- //Re-walk to adjust speed (we do not check if walktimer != INVALID_TIMER
- //because if you step on something while walking, the moment this
- //piece of code triggers the walk-timer is set on INVALID_TIMER) [Skotlex]
- if (ud)
- ud->state.change_walk_target = ud->state.speed_changed = 1;
-
if( bl->type&BL_PC && !(sd && sd->state.permanent_speed) && st->speed < battle_config.max_walk_speed )
st->speed = battle_config.max_walk_speed;
@@ -4200,8 +4208,6 @@ unsigned short status_calc_str(struct block_list *bl, struct status_change *sc,
}
if(sc->data[SC_BEYOND_OF_WARCRY])
str += sc->data[SC_BEYOND_OF_WARCRY]->val3;
- if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && str < 50)
- return 50;
if(sc->data[SC_INCALLSTATUS])
str += sc->data[SC_INCALLSTATUS]->val1;
if(sc->data[SC_CHASEWALK2])
@@ -4232,6 +4238,8 @@ unsigned short status_calc_str(struct block_list *bl, struct status_change *sc,
str -= ((sc->data[SC_MARIONETTE_MASTER]->val3)>>16)&0xFF;
if(sc->data[SC_MARIONETTE])
str += ((sc->data[SC_MARIONETTE]->val3)>>16)&0xFF;
+ if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH)
+ str += ((sc->data[SC_SOULLINK]->val3)>>16)&0xFF;
if(sc->data[SC_GIANTGROWTH])
str += 30;
if(sc->data[SC_SAVAGE_STEAK])
@@ -4257,8 +4265,6 @@ unsigned short status_calc_agi(struct block_list *bl, struct status_change *sc,
agi -= sc->data[SC_HARMONIZE]->val2;
return (unsigned short)cap_value(agi,0,USHRT_MAX);
}
- if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && agi < 50)
- return 50;
if(sc->data[SC_CONCENTRATION] && !sc->data[SC_QUAGMIRE])
agi += (agi-sc->data[SC_CONCENTRATION]->val3)*sc->data[SC_CONCENTRATION]->val2/100;
if(sc->data[SC_INCALLSTATUS])
@@ -4287,6 +4293,8 @@ unsigned short status_calc_agi(struct block_list *bl, struct status_change *sc,
agi -= ((sc->data[SC_MARIONETTE_MASTER]->val3)>>8)&0xFF;
if(sc->data[SC_MARIONETTE])
agi += ((sc->data[SC_MARIONETTE]->val3)>>8)&0xFF;
+ if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH)
+ agi += ((sc->data[SC_SOULLINK]->val3)>>8)&0xFF;
if(sc->data[SC_ADORAMUS])
agi -= sc->data[SC_ADORAMUS]->val2;
if(sc->data[SC_DROCERA_HERB_STEAMED])
@@ -4315,8 +4323,6 @@ unsigned short status_calc_vit(struct block_list *bl, struct status_change *sc,
vit -= sc->data[SC_HARMONIZE]->val2;
return (unsigned short)cap_value(vit,0,USHRT_MAX);
}
- if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && vit < 50)
- return 50;
if(sc->data[SC_INCALLSTATUS])
vit += sc->data[SC_INCALLSTATUS]->val1;
if(sc->data[SC_INCVIT])
@@ -4335,6 +4341,8 @@ unsigned short status_calc_vit(struct block_list *bl, struct status_change *sc,
vit -= sc->data[SC_MARIONETTE_MASTER]->val3&0xFF;
if(sc->data[SC_MARIONETTE])
vit += sc->data[SC_MARIONETTE]->val3&0xFF;
+ if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH)
+ vit += sc->data[SC_SOULLINK]->val3&0xFF;
if(sc->data[SC_LAUDAAGNUS])
vit += 4 + sc->data[SC_LAUDAAGNUS]->val1;
if(sc->data[SC_MINOR_BBQ])
@@ -4365,8 +4373,6 @@ unsigned short status_calc_int(struct block_list *bl, struct status_change *sc,
}
if(sc->data[SC_MELODYOFSINK])
int_ -= sc->data[SC_MELODYOFSINK]->val3;
- if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && int_ < 50)
- return 50;
if(sc->data[SC_INCALLSTATUS])
int_ += sc->data[SC_INCALLSTATUS]->val1;
if(sc->data[SC_INCINT])
@@ -4393,6 +4399,8 @@ unsigned short status_calc_int(struct block_list *bl, struct status_change *sc,
int_ -= ((sc->data[SC_MARIONETTE_MASTER]->val4)>>16)&0xFF;
if(sc->data[SC_MARIONETTE])
int_ += ((sc->data[SC_MARIONETTE]->val4)>>16)&0xFF;
+ if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH)
+ int_ += ((sc->data[SC_SOULLINK]->val4)>>16)&0xFF;
if(sc->data[SC_MANDRAGORA])
int_ -= 4 * sc->data[SC_MANDRAGORA]->val1;
if(sc->data[SC_COCKTAIL_WARG_BLOOD])
@@ -4425,8 +4433,6 @@ unsigned short status_calc_dex(struct block_list *bl, struct status_change *sc,
dex -= sc->data[SC_HARMONIZE]->val2;
return (unsigned short)cap_value(dex,0,USHRT_MAX);
}
- if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && dex < 50)
- return 50;
if(sc->data[SC_CONCENTRATION] && !sc->data[SC_QUAGMIRE])
dex += (dex-sc->data[SC_CONCENTRATION]->val4)*sc->data[SC_CONCENTRATION]->val2/100;
if(sc->data[SC_INCALLSTATUS])
@@ -4457,6 +4463,8 @@ unsigned short status_calc_dex(struct block_list *bl, struct status_change *sc,
dex -= ((sc->data[SC_MARIONETTE_MASTER]->val4)>>8)&0xFF;
if(sc->data[SC_MARIONETTE])
dex += ((sc->data[SC_MARIONETTE]->val4)>>8)&0xFF;
+ if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH)
+ dex += ((sc->data[SC_SOULLINK]->val4)>>8)&0xFF;
if(sc->data[SC_SIROMA_ICE_TEA])
dex += sc->data[SC_SIROMA_ICE_TEA]->val1;
if(sc->data[SC_INSPIRATION])
@@ -4487,8 +4495,6 @@ unsigned short status_calc_luk(struct block_list *bl, struct status_change *sc,
}
if(sc->data[SC_CURSE])
return 0;
- if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && luk < 50)
- return 50;
if(sc->data[SC_INCALLSTATUS])
luk += sc->data[SC_INCALLSTATUS]->val1;
if(sc->data[SC_INCLUK])
@@ -4505,6 +4511,8 @@ unsigned short status_calc_luk(struct block_list *bl, struct status_change *sc,
luk -= sc->data[SC_MARIONETTE_MASTER]->val4&0xFF;
if(sc->data[SC_MARIONETTE])
luk += sc->data[SC_MARIONETTE]->val4&0xFF;
+ if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH)
+ luk += sc->data[SC_SOULLINK]->val4&0xFF;
if(sc->data[SC_PUTTI_TAILS_NOODLES])
luk += sc->data[SC_PUTTI_TAILS_NOODLES]->val1;
if(sc->data[SC_INSPIRATION])
@@ -7231,9 +7239,13 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t
if (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE)
status_change_end(bl, SC_STONE, INVALID_TIMER);
}
+ if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH)
+ status_change_end(bl, SC_SOULLINK, INVALID_TIMER);
break;
case SC_INC_AGI:
status_change_end(bl, SC_DEC_AGI, INVALID_TIMER);
+ if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH)
+ status_change_end(bl, SC_SOULLINK, INVALID_TIMER);
break;
case SC_QUAGMIRE:
status_change_end(bl, SC_CONCENTRATION, INVALID_TIMER);
@@ -8051,6 +8063,23 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t
stat = (psce->val4 >> 0)&0xFF; stat = min(stat, max_stat - tst->luk ); val4 |= cap_value(stat,0,0xFF);
}
break;
+ case SC_SOULLINK:
+ //1st Transcendent Spirit works similar to Marionette Control
+ if(sd && val2 == SL_HIGH) {
+ int stat,max_stat;
+ // Fetch target's stats
+ struct status_data* status2 = status_get_status_data(bl); // Battle status
+ val3 = 0;
+ val4 = 0;
+ max_stat = (status_get_lv(bl)-10<50)?status_get_lv(bl)-10:50;
+ stat = max(0, max_stat - status2->str ); val3 |= cap_value(stat,0,0xFF)<<16;
+ stat = max(0, max_stat - status2->agi ); val3 |= cap_value(stat,0,0xFF)<<8;
+ stat = max(0, max_stat - status2->vit ); val3 |= cap_value(stat,0,0xFF);
+ stat = max(0, max_stat - status2->int_); val4 |= cap_value(stat,0,0xFF)<<16;
+ stat = max(0, max_stat - status2->dex ); val4 |= cap_value(stat,0,0xFF)<<8;
+ stat = max(0, max_stat - status2->luk ); val4 |= cap_value(stat,0,0xFF);
+ }
+ break;
case SC_SWORDREJECT:
val2 = 15*val1; //Reflect chance
val3 = 3; //Reflections
diff --git a/src/map/unit.c b/src/map/unit.c
index c00a0631d..aa71ad1fb 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -100,6 +100,13 @@ int unit_walktoxy_sub(struct block_list *bl)
if( !path->search(&wpd,bl->m,bl->x,bl->y,ud->to_x,ud->to_y,ud->state.walk_easy,CELL_CHKNOPASS) )
return 0;
+#ifdef OFFICIAL_WALKPATH
+ if( !path->search_long(NULL, bl->m, bl->x, bl->y, ud->to_x, ud->to_y, CELL_CHKNOPASS) // Check if there is an obstacle between
+ && wpd.path_len > 14 // Official number of walkable cells is 14 if and only if there is an obstacle between. [malufett]
+ && (bl->type != BL_NPC) ) // If type is a NPC, please disregard.
+ return 0;
+#endif
+
memcpy(&ud->walkpath,&wpd,sizeof(wpd));
if (ud->target_to && ud->chaserange>1) {
@@ -391,8 +398,14 @@ int unit_walktoxy_timer(int tid, int64 tick, int id, intptr_t data) {
ud->steptimer = timer->add(tick+i, unit->step_timer, bl->id, 0);
}
- if(ud->state.change_walk_target)
- return unit->walktoxy_sub(bl);
+ if(ud->state.change_walk_target) {
+ if(unit_walktoxy_sub(bl)) {
+ return 1;
+ } else {
+ clif->fixpos(bl);
+ return 0;
+ }
+ }
ud->walkpath.path_pos++;
if(ud->walkpath.path_pos>=ud->walkpath.path_len)
@@ -572,6 +585,10 @@ int unit_walktobl(struct block_list *bl, struct block_list *tbl, int range, int
ud->to_y = bl->y;
ud->target_to = 0;
return 0;
+ } else if (range == 0) {
+ //Should walk on the same cell as target (for looters)
+ ud->to_x = tbl->x;
+ ud->to_y = tbl->y;
}
ud->state.walk_easy = flag&1;
@@ -1131,6 +1148,10 @@ int unit_set_walkdelay(struct block_list *bl, int64 tick, int delay, int type) {
if (delay <= 0 || !ud) return 0;
if (type) {
+ //Bosses can ignore skill induced walkdelay (but not damage induced)
+ if(bl->type == BL_MOB && (((TBL_MOB*)bl)->status.mode&MD_BOSS))
+ return 0;
+ //Make sure walk delay is not decreased
if (DIFF_TICK(ud->canmove_tick, tick+delay) > 0)
return 0;
} else {