Initial Commit

This commit is contained in:
Tobba
2016-03-06 20:52:14 +01:00
commit b181d0b552
4325 changed files with 579453 additions and 0 deletions
@@ -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()
+167
View File
@@ -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>&nbsp;</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")
+752
View File
@@ -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)