mirror of
https://github.com/goonstation/goonstation-2016.git
synced 2026-07-21 05:52:20 +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()
|
||||
@@ -0,0 +1,167 @@
|
||||
/proc/findPath_H(var/turf/A, var/turf/target)
|
||||
var/dx = target.x - A.x
|
||||
var/dy = target.y - A.y
|
||||
if (dx < 0)
|
||||
dx = -dx
|
||||
if (dy < 0)
|
||||
dy = -dy
|
||||
return max(dx, dy)
|
||||
|
||||
/proc/findPath_isValid(var/turf/A)
|
||||
if (A.density)
|
||||
return 0
|
||||
for (var/obj/O in A)
|
||||
if (O.density)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/proc/findPath_heapInsert(var/list/heap, var/turf/add, var/value)
|
||||
heap += add
|
||||
heap[add] = value
|
||||
var/i = heap.len
|
||||
while (i > 1)
|
||||
var/p = round(i / 2)
|
||||
var/key1 = heap[i]
|
||||
var/key2 = heap[p]
|
||||
if (heap[key1] < heap[key2])
|
||||
heap.Swap(p, i)
|
||||
i = p
|
||||
else
|
||||
break
|
||||
|
||||
/proc/findPath_heapify(var/list/heap, var/entry)
|
||||
var/i = entry
|
||||
while (i < heap.len)
|
||||
if (i * 2 + 1 <= heap.len)
|
||||
var/c1 = i * 2
|
||||
var/c2 = i * 2 + 1
|
||||
var/keyi = heap[i]
|
||||
var/key1 = heap[c1]
|
||||
var/key2 = heap[c2]
|
||||
var/lesser = c1
|
||||
var/lesskey = key1
|
||||
if (heap[key2] < heap[key1])
|
||||
lesser = c2
|
||||
lesskey = key2
|
||||
if (heap[lesskey] < heap[keyi])
|
||||
heap.Swap(i, lesser)
|
||||
i = lesser
|
||||
else
|
||||
break
|
||||
else if (i * 2 <= heap.len)
|
||||
var/lesser = i * 2
|
||||
var/keyi = heap[i]
|
||||
var/lesskey = heap[lesser]
|
||||
if (heap[lesskey] < heap[keyi])
|
||||
heap.Swap(i, lesser)
|
||||
i = lesser
|
||||
else
|
||||
break
|
||||
else
|
||||
break
|
||||
|
||||
/proc/findPath_heapRemove(var/list/heap)
|
||||
var/turf/get = heap[1]
|
||||
var/value = heap[get]
|
||||
heap.Swap(1, heap.len)
|
||||
heap -= get
|
||||
findPath_heapify(heap, 1)
|
||||
return list(get, value)
|
||||
|
||||
/proc/findPath_heapModify(var/list/heap, var/turf/key, var/value)
|
||||
if (!(key in heap))
|
||||
return
|
||||
var/i = heap.Find(key)
|
||||
heap[key] = value
|
||||
findPath_heapify(heap, i)
|
||||
|
||||
/proc/findPath_weigh(var/turf/which, var/turf/parent, var/turf/target)
|
||||
var/moveDir = get_dir(parent, which)
|
||||
var/opposite = get_dir(which, parent)
|
||||
var/targetDir = get_dir(which, target)
|
||||
if (targetDir == moveDir)
|
||||
return 1
|
||||
if (targetDir == opposite)
|
||||
return 3
|
||||
if (moveDir in list(1,2,4,8))
|
||||
if (moveDir & targetDir)
|
||||
return 1.5
|
||||
if (opposite & targetDir)
|
||||
return 2.5
|
||||
return 2
|
||||
else
|
||||
if (targetDir in list(1,2,4,8))
|
||||
if (moveDir & targetDir)
|
||||
return 1.5
|
||||
if (opposite & targetDir)
|
||||
return 2.5
|
||||
return 2
|
||||
|
||||
/proc/findPath(var/turf/source, var/turf/target, var/maxIterations = 2500, var/stopRange = 5, var/stopOverflow = 50)
|
||||
var/list/open = list()
|
||||
open += source
|
||||
open[source] = findPath_H(source, target)
|
||||
var/list/parent = list()
|
||||
var/list/G = list()
|
||||
var/list/ignore = list()
|
||||
var/list/ret = list()
|
||||
var/iterations = 0
|
||||
var/turf/closest = source
|
||||
var/closest_H = maxIterations
|
||||
var/stop_counter = 0
|
||||
while (open.len)
|
||||
var/list/data = findPath_heapRemove(open)
|
||||
var/turf/check = data[1]
|
||||
var/H = findPath_H(check, target)
|
||||
var/dist = data[2] - H
|
||||
if (check == target)
|
||||
while (check != source)
|
||||
ret.Insert(1, check)
|
||||
check = parent[check]
|
||||
return ret
|
||||
if (stop_counter)
|
||||
stop_counter++
|
||||
if (H < closest_H)
|
||||
closest = check
|
||||
closest_H = H
|
||||
if (closest_H <= stopRange && !stop_counter)
|
||||
stop_counter++
|
||||
iterations++
|
||||
if (iterations >= maxIterations || stop_counter > stopOverflow)
|
||||
check = closest
|
||||
while (check != source)
|
||||
ret.Insert(1, check)
|
||||
check = parent[check]
|
||||
return ret
|
||||
for (var/turf/Q in orange(1, check))
|
||||
if (Q in ignore)
|
||||
continue
|
||||
if (!findPath_isValid(Q))
|
||||
ignore += Q
|
||||
continue
|
||||
if (!(Q in G))
|
||||
G += Q
|
||||
var/cG = dist + findPath_weigh(Q, check, target)
|
||||
G[Q] = cG
|
||||
parent += Q
|
||||
parent[Q] = check
|
||||
findPath_heapInsert(open, Q, dist + 1 + findPath_H(Q, target))
|
||||
else
|
||||
var/cG = dist + findPath_weigh(Q, check, target)
|
||||
if (cG < G[Q])
|
||||
G[Q] = cG
|
||||
parent[Q] = check
|
||||
findPath_heapModify(open, Q, dist + 1 + findPath_H(Q, target))
|
||||
|
||||
/proc/findPath_test()
|
||||
var/sx = input("Source X", "Source X", 50) as num
|
||||
var/sy = input("Source Y", "Source Y", 50) as num
|
||||
var/sz = input("Source Z", "Source Z", 50) as num
|
||||
var/tx = input("Target X", "Target X", 50) as num
|
||||
var/ty = input("Target Y", "Target Y", 50) as num
|
||||
var/tz = input("Target Z", "Target Z", 50) as num
|
||||
var/list/path = findPath(locate(sx,sy,sz),locate(tx,ty,tz))
|
||||
if (!path)
|
||||
boutput(world, "No path found.")
|
||||
else
|
||||
boutput(world, "Path of [path.len] found.")
|
||||
@@ -0,0 +1,429 @@
|
||||
/datum/progress
|
||||
var/name = "Milestone"
|
||||
var/list/required = list()
|
||||
var/requirements_cache = null
|
||||
|
||||
var/is_room = 0
|
||||
var/minimum_width = 0
|
||||
var/minimum_height = 0
|
||||
var/room_area = null
|
||||
|
||||
var/announce_completion = 0
|
||||
var/announced_message = ""
|
||||
var/announce_uncompletion = 0
|
||||
var/uncompleted_message = ""
|
||||
|
||||
var/completed = 0
|
||||
|
||||
var/can_uncomplete = 0
|
||||
var/uncompletion = 0
|
||||
var/uncompleted_at = 0
|
||||
var/grace_period = 0
|
||||
var/periodical_check = 0
|
||||
var/datum/progress/parent = null
|
||||
|
||||
var/is_abstract = 1
|
||||
|
||||
var/list/completed_space = list()
|
||||
var/turf/completed_origin = null
|
||||
|
||||
New()
|
||||
for (var/objt in required)
|
||||
var/obj/O = locate(objt)
|
||||
var/needs_deletion = 0
|
||||
if (!O)
|
||||
O = new objt(null)
|
||||
needs_deletion = 1
|
||||
var/req_string
|
||||
if (requirements_cache)
|
||||
req_string = ", [required[objt]] [O]"
|
||||
else
|
||||
req_string = "[required[objt]] [O]"
|
||||
requirements_cache = ""
|
||||
requirements_cache += req_string
|
||||
if (needs_deletion)
|
||||
qdel(O)
|
||||
|
||||
proc/announce()
|
||||
if (announce_completion)
|
||||
boutput(world, "<B><font color='blue'>[announced_message]</font></B>")
|
||||
|
||||
proc/set_complete()
|
||||
completed = 1
|
||||
logTheThing("debug", null, null, "<B>Marquesas/Progress</B>: Milestone [name] complete.")
|
||||
var/datum/game_mode/construction/C = ticker.mode
|
||||
C.events.notify_milestone_complete(src)
|
||||
|
||||
proc/uncomplete()
|
||||
if (is_room && room_area)
|
||||
var/area/AR = locate(room_area)
|
||||
for (var/turf/T in AR)
|
||||
new /area(T)
|
||||
if (announce_uncompletion)
|
||||
boutput(world, "<B><font color='red'>[uncompleted_message]</font></B>")
|
||||
var/datum/game_mode/construction/C = ticker.mode
|
||||
C.events.notify_milestone_uncomplete(src)
|
||||
logTheThing("debug", null, null, "<B>Marquesas/Progress</B>: Milestone [name] uncompleted.")
|
||||
|
||||
proc/check_uncompletion()
|
||||
if (is_abstract)
|
||||
return
|
||||
if (parent)
|
||||
if (completed && !parent.completed)
|
||||
uncomplete()
|
||||
if (!can_uncomplete)
|
||||
return
|
||||
var/is_complete = check_completion(completed_origin)
|
||||
if (completed && !uncompletion && !is_complete)
|
||||
uncompletion = 1
|
||||
uncompleted_at = ticker.round_elapsed_ticks
|
||||
logTheThing("debug", null, null, "<B>Marquesas/Progress</B>: Milestone [name] uncompleting.")
|
||||
else if (completed && uncompletion && is_complete)
|
||||
uncompletion = 0
|
||||
else if (completed && uncompletion && ticker.round_elapsed_ticks > uncompleted_at + grace_period)
|
||||
completed = 0
|
||||
uncompletion = 0
|
||||
uncomplete()
|
||||
|
||||
proc/check_completion(var/turf/T)
|
||||
if (is_abstract)
|
||||
return
|
||||
if (parent)
|
||||
if (!parent.completed)
|
||||
return
|
||||
if (!required.len)
|
||||
return 1
|
||||
if (istype(get_area(T), /area/shuttle))
|
||||
return 0
|
||||
if (is_room)
|
||||
var/list/temp = identify_room(T)
|
||||
var/minx = 300
|
||||
var/maxx = 0
|
||||
var/miny = 300
|
||||
var/maxy = 0
|
||||
if (temp)
|
||||
var/list/counted = list()
|
||||
for (var/objt in required)
|
||||
counted += objt
|
||||
counted[objt] = 0
|
||||
for (var/turf/Q in temp)
|
||||
if (minx > Q.x)
|
||||
minx = Q.x
|
||||
if (maxx < Q.x)
|
||||
maxx = Q.x
|
||||
if (miny > Q.y)
|
||||
miny = Q.y
|
||||
if (maxy < Q.y)
|
||||
maxy = Q.y
|
||||
for (var/atom/movable/O in Q)
|
||||
if (O.type in counted)
|
||||
counted[O.type]++
|
||||
for (var/objt in required)
|
||||
if (required[objt] > counted[objt])
|
||||
return 0
|
||||
if (maxx - minx + 1 < minimum_width)
|
||||
return 0
|
||||
if (maxy - miny + 1 < minimum_height)
|
||||
return 0
|
||||
if (!completed)
|
||||
completed_space = temp
|
||||
completed_origin = T
|
||||
set_complete()
|
||||
if (room_area)
|
||||
var/datum/game_mode/construction/CN = ticker.mode
|
||||
for (var/turf/Q in completed_space)
|
||||
var/area/AR = get_area(Q)
|
||||
if (AR.type != room_area)
|
||||
if (AR.type in CN.assigned_areas)
|
||||
var/datum/progress/assigned_progress = CN.assigned_areas[AR.type]
|
||||
if (assigned_progress.completed)
|
||||
assigned_progress.uncomplete()
|
||||
if (!istype(AR, /area/shuttle))
|
||||
new room_area(Q)
|
||||
if (!(room_area in CN.assigned_areas))
|
||||
CN.assigned_areas += room_area
|
||||
CN.assigned_areas[room_area] = src
|
||||
announce()
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
else
|
||||
var/list/counted = list()
|
||||
for (var/objt in required)
|
||||
counted += objt
|
||||
counted[objt] = 0
|
||||
for (var/atom/movable/O in world)
|
||||
if (O.type in counted)
|
||||
counted[O.type]++
|
||||
for (var/objt in required)
|
||||
if (required[objt] > counted[objt])
|
||||
return 0
|
||||
if (!completed)
|
||||
completed_origin = T
|
||||
set_complete()
|
||||
announce()
|
||||
return 1
|
||||
|
||||
proc/identify_room(var/turf/T)
|
||||
var/list/affected = list()
|
||||
var/list/next = list()
|
||||
var/list/processed = list()
|
||||
|
||||
next += T
|
||||
processed += T
|
||||
while (next.len)
|
||||
var/turf/C = next[1]
|
||||
next -= C
|
||||
|
||||
affected += C
|
||||
|
||||
if (C.density)
|
||||
continue
|
||||
|
||||
var/dense = 0
|
||||
for (var/obj/O in C)
|
||||
if (istype(O, /obj/machinery/door) || istype(O, /obj/grille) || istype(O, /obj/window) || istype(O, /obj/table))
|
||||
dense = 1
|
||||
break
|
||||
if (dense)
|
||||
continue
|
||||
|
||||
/*var/area/SP = get_area(C)
|
||||
if (SP.name != "Space") // i mean i can't just check for istype(SP, /area)
|
||||
return null*/
|
||||
|
||||
if (istype(C, /turf/space))
|
||||
return null
|
||||
|
||||
var/turf/N = get_step(C, NORTH)
|
||||
if (N && !(N in processed))
|
||||
next += N
|
||||
processed += N
|
||||
|
||||
N = get_step(C, SOUTH)
|
||||
if (N && !(N in processed))
|
||||
next += N
|
||||
processed += N
|
||||
|
||||
N = get_step(C, WEST)
|
||||
if (N && !(N in processed))
|
||||
next += N
|
||||
processed += N
|
||||
|
||||
N = get_step(C, EAST)
|
||||
if (N && !(N in processed))
|
||||
next += N
|
||||
processed += N
|
||||
|
||||
return affected
|
||||
|
||||
proc/process()
|
||||
if (!periodical_check)
|
||||
return
|
||||
if (!completed)
|
||||
check_completion(null)
|
||||
else
|
||||
check_uncompletion()
|
||||
|
||||
/datum/progress/time
|
||||
periodical_check = 1
|
||||
var/elapsed_ticks = 1
|
||||
announce_completion = 1
|
||||
|
||||
check_completion(var/turf/T)
|
||||
var/datum/game_mode/construction/C = ticker.mode
|
||||
if (ticker.round_elapsed_ticks - C.starttime >= elapsed_ticks)
|
||||
announce()
|
||||
set_complete()
|
||||
|
||||
/datum/progress/time/twohours
|
||||
elapsed_ticks = 90000
|
||||
is_abstract = 0
|
||||
name = "2 Hours"
|
||||
announced_message = "<B>10 hours left until construction reset.</B>"
|
||||
|
||||
/datum/progress/time/sixhours
|
||||
elapsed_ticks = 234000
|
||||
is_abstract = 0
|
||||
name = "6 Hours"
|
||||
announced_message = "<B>6 hours left until construction reset.</B>"
|
||||
|
||||
/datum/progress/time/ninehours
|
||||
elapsed_ticks = 342000
|
||||
is_abstract = 0
|
||||
name = "9 Hours"
|
||||
announced_message = "<B>3 hours left until construction reset.</B>"
|
||||
|
||||
/datum/progress/time/tenhours
|
||||
elapsed_ticks = 378000
|
||||
is_abstract = 0
|
||||
name = "10 Hours"
|
||||
announced_message = "<B>2 hours left until construction reset.</B>"
|
||||
|
||||
/datum/progress/time/elevenhours
|
||||
elapsed_ticks = 414000
|
||||
is_abstract = 0
|
||||
name = "11 Hours"
|
||||
announced_message = "<B>1 hours left until construction reset.</B>"
|
||||
|
||||
/datum/progress/time/almostover
|
||||
elapsed_ticks = 432000
|
||||
is_abstract = 0
|
||||
name = "11 Hours and 30 Minutes"
|
||||
announced_message = "<B>30 minutes left until construction reset.</B>"
|
||||
|
||||
/datum/progress/time/almostoverreally
|
||||
elapsed_ticks = 444000
|
||||
is_abstract = 0
|
||||
name = "11 Hours and 50 Minutes"
|
||||
announced_message = "<B>10 minutes left until construction reset.</B>"
|
||||
|
||||
/datum/progress/pods
|
||||
can_uncomplete = 1
|
||||
periodical_check = 1
|
||||
grace_period = 1800
|
||||
var/pod_score_required = 0
|
||||
|
||||
check_completion(var/turf/T)
|
||||
if (parent)
|
||||
if (!parent.completed)
|
||||
return
|
||||
var/pod_score = 0
|
||||
for (var/obj/machinery/vehicle/pod_smooth/P in world)
|
||||
var/score = 0
|
||||
var/multiplier = P.armor_score_multiplier
|
||||
if (P.m_w_system)
|
||||
score += P.m_w_system.weapon_score
|
||||
pod_score += score * multiplier
|
||||
for (var/obj/machinery/vehicle/miniputt/P in world)
|
||||
var/score = 0
|
||||
var/multiplier = P.armor_score_multiplier
|
||||
if (P.m_w_system)
|
||||
score += P.m_w_system.weapon_score
|
||||
pod_score += score * multiplier * 0.5
|
||||
logTheThing("debug", null, null, "<B>Marquesas/Progress</B>: Pod score is [pod_score].")
|
||||
if (pod_score >= pod_score_required)
|
||||
if (!completed)
|
||||
set_complete()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/progress/pods/tier1
|
||||
name = "Pod Armaments Tier 1"
|
||||
is_abstract = 0
|
||||
pod_score_required = 1.7
|
||||
|
||||
/datum/progress/pods/tier2
|
||||
name = "Pod Armaments Tier 2"
|
||||
pod_score_required = 4.5
|
||||
is_abstract = 0
|
||||
parent = /datum/progress/pods/tier1
|
||||
|
||||
/datum/progress/pods/tier3
|
||||
name = "Pod Armaments Tier 3"
|
||||
pod_score_required = 9
|
||||
is_abstract = 0
|
||||
parent = /datum/progress/pods/tier2
|
||||
|
||||
/datum/progress/rooms
|
||||
is_room = 1
|
||||
can_uncomplete = 1
|
||||
announce_completion = 1
|
||||
grace_period = 600
|
||||
|
||||
/datum/progress/rooms/robotics
|
||||
name = "Robotics Lab"
|
||||
is_abstract = 0
|
||||
required = list(/obj/machinery/manufacturer/robotics = 1, /obj/machinery/optable = 1, /obj/machinery/recharge_station = 1)
|
||||
minimum_width = 7
|
||||
minimum_height = 7
|
||||
|
||||
announced_message = "The station now has an operating Robotics lab."
|
||||
uncompleted_message = "The station no longer has an operation Robotics lab!"
|
||||
|
||||
room_area = /area/station/medical/robotics
|
||||
|
||||
/datum/progress/rooms/genetics
|
||||
name = "Genetics Lab"
|
||||
is_abstract = 0
|
||||
required = list(/obj/machinery/computer/cloning = 1, /obj/machinery/computer/genetics = 1, /obj/machinery/genetics_scanner = 1, /obj/machinery/clone_scanner = 1, /obj/machinery/clonepod = 1, /obj/machinery/clonegrinder = 1)
|
||||
minimum_width = 7
|
||||
minimum_height = 7
|
||||
|
||||
announced_message = "The station now has an operating Genetics lab."
|
||||
uncompleted_message = "The station no longer has an operation Genetics lab!"
|
||||
|
||||
room_area = /area/station/medical/research
|
||||
|
||||
/datum/progress/rooms/chemistry
|
||||
name = "Chemistry Lab"
|
||||
is_abstract = 0
|
||||
required = list(/obj/machinery/chem_master = 2, /obj/machinery/chem_dispenser = 2, /obj/machinery/chem_heater = 2, /obj/submachine/chem_extractor = 1, /obj/machinery/vending/monkey = 1)
|
||||
minimum_width = 7
|
||||
minimum_height = 7
|
||||
|
||||
announced_message = "The station now has an operating Chemistry lab."
|
||||
uncompleted_message = "The station no longer has an operation Chemistry lab!"
|
||||
|
||||
room_area = /area/station/chemistry
|
||||
|
||||
/datum/progress/rooms/medbay
|
||||
name = "Medical Bay"
|
||||
is_abstract = 0
|
||||
required = list(/obj/machinery/optable = 1, /obj/machinery/vending/medical = 2)
|
||||
minimum_width = 9
|
||||
minimum_height = 9
|
||||
|
||||
announced_message = "The station now has an operating Medical Bay. Additional supply kits are now available."
|
||||
uncompleted_message = "The station no longer has an operation Medical Bay! Related supply kits are no longer available."
|
||||
|
||||
room_area = /area/station/medical/medbay
|
||||
|
||||
/datum/progress/rooms/mechanics
|
||||
name = "Mechanics Lab"
|
||||
is_abstract = 0
|
||||
required = list(/obj/machinery/rkit = 1, /obj/machinery/manufacturer/mechanic = 1, /obj/machinery/vending/mechanics = 1)
|
||||
minimum_width = 9
|
||||
minimum_height = 9
|
||||
|
||||
announced_message = "The station now has an operating Mechanics lab."
|
||||
uncompleted_message = "The station no longer has an operation Mechanics lab!"
|
||||
|
||||
room_area = /area/station/engine/elect
|
||||
|
||||
/datum/progress/rooms/aicore
|
||||
name = "AI Core"
|
||||
is_abstract = 0
|
||||
required = list(/mob/living/silicon/ai = 1, /obj/machinery/turret/construction = 2, /obj/machinery/turretid/computer = 1)
|
||||
minimum_width = 7
|
||||
minimum_height = 7
|
||||
|
||||
announced_message = "The station now has an operating AI core."
|
||||
uncompleted_message = "The station no longer has an operation AI core!"
|
||||
|
||||
room_area = /area/station/turret_protected/AIbasecore1
|
||||
|
||||
/datum/progress/rooms/cargo_bay
|
||||
name = "Cargo Bay"
|
||||
is_abstract = 0
|
||||
required = list(/obj/supply_pad/incoming = 1, /obj/supply_pad/outgoing = 1, /obj/machinery/computer/special_supply/commerce = 1, /obj/submachine/cargopad = 1)
|
||||
minimum_width = 11
|
||||
minimum_height = 11
|
||||
|
||||
announced_message = "The station now has an operating Cargo Bay. Additional supply kits are now available."
|
||||
uncompleted_message = "The station no longer has an operation Cargo Bay! Related supply kits are no longer available."
|
||||
|
||||
room_area = /area/station/quartermaster/office
|
||||
|
||||
/datum/progress/rooms/hydroponics
|
||||
name = "Hydroponics"
|
||||
is_abstract = 0
|
||||
required = list(/obj/machinery/plantpot = 6, /obj/machinery/vending/hydroponics = 1, /obj/submachine/chem_extractor = 1, /obj/submachine/seed_vendor = 1, /obj/submachine/seed_manipulator = 1)
|
||||
minimum_width = 9
|
||||
minimum_height = 9
|
||||
|
||||
announced_message = "The station now has an operating Hydroponics lab."
|
||||
uncompleted_message = "The station no longer has an operation Hydroponics lab!"
|
||||
|
||||
room_area = /area/station/hydroponics
|
||||
|
||||
@@ -0,0 +1,855 @@
|
||||
/datum/demand_control
|
||||
var/list/commodities = list()
|
||||
var/price_multiplier = 1
|
||||
var/base_price_multiplier = 1
|
||||
var/high_demand_level = 30
|
||||
|
||||
var/workstation_grade = 1
|
||||
|
||||
var/current_demand_level = 30
|
||||
|
||||
var/demand_change_interval = 3000
|
||||
var/last_demand_change = 0
|
||||
var/fluctuates = 1
|
||||
var/static_growth = 0
|
||||
|
||||
var/maximum_demand_level = 120
|
||||
|
||||
var/demand_change_text = null
|
||||
|
||||
New()
|
||||
..()
|
||||
var/new_packs = list()
|
||||
for (var/P in commodities)
|
||||
if (ispath(P))
|
||||
new_packs += new P()
|
||||
else if (istype(P, /datum/commodity))
|
||||
new_packs += P
|
||||
commodities = new_packs
|
||||
|
||||
proc/visibility(var/grade)
|
||||
if (!istype(ticker.mode, /datum/game_mode/construction))
|
||||
return 0
|
||||
if (workstation_grade > grade)
|
||||
return 0
|
||||
if (current_demand_level < high_demand_level * 0.5)
|
||||
return "out-of-stock"
|
||||
return "available"
|
||||
|
||||
proc/fluctuate()
|
||||
current_demand_level += static_growth
|
||||
if (fluctuates)
|
||||
if (current_demand_level < high_demand_level)
|
||||
var/difference = high_demand_level - current_demand_level
|
||||
if (prob(3))
|
||||
current_demand_level = 0
|
||||
else if (prob(50))
|
||||
current_demand_level += rand(difference)
|
||||
else if (prob(75))
|
||||
current_demand_level -= rand(difference)
|
||||
current_demand_level = max(current_demand_level, 0)
|
||||
else
|
||||
current_demand_level = high_demand_level
|
||||
else
|
||||
if (prob(30))
|
||||
current_demand_level = high_demand_level
|
||||
else if (prob(40))
|
||||
current_demand_level = round(current_demand_level / 2)
|
||||
else if (prob(40))
|
||||
current_demand_level = round(current_demand_level * ((100 + rand(100)) / 100))
|
||||
else
|
||||
current_demand_level = (current_demand_level - high_demand_level)
|
||||
if (current_demand_level > maximum_demand_level)
|
||||
current_demand_level = maximum_demand_level
|
||||
adjust_price_multiplier()
|
||||
|
||||
proc/adjust_price_multiplier()
|
||||
if (current_demand_level > high_demand_level * 1.2)
|
||||
price_multiplier = (high_demand_level / current_demand_level) - 0.2
|
||||
else if (current_demand_level > high_demand_level * 0.5)
|
||||
price_multiplier = 1
|
||||
else
|
||||
var/ratio = current_demand_level / (high_demand_level * 0.5)
|
||||
price_multiplier = 0.2 + 0.8 * ratio
|
||||
price_multiplier *= base_price_multiplier
|
||||
|
||||
proc/fulfill(var/datum/commodity/C)
|
||||
if (current_demand_level > 0)
|
||||
current_demand_level--
|
||||
var/profit = price_multiplier * C.baseprice
|
||||
wagesystem.shipping_budget += profit
|
||||
adjust_price_multiplier()
|
||||
return profit
|
||||
|
||||
proc/match_condition(var/obj/O)
|
||||
return null
|
||||
|
||||
proc/is_sellable(var/obj/O)
|
||||
if (istype(O, /obj/storage/crate))
|
||||
return 1
|
||||
|
||||
proc/unlisted_commodities()
|
||||
return null
|
||||
|
||||
/datum/demand_control/artifacts
|
||||
commodities = list()
|
||||
high_demand_level = 20
|
||||
static_growth = 0
|
||||
current_demand_level = 20
|
||||
maximum_demand_level = 20
|
||||
base_price_multiplier = 1
|
||||
|
||||
var/comhandheld
|
||||
var/comlarge
|
||||
|
||||
New()
|
||||
..()
|
||||
comhandheld = new /datum/commodity/smallartifact()
|
||||
comlarge = new /datum/commodity/largeartifact()
|
||||
|
||||
match_condition(var/obj/O)
|
||||
if (istype(O, /obj/item) && O.artifact)
|
||||
return comhandheld
|
||||
else if (O.artifact)
|
||||
return comlarge
|
||||
return null
|
||||
|
||||
is_sellable(var/obj/O)
|
||||
if (match_condition(O))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
unlisted_commodities()
|
||||
return list(comhandheld, comlarge)
|
||||
|
||||
/datum/demand_control/produce
|
||||
commodities = list(/datum/commodity/produce)
|
||||
high_demand_level = 200
|
||||
static_growth = 40
|
||||
current_demand_level = 200
|
||||
maximum_demand_level = 1000
|
||||
base_price_multiplier = 1.5
|
||||
|
||||
/datum/demand_control/herbs
|
||||
commodities = list(/datum/commodity/herbs)
|
||||
high_demand_level = 20
|
||||
static_growth = 10
|
||||
current_demand_level = 20
|
||||
maximum_demand_level = 100
|
||||
base_price_multiplier = 1.5
|
||||
|
||||
/datum/demand_control/gold
|
||||
commodities = list(/datum/commodity/goldbar)
|
||||
high_demand_level = 8
|
||||
static_growth = 0
|
||||
current_demand_level = 10
|
||||
maximum_demand_level = 20
|
||||
base_price_multiplier = 0.5
|
||||
|
||||
/datum/demand_control/goldnuggets
|
||||
commodities = list(/datum/commodity/ore/gold)
|
||||
high_demand_level = 20
|
||||
static_growth = 0
|
||||
current_demand_level = 20
|
||||
maximum_demand_level = 25
|
||||
base_price_multiplier = 0.5
|
||||
|
||||
/datum/demand_control/common_ores
|
||||
commodities = list(/datum/commodity/ore/mauxite, /datum/commodity/ore/pharosium, /datum/commodity/ore/molitz, /datum/commodity/ore/char)
|
||||
high_demand_level = 100
|
||||
static_growth = 20
|
||||
current_demand_level = 100
|
||||
maximum_demand_level = 500
|
||||
base_price_multiplier = 8
|
||||
|
||||
/datum/demand_control/common_valuables
|
||||
commodities = list(/datum/commodity/ore/cobryl)
|
||||
high_demand_level = 50
|
||||
static_growth = 5
|
||||
current_demand_level = 20
|
||||
maximum_demand_level = 100
|
||||
|
||||
/datum/demand_control/alien_ores
|
||||
commodities = list(/datum/commodity/ore/koshmarite, /datum/commodity/ore/viscerite)
|
||||
high_demand_level = 250
|
||||
static_growth = 10
|
||||
current_demand_level = 250
|
||||
maximum_demand_level = 300
|
||||
|
||||
/datum/demand_control/rare_ores
|
||||
commodities = list(/datum/commodity/ore/claretine, /datum/commodity/ore/bohrum)
|
||||
high_demand_level = 100
|
||||
static_growth = 20
|
||||
current_demand_level = 100
|
||||
maximum_demand_level = 500
|
||||
|
||||
/datum/demand_control/special_ores
|
||||
commodities = list(/datum/commodity/ore/cerenkite, /datum/commodity/ore/plasmastone)
|
||||
high_demand_level = 10
|
||||
static_growth = 2
|
||||
current_demand_level = 0
|
||||
maximum_demand_level = 100
|
||||
|
||||
/datum/demand_control/rare_valuables
|
||||
commodities = list(/datum/commodity/ore/syreline)
|
||||
high_demand_level = 25
|
||||
static_growth = 0
|
||||
current_demand_level = 60
|
||||
maximum_demand_level = 100
|
||||
|
||||
/datum/demand_control/rare_crystals
|
||||
commodities = list(/datum/commodity/ore/erebite, /datum/commodity/ore/telecrystal, /datum/commodity/ore/uqill)
|
||||
high_demand_level = 20
|
||||
static_growth = 1
|
||||
fluctuates = 0
|
||||
current_demand_level = 30
|
||||
maximum_demand_level = 50
|
||||
|
||||
/datum/supply_control
|
||||
var/datum/progress/required = null
|
||||
var/maximum_stock = 1
|
||||
var/replenishment_time = 6000
|
||||
var/list/supply_packs = list()
|
||||
|
||||
var/cost_multiplier = 1
|
||||
|
||||
var/initial_stock = 1
|
||||
var/current_stock = 1
|
||||
|
||||
var/next_resupply_at = 0
|
||||
var/next_resupply_text = null
|
||||
|
||||
var/workstation_grade = 1
|
||||
|
||||
proc/update_resupply_text()
|
||||
if (next_resupply_at)
|
||||
next_resupply_text = dstohms(next_resupply_at - ticker.round_elapsed_ticks)
|
||||
else
|
||||
if (next_resupply_text)
|
||||
next_resupply_text = null
|
||||
|
||||
New()
|
||||
..()
|
||||
var/new_packs = list()
|
||||
for (var/P in supply_packs)
|
||||
if (ispath(P))
|
||||
new_packs += new P()
|
||||
else if (istype(P, /datum/supply_packs))
|
||||
new_packs += P
|
||||
supply_packs = new_packs
|
||||
|
||||
proc/visibility(var/grade)
|
||||
if (!istype(ticker.mode, /datum/game_mode/construction))
|
||||
return 0
|
||||
if (workstation_grade > grade)
|
||||
return 0
|
||||
var/datum/game_mode/construction/C = ticker.mode
|
||||
if (required)
|
||||
var/datum/progress/P = locate(required) in C.milestones
|
||||
if (!P)
|
||||
return 0
|
||||
if (!P.completed)
|
||||
return "not-yet-available"
|
||||
if (!current_stock && maximum_stock)
|
||||
return "out-of-stock"
|
||||
return "available"
|
||||
|
||||
proc/is_available(var/grade)
|
||||
if (!istype(ticker.mode, /datum/game_mode/construction))
|
||||
return 0
|
||||
if (workstation_grade > grade)
|
||||
return 0
|
||||
if (!current_stock && maximum_stock)
|
||||
return 0
|
||||
var/datum/game_mode/construction/C = ticker.mode
|
||||
if (required)
|
||||
var/datum/progress/P = locate(required) in C.milestones
|
||||
if (!P)
|
||||
return 0
|
||||
if (!P.completed)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
proc/consume()
|
||||
current_stock--
|
||||
if (maximum_stock && replenishment_time > 0 && !next_resupply_at)
|
||||
next_resupply_at = ticker.round_elapsed_ticks + replenishment_time
|
||||
update_resupply_text()
|
||||
|
||||
/datum/supply_control/crate
|
||||
maximum_stock = 0
|
||||
supply_packs = list(/datum/supply_packs/emptycrate)
|
||||
|
||||
/datum/supply_control/glass_kit
|
||||
maximum_stock = 3
|
||||
supply_packs = list(/datum/supply_packs/glass50)
|
||||
|
||||
/datum/supply_control/metal_kit
|
||||
maximum_stock = 3
|
||||
supply_packs = list(/datum/supply_packs/metal50)
|
||||
|
||||
/datum/supply_control/cable_kit
|
||||
maximum_stock = 3
|
||||
supply_packs = list(/datum/supply_packs/electrical4)
|
||||
|
||||
/datum/supply_control/homing_kit
|
||||
maximum_stock = 3
|
||||
replenishment_time = 18000
|
||||
supply_packs = list(/datum/supply_packs/homing_kit)
|
||||
|
||||
/datum/supply_control/cargo_kit
|
||||
maximum_stock = 2
|
||||
replenishment_time = 18000
|
||||
supply_packs = list(/datum/supply_packs/complex/cargo_kit)
|
||||
|
||||
/datum/supply_control/manufacturer_kit
|
||||
maximum_stock = 2
|
||||
replenishment_time = 18000
|
||||
supply_packs = list(/datum/supply_packs/complex/manufacturer_kit)
|
||||
|
||||
/datum/supply_control/pod_kit
|
||||
maximum_stock = 2
|
||||
replenishment_time = 9000
|
||||
supply_packs = list(/datum/supply_packs/complex/pod_kit)
|
||||
workstation_grade = 2
|
||||
|
||||
/datum/supply_control/ai_kit
|
||||
maximum_stock = 2
|
||||
replenishment_time = 36000
|
||||
supply_packs = list(/datum/supply_packs/complex/ai_kit)
|
||||
workstation_grade = 2
|
||||
|
||||
/datum/supply_control/security_camera
|
||||
maximum_stock = 0
|
||||
supply_packs = list(/datum/supply_packs/complex/security_camera)
|
||||
workstation_grade = 2
|
||||
|
||||
/datum/supply_control/mainframe_kit
|
||||
maximum_stock = 2
|
||||
replenishment_time = 36000
|
||||
supply_packs = list(/datum/supply_packs/complex/mainframe_kit)
|
||||
workstation_grade = 2
|
||||
|
||||
/datum/supply_control/manufacturer_kit
|
||||
maximum_stock = 1
|
||||
replenishment_time = 6000
|
||||
supply_packs = list(/datum/supply_packs/complex/manufacturer_kit)
|
||||
|
||||
/datum/supply_control/elec_kit
|
||||
maximum_stock = 1
|
||||
supply_packs = list(/datum/supply_packs/complex/electronics_kit)
|
||||
|
||||
/datum/supply_control/mini_magnet_kit
|
||||
maximum_stock = 2
|
||||
replenishment_time = 9000
|
||||
supply_packs = list(/datum/supply_packs/complex/mini_magnet_kit)
|
||||
|
||||
/datum/supply_control/magnet_kit
|
||||
maximum_stock = 2
|
||||
replenishment_time = 36000
|
||||
supply_packs = list(/datum/supply_packs/complex/magnet_kit)
|
||||
workstation_grade = 2
|
||||
|
||||
/datum/supply_control/medkits
|
||||
maximum_stock = 1
|
||||
replenishment_time = 6000
|
||||
supply_packs = list(/datum/supply_packs/medicalfirstaid)
|
||||
|
||||
/datum/supply_control/bathroom
|
||||
maximum_stock = 5
|
||||
replenishment_time = 3000
|
||||
supply_packs = list(/datum/supply_packs/medicalfirstaid)
|
||||
|
||||
/datum/supply_control/arc_smelter
|
||||
required = /datum/progress/rooms/cargo_bay
|
||||
maximum_stock = 2
|
||||
replenishment_time = 36000
|
||||
supply_packs = list(/datum/supply_packs/complex/arc_smelter)
|
||||
workstation_grade = 2
|
||||
|
||||
/datum/supply_control/weapon_kit
|
||||
maximum_stock = 3
|
||||
initial_stock = 1
|
||||
replenishment_time = 36000
|
||||
supply_packs = list(/datum/supply_packs/weapons2)
|
||||
|
||||
/datum/supply_control/stun_baton
|
||||
maximum_stock = 3
|
||||
initial_stock = 2
|
||||
replenishment_time = 6000
|
||||
supply_packs = list(/datum/supply_packs/baton)
|
||||
|
||||
/datum/supply_control/administrative_id
|
||||
maximum_stock = 3
|
||||
initial_stock = 2
|
||||
replenishment_time = 6000
|
||||
supply_packs = list(/datum/supply_packs/administrative_id)
|
||||
|
||||
/datum/supply_control/plasmastone
|
||||
maximum_stock = 3
|
||||
initial_stock = 2
|
||||
replenishment_time = 18000
|
||||
supply_packs = list(/datum/supply_packs/plasmastone)
|
||||
|
||||
/datum/supply_control/banking
|
||||
required = /datum/progress/rooms/cargo_bay
|
||||
maximum_stock = 2
|
||||
initial_stock = 2
|
||||
workstation_grade = 2
|
||||
replenishment_time = 18000
|
||||
supply_packs = list(/datum/supply_packs/banking_kit)
|
||||
|
||||
/datum/supply_control/basic_power
|
||||
required = /datum/progress/rooms/cargo_bay
|
||||
maximum_stock = 2
|
||||
initial_stock = 2
|
||||
workstation_grade = 2
|
||||
replenishment_time = 18000
|
||||
supply_packs = list(/datum/supply_packs/complex/basic_power_kit)
|
||||
|
||||
/datum/supply_control/id_computer
|
||||
required = /datum/progress/rooms/cargo_bay
|
||||
maximum_stock = 2
|
||||
initial_stock = 2
|
||||
workstation_grade = 2
|
||||
replenishment_time = 18000
|
||||
supply_packs = list(/datum/supply_packs/id_computer)
|
||||
|
||||
/datum/supply_control/medical
|
||||
required = /datum/progress/rooms/cargo_bay
|
||||
maximum_stock = 2
|
||||
initial_stock = 2
|
||||
workstation_grade = 2
|
||||
replenishment_time = 18000
|
||||
supply_packs = list(/datum/supply_packs/complex/medical_kit)
|
||||
|
||||
/datum/supply_control/robotics
|
||||
required = /datum/progress/rooms/medbay
|
||||
maximum_stock = 2
|
||||
initial_stock = 2
|
||||
workstation_grade = 2
|
||||
replenishment_time = 18000
|
||||
supply_packs = list(/datum/supply_packs/complex/robotics_kit)
|
||||
|
||||
/datum/supply_control/genetics
|
||||
required = /datum/progress/rooms/medbay
|
||||
maximum_stock = 2
|
||||
initial_stock = 2
|
||||
workstation_grade = 2
|
||||
replenishment_time = 18000
|
||||
supply_packs = list(/datum/supply_packs/complex/genetics_kit)
|
||||
|
||||
/datum/supply_control/artlab
|
||||
maximum_stock = 2
|
||||
initial_stock = 2
|
||||
workstation_grade = 2
|
||||
replenishment_time = 18000
|
||||
supply_packs = list(/datum/supply_packs/complex/artlab_kit)
|
||||
|
||||
/datum/supply_control/telesci
|
||||
maximum_stock = 2
|
||||
initial_stock = 2
|
||||
workstation_grade = 2
|
||||
replenishment_time = 18000
|
||||
supply_packs = list(/datum/supply_packs/complex/telescience_kit)
|
||||
|
||||
/datum/supply_control/defense
|
||||
maximum_stock = 5
|
||||
initial_stock = 0
|
||||
replenishment_time = 18000
|
||||
supply_packs = list(/datum/supply_packs/complex/turret_kit)
|
||||
|
||||
/datum/supply_control/fueltank
|
||||
maximum_stock = 1
|
||||
initial_stock = 1
|
||||
replenishment_time = 18000
|
||||
supply_packs = list(/datum/supply_packs/fueltank)
|
||||
|
||||
/datum/supply_control/watertank
|
||||
maximum_stock = 1
|
||||
initial_stock = 1
|
||||
replenishment_time = 18000
|
||||
supply_packs = list(/datum/supply_packs/watertank)
|
||||
|
||||
/datum/supply_control/compostbin
|
||||
maximum_stock = 1
|
||||
initial_stock = 1
|
||||
replenishment_time = 18000
|
||||
supply_packs = list(/datum/supply_packs/compostbin)
|
||||
|
||||
/datum/supply_control/telecrystal
|
||||
maximum_stock = 6
|
||||
initial_stock = 4
|
||||
replenishment_time = 18000
|
||||
supply_packs = list(/datum/supply_packs/telecrystal)
|
||||
|
||||
/datum/supply_control/telecrystal_bulk
|
||||
maximum_stock = 3
|
||||
initial_stock = 2
|
||||
replenishment_time = 36000
|
||||
supply_packs = list(/datum/supply_packs/telecrystal_bulk)
|
||||
|
||||
/datum/supply_control/janitor
|
||||
maximum_stock = 2
|
||||
initial_stock = 2
|
||||
replenishment_time = 2500
|
||||
supply_packs = list(/datum/supply_packs/janitor)
|
||||
|
||||
/obj/supply_pad
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "pad0"
|
||||
name = "supply pad"
|
||||
desc = "A pad used to teleport goods between Central Command and a survey outpost. Requires a telecrystal to function."
|
||||
density = 0
|
||||
anchored = 1
|
||||
opacity = 0
|
||||
|
||||
var/has_crystal = 0
|
||||
var/direction = 0 // 0 = incoming, 1 = outgoing
|
||||
var/obj/machinery/computer/linked = null
|
||||
|
||||
var/charge = 100
|
||||
var/recharge_rate = 1
|
||||
|
||||
proc/is_ready()
|
||||
return has_crystal && charge == 100
|
||||
|
||||
proc/used()
|
||||
charge = 0
|
||||
has_crystal--
|
||||
spawn(0)
|
||||
while (charge < 100)
|
||||
charge++
|
||||
sleep(1)
|
||||
|
||||
examine()
|
||||
..()
|
||||
boutput(usr, "<span style=\"color:blue\">The pad is currently at [charge]% charge.</span>")
|
||||
if (has_crystal)
|
||||
boutput(usr, "<span style=\"color:blue\">The pad is complete with a telecrystal.</span>")
|
||||
else
|
||||
boutput(usr, "<span style=\"color:red\">The pad's telecrystal socket is empty!</span>")
|
||||
|
||||
attackby(var/obj/item/I as obj, user as mob)
|
||||
if (istype(I, /obj/item/raw_material/telecrystal))
|
||||
qdel(I)
|
||||
has_crystal++
|
||||
boutput(user, "<span style=\"color:blue\">You plug the telecrystal into the teleportation pad.</span>")
|
||||
|
||||
ex_act()
|
||||
return
|
||||
meteorhit()
|
||||
return
|
||||
bullet_act()
|
||||
return
|
||||
|
||||
/obj/supply_pad/incoming
|
||||
name = "Incoming supply pad"
|
||||
direction = 0
|
||||
mats = 10
|
||||
|
||||
/obj/supply_pad/outgoing
|
||||
name = "Outgoing supply pad"
|
||||
direction = 1
|
||||
mats = 10
|
||||
|
||||
/obj/machinery/computer/special_supply
|
||||
// This is a grade 1 workstation. Contains bare-bones supplies.
|
||||
name = "Special Supply Computer"
|
||||
icon = 'icons/obj/computer.dmi'
|
||||
icon_state = "QMcom"
|
||||
density = 1
|
||||
anchored = 1
|
||||
opacity = 0
|
||||
|
||||
var/obj/supply_pad/in_target
|
||||
var/obj/supply_pad/out_target
|
||||
|
||||
var/static/list/sellables_cache = list()
|
||||
var/static/list/unsellables_cache = list()
|
||||
var/static/list/dccache = list()
|
||||
var/static/list/comcache = list()
|
||||
|
||||
var/message = null
|
||||
|
||||
var/mode = 0
|
||||
var/workstation_grade = 1
|
||||
|
||||
var/has_battery_power = 1
|
||||
|
||||
commerce
|
||||
// Grade 2 workstation. No trader contact, contains the full NT catalog.
|
||||
name = "Commerce Computer"
|
||||
workstation_grade = 2
|
||||
has_battery_power = 0
|
||||
|
||||
ex_act()
|
||||
return
|
||||
meteorhit()
|
||||
return
|
||||
bullet_act()
|
||||
return
|
||||
|
||||
proc/recheck()
|
||||
for (var/obj/supply_pad/S in orange(1, src))
|
||||
if (S.direction && !out_target)
|
||||
out_target = S
|
||||
else if (!S.direction && !in_target)
|
||||
in_target = S
|
||||
if (!out_target)
|
||||
var/obj/supply_pad/outgoing/OUT = locate() in range(1, src)
|
||||
if (OUT)
|
||||
out_target = OUT
|
||||
if (!in_target)
|
||||
var/obj/supply_pad/incoming/IN = locate() in range(1, src)
|
||||
if (IN)
|
||||
in_target = IN
|
||||
|
||||
New()
|
||||
..()
|
||||
spawn(50)
|
||||
recheck()
|
||||
|
||||
proc/is_sellable(var/obj/O)
|
||||
if (!istype(O))
|
||||
return 0
|
||||
if (O.type in sellables_cache)
|
||||
return 1
|
||||
if (O.type in unsellables_cache)
|
||||
return 0
|
||||
var/datum/game_mode/construction/C = ticker.mode
|
||||
for (var/datum/demand_control/DQ in C.special_demand_control)
|
||||
if (DQ.is_sellable(O))
|
||||
sellables_cache += O.type
|
||||
return 1
|
||||
unsellables_cache += O.type
|
||||
return 0
|
||||
|
||||
proc/do_sell(var/obj/Q)
|
||||
var/datum/game_mode/construction/C = ticker.mode
|
||||
var/datum/demand_control/DCO = null
|
||||
var/datum/commodity/COM = null
|
||||
if (Q.type in dccache)
|
||||
DCO = dccache[Q.type]
|
||||
COM = comcache[Q.type]
|
||||
else
|
||||
for (var/datum/demand_control/DQ in C.special_demand_control)
|
||||
for (var/datum/commodity/CO in DQ.commodities)
|
||||
if (istype(Q, CO.comtype))
|
||||
DCO = DQ
|
||||
COM = CO
|
||||
dccache[Q.type] = DCO
|
||||
comcache[Q.type] = COM
|
||||
break
|
||||
if (!DCO)
|
||||
COM = DQ.match_condition(Q)
|
||||
if (COM)
|
||||
DCO = DQ
|
||||
if (DCO)
|
||||
break
|
||||
if (DCO)
|
||||
return DCO.fulfill(COM)
|
||||
return 0
|
||||
|
||||
Topic(href, href_list)
|
||||
if (!usr in range(1))
|
||||
return
|
||||
if (!ticker)
|
||||
return
|
||||
if (!ticker.mode)
|
||||
return
|
||||
if (!powered() && !has_battery_power)
|
||||
return
|
||||
if (href_list["recheck"])
|
||||
recheck()
|
||||
if (href_list["purchase"] && href_list["control"])
|
||||
if (!in_target)
|
||||
message = "<span class='bad'>Cannot lock targeting vector, aborting purchase.</span>"
|
||||
else
|
||||
if (!in_target.is_ready())
|
||||
if (!in_target.has_crystal)
|
||||
message = "<span class='bad'>The supply pad requires a telecrystal to function.</span>"
|
||||
else
|
||||
message = "<span class='bad'>The supply pad is recharging.</span>"
|
||||
else
|
||||
var/turf/T = get_turf(in_target)
|
||||
for (var/atom/movable/O in T)
|
||||
if ((O != in_target && O.density) || istype(O, /mob/living))
|
||||
message = "<span class='bad'>Please clear the teleportation target area.</span>"
|
||||
attack_hand(usr)
|
||||
return
|
||||
var/datum/supply_packs/P = locate(href_list["purchase"])
|
||||
var/datum/supply_control/C = locate(href_list["control"])
|
||||
if (C.is_available(workstation_grade))
|
||||
if (P.cost <= wagesystem.shipping_budget)
|
||||
in_target.used()
|
||||
C.consume()
|
||||
wagesystem.shipping_budget -= P.cost
|
||||
P.create(T)
|
||||
showswirl(T)
|
||||
message = "<span class='good'>Purchase complete. Cost: [P.cost] credits.</span>"
|
||||
else
|
||||
message = "<span class='bad'>Insufficient funds in budget to purchase that item.</span>"
|
||||
else
|
||||
message = "<span class='bad'>That item is currently not available.</span>"
|
||||
else if (href_list["sell"])
|
||||
if (!out_target)
|
||||
message = "<span class='bad'>Cannot lock targeting vector, aborting purchase.</span>"
|
||||
else
|
||||
if (!out_target.is_ready())
|
||||
if (!out_target.has_crystal)
|
||||
message = "<span class='bad'>The supply pad requires a telecrystal to function.</span>"
|
||||
else
|
||||
message = "<span class='bad'>The supply pad is recharging.</span>"
|
||||
else
|
||||
var/turf/T = get_turf(out_target)
|
||||
var/obj/CR = null
|
||||
for (var/atom/movable/O in T)
|
||||
if (O == src)
|
||||
continue
|
||||
if (is_sellable(O))
|
||||
CR = O
|
||||
else if (O.density || istype(O, /mob/living) || istype(O, /obj/item))
|
||||
message = "<span class='bad'>Please remove all objects and lifeforms not being sold from the telepad.</span>"
|
||||
attack_hand(usr)
|
||||
return
|
||||
if (!CR)
|
||||
message = "<span class='bad'>No objects slated for selling found on the pad.</span>"
|
||||
else
|
||||
var/profit = 0
|
||||
for (var/obj/item/Q in CR)
|
||||
if (!istype(Q))
|
||||
Q.set_loc(T)
|
||||
for (var/mob/M in viewers(Q))
|
||||
boutput(M, "<span style=\"color:blue\">[Q] pops out of [CR]!</span>")
|
||||
else
|
||||
profit += do_sell(Q)
|
||||
qdel(Q)
|
||||
profit += do_sell(CR)
|
||||
message = "<span class='good'>Sold [CR] from outgoing pad. Profit: [profit] credits</span>"
|
||||
qdel(CR)
|
||||
showswirl(get_turf(out_target))
|
||||
out_target.used()
|
||||
else if (href_list["mode"])
|
||||
mode = text2num(href_list["mode"])
|
||||
attack_hand(usr)
|
||||
|
||||
attack_hand(var/mob/user)
|
||||
if (!ticker || !ticker.mode)
|
||||
return
|
||||
if (!istype(ticker.mode, /datum/game_mode/construction))
|
||||
return
|
||||
if (!in_target || !out_target)
|
||||
recheck()
|
||||
var/datum/game_mode/construction/C = ticker.mode
|
||||
var/is_powered = src.powered()
|
||||
if (!is_powered && !has_battery_power)
|
||||
user << browse("The screen is blank.", "window=specsupply;size=500x400")
|
||||
return
|
||||
var/interface = {"<html><head><style>
|
||||
table.orderable {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
table.orderable thead tr {
|
||||
background-color: #F0DC82;
|
||||
}
|
||||
table.orderable tr.out-of-stock {
|
||||
background-color: #FF6666;
|
||||
}
|
||||
table.orderable tr.not-yet-available {
|
||||
background-color: #999999;
|
||||
}
|
||||
table.orderable td.purchase {
|
||||
text-align: right;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
h2 {
|
||||
margin-left: 5px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.bad {
|
||||
color: red;
|
||||
}
|
||||
.good {
|
||||
color: blue;
|
||||
}
|
||||
</style></head><body>"}
|
||||
interface += "<h2>Survey Supply Console</h2>"
|
||||
if (!is_powered)
|
||||
interface += "<span class='bad'><b>Warning:</b> workstation operating off battery power.<br><br>"
|
||||
if (message)
|
||||
interface += "[message]<br><br>"
|
||||
interface += "<strong>Expedition budget:</strong> [wagesystem.shipping_budget] credits<br>"
|
||||
if (!in_target)
|
||||
interface += "<span class='bad'>Incoming supply pad not detected. <a href='?src=\ref[src];recheck=1'>Re-check</a></span><br>"
|
||||
else
|
||||
if (in_target.has_crystal == 0)
|
||||
interface += "<span class='bad'>Incoming supply pad telecrystal storage depleted.</span><br>"
|
||||
else if (in_target.charge < 100)
|
||||
interface += "<span class='bad'>Incoming supply pad is recharging. Current charge: [in_target.charge]%.</span><br>"
|
||||
else
|
||||
interface += "<span class='good'>Incoming supply pad is ready. Available crystals: [in_target.has_crystal].</span><br>"
|
||||
if (!out_target)
|
||||
interface += "<span class='bad'>Outgoing supply pad not detected. <a href='?src=\ref[src];recheck=1'>Re-check</a></span><br>"
|
||||
else
|
||||
if (out_target.has_crystal == 0)
|
||||
interface += "<span class='bad'>Outgoing supply pad telecrystal storage depleted.</span><br>"
|
||||
else if (out_target.charge < 100)
|
||||
interface += "<span class='bad'>Outgoing supply pad is recharging. Current charge: [out_target.charge]%.</span><br>"
|
||||
else
|
||||
interface += "<span class='good'>Outgoing supply pad is ready. Available crystals: [out_target.has_crystal].</span><br>"
|
||||
if (mode == 0)
|
||||
interface += "<strong>Purchase items</strong> | <a href='?src=\ref[src];mode=1'>View market demand</a> | <a href='?src=\ref[src];sell=1'>Sell goods</a><br>"
|
||||
interface += "<table class='orderable'><thead><tr><th>Item name and contents</th><th>Stock</th><th>Cost</th><th>Purchase</th></tr></thead>"
|
||||
interface += "<tbody>"
|
||||
for (var/datum/supply_control/S in C.special_supply_control)
|
||||
var/vis = S.visibility(workstation_grade)
|
||||
if (vis)
|
||||
for (var/datum/supply_packs/P in S.supply_packs)
|
||||
interface += "<tr class='[vis]'><td><strong>[P.name]</strong><br>[P.desc]"
|
||||
if (S.next_resupply_text)
|
||||
interface += "<br><em>Projected stock update in [S.next_resupply_text]</em>"
|
||||
interface += "</td>"
|
||||
if (S.maximum_stock)
|
||||
interface += "<td>[S.current_stock]</td>"
|
||||
else
|
||||
interface += "<td> </td>"
|
||||
interface += "<td>[P.cost * S.cost_multiplier]</td>"
|
||||
interface += "<td class='purchase'>"
|
||||
if (S.is_available(workstation_grade) && in_target)
|
||||
interface += "<a href='?src=\ref[src];purchase=\ref[P];control=\ref[S]'>Buy</a>"
|
||||
interface += "</td></tr>"
|
||||
interface += "</tbody></table>"
|
||||
else
|
||||
interface += "<a href='?src=\ref[src];mode=0'>Purchase items</a> | <strong>View market demand</strong> | <a href='?src=\ref[src];sell=1'>Sell goods</a><br>"
|
||||
interface += "<table class='orderable'><thead><tr><th>Demanded commodity</th><th>Price per unit</th><th>Demand level</th></thead>"
|
||||
for (var/datum/demand_control/D in C.special_demand_control)
|
||||
var/vis = D.visibility(workstation_grade)
|
||||
if (vis)
|
||||
var/list/all_commodities = D.unlisted_commodities()
|
||||
if (!all_commodities)
|
||||
all_commodities = list()
|
||||
all_commodities += D.commodities
|
||||
for (var/datum/commodity/CO in all_commodities)
|
||||
var/DLI = null
|
||||
if (D.current_demand_level > D.high_demand_level)
|
||||
DLI = "high"
|
||||
else if (D.current_demand_level > D.high_demand_level * 0.7)
|
||||
DLI = "normal"
|
||||
else if (D.current_demand_level > D.high_demand_level * 0.4)
|
||||
DLI = "low"
|
||||
else
|
||||
DLI = "very low"
|
||||
interface += "<tr class='[vis]'><td>[CO.comname]"
|
||||
if (D.demand_change_text)
|
||||
interface += "<br><em>Projected market shift in [D.demand_change_text]</em>"
|
||||
interface += "</td><td>[CO.baseprice * D.price_multiplier]</td><td>[DLI]</td></tr>"
|
||||
interface += "<tbody>"
|
||||
|
||||
interface += "</tbody></table>"
|
||||
interface += "</body></html>"
|
||||
user << browse(interface, "window=specsupply;size=500x400")
|
||||
@@ -0,0 +1,752 @@
|
||||
// hack of the century
|
||||
/obj/smes_spawner
|
||||
name = "power storage unit"
|
||||
icon = 'icons/obj/power.dmi'
|
||||
icon_state = "smes"
|
||||
density = 1
|
||||
anchored = 1
|
||||
New()
|
||||
spawn(10)
|
||||
var/obj/term = new /obj/machinery/power/terminal(get_step(get_turf(src), dir))
|
||||
term.dir = get_dir(get_turf(term), src)
|
||||
new /obj/machinery/power/smes(get_turf(src))
|
||||
qdel(src)
|
||||
|
||||
/obj/ai_frame
|
||||
name = "Asimov 5 Artifical Intelligence"
|
||||
desc = "An artificial intelligence unit which requires the brain of a living organism to function as a neural processor."
|
||||
icon = 'icons/mob/ai.dmi'
|
||||
icon_state = "ai"
|
||||
anchored = 0
|
||||
density = 1
|
||||
opacity = 0
|
||||
|
||||
var/processing = 0
|
||||
|
||||
New()
|
||||
..()
|
||||
src.overlays += image('icons/mob/ai.dmi', "topopen")
|
||||
src.overlays += image('icons/mob/ai.dmi', "batterymode")
|
||||
|
||||
attackby(var/obj/item/I as obj, user as mob)
|
||||
if (istype(I, /obj/item/organ/brain) && !processing)
|
||||
processing = 1
|
||||
var/valid = 0
|
||||
var/obj/item/organ/brain/B = I
|
||||
if(B.owner)
|
||||
if(B.owner.current)
|
||||
if(B.owner.current.client)
|
||||
valid = 1
|
||||
if (!valid)
|
||||
boutput(user, "<span style=\"color:red\">This brain doesn't look any good to use!</span>")
|
||||
processing = 0
|
||||
return
|
||||
var/mob/M = B.owner.current
|
||||
M.set_loc(get_turf(src))
|
||||
var/mob/living/silicon/ai/TheAI = M.AIize(0, 1)
|
||||
TheAI.set_loc(src)
|
||||
src.loc = null
|
||||
B.set_loc(TheAI)
|
||||
TheAI.brain = B
|
||||
TheAI.anchored = 0
|
||||
TheAI.dismantle_stage = 3
|
||||
TheAI.update_appearance()
|
||||
qdel(src)
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/turret/construction
|
||||
power_usage = 250
|
||||
var/obj/machinery/turretid/computer/control = null
|
||||
var/firesat = "humanoids"
|
||||
override_area_bullshit = 1
|
||||
|
||||
process()
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
..()
|
||||
if(stat & NOPOWER)
|
||||
return
|
||||
if(lastfired && world.time - lastfired < shot_delay)
|
||||
return
|
||||
lastfired = world.time
|
||||
if (src.cover==null)
|
||||
src.cover = new /obj/machinery/turretcover(src.loc)
|
||||
power_usage = 250
|
||||
var/list/targets = list()
|
||||
if (firesat == "humanoids")
|
||||
for (var/mob/living/carbon/M in view(5, src))
|
||||
if (M.stat != 2)
|
||||
targets += M
|
||||
else if (firesat == "critters")
|
||||
for (var/obj/critter/C in view(5, src))
|
||||
if (C.alive)
|
||||
targets += C
|
||||
if (targets.len > 0)
|
||||
if (!isPopping())
|
||||
if (isDown())
|
||||
popUp()
|
||||
power_usage = 750
|
||||
else
|
||||
var/target = pick(targets)
|
||||
src.dir = get_dir(src, target)
|
||||
if (src.enabled)
|
||||
power_usage = 750
|
||||
src.shootAt(target)
|
||||
|
||||
/obj/machinery/turretid/computer
|
||||
var/list/turrets = list()
|
||||
icon = 'icons/obj/computer.dmi'
|
||||
icon_state = "turret3"
|
||||
density = 1
|
||||
var/firesat = "humanoids"
|
||||
|
||||
New()
|
||||
..()
|
||||
scan()
|
||||
|
||||
proc/scan()
|
||||
for (var/obj/machinery/turret/construction/T in range(src, 7))
|
||||
if (!T.control && !(T in turrets))
|
||||
turrets += T
|
||||
T.control = src
|
||||
|
||||
attack_hand(var/mob/user as mob)
|
||||
if ( (get_dist(src, user) > 1 ))
|
||||
if (!istype(user, /mob/living/silicon))
|
||||
boutput(user, text("Too far away."))
|
||||
user.machine = null
|
||||
user << browse(null, "window=turretid")
|
||||
return
|
||||
|
||||
user.machine = src
|
||||
var/t = "<TT><B>Turret Control Panel</B><BR><B>Controlled turrets:</B> [turrets.len] (<A href='?src=\ref[src];rescan=1'>Rescan</a>)<HR>"
|
||||
|
||||
if(src.locked && (!istype(user, /mob/living/silicon)))
|
||||
t += "<I>(Swipe ID card to unlock control panel.)</I><BR>"
|
||||
else
|
||||
t += text("Turrets [] - <A href='?src=\ref[];toggleOn=1'>[]?</a><br><br>", src.enabled?"activated":"deactivated", src, src.enabled?"Disable":"Enable")
|
||||
t += text("Currently firing at <A href='?src=\ref[];firesAt=1'>[]</a><br><br>", src, firesat)
|
||||
t += text("Currently set for [] - <A href='?src=\ref[];toggleLethal=1'>Change to []?</a><br><br>", src.lethal?"lethal":"stun repeatedly", src, src.lethal?"Stun repeatedly":"Lethal")
|
||||
|
||||
user << browse(t, "window=turretid")
|
||||
onclose(user, "turretid")
|
||||
|
||||
|
||||
Topic(href, href_list)
|
||||
if (src.locked)
|
||||
if (!istype(usr, /mob/living/silicon))
|
||||
boutput(usr, "Control panel is locked!")
|
||||
return
|
||||
if (href_list["rescan"])
|
||||
scan()
|
||||
if (href_list["firesAt"])
|
||||
cycleFiresAt()
|
||||
updateFiresAt()
|
||||
..()
|
||||
|
||||
proc/cycleFiresAt()
|
||||
if (!src.locked)
|
||||
switch (firesat)
|
||||
if ("humanoids")
|
||||
firesat = "critters"
|
||||
if ("critters")
|
||||
firesat = "humanoids"
|
||||
|
||||
proc/updateFiresAt()
|
||||
for (var/obj/machinery/turret/construction/aTurret in turrets)
|
||||
aTurret.firesat = firesat
|
||||
|
||||
updateTurrets()
|
||||
if (src.enabled)
|
||||
if (src.lethal)
|
||||
icon_state = "turret2"
|
||||
else
|
||||
icon_state = "turret3"
|
||||
else
|
||||
icon_state = "turret1"
|
||||
|
||||
for (var/obj/machinery/turret/construction/aTurret in turrets)
|
||||
aTurret.setState(enabled, lethal)
|
||||
|
||||
/obj/item/room_marker
|
||||
name = "Room Designator"
|
||||
icon = 'icons/obj/construction.dmi'
|
||||
icon_state = "room"
|
||||
item_state = "gun"
|
||||
w_class = 2
|
||||
|
||||
mats = 6
|
||||
var/using = 0
|
||||
var/datum/progress/designated = null
|
||||
|
||||
attack_self(var/mob/user)
|
||||
if (!(ticker && ticker.mode && istype(ticker.mode, /datum/game_mode/construction)))
|
||||
boutput(user, "<span style=\"color:red\">You can only use this tool in construction mode.</span>")
|
||||
var/datum/game_mode/construction/C = ticker.mode
|
||||
var/list/pickable = list()
|
||||
for (var/datum/progress/P in C.milestones)
|
||||
if (P.is_room && !P.completed)
|
||||
pickable += P
|
||||
if (!pickable.len)
|
||||
boutput(user, "<span style=\"color:red\">No rooms available for designation.</span>")
|
||||
designated = input("Which room would you like to designate?", "Room", pickable[1]) in pickable
|
||||
boutput(user, "<span style=\"color:blue\">Using this tool will now designate the room: [designated]. A room is surrounded by dense objects or walls on all sides.</span>")
|
||||
if (designated.minimum_width)
|
||||
boutput(user, "<span style=\"color:blue\">The room must be at least [designated.minimum_width] tiles wide (including the walls).</span>")
|
||||
if (designated.minimum_height)
|
||||
boutput(user, "<span style=\"color:blue\">The room must be at least [designated.minimum_height] tiles high (including the walls).</span>")
|
||||
if (designated.requirements_cache)
|
||||
boutput(user, "<span style=\"color:blue\">The room must contain at least the following objects: [designated.requirements_cache].</span>")
|
||||
|
||||
afterattack(atom/target as mob|obj|turf|area, mob/user as mob)
|
||||
if (!isturf(target))
|
||||
return
|
||||
if (!designated)
|
||||
boutput(user, "<span style=\"color:red\">No designated room selected.</span>")
|
||||
return
|
||||
if (designated.completed)
|
||||
boutput(user, "<span style=\"color:blue\">The designated room already exists.</span>")
|
||||
designated = null
|
||||
return
|
||||
if (using)
|
||||
boutput(user, "<span style=\"color:red\">Already verifying a room. Please wait.</span>")
|
||||
return
|
||||
using = 1
|
||||
boutput(user, "<span style=\"color:blue\">Designating room.</span>")
|
||||
spawn(0)
|
||||
if (designated.check_completion(target))
|
||||
boutput(user, "<span style=\"color:blue\">Designation successful, room matches required parameters.</span>")
|
||||
//new /obj/machinery/power/apc(get_turf(target))
|
||||
//boutput(user, "<span style=\"color:red\">Yes I am aware that that APC is in a shit place. You will have to make do until I can actually finish working on power stuff okay???</span>")
|
||||
designated = null
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">Designation failed.</span>")
|
||||
using = 0
|
||||
|
||||
/obj/item/clothing/glasses/construction
|
||||
name = "Construction Visualizer"
|
||||
icon_state = "meson"
|
||||
item_state = "glasses"
|
||||
mats = 6
|
||||
desc = "The latest technology in viewing live blueprints."
|
||||
|
||||
/obj/item/material_shaper
|
||||
name = "Material Shaper"
|
||||
icon = 'icons/obj/construction.dmi'
|
||||
icon_state = "shaper"
|
||||
item_state = "gun"
|
||||
mats = 6
|
||||
|
||||
var/mode = 0
|
||||
var/datum/material/metal = null
|
||||
var/metal_count = 0
|
||||
var/datum/material/glass = null
|
||||
var/glass_count = 0
|
||||
|
||||
var/processing = 0
|
||||
|
||||
w_class = 2
|
||||
|
||||
var/sound/sound_process = sound('sound/effects/pop.ogg')
|
||||
var/sound/sound_grump = sound('sound/machines/buzz-two.ogg')
|
||||
|
||||
proc/determine_material(var/obj/item/material_piece/D, mob/user as mob)
|
||||
var/datum/material/DM = D.material
|
||||
var/which = null
|
||||
if ((DM.material_flags & MATERIAL_METAL) && (DM.material_flags & MATERIAL_CRYSTAL))
|
||||
var/be_metal = 0
|
||||
var/be_glass = 0
|
||||
if (!metal)
|
||||
be_metal = 1
|
||||
else if (metal.mat_id == DM.mat_id)
|
||||
be_metal = 1
|
||||
if (!glass)
|
||||
be_glass = 1
|
||||
else if (glass.mat_id == DM.mat_id)
|
||||
be_glass = 1
|
||||
if (be_metal && be_glass)
|
||||
which = input("Use [D] as?", "Pick", null) in list("metal", "glass")
|
||||
else if (be_metal)
|
||||
which = "metal"
|
||||
else if (be_glass)
|
||||
which = "glass"
|
||||
else
|
||||
playsound(src.loc, sound_grump, 40, 1)
|
||||
boutput(user, "<span style=\"color:red\">[D] incompatible with current metal or glass.</span>")
|
||||
return null
|
||||
else if (DM.material_flags & MATERIAL_METAL)
|
||||
if (!metal)
|
||||
which = "metal"
|
||||
else if (metal.mat_id == DM.mat_id)
|
||||
which = "metal"
|
||||
else
|
||||
playsound(src.loc, sound_grump, 40, 1)
|
||||
boutput(user, "<span style=\"color:red\">[D] incompatible with current metal.</span>")
|
||||
return null
|
||||
else if (DM.material_flags & MATERIAL_CRYSTAL)
|
||||
if (!glass)
|
||||
which = "glass"
|
||||
else if (glass.mat_id == DM.mat_id)
|
||||
which = "glass"
|
||||
else
|
||||
playsound(src.loc, sound_grump, 40, 1)
|
||||
boutput(user, "<span style=\"color:red\">[D] incompatible with current glass.</span>")
|
||||
return null
|
||||
else
|
||||
playsound(src.loc, sound_grump, 40, 1)
|
||||
boutput(user, "<span style=\"color:red\">[D] is not a metal or glass material.</span>")
|
||||
if (!which)
|
||||
playsound(src.loc, sound_grump, 40, 1)
|
||||
boutput(user, "<span style=\"color:red\">[D] is not a metal or glass material.</span>")
|
||||
|
||||
if (which == "metal" && !metal)
|
||||
metal = DM
|
||||
else if (which == "glass" && !glass)
|
||||
glass = DM
|
||||
|
||||
return which
|
||||
|
||||
proc/has_materials(var/metalc, var/glassc)
|
||||
if (metal_count < metalc || glass_count < glassc)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
proc/use_materials(var/metalc, var/glassc)
|
||||
metal_count -= metalc
|
||||
glass_count -= glassc
|
||||
if (metal_count <= 0)
|
||||
metal = null
|
||||
if (glass_count <= 0)
|
||||
glass = null
|
||||
boutput(usr, "<span style=\"color:blue\">The shaper has [metal_count] units of metal and [glass_count] units of glass left.</span>")
|
||||
|
||||
examine()
|
||||
..()
|
||||
if (metal)
|
||||
boutput(usr, "<span style=\"color:blue\">Metal: [metal_count] units of [metal.name].</span>")
|
||||
else
|
||||
boutput(usr, "<span style=\"color:red\">Metal: 0 units.</span>")
|
||||
|
||||
if (glass)
|
||||
boutput(usr, "<span style=\"color:blue\">Glass: [glass_count] units of [glass.name].</span>")
|
||||
else
|
||||
boutput(usr, "<span style=\"color:red\">Glass: 0 units</span>")
|
||||
|
||||
attack_self(mob/user as mob)
|
||||
mode = !mode
|
||||
if (!mode)
|
||||
boutput(user, "<span style=\"color:blue\">Mode: marking/unmarking plans for grille and glass structures.</span>")
|
||||
else
|
||||
boutput(user, "<span style=\"color:blue\">Mode: constructing planned grille and glass structures.</span>")
|
||||
|
||||
attackby(var/obj/item/W, mob/user as mob)
|
||||
if (W.disposed)
|
||||
return
|
||||
if (istype(W, /obj/item/material_piece))
|
||||
var/obj/item/material_piece/D = W
|
||||
var/which = determine_material(D, user)
|
||||
if (which == "metal")
|
||||
qdel(W)
|
||||
metal_count += 10
|
||||
else if (which == "glass")
|
||||
qdel(W)
|
||||
glass_count += 10
|
||||
else
|
||||
return
|
||||
|
||||
pixelaction(atom/target, params, mob/user)
|
||||
if (mode)
|
||||
return 0
|
||||
var/turf/T = target
|
||||
if (!istype(T))
|
||||
T = get_turf(T)
|
||||
if (!T)
|
||||
return 0
|
||||
|
||||
var/obj/plan_marker/glass_shaper/old = locate() in T
|
||||
if (old)
|
||||
old.cancelled()
|
||||
else
|
||||
new /obj/plan_marker/glass_shaper(T)
|
||||
|
||||
boutput(user, "<span style=\"color:blue\">Done.</span>")
|
||||
if (!disable_next_click || ismob(target))
|
||||
user.next_click = world.time + 1
|
||||
|
||||
return 1
|
||||
|
||||
MouseDrop_T(var/obj/over_object, mob/user as mob)
|
||||
if (processing)
|
||||
return
|
||||
processing = 1
|
||||
var/procloc = user.loc
|
||||
if (!istype(over_object))
|
||||
processing = 0
|
||||
return
|
||||
if (!istype(over_object.loc, /turf))
|
||||
processing = 0
|
||||
return
|
||||
if (istype(over_object, /obj/item/material_piece))
|
||||
var/obj/item/material_piece/D = over_object
|
||||
if (!D.material)
|
||||
playsound(src.loc, sound_grump, 40, 1)
|
||||
boutput(user, "<span style=\"color:red\">That does not have a usable material.</span>")
|
||||
return
|
||||
|
||||
var/which = determine_material(D, user)
|
||||
if (!which)
|
||||
processing = 0
|
||||
return
|
||||
var/datum/material/DM = null
|
||||
if (which == "metal")
|
||||
DM = metal
|
||||
else if (which == "glass")
|
||||
DM = glass
|
||||
else
|
||||
processing = 0
|
||||
return
|
||||
|
||||
user.visible_message("<span style=\"color:blue\">[user] begins stuffing materials into [src].</span>")
|
||||
|
||||
for (var/obj/item/material_piece/M in over_object.loc)
|
||||
if (user.loc != procloc)
|
||||
break
|
||||
var/datum/material/MT = M.material
|
||||
if (!MT)
|
||||
continue
|
||||
if (MT.mat_id == DM.mat_id)
|
||||
playsound(src.loc, sound_process, 40, 1)
|
||||
M.loc = null
|
||||
if (which == "metal")
|
||||
metal_count += 10
|
||||
else
|
||||
glass_count += 10
|
||||
qdel(M)
|
||||
sleep(1)
|
||||
processing = 0
|
||||
user.visible_message("<span style=\"color:blue\">[user] finishes stuffing materials into [src].</span>")
|
||||
|
||||
/obj/item/room_planner
|
||||
name = "Plan Designator"
|
||||
icon = 'icons/obj/construction.dmi'
|
||||
icon_state = "plan"
|
||||
item_state = "gun"
|
||||
mats = 6
|
||||
w_class = 2
|
||||
|
||||
var/selecting = 0
|
||||
var/mode = "floors"
|
||||
var/icons = list("floors" = 'icons/turf/construction_floors.dmi', "walls" = 'icons/turf/construction_walls.dmi')
|
||||
var/marker_class = list("floors" = /obj/plan_marker/floor, "walls" = /obj/plan_marker/wall)
|
||||
var/selected = "floor"
|
||||
var/pod_turf = 0
|
||||
var/turf_op = 0
|
||||
|
||||
attack_self(mob/user as mob)
|
||||
if (!(ticker && ticker.mode && istype(ticker.mode, /datum/game_mode/construction)))
|
||||
boutput(user, "<span style=\"color:red\">You can only use this tool in construction mode.</span>")
|
||||
|
||||
if (selecting)
|
||||
return
|
||||
|
||||
selecting = 1
|
||||
mode = input("What to mark?", "Marking", mode) in icons
|
||||
selected = null
|
||||
var/list/states = icon_states(icons[mode])
|
||||
selected = input("What kind?", "Marking", states[1]) in states
|
||||
if (mode == "floors" && findtext(selected, "catwalk") != 0)
|
||||
pod_turf = 1
|
||||
else
|
||||
pod_turf = 0
|
||||
if (mode == "floors" || (mode == "walls" && findtext(selected, "window") != 0))
|
||||
turf_op = 0
|
||||
else
|
||||
turf_op = 1
|
||||
boutput(user, "<span style=\"color:blue\">Now marking plan for [mode] of type [selected].</span>")
|
||||
selecting = 0
|
||||
|
||||
pixelaction(atom/target, params, mob/user)
|
||||
var/turf/T = target
|
||||
if (!istype(T))
|
||||
T = get_turf(T)
|
||||
if (!T)
|
||||
return 0
|
||||
|
||||
var/obj/plan_marker/old = null
|
||||
for (var/obj/plan_marker/K in T)
|
||||
if (istype(K, /obj/plan_marker/floor) || istype(K, /obj/plan_marker/wall))
|
||||
old = K
|
||||
break
|
||||
if (old)
|
||||
old.attackby(src, user)
|
||||
else
|
||||
var/class = marker_class[mode]
|
||||
old = new class(T, selected)
|
||||
old.dir = get_dir(user, T)
|
||||
if (pod_turf)
|
||||
old:allows_vehicles = 1
|
||||
old.turf_op = turf_op
|
||||
old:check()
|
||||
boutput(user, "<span style=\"color:blue\">Done.</span>")
|
||||
if (!disable_next_click || ismob(target))
|
||||
user.next_click = world.time + 1
|
||||
|
||||
return 1
|
||||
|
||||
/obj/plan_marker
|
||||
name = "Plan Marker"
|
||||
icon = 'icons/turf/construction_walls.dmi'
|
||||
icon_state = null
|
||||
anchored = 1
|
||||
density = 0
|
||||
opacity = 0
|
||||
invisibility = 8
|
||||
var/allows_vehicles = 0
|
||||
var/turf_op = 1
|
||||
|
||||
alpha = 128
|
||||
|
||||
New(var/initial_loc, var/initial_state)
|
||||
..()
|
||||
color = rgb(0, 255, 0)
|
||||
icon_state = initial_state
|
||||
|
||||
attackby(obj/item/W as obj, mob/user as mob)
|
||||
if (istype(W, /obj/item/room_planner))
|
||||
qdel(src)
|
||||
return
|
||||
var/turf/T = get_turf(src)
|
||||
if (T)
|
||||
T.attackby(W, user)
|
||||
W.afterattack(T, user)
|
||||
|
||||
/obj/plan_marker/glass_shaper
|
||||
name = "Window Plan Marker"
|
||||
icon = 'icons/obj/grille.dmi'
|
||||
icon_state = "grille-0"
|
||||
anchored = 1
|
||||
density = 0
|
||||
opacity = 0
|
||||
invisibility = 8
|
||||
|
||||
var/static/image/wE = null
|
||||
var/static/image/wW = null
|
||||
var/static/image/wN = null
|
||||
var/static/image/wS = null
|
||||
|
||||
var/bmask = 15
|
||||
var/borders = 4
|
||||
|
||||
var/filling = 0
|
||||
|
||||
alpha = 128
|
||||
|
||||
New(var/initial_loc)
|
||||
..()
|
||||
color = rgb(255, 0, 0)
|
||||
calculate_orientation(1)
|
||||
|
||||
if (!wE)
|
||||
wE = image('icons/obj/construction.dmi', "plan_window_e")
|
||||
if (!wW)
|
||||
wW = image('icons/obj/construction.dmi', "plan_window_w")
|
||||
if (!wN)
|
||||
wN = image('icons/obj/construction.dmi', "plan_window_n")
|
||||
if (!wS)
|
||||
wS = image('icons/obj/construction.dmi', "plan_window_s")
|
||||
|
||||
icon_state = "grille-0"
|
||||
|
||||
proc/calculate_orientation(var/recurse = 0)
|
||||
var/borders_mask = 15
|
||||
var/gcount = 4
|
||||
var/turf/N = locate(x, y + 1, 1)
|
||||
var/turf/S = locate(x, y - 1, 1)
|
||||
var/turf/W = locate(x - 1, y, 1)
|
||||
var/turf/E = locate(x + 1, y, 1)
|
||||
if (N)
|
||||
var/obj/plan_marker/glass_shaper/G = locate() in N
|
||||
if (G)
|
||||
borders_mask -= 1
|
||||
gcount--
|
||||
if (recurse)
|
||||
G.calculate_orientation(0)
|
||||
else
|
||||
var/obj/grille/Gr = locate() in N
|
||||
if (Gr)
|
||||
borders_mask -= 1
|
||||
gcount--
|
||||
if (S)
|
||||
var/obj/plan_marker/glass_shaper/G = locate() in S
|
||||
if (G)
|
||||
borders_mask -= 2
|
||||
gcount--
|
||||
if (recurse)
|
||||
G.calculate_orientation(0)
|
||||
else
|
||||
var/obj/grille/Gr = locate() in S
|
||||
if (Gr)
|
||||
borders_mask -= 2
|
||||
gcount--
|
||||
if (E)
|
||||
var/obj/plan_marker/glass_shaper/G = locate() in E
|
||||
if (G)
|
||||
borders_mask -= 4
|
||||
gcount--
|
||||
if (recurse)
|
||||
G.calculate_orientation(0)
|
||||
else
|
||||
var/obj/grille/Gr = locate() in E
|
||||
if (Gr)
|
||||
borders_mask -= 4
|
||||
gcount--
|
||||
if (W)
|
||||
var/obj/plan_marker/glass_shaper/G = locate() in W
|
||||
if (G)
|
||||
borders_mask -= 8
|
||||
gcount--
|
||||
if (recurse)
|
||||
G.calculate_orientation(0)
|
||||
else
|
||||
var/obj/grille/Gr = locate() in W
|
||||
if (Gr)
|
||||
borders_mask -= 8
|
||||
gcount--
|
||||
|
||||
bmask = borders_mask
|
||||
borders = gcount
|
||||
overlays.len = 0
|
||||
if (borders_mask & 1)
|
||||
overlays += wN
|
||||
if (borders_mask & 2)
|
||||
overlays += wS
|
||||
if (borders_mask & 4)
|
||||
overlays += wE
|
||||
if (borders_mask & 8)
|
||||
overlays += wW
|
||||
|
||||
proc/spawn_in(var/obj/item/material_shaper/origin)
|
||||
if (filling)
|
||||
return
|
||||
filling = 1
|
||||
if (!isturf(src.loc))
|
||||
filling = 0
|
||||
return
|
||||
var/turf/T = src.loc
|
||||
if (T.density)
|
||||
boutput(usr, "<span style=\"color:red\">Cannot complete material shaping: plan inside dense turf.</span>")
|
||||
filling = 0
|
||||
return
|
||||
else
|
||||
for (var/atom/movable/O in T)
|
||||
if ((istype(O, /obj) && O.density) || istype(O, /mob/living))
|
||||
boutput(usr, "<span style=\"color:red\">Cannot complete material shaping: [O] blocking construction.</span>")
|
||||
filling = 0
|
||||
return
|
||||
var/datum/material/metal = origin.metal
|
||||
var/datum/material/glass = origin.glass
|
||||
var/turf/L = get_turf(src)
|
||||
if (!metal)
|
||||
metal = getCachedMaterial("steel")
|
||||
if (!glass)
|
||||
glass = getCachedMaterial("glass")
|
||||
|
||||
origin.use_materials(2, borders)
|
||||
|
||||
var/obj/grille/G = new /obj/grille(L)
|
||||
G.setMaterial(metal)
|
||||
|
||||
var/mask = bmask
|
||||
if (mask & 1)
|
||||
var/obj/window/reinforced/W = new /obj/window/reinforced(L)
|
||||
W.dir = 1
|
||||
W.setMaterial(glass)
|
||||
|
||||
if (mask & 2)
|
||||
var/obj/window/reinforced/W = new /obj/window/reinforced(L)
|
||||
W.dir = 2
|
||||
W.setMaterial(glass)
|
||||
|
||||
if (mask & 4)
|
||||
var/obj/window/reinforced/W = new /obj/window/reinforced(L)
|
||||
W.dir = 4
|
||||
W.setMaterial(glass)
|
||||
|
||||
if (mask & 8)
|
||||
var/obj/window/reinforced/W = new /obj/window/reinforced(L)
|
||||
W.dir = 8
|
||||
W.setMaterial(glass)
|
||||
|
||||
src.loc = null
|
||||
qdel(src)
|
||||
|
||||
proc/cancelled()
|
||||
var/turf/N = locate(x, y + 1, 1)
|
||||
var/turf/S = locate(x, y - 1, 1)
|
||||
var/turf/W = locate(x - 1, y, 1)
|
||||
var/turf/E = locate(x + 1, y, 1)
|
||||
src.loc = null
|
||||
if (N)
|
||||
var/obj/plan_marker/glass_shaper/G = locate() in N
|
||||
if (G)
|
||||
G.calculate_orientation(0)
|
||||
if (S)
|
||||
var/obj/plan_marker/glass_shaper/G = locate() in S
|
||||
if (G)
|
||||
G.calculate_orientation(0)
|
||||
if (E)
|
||||
var/obj/plan_marker/glass_shaper/G = locate() in E
|
||||
if (G)
|
||||
G.calculate_orientation(0)
|
||||
if (W)
|
||||
var/obj/plan_marker/glass_shaper/G = locate() in W
|
||||
if (G)
|
||||
G.calculate_orientation(0)
|
||||
|
||||
qdel(src)
|
||||
|
||||
proc/handle_shaper(var/obj/item/material_shaper/W)
|
||||
if (!W:mode)
|
||||
cancelled()
|
||||
else
|
||||
if (W:has_materials(2, borders))
|
||||
spawn_in(W)
|
||||
else
|
||||
boutput(usr, "<span style=\"color:red\">Insufficient materials -- requires 2 metal and [borders] glass.</span>")
|
||||
|
||||
attackby(obj/item/W as obj, mob/user as mob)
|
||||
if (istype(W, /obj/item/material_shaper))
|
||||
handle_shaper(W)
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/plan_marker/wall
|
||||
name = "Wall Plan Marker"
|
||||
desc = "Build a wall here to complete the plan."
|
||||
|
||||
proc/check()
|
||||
var/turf/T = get_turf(src)
|
||||
if (T.type == /turf/simulated/wall)
|
||||
T.icon = src.icon
|
||||
T.icon_state = src.icon_state
|
||||
T.dir = src.dir
|
||||
T:allows_vehicles = src.allows_vehicles
|
||||
T.opacity = turf_op
|
||||
src.loc = null
|
||||
qdel(src)
|
||||
|
||||
/obj/plan_marker/floor
|
||||
name = "Floor Plan Marker"
|
||||
desc = "Build a floor here to complete the plan."
|
||||
icon = 'icons/turf/construction_floors.dmi'
|
||||
|
||||
proc/check()
|
||||
var/turf/T = get_turf(src)
|
||||
if (T.type == /turf/simulated/floor)
|
||||
T.icon = src.icon
|
||||
T.icon_state = src.icon_state
|
||||
T.dir = src.dir
|
||||
T:allows_vehicles = src.allows_vehicles
|
||||
src.loc = null
|
||||
qdel(src)
|
||||
Reference in New Issue
Block a user