Hivebot scaling and minor refactor (#18984)

Hivebot beacons scale with the currently playing player count, if they
spawn on the main map (the Horizon, most likely).
Refactored the hivebot code slightly, mostly in terms of DMDoc and
reordering.
This commit is contained in:
Fluffy
2024-05-01 22:35:32 +00:00
committed by GitHub
parent 27e616c673
commit 4e532ee760
3 changed files with 252 additions and 96 deletions
@@ -40,9 +40,30 @@
)
speak_chance = 5
attack_emote = "focuses on"
var/mob/living/simple_animal/hostile/hivebotbeacon/linked_parent = null
psi_pingable = FALSE
/**
* The hivebot beacon that we are liked to (and likely generated us)
*/
var/mob/living/simple_animal/hostile/hivebotbeacon/linked_parent = null
/mob/living/simple_animal/hostile/hivebot/Initialize(mapload,mob/living/simple_animal/hostile/hivebot/hivebotbeacon)
. = ..()
if(hivebotbeacon)
linked_parent = hivebotbeacon
if(!mapload)
new /obj/effect/effect/smoke(src.loc,30)
playsound(src.loc, 'sound/effects/EMPulse.ogg', 25, 1)
/mob/living/simple_animal/hostile/hivebot/Destroy()
if(linked_parent)
linked_parent.linked_bots -= src
linked_parent = null
. = ..()
/mob/living/simple_animal/hostile/hivebot/get_bullet_impact_effect_type(var/def_zone)
return BULLET_IMPACT_METAL
@@ -60,6 +81,55 @@
else
return "blood_overlay_armed"
/mob/living/simple_animal/hostile/hivebot/bullet_act(var/obj/item/projectile/Proj)
if(istype(Proj, /obj/item/projectile/bullet/pistol/hivebotspike) || istype(Proj, /obj/item/projectile/beam/hivebot))
Proj.no_attack_log = 1
return PROJECTILE_CONTINUE
else
return ..(Proj)
/mob/living/simple_animal/hostile/hivebot/death()
..(null,"blows apart!")
var/T = get_turf(src)
new /obj/effect/gibspawner/robot(T)
spark(T, 1, GLOB.alldirs)
qdel(src)
/mob/living/simple_animal/hostile/hivebot/think()
. =..()
if(stance == HOSTILE_STANCE_IDLE)
icon_state = "[initial(icon_state)]"
else
icon_state = "[initial(icon_state)]_armed"
/mob/living/simple_animal/hostile/hivebot/Allow_Spacemove(var/check_drift = 0)
return TRUE
/mob/living/simple_animal/hostile/hivebot/AirflowCanMove(n)
return FALSE
/mob/living/simple_animal/hostile/hivebot/emp_act(severity)
. = ..()
LoseTarget()
change_stance(HOSTILE_STANCE_TIRED)
addtimer(CALLBACK(src, PROC_REF(wakeup)), 50)
visible_message(SPAN_DANGER("[src] suffers a teleportation malfunction!"))
playsound(src.loc, 'sound/effects/teleport.ogg', 25, 1)
var/turf/random_turf = get_turf(pick(orange(src,7)))
do_teleport(src, random_turf)
/mob/living/simple_animal/hostile/hivebot/proc/wakeup()
change_stance(HOSTILE_STANCE_IDLE)
/*############
SUBTYPES
############*/
/**
* # Hivebot Guardian
*/
/mob/living/simple_animal/hostile/hivebot/guardian
health = 80
maxHealth = 45
@@ -72,22 +142,24 @@
mob_swap_flags = ~HEAVY
mob_push_flags = 0
/mob/living/simple_animal/hostile/hivebot/guardian/Initialize(mapload,mob/living/simple_animal/hostile/hivebot/hivebotbeacon)
.=..()
if(hivebotbeacon && linked_parent)
linked_parent.guard_amt++
/mob/living/simple_animal/hostile/hivebot/guardian/think()
. =..()
if(stance != HOSTILE_STANCE_IDLE)
wander = 1
/mob/living/simple_animal/hostile/hivebot/guardian/Destroy()
.=..()
if(linked_parent)
linked_parent.guard_amt--
/mob/living/simple_animal/hostile/hivebot/guardian/think()
. =..()
if(stance != HOSTILE_STANCE_IDLE)
wander = 1
/**
* # Hivebot Bomber
*/
/mob/living/simple_animal/hostile/hivebot/bomber
desc = "A primitive in design, hovering robot, with some menacing looking blades jutting out from it. It bears no manufacturer markings of any kind. This one appears round in design and moves slower than its brethren."
health = 100
@@ -121,6 +193,9 @@
fragem(src,10,30,2,3,5,1,FALSE)
src.gib()
/**
* # Hivebot Ranged
*/
/mob/living/simple_animal/hostile/hivebot/range
name = "Hivebot"
desc = "A primitive in design, hovering robot, with a simple looking launcher sticking out of it. It bears no manufacturer markings of any kind."
@@ -130,58 +205,3 @@
/mob/living/simple_animal/hostile/hivebot/range/rapid
projectiletype = /obj/item/projectile/bullet/pistol/hivebotspike/needle
rapid = 1
//Creates a reference to its parent beacon on init.
/mob/living/simple_animal/hostile/hivebot/Initialize(mapload,mob/living/simple_animal/hostile/hivebot/hivebotbeacon)
if(hivebotbeacon)
linked_parent = hivebotbeacon
.=..()
if(!mapload)
new /obj/effect/effect/smoke(src.loc,30)
playsound(src.loc, 'sound/effects/EMPulse.ogg', 25, 1)
/mob/living/simple_animal/hostile/hivebot/bullet_act(var/obj/item/projectile/Proj)
if(istype(Proj, /obj/item/projectile/bullet/pistol/hivebotspike) || istype(Proj, /obj/item/projectile/beam/hivebot))
Proj.no_attack_log = 1
return PROJECTILE_CONTINUE
else
return ..(Proj)
/mob/living/simple_animal/hostile/hivebot/death()
..(null,"blows apart!")
var/T = get_turf(src)
new /obj/effect/gibspawner/robot(T)
spark(T, 1, GLOB.alldirs)
qdel(src)
/mob/living/simple_animal/hostile/hivebot/Destroy()
. = ..()
if(linked_parent)
linked_parent.linked_bots -= src
/mob/living/simple_animal/hostile/hivebot/think()
. =..()
if(stance == HOSTILE_STANCE_IDLE)
icon_state = "[initial(icon_state)]"
else
icon_state = "[initial(icon_state)]_armed"
/mob/living/simple_animal/hostile/hivebot/Allow_Spacemove(var/check_drift = 0)
return 1
/mob/living/simple_animal/hostile/hivebot/AirflowCanMove(n)
return 0
/mob/living/simple_animal/hostile/hivebot/emp_act(severity)
. = ..()
LoseTarget()
change_stance(HOSTILE_STANCE_TIRED)
addtimer(CALLBACK(src, PROC_REF(wakeup)), 50)
visible_message(SPAN_DANGER("[src] suffers a teleportation malfunction!"))
playsound(src.loc, 'sound/effects/teleport.ogg', 25, 1)
var/turf/random_turf = get_turf(pick(orange(src,7)))
do_teleport(src, random_turf)
/mob/living/simple_animal/hostile/hivebot/proc/wakeup()
change_stance(HOSTILE_STANCE_IDLE)
@@ -34,28 +34,84 @@
minbodytemp = 0
speed = -10
destroy_surroundings = 0
var/bot_type
var/bot_amt = 160 //Number of total bots that are spawned before the beacon disappears completely.
var/max_bots = 40 //Number of bots linked to this beacon specifically that can exist, before spawning more is halted.
var/list/linked_bots = list()
var/guard_amt = 0
var/harvester_amt = 0
var/spawn_delay
var/activated = 0
var/max_bots_reached
var/list/destinations = list()
var/list/close_destinations = list()
var/area/latest_area
attack_emote = "focuses on"
psi_pingable = FALSE
/mob/living/simple_animal/hostile/hivebotbeacon/incendiary
projectiletype = /obj/item/projectile/beam/hivebot/incendiary
projectilesound = 'sound/weapons/plasma_cutter.ogg'
rapid = 0
/**
* Number of total bots that are spawned before the beacon disappears completely
*
* This gets updated in /Initialize() with a formula based on the
* `total_hivebots_to_spawn_to_playing_players_scaling_factor` variable
*/
var/total_hivebots_to_spawn = 160
/**
* The scaling factor for the number of total hivebots to spawn respective to playing players
*
* Eg: scaling factor of 1 would mean that the beacon would spawn 1 additional hivebot per player
*/
var/total_hivebots_to_spawn_to_playing_players_scaling_factor = 1
/**
* Number of bots linked to this beacon specifically that can exist, before spawning more is halted
*
* This gets updated in /Initialize() with a formula based on the
* `maximum_linked_and_alive_hivebots_to_playing_players_scaling_factor` variable
*/
var/maximum_linked_and_alive_hivebots = 40
/**
* The scaling factor for the maximum number of linked and alive hivebots respective to playing players
*
* Eg: scaling factor of 1 would mean that the beacon would have one additional linked and alive hivebot per player
*/
var/maximum_linked_and_alive_hivebots_to_playing_players_scaling_factor = 1
///A list of `/mob/living/simple_animal/hostile` hivebots that are linked to this beacon
var/list/mob/living/simple_animal/hostile/hivebot/linked_bots = list()
///Amount of hivebots spawned and alive linked to this beacon, guardian type
var/guard_amt = 0
///Amount of hivebots spawned and alive linked to this beacon, harvester type
var/harvester_amt = 0
///Calculated delay between spawning new bots, internal use only
VAR_PRIVATE/spawn_delay
/**
* The scaling factor for the subtraction from the calculated `spawn_delay` based on player count
*
* Eg: scaling factor of 1 would mean that each player reduces the `spawn_delay` by 1 decisecond
*
* This only works up to a minumum of 80 deciseconds
*/
var/spawn_delay_to_playing_players_scaling_factor = 1.8
/**
* The activation state of the beacon
*
* FALSE (0) -> beacon is off
* TRUE (1) -> beacon is on
* -1 -> beacon is disabled and should not be activated (usually for mapping purposes)
*/
var/activated = 0
///Boolean, if the maximum number of bots has been reached, internal use only
VAR_PRIVATE/maximum_linked_and_alive_hivebots_reached
var/list/destinations = list()
var/list/close_destinations = list()
var/area/latest_area
/mob/living/simple_animal/hostile/hivebotbeacon/Initialize(mapload)
.=..()
. = ..()
//Calculate the actual values based on player population, but only if it's on the main map (most likely the Horizon)
if(isStationLevel(src.z))
total_hivebots_to_spawn = total_hivebots_to_spawn + (length(GLOB.player_list) * total_hivebots_to_spawn_to_playing_players_scaling_factor)
maximum_linked_and_alive_hivebots = maximum_linked_and_alive_hivebots + (length(GLOB.player_list) * maximum_linked_and_alive_hivebots_to_playing_players_scaling_factor)
if(!mapload)
var/datum/effect/effect/system/smoke_spread/S = new /datum/effect/effect/system/smoke_spread()
S.set_up(5, 0, src.loc)
@@ -63,11 +119,25 @@
visible_message(SPAN_DANGER("[src] warps in!"))
playsound(src.loc, 'sound/effects/EMPulse.ogg', 25, 1)
addtimer(CALLBACK(src, PROC_REF(activate_beacon)), 450)
latest_area = get_area(src)
icon_state = "hivebotbeacon_off"
addtimer(CALLBACK(src, PROC_REF(generate_warp_destinations)), 10) //So we don't sleep during init
set_light(6,0.5,LIGHT_COLOR_GREEN)
/mob/living/simple_animal/hostile/hivebotbeacon/Destroy()
//Remove the reference from all linked bots to us
for(var/mob/living/simple_animal/hostile/hivebot/latest_child in linked_bots)
latest_child.linked_parent = null
linked_bots.Cut()
//Smoke effect, we disappear in a smoke
var/datum/effect/effect/system/smoke_spread/S = new /datum/effect/effect/system/smoke_spread()
S.set_up(5, 0, src.loc)
S.start()
. = ..()
/mob/living/simple_animal/hostile/hivebotbeacon/proc/generate_warp_destinations()
destinations.Cut()
@@ -102,15 +172,6 @@
qdel(src)
return
/mob/living/simple_animal/hostile/hivebotbeacon/Destroy()
for (var/mob/living/simple_animal/hostile/hivebot/latest_child in linked_bots)
latest_child.linked_parent = null
linked_bots.Cut()
var/datum/effect/effect/system/smoke_spread/S = new /datum/effect/effect/system/smoke_spread()
S.set_up(5, 0, src.loc)
S.start()
.=..()
/mob/living/simple_animal/hostile/hivebotbeacon/think()
. =..()
if(stance != HOSTILE_STANCE_IDLE && activated == 0)
@@ -180,7 +241,7 @@
activate_beacon()
/mob/living/simple_animal/hostile/hivebotbeacon/proc/warpbots()
if(!bot_amt)
if(!total_hivebots_to_spawn)
visible_message(SPAN_DANGER("[src] disappears in a cloud of smoke!"))
playsound(src.loc, 'sound/effects/teleport.ogg', 25, 1)
new /obj/effect/decal/cleanable/greenglow(src.loc)
@@ -190,9 +251,11 @@
if(activated == -1)
return
if(linked_bots.len < max_bots)
if(linked_bots.len < maximum_linked_and_alive_hivebots)
visible_message(SPAN_WARNING("[src] radiates with energy!"))
var/bot_type
if(guard_amt < 4 && prob(50))
bot_type = GUARDIAN
else
@@ -245,16 +308,21 @@
linked_bots += latest_child //Adds the spawned hivebot to the list of the beacon's children.
latest_child.faction = faction
bot_amt--
total_hivebots_to_spawn--
if(bot_amt>0 && linked_bots.len < max_bots)
if(total_hivebots_to_spawn>0 && linked_bots.len < maximum_linked_and_alive_hivebots)
calc_spawn_delay()
addtimer(CALLBACK(src, PROC_REF(warpbots)), spawn_delay)
else
max_bots_reached = 1
maximum_linked_and_alive_hivebots_reached = 1
/mob/living/simple_animal/hostile/hivebotbeacon/proc/calc_spawn_delay()
spawn_delay = 80*1.085**(linked_bots.len + 1)
spawn_delay = 80 * (1.085 ** (linked_bots.len + 1))
//Adapt the value based on player population, but only if it's on the main map (most likely the Horizon)
if(isStationLevel(src.z))
spawn_delay = min(80, spawn_delay - (length(GLOB.player_list) * spawn_delay_to_playing_players_scaling_factor))
return
/mob/living/simple_animal/hostile/hivebotbeacon/Life()
@@ -262,11 +330,20 @@
if(wander)
wander = 0
stop_automated_movement = 1
if(max_bots_reached && activated == 1 && linked_bots.len < max_bots)
max_bots_reached = 0
if(maximum_linked_and_alive_hivebots_reached && activated == 1 && linked_bots.len < maximum_linked_and_alive_hivebots)
maximum_linked_and_alive_hivebots_reached = 0
calc_spawn_delay()
addtimer(CALLBACK(src, PROC_REF(warpbots)), spawn_delay)
/*################
SUBTYPES
################*/
/mob/living/simple_animal/hostile/hivebotbeacon/incendiary
projectiletype = /obj/item/projectile/beam/hivebot/incendiary
projectilesound = 'sound/weapons/plasma_cutter.ogg'
rapid = 0
#undef NORMAL
#undef RANGED
#undef RAPID