mirror of
https://github.com/goonstation/goonstation-2016.git
synced 2026-07-21 22:12:21 +01:00
Initial Commit
This commit is contained in:
@@ -0,0 +1,587 @@
|
||||
/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()
|
||||
Reference in New Issue
Block a user