Skip to content

Commit

Permalink
Timer interval, Waterball, Crimson Fire Formation and boss walk delay…
Browse files Browse the repository at this point in the history
… updates

- Reduced the timer interval from 50ms to 20ms (official value)
  * For a long time it is well known that the Aegis interval is 20ms, but devs have been hesitant to set it to that out of performance reasons; these days however, machines are better and there aren't really many 2000+ player servers anymore, so a 20ms interval is actually quite viable now.
  * Setting the interval to 20ms makes the server perfectly in sync with the client that expects the server to have a delay of no longer than 20ms.
  * All skills that are "chain-able" on official servers will now also be 100% chain-able here (previously it just worked to 40%), assuming there is no lag
  * Skills with cast time will no longer go off 30ms later than officially
  * Several others improvements in regards of client-server sync (timers are used almost everywhere)
  * This might increase the CPU usage by up to ~50%, if you have trouble running your server with this, you can increase it again in timer.c (TIMER_MIN_INTERVAL)
- Strongly improved the Waterball implementation (bugreport:9382)
  * The interval between Waterballs is now 150ms (previously 125ms); due to the timer interval it will alternate between 140ms and 160ms (yes, this is official)
  * While the Waterball effect is active, players and non-boss monsters can no longer walk
  * Added a server-sided canact delay each time a Waterball is shot, which is equal to the one the client gives; this is to prevent hackers from being able to mass-cast Waterball; you can still multi-cast Waterball if your aMotion is shorter than the Waterball interval (i.e. 186 ASPD or higher)
  * The Waterball effect is no longer canceled when the target hides behind an obstacle, but no waterballs will fly and no damage will be applied; walkdelay will remain, but there won't be any canact delay for the caster (meaning he can cast another spell); if the target comes out of its cover during the duration, it will be hit again (this also fixes an exploit against MVPs)
  * Waterball now has a max duration of 10 seconds, even if more water cells are available, the effect will stop; this means that level 10 monster water ball will now only hit up to 67 times
- Fixed Crimson Fire Formation having a knock-back effect although it shouldn't (bugreport:6949)
  * It will hit once every 20ms with no knock-back, regardless of whether the target is undead, non-undead or a player
  * If you want to it to display more "fluently" you would need to set the SKILLUNITTIMER_INTERVAL in skill.c to 20ms, but the performance loss is pretty big for something only this skill and Firewall would benefit from
- Bosses are now able to ignore skill-induced walk delay (#100)
  * They can for example walk after casting Sonic Blow and Waterball (see above)
- Minor description improvements
  • Loading branch information
Playtester committed Nov 12, 2014
1 parent b28e9dc commit 525e817
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 16 deletions.
2 changes: 1 addition & 1 deletion db/pre-re/skill_db.txt
Expand Up @@ -756,7 +756,7 @@
532,0,6,4,0,0x1,0,10,1,yes,0,0,0,magic,0,0x0, NJ_BUNSINJYUTSU,Mirror Image
533,0,0,0,0,0,0,10,0,no,0,0,0,none,0,0x0, 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,0x0, NJ_KOUENKA,Crimson Fire Petal
535,0,8,4,3,0,0,10,1,yes,0,0,0,magic,1,0x0, NJ_KAENSIN,Crimson Fire Formation
535,0,8,4,3,0,0,10,1,yes,0,0,0,magic,0,0x0, NJ_KAENSIN,Crimson Fire Formation
536,9,8,1,3,0x2,2,5,3,yes,0,0,0,magic,0,0x0, 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,0x0, NJ_HYOUSENSOU,Spear of Ice
538,9,6,2,1,0x1,0,10,1,yes,0,0,0,magic,0,0x1000, NJ_SUITON,Hidden Water
Expand Down
2 changes: 1 addition & 1 deletion db/re/skill_db.txt
Expand Up @@ -756,7 +756,7 @@
532,0,6,4,0,0x1,0,10,1,yes,0,0,0,magic,0,0x0, NJ_BUNSINJYUTSU,Mirror Image
533,0,0,0,0,0,0,10,0,no,0,0,0,none,0,0x0, 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,0x0, NJ_KOUENKA,Crimson Fire Petal
535,0,8,4,3,0,0,10,1,yes,0,0,0,magic,1,0x0, NJ_KAENSIN,Crimson Fire Formation
535,0,8,4,3,0,0,10,1,yes,0,0,0,magic,0,0x0, NJ_KAENSIN,Crimson Fire Formation
536,9,8,1,3,0x2,2,5,3,yes,0,0,0,magic,0,0x0, 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,0x0, NJ_HYOUSENSOU,Spear of Ice
538,9,6,2,1,0x1,0,10,1,yes,0,0,0,magic,0,0x1000, NJ_SUITON,Hidden Water
Expand Down
4 changes: 3 additions & 1 deletion src/common/timer.c
Expand Up @@ -23,7 +23,9 @@

// If the server can't handle processing thousands of monsters
// or many connected clients, please increase TIMER_MIN_INTERVAL.
#define TIMER_MIN_INTERVAL 50
// The official interval of 20ms is however strongly recommended,
// as it is needed for perfect server-client syncing.
#define TIMER_MIN_INTERVAL 20
#define TIMER_MAX_INTERVAL 1000

// timers (array)
Expand Down
14 changes: 6 additions & 8 deletions src/map/battle.c
Expand Up @@ -3045,12 +3045,11 @@ struct Damage battle_calc_skill_base_damage(struct Damage wd, struct block_list
#define DAMAGE_DIV_FIX(dmg, div) { if (div < 0) { (div)*=-1; (dmg)/=div; } (dmg)*=div; }
#define DAMAGE_DIV_FIX2(dmg, div) { if (div > 1) (dmg)*=div; }
#define DAMAGE_DIV_FIX_RENEWAL(wd, div) { DAMAGE_DIV_FIX2(wd.statusAtk, div); DAMAGE_DIV_FIX2(wd.weaponAtk, div); DAMAGE_DIV_FIX2(wd.equipAtk, div); DAMAGE_DIV_FIX2(wd.masteryAtk, div); }
/*=================================================
/*================================================= [Playtester]
* Applies DAMAGE_DIV_FIX and checks for min damage
*-------------------------------------------------
* Credits:
* Original coder Playtester
*/
* @param d: Damage struct to apply DAMAGE_DIV_FIX to
* @return Modified damage struct
*------------------------------------------------*/
static struct Damage battle_apply_div_fix(struct Damage d)
{
if(d.damage) {
Expand Down Expand Up @@ -5342,11 +5341,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;
//Fall through
case NJ_KAENSIN:
case PR_SANCTUARY:
ad.dmotion = 0; //No flinch animation.
break;
Expand Down
17 changes: 12 additions & 5 deletions src/map/skill.c
Expand Up @@ -42,6 +42,7 @@
#include <math.h>

#define SKILLUNITTIMER_INTERVAL 100
#define WATERBALL_INTERVAL 150

// ranges reserved for mapping skill ids to skilldb offsets
#define HM_SKILLRANGEMIN 700
Expand Down Expand Up @@ -3721,11 +3722,15 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data)
case WZ_WATERBALL:
skill_toggle_magicpower(src, skl->skill_id); // only the first hit will be amplify
// Official behaviour is to hit as long as there is a line of sight, regardless of distance
range = path_search_long(NULL,src->m,src->x,src->y,target->x,target->y,CELL_CHKNOREACH);
if (!status_isdead(target) && range)
if (!status_isdead(target) && path_search_long(NULL,src->m,src->x,src->y,target->x,target->y,CELL_CHKNOREACH)) {
//Apply canact delay here to prevent hacks (unlimited waterball casting)
ud->canact_tick = tick + skill_delayfix(src, skl->skill_id, skl->skill_lv);
skill_attack(BF_MAGIC,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag);
if (skl->type>1 && !status_isdead(target) && !status_isdead(src) && range) {
skill_addtimerskill(src,tick+125,target->id,0,0,skl->skill_id,skl->skill_lv,skl->type-1,skl->flag);
}
if (skl->type>1 && !status_isdead(target) && !status_isdead(src)) {
//Timer will continue and walkdelay set until target is dead, even if there is currently no line of sight
unit_set_walkdelay(src, tick, WATERBALL_INTERVAL, 1);
skill_addtimerskill(src,tick+WATERBALL_INTERVAL,target->id,0,0,skl->skill_id,skl->skill_lv,skl->type-1,skl->flag);
} else {
struct status_change *sc = status_get_sc(src);
if(sc) {
Expand Down Expand Up @@ -4670,8 +4675,10 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
}
}

if( count > (10000/WATERBALL_INTERVAL)+1 ) //Waterball has a max duration of 10 seconds [Playtester]
count = (10000/WATERBALL_INTERVAL)+1;
if( count > 1 ) // queue the remaining count - 1 timerskill Waterballs
skill_addtimerskill(src,tick+150,bl->id,0,0,skill_id,skill_lv,count-1,flag);
skill_addtimerskill(src,tick+WATERBALL_INTERVAL,bl->id,0,0,skill_id,skill_lv,count-1,flag);
}
skill_attack(BF_MAGIC,src,src,bl,skill_id,skill_lv,tick,flag);
break;
Expand Down
4 changes: 4 additions & 0 deletions src/map/unit.c
Expand Up @@ -1420,6 +1420,10 @@ int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int
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 {
Expand Down

0 comments on commit 525e817

Please sign in to comment.