mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-13 08:03:43 +01:00
Mob Hunt Adjustments
Removes server instability, random disconnects, and server crash due to trap mobs / high player count Trap mobs are now capped just like normal spawns - If a trap mob is created that would push the total number of trap mobs over this limit, the server will remove the oldest trap mob (effectively replacing it) Changes health from a list using magic numbers to an associated list for readability (doesn't make sense to have two vars for what little uses this) Converts mob displaying to use the alternate appearance system, to allow for a per-mob control over visibility - Only will show for mobs that are holding a PDA with a game client that is connected to the game server. - Nanomobs properly are concealed from player mobs after being interacted with (capture/escape), PDA dropped, or game client disconnection - Game client will disconnect from game server when you change the active PDA app (including going to PDA main menu) and/or eject the game cartridge Also finished my thought in that one comment. It's about time I-
This commit is contained in:
@@ -3,9 +3,9 @@ var/global/datum/controller/process/mob_hunt/mob_hunt_server
|
||||
/datum/controller/process/mob_hunt
|
||||
var/max_normal_spawns = 15 //change this to adjust the number of normal spawns that can exist at one time. trapped spawns (from traitors) don't count towards this
|
||||
var/list/normal_spawns = list()
|
||||
var/max_trap_spawns = 15 //change this to adjust the number of trap spawns that can exist at one time. traps spawned beyond this point clear the oldest traps
|
||||
var/list/trap_spawns = list()
|
||||
var/list/connected_clients = list()
|
||||
var/server_instability = 0 //tracks the instability of the game server. trapped mobs and users increase instability, which causes random kicks and eventually crashing
|
||||
var/server_status = 1 //1 is online, 0 is offline
|
||||
|
||||
/datum/controller/process/mob_hunt/setup()
|
||||
@@ -23,24 +23,12 @@ var/global/datum/controller/process/mob_hunt/mob_hunt_server
|
||||
/datum/controller/process/mob_hunt/doWork()
|
||||
if(server_status == 0)
|
||||
return
|
||||
client_mob_update()
|
||||
if(normal_spawns.len < max_normal_spawns)
|
||||
spawn_mob()
|
||||
check_stability()
|
||||
if(server_instability >= 75)
|
||||
if(server_instability >= 100)
|
||||
server_crash()
|
||||
else if(prob(server_instability - 50))
|
||||
server_crash()
|
||||
|
||||
if(server_instability >= 25 && connected_clients.len >= 5)
|
||||
if(prob(server_instability))
|
||||
var/datum/data/pda/app/mob_hunter_game/client = pick(connected_clients)
|
||||
client.disconnect("Server Communication Error")
|
||||
|
||||
/datum/controller/process/mob_hunt/proc/check_stability()
|
||||
server_instability = connected_clients.len + (trap_spawns.len * 5)
|
||||
|
||||
/datum/controller/process/mob_hunt/proc/server_crash()
|
||||
//leaving this here in case admins want to use it for a random mini-event or something
|
||||
/datum/controller/process/mob_hunt/proc/server_crash(recover_time = 3000)
|
||||
server_status = 0
|
||||
for(var/datum/data/pda/app/mob_hunter_game/client in connected_clients)
|
||||
client.disconnect("Server Crash")
|
||||
@@ -52,13 +40,27 @@ var/global/datum/controller/process/mob_hunt/mob_hunt_server
|
||||
normal_spawns.Cut()
|
||||
trap_spawns.Cut()
|
||||
connected_clients.Cut()
|
||||
//set a timer to automatically recover in 5 minutes (can be manually restarted if you get impatient too)
|
||||
addtimer(src, "auto_recover", 3000, TRUE)
|
||||
if(!isnum(recover_time))
|
||||
recover_time = 3000
|
||||
if(recover_time > 0) //when provided with a negative or zero valued recover_time argument, the server won't auto-restart but can be manually rebooted still
|
||||
//set a timer to automatically recover after recover_time has passed (can be manually restarted if you get impatient too)
|
||||
addtimer(src, "auto_recover", recover_time, TRUE)
|
||||
|
||||
/datum/controller/process/mob_hunt/proc/client_mob_update()
|
||||
var/list/ex_players = list()
|
||||
for(var/datum/data/pda/app/mob_hunter_game/client in connected_clients)
|
||||
var/mob/living/carbon/human/H = client.get_player()
|
||||
if(connected_clients[client])
|
||||
if(!H || H != connected_clients[client])
|
||||
ex_players |= connected_clients[client]
|
||||
connected_clients[client] = H
|
||||
if(ex_players.len) //to make sure we don't do this if we didn't lose any player since the last update
|
||||
for(var/obj/effect/nanomob/N in (normal_spawns + trap_spawns))
|
||||
N.conceal(ex_players)
|
||||
|
||||
/datum/controller/process/mob_hunt/proc/auto_recover()
|
||||
if(server_status != 0)
|
||||
return
|
||||
server_instability = 0
|
||||
server_status = 1
|
||||
while(normal_spawns.len < max_normal_spawns) //repopulate the server's spawns completely if we auto-recover from crash
|
||||
spawn_mob()
|
||||
@@ -68,7 +70,6 @@ var/global/datum/controller/process/mob_hunt/mob_hunt_server
|
||||
N.despawn()
|
||||
for(var/obj/effect/nanomob/N in normal_spawns)
|
||||
N.despawn()
|
||||
check_stability()
|
||||
server_status = 1
|
||||
|
||||
/datum/controller/process/mob_hunt/proc/spawn_mob()
|
||||
@@ -81,6 +82,7 @@ var/global/datum/controller/process/mob_hunt/mob_hunt_server
|
||||
return 0
|
||||
var/obj/effect/nanomob/new_mob = new /obj/effect/nanomob(mob_info.spawn_point, mob_info)
|
||||
normal_spawns += new_mob
|
||||
new_mob.reveal()
|
||||
return 1
|
||||
|
||||
/datum/controller/process/mob_hunt/proc/register_trap(datum/mob_hunt/mob_info)
|
||||
@@ -90,5 +92,8 @@ var/global/datum/controller/process/mob_hunt/mob_hunt_server
|
||||
return register_spawn(mob_info)
|
||||
var/obj/effect/nanomob/new_mob = new /obj/effect/nanomob(mob_info.spawn_point, mob_info)
|
||||
trap_spawns += new_mob
|
||||
check_stability()
|
||||
new_mob.reveal()
|
||||
if(trap_spawns.len > max_trap_spawns)
|
||||
var/obj/effect/nanomob/old_trap = trap_spawns[1]
|
||||
old_trap.despawn()
|
||||
return 1
|
||||
@@ -2,14 +2,15 @@
|
||||
/obj/effect/nanomob
|
||||
name = "Nano-Mob Avatar" //will be overridden by the mob datum name value when created
|
||||
desc = "A wild Nano-Mob appeared! Hit it with your PDA with the game open to attempt to capture it!"
|
||||
invisibility = 101 //normally invisible, this gets adjusted through the game's scanning
|
||||
invisibility = 101
|
||||
alpha = 128
|
||||
anchored = 1 //just in case
|
||||
density = 0
|
||||
icon = 'icons/effects/mob_hunt.dmi'
|
||||
//icon_state gets set in New() because it is determined by the mob_hunt datum being used
|
||||
var/state_name
|
||||
var/datum/mob_hunt/mob_info = null
|
||||
var/list/clients_encountered = list() //tracks who has already interacted with us, so they can't attempt a second capture
|
||||
var/image/avatar
|
||||
|
||||
/obj/effect/nanomob/New(loc, datum/mob_hunt/new_info)
|
||||
..()
|
||||
@@ -28,21 +29,20 @@
|
||||
name = mob_info.mob_name
|
||||
desc = "A wild [name] (level [mob_info.level]) appeared! Hit it with your PDA with the game open to attempt to capture it!"
|
||||
if(mob_info.is_shiny)
|
||||
icon_state = mob_info.icon_state_shiny
|
||||
state_name = mob_info.icon_state_shiny
|
||||
else
|
||||
icon_state = mob_info.icon_state_normal
|
||||
state_name = mob_info.icon_state_normal
|
||||
avatar = image(icon, src, state_name)
|
||||
avatar.override = 1
|
||||
add_alt_appearance("nanomob_avatar", avatar)
|
||||
|
||||
/obj/effect/nanomob/attackby(obj/item/O, mob/user)
|
||||
if(invisibility) //no catching mobs you can't normally see!
|
||||
return
|
||||
if(istype(O, /obj/item/device/pda))
|
||||
var/obj/item/device/pda/P = O
|
||||
attempt_capture(P, -20) //attempting a melee capture reduces the mob's effective run_chance by 20% to balance the risk of triggering a trap mob
|
||||
return 1
|
||||
|
||||
/obj/effect/nanomob/hitby(obj/item/O)
|
||||
if(invisibility) //no catching mobs you can't normally see!
|
||||
return
|
||||
if(istype(O, /obj/item/device/pda))
|
||||
var/obj/item/device/pda/P = O
|
||||
attempt_capture(P) //attempting a ranged capture does not affect the mob's effective run_chance but does prevent you from being shocked by a trap mob
|
||||
@@ -63,7 +63,7 @@
|
||||
return
|
||||
if(istype(P.loc, /mob/living/carbon))
|
||||
var/mob/living/carbon/C = P.loc
|
||||
//Strike them down with a lightning bolt to complete the illusion (copied from the surge reagent overdose, probably could
|
||||
//Strike them down with a lightning bolt to complete the illusion (copied from the surge reagent overdose, probably could make this a general-use proc in the future)
|
||||
playsound(get_turf(C), 'sound/effects/eleczap.ogg', 75, 1)
|
||||
var/icon/I=new('icons/obj/zap.dmi',"lightningend")
|
||||
I.Turn(-135)
|
||||
@@ -75,36 +75,50 @@
|
||||
C.electrocute_act(20, P, 1) //same damage as a revenant's overload ability, except subject to gloves/species shock resistance (for human mobs at least)
|
||||
return
|
||||
|
||||
var/obj/item/weapon/cartridge/cartridge = P.cartridge
|
||||
var/cart_ref = "\ref[cartridge]"
|
||||
if(cart_ref in clients_encountered) //we've already dealt with you, go away!
|
||||
if(client in clients_encountered) //we've already dealt with you, go away!
|
||||
return
|
||||
else //deal with the new hunter by either running away or getting caught
|
||||
clients_encountered += cart_ref
|
||||
clients_encountered += client
|
||||
var/message = "[bicon(P)] "
|
||||
var/effective_run_chance = mob_info.run_chance + total_catch_mod
|
||||
if((effective_run_chance > 0) && prob(effective_run_chance))
|
||||
message += "Capture failed! [name] escaped [P.owner ? "from [P.owner]" : "from this hunter"]!"
|
||||
conceal(client)
|
||||
else
|
||||
if(client.register_capture(mob_info, 1))
|
||||
message += "Capture success! [P.owner ? P.owner : "This hunter"] captured [name]!"
|
||||
conceal(client)
|
||||
else
|
||||
message += "Capture error! Try again."
|
||||
clients_encountered -= cart_ref //if the capture registration failed somehow, let them have another chance with this mob
|
||||
clients_encountered -= client //if the capture registration failed somehow, let them have another chance with this mob
|
||||
P.audible_message(message, null, 4)
|
||||
|
||||
/obj/effect/nanomob/proc/despawn()
|
||||
if(mob_hunt_server)
|
||||
if(mob_info.is_trap)
|
||||
mob_hunt_server.trap_spawns -= src
|
||||
mob_hunt_server.check_stability()
|
||||
else
|
||||
mob_hunt_server.normal_spawns -= src
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/nanomob/proc/reveal()
|
||||
if(invisibility == 101)
|
||||
invisibility = 0
|
||||
spawn(30)
|
||||
if(src)
|
||||
invisibility = 101
|
||||
if(!mob_hunt_server)
|
||||
return
|
||||
var/list/show_to = list()
|
||||
for(var/A in mob_hunt_server.connected_clients)
|
||||
if((A in clients_encountered) || !mob_hunt_server.connected_clients[A])
|
||||
continue
|
||||
show_to |= mob_hunt_server.connected_clients[A]
|
||||
display_alt_appearance("nanomob_avatar", show_to)
|
||||
|
||||
/obj/effect/nanomob/proc/conceal(list/hide_from)
|
||||
if(!mob_hunt_server)
|
||||
return
|
||||
var/list/hiding_from = list()
|
||||
if(hide_from)
|
||||
hiding_from = hide_from
|
||||
else
|
||||
for(var/A in mob_hunt_server.connected_clients)
|
||||
if((A in clients_encountered) && mob_hunt_server.connected_clients[A])
|
||||
hiding_from |= mob_hunt_server.connected_clients[A]
|
||||
hide_alt_appearance("nanomob_avatar", hiding_from)
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
var/base_health = 5 //base health of the mob for battling (effectively max health at level 0)
|
||||
var/attack_multiplier = 1 //how much additional damage per level the mob deals (level * attack_multiplier)
|
||||
var/health_multiplier = 1 //how much additional health per level the mob gets (level * health_multiplier) for calculating max health
|
||||
var/health = list(0, 0) //health[1] is the mob's current health, health[2] is the mob's max health (calculated in New())
|
||||
var/health = list("current" = 0, "max" = 0)
|
||||
|
||||
//SPAWN PREFERENCES AND VARIABLES
|
||||
//A note on mob spawn preferences: The mob types also have preferences, which are handled prior to per-mob preferences, so ultimately you use a combined set of preferences
|
||||
@@ -61,7 +61,7 @@
|
||||
level = rand(min_level, max_level)
|
||||
if(prob(1) && prob(1))
|
||||
is_shiny = 1
|
||||
health[2] = base_health + (level * health_multiplier)
|
||||
health["max"] = base_health + (level * health_multiplier)
|
||||
if(primary_type)
|
||||
primary_type = new primary_type()
|
||||
if(secondary_type)
|
||||
@@ -152,28 +152,27 @@
|
||||
var/list/possible_turfs = list()
|
||||
//setup, sets all turfs in spawn_area to weight 1
|
||||
for(var/turf/T in spawn_area)
|
||||
if(T.z > 1) //mobs will only consider station-level turfs for spawning. Largely here so we won't have to worry about mapping errors or mobs on the derelict solars
|
||||
if(!is_station_level(T.z)) //mobs will only consider station-level turfs for spawning. Largely here so we won't have to worry about mapping errors or mobs on the derelict solars
|
||||
continue
|
||||
possible_turfs[T] = 1
|
||||
//primary type preferences
|
||||
if(primary_type)
|
||||
for(var/turf/T in primary_type.turf_whitelist)
|
||||
//primary type preferences
|
||||
if(primary_type)
|
||||
if(is_type_in_list(T, primary_type.turf_whitelist))
|
||||
possible_turfs[T] += 4
|
||||
if(is_type_in_list(T, primary_type.turf_blacklist))
|
||||
possible_turfs[T] -= 2
|
||||
//secondary type preferences
|
||||
if(secondary_type)
|
||||
if(is_type_in_list(T, secondary_type.turf_whitelist))
|
||||
possible_turfs[T] += 4
|
||||
if(is_type_in_list(T, secondary_type.turf_blacklist))
|
||||
possible_turfs[T] -= 2
|
||||
//mob preferences
|
||||
if(is_type_in_list(T, turf_whitelist))
|
||||
possible_turfs[T] += 4
|
||||
for(var/turf/T in primary_type.turf_blacklist)
|
||||
if(is_type_in_list(T, turf_blacklist))
|
||||
possible_turfs[T] -= 2
|
||||
//secondary type preferences
|
||||
if(secondary_type)
|
||||
for(var/turf/T in secondary_type.turf_whitelist)
|
||||
possible_turfs[T] += 4
|
||||
for(var/turf/T in secondary_type.turf_blacklist)
|
||||
possible_turfs[T] -= 2
|
||||
//mob preferences
|
||||
for(var/turf/T in turf_whitelist)
|
||||
possible_turfs[T] += 4
|
||||
for(var/turf/T in turf_blacklist)
|
||||
possible_turfs[T] -= 2
|
||||
//weight check, remove negative or zero weight turfs from the list, then return the list
|
||||
for(var/T in possible_turfs)
|
||||
//weight check, remove negative or zero weight turfs from the list, then return the list
|
||||
if(possible_turfs[T] < 1)
|
||||
possible_turfs -= T
|
||||
return possible_turfs
|
||||
@@ -210,9 +209,9 @@
|
||||
var/message = ""
|
||||
var/multiplier = calc_dam_multiplier(attack_type)
|
||||
var/total_damage = raw_damage * multiplier
|
||||
if(!health[1]) //it's already downed, quit hitting it
|
||||
if(!health["current"]) //it's already downed, quit hitting it
|
||||
return null
|
||||
health[1] = max(health[1] - total_damage, 0)
|
||||
health["current"] = max(health["current"] - total_damage, 0)
|
||||
switch(multiplier)
|
||||
if(0)
|
||||
message += "The attack is completely ineffective! "
|
||||
@@ -224,7 +223,7 @@
|
||||
message += "It's super effective! "
|
||||
if(4)
|
||||
message += "It's ultra effective! "
|
||||
if(!health[1])
|
||||
if(!health["current"])
|
||||
message += "[nickname ? nickname : mob_name] is downed!"
|
||||
return message
|
||||
|
||||
@@ -236,7 +235,7 @@
|
||||
message += "[nickname ? nickname : mob_name] can't get any stronger right now!"
|
||||
else
|
||||
|
||||
health[2] = base_health + (level * health_multiplier)
|
||||
health["max"] = base_health + (level * health_multiplier)
|
||||
message += "[nickname ? nickname : mob_name] has reached level [level]!"
|
||||
|
||||
/datum/mob_hunt/proc/get_type1()
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
var/hacked = 0 //if set, this cartridge is able to spawn trap mobs from its collection (set via emag_act on the cartridge)
|
||||
var/catch_mod = 0 //used to adjust the likelihood of a mob running from this client, a negative value means it is less likely to run (support for temporary bonuses)
|
||||
var/wild_captures = 0 //used to track the total number of mobs captured from the wild (does not count card mobs) by this client
|
||||
var/scan_range = 3 //maximum distance (in tiles) from which the client can reveal nearby mobs
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/start()
|
||||
..()
|
||||
@@ -24,18 +25,20 @@
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/stop()
|
||||
..()
|
||||
disconnect("Program Terminated")
|
||||
processing_objects.Remove(pda)
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/proc/scan_nearby()
|
||||
if(!mob_hunt_server || !connected)
|
||||
return
|
||||
for(var/turf/T in range(3, get_turf(pda)))
|
||||
for(var/obj/O in T.contents)
|
||||
if(!istype(O, /obj/effect/nanomob))
|
||||
continue
|
||||
var/obj/effect/nanomob/N = O
|
||||
//reveal the mob
|
||||
N.reveal()
|
||||
for(var/turf/T in range(scan_range, get_turf(pda)))
|
||||
for(var/obj/effect/nanomob/N in T.contents)
|
||||
if(src in N.clients_encountered)
|
||||
//hide the mob
|
||||
N.conceal()
|
||||
else
|
||||
//reveal the mob
|
||||
N.reveal()
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/proc/reconnect()
|
||||
if(!mob_hunt_server || !mob_hunt_server.server_status || connected)
|
||||
@@ -47,10 +50,20 @@
|
||||
pda.audible_message("[bicon(pda)] Connection established. Capture all of the mobs, [pda.owner ? pda.owner : "hunter"]!", null, 2)
|
||||
return 1
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/proc/get_player()
|
||||
if(!pda)
|
||||
return null
|
||||
if(ishuman(pda.loc))
|
||||
var/mob/living/carbon/human/H = pda.loc
|
||||
return H
|
||||
return null
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/proc/disconnect(reason = null)
|
||||
if(!mob_hunt_server || !connected)
|
||||
return
|
||||
mob_hunt_server.connected_clients -= src
|
||||
for(var/obj/effect/nanomob/N in (mob_hunt_server.normal_spawns + mob_hunt_server.trap_spawns))
|
||||
N.conceal(list(get_player()))
|
||||
connected = 0
|
||||
//show a disconnect message if we were disconnected involuntarily (reason argument provided)
|
||||
if(pda && reason)
|
||||
@@ -105,8 +118,6 @@
|
||||
if(mob_info.is_shiny)
|
||||
entry["sprite"] = "[mob_info.icon_state_shiny].png"
|
||||
data["entry"] = entry
|
||||
for(var/a in entry)
|
||||
log_debug("[a] = [entry[a]]")
|
||||
|
||||
/datum/data/pda/app/mob_hunter_game/proc/assign_nickname()
|
||||
if(!my_collection.len)
|
||||
|
||||
Reference in New Issue
Block a user