Skip to content

Commit

Permalink
Rebalances Hivemind Special Options (#5287)
Browse files Browse the repository at this point in the history
* Rebalances Hivemind Special Options

* Fixes a wrong proc I used

* Makes the gibbing toggle into a float for how long a warning is given

* Backend code improvements, make Hive turrets shoot again

* Gives hive turrets IFF and makes them not shoot corpses

* Fixes a proc
  • Loading branch information
SingingSpock authored May 25, 2024
1 parent cde2efd commit 2968611
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 25 deletions.
17 changes: 9 additions & 8 deletions code/game/gamemodes/events/hivemind_controller.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ GLOBAL_LIST_INIT(hive_data_bool, list(
"allow_tyrant_spawn" = TRUE,
"tyrant_death_kills_hive" = FALSE,
"all_church_to_battle" = FALSE,
"prevent_gibbing_dead" = TRUE,
"pop_lock" = TRUE,
"slime_pop_lock" = TRUE))

GLOBAL_LIST_INIT(hive_data_float, list(
"maximum_controlled_areas" = 0, // Stop expansion when controlling certain number of areas, 0 to disable
"maximum_existing_mobs" = 50, // Should be true in "hive_data_bool" to take effect, 0 means no hive mob spawn (except champions)
"core_oddity_drop_chance" = 50)) // prob() of hive node leaving hive-themed oddity on death
"gibbing_warning_timer" = 0, //How many seconds of warning should be given before a humanoid body is gibbed by hivemind wires. 0 means it doesn't at all
"core_oddity_drop_chance" = 50,)) // prob() of hive node leaving hive-themed oddity on death

GLOBAL_LIST_INIT(hive_names, list("Von Neumann", "Lazarus", "Abattoir", "Auto-Surgeon", "NanoTrasen",
"NanoNurse", "Vivisector", "Ex Costa", "Apostasy", "Gnosis", "Balaam", "Ophite",
Expand Down Expand Up @@ -92,6 +92,9 @@ GLOBAL_VAR_INIT(hivemind_panel, new /datum/hivemind_panel)
data += "<br>Core oddity drop chance: [GLOB.hive_data_float["core_oddity_drop_chance"]] \
<a href='?src=\ref[src];rig_gacha=1'>\[SET\]</a>"

data += "<br>How Long before Gibbing Humans? (0 is disabled): [GLOB.hive_data_float["gibbing_warning_timer"]] \
<a href='?src=\ref[src];set_gibbing_warning_timer=1'>\[SET\]</a>"

data += "<br>Spread trough burrows: [GLOB.hive_data_bool["spread_trough_burrows"] ? "Enabled" : "Disabled"] \
<a href='?src=\ref[src];toggle_burrow=1'>\[TOGGLE\]</a>"

Expand All @@ -110,9 +113,6 @@ GLOBAL_VAR_INIT(hivemind_panel, new /datum/hivemind_panel)
data += "<br>All Church To Inquisitors: [GLOB.hive_data_bool["all_church_to_battle"] ? "Enabled" : "Disabled"] \
<a href='?src=\ref[src];toggle_inquisitors=1'>\[TOGGLE\]</a>"

data += "<br>Prevent Hivemind Gibbing Dead Victims: [GLOB.hive_data_bool["prevent_gibbing_dead"] ? "Enabled" : "Disabled"] \
<a href='?src=\ref[src];toggle_prevent_gibbing_dead=1'>\[TOGGLE\]</a>"

data += "<br>Prevent Hivemind Events Below 7 Pop: [GLOB.hive_data_bool["pop_lock"] ? "Enabled" : "Disabled"] \
<a href='?src=\ref[src];toggle_pop_lock=1'>\[TOGGLE\]</a>"

Expand Down Expand Up @@ -148,6 +148,10 @@ GLOBAL_VAR_INIT(hivemind_panel, new /datum/hivemind_panel)
var/percent = input(usr, "Percentage probability of hive node dropping oddity on destruction", "Rigging gacha") as null|num
GLOB.hive_data_float["core_oddity_drop_chance"] = CLAMP(percent ? percent : 0, 0, 100)

if(href_list["set_gibbing_warning_timer"])
var/timer = input(usr, "Time in seconds before human bodies are destroyed on wires, 0 to disable", "Time in Seconds") as null|num
GLOB.hive_data_float["gibbing_warning_timer"] = CLAMP(timer ? timer : 0, 0, 300)

if(href_list["set_name"])
var/name = input(usr, "Choose wisely", "Hivemind name") as null|anything in GLOB.hive_names
if(name)
Expand Down Expand Up @@ -204,9 +208,6 @@ GLOBAL_VAR_INIT(hivemind_panel, new /datum/hivemind_panel)
if(href_list["toggle_tyrant_gameover"])
GLOB.hive_data_bool["tyrant_death_kills_hive"] = !GLOB.hive_data_bool["tyrant_death_kills_hive"]

if(href_list["toggle_prevent_gibbing_dead"])
GLOB.hive_data_bool["prevent_gibbing_dead"] = !GLOB.hive_data_bool["prevent_gibbing_dead"]

if(href_list["toggle_pop_lock"])
GLOB.hive_data_bool["pop_lock"] = !GLOB.hive_data_bool["pop_lock"]

Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/structures/burrows.dm
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ percentage is a value in the range 0..1 that determines what portion of this mob
if(locate(/obj/effect/plant) in loc)
return

if(!hive_mind_ai || !hive_mind_ai.hives.len || maintenance || !GLOB.hive_data_bool["spread_trough_burrows"])
if(!hive_mind_ai || !hive_mind_ai.hives.len || !GLOB.hive_data_bool["spread_trough_burrows"])
return

var/area/A = get_area(src)
Expand Down
83 changes: 78 additions & 5 deletions code/modules/hivemind/machines.dm
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
//Hivemind various machines

#define REGENERATION_SPEED 4
#define TURRET_PRIORITY_TARGET 2
#define TURRET_SECONDARY_TARGET 1
#define TURRET_NOT_TARGET 0



Expand Down Expand Up @@ -446,19 +449,86 @@
icon_state = "turret"
cooldown_time = 1 SECONDS
spawn_weight = 60
var/firing_range = 7
var/last_target //last target fired at, prevents turrets from erratically firing at all valid targets in range
var/shot_delay = 30 //3 seconds between each shot by default, gets faster with evo level
var/last_fired = 0 //1: if the turret is cooling down from a shot, 0: turret is ready to fire
var/proj_type = /obj/item/projectile/goo

/obj/machinery/hivemind_machine/turret/Process()
/obj/machinery/hivemind_machine/turret/Process() //Copied mostly from porta_turret code now
if(!..())
return

var/mob/living/target = locate() in all_mobs_in_view(world.view, src)
if(target && is_attackable(target) && target.faction != HIVE_FACTION)
use_ability(target)
set_cooldown()
var/list/targets = list() //Primary targets
var/list/secondarytargets = list() //targets that are less important

shot_delay = max(30 - hive_mind_ai.evo_level * 5, 5) //Scales at half a second faster for each evo level, minimum half a second

for(var/mob/living/M in view(firing_range, src))
assess_and_assign(M, targets, secondarytargets)

for(var/obj/mecha/mech in GLOB.mechas_list)
if (mech.z == z && (get_dist(mech, src) < firing_range) && can_see(src, mech, firing_range))
var/mob/living/occupant = mech.get_mob()
if (occupant)
assess_and_assign(occupant, targets, secondarytargets)

if(!tryToShootAt(targets))
tryToShootAt(secondarytargets)

/obj/machinery/hivemind_machine/turret/proc/assess_and_assign(var/mob/living/L, var/list/targets, var/list/secondarytargets)
switch(assess_living(L))
if(TURRET_PRIORITY_TARGET)
targets += L
if(TURRET_SECONDARY_TARGET)
secondarytargets += L

/obj/machinery/hivemind_machine/turret/proc/assess_living(var/mob/living/L)
if(L.faction == "hive") //Don't shoot hive mobs
return TURRET_NOT_TARGET
if(L.stat == DEAD)
return TURRET_NOT_TARGET //Don't shoot the dead either
if(L.lying) //Lying down people are lower priority to shoot
return TURRET_SECONDARY_TARGET
return TURRET_PRIORITY_TARGET //If you ain't hive or lying, you're a priority target

/obj/machinery/hivemind_machine/turret/proc/tryToShootAt(var/list/mob/living/targets)
if(targets.len && last_target && (last_target in targets) && target(last_target))
return TRUE

while(targets.len > 0)
var/mob/living/M = pick(targets)
targets -= M
if(target(M))
return TRUE

/obj/machinery/hivemind_machine/turret/proc/target(var/mob/living/target)
if(target)
last_target = target
set_dir(get_dir(src, target)) //even if you can't shoot, follow the target
spawn()
shootAt(target)
return TRUE
return

/obj/machinery/hivemind_machine/turret/proc/shootAt(var/mob/living/target)
if(last_fired) //prevents rapid-fire shooting
return
last_fired = 1
spawn()
sleep(shot_delay)
last_fired = 0

var/turf/T = get_turf(src)
var/turf/U = get_turf(target)
if(!istype(T) || !istype(U))
return

use_ability(target)

/obj/machinery/hivemind_machine/turret/use_ability(atom/target)
var/obj/item/projectile/proj = new proj_type(loc)
proj.faction_iff = "hive" //We get some iff so we're not used as a weapon against the hive... we should pretty much always have mobs attacking!
proj.launch(target)
playsound(src, 'sound/effects/blobattack.ogg', 70, 1)

Expand Down Expand Up @@ -724,3 +794,6 @@


#undef REGENERATION_SPEED
#undef TURRET_PRIORITY_TARGET
#undef TURRET_SECONDARY_TARGET
#undef TURRET_NOT_TARGET
36 changes: 25 additions & 11 deletions code/modules/hivemind/wires.dm
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
var/obj/machinery/hivemind_machine/node/master_node
var/list/wires_connections = list("0", "0", "0", "0")
var/my_area
var/assimilation_timer

/obj/effect/plant/hivemind/New()
..()
Expand All @@ -35,6 +36,10 @@
GLOB.hivemind_areas.Remove(my_area)
return ..()

/obj/effect/plant/hivemind/die_off()
if(assimilation_timer)
deltimer(assimilation_timer)
return ..()

/obj/effect/plant/hivemind/after_spread(obj/effect/plant/child, turf/target_turf)
if(master_node)
Expand Down Expand Up @@ -378,23 +383,23 @@
//Corpse reanimation
if(isliving(subject) && !ishivemindmob(subject))
//human bodies
if(ishuman(subject))
if(ishuman(subject) && !assimilation_timer)
var/mob/living/L = subject

if(GLOB.hive_data_bool["prevent_gibbing_dead"])
//We we dont touch the dead via are controler we dont want to pk people form the round
if(!GLOB.hive_data_float["gibbing_warning_timer"]) //If the value is set to 0 (the default) we don't touch player humans
return

//if our target has cruciform, let's just leave it
if(is_neotheology_disciple(L))
var/timer = GLOB.hive_data_float["gibbing_warning_timer"] SECONDS //If we've continued, then there's a value there and we want it in seconds

if(is_neotheology_disciple(L)) //If our target has a cruciform, we don't touch it
return

for(var/obj/item/W in L)
L.drop_from_inventory(W)
var/M = pick(/mob/living/simple_animal/hostile/hivemind/himan, /mob/living/simple_animal/hostile/hivemind/phaser)
new M(loc)
visible_message("Wires begin to wreathe around [L], starting the process of converting them into part of the hivemind.") //We tell people to get them off the wires
assimilation_timer = addtimer(CALLBACK(src, .proc/assimilate_human, L), timer, TIMER_STOPPABLE)
return

//robot corpses
else if(issilicon(subject))
else if(issilicon(subject)) //If you're a borg... sucks to suck? I don't feel like reworking this, you're too mechanical to prevent hivemind taking over you
new /mob/living/simple_animal/hostile/hivemind/hiborg(loc)
//other dead bodies
else
Expand All @@ -403,6 +408,15 @@

qdel(subject)

/obj/effect/plant/hivemind/proc/assimilate_human(var/mob/living/L)
if(!locate(/obj/effect/plant/hivemind) in L.loc || !(L.stat == DEAD)) //If we don't see any wires after the alotted time or we're alive again, we don't get got
return
for(var/obj/item/W in L)
L.drop_from_inventory(W)
var/M = pick(/mob/living/simple_animal/hostile/hivemind/himan, /mob/living/simple_animal/hostile/hivemind/phaser)
new M(loc)

L.dust()

//////////////////////////////////////////////////////////////////
/////////////////////////>RESPONSE CODE<//////////////////////////
Expand Down Expand Up @@ -461,4 +475,4 @@
#undef HIVE_FACTION
#undef MAX_NODES_AMOUNT
#undef MIN_NODES_RANGE
#undef ishivemindmob
#undef ishivemindmob

0 comments on commit 2968611

Please sign in to comment.