mirror of
https://github.com/goonstation/goonstation-2016.git
synced 2026-05-18 14:39:01 +01:00
587 lines
16 KiB
Plaintext
587 lines
16 KiB
Plaintext
/datum/construction_controller
|
|
var/human_next_event
|
|
|
|
var/next_event_type = null
|
|
var/datum/construction_event/current_event = null
|
|
var/datum/construction_event/next_event = null
|
|
var/datum/construction_event/fallback_event = null
|
|
var/list/all_events = list()
|
|
var/list/possible_events = list()
|
|
var/list/event_types = list()
|
|
|
|
var/event_delay = 0
|
|
var/choose_at = 0
|
|
var/next_event_at = 0
|
|
|
|
New()
|
|
for (var/evtype in typesof(/datum/construction_event))
|
|
var/datum/construction_event/E = new evtype()
|
|
if (E.is_abstract)
|
|
qdel(E)
|
|
else
|
|
all_events += E
|
|
if (E.milestone == null)
|
|
possible_events += E
|
|
rebuild_event_types()
|
|
|
|
proc/notify_milestone_complete(var/datum/progress/P)
|
|
for (var/datum/construction_event/E in all_events)
|
|
if (istype(P, E.milestone))
|
|
possible_events += E
|
|
rebuild_event_types()
|
|
|
|
proc/notify_milestone_uncomplete(var/datum/progress/P)
|
|
for (var/datum/construction_event/E in possible_events)
|
|
if (istype(P, E.milestone))
|
|
possible_events -= E
|
|
rebuild_event_types()
|
|
|
|
proc/rebuild_event_types()
|
|
event_types.len = 0
|
|
for (var/datum/construction_event/E in possible_events)
|
|
if (!(E.event_type in event_types))
|
|
event_types += E.event_type
|
|
|
|
proc/process()
|
|
if (!ticker)
|
|
return
|
|
if (!ticker.mode)
|
|
return
|
|
if (!istype(ticker.mode, /datum/game_mode/construction))
|
|
return
|
|
|
|
if (event_delay)
|
|
if (ticker.round_elapsed_ticks < event_delay)
|
|
if (current_event)
|
|
current_event.process()
|
|
return
|
|
else
|
|
if (current_event)
|
|
current_event.tear_down()
|
|
current_event = null
|
|
event_delay = 0
|
|
|
|
if (!next_event_type)
|
|
next_event_type = pick(event_types)
|
|
var/minutes = rand(15, 30)
|
|
next_event_at = ticker.round_elapsed_ticks + minutes * 60 * 10 + rand(0, 59) * 10
|
|
choose_at = ticker.round_elapsed_ticks + rand(5, round(minutes / 2)) * 60 * 10 + rand(0, 59) * 10
|
|
for (var/datum/construction_event/E in possible_events)
|
|
if (E.event_type == next_event_type)
|
|
fallback_event = E
|
|
break
|
|
if (!fallback_event)
|
|
next_event_type = null
|
|
return
|
|
|
|
if (choose_at)
|
|
if (ticker.round_elapsed_ticks >= choose_at)
|
|
var/list/type_events = list()
|
|
for (var/datum/construction_event/E in possible_events)
|
|
if (E.event_type == next_event_type)
|
|
type_events += E
|
|
if (type_events.len)
|
|
next_event = pick(type_events)
|
|
else
|
|
next_event = fallback_event
|
|
next_event.early_warning()
|
|
fallback_event = null
|
|
if (next_event.additional_prep_time)
|
|
next_event_at += next_event.additional_prep_time
|
|
choose_at = 0
|
|
else
|
|
return
|
|
|
|
if (next_event_at)
|
|
if (ticker.round_elapsed_ticks >= next_event_at)
|
|
next_event.set_up()
|
|
current_event = next_event
|
|
next_event = null
|
|
event_delay = ticker.round_elapsed_ticks + current_event.duration
|
|
next_event_at = 0
|
|
next_event_type = null
|
|
else
|
|
return
|
|
|
|
/datum/construction_event
|
|
var/name = null
|
|
var/early_warning_heading = "Anomaly alert"
|
|
var/early_warning_text = "An anomaly is heading towards the station."
|
|
var/warning_heading = "Anomaly alert"
|
|
var/warning_text = "The anomaly has reached the station."
|
|
var/datum/progress/milestone = null
|
|
var/event_type = "Anomaly"
|
|
var/duration = 600 // 1 min
|
|
var/additional_prep_time = 0
|
|
var/is_abstract = 1
|
|
var/time_scaling = 0.167
|
|
var/time_modifier = 0
|
|
var/player_scaling = 0.1
|
|
var/player_modifier = 0
|
|
|
|
proc/early_warning()
|
|
for (var/obj/machinery/communications_dish/C in machines)
|
|
C.add_centcom_report("[command_name()] Update", early_warning_text)
|
|
|
|
if (!early_warning_heading)
|
|
command_alert(early_warning_text)
|
|
else
|
|
command_alert(early_warning_text, early_warning_heading)
|
|
|
|
proc/set_up()
|
|
for (var/obj/machinery/communications_dish/C in machines)
|
|
C.add_centcom_report("[command_name()] Update", warning_text)
|
|
|
|
if (!warning_heading)
|
|
command_alert(warning_text)
|
|
else
|
|
command_alert(warning_text, warning_heading)
|
|
|
|
calculate_player_modifier()
|
|
calculate_time_modifier()
|
|
|
|
proc/process()
|
|
return
|
|
proc/tear_down()
|
|
return
|
|
|
|
proc/calculate_player_modifier()
|
|
player_modifier = 1
|
|
for (var/mob/living/M in mobs)
|
|
if (M.client && M.stat < 2)
|
|
player_modifier += player_scaling
|
|
|
|
proc/calculate_time_modifier()
|
|
var/datum/game_mode/construction/C = ticker.mode
|
|
var/elapsed_time = ticker.round_elapsed_ticks - C.starttime
|
|
time_modifier = (1 + round(elapsed_time / 36000) * time_scaling)
|
|
|
|
/datum/construction_event/nothing
|
|
duration = 600
|
|
name = "Nothing"
|
|
siege
|
|
early_warning_heading = "Siege alert"
|
|
early_warning_text = "A large attack force has been detected on collision course with the station."
|
|
warning_heading = "Siege alert averted"
|
|
warning_text = "The attacking force changed course towards a nearby planet."
|
|
event_type = "Siege"
|
|
|
|
syndicate
|
|
event_type = "Syndicate Siege"
|
|
|
|
anomaly
|
|
early_warning_text = "Chunks from a nearby asteroid collision are headed towards the station from the"
|
|
warning_text = "The gravitational field of a nearby planet diverted the meteors off collision course."
|
|
event_type = "Cosmic Anomaly"
|
|
|
|
early_warning()
|
|
var/early_warning_orig = early_warning_heading
|
|
early_warning_text = "[early_warning_heading] [pick("north!", "south!", "east!", "west!")]"
|
|
..()
|
|
early_warning_text = early_warning_orig
|
|
|
|
#define METHOD_TELEPORT 1
|
|
#define METHOD_SPAWN 2
|
|
//#define METHOD_TELEPORT_TO_SPACE 3
|
|
#define METHOD_EDGE_WANDER 4
|
|
|
|
/datum/construction_event/siege
|
|
name = "Siege"
|
|
early_warning_heading = "Siege alert"
|
|
early_warning_text = "A large attack force has been detected on collision course with the station."
|
|
warning_heading = "Siege alert"
|
|
warning_text = "We are under attack!"
|
|
event_type = "Siege"
|
|
|
|
time_scaling = 0.33
|
|
player_scaling = 0.2
|
|
var/original_duration = 600
|
|
var/spawn_delay = 2
|
|
var/current_delay = 0
|
|
var/max_attack_force_size = 50
|
|
var/original_size = 50
|
|
var/current_attack_force_size = 0
|
|
var/list/attacker_types = list()
|
|
var/list/bosses = list()
|
|
var/current_bosses = 0
|
|
var/difficulty_multiplier = 0
|
|
var/original_bosses = 2
|
|
var/max_bosses = 2
|
|
var/method = METHOD_TELEPORT
|
|
var/list/possible_target_turfs = list()
|
|
var/per_process = 1
|
|
|
|
var/x_min
|
|
var/x_max
|
|
var/y_min
|
|
var/y_max
|
|
|
|
set_up()
|
|
..()
|
|
player_modifier -= 1
|
|
time_modifier -= 0.5
|
|
difficulty_multiplier = time_modifier * player_modifier
|
|
duration = original_duration * difficulty_multiplier
|
|
max_attack_force_size = round(original_size * difficulty_multiplier)
|
|
per_process = max(1, round(max_attack_force_size / 20))
|
|
max_bosses = round(original_bosses * difficulty_multiplier)
|
|
current_attack_force_size = 0
|
|
current_delay = 0
|
|
current_bosses = 0
|
|
possible_target_turfs.len = 0
|
|
|
|
var/area/shuttle/arrival/station/A = locate() in world
|
|
var/turf/Q = A.find_middle(0)
|
|
for (var/turf/simulated/floor/F in range(50, Q))
|
|
if (!(F in A))
|
|
possible_target_turfs += F
|
|
|
|
if (method == METHOD_EDGE_WANDER)
|
|
switch(rand(1,4))
|
|
if (1)
|
|
x_min = 50
|
|
x_max = 250
|
|
y_min = 295
|
|
y_max = 297
|
|
if (2)
|
|
x_min = 50
|
|
x_max = 250
|
|
y_min = 3
|
|
y_max = 5
|
|
if (3)
|
|
x_min = 295
|
|
x_max = 297
|
|
y_min = 50
|
|
y_max = 250
|
|
if (4)
|
|
x_min = 3
|
|
x_max = 5
|
|
y_min = 50
|
|
y_max = 250
|
|
|
|
process()
|
|
if (current_attack_force_size < max_attack_force_size)
|
|
var/runs = 1
|
|
if (per_process > 1)
|
|
runs = rand(1, per_process)
|
|
for (var/times = 1, times <= runs, times++)
|
|
if (current_delay > 0)
|
|
current_delay--
|
|
else if (prob(25 * difficulty_multiplier))
|
|
if (method == METHOD_TELEPORT || method == METHOD_SPAWN)
|
|
var/valid = 0
|
|
while (!valid)
|
|
if (!possible_target_turfs.len)
|
|
current_attack_force_size = max_attack_force_size
|
|
break
|
|
var/turf/target = pick(possible_target_turfs)
|
|
if (target.density)
|
|
possible_target_turfs -= target
|
|
continue
|
|
valid = 1
|
|
for (var/obj/O in target)
|
|
if (O.density)
|
|
possible_target_turfs -= target
|
|
valid = 0
|
|
break
|
|
if (!valid)
|
|
continue
|
|
var/attacker_type
|
|
if (current_bosses < max_bosses && bosses.len && prob(5))
|
|
attacker_type = pick(bosses)
|
|
current_bosses++
|
|
else
|
|
attacker_type = pick(attacker_types)
|
|
new attacker_type(target)
|
|
current_attack_force_size++
|
|
current_delay = spawn_delay
|
|
if (method == METHOD_TELEPORT)
|
|
showswirl(target)
|
|
else if (method == METHOD_EDGE_WANDER)
|
|
var/valid = 0
|
|
while (!valid)
|
|
if (!possible_target_turfs.len)
|
|
current_attack_force_size = max_attack_force_size
|
|
break
|
|
var/turf/target = pick(possible_target_turfs)
|
|
if (target.density)
|
|
possible_target_turfs -= target
|
|
continue
|
|
valid = 1
|
|
for (var/obj/O in target)
|
|
if (O.density)
|
|
possible_target_turfs -= target
|
|
valid = 0
|
|
break
|
|
if (!valid)
|
|
continue
|
|
var/attacker_type
|
|
if (current_bosses < max_bosses && bosses.len && prob(5))
|
|
attacker_type = pick(bosses)
|
|
current_bosses++
|
|
else
|
|
attacker_type = pick(attacker_types)
|
|
var/obj/critter/CR = new attacker_type(locate(rand(x_min, x_max), rand(y_min, y_max), 1))
|
|
current_attack_force_size++
|
|
CR.task = "following path"
|
|
CR.followed_path = findPath(CR.loc, target)
|
|
CR.followed_path_retry_target = target
|
|
if (prob(30 / difficulty_multiplier))
|
|
CR.follow_path_blindly = 1
|
|
|
|
/datum/construction_event/siege/rockworm
|
|
name = "Siege?"
|
|
warning_text = "We are under attack by the Space Rock Worm Federation!"
|
|
attacker_types = list(/obj/critter/rockworm)
|
|
original_size = 20
|
|
original_bosses = 0
|
|
is_abstract = 0
|
|
|
|
/datum/construction_event/siege/hobo
|
|
name = "Siege?"
|
|
warning_text = "We are under attack by the Space Hobo Federation!"
|
|
attacker_types = list(/mob/living/carbon/human/biker)
|
|
original_size = 3
|
|
original_bosses = 0
|
|
is_abstract = 0
|
|
|
|
/datum/construction_event/siege/martian
|
|
name = "Martian Siege"
|
|
warning_text = "We are under attack by a martian siege force!"
|
|
attacker_types = list(/obj/critter/martian/warrior, /obj/critter/martian/soldier)
|
|
bosses = list(/obj/critter/martian/psychic/weak, /obj/critter/martian/sapper)
|
|
original_size = 20
|
|
original_bosses = 2
|
|
is_abstract = 0
|
|
|
|
/datum/construction_event/siege/spirits
|
|
name = "Spirit Siege"
|
|
warning_text = "We are under siege from a dimensional fissure!"
|
|
attacker_types = list(/obj/critter/spirit)
|
|
bosses = list(/obj/critter/aberration)
|
|
method = METHOD_SPAWN
|
|
original_size = 15
|
|
original_bosses = 1
|
|
is_abstract = 0
|
|
|
|
/datum/construction_event/siege/animals
|
|
name = "Animal Siege"
|
|
warning_text = "A pack of animals have been teleported on board our station!"
|
|
attacker_types = list(/obj/critter/spacebee, /obj/critter/mouse, /obj/critter/goose, /obj/critter/owl, /obj/critter/bat/buff, /obj/critter/cat, /obj/critter/nicespider, /obj/critter/spider/spacerachnid)
|
|
bosses = list(/obj/critter/lion, /obj/critter/bear)
|
|
original_size = 30
|
|
original_bosses = 5
|
|
is_abstract = 0
|
|
|
|
/datum/construction_event/siege/plants
|
|
name = "Plant Siege"
|
|
warning_text = "We are under attack by a group of sentient vegetables!"
|
|
attacker_types = list(/obj/critter/killertomato)
|
|
bosses = list(/obj/critter/maneater)
|
|
original_size = 30
|
|
original_bosses = 1
|
|
is_abstract = 0
|
|
|
|
/datum/construction_event/siege/drones
|
|
name = "Drone Siege"
|
|
event_type = "Syndicate Siege"
|
|
warning_text = "We are under siege from a small drone force!"
|
|
attacker_types = list(/obj/critter/gunbot/drone)
|
|
bosses = list(/obj/critter/gunbot/drone/buzzdrone)
|
|
original_size = 8
|
|
original_bosses = 1
|
|
is_abstract = 0
|
|
method = METHOD_EDGE_WANDER
|
|
|
|
/datum/construction_event/siege/drones_buzz
|
|
name = "Buzz Drone Siege"
|
|
event_type = "Syndicate Siege"
|
|
warning_text = "We are under siege from a small drone force!"
|
|
attacker_types = list(/obj/critter/gunbot/drone/buzzdrone)
|
|
bosses = list(/obj/critter/gunbot/drone/buzzdrone)
|
|
milestone = /datum/progress/pods/tier1
|
|
original_size = 6
|
|
original_bosses = 1
|
|
is_abstract = 0
|
|
method = METHOD_EDGE_WANDER
|
|
|
|
/datum/construction_event/siege/drones_heavy
|
|
name = "Heavy Drone Siege"
|
|
event_type = "Syndicate Siege"
|
|
warning_text = "We are under siege from a small drone force!"
|
|
attacker_types = list(/obj/critter/gunbot/drone/buzzdrone)
|
|
bosses = list(/obj/critter/gunbot/drone/heavydrone)
|
|
milestone = /datum/progress/pods/tier2
|
|
original_size = 6
|
|
original_bosses = 1
|
|
is_abstract = 0
|
|
method = METHOD_EDGE_WANDER
|
|
|
|
/datum/construction_event/meteors
|
|
warning_text = "The meteor shower has reached the station."
|
|
var/early_warning_original = "Chunks from a nearby asteroid collision are headed towards the station"
|
|
event_type = "Cosmic Anomaly"
|
|
|
|
var/direction = 0
|
|
var/x_min = 0
|
|
var/x_max = 0
|
|
var/y_min = 0
|
|
var/y_max = 0
|
|
var/turf/around = null
|
|
is_abstract = 1
|
|
|
|
early_warning()
|
|
direction = rand(1,4)
|
|
switch (direction)
|
|
if (1)
|
|
early_warning_text = "[early_warning_original] from the north!"
|
|
if (2)
|
|
early_warning_text = "[early_warning_original] from the south!"
|
|
if (3)
|
|
early_warning_text = "[early_warning_original] from the east!"
|
|
if (4)
|
|
early_warning_text = "[early_warning_original] from the west!"
|
|
..()
|
|
|
|
set_up()
|
|
..()
|
|
player_modifier -= 1
|
|
|
|
var/area/shuttle/arrival/station/A = locate() in world
|
|
around = A.find_middle(0)
|
|
if (!around)
|
|
around = locate(150, 150, 1)
|
|
switch(direction)
|
|
if (1)
|
|
x_min = 50
|
|
x_max = 250
|
|
y_min = 295
|
|
y_max = 297
|
|
if (2)
|
|
x_min = 50
|
|
x_max = 250
|
|
y_min = 3
|
|
y_max = 5
|
|
if (3)
|
|
x_min = 295
|
|
x_max = 297
|
|
y_min = 50
|
|
y_max = 250
|
|
if (4)
|
|
x_min = 3
|
|
x_max = 5
|
|
y_min = 50
|
|
y_max = 250
|
|
|
|
process()
|
|
if (prob(20 * player_modifier * time_modifier))
|
|
var/turf/target = null
|
|
var/retries = 0
|
|
do
|
|
if (retries > 5)
|
|
return
|
|
target = pick(range(50, around))
|
|
retries++
|
|
while (!target)
|
|
if (!isturf(target))
|
|
target = get_turf(target)
|
|
if (!target)
|
|
return
|
|
create_meteor(locate(rand(x_min, x_max), rand(y_min, y_max), 1), target)
|
|
|
|
proc/create_meteor(var/turf/from, var/turf/target)
|
|
return
|
|
|
|
/datum/construction_event/meteors/small_meteor_storm
|
|
name = "Small Meteor Shower"
|
|
early_warning_original = "Chunks from a nearby asteroid collision are headed towards the station"
|
|
is_abstract = 0
|
|
|
|
create_meteor(var/turf/from, var/turf/target)
|
|
new /obj/newmeteor/small(from, target)
|
|
|
|
/datum/construction_event/meteors/medium_meteor_storm
|
|
name = "Medium Meteor Shower"
|
|
milestone = /datum/progress/time/twohours
|
|
early_warning_original = "Chunks from a nearby microplanet collision are headed towards the station"
|
|
is_abstract = 0
|
|
|
|
create_meteor(var/turf/from, var/turf/target)
|
|
if (prob(80))
|
|
new /obj/newmeteor/small(from, target)
|
|
else
|
|
new /obj/newmeteor/massive(from, target)
|
|
|
|
/datum/construction_event/meteors/massive_meteor_storm
|
|
name = "Large Meteor Shower"
|
|
milestone = /datum/progress/time/sixhours
|
|
early_warning_original = "Chunks from a nearby planetary collision are headed towards the station"
|
|
is_abstract = 0
|
|
|
|
create_meteor(var/turf/from, var/turf/target)
|
|
if (prob(30))
|
|
new /obj/newmeteor/small(from, target)
|
|
else
|
|
new /obj/newmeteor/massive(from, target)
|
|
|
|
/datum/construction_event/radiation_storm
|
|
name = "Radiation Storm"
|
|
early_warning_text = "A large wave of radiation is approaching the station."
|
|
warning_text = "The radiation wave is hitting the station!"
|
|
event_type = "Cosmic Anomaly"
|
|
is_abstract = 0
|
|
|
|
var/sound/radsound = 'sound/weapons/ACgun2.ogg'
|
|
var/list/possible_target_turfs = list()
|
|
|
|
set_up()
|
|
..()
|
|
possible_target_turfs.len = 0
|
|
var/area/shuttle/arrival/station/A = locate() in world
|
|
var/turf/Q = A.find_middle(0)
|
|
for (var/turf/simulated/floor/F in range(50, Q))
|
|
if (!(F in A))
|
|
possible_target_turfs += F
|
|
|
|
process()
|
|
if (prob(40))
|
|
var/turf/target = pick(possible_target_turfs)
|
|
if (!target)
|
|
possible_target_turfs -= target
|
|
return
|
|
create_radwave(target, rand(30, 60), radsound)
|
|
|
|
/proc/trigger_construction_event()
|
|
if (!ticker)
|
|
return
|
|
if (!ticker.mode)
|
|
return
|
|
if (!istype(ticker.mode, /datum/game_mode/construction))
|
|
return
|
|
var/datum/game_mode/construction/C = ticker.mode
|
|
var/datum/construction_controller/E = C.events
|
|
E.event_delay = 1
|
|
E.process()
|
|
E.choose_at = 1
|
|
E.process()
|
|
E.next_event_at = 1
|
|
E.process()
|
|
|
|
/proc/trigger_specific_construction_event()
|
|
if (!ticker)
|
|
return
|
|
if (!ticker.mode)
|
|
return
|
|
if (!istype(ticker.mode, /datum/game_mode/construction))
|
|
return
|
|
var/datum/game_mode/construction/C = ticker.mode
|
|
var/datum/construction_controller/E = C.events
|
|
var/datum/construction_event/EV = input("Which event", "Event", null) in E.all_events
|
|
E.event_delay = 1
|
|
E.process()
|
|
E.next_event_type = EV.type
|
|
E.choose_at = 1
|
|
E.process()
|
|
E.next_event = EV
|
|
E.next_event_at = 1
|
|
E.process() |