diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm
index 3aa638aa40f..a7678e1d261 100644
--- a/code/controllers/verbs.dm
+++ b/code/controllers/verbs.dm
@@ -18,7 +18,7 @@
return
-/client/proc/debug_controller(controller in list("Master","failsafe","Ticker","Air","Lighting","Jobs","Sun","Radio","Configuration","pAI", "Cameras","Garbage", "Transfer Controller","Event","Alarm","Scheduler","Nano","Vote"))
+/client/proc/debug_controller(controller in list("Master","failsafe","Ticker","Air","Lighting","Jobs","Sun","Radio","Configuration","pAI", "Cameras","Garbage", "Transfer Controller","Event","Alarm","Scheduler","Nano","Vote","Mob Hunt Server"))
set category = "Debug"
set name = "Debug Controller"
set desc = "Debug the various periodic loop controllers for the game (be careful!)"
@@ -76,6 +76,9 @@
if("Vote")
debug_variables(vote)
feedback_add_details("admin_verb","DVote")
+ if("Mob Hunt Server")
+ debug_variables(mob_hunt_server)
+ feedback_add_details("admin_verb","DMobHuntServer")
message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.")
return
diff --git a/code/modules/arcade/mob_hunt/game_server.dm b/code/modules/arcade/mob_hunt/game_server.dm
index 1f801250835..cbcaa400925 100644
--- a/code/modules/arcade/mob_hunt/game_server.dm
+++ b/code/modules/arcade/mob_hunt/game_server.dm
@@ -1,12 +1,6 @@
+var/global/datum/controller/process/mob_hunt/mob_hunt_server
-var/global/obj/machinery/mob_hunt_server/mob_hunt_server = null
-
-/obj/machinery/mob_hunt_server
- name = "Nano-Mob Hunter GO Server "
- desc = "A game server for the new hit PDA game \"Nano-Mob Hunter GO\". May be unstable."
- icon_state = "processor"
- density = 1
- anchored = 1
+/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/list/trap_spawns = list()
@@ -14,24 +8,19 @@ var/global/obj/machinery/mob_hunt_server/mob_hunt_server = null
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
-/obj/machinery/mob_hunt_server/New()
- ..()
- if(!mob_hunt_server)
- mob_hunt_server = src
- else
- log_admin("A Nano-Mob Hunter GO server was created at ([x], [y]) on z[z] while one already exists. Deleting the new server.")
- //there can only be one!
- qdel(src)
+/datum/controller/process/mob_hunt/setup()
+ name = "Nano-Mob Hunter GO Server"
+ start_delay = 20
+ mob_hunt_server = src
-/obj/machinery/mob_hunt_server/Destroy()
+/datum/controller/process/mob_hunt/Destroy()
for(var/datum/data/pda/app/mob_hunter_game/client in connected_clients)
client.disconnect("Server Destruction")
if(mob_hunt_server && mob_hunt_server == src)
mob_hunt_server = null
return ..()
-/obj/machinery/mob_hunt_server/process()
- ..()
+/datum/controller/process/mob_hunt/doWork()
if(server_status == 0)
return
if(normal_spawns.len < max_normal_spawns)
@@ -48,10 +37,10 @@ var/global/obj/machinery/mob_hunt_server/mob_hunt_server = null
var/datum/data/pda/app/mob_hunter_game/client = pick(connected_clients)
client.disconnect("Server Communication Error")
-/obj/machinery/mob_hunt_server/proc/check_stability()
+/datum/controller/process/mob_hunt/proc/check_stability()
server_instability = connected_clients.len + (trap_spawns.len * 5)
-/obj/machinery/mob_hunt_server/proc/server_crash()
+/datum/controller/process/mob_hunt/proc/server_crash()
server_status = 0
for(var/datum/data/pda/app/mob_hunter_game/client in connected_clients)
client.disconnect("Server Crash")
@@ -66,7 +55,7 @@ var/global/obj/machinery/mob_hunt_server/mob_hunt_server = null
//set a timer to automatically recover in 5 minutes (can be manually restarted if you get impatient too)
addtimer(src, "auto_recover", 3000, TRUE)
-/obj/machinery/mob_hunt_server/proc/auto_recover()
+/datum/controller/process/mob_hunt/proc/auto_recover()
if(server_status != 0)
return
server_instability = 0
@@ -74,7 +63,7 @@ var/global/obj/machinery/mob_hunt_server/mob_hunt_server = null
while(normal_spawns.len < max_normal_spawns) //repopulate the server's spawns completely if we auto-recover from crash
spawn_mob()
-/obj/machinery/mob_hunt_server/proc/manual_reboot()
+/datum/controller/process/mob_hunt/proc/manual_reboot()
for(var/obj/effect/nanomob/N in trap_spawns)
N.despawn()
for(var/obj/effect/nanomob/N in normal_spawns)
@@ -82,19 +71,19 @@ var/global/obj/machinery/mob_hunt_server/mob_hunt_server = null
check_stability()
server_status = 1
-/obj/machinery/mob_hunt_server/proc/spawn_mob()
+/datum/controller/process/mob_hunt/proc/spawn_mob()
var/list/nanomob_types = subtypesof(/datum/mob_hunt)
var/datum/mob_hunt/mob_info = pick(nanomob_types)
new mob_info()
-/obj/machinery/mob_hunt_server/proc/register_spawn(datum/mob_hunt/mob_info)
+/datum/controller/process/mob_hunt/proc/register_spawn(datum/mob_hunt/mob_info)
if(!mob_info)
return 0
var/obj/effect/nanomob/new_mob = new /obj/effect/nanomob(mob_info.spawn_point, mob_info)
normal_spawns += new_mob
return 1
-/obj/machinery/mob_hunt_server/proc/register_trap(datum/mob_hunt/mob_info)
+/datum/controller/process/mob_hunt/proc/register_trap(datum/mob_hunt/mob_info)
if(!mob_info)
return 0
if(!mob_info.is_trap)
diff --git a/code/modules/arcade/mob_hunt/mob_avatar.dm b/code/modules/arcade/mob_hunt/mob_avatar.dm
index 3d5ad935d58..085d2a7f6bc 100644
--- a/code/modules/arcade/mob_hunt/mob_avatar.dm
+++ b/code/modules/arcade/mob_hunt/mob_avatar.dm
@@ -37,27 +37,25 @@
return
if(istype(O, /obj/item/device/pda))
var/obj/item/device/pda/P = O
- if(P.current_app && istype(P.current_app, /datum/data/pda/app/mob_hunter_game))
- attempt_capture(P)
- return 1
+ 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
- if(P.current_app && istype(P.current_app, /datum/data/pda/app/mob_hunter_game))
- attempt_capture(P)
- return 1
+ 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
+ return 1
-/obj/effect/nanomob/proc/attempt_capture(obj/item/device/pda/P)
+/obj/effect/nanomob/proc/attempt_capture(obj/item/device/pda/P, catch_mod = 0) //negative catch_mods lower effective run chance,
if(!P || !P.current_app || !istype(P.current_app, /datum/data/pda/app/mob_hunter_game) || !P.cartridge)
return
var/datum/data/pda/app/mob_hunter_game/client = P.current_app
+ var/total_catch_mod = client.catch_mod + catch_mod //negative values decrease the chance of the mob running, positive values makes it more likely to flee
if(!client.connected) //must be connected to attempt captures
- for(var/mob/O in hearers(4, P.loc))
- O.show_message("[bicon(P)] No server connection. Capture aborted.")
+ P.audible_message("[bicon(P)] No server connection. Capture aborted.", null, 4)
return
if(mob_info.is_trap) //traps work even if you ran into them before, which is why this is before the clients_encountered check
@@ -84,16 +82,16 @@
else //deal with the new hunter by either running away or getting caught
clients_encountered += cart_ref
var/message = "[bicon(P)] "
- if(mob_info.run_chance && prob(mob_info.run_chance))
+ 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"]!"
else
- if(client.register_capture(mob_info))
+ if(client.register_capture(mob_info, 1))
message += "Capture success! [P.owner ? P.owner : "This hunter"] captured [name]!"
else
message += "Capture error! Try again."
clients_encountered -= cart_ref //if the capture registration failed somehow, let them have another chance with this mob
- for(var/mob/O in hearers(4, P.loc))
- O.show_message(message)
+ P.audible_message(message, null, 4)
/obj/effect/nanomob/proc/despawn()
if(mob_hunt_server)
@@ -107,8 +105,6 @@
/obj/effect/nanomob/proc/reveal()
if(invisibility == 101)
invisibility = 0
- //density = 1
spawn(30)
if(src)
invisibility = 101
- //density = 1
diff --git a/code/modules/arcade/mob_hunt/mob_datums.dm b/code/modules/arcade/mob_hunt/mob_datums.dm
index 07987594b44..20dd869bf28 100644
--- a/code/modules/arcade/mob_hunt/mob_datums.dm
+++ b/code/modules/arcade/mob_hunt/mob_datums.dm
@@ -62,6 +62,10 @@
if(prob(1) && prob(1))
is_shiny = 1
health[2] = base_health + (level * health_multiplier)
+ if(primary_type)
+ primary_type = new primary_type()
+ if(secondary_type)
+ secondary_type = new secondary_type()
if(no_register) //for booster pack cards
return
if(mob_hunt_server)
@@ -101,7 +105,9 @@
var/list/possible_areas = list()
//setup, sets all station areas (and subtypes) to weight 1
for(var/A in the_station_areas)
- if(istype(A, /area/holodeck)) //don't allow holodeck areas as possible spawns since it will allow it to spawn in the holodeck rooms on z2 as well
+ if(A == /area/holodeck) //don't allow holodeck areas as possible spawns since it will allow it to spawn in the holodeck rooms on z2 as well
+ continue
+ if(A in possible_areas)
continue
for(var/areapath in typesof(A))
possible_areas[areapath] = 1
@@ -128,10 +134,16 @@
for(var/A in area_blacklist)
for(var/areapath in typesof(A))
possible_areas[areapath] -= 2
- //weight check, remove negative or zero weight areas from the list, then return the list
+ //removes "bad areas" which shouldn't be on-station but are subtypes of station areas. probably should the unused ones and consider repathing the rest
+ var/list/bad_areas = list(subtypesof(/area/construction), /area/solar/derelict_starboard, /area/solar/derelict_aft, /area/solar/constructionsite)
+ for(var/A in bad_areas)
+ possible_areas -= A
+ //weight check, remove negative or zero weight areas from the list, then return the list.
for(var/areapath in possible_areas)
+ //remove any areas that shouldn't be on the station-level
if(possible_areas[areapath] < 1)
possible_areas -= areapath
+ continue
return possible_areas
/datum/mob_hunt/proc/get_possible_turfs(area/spawn_area)
@@ -140,6 +152,8 @@
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
+ continue
possible_turfs[T] = 1
//primary type preferences
if(primary_type)
@@ -229,13 +243,13 @@
if(!primary_type)
return "Typeless"
else
- return initial(primary_type.name)
+ return primary_type.name
/datum/mob_hunt/proc/get_type2()
if(!secondary_type)
return null
else
- return initial(secondary_type.name)
+ return secondary_type.name
/datum/mob_hunt/nemabug
diff --git a/code/modules/pda/mob_hunt_game_app.dm b/code/modules/pda/mob_hunt_game_app.dm
index 2d034ba13de..512f320a32b 100644
--- a/code/modules/pda/mob_hunt_game_app.dm
+++ b/code/modules/pda/mob_hunt_game_app.dm
@@ -15,6 +15,8 @@
var/current_index = 0
var/connected = 0
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
/datum/data/pda/app/mob_hunter_game/start()
..()
@@ -42,8 +44,7 @@
mob_hunt_server.connected_clients += src
connected = 1
if(pda)
- for(var/mob/O in hearers(2, pda.loc))
- O.show_message("[bicon(pda)] Connection established. Capture all of the mobs, [pda.owner ? pda.owner : "hunter"]!")
+ 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/disconnect(reason = null)
@@ -53,18 +54,25 @@
connected = 0
//show a disconnect message if we were disconnected involuntarily (reason argument provided)
if(pda && reason)
- for(var/mob/O in hearers(2, pda.loc))
- O.show_message("[bicon(pda)] Disconnected from server. Reason: [reason].")
+ pda.audible_message("[bicon(pda)] Disconnected from server. Reason: [reason].", null, 2)
/datum/data/pda/app/mob_hunter_game/program_process()
if(!mob_hunt_server || !connected)
return
scan_nearby()
-/datum/data/pda/app/mob_hunter_game/proc/register_capture(datum/mob_hunt/captured)
+/datum/data/pda/app/mob_hunter_game/program_hit_check()
+ if(!pda)
+ return
+ for(var/obj/effect/nanomob/hit_mob in get_turf(pda))
+ hit_mob.hitby(pda)
+
+/datum/data/pda/app/mob_hunter_game/proc/register_capture(datum/mob_hunt/captured, wild = 0)
if(!captured)
return 0
my_collection.Add(captured)
+ if(wild)
+ wild_captures++
return 1
/datum/data/pda/app/mob_hunter_game/update_ui(mob/user as mob, list/data)
@@ -72,6 +80,7 @@
data["connected"] = 0
else
data["connected"] = 1
+ data["wild_captures"] = wild_captures
data["no_collection"] = 0
if(!my_collection.len)
data["no_collection"] = 1
diff --git a/nano/templates/pda_mob_hunt.tmpl b/nano/templates/pda_mob_hunt.tmpl
index 7bdb87bf9e0..dde4ab82a5c 100644
--- a/nano/templates/pda_mob_hunt.tmpl
+++ b/nano/templates/pda_mob_hunt.tmpl
@@ -32,6 +32,8 @@
Your collection is empty! Go capture some Nano-Mobs!
+
+ Wild mobs captured: {{:data.wild_captures}}
{{else}}