Browse Source

Timer interval, Waterball, Crimson Fire Formation and boss walk delay 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

Playtester 10 years ago
parent
commit
525e8178c2
6 changed files with 27 additions and 16 deletions
  1. 1 1
      db/pre-re/skill_db.txt
  2. 1 1
      db/re/skill_db.txt
  3. 3 1
      src/common/timer.c
  4. 6 8
      src/map/battle.c
  5. 12 5
      src/map/skill.c
  6. 4 0
      src/map/unit.c

+ 1 - 1
db/pre-re/skill_db.txt

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

+ 1 - 1
db/re/skill_db.txt

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

+ 3 - 1
src/common/timer.c

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

+ 6 - 8
src/map/battle.c

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

+ 12 - 5
src/map/skill.c

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

+ 4 - 0
src/map/unit.c

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