Browse Source

Adds battle config mob_respawn_time (#7312)

* Adjusts the minimum respawn time of a monster to be 1 second as it is officially.
* Adds a battle config to allow for easy adjustment.
* Monsters that don't define a delay1 for permanent spawn scripts are defaulted to 5 seconds.
Thanks to @mrjnumber1, @vstumpf, @Lemongrass3110, and @Atemo!
Co-authored-by: Lemongrass3110 <lemongrass@kstp.at>
Aleos 2 years ago
parent
commit
da375a04c1

+ 5 - 0
conf/battle/monster.conf

@@ -297,3 +297,8 @@ achievement_mob_share: no
 // Should slaves teleport back to their master if they get too far during chase? (Note 1)
 // Should slaves teleport back to their master if they get too far during chase? (Note 1)
 // Default (Official): no
 // Default (Official): no
 slave_stick_with_master: no
 slave_stick_with_master: no
+
+// Absolute minimum respawn time in milliseconds of a monster.
+// Also used in delaying the spawning of guardians when a guild is not loaded.
+// Default (Official): 1000
+mob_respawn_time: 1000

+ 2 - 1
doc/script_commands.txt

@@ -159,7 +159,8 @@ executed, it is affected by spawn rates in 'battle_athena.conf'.
 Delay1 and delay2 control monster respawn delays - the first one is the fixed
 Delay1 and delay2 control monster respawn delays - the first one is the fixed
 base respawn time, and the second is random variance on top of the base time.
 base respawn time, and the second is random variance on top of the base time.
 Both values are given in milliseconds (1000 = 1 second).
 Both values are given in milliseconds (1000 = 1 second).
-Note that the server also enforces a minimum respawn delay of 5 seconds.
+Note that the server also enforces a minimum respawn delay of 1 second (See
+/conf/battle/monster.conf::mob_respawn_time).
 
 
 Event is a script event to be executed when the mob is killed. The event must
 Event is a script event to be executed when the mob is killed. The event must
 be in the form "NPCName::OnEventName" to execute, and the event name label
 be in the form "NPCName::OnEventName" to execute, and the event name label

+ 1 - 1
npc/pre-re/mobs/dungeons/nyd_dun.txt

@@ -14,7 +14,7 @@
 // nyd_dun01 - Yggdrasil Root Dungeon
 // nyd_dun01 - Yggdrasil Root Dungeon
 //==================================================
 //==================================================
 nyd_dun01,0,0	monster	Draco	2013,40
 nyd_dun01,0,0	monster	Draco	2013,40
-nyd_dun01,0,0	monster	Draco's Egg	2014,10,0,0,0
+nyd_dun01,0,0	monster	Draco's Egg	2014,10
 nyd_dun01,0,0	monster	Aqua Elemental	2016,20
 nyd_dun01,0,0	monster	Aqua Elemental	2016,20
 nyd_dun01,0,0	monster	Dark Pinguicula	2015,10
 nyd_dun01,0,0	monster	Dark Pinguicula	2015,10
 nyd_dun01,0,0	monster	Rata	2017,2,900000
 nyd_dun01,0,0	monster	Rata	2017,2,900000

+ 1 - 1
npc/pre-re/mobs/dungeons/prt_maze.txt

@@ -84,7 +84,7 @@ prt_maze03,50,150,70,70	monster	Vagabond Wolf	1092,1,1920000,150000
 prt_maze03,170,170,70,70	monster	Mantis	1139,30,60000,30000
 prt_maze03,170,170,70,70	monster	Mantis	1139,30,60000,30000
 prt_maze03,170,170,70,70	monster	Eclipse	1093,1,1920000,150000
 prt_maze03,170,170,70,70	monster	Eclipse	1093,1,1920000,150000
 prt_maze03,23,23,70,70	monster	Mastering	1090,1,1920000,150000
 prt_maze03,23,23,70,70	monster	Mastering	1090,1,1920000,150000
-prt_maze03,100,100,80,80	monster	Baphomet Jr.	1101,25,0,0,0
+prt_maze03,100,100,80,80	monster	Baphomet Jr.	1101,25
 prt_maze03,0,0,0,0	boss_monster	Baphomet	1039,1,7200000,600000,1
 prt_maze03,0,0,0,0	boss_monster	Baphomet	1039,1,7200000,600000,1
 prt_maze03,61,98,10,10	monster	Shining Plant	1083,1,1800000,900000
 prt_maze03,61,98,10,10	monster	Shining Plant	1083,1,1800000,900000
 prt_maze03,61,98,10,10	monster	Blue Plant	1079,1,1800000,900000
 prt_maze03,61,98,10,10	monster	Blue Plant	1079,1,1800000,900000

+ 7 - 7
npc/re/mobs/dungeons/glastheim.txt

@@ -184,11 +184,11 @@ gl_step,0,0	monster	Mimic	1191,6,5000
 //==================================================
 //==================================================
 // gl_cas02_ - Nightmare Mode 2f
 // gl_cas02_ - Nightmare Mode 2f
 //==================================================
 //==================================================
-gl_cas02_,0,0	monster	Evil Druid (Nightmare)	2480,4,0,0,0
-gl_cas02_,0,0	monster	Chimera (Nightmare)	2485,1,0,0,0
-gl_cas02_,0,0	monster	Mimic (Nightmare)	2479,19,0,0,0
-gl_cas02_,0,0	monster	Rideword (Nightmare)	2478,10,0,0,0
-gl_cas02_,0,0	monster	Wanderer (Nightmare)	2477,60,0,0,0
+gl_cas02_,0,0	monster	Evil Druid (Nightmare)	2480,4,5000
+gl_cas02_,0,0	monster	Chimera (Nightmare)	2485,1,5000
+gl_cas02_,0,0	monster	Mimic (Nightmare)	2479,19,5000
+gl_cas02_,0,0	monster	Rideword (Nightmare)	2478,10,5000
+gl_cas02_,0,0	monster	Wanderer (Nightmare)	2477,60,5000
 gl_cas02_,0,0	monster	Mysteltainn	1203,1,7200000,3600000
 gl_cas02_,0,0	monster	Mysteltainn	1203,1,7200000,3600000
 gl_cas02_,0,0	monster	Alice	1275,1,5000
 gl_cas02_,0,0	monster	Alice	1275,1,5000
 gl_cas02_,102,180	monster	Whisper	1185,1,1800000,900000
 gl_cas02_,102,180	monster	Whisper	1185,1,1800000,900000
@@ -197,8 +197,8 @@ gl_cas02_,0,0	monster	Baphomet (Nightmare)	2483,1,7200000,0,0
 //==================================================
 //==================================================
 // gl_chyard_ - Nightmare Mode Churchyard
 // gl_chyard_ - Nightmare Mode Churchyard
 //==================================================
 //==================================================
-gl_chyard_,0,0	monster	Wraith Dead (Nightmare)	2481,91,0,0,0
-gl_chyard_,0,0	monster	Wraith Dead	1291,31,0,0,0
+gl_chyard_,0,0	monster	Wraith Dead (Nightmare)	2481,91,5000
+gl_chyard_,0,0	monster	Wraith Dead	1291,31,5000
 gl_chyard_,0,0	monster	Evil Druid (Nightmare)	2480,22,60000,0,0
 gl_chyard_,0,0	monster	Evil Druid (Nightmare)	2480,22,60000,0,0
 gl_chyard_,0,0	monster	Mimic (Nightmare)	2479,34,60000,0,0
 gl_chyard_,0,0	monster	Mimic (Nightmare)	2479,34,60000,0,0
 gl_chyard_,0,0,0,0	boss_monster	Dark Lord	1272,1,3600000,600000,1
 gl_chyard_,0,0,0,0	boss_monster	Dark Lord	1272,1,3600000,600000,1

+ 20 - 20
npc/re/mobs/verus.txt

@@ -10,28 +10,28 @@
 //============================================================
 //============================================================
 
 
 // ver_eju
 // ver_eju
-ver_eju,0,0,0,0	monster	Recon Robot	3154,50,0,0,0
-ver_eju,0,0,0,0	monster	Excavator Robot	3153,10,0,0,0
+ver_eju,0,0,0,0	monster	Recon Robot	3154,50,5000
+ver_eju,0,0,0,0	monster	Excavator Robot	3153,10,5000
 // ver_tunn
 // ver_tunn
-ver_tunn,0,0,0,0	monster	Recon Robot	3154,5,0,0,0
+ver_tunn,0,0,0,0	monster	Recon Robot	3154,5,30000
 // verus01
 // verus01
-verus01,0,0,0,0	monster	Green Cenere	3247,50,0,0,0
-verus01,0,0,0,0	monster	Explorer Robot Turbo	3249,25,0,0,0
-verus01,0,0,0,0	monster	Repair Robot Turbo	3248,25,0,0,0
+verus01,0,0,0,0	monster	Green Cenere	3247,50,5000
+verus01,0,0,0,0	monster	Explorer Robot Turbo	3249,25,5000
+verus01,0,0,0,0	monster	Repair Robot Turbo	3248,25,5000
 // verus02
 // verus02
-verus02,0,0,0,0	monster	Repair Robot Turbo	3248,50,0,0,0
-verus02,0,0,0,0	monster	Explorer Robot Turbo	3249,50,0,0,0
+verus02,0,0,0,0	monster	Repair Robot Turbo	3248,50,5000
+verus02,0,0,0,0	monster	Explorer Robot Turbo	3249,50,5000
 // verus03
 // verus03
-verus03,0,0,0,0	monster	Illegal Promotion	3159,40,0,0,0
-verus03,0,0,0,0	monster	Explorer Robot	3156,50,0,0,0
-verus03,0,0,0,0	monster	Repair Robot	3155,50,0,0,0
-verus03,0,0,0,0	monster	Ruin Grace Believer	3158,10,0,0,0
+verus03,0,0,0,0	monster	Illegal Promotion	3159,40,5000
+verus03,0,0,0,0	monster	Explorer Robot	3156,50,5000
+verus03,0,0,0,0	monster	Repair Robot	3155,50,5000
+verus03,0,0,0,0	monster	Ruin Grace Believer	3158,10,5000
 // un_bunker
 // un_bunker
-un_bunker,0,0,0,0	monster	Thief Bug	1051,6,0,0,0
-un_bunker,0,0,0,0	monster	Smelly Ghoul	3255,68,0,0,0
-un_bunker,0,0,0,0	monster	Smelly Zombie	3256,80,0,0,0
-un_bunker,0,0,0,0	monster	Machine Component	3250,28,0,0,0
-un_bunker,0,0,0,0	monster	DR815	3252,14,0,0,0
-un_bunker,0,0,0,0	monster	GC109	3251,10,0,0,0
-un_bunker,0,0,0,0	monster	Black Mushroom	1084,1,0,0,0
-un_bunker,0,0,0,0	monster	Chonchon	1011,2,0,0,0
+un_bunker,0,0,0,0	monster	Thief Bug	1051,6,5000
+un_bunker,0,0,0,0	monster	Smelly Ghoul	3255,68,5000
+un_bunker,0,0,0,0	monster	Smelly Zombie	3256,80,5000
+un_bunker,0,0,0,0	monster	Machine Component	3250,28,5000
+un_bunker,0,0,0,0	monster	DR815	3252,14,5000
+un_bunker,0,0,0,0	monster	GC109	3251,10,5000
+un_bunker,0,0,0,0	monster	Black Mushroom	1084,1,5000
+un_bunker,0,0,0,0	monster	Chonchon	1011,2,5000

+ 2 - 0
src/map/battle.cpp

@@ -10283,6 +10283,8 @@ static const struct _battle_data {
 	{ "feature.dynamicnpc_rangey",          &battle_config.feature_dynamicnpc_rangey,       2,      0,      INT_MAX,        },
 	{ "feature.dynamicnpc_rangey",          &battle_config.feature_dynamicnpc_rangey,       2,      0,      INT_MAX,        },
 	{ "feature.dynamicnpc_direction",       &battle_config.feature_dynamicnpc_direction,    0,      0,      1,              },
 	{ "feature.dynamicnpc_direction",       &battle_config.feature_dynamicnpc_direction,    0,      0,      1,              },
 
 
+	{ "mob_respawn_time",                   &battle_config.mob_respawn_time,                1000,   1000,   INT_MAX,        },
+
 #include "../custom/battle_config_init.inc"
 #include "../custom/battle_config_init.inc"
 };
 };
 
 

+ 2 - 0
src/map/battle.hpp

@@ -722,6 +722,8 @@ struct Battle_Config
 	int feature_dynamicnpc_rangey;
 	int feature_dynamicnpc_rangey;
 	int feature_dynamicnpc_direction;
 	int feature_dynamicnpc_direction;
 
 
+	int mob_respawn_time;
+
 #include "../custom/battle_config_struct.inc"
 #include "../custom/battle_config_struct.inc"
 };
 };
 
 

+ 6 - 7
src/map/mob.cpp

@@ -695,8 +695,8 @@ int mob_once_spawn(struct map_session_data* sd, int16 m, int16 x, int16 y, const
 					md->guardian_data->emblem_id = g->emblem_id;
 					md->guardian_data->emblem_id = g->emblem_id;
 					memcpy(md->guardian_data->guild_name, g->name, NAME_LENGTH);
 					memcpy(md->guardian_data->guild_name, g->name, NAME_LENGTH);
 				}
 				}
-				else if (gc->guild_id) //Guild not yet available, retry in 5.
-					add_timer(gettick()+5000,mob_spawn_guardian_sub,md->bl.id,md->guardian_data->guild_id);
+				else if (gc->guild_id) // Guild is not yet available, retry after the configured timespan.
+					add_timer(gettick() + battle_config.mob_respawn_time,mob_spawn_guardian_sub,md->bl.id,md->guardian_data->guild_id);
 			}
 			}
 		}	// end addition [Valaris]
 		}	// end addition [Valaris]
 
 
@@ -914,7 +914,7 @@ int mob_spawn_guardian(const char* mapname, int16 x, int16 y, const char* mobnam
 		memcpy (md->guardian_data->guild_name, g->name, NAME_LENGTH);
 		memcpy (md->guardian_data->guild_name, g->name, NAME_LENGTH);
 		md->guardian_data->guardup_lv = guild_checkskill(g,GD_GUARDUP);
 		md->guardian_data->guardup_lv = guild_checkskill(g,GD_GUARDUP);
 	} else if (md->guardian_data->guild_id)
 	} else if (md->guardian_data->guild_id)
-		add_timer(gettick()+5000,mob_spawn_guardian_sub,md->bl.id,md->guardian_data->guild_id);
+		add_timer(gettick() + battle_config.mob_respawn_time,mob_spawn_guardian_sub,md->bl.id,md->guardian_data->guild_id);
 	mob_spawn(md);
 	mob_spawn(md);
 
 
 	return md->bl.id;
 	return md->bl.id;
@@ -1073,8 +1073,7 @@ int mob_setdelayspawn(struct mob_data *md)
 		spawntime = spawntime/100*battle_config.mob_spawn_delay;
 		spawntime = spawntime/100*battle_config.mob_spawn_delay;
 	}
 	}
 
 
-	if (spawntime < 5000) //Monsters should never respawn faster than within 5 seconds
-		spawntime = 5000;
+	spawntime = u32max(1000, spawntime); //Monsters should never respawn faster than 1 second
 
 
 	if( md->spawn_timer != INVALID_TIMER )
 	if( md->spawn_timer != INVALID_TIMER )
 		delete_timer(md->spawn_timer, mob_delayspawn);
 		delete_timer(md->spawn_timer, mob_delayspawn);
@@ -1126,7 +1125,7 @@ int mob_spawn (struct mob_data *md)
 			{ // retry again later
 			{ // retry again later
 				if( md->spawn_timer != INVALID_TIMER )
 				if( md->spawn_timer != INVALID_TIMER )
 					delete_timer(md->spawn_timer, mob_delayspawn);
 					delete_timer(md->spawn_timer, mob_delayspawn);
-				md->spawn_timer = add_timer(tick+5000,mob_delayspawn,md->bl.id,0);
+				md->spawn_timer = add_timer(tick + battle_config.mob_respawn_time,mob_delayspawn,md->bl.id,0);
 				return 1;
 				return 1;
 			}
 			}
 		}
 		}
@@ -1134,7 +1133,7 @@ int mob_spawn (struct mob_data *md)
 		{ // retry again later (players on sight)
 		{ // retry again later (players on sight)
 			if( md->spawn_timer != INVALID_TIMER )
 			if( md->spawn_timer != INVALID_TIMER )
 				delete_timer(md->spawn_timer, mob_delayspawn);
 				delete_timer(md->spawn_timer, mob_delayspawn);
-			md->spawn_timer = add_timer(tick+5000,mob_delayspawn,md->bl.id,0);
+			md->spawn_timer = add_timer(tick + battle_config.mob_respawn_time,mob_delayspawn,md->bl.id,0);
 			return 1;
 			return 1;
 		}
 		}
 	}
 	}

+ 8 - 2
src/map/npc.cpp

@@ -5118,7 +5118,7 @@ void npc_parse_mob2(struct spawn_data* mob)
 
 
 static const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath)
 static const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath)
 {
 {
-	int num, mob_id, mob_lv = -1, size = -1, w1count;
+	int num, mob_id, mob_lv = -1, delay = 5000, size = -1, w1count, w4count;
 	short m, x = 0, y = 0, xs = -1, ys = -1;
 	short m, x = 0, y = 0, xs = -1, ys = -1;
 	char mapname[MAP_NAME_LENGTH_EXT], mobname[NAME_LENGTH], sprite[NAME_LENGTH];
 	char mapname[MAP_NAME_LENGTH_EXT], mobname[NAME_LENGTH], sprite[NAME_LENGTH];
 	struct spawn_data mob, *data;
 	struct spawn_data mob, *data;
@@ -5133,7 +5133,7 @@ static const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const c
 	// w4=<mob id>,<amount>{,<delay1>{,<delay2>{,<event>{,<mob size>{,<mob ai>}}}}}
 	// w4=<mob id>,<amount>{,<delay1>{,<delay2>{,<event>{,<mob size>{,<mob ai>}}}}}
 	if( ( w1count = sscanf(w1, "%15[^,],%6hd,%6hd,%6hd,%6hd", mapname, &x, &y, &xs, &ys) ) < 1
 	if( ( w1count = sscanf(w1, "%15[^,],%6hd,%6hd,%6hd,%6hd", mapname, &x, &y, &xs, &ys) ) < 1
 	||	sscanf(w3, "%23[^,],%11d", mobname, &mob_lv) < 1
 	||	sscanf(w3, "%23[^,],%11d", mobname, &mob_lv) < 1
-	||	sscanf(w4, "%23[^,],%11d,%11u,%11u,%77[^,],%11d,%11d[^\t\r\n]", sprite, &num, &mob.delay1, &mob.delay2, mob.eventname, &size, &ai) < 2 )
+	||	( w4count = sscanf(w4, "%23[^,],%11d,%11u,%11u,%77[^,],%11d,%11d[^\t\r\n]", sprite, &num, &delay, &mob.delay2, mob.eventname, &size, &ai) ) < 2 )
 	{
 	{
 		ShowError("npc_parse_mob: Invalid mob definition in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4);
 		ShowError("npc_parse_mob: Invalid mob definition in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4);
 		return strchr(start,'\n');// skip and continue
 		return strchr(start,'\n');// skip and continue
@@ -5181,6 +5181,12 @@ static const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const c
 		return strchr(start,'\n');// skip and continue
 		return strchr(start,'\n');// skip and continue
 	}
 	}
 
 
+	if (w4count > 2 && delay != 5000 && delay < battle_config.mob_respawn_time) {
+		ShowWarning("npc_parse_mob: Invalid delay %u for mob ID %d (file '%s', line '%d'), defaulting to 5 seconds.\n", delay, mob_id, filepath, strline(buffer, start - buffer));
+		mob.delay1 = 5000;
+	} else
+		mob.delay1 = delay;
+
 	if( mob.state.size > SZ_BIG && size != -1 )
 	if( mob.state.size > SZ_BIG && size != -1 )
 	{
 	{
 		ShowError("npc_parse_mob: Invalid size number %d for mob ID %d (file '%s', line '%d').\n", mob.state.size, mob_id, filepath, strline(buffer, start - buffer));
 		ShowError("npc_parse_mob: Invalid size number %d for mob ID %d (file '%s', line '%d').\n", mob.state.size, mob_id, filepath, strline(buffer, start - buffer));