mirror of
https://github.com/goonstation/goonstation-2016.git
synced 2026-08-27 07:56:12 +01:00
Initial Commit
This commit is contained in:
@@ -0,0 +1,893 @@
|
||||
var/datum/action_controller/actions
|
||||
|
||||
//See _setup.dm for interrupt and state definitions
|
||||
|
||||
/datum/action_controller
|
||||
var/list/running = list() //Associative list of running actions, format: owner=list of action datums
|
||||
|
||||
proc/hasAction(var/atom/owner, var/id) //has this mob an action of a given type running?
|
||||
if(running.Find(owner))
|
||||
var/list/actions = running[owner]
|
||||
for(var/datum/action/A in actions)
|
||||
if(A.id == id) return 1
|
||||
return 0
|
||||
|
||||
proc/stop_all(var/atom/owner) //Interrupts all actions of a given owner.
|
||||
if(running.Find(owner))
|
||||
for(var/datum/action/A in running[owner])
|
||||
A.interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
|
||||
proc/stop(var/datum/action/A, var/atom/owner) //Manually interrupts a given action of a given owner.
|
||||
if(running.Find(owner))
|
||||
var/list/actions = running[owner]
|
||||
if(actions.Find(A))
|
||||
A.interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
|
||||
proc/stopId(var/id, var/atom/owner) //Manually interrupts a given action id of a given owner.
|
||||
if(running.Find(owner))
|
||||
var/list/actions = running[owner]
|
||||
for(var/datum/action/A in actions)
|
||||
if(A.id == id)
|
||||
A.interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
|
||||
proc/start(var/datum/action/A, var/atom/owner) //Starts a new action.
|
||||
if(!running.Find(owner))
|
||||
running.Add(owner)
|
||||
running[owner] = list(A)
|
||||
A.owner = owner
|
||||
A.started = world.time
|
||||
A.onStart()
|
||||
else
|
||||
interrupt(owner, INTERRUPT_ACTION)
|
||||
running[owner] += A
|
||||
A.owner = owner
|
||||
A.started = world.time
|
||||
A.onStart()
|
||||
|
||||
return
|
||||
|
||||
proc/interrupt(var/atom/owner, var/flag) //Is called by all kinds of things to check for action interrupts.
|
||||
if(running.Find(owner))
|
||||
for(var/datum/action/A in running[owner])
|
||||
A.interrupt(flag)
|
||||
return
|
||||
|
||||
proc/process() //Handles the action countdowns, updates and deletions.
|
||||
for(var/X in running)
|
||||
for(var/datum/action/A in running[X])
|
||||
|
||||
if( ((A.duration >= 0 && world.time >= (A.started + A.duration)) && A.state == ACTIONSTATE_RUNNING) || A.state == ACTIONSTATE_FINISH)
|
||||
A.state = ACTIONSTATE_ENDED
|
||||
A.onEnd()
|
||||
//continue //If this is not commented out the deletion will take place the tick after the action ends. This will break things like objects being deleted onEnd with progressbars - the bars will be left behind. But it will look better for things that do not do this.
|
||||
|
||||
if(A.state == ACTIONSTATE_DELETE)
|
||||
A.onDelete()
|
||||
running[X] -= A
|
||||
continue
|
||||
|
||||
A.onUpdate()
|
||||
|
||||
if(length(running[X]) == 0)
|
||||
running.Remove(X)
|
||||
return
|
||||
|
||||
/datum/action
|
||||
var/atom/owner = null //Object that owns this action.
|
||||
var/duration = 1 //How long does this action take in ticks.
|
||||
var/interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION //When and how this action is interrupted.
|
||||
var/state = ACTIONSTATE_STOPPED //Current state of the action.
|
||||
var/started = -1 //world.time this action was started at
|
||||
var/id = "base" //Unique ID for this action. For when you want to remove actions by ID on a person.
|
||||
|
||||
proc/interrupt(var/flag) //This is called by the default interrupt actions
|
||||
if(interrupt_flags & flag || flag == INTERRUPT_ALWAYS)
|
||||
state = ACTIONSTATE_INTERRUPTED
|
||||
onInterrupt(flag)
|
||||
return
|
||||
|
||||
proc/onUpdate() //Called every tick this action is running. If you absolutely(!!!) have to you can do manual interrupt checking in here. Otherwise this is mostly used for drawing progress bars and shit.
|
||||
return
|
||||
|
||||
proc/onInterrupt(var/flag = 0) //Called when the action fails / is interrupted.
|
||||
state = ACTIONSTATE_DELETE
|
||||
return
|
||||
|
||||
proc/onStart() //Called when the action begins
|
||||
state = ACTIONSTATE_RUNNING
|
||||
return
|
||||
|
||||
proc/onEnd() //Called when the action succesfully ends.
|
||||
state = ACTIONSTATE_DELETE
|
||||
return
|
||||
|
||||
proc/onDelete() //Called when the action is complete and about to be deleted. Usable for cleanup and such.
|
||||
return
|
||||
|
||||
/datum/action/bar //This subclass has a progressbar that attaches to the owner to show how long we need to wait.
|
||||
var/obj/actions/bar/bar
|
||||
var/obj/actions/border/border
|
||||
|
||||
onStart()
|
||||
..()
|
||||
if(owner != null)
|
||||
bar = unpool(/obj/actions/bar)
|
||||
bar.loc = owner.loc
|
||||
border = unpool(/obj/actions/border)
|
||||
border.loc = owner.loc
|
||||
bar.pixel_y = 5
|
||||
border.pixel_y = 5
|
||||
owner.attached_objs.Add(bar)
|
||||
owner.attached_objs.Add(border)
|
||||
|
||||
onDelete()
|
||||
..()
|
||||
if(owner != null)
|
||||
owner.attached_objs.Remove(bar)
|
||||
owner.attached_objs.Remove(border)
|
||||
if (bar)
|
||||
pool(bar)
|
||||
bar = null
|
||||
if (border)
|
||||
pool(border)
|
||||
border = null
|
||||
|
||||
onEnd()
|
||||
bar.color = "#00FF00"
|
||||
bar.transform = matrix() //Tiny cosmetic fix. Makes it so the bar is completely filled when the action ends.
|
||||
bar.pixel_x = 0
|
||||
..()
|
||||
|
||||
onInterrupt(var/flag)
|
||||
if(state != ACTIONSTATE_DELETE)
|
||||
bar.color = "#FF0000"
|
||||
..()
|
||||
|
||||
onUpdate()
|
||||
var/done = world.time - started
|
||||
var/complete = max(min((done / duration), 1), 0)
|
||||
bar.transform = matrix(complete, 1, MATRIX_SCALE)
|
||||
bar.color = "#0000FF"
|
||||
bar.pixel_x = -nround( ((30 - (30 * complete)) / 2) )
|
||||
..()
|
||||
|
||||
/datum/action/bar/blob_health // WOW HACK
|
||||
onUpdate()
|
||||
var/obj/blob/B = owner
|
||||
if (!owner || !istype(owner))
|
||||
return
|
||||
if (B.health == B.health_max)
|
||||
border.invisibility = 101
|
||||
bar.invisibility = 101
|
||||
else
|
||||
border.invisibility = 0
|
||||
bar.invisibility = 0
|
||||
var/complete = B.health / B.health_max
|
||||
bar.color = "#00FF00"
|
||||
bar.transform = matrix(complete, 1, MATRIX_SCALE)
|
||||
bar.pixel_x = -nround( ((30 - (30 * complete)) / 2) )
|
||||
|
||||
/datum/action/bar/bullethell
|
||||
var/obj/actions/bar/shield_bar
|
||||
var/obj/actions/bar/armor_bar
|
||||
|
||||
onStart()
|
||||
..()
|
||||
if(owner != null)
|
||||
shield_bar = unpool(/obj/actions/bar)
|
||||
shield_bar.loc = owner.loc
|
||||
armor_bar = unpool(/obj/actions/bar)
|
||||
armor_bar.loc = owner.loc
|
||||
shield_bar.pixel_y = 5
|
||||
armor_bar.pixel_y = 5
|
||||
owner.attached_objs.Add(shield_bar)
|
||||
owner.attached_objs.Add(armor_bar)
|
||||
shield_bar.layer = initial(shield_bar.layer) + 2
|
||||
armor_bar.layer = initial(armor_bar.layer) + 1
|
||||
|
||||
onDelete()
|
||||
..()
|
||||
shield_bar.invisibility = 0
|
||||
armor_bar.invisibility = 0
|
||||
bar.invisibility = 0
|
||||
border.invisibility = 0
|
||||
if(owner != null)
|
||||
owner.attached_objs.Remove(shield_bar)
|
||||
owner.attached_objs.Remove(armor_bar)
|
||||
pool(shield_bar)
|
||||
shield_bar = null
|
||||
pool(armor_bar)
|
||||
armor_bar = null
|
||||
|
||||
onUpdate()
|
||||
var/obj/bullethell/B = owner
|
||||
if (!owner || !istype(owner))
|
||||
return
|
||||
var/h_complete = B.health / B.max_health
|
||||
bar.color = "#00FF00"
|
||||
bar.transform = matrix(h_complete, 1, MATRIX_SCALE)
|
||||
bar.pixel_x = -nround( ((30 - (30 * h_complete)) / 2) )
|
||||
if (B.max_armor && B.armor)
|
||||
armor_bar.invisibility = 0
|
||||
var/a_complete = B.armor / B.max_armor
|
||||
armor_bar.color = "#FF8800"
|
||||
armor_bar.transform = matrix(a_complete, 1, MATRIX_SCALE)
|
||||
armor_bar.pixel_x = -nround( ((30 - (30 * a_complete)) / 2) )
|
||||
else
|
||||
armor_bar.invisibility = 101
|
||||
if (B.max_shield && B.shield)
|
||||
shield_bar.invisibility = 0
|
||||
var/s_complete = B.shield / B.max_shield
|
||||
shield_bar.color = "#3333FF"
|
||||
shield_bar.transform = matrix(s_complete, 1, MATRIX_SCALE)
|
||||
shield_bar.pixel_x = -nround( ((30 - (30 * s_complete)) / 2) )
|
||||
else
|
||||
shield_bar.invisibility = 101
|
||||
|
||||
|
||||
/datum/action/bar/blob_replicator
|
||||
onUpdate()
|
||||
var/obj/blob/deposit/replicator/B = owner
|
||||
if (!owner)
|
||||
return
|
||||
if (!B.converting || (B.converting && !B.converting.maximum_volume))
|
||||
border.invisibility = 101
|
||||
bar.invisibility = 101
|
||||
return
|
||||
else
|
||||
border.invisibility = 0
|
||||
bar.invisibility = 0
|
||||
var/complete = 1 - (B.converting.total_volume / B.converting.maximum_volume)
|
||||
bar.color = "#0000FF"
|
||||
bar.transform = matrix(complete, 1, MATRIX_SCALE)
|
||||
bar.pixel_x = -nround( ((30 - (30 * complete)) / 2) )
|
||||
|
||||
onDelete()
|
||||
bar.invisibility = 0
|
||||
border.invisibility = 0
|
||||
..()
|
||||
|
||||
/datum/action/bar/icon //Visible to everyone and has an icon.
|
||||
var/icon
|
||||
var/icon_state
|
||||
var/icon_y_off = 20
|
||||
var/icon_x_off = 0
|
||||
var/image/icon_image
|
||||
|
||||
onStart()
|
||||
..()
|
||||
if(icon && icon_state && owner)
|
||||
icon_image = image(icon, border ,icon_state, 7)
|
||||
icon_image.pixel_y = icon_y_off
|
||||
icon_image.pixel_x = icon_x_off
|
||||
border.overlays += icon_image
|
||||
|
||||
onDelete()
|
||||
bar.overlays.Cut()
|
||||
del(icon_image)
|
||||
..()
|
||||
|
||||
/datum/action/bar/icon/build
|
||||
duration = 30
|
||||
var/obj/item/sheet/sheet
|
||||
var/objtype
|
||||
var/cost
|
||||
var/datum/material/mat
|
||||
var/amount
|
||||
var/objname
|
||||
var/callback = null
|
||||
|
||||
New(var/obj/item/sheet/csheet, var/cobjtype, var/ccost, var/datum/material/cmat, var/camount, var/cicon, var/cicon_state, var/cobjname, var/post_action_callback = null)
|
||||
..()
|
||||
icon = cicon
|
||||
icon_state = cicon_state
|
||||
sheet = csheet
|
||||
objtype = cobjtype
|
||||
cost = ccost
|
||||
mat = cmat
|
||||
amount = camount
|
||||
objname = cobjname
|
||||
callback = post_action_callback
|
||||
|
||||
onStart()
|
||||
..()
|
||||
if(istype(owner, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if(H.traitHolder.hasTrait("carpenter"))
|
||||
duration = round(duration / 2)
|
||||
|
||||
owner.visible_message("<span style=\"color:blue\">[owner] begins assembling [objname]!</span>")
|
||||
|
||||
onEnd()
|
||||
..()
|
||||
owner.visible_message("<span style=\"color:blue\">[owner] assembles [objname]!</span>")
|
||||
var/obj/item/R = new objtype(get_turf(owner))
|
||||
R.setMaterial(mat)
|
||||
if (istype(R))
|
||||
R.amount = amount
|
||||
R.dir = owner.dir
|
||||
sheet.consume_sheets(cost)
|
||||
logTheThing("station", owner, null, "builds [objname] (<b>Material:</b> [mat && istype(mat) && mat.mat_id ? "[mat.mat_id]" : "*UNKNOWN*"]) at [log_loc(owner)].")
|
||||
if (callback)
|
||||
call(callback)(src, R)
|
||||
|
||||
/datum/action/bar/icon/cruiser_repair
|
||||
id = "genproc"
|
||||
interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION
|
||||
duration = 30
|
||||
icon = 'icons/ui/actions.dmi'
|
||||
icon_state = "working"
|
||||
|
||||
var/obj/machinery/cruiser_destroyable/repairing
|
||||
var/obj/item/using
|
||||
|
||||
New(var/obj/machinery/cruiser_destroyable/D, var/obj/item/U, var/duration_i)
|
||||
..()
|
||||
repairing = D
|
||||
using = U
|
||||
duration = duration_i
|
||||
|
||||
onUpdate()
|
||||
..()
|
||||
if(get_dist(owner, repairing) > 1 || repairing == null || owner == null || using == null)
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
|
||||
var/mob/source = owner
|
||||
if(using != source.equipped())
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
|
||||
onStart()
|
||||
..()
|
||||
owner.visible_message("<span style=\"color:blue\">[owner] begins repairing [repairing]!</span>")
|
||||
|
||||
onEnd()
|
||||
..()
|
||||
owner.visible_message("<span style=\"color:blue\">[owner] successfully repairs [repairing]!</span>")
|
||||
repairing.adjustHealth(repairing.health_max)
|
||||
|
||||
/datum/action/bar/private //This subclass is only visible to the owner of the action
|
||||
onStart()
|
||||
..()
|
||||
bar.icon = null
|
||||
border.icon = null
|
||||
owner << bar.img
|
||||
owner << border.img
|
||||
|
||||
onDelete()
|
||||
bar.icon = 'icons/ui/actions.dmi'
|
||||
border.icon = 'icons/ui/actions.dmi'
|
||||
del(bar.img)
|
||||
del(border.img)
|
||||
..()
|
||||
|
||||
/datum/action/bar/private/icon //Only visible to the owner and has a little icon on the bar.
|
||||
var/icon
|
||||
var/icon_state
|
||||
var/icon_y_off = 25
|
||||
var/icon_x_off = 0
|
||||
var/image/icon_image
|
||||
|
||||
onStart()
|
||||
..()
|
||||
if(icon && icon_state && owner)
|
||||
icon_image = image(icon ,owner,icon_state,7)
|
||||
icon_image.pixel_y = icon_y_off
|
||||
icon_image.pixel_x = icon_x_off
|
||||
owner << icon_image
|
||||
|
||||
onDelete()
|
||||
del(icon_image)
|
||||
..()
|
||||
|
||||
//ACTIONS
|
||||
/datum/action/bar/icon/genericProc //Calls a specific proc with the given arguments when the action succeeds. TBI
|
||||
id = "genproc"
|
||||
interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION
|
||||
icon = 'icons/mob/screen1.dmi'
|
||||
icon_state = "grabbed"
|
||||
|
||||
/datum/action/bar/icon/otherItem//Putting items on or removing items from others.
|
||||
id = "otheritem"
|
||||
interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION
|
||||
icon = 'icons/mob/screen1.dmi'
|
||||
icon_state = "grabbed"
|
||||
|
||||
var/mob/living/carbon/human/source //The person doing the action
|
||||
var/mob/living/carbon/human/target //The target of the action
|
||||
var/obj/item/item //The item if any. If theres no item, we tried to remove something from that slot instead of putting an item there.
|
||||
var/slot //The slot number
|
||||
|
||||
New(var/Source, var/Target, var/Item, var/Slot)
|
||||
source = Source
|
||||
target = Target
|
||||
item = Item
|
||||
slot = Slot
|
||||
|
||||
if(item)
|
||||
if(item.duration_put > 0)
|
||||
duration = item.duration_put
|
||||
else
|
||||
duration = 45
|
||||
else
|
||||
var/obj/item/I = target.get_slot(slot)
|
||||
if(I)
|
||||
if(I.duration_remove > 0)
|
||||
duration = I.duration_remove
|
||||
else
|
||||
duration = 25
|
||||
..()
|
||||
|
||||
onStart()
|
||||
..()
|
||||
|
||||
target.add_fingerprint(source) // Added for forensics (Convair880).
|
||||
|
||||
if(item)
|
||||
if(!target.can_equip(item, slot))
|
||||
boutput(source, "<span style=\"color:red\">[item] can not be put there.</span>")
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
logTheThing("combat", source, target, "tries to put \an [item] on %target% at at [log_loc(target)].")
|
||||
for(var/mob/O in AIviewers(owner))
|
||||
O.show_message("<span style=\"color:red\"><B>[source] tries to put [item] on [target]!</B></span>", 1)
|
||||
else
|
||||
var/obj/item/I = target.get_slot(slot)
|
||||
|
||||
if(!I)
|
||||
boutput(source, "<span style=\"color:red\">There's nothing in that slot.</span>")
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
/* Some things use handle_other_remove to do stuff (ripping out staples, wiz hat probability, etc) should only be called once per removal.
|
||||
if(!I.handle_other_remove(source, target))
|
||||
boutput(source, "<span style=\"color:red\">[I] can not be removed.</span>")
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
*/
|
||||
|
||||
logTheThing("combat", source, target, "tries to remove \an [I] from %target% at [log_loc(target)].")
|
||||
|
||||
for(var/mob/O in AIviewers(owner))
|
||||
O.show_message("<span style=\"color:red\"><B>[source] tries to remove something from [target]!</B></span>", 1)
|
||||
|
||||
onEnd()
|
||||
..()
|
||||
|
||||
if(get_dist(source, target) > 1 || target == null || source == null)
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
|
||||
var/obj/item/I = target.get_slot(slot)
|
||||
|
||||
if(item)
|
||||
if(item == source.equipped() && !I)
|
||||
if(target.can_equip(item, slot))
|
||||
logTheThing("combat", source, target, "successfully puts \an [item] on %target% at at [log_loc(target)].")
|
||||
for(var/mob/O in AIviewers(owner))
|
||||
O.show_message("<span style=\"color:red\"><B>[source] puts [item] on [target]!</B></span>", 1)
|
||||
source.u_equip(item)
|
||||
target.force_equip(item, slot)
|
||||
else if (I) //Wire: Fix for Cannot execute null.handle other remove().
|
||||
if(I.handle_other_remove(source, target))
|
||||
logTheThing("combat", source, target, "successfully removes \an [I] from %target% at [log_loc(target)].")
|
||||
for(var/mob/O in AIviewers(owner))
|
||||
O.show_message("<span style=\"color:red\"><B>[source] removes [I] from [target]!</B></span>", 1)
|
||||
|
||||
// Re-added (Convair880).
|
||||
if (istype(I, /obj/item/mousetrap/))
|
||||
var/obj/item/mousetrap/MT = I
|
||||
if (MT && MT.armed)
|
||||
for (var/mob/O in AIviewers(owner))
|
||||
O.show_message("<span style=\"color:red\"><B>...and triggers it accidentally!</B></span>", 1)
|
||||
MT.triggered(source, source.hand ? "l_hand" : "r_hand")
|
||||
else if (istype(I, /obj/item/mine))
|
||||
var/obj/item/mine/M = I
|
||||
if (M.armed && M.used_up != 1)
|
||||
for (var/mob/O in AIviewers(owner))
|
||||
O.show_message("<span style=\"color:red\"><B>...and triggers it accidentally!</B></span>", 1)
|
||||
M.triggered(source)
|
||||
|
||||
target.u_equip(I)
|
||||
I.set_loc(target.loc)
|
||||
I.dropped(target)
|
||||
I.layer = initial(I.layer)
|
||||
I.add_fingerprint(source)
|
||||
else
|
||||
boutput(source, "<span style=\"color:red\">You fail to remove [I] from [target].</span>")
|
||||
onUpdate()
|
||||
..()
|
||||
if(get_dist(source, target) > 1 || target == null || source == null)
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
|
||||
if(item)
|
||||
if(item != source.equipped() || target.get_slot(slot))
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
else
|
||||
if(!target.get_slot(slot=slot))
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
|
||||
/datum/action/bar/icon/internalsOther //This is used when you try to set someones internals
|
||||
duration = 40
|
||||
interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION
|
||||
id = "internalsother"
|
||||
icon = 'icons/obj/clothing/item_masks.dmi'
|
||||
icon_state = "breath"
|
||||
var/mob/living/carbon/human/target
|
||||
var/remove_internals
|
||||
|
||||
New(Target)
|
||||
target = Target
|
||||
..()
|
||||
|
||||
onUpdate()
|
||||
..()
|
||||
if(get_dist(owner, target) > 1 || target == null || owner == null)
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
|
||||
onStart()
|
||||
..()
|
||||
if(get_dist(owner, target) > 1 || target == null || owner == null)
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
|
||||
for(var/mob/O in AIviewers(owner))
|
||||
if(target.internal)
|
||||
O.show_message("<span style=\"color:red\"><B>[owner] attempts to remove [target]'s internals!</B></span>", 1)
|
||||
remove_internals = 1
|
||||
else
|
||||
O.show_message("<span style=\"color:red\"><B>[owner] attempts to set [target]'s internals!</B></span>", 1)
|
||||
remove_internals = 0
|
||||
onEnd()
|
||||
..()
|
||||
if(owner && target && get_dist(owner, target) <= 1)
|
||||
if(remove_internals)
|
||||
target.internal.add_fingerprint(owner)
|
||||
for (var/obj/ability_button/tank_valve_toggle/T in target.internal.ability_buttons)
|
||||
T.icon_state = "airoff"
|
||||
target.internal = null
|
||||
for(var/mob/O in AIviewers(owner))
|
||||
O.show_message("<span style=\"color:red\"><B>[owner] removes [target]'s internals!</B></span>", 1)
|
||||
else
|
||||
if (!istype(target.wear_mask, /obj/item/clothing/mask))
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
else
|
||||
if (istype(target.back, /obj/item/tank))
|
||||
target.internal = target.back
|
||||
for (var/obj/ability_button/tank_valve_toggle/T in target.internal.ability_buttons)
|
||||
T.icon_state = "airon"
|
||||
for(var/mob/M in AIviewers(target, 1))
|
||||
M.show_message(text("[] is now running on internals.", src.target), 1)
|
||||
target.internal.add_fingerprint(owner)
|
||||
|
||||
/datum/action/bar/icon/handcuffSet //This is used when you try to handcuff someone.
|
||||
duration = 40
|
||||
interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION
|
||||
id = "handcuffsset"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "handcuff"
|
||||
var/mob/living/carbon/human/target
|
||||
var/obj/item/handcuffs/cuffs
|
||||
|
||||
New(Target, Cuffs)
|
||||
target = Target
|
||||
cuffs = Cuffs
|
||||
..()
|
||||
|
||||
onUpdate()
|
||||
..()
|
||||
if(get_dist(owner, target) > 1 || target == null || owner == null || cuffs == null)
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
|
||||
if(target.handcuffed)
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
|
||||
onStart()
|
||||
..()
|
||||
if(get_dist(owner, target) > 1 || target == null || owner == null || cuffs == null)
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
|
||||
for(var/mob/O in AIviewers(owner))
|
||||
O.show_message("<span style=\"color:red\"><B>[owner] attempts to handcuff [target]!</B></span>", 1)
|
||||
|
||||
onEnd()
|
||||
..()
|
||||
var/mob/ownerMob = owner
|
||||
if(owner && ownerMob && target && cuffs && !target.handcuffed && cuffs == ownerMob.equipped() && get_dist(owner, target) <= 1)
|
||||
|
||||
var/obj/item/handcuffs/cuffs2
|
||||
|
||||
if (issilicon(ownerMob))
|
||||
cuffs2 = new /obj/item/handcuffs
|
||||
else
|
||||
if (cuffs.amount >= 2)
|
||||
cuffs2 = new /obj/item/handcuffs/tape
|
||||
cuffs.amount--
|
||||
boutput(ownerMob, "<span style=\"color:blue\">The [cuffs.name] now has [cuffs.amount] lengths of [istype(cuffs, /obj/item/handcuffs/tape_roll) ? "tape" : "ziptie"] left.</span>")
|
||||
else if (cuffs.amount == 1 && cuffs.delete_on_last_use == 1)
|
||||
cuffs2 = new /obj/item/handcuffs/tape
|
||||
ownerMob.u_equip(cuffs)
|
||||
boutput(ownerMob, "<span style=\"color:red\">You used up the remaining length of [istype(cuffs, /obj/item/handcuffs/tape_roll) ? "tape" : "ziptie"].</span>")
|
||||
qdel(cuffs)
|
||||
else
|
||||
ownerMob.u_equip(cuffs)
|
||||
|
||||
logTheThing("combat", ownerMob, target, "handcuffs %target% with [cuffs2 ? "[cuffs2]" : "[cuffs]"] at [log_loc(ownerMob)].")
|
||||
|
||||
if (cuffs2 && istype(cuffs2))
|
||||
cuffs2.set_loc(target)
|
||||
target.handcuffed = cuffs2
|
||||
else
|
||||
cuffs.set_loc(target)
|
||||
target.handcuffed = cuffs
|
||||
target.drop_from_slot(target.r_hand)
|
||||
target.drop_from_slot(target.l_hand)
|
||||
target.drop_juggle()
|
||||
target.update_clothing()
|
||||
|
||||
for(var/mob/O in AIviewers(ownerMob))
|
||||
O.show_message("<span style=\"color:red\"><B>[owner] handcuffs [target]!</B></span>", 1)
|
||||
|
||||
/datum/action/bar/icon/handcuffRemovalOther //This is used when you try to remove someone elses handcuffs.
|
||||
duration = 70
|
||||
interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION
|
||||
id = "handcuffsother"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "handcuff"
|
||||
var/mob/living/carbon/human/target
|
||||
|
||||
New(Target)
|
||||
target = Target
|
||||
..()
|
||||
|
||||
onUpdate()
|
||||
..()
|
||||
if(get_dist(owner, target) > 1 || target == null || owner == null)
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
|
||||
if(!target.handcuffed)
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
|
||||
onStart()
|
||||
..()
|
||||
if(get_dist(owner, target) > 1 || target == null || owner == null)
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
|
||||
for(var/mob/O in AIviewers(owner))
|
||||
O.show_message("<span style=\"color:red\"><B>[owner] attempts to remove [target]'s handcuffs!</B></span>", 1)
|
||||
|
||||
onEnd()
|
||||
..()
|
||||
if(owner && target && target.handcuffed)
|
||||
var/mob/living/carbon/human/H = target
|
||||
H.handcuffed:set_loc(H.loc)
|
||||
H.handcuffed.unequipped(H)
|
||||
H.handcuffed = null
|
||||
H.update_clothing()
|
||||
for(var/mob/O in AIviewers(H))
|
||||
O.show_message("<span style=\"color:red\"><B>[owner] manages to remove [target]'s handcuffs!</B></span>", 1)
|
||||
|
||||
/datum/action/bar/private/icon/handcuffRemoval //This is used when you try to resist out of handcuffs.
|
||||
duration = 600
|
||||
interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION
|
||||
id = "handcuffs"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "handcuff"
|
||||
|
||||
New(var/dur)
|
||||
duration = dur
|
||||
..()
|
||||
|
||||
onStart()
|
||||
..()
|
||||
for(var/mob/O in AIviewers(owner))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] attempts to remove the handcuffs!</B></span>", owner), 1)
|
||||
|
||||
onInterrupt(var/flag)
|
||||
..()
|
||||
boutput(owner, "<span style=\"color:red\">Your attempt to remove your handcuffs was interrupted!</span>")
|
||||
|
||||
onEnd()
|
||||
..()
|
||||
if(owner != null && istype(owner, /mob/living/carbon/human) && owner:handcuffed)
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.handcuffed:set_loc(H.loc)
|
||||
H.handcuffed.unequipped(H)
|
||||
H.handcuffed = null
|
||||
H.update_clothing()
|
||||
if (H.handcuffed)
|
||||
H.handcuffed.layer = initial(H.handcuffed.layer)
|
||||
for(var/mob/O in AIviewers(H))
|
||||
O.show_message("<span style=\"color:red\"><B>[H] manages to remove the handcuffs!</B></span>", 1)
|
||||
boutput(H, "<span style=\"color:blue\">You successfully remove your handcuffs.</span>")
|
||||
|
||||
/datum/action/bar/private/icon/shackles_removal // Resisting out of shackles (Convair880).
|
||||
duration = 450
|
||||
interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION
|
||||
id = "shackles"
|
||||
icon = 'icons/obj/clothing/item_shoes.dmi'
|
||||
icon_state = "orange1"
|
||||
|
||||
New(var/dur)
|
||||
duration = dur
|
||||
..()
|
||||
|
||||
onStart()
|
||||
..()
|
||||
for(var/mob/O in AIviewers(owner))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] attempts to remove the shackles!</B></span>", owner), 1)
|
||||
|
||||
onInterrupt(var/flag)
|
||||
..()
|
||||
boutput(owner, "<span style=\"color:red\">Your attempt to remove the shackles was interrupted!</span>")
|
||||
|
||||
onEnd()
|
||||
..()
|
||||
if (owner != null && ishuman(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if (H.shoes && H.shoes.chained)
|
||||
var/obj/item/clothing/shoes/SH = H.shoes
|
||||
H.u_equip(SH)
|
||||
SH.set_loc(H.loc)
|
||||
H.update_clothing()
|
||||
if (SH)
|
||||
SH.layer = initial(SH.layer)
|
||||
for(var/mob/O in AIviewers(H))
|
||||
O.show_message("<span style=\"color:red\"><B>[H] manages to remove the shackles!</B></span>", 1)
|
||||
H.show_text("You successfully remove the shackles.", "blue")
|
||||
|
||||
//CLASSES & OBJS
|
||||
|
||||
/obj/actions //These objects are mostly used for the attached_objs var on mobs to attach progressbars to mobs.
|
||||
icon = 'icons/ui/actions.dmi'
|
||||
anchored = 1
|
||||
density = 0
|
||||
opacity = 0
|
||||
layer = 5
|
||||
name = ""
|
||||
desc = ""
|
||||
mouse_opacity = 0
|
||||
|
||||
/obj/actions/bar
|
||||
icon_state = "bar"
|
||||
layer = 6
|
||||
var/image/img
|
||||
New()
|
||||
img = image('icons/ui/actions.dmi',src,"bar",6)
|
||||
|
||||
unpooled()
|
||||
img = image('icons/ui/actions.dmi',src,"bar",6)
|
||||
icon = initial(icon)
|
||||
icon_state = initial(icon_state)
|
||||
|
||||
pooled()
|
||||
loc = null
|
||||
attached_objs = list()
|
||||
overlays.len = 0
|
||||
|
||||
/obj/actions/border
|
||||
icon_state = "border"
|
||||
var/image/img
|
||||
New()
|
||||
img = image('icons/ui/actions.dmi',src,"border",5)
|
||||
|
||||
unpooled()
|
||||
img = image('icons/ui/actions.dmi',src,"border",5)
|
||||
icon = initial(icon)
|
||||
icon_state = initial(icon_state)
|
||||
|
||||
pooled()
|
||||
loc = null
|
||||
attached_objs = list()
|
||||
overlays.len = 0
|
||||
|
||||
//Use this to start the action
|
||||
//actions.start(new/datum/action/bar/private/icon/magPicker(item, picker), usr)
|
||||
/datum/action/bar/private/icon/magPicker
|
||||
duration = 30 //How long does this action take in ticks.
|
||||
interrupt_flags = INTERRUPT_MOVE | INTERRUPT_ACT | INTERRUPT_STUNNED | INTERRUPT_ACTION
|
||||
id = "magpicker"
|
||||
icon = 'icons/obj/items.dmi' //In these two vars you can define an icon you want to have on your little progress bar.
|
||||
icon_state = "magtractor-small"
|
||||
|
||||
var/obj/item/target = null //This will contain the object we are trying to pick up.
|
||||
var/obj/item/magtractor/picker = null //This is the magpicker.
|
||||
|
||||
New(Target, Picker)
|
||||
target = Target
|
||||
picker = Picker
|
||||
..()
|
||||
|
||||
onUpdate() //check for special conditions that could interrupt the picking-up here.
|
||||
..()
|
||||
if(get_dist(owner, target) > 1 || picker == null || target == null || owner == null) //If the thing is suddenly out of range, interrupt the action. Also interrupt if the user or the item disappears.
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
|
||||
onStart()
|
||||
..()
|
||||
if(get_dist(owner, target) > 1 || picker == null || target == null || owner == null || picker.working) //If the thing is out of range, interrupt the action. Also interrupt if the user or the item disappears.
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
else
|
||||
picker.working = 1
|
||||
playsound(picker.loc, "sound/machines/whistlebeep.ogg", 50, 1)
|
||||
out(owner, "<span style='color: blue;'>The [picker.name] whirs and beeps as it charges it's coils. You must hold still...</span>")
|
||||
|
||||
onInterrupt(var/flag) //They did something else while picking it up. I guess you dont have to do anything here unless you want to.
|
||||
..()
|
||||
picker.working = 0
|
||||
|
||||
onEnd()
|
||||
..()
|
||||
//Shove the item into the picker here!!!
|
||||
picker.pickupItem(target, owner)
|
||||
actions.start(new/datum/action/magPickerHold(picker, picker.highpower), owner)
|
||||
|
||||
|
||||
/datum/action/magPickerHold
|
||||
duration = 30
|
||||
interrupt_flags = INTERRUPT_MOVE | INTERRUPT_STUNNED
|
||||
id = "magpickerhold"
|
||||
|
||||
var/obj/item/magtractor/picker = null //This is the magpicker.
|
||||
|
||||
New(Picker, hpm)
|
||||
if (hpm)
|
||||
src.interrupt_flags &= ~INTERRUPT_MOVE
|
||||
picker = Picker
|
||||
picker.holdAction = src
|
||||
..()
|
||||
|
||||
onUpdate() //Again, check here for special conditions that are not normally handled in here. You probably dont need to do anything.
|
||||
..()
|
||||
if(picker == null || owner == null) //Interrupt if the user or the magpicker disappears.
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
|
||||
onStart()
|
||||
..()
|
||||
state = ACTIONSTATE_INFINITE //We can hold it indefinitely unless we move.
|
||||
if(picker == null || owner == null) //Interrupt if the user or the magpicker dont exist.
|
||||
interrupt(INTERRUPT_ALWAYS)
|
||||
return
|
||||
|
||||
onEnd()
|
||||
..()
|
||||
picker.dropItem()
|
||||
|
||||
onInterrupt(var/flag)
|
||||
..()
|
||||
picker.dropItem()
|
||||
|
||||
//DEBUG STUFF
|
||||
|
||||
/datum/action/bar/private/bombtest
|
||||
duration = 100
|
||||
id = "bombtest"
|
||||
|
||||
onEnd()
|
||||
..()
|
||||
qdel(owner)
|
||||
|
||||
/obj/bombtest
|
||||
name = "large cartoon bomb"
|
||||
desc = "It looks like it's gonna blow."
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "dumb_bomb"
|
||||
density = 1
|
||||
|
||||
New()
|
||||
actions.start(new/datum/action/bar/private/bombtest(), src)
|
||||
..()
|
||||
@@ -0,0 +1,349 @@
|
||||
var/datum/artifact_controller/artifact_controls
|
||||
|
||||
/datum/artifact_controller
|
||||
var/list/artifacts = list()
|
||||
var/list/artifact_types = list()
|
||||
var/list/artifact_origins = list()
|
||||
var/spawner_type = null
|
||||
var/spawner_cine = 0
|
||||
|
||||
New()
|
||||
..()
|
||||
for (var/X in typesof(/datum/artifact) - /datum/artifact - /datum/artifact/art)
|
||||
var/datum/artifact/A = new X
|
||||
artifact_types += A
|
||||
|
||||
for (var/X in typesof(/datum/artifact_origin) - /datum/artifact_origin)
|
||||
var/datum/artifact_origin/AO = new X
|
||||
artifact_origins += AO
|
||||
|
||||
proc/get_origin_from_string(var/string)
|
||||
if (!istext(string))
|
||||
return
|
||||
for (var/datum/artifact_origin/AO in src.artifact_origins)
|
||||
if (AO.name == string)
|
||||
return AO
|
||||
return null
|
||||
|
||||
// Added. Admin actions related to artfacts were not logged at all (Convair880).
|
||||
proc/log_me(var/mob/user, var/obj/O, var/type_of_action, var/trigger_alert = 0)
|
||||
if (type_of_action == "spawns")
|
||||
logTheThing("admin", user, null, "spawns a random artifact at [user && ismob(user) ? "[log_loc(user)]" : "*unknown*"].")
|
||||
logTheThing("diary", user, null, "spawns a random artifact at [user && ismob(user) ? "[log_loc(user)]" : "*unknown*"].", "admin")
|
||||
return
|
||||
|
||||
if (!O || !istype(O.artifact, /datum/artifact) || !type_of_action)
|
||||
return
|
||||
|
||||
var/datum/artifact/A = O.artifact
|
||||
|
||||
logTheThing("admin", user, null, "[type_of_action] an artifact ([A.type]) at [log_loc(O)].")
|
||||
logTheThing("diary", user, null, "[type_of_action] an artifact ([A.type]) at [log_loc(O)].", "admin")
|
||||
if (trigger_alert)
|
||||
message_admins("[key_name(user)] [type_of_action] an artifact ([A.type]) at [log_loc(O)].")
|
||||
return
|
||||
|
||||
proc/config()
|
||||
var/dat = "<html><body><title>Artifact Controller</title>"
|
||||
dat += "<b><u>Artifact Controls</u></b><HR><small>"
|
||||
dat += "<a href='byond://?src=\ref[src];Spawnnew=1'>Spawn a new Artifact on your current tile</b></a><br>"
|
||||
|
||||
dat += "<a href='byond://?src=\ref[src];Spawntype=1'>Spawn Type:</a> "
|
||||
if (!spawner_type)
|
||||
dat += "Random"
|
||||
else
|
||||
dat += "[spawner_type]"
|
||||
|
||||
dat += "<br><a href='byond://?src=\ref[src];Spawncine=1'>Cinematic Spawning:</a> "
|
||||
if (spawner_cine)
|
||||
dat += "Yes"
|
||||
else
|
||||
dat += "No"
|
||||
dat += "<br><br>"
|
||||
|
||||
var/datum/artifact/A = null
|
||||
var/turf/T = null
|
||||
for (var/obj/O in src.artifacts)
|
||||
if (!istype(O.artifact,/datum/artifact/))
|
||||
continue
|
||||
A = O.artifact
|
||||
T = get_turf(O)
|
||||
|
||||
dat += "<b>"
|
||||
if (A.internal_name)
|
||||
dat += "[A.internal_name] "
|
||||
else
|
||||
dat += "Unnamed Artifact "
|
||||
dat += "</b>"
|
||||
if (istype(T,/turf/))
|
||||
dat += "in [T.loc]<br>"
|
||||
|
||||
dat += "[O.name], [A.artitype.name], [A.type]<br>"
|
||||
|
||||
dat += "<a href='byond://?src=\ref[src];Activate=\ref[O]'>"
|
||||
if (!A.activated)
|
||||
dat += "Activate"
|
||||
else
|
||||
dat += "Deactivate"
|
||||
dat += "</a> * "
|
||||
dat += "<a href='byond://?src=\ref[src];Jumpto=\ref[O]'>Jump To</a> * "
|
||||
dat += "<a href='byond://?src=\ref[src];Get=\ref[O]'>Get</a> * "
|
||||
dat += "<a href='byond://?src=\ref[src];Destroy=\ref[O]'>Destroy</a><br><br>"
|
||||
|
||||
dat += "</small></body></html>"
|
||||
|
||||
usr << browse(dat,"window=artifacts;size=400x600")
|
||||
|
||||
Topic(href, href_list[])
|
||||
if (href_list["Activate"])
|
||||
var/obj/O = locate(href_list["Activate"]) in src.artifacts
|
||||
if (!istype(O,/obj/))
|
||||
return
|
||||
if (!istype(O.artifact,/datum/artifact/))
|
||||
return
|
||||
var/datum/artifact/A = O.artifact
|
||||
if (A.activated)
|
||||
O.ArtifactDeactivated()
|
||||
else
|
||||
O.ArtifactActivated()
|
||||
|
||||
src.log_me(usr, O, A.activated ? "activates" : "deactivates", 1)
|
||||
|
||||
else if (href_list["Jumpto"])
|
||||
var/obj/O = locate(href_list["Jumpto"]) in src.artifacts
|
||||
if (!istype(O,/obj/))
|
||||
return
|
||||
var/turf/T = O.loc
|
||||
usr.set_loc(T)
|
||||
|
||||
src.log_me(usr, O, "jumps to", 0)
|
||||
|
||||
else if (href_list["Get"])
|
||||
var/obj/O = locate(href_list["Get"]) in src.artifacts
|
||||
if (!istype(O,/obj/))
|
||||
return
|
||||
var/turf/T = usr.loc
|
||||
O.set_loc(T)
|
||||
|
||||
src.log_me(usr, O, "teleports", 0)
|
||||
|
||||
else if (href_list["Destroy"])
|
||||
var/obj/O = locate(href_list["Destroy"]) in src.artifacts
|
||||
if (!istype(O,/obj/))
|
||||
return
|
||||
if (!istype(O.artifact,/datum/artifact/))
|
||||
return
|
||||
|
||||
src.log_me(usr, O, "destroys", 1)
|
||||
O.ArtifactDestroyed()
|
||||
|
||||
else if (href_list["Spawnnew"])
|
||||
var/turf/T = get_turf(usr)
|
||||
new /obj/artifact_spawner(T,spawner_type,spawner_cine)
|
||||
|
||||
src.log_me(usr, null, "spawns", 0)
|
||||
|
||||
else if (href_list["Spawntype"])
|
||||
spawner_type = input("What type of artifact?","Artifact Controls") as null|anything in list("ancient","martian","wizard","eldritch","precursor")
|
||||
|
||||
else if (href_list["Spawncine"])
|
||||
spawner_cine = !spawner_cine
|
||||
|
||||
src.config()
|
||||
|
||||
// Origins
|
||||
|
||||
/datum/artifact_origin
|
||||
var/name = "unknown"
|
||||
var/max_sprites = 7
|
||||
var/impact_reaction_one = 0
|
||||
var/impact_reaction_two = 0
|
||||
var/heat_reaction_one = 0
|
||||
var/fx_red_min = 0
|
||||
var/fx_red_max = 255
|
||||
var/fx_green_min = 0
|
||||
var/fx_green_max = 255
|
||||
var/fx_blue_min = 0
|
||||
var/fx_blue_max = 255
|
||||
var/list/activation_sounds = list()
|
||||
var/list/fault_types = list("all")
|
||||
var/list/adjectives = list("strange","unusual","odd","curious","bizarre","weird","abnormal","peculiar")
|
||||
var/list/nouns_large = list("object","machine","artifact","contraption","structure","edifice")
|
||||
var/list/nouns_small = list("item","device","relic","widget","utensil","gadget","accessory","gizmo")
|
||||
var/list/touch_descriptors = list("You can't really tell how it feels.")
|
||||
|
||||
New()
|
||||
..()
|
||||
if ("all" in fault_types)
|
||||
fault_types += typesof(/datum/artifact_fault) - /datum/artifact_fault
|
||||
|
||||
proc/generate_name()
|
||||
return "unknown object"
|
||||
|
||||
/datum/artifact_origin/ancient
|
||||
name = "ancient"
|
||||
fault_types = list(/datum/artifact_fault/burn,/datum/artifact_fault/irradiate,/datum/artifact_fault/shutdown,
|
||||
/datum/artifact_fault/murder,/datum/artifact_fault/zap)
|
||||
activation_sounds = list('sound/machines/ArtifactAnc1.ogg')
|
||||
impact_reaction_one = 1
|
||||
impact_reaction_two = 0.5
|
||||
heat_reaction_one = 1.5
|
||||
fx_red_min = 50
|
||||
fx_red_max = 255
|
||||
fx_green_min = 50
|
||||
fx_green_max = 255
|
||||
fx_blue_min = 50
|
||||
fx_blue_max = 255
|
||||
adjectives = list("dark","cold","smooth","angular","humming","sharp-edged","droning")
|
||||
nouns_large = list("monolith","slab","obelisk","pylon","menhir","machine","structure")
|
||||
nouns_small = list("implement","device","instrument","apparatus","appliance","mechanism","tool")
|
||||
touch_descriptors = list("It feels cold.","It feels smooth.","Touching it makes you feel uneasy.")
|
||||
|
||||
generate_name()
|
||||
return "unit [pick("alpha","sigma","tau","phi","gamma","epsilon")]-[pick("x","z","d","e","k")] [rand(100,999)]"
|
||||
|
||||
/datum/artifact_origin/martian
|
||||
name = "martian"
|
||||
fault_types = list(/datum/artifact_fault/shutdown,/datum/artifact_fault/zap,/datum/artifact_fault/poison)
|
||||
activation_sounds = list('sound/machines/ArtifactMar1.ogg','sound/machines/ArtifactMar2.ogg')
|
||||
impact_reaction_one = 1
|
||||
impact_reaction_two = 0
|
||||
heat_reaction_one = 0.99
|
||||
fx_red_min = 50
|
||||
fx_red_max = 90
|
||||
fx_green_min = 70
|
||||
fx_green_max = 120
|
||||
fx_blue_min = 50
|
||||
fx_blue_max = 90
|
||||
adjectives = list("squishy","gooey","clammy","quivering","twitching","pulpy","fleshy")
|
||||
nouns_large = list("mass","pile","heap","glob","mound","clump","bulk")
|
||||
nouns_small = list("lump","chunk","cluster","clod","nugget","giblet","organ")
|
||||
touch_descriptors = list("It feels warm.","It feels gross.","You can feel a faint pulsing.")
|
||||
var/list/prefix = list("cardio","neuro","physio","morpho","brachio","bronchi","dermo","ossu")
|
||||
var/list/thingy = list("cystic","genetic","metabolic","static","vascular","muscular")
|
||||
var/list/action = list("stimulator","suppressor","regenerator","depressor","mutator")
|
||||
|
||||
generate_name()
|
||||
var/namestring = ""
|
||||
namestring += "[pick(prefix)]"
|
||||
namestring += "[pick(thingy)] "
|
||||
namestring += "[pick(action)]"
|
||||
return namestring
|
||||
|
||||
/datum/artifact_origin/wizard
|
||||
name = "wizard"
|
||||
fault_types = list(/datum/artifact_fault/irradiate,/datum/artifact_fault/shutdown,/datum/artifact_fault/murder,
|
||||
/datum/artifact_fault/warp,/datum/artifact_fault/zap,/datum/artifact_fault/messager/creepy_whispers)
|
||||
activation_sounds = list('sound/machines/ArtifactWiz1.ogg')
|
||||
impact_reaction_one = 8
|
||||
impact_reaction_two = 6
|
||||
heat_reaction_one = 0.75
|
||||
fx_red_min = 40
|
||||
fx_red_max = 125
|
||||
fx_green_min = 125
|
||||
fx_green_max = 255
|
||||
fx_blue_min = 125
|
||||
fx_blue_max = 255
|
||||
adjectives = list("ornate","regal","imposing","fancy","elaborate","elegant","ostentatious")
|
||||
nouns_large = list("jewel","crystal","sculpture","statue","brazier","ornament","edifice")
|
||||
nouns_small = list("wand","scepter","staff","rod","cane","crozier","trophy")
|
||||
touch_descriptors = list("It feels warm.","It feels smooth.","It is suprisingly pleasant to touch.")
|
||||
var/list/material = list("ebon","ivory","pearl","golden","malachite","diamond","ruby","emerald","sapphire","opal")
|
||||
var/list/object = list("jewel","trophy","favor","boon","token","crown","treaure","sacrament","oath")
|
||||
var/list/aspect = list("wonder","splendor","power","plenty","mystery","glory","majesty","eminence","grace")
|
||||
|
||||
generate_name()
|
||||
var/namestring = ""
|
||||
namestring += "[pick(material)] "
|
||||
namestring += "[pick(object)] of "
|
||||
namestring += "[pick(aspect)]"
|
||||
return namestring
|
||||
|
||||
/datum/artifact_origin/eldritch
|
||||
name = "eldritch"
|
||||
activation_sounds = list('sound/machines/ArtifactEld1.ogg','sound/machines/ArtifactEld2.ogg')
|
||||
impact_reaction_one = 0.5
|
||||
impact_reaction_two = 0
|
||||
heat_reaction_one = 0.25
|
||||
fx_red_min = 40
|
||||
fx_red_max = 255
|
||||
fx_green_min = 40
|
||||
fx_green_max = 255
|
||||
fx_blue_min = 40
|
||||
fx_blue_max = 255
|
||||
adjectives = list("creepy","unnerving","ominous","threatening","horrid","evil-looking","lurid")
|
||||
nouns_large = list("edifice","effigy","statue","idol","sculpture","stele","artifact")
|
||||
nouns_small = list("spike","needle","thorns","relic","carving","figurine","item")
|
||||
touch_descriptors = list("It feels cold.","It feels gross.","Touching it makes you feel uneasy.")
|
||||
var/list/general_adjectives = list("dark","cold","horrid","foul","sinister","cruel","rancid","demonic")
|
||||
var/list/object_nouns = list("hand","eye","finger","blood","breath","thorns","mantle","skin","bane","scourge","wrath",
|
||||
"favor","will","tentacles","mandible","fangs","maw","flesh","ichor","teeth","heart")
|
||||
var/list/people = list("master","lord","king","queen","lady","mother","father","master","beast","brute","tyrant")
|
||||
var/list/person_adjectives = list("dread","great","old","ancient","vile","wicked","majestic","vast","mighty",
|
||||
"evil","heartless","fierce","ferocious")
|
||||
var/list/horror_name_start = list("trog","yogg","ta","y","has","shub","az","cth","cha","ul","xel","og","flu","wrk")
|
||||
var/list/horror_name_mid = list("sog","ran","gon","ni","a","hul","ttur","ay","o","lo","ncac","sin","fel","di")
|
||||
var/list/horror_name_end = list("dyte","oth","tula","olac","tur","bburath","thoth","hu","dha","aoth","tath","goth","ter")
|
||||
|
||||
generate_name()
|
||||
var/the_horror = src.horror_name()
|
||||
var/namestring = ""
|
||||
if (prob(50))
|
||||
if (prob(20))
|
||||
namestring += "[pick(general_adjectives)] "
|
||||
namestring += "[pick(object_nouns)] of "
|
||||
if (prob(20))
|
||||
namestring += "[pick(person_adjectives)] "
|
||||
namestring += "[the_horror]"
|
||||
else
|
||||
if (prob(20))
|
||||
namestring += "[pick(person_adjectives)] "
|
||||
namestring += "[the_horror]'s "
|
||||
if (prob(20))
|
||||
namestring += "[pick(general_adjectives)] "
|
||||
namestring += "[pick(object_nouns)]"
|
||||
return namestring
|
||||
|
||||
proc/horror_name()
|
||||
var/fthagn = ""
|
||||
if (prob(20))
|
||||
fthagn += "[pick(people)] "
|
||||
fthagn += "[pick(horror_name_start)]"
|
||||
if (prob(20))
|
||||
fthagn += "[pick("'","-")]"
|
||||
fthagn += "[pick(horror_name_mid)]"
|
||||
if (prob(20))
|
||||
fthagn += "[pick("'","-")]"
|
||||
fthagn += "[pick(horror_name_end)]"
|
||||
return fthagn // ia ia
|
||||
|
||||
/datum/artifact_origin/precursor
|
||||
name = "precursor"
|
||||
activation_sounds = list('sound/machines/ArtifactPre1.ogg')
|
||||
impact_reaction_one = 2
|
||||
impact_reaction_two = 10
|
||||
heat_reaction_one = 2
|
||||
fx_red_min = 155
|
||||
fx_red_max = 255
|
||||
fx_green_min = 155
|
||||
fx_green_max = 255
|
||||
fx_blue_min = 155
|
||||
fx_blue_max = 255
|
||||
adjectives = list("quirky","metallic","janky","bulky","chunky","cumbersome","unwieldy")
|
||||
nouns_large = list("contraption","machine","object","mechanism","artifact","machinery","structure")
|
||||
nouns_small = list("widget","thingy","device","appliance","mechanism","accessory","gizmo")
|
||||
touch_descriptors = list("It feels warm.","It feels cold.","It is suprisingly pleasant to touch.",
|
||||
"You can feel a faint pulsing.")
|
||||
var/list/prefixes = list("meta","poly","anti","hyper","hypo","nano","mega","infra","ultra","trans","micro","macro")
|
||||
var/list/particles = list("quark","tachyon","neutron","positron","photon","neutrino","lepton","baryon","atom","molecule")
|
||||
var/list/verber = list("stabilizer","synchroniser","generator","coupler","fuser","linker","materializer")
|
||||
|
||||
generate_name()
|
||||
var/namestring = ""
|
||||
if (prob(40))
|
||||
namestring += "[pick(prefixes)]"
|
||||
namestring += "[pick(particles)] "
|
||||
if (prob(33))
|
||||
namestring += "de"
|
||||
namestring += "[pick(verber)]"
|
||||
return namestring
|
||||
@@ -0,0 +1,38 @@
|
||||
var/datum/disease_controller/disease_controls
|
||||
|
||||
/datum/disease_controller
|
||||
var/list/standard_diseases = list()
|
||||
var/list/custom_diseases = list()
|
||||
|
||||
New()
|
||||
for (var/X in typesof(/datum/ailment))
|
||||
if (X == /datum/ailment || X == /datum/ailment/disease || X == /datum/ailment/parasite || X == /datum/ailment/disability)
|
||||
continue
|
||||
var/datum/ailment/A = new X
|
||||
standard_diseases += A
|
||||
|
||||
/proc/get_disease_from_path(var/disease_path)
|
||||
if (!ispath(disease_path))
|
||||
logTheThing("debug", null, null, "<b>Disease:</b> Attempt to find schematic with null path")
|
||||
return null
|
||||
if (!disease_controls.standard_diseases.len)
|
||||
logTheThing("debug", null, null, "<b>Disease:</b> Cant find disease due to empty disease list")
|
||||
return null
|
||||
for (var/datum/ailment/A in disease_controls.standard_diseases)
|
||||
if (disease_path == A.type)
|
||||
return A
|
||||
logTheThing("debug", null, null, "<b>Disease:</b> Disease \"[disease_path]\" not found")
|
||||
return null
|
||||
|
||||
/proc/get_disease_from_name(var/disease_name)
|
||||
if (!istext(disease_name))
|
||||
logTheThing("debug", null, null, "<b>Disease:</b> Attempt to find disase with non-string")
|
||||
return null
|
||||
if (!disease_controls.standard_diseases.len && !disease_controls.custom_diseases.len)
|
||||
logTheThing("debug", null, null, "<b>Disease:</b> Cant find schematic due to empty disease lists")
|
||||
return null
|
||||
for (var/datum/ailment/A in (disease_controls.standard_diseases + disease_controls.custom_diseases))
|
||||
if (disease_name == A.name)
|
||||
return A
|
||||
logTheThing("debug", null, null, "<b>Disease:</b> Disease with name \"[disease_name]\" not found")
|
||||
return null
|
||||
@@ -0,0 +1,313 @@
|
||||
var/datum/event_controller/random_events
|
||||
|
||||
/datum/event_controller
|
||||
var/list/events = list()
|
||||
var/events_begin = 18000 // 30m
|
||||
var/time_between_events_lower = 6600 // 11m
|
||||
var/time_between_events_upper = 12000 // 20m
|
||||
var/events_enabled = 1
|
||||
var/announce_events = 1
|
||||
var/next_event = 0
|
||||
var/event_cycle_count = 0
|
||||
|
||||
var/list/minor_events = list()
|
||||
var/minor_events_begin = 6000 // 10m
|
||||
var/time_between_minor_events_lower = 4000 // roughly 8m
|
||||
var/time_between_minor_events_upper = 8000 // roughly 14m
|
||||
var/minor_events_enabled = 1
|
||||
var/next_minor_event = 0
|
||||
var/minor_event_cycle_count = 0
|
||||
|
||||
var/time_lock = 1
|
||||
var/list/special_events = list()
|
||||
var/minimum_population = 15 // Minimum amount of players connected for event to occur
|
||||
|
||||
New()
|
||||
for (var/X in typesof(/datum/random_event/major) - /datum/random_event/major)
|
||||
var/datum/random_event/RE = new X
|
||||
events += RE
|
||||
|
||||
for (var/X in typesof(/datum/random_event/minor) - /datum/random_event/minor)
|
||||
var/datum/random_event/RE = new X
|
||||
minor_events += RE
|
||||
|
||||
for (var/X in typesof(/datum/random_event/special) - /datum/random_event/special)
|
||||
var/datum/random_event/RE = new X
|
||||
special_events += RE
|
||||
|
||||
proc/event_cycle()
|
||||
event_cycle_count++
|
||||
var/num_players = 0
|
||||
for(var/mob/players in mobs)
|
||||
if(players.client) num_players++
|
||||
|
||||
if (events_enabled && (num_players >= minimum_population))
|
||||
do_random_event(events)
|
||||
else
|
||||
message_admins("<span style=\"color:blue\">A random event would have happened now, but they are disabled!</span>")
|
||||
var/event_timer = rand(time_between_events_lower,time_between_events_upper)
|
||||
next_event = ticker.round_elapsed_ticks + event_timer
|
||||
message_admins("<span style=\"color:blue\">Next event will occur at [round(next_event / 600)] minutes into the round.</span>")
|
||||
spawn(event_timer)
|
||||
event_cycle()
|
||||
|
||||
proc/minor_event_cycle()
|
||||
minor_event_cycle_count++
|
||||
if (minor_events_enabled)
|
||||
do_random_event(minor_events)
|
||||
var/event_timer = rand(time_between_minor_events_lower,time_between_minor_events_upper)
|
||||
next_minor_event = ticker.round_elapsed_ticks + event_timer
|
||||
spawn(event_timer)
|
||||
minor_event_cycle()
|
||||
|
||||
proc/do_random_event(var/list/event_bank)
|
||||
if (!event_bank || event_bank.len < 1)
|
||||
logTheThing("debug", null, null, "<b>Random Events:</b> do_random_event proc was passed a bad event bank")
|
||||
return
|
||||
var/list/eligible = list()
|
||||
for (var/datum/random_event/RE in event_bank)
|
||||
if (!RE.is_event_available())
|
||||
continue
|
||||
eligible += RE
|
||||
if (eligible.len > 0)
|
||||
var/datum/random_event/this = pick(eligible)
|
||||
this.event_effect()
|
||||
else
|
||||
logTheThing("debug", null, null, "<b>Random Events:</b> do_random_event couldn't find any eligible events")
|
||||
|
||||
proc/force_event(var/string,var/reason)
|
||||
if (!string)
|
||||
return
|
||||
if (!reason)
|
||||
reason = "coded instance (undefined)"
|
||||
|
||||
var/list/allevents = events | minor_events | special_events
|
||||
for (var/datum/random_event/RE in allevents)
|
||||
if (RE.name == string)
|
||||
RE.event_effect(string,reason)
|
||||
break
|
||||
|
||||
///////////////////
|
||||
// CONFIGURATION //
|
||||
///////////////////
|
||||
|
||||
proc/event_config()
|
||||
var/dat = "<html><body><title>Random Events Controller</title>"
|
||||
dat += "<b><u>Random Event Controls</u></b><HR>"
|
||||
|
||||
if (ticker.current_state == GAME_STATE_PREGAME)
|
||||
dat += "<b>Random Events begin at: <a href='byond://?src=\ref[src];EventBegin=1'>[round(events_begin / 600)] minutes</a><br>"
|
||||
dat += "<b>Minor Events begin at: <a href='byond://?src=\ref[src];MEventBegin=1'>[round(minor_events_begin / 600)] minutes</a><br>"
|
||||
else
|
||||
dat += "Next random event at [round(next_event / 600)] minutes into the round.<br>"
|
||||
dat += "Next minor event at [round(next_minor_event / 600)] minutes into the round.<br>"
|
||||
dat += "<b><a href='byond://?src=\ref[src];EnableEvents=1'>Random Events Enabled:</a></b> [events_enabled ? "Yes" : "No"]<br>"
|
||||
dat += "<b><a href='byond://?src=\ref[src];EnableMEvents=1'>Minor Events Enabled:</a></b> [minor_events_enabled ? "Yes" : "No"]<br>"
|
||||
dat += "<b><a href='byond://?src=\ref[src];AnnounceEvents=1'>Announce Events to Station:</a></b> [announce_events ? "Yes" : "No"]<br>"
|
||||
dat += "<b><a href='byond://?src=\ref[src];TimeLocks=1'>Time Locking:</a></b> [time_lock ? "Yes" : "No"]<br>"
|
||||
dat += "<b>Minimum Population for Events: <a href='byond://?src=\ref[src];MinPop=1'>[minimum_population] players</a><br>"
|
||||
dat += "<b>Time Between Events:</b> <a href='byond://?src=\ref[src];TimeLower=1'>[round(time_between_events_lower / 600)]m</a> /"
|
||||
dat += " <a href='byond://?src=\ref[src];TimeUpper=1'>[round(time_between_events_upper / 600)]m</a><br>"
|
||||
dat += "<b>Time Between Minor Events:</b> <a href='byond://?src=\ref[src];MTimeLower=1'>[round(time_between_minor_events_lower / 600)]m</a> /"
|
||||
dat += " <a href='byond://?src=\ref[src];MTimeUpper=1'>[round(time_between_minor_events_upper / 600)]m</a>"
|
||||
dat += "<HR>"
|
||||
|
||||
dat += "<b><u>Normal Random Events</u></b><BR>"
|
||||
for(var/datum/random_event/RE in events)
|
||||
dat += "<a href='byond://?src=\ref[src];TriggerEvent=\ref[RE]'><b>[RE.name]</b></a>"
|
||||
dat += " <small><a href='byond://?src=\ref[src];DisableEvent=\ref[RE]'>([RE.disabled ? "Disabled" : "Enabled"])</a>"
|
||||
if (RE.is_event_available())
|
||||
dat += " (Active)"
|
||||
dat += "<br></small>"
|
||||
dat += "<BR>"
|
||||
|
||||
dat += "<b><u>Minor Random Events</u></b><BR>"
|
||||
for(var/datum/random_event/RE in minor_events)
|
||||
dat += "<a href='byond://?src=\ref[src];TriggerMEvent=\ref[RE]'><b>[RE.name]</b></a>"
|
||||
dat += " <small><a href='byond://?src=\ref[src];DisableMEvent=\ref[RE]'>([RE.disabled ? "Disabled" : "Enabled"])</a>"
|
||||
if (RE.is_event_available())
|
||||
dat += " (Active)"
|
||||
dat += "<br></small>"
|
||||
dat += "<BR>"
|
||||
|
||||
dat += "<b><u>Gimmick Events</u></b><BR>"
|
||||
for(var/datum/random_event/RE in special_events)
|
||||
dat += "<a href='byond://?src=\ref[src];TriggerSEvent=\ref[RE]'><b>[RE.name]</b></a><br>"
|
||||
|
||||
dat += "<HR>"
|
||||
dat += "</body></html>"
|
||||
usr << browse(dat,"window=reconfig;size=450x450")
|
||||
|
||||
Topic(href, href_list[])
|
||||
|
||||
if(href_list["TriggerEvent"])
|
||||
var/datum/random_event/RE = locate(href_list["TriggerEvent"]) in events
|
||||
if (!istype(RE,/datum/random_event/))
|
||||
return
|
||||
var/choice = alert("Trigger a [RE.name] event?","Random Events","Yes","No")
|
||||
if (choice == "Yes")
|
||||
if (RE.customization_available)
|
||||
var/choice2 = alert("Random or custom variables?","[RE.name]","Random","Custom")
|
||||
if (choice2 == "Custom")
|
||||
RE.admin_call(key_name(usr, 1))
|
||||
else
|
||||
RE.event_effect("Triggered by [key_name(usr)]")
|
||||
else
|
||||
RE.event_effect("Triggered by [key_name(usr)]")
|
||||
|
||||
else if(href_list["TriggerMEvent"])
|
||||
var/datum/random_event/RE = locate(href_list["TriggerMEvent"]) in minor_events
|
||||
if (!istype(RE,/datum/random_event/))
|
||||
return
|
||||
var/choice = alert("Trigger a [RE.name] event?","Random Events","Yes","No")
|
||||
if (choice == "Yes")
|
||||
RE.event_effect("Triggered by [key_name(usr)]")
|
||||
|
||||
else if(href_list["TriggerSEvent"])
|
||||
var/datum/random_event/RE = locate(href_list["TriggerSEvent"]) in special_events
|
||||
if (!istype(RE,/datum/random_event/))
|
||||
return
|
||||
var/choice = alert("Trigger a [RE.name] event?","Random Events","Yes","No")
|
||||
if (choice == "Yes")
|
||||
if (RE.customization_available)
|
||||
var/choice2 = alert("Random or custom variables?","[RE.name]","Random","Custom")
|
||||
if (choice2 == "Custom")
|
||||
RE.admin_call(key_name(usr, 1))
|
||||
else
|
||||
RE.event_effect("Triggered by [key_name(usr)]")
|
||||
else
|
||||
RE.event_effect("Triggered by [key_name(usr)]")
|
||||
|
||||
else if(href_list["DisableEvent"])
|
||||
var/datum/random_event/RE = locate(href_list["DisableEvent"]) in events
|
||||
if (!istype(RE,/datum/random_event/))
|
||||
return
|
||||
RE.disabled = !RE.disabled
|
||||
message_admins("Admin [key_name(usr)] switched [RE.name] event [RE.disabled ? "Off" : "On"]")
|
||||
logTheThing("admin", usr, null, "switched [RE.name] event [RE.disabled ? "Off" : "On"]")
|
||||
logTheThing("diary", usr, null, "switched [RE.name] event [RE.disabled ? "Off" : "On"]", "admin")
|
||||
|
||||
else if(href_list["DisableMEvent"])
|
||||
var/datum/random_event/RE = locate(href_list["DisableMEvent"]) in minor_events
|
||||
if (!istype(RE,/datum/random_event/))
|
||||
return
|
||||
RE.disabled = !RE.disabled
|
||||
message_admins("Admin [key_name(usr)] switched [RE.name] event [RE.disabled ? "Off" : "On"]")
|
||||
logTheThing("admin", usr, null, "switched [RE.name] event [RE.disabled ? "Off" : "On"]")
|
||||
logTheThing("diary", usr, null, "switched [RE.name] event [RE.disabled ? "Off" : "On"]", "admin")
|
||||
|
||||
else if(href_list["MinPop"])
|
||||
var/new_min = input("How many players need to be connected before events will occur?","Random Events",minimum_population) as num
|
||||
if (new_min == minimum_population) return
|
||||
|
||||
if (new_min < 1)
|
||||
boutput(usr, "<span style=\"color:red\">Well that doesn't even make sense.</span>")
|
||||
return
|
||||
else
|
||||
minimum_population = new_min
|
||||
|
||||
message_admins("Admin [key_name(usr)] set the minimum population for events to [minimum_population]")
|
||||
logTheThing("admin", usr, null, "set the minimum population for events to [minimum_population]")
|
||||
logTheThing("diary", usr, null, "set the minimum population for events to [minimum_population]", "admin")
|
||||
|
||||
else if(href_list["EventBegin"])
|
||||
var/time = input("How many minutes into the round until events begin?","Random Events") as num
|
||||
events_begin = time * 600
|
||||
|
||||
message_admins("Admin [key_name(usr)] set random events to begin at [time] minutes")
|
||||
logTheThing("admin", usr, null, "set random events to begin at [time] minutes")
|
||||
logTheThing("diary", usr, null, "set random events to begin at [time] minutes", "admin")
|
||||
|
||||
else if(href_list["MEventBegin"])
|
||||
var/time = input("How many minutes into the round until minor events begin?","Random Events") as num
|
||||
minor_events_begin = time * 600
|
||||
|
||||
message_admins("Admin [key_name(usr)] set minor events to begin at [time] minutes")
|
||||
logTheThing("admin", usr, null, "set minor events to begin at [time] minutes")
|
||||
logTheThing("diary", usr, null, "set minor events to begin at [time] minutes", "admin")
|
||||
|
||||
else if(href_list["EnableEvents"])
|
||||
events_enabled = !events_enabled
|
||||
message_admins("Admin [key_name(usr)] [events_enabled ? "enabled" : "disabled"] random events")
|
||||
logTheThing("admin", usr, null, "[events_enabled ? "enabled" : "disabled"] random events")
|
||||
logTheThing("diary", usr, null, "[events_enabled ? "enabled" : "disabled"] random events", "admin")
|
||||
|
||||
else if(href_list["EnableMEvents"])
|
||||
minor_events_enabled = !minor_events_enabled
|
||||
message_admins("Admin [key_name(usr)] [minor_events_enabled ? "enabled" : "disabled"] minor events")
|
||||
logTheThing("admin", usr, null, "[minor_events_enabled ? "enabled" : "disabled"] minor events")
|
||||
logTheThing("diary", usr, null, "[minor_events_enabled ? "enabled" : "disabled"] minor events", "admin")
|
||||
|
||||
else if(href_list["AnnounceEvents"])
|
||||
announce_events = !announce_events
|
||||
message_admins("Admin [key_name(usr)] [announce_events ? "enabled" : "disabled"] random event announcements")
|
||||
logTheThing("admin", usr, null, "[announce_events ? "enabled" : "disabled"] random event announcements")
|
||||
logTheThing("diary", usr, null, "[announce_events ? "enabled" : "disabled"] random event announcements", "admin")
|
||||
|
||||
else if(href_list["TimeLocks"])
|
||||
time_lock = !time_lock
|
||||
message_admins("Admin [key_name(usr)] [time_lock ? "enabled" : "disabled"] random event time locks")
|
||||
logTheThing("admin", usr, null, "[time_lock ? "enabled" : "disabled"] random event time locks")
|
||||
logTheThing("diary", usr, null, "[time_lock ? "enabled" : "disabled"] random event time locks", "admin")
|
||||
|
||||
else if(href_list["TimeLower"])
|
||||
var/time = input("Set the lower bound to how many minutes?","Random Events") as num
|
||||
if (time < 1)
|
||||
boutput(usr, "<span style=\"color:red\">The fuck is that supposed to mean???? Knock it off!</span>")
|
||||
return
|
||||
|
||||
time *= 600
|
||||
if (time > time_between_events_upper)
|
||||
boutput(usr, "<span style=\"color:red\">You cannot set the lower bound higher than the upper bound.</span>")
|
||||
else
|
||||
time_between_events_lower = time
|
||||
message_admins("Admin [key_name(usr)] set event lower interval bound to [time_between_events_lower / 600] minutes")
|
||||
logTheThing("admin", usr, null, "set event lower interval bound to [time_between_events_lower / 600] minutes")
|
||||
logTheThing("diary", usr, null, "set event lower interval bound to [time_between_events_lower / 600] minutes", "admin")
|
||||
|
||||
else if(href_list["TimeUpper"])
|
||||
var/time = input("Set the upper bound to how many minutes?","Random Events") as num
|
||||
if (time > 100)
|
||||
boutput(usr, "<span style=\"color:red\">That's a bit much.</span>")
|
||||
return
|
||||
|
||||
time *= 600
|
||||
if (time < time_between_events_lower)
|
||||
boutput(usr, "<span style=\"color:red\">You cannot set the upper bound lower than the lower bound.</span>")
|
||||
else
|
||||
time_between_events_upper = time
|
||||
message_admins("Admin [key_name(usr)] set event upper interval bound to [time_between_events_upper / 600] minutes")
|
||||
logTheThing("admin", usr, null, "set event upper interval bound to [time_between_events_upper / 600] minutes")
|
||||
logTheThing("diary", usr, null, "set event upper interval bound to [time_between_events_upper / 600] minutes", "admin")
|
||||
|
||||
else if(href_list["MTimeLower"])
|
||||
var/time = input("Set the lower bound to how many minutes?","Random Events") as num
|
||||
if (time < 1)
|
||||
boutput(usr, "<span style=\"color:red\">The fuck is that supposed to mean???? Knock it off!</span>")
|
||||
return
|
||||
|
||||
time *= 600
|
||||
if (time > time_between_minor_events_upper)
|
||||
boutput(usr, "<span style=\"color:red\">You cannot set the lower bound higher than the upper bound.</span>")
|
||||
else
|
||||
time_between_minor_events_lower = time
|
||||
message_admins("Admin [key_name(usr)] set minor event lower interval bound to [time_between_minor_events_lower / 600] minutes")
|
||||
logTheThing("admin", usr, null, "set minor event lower interval bound to [time_between_minor_events_lower / 600] minutes")
|
||||
logTheThing("diary", usr, null, "set minor event lower interval bound to [time_between_minor_events_lower / 600] minutes", "admin")
|
||||
|
||||
else if(href_list["MTimeUpper"])
|
||||
var/time = input("Set the upper bound to how many minutes?","Random Events") as num
|
||||
if (time > 100)
|
||||
boutput(usr, "<span style=\"color:red\">That's a bit much.</span>")
|
||||
return
|
||||
|
||||
time *= 600
|
||||
if (time < time_between_events_lower)
|
||||
boutput(usr, "<span style=\"color:red\">You cannot set the upper bound lower than the lower bound.</span>")
|
||||
else
|
||||
time_between_minor_events_upper = time
|
||||
message_admins("Admin [key_name(usr)] set minor event upper interval bound to [time_between_minor_events_upper / 600] minutes")
|
||||
logTheThing("admin", usr, null, "set minor event upper interval bound to [time_between_minor_events_upper / 600] minutes")
|
||||
logTheThing("diary", usr, null, "set minor event upper interval bound to [time_between_minor_events_upper / 600] minutes", "admin")
|
||||
|
||||
src.event_config()
|
||||
@@ -0,0 +1,95 @@
|
||||
var/datum/hydroponics_controller/hydro_controls
|
||||
|
||||
/datum/hydroponics_controller/
|
||||
// global variable name is currently "hydro_controls"
|
||||
var/max_harvest_cap = 10 // How many items can be harvested at once.
|
||||
var/delay_between_harvests = 300 // How long between harvests, in spawn() ticks.
|
||||
var/list/plant_species = list()
|
||||
var/list/mutations = list()
|
||||
var/list/strains = list()
|
||||
|
||||
var/image/pot_death_display = null
|
||||
var/image/pot_health_display = null
|
||||
var/image/pot_harvest_display = null
|
||||
|
||||
proc/set_up()
|
||||
pot_death_display = image('icons/obj/hydroponics/hydroponics.dmi', "led-dead")
|
||||
pot_health_display = image('icons/obj/hydroponics/hydroponics.dmi', "led-health")
|
||||
pot_harvest_display = image('icons/obj/hydroponics/hydroponics.dmi', "led-harv")
|
||||
|
||||
for (var/B in typesof(/datum/plantmutation))
|
||||
if (B == /datum/plantmutation)
|
||||
continue
|
||||
src.mutations += new B(src)
|
||||
|
||||
for (var/C in typesof(/datum/plant_gene_strain))
|
||||
if (C == /datum/plant_gene_strain)
|
||||
continue
|
||||
src.strains += new C(src)
|
||||
|
||||
// You need to do plants after the others or they won't set up properly due to mutations and strains
|
||||
// not having been set up yet
|
||||
for (var/A in typesof(/datum/plant))
|
||||
if (A == /datum/plant)
|
||||
continue
|
||||
src.plant_species += new A(src)
|
||||
|
||||
spawn(0)
|
||||
for (var/datum/plant/P in src.plant_species)
|
||||
for (var/X in P.mutations)
|
||||
if (ispath(X))
|
||||
P.mutations += HY_get_mutation_from_path(X)
|
||||
P.mutations -= X
|
||||
|
||||
for (var/X in P.commuts)
|
||||
if (ispath(X))
|
||||
P.commuts += HY_get_strain_from_path(X)
|
||||
P.commuts -= X
|
||||
|
||||
/proc/HY_get_species_from_path(var/species_path)
|
||||
if (!hydro_controls)
|
||||
logTheThing("debug", null, null, "<b>Hydro Controller:</b> Attempt to find species before controller setup")
|
||||
return null
|
||||
if (!species_path)
|
||||
logTheThing("debug", null, null, "<b>Hydro Controller:</b> Attempt to find species with null path in controller")
|
||||
return null
|
||||
if (!hydro_controls.plant_species.len)
|
||||
logTheThing("debug", null, null, "<b>Hydro Controller:</b> Cant find species due to empty species list in controller")
|
||||
return null
|
||||
for (var/datum/plant/P in hydro_controls.plant_species)
|
||||
if (species_path == P.type)
|
||||
return P
|
||||
logTheThing("debug", null, null, "<b>Hydro Controller:</b> Species \"[species_path]\" not found")
|
||||
return null
|
||||
|
||||
/proc/HY_get_mutation_from_path(var/mutation_path)
|
||||
if (!hydro_controls)
|
||||
logTheThing("debug", null, null, "<b>Hydro Controller:</b> Attempt to find mutation before controller setup")
|
||||
return null
|
||||
if (!mutation_path)
|
||||
logTheThing("debug", null, null, "<b>Hydro Controller:</b> Attempt to find mutation with null path in controller")
|
||||
return null
|
||||
if (!hydro_controls.mutations.len)
|
||||
logTheThing("debug", null, null, "<b>Hydro Controller:</b> Cant find mutation due to empty mutation list in controller")
|
||||
return null
|
||||
for (var/datum/plantmutation/M in hydro_controls.mutations)
|
||||
if (mutation_path == M.type)
|
||||
return M
|
||||
logTheThing("debug", null, null, "<b>Hydro Controller:</b> Mutation \"[mutation_path]\" not found")
|
||||
return null
|
||||
|
||||
/proc/HY_get_strain_from_path(var/strain_path)
|
||||
if (!hydro_controls)
|
||||
logTheThing("debug", null, null, "<b>Hydro Controller:</b> Attempt to find strain before controller setup")
|
||||
return null
|
||||
if (!strain_path)
|
||||
logTheThing("debug", null, null, "<b>Hydro Controller:</b> Attempt to find strain with null path in controller")
|
||||
return null
|
||||
if (!hydro_controls.strains.len)
|
||||
logTheThing("debug", null, null, "<b>Hydro Controller:</b> Cant find strain due to empty strain list in controller")
|
||||
return null
|
||||
for (var/datum/plant_gene_strain/S in hydro_controls.strains)
|
||||
if (strain_path == S.type)
|
||||
return S
|
||||
logTheThing("debug", null, null, "<b>Hydro Controller:</b> Strain \"[strain_path]\" not found")
|
||||
return null
|
||||
@@ -0,0 +1,710 @@
|
||||
var/datum/job_controller/job_controls
|
||||
|
||||
/datum/job_controller/
|
||||
var/list/staple_jobs = list()
|
||||
var/list/special_jobs = list()
|
||||
var/allow_special_jobs = 1 // hopefully this doesn't break anything!!
|
||||
var/datum/job/job_creator = null
|
||||
|
||||
New()
|
||||
..()
|
||||
if (derelict_mode)
|
||||
src.staple_jobs = list(new /datum/job/command/captain/derelict {limit = 1;name = "NT-SO Commander";} (),
|
||||
new /datum/job/command/head_of_security/derelict {limit = 1; name = "NT-SO Special Operative";} (),
|
||||
new /datum/job/command/chief_engineer/derelict {limit = 1; name = "Salvage Chief";} (),
|
||||
new /datum/job/security/security_officer/derelict {limit = 6; name = "NT-SO Officer";} (),
|
||||
new /datum/job/research/medical_doctor/derelict {limit = 6; name = "Salvage Medic";} (),
|
||||
new /datum/job/engineering/engineer/derelict {limit = 6; name = "Salvage Engineer";} (),
|
||||
new /datum/job/civilian/staff_assistant (),
|
||||
new /datum/job/civilian/chef (),
|
||||
new /datum/job/civilian/barman (),
|
||||
new /datum/job/civilian/chaplain ())
|
||||
|
||||
else
|
||||
for (var/A in typesof(/datum/job/command)) src.staple_jobs += new A(src)
|
||||
for (var/A in typesof(/datum/job/security)) src.staple_jobs += new A(src)
|
||||
for (var/A in typesof(/datum/job/research)) src.staple_jobs += new A(src)
|
||||
for (var/A in typesof(/datum/job/engineering)) src.staple_jobs += new A(src)
|
||||
for (var/A in typesof(/datum/job/civilian)) src.staple_jobs += new A(src)
|
||||
for (var/A in typesof(/datum/job/special)) src.special_jobs += new A(src)
|
||||
job_creator = new /datum/job/created(src)
|
||||
//Add special daily variety job
|
||||
var/variety_job_path = text2path("/datum/job/daily/[lowertext(time2text(world.realtime,"Day"))]")
|
||||
if (variety_job_path)
|
||||
src.staple_jobs += new variety_job_path(src)
|
||||
|
||||
for (var/datum/job/J in src.staple_jobs)
|
||||
// Cull any of those nasty null jobs from the category heads
|
||||
if (!J.name)
|
||||
src.staple_jobs -= J
|
||||
for (var/datum/job/J in src.special_jobs)
|
||||
if (!J.name)
|
||||
src.special_jobs -= J
|
||||
|
||||
proc/job_config()
|
||||
var/dat = "<html><body><title>Job Controller</title>"
|
||||
dat += "<b><u>Job Controls</u></b><HR>"
|
||||
dat += "<b>Command & Security Jobs</b><BR>"
|
||||
for(var/datum/job/command/JOB in src.staple_jobs)
|
||||
dat += "<a href='byond://?src=\ref[src];AlterCap=\ref[JOB]'>[JOB.name]: [countJob("[JOB.name]")]/[JOB.limit]</A><BR>"
|
||||
for(var/datum/job/security/JOB in src.staple_jobs)
|
||||
dat += "<a href='byond://?src=\ref[src];AlterCap=\ref[JOB]'>[JOB.name]: [countJob("[JOB.name]")]/[JOB.limit]</A><BR>"
|
||||
dat += "<BR>"
|
||||
dat += "<b>Research Jobs</b><BR>"
|
||||
for(var/datum/job/research/JOB in src.staple_jobs)
|
||||
dat += "<a href='byond://?src=\ref[src];AlterCap=\ref[JOB]'>[JOB.name]: [countJob("[JOB.name]")]/[JOB.limit]</A><BR>"
|
||||
dat += "<BR>"
|
||||
dat += "<b>Engineering Jobs</b><BR>"
|
||||
for(var/datum/job/engineering/JOB in src.staple_jobs)
|
||||
dat += "<a href='byond://?src=\ref[src];AlterCap=\ref[JOB]'>[JOB.name]: [countJob("[JOB.name]")]/[JOB.limit]</A><BR>"
|
||||
dat += "<BR>"
|
||||
dat += "<b>Civilian Jobs</b><BR>"
|
||||
for(var/datum/job/civilian/JOB in src.staple_jobs)
|
||||
dat += "<a href='byond://?src=\ref[src];AlterCap=\ref[JOB]'>[JOB.name]: [countJob("[JOB.name]")]/[JOB.limit]</A><BR>"
|
||||
dat += "<BR>"
|
||||
dat += "<b>Special Jobs</b><BR>"
|
||||
for(var/datum/job/special/JOB in src.special_jobs)
|
||||
dat += "<a href='byond://?src=\ref[src];AlterCap=\ref[JOB]'>[JOB.name]: [countJob("[JOB.name]")]/[JOB.limit]</A><BR>"
|
||||
for(var/datum/job/created/JOB in src.special_jobs)
|
||||
dat += "<a href='byond://?src=\ref[src];AlterCap=\ref[JOB]'>[JOB.name]: [countJob("[JOB.name]")]/[JOB.limit]</A>"
|
||||
dat += " <a href='byond://?src=\ref[src];RemoveJob=\ref[JOB]'>(Remove)</A><BR>"
|
||||
dat += "<BR>"
|
||||
if (src.allow_special_jobs)
|
||||
dat += "<A href='?src=\ref[src];SpecialToggle=1'>Special Jobs Enabled</A><BR>"
|
||||
else
|
||||
dat += "<A href='?src=\ref[src];SpecialToggle=1'>Special Jobs Disabled</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];JobCreator=1'>Create New Job</A>"
|
||||
dat += "</body></html>"
|
||||
|
||||
usr << browse(dat,"window=jobconfig;size=300x600")
|
||||
|
||||
proc/job_creator()
|
||||
var/dat = "<html><body><title>Job Creation</title>"
|
||||
dat += "<b><u>Job Creator</u></b><HR>"
|
||||
|
||||
dat += "<A href='?src=\ref[src];EditName=1'>Job Name:</A> [src.job_creator.name]<br>"
|
||||
dat += "<A href='?src=\ref[src];EditWages=1'>Wages Per Payday:</A> [src.job_creator.wages]<br>"
|
||||
dat += "<A href='?src=\ref[src];EditLimit=1'>Job Limit:</A> [src.job_creator.limit]<br>"
|
||||
dat += "<A href='?src=\ref[src];EditMob=1'>Mob Type:</A> [src.job_creator.mob_type]<br>"
|
||||
if (ispath(src.job_creator.mob_type, /mob/living/carbon/human))
|
||||
dat += "<A href='?src=\ref[src];EditHeadgear=1'>Starting Headgear:</A> [src.job_creator.slot_head]<br>"
|
||||
dat += "<A href='?src=\ref[src];EditMask=1'>Starting Mask:</A> [src.job_creator.slot_mask]<br>"
|
||||
dat += "<A href='?src=\ref[src];EditHeadset=1'>Starting Headset:</A> [src.job_creator.slot_ears]<br>"
|
||||
dat += "<A href='?src=\ref[src];EditGlasses=1'>Starting Glasses:</A> [src.job_creator.slot_eyes]<br>"
|
||||
dat += "<A href='?src=\ref[src];EditOvercoat=1'>Starting Overcoat:</A> [src.job_creator.slot_suit]<br>"
|
||||
dat += "<A href='?src=\ref[src];EditJumpsuit=1'>Starting Jumpsuit:</A> [src.job_creator.slot_jump]<br>"
|
||||
dat += "<A href='?src=\ref[src];EditIDCard=1'>Starting ID Card:</A> [src.job_creator.slot_card]<br>"
|
||||
dat += "<A href='?src=\ref[src];EditGloves=1'>Starting Gloves:</A> [src.job_creator.slot_glov]<br>"
|
||||
dat += "<A href='?src=\ref[src];EditShoes=1'>Starting Shoes:</A> [src.job_creator.slot_foot]<br>"
|
||||
dat += "<A href='?src=\ref[src];EditBack=1'>Starting Back Item:</A> [src.job_creator.slot_back]<br>"
|
||||
dat += "<A href='?src=\ref[src];EditBelt=1'>Starting Belt Item:</A> [src.job_creator.slot_belt]<br>"
|
||||
dat += "<A href='?src=\ref[src];EditPock1=1'>Starting 1st Pocket Item:</A> [src.job_creator.slot_poc1]<br>"
|
||||
dat += "<A href='?src=\ref[src];EditPock2=1'>Starting 2nd Pocket Item:</A> [src.job_creator.slot_poc2]<br>"
|
||||
dat += "<A href='?src=\ref[src];EditLhand=1'>Starting Left Hand Item:</A> [src.job_creator.slot_lhan]<br>"
|
||||
dat += "<A href='?src=\ref[src];EditRhand=1'>Starting Right Hand Item:</A> [src.job_creator.slot_rhan]<br>"
|
||||
dat += "<A href='?src=\ref[src];GetAccess=1'>Access Permissions:</A><br>"
|
||||
for(var/X in src.job_creator.access)
|
||||
dat += "[X], "
|
||||
dat += "<BR>"
|
||||
dat += "<A href='?src=\ref[src];CreateJob=1'><b>Create Job</b></A>"
|
||||
dat += "</body></html>"
|
||||
|
||||
usr << browse(dat,"window=jobcreator;size=500x600")
|
||||
|
||||
Topic(href, href_list[])
|
||||
// JOB CONFIG COMMANDS
|
||||
if(href_list["AlterCap"])
|
||||
var/list/alljobs = src.staple_jobs | src.special_jobs
|
||||
var/datum/job/JOB = locate(href_list["AlterCap"]) in alljobs
|
||||
var/newcap = input("Choose the new cap.","Job Cap Config") as num
|
||||
JOB.limit = newcap
|
||||
message_admins("Admin [key_name(usr)] altered [JOB.name] job cap to [newcap]")
|
||||
logTheThing("admin", usr, null, "altered [JOB.name] job cap to [newcap]")
|
||||
logTheThing("diary", usr, null, "altered [JOB.name] job cap to [newcap]", "admin")
|
||||
src.job_config()
|
||||
|
||||
if(href_list["RemoveJob"])
|
||||
var/list/alljobs = src.staple_jobs | src.special_jobs
|
||||
var/datum/job/JOB = locate(href_list["RemoveJob"]) in alljobs
|
||||
if (!istype(JOB,/datum/job/created/))
|
||||
boutput(usr, "<span style=\"color:red\"><b>Removing integral jobs is not allowed. Bad for business, y'know.</b></span>")
|
||||
return
|
||||
message_admins("Admin [key_name(usr)] removed special job [JOB.name]")
|
||||
logTheThing("admin", usr, null, "removed special job [JOB.name]")
|
||||
logTheThing("diary", usr, null, "removed special job [JOB.name]", "admin")
|
||||
src.special_jobs -= JOB
|
||||
src.job_config()
|
||||
|
||||
if(href_list["SpecialToggle"])
|
||||
src.allow_special_jobs = !src.allow_special_jobs
|
||||
message_admins("Admin [key_name(usr)] toggled Special Jobs [src.allow_special_jobs ? "On" : "Off"]")
|
||||
logTheThing("admin", usr, null, "toggled Special Jobs [src.allow_special_jobs ? "On" : "Off"]")
|
||||
logTheThing("diary", usr, null, "toggled Special Jobs [src.allow_special_jobs ? "On" : "Off"]", "admin")
|
||||
src.job_config()
|
||||
|
||||
if(href_list["JobCreator"])
|
||||
src.job_creator()
|
||||
|
||||
// JOB CREATOR COMMANDS
|
||||
|
||||
// I tweaked this section a little so you can actual search for certain items.
|
||||
// Scrolling through a list of ~2600 items wasn't exactly great (Convair880).
|
||||
|
||||
if(href_list["EditName"])
|
||||
var/picker = input("What is this job's name?","Job Creator")
|
||||
src.job_creator.name = picker
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["EditWages"])
|
||||
var/picker = input("How much does this job get paid each payday?","Job Creator") as num
|
||||
src.job_creator.wages = picker
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["EditLimit"])
|
||||
var/picker = input("How many of this job can there be on the station?","Job Creator") as num
|
||||
src.job_creator.limit = picker
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["EditMob"])
|
||||
var/list/L = list()
|
||||
var/search_for = input(usr, "Search for mob (or leave blank for complete list)", "Select mob") as null|text
|
||||
if (search_for)
|
||||
for (var/R in typesof(/mob))
|
||||
if (findtext("[R]", search_for)) L += R
|
||||
else
|
||||
L = typesof(/mob)
|
||||
|
||||
var/picker = null
|
||||
if (L.len == 1)
|
||||
picker = L[1]
|
||||
else if (L.len > 1)
|
||||
picker = input(usr,"Select mob:","Job Creator",null) as null|anything in L
|
||||
else
|
||||
usr.show_text("No mob matching that name", "red")
|
||||
return
|
||||
|
||||
src.job_creator.mob_type = picker
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["EditHeadgear"])
|
||||
switch(alert("Clear or reselect slotted item?","Job Creator","Clear","Reselect"))
|
||||
if("Clear")
|
||||
src.job_creator.slot_head = null
|
||||
|
||||
if("Reselect")
|
||||
var/list/L = list()
|
||||
var/search_for = input(usr, "Search for headgear (or leave blank for complete list)", "Select headgear") as null|text
|
||||
if (search_for)
|
||||
for (var/R in typesof(/obj/item/clothing/head))
|
||||
if (findtext("[R]", search_for)) L += R
|
||||
else
|
||||
L = typesof(/obj/item/clothing/head)
|
||||
|
||||
var/picker = null
|
||||
if (L.len == 1)
|
||||
picker = L[1]
|
||||
else if (L.len > 1)
|
||||
picker = input(usr,"Select headgear:","Job Creator",null) as null|anything in L
|
||||
else
|
||||
usr.show_text("No headgear matching that name", "red")
|
||||
return
|
||||
|
||||
src.job_creator.slot_head = picker
|
||||
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["EditMask"])
|
||||
switch(alert("Clear or reselect slotted item?","Job Creator","Clear","Reselect"))
|
||||
if("Clear")
|
||||
src.job_creator.slot_mask = null
|
||||
|
||||
if("Reselect")
|
||||
var/list/L = list()
|
||||
var/search_for = input(usr, "Search for mask (or leave blank for complete list)", "Select mask") as null|text
|
||||
if (search_for)
|
||||
for (var/R in typesof(/obj/item/clothing/mask))
|
||||
if (findtext("[R]", search_for)) L += R
|
||||
else
|
||||
L = typesof(/obj/item/clothing/mask)
|
||||
|
||||
var/picker = null
|
||||
if (L.len == 1)
|
||||
picker = L[1]
|
||||
else if (L.len > 1)
|
||||
picker = input(usr,"Select mask:","Job Creator",null) as null|anything in L
|
||||
else
|
||||
usr.show_text("No mask matching that name", "red")
|
||||
return
|
||||
|
||||
src.job_creator.slot_mask = picker
|
||||
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["EditHeadset"])
|
||||
switch(alert("Clear or reselect slotted item?","Job Creator","Clear","Reselect"))
|
||||
if("Clear")
|
||||
src.job_creator.slot_ears = null
|
||||
|
||||
if("Reselect")
|
||||
var/list/L = list()
|
||||
var/search_for = input(usr, "Search for headset (or leave blank for complete list)", "Select headset") as null|text
|
||||
if (search_for)
|
||||
for (var/R in typesof(/obj/item/device/radio/headset))
|
||||
if (findtext("[R]", search_for)) L += R
|
||||
else
|
||||
L = typesof(/obj/item/device/radio/headset)
|
||||
|
||||
var/picker = null
|
||||
if (L.len == 1)
|
||||
picker = L[1]
|
||||
else if (L.len > 1)
|
||||
picker = input(usr,"Select headset:","Job Creator",null) as null|anything in L
|
||||
else
|
||||
usr.show_text("No headset matching that name", "red")
|
||||
return
|
||||
|
||||
src.job_creator.slot_ears = picker
|
||||
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["EditGlasses"])
|
||||
switch(alert("Clear or reselect slotted item?","Job Creator","Clear","Reselect"))
|
||||
if("Clear")
|
||||
src.job_creator.slot_eyes = null
|
||||
|
||||
if("Reselect")
|
||||
var/list/L = list()
|
||||
var/search_for = input(usr, "Search for glasses (or leave blank for complete list)", "Select glasses") as null|text
|
||||
if (search_for)
|
||||
for (var/R in typesof(/obj/item/clothing/glasses))
|
||||
if (findtext("[R]", search_for)) L += R
|
||||
else
|
||||
L = typesof(/obj/item/clothing/glasses)
|
||||
|
||||
var/picker = null
|
||||
if (L.len == 1)
|
||||
picker = L[1]
|
||||
else if (L.len > 1)
|
||||
picker = input(usr,"Select glasses:","Job Creator",null) as null|anything in L
|
||||
else
|
||||
usr.show_text("No glasses matching that name", "red")
|
||||
return
|
||||
|
||||
src.job_creator.slot_eyes = picker
|
||||
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["EditOvercoat"])
|
||||
switch(alert("Clear or reselect slotted item?","Job Creator","Clear","Reselect"))
|
||||
if("Clear")
|
||||
src.job_creator.slot_suit = null
|
||||
|
||||
if("Reselect")
|
||||
var/list/L = list()
|
||||
var/search_for = input(usr, "Search for exosuit (or leave blank for complete list)", "Select exosuit") as null|text
|
||||
if (search_for)
|
||||
for (var/R in typesof(/obj/item/clothing/suit))
|
||||
if (findtext("[R]", search_for)) L += R
|
||||
else
|
||||
L = typesof(/obj/item/clothing/suit)
|
||||
|
||||
var/picker = null
|
||||
if (L.len == 1)
|
||||
picker = L[1]
|
||||
else if (L.len > 1)
|
||||
picker = input(usr,"Select exosuit:","Job Creator",null) as null|anything in L
|
||||
else
|
||||
usr.show_text("No exosuit matching that name", "red")
|
||||
return
|
||||
|
||||
src.job_creator.slot_suit = picker
|
||||
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["EditJumpsuit"])
|
||||
switch(alert("Clear or reselect slotted item?","Job Creator","Clear","Reselect"))
|
||||
if("Clear")
|
||||
src.job_creator.slot_jump = null
|
||||
|
||||
if("Reselect")
|
||||
var/list/L = list()
|
||||
var/search_for = input(usr, "Search for jumpsuit (or leave blank for complete list)", "Select jumpsuit") as null|text
|
||||
if (search_for)
|
||||
for (var/R in typesof(/obj/item/clothing/under))
|
||||
if (findtext("[R]", search_for)) L += R
|
||||
else
|
||||
L = typesof(/obj/item/clothing/under)
|
||||
|
||||
var/picker = null
|
||||
if (L.len == 1)
|
||||
picker = L[1]
|
||||
else if (L.len > 1)
|
||||
picker = input(usr,"Select jumpsuit:","Job Creator",null) as null|anything in L
|
||||
else
|
||||
usr.show_text("No jumpsuit matching that name", "red")
|
||||
return
|
||||
|
||||
src.job_creator.slot_jump = picker
|
||||
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["EditIDCard"])
|
||||
switch(alert("Clear or reselect slotted item?","Job Creator","Clear","Reselect"))
|
||||
if("Clear")
|
||||
src.job_creator.slot_card = null
|
||||
|
||||
if("Reselect")
|
||||
var/list/L = list()
|
||||
var/search_for = input(usr, "Search for ID card (or leave blank for complete list)", "Select ID card") as null|text
|
||||
if (search_for)
|
||||
for (var/R in (typesof(/obj/item/card) - list(/obj/item/card/emag, /obj/item/card/emag/fake, /obj/item/card/id/gauntlet)))
|
||||
if (findtext("[R]", search_for)) L += R
|
||||
else
|
||||
// These cards can't be worn on the ID slot and they're not compatible with the
|
||||
// job controller because they don't support access lists (Convair880).
|
||||
L = (typesof(/obj/item/card) - list(/obj/item/card/emag, /obj/item/card/emag/fake, /obj/item/card/id/gauntlet))
|
||||
|
||||
var/picker = null
|
||||
if (L.len == 1)
|
||||
picker = L[1]
|
||||
else if (L.len > 1)
|
||||
picker = input(usr,"Select ID card:","Job Creator",null) as null|anything in L
|
||||
else
|
||||
usr.show_text("No ID card matching that name", "red")
|
||||
return
|
||||
|
||||
src.job_creator.slot_card = picker
|
||||
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["EditGloves"])
|
||||
switch(alert("Clear or reselect slotted item?","Job Creator","Clear","Reselect"))
|
||||
if("Clear")
|
||||
src.job_creator.slot_glov = null
|
||||
|
||||
if("Reselect")
|
||||
var/list/L = list()
|
||||
var/search_for = input(usr, "Search for gloves (or leave blank for complete list)", "Select gloves") as null|text
|
||||
if (search_for)
|
||||
for (var/R in typesof(/obj/item/clothing/gloves))
|
||||
if (findtext("[R]", search_for)) L += R
|
||||
else
|
||||
L = typesof(/obj/item/clothing/gloves)
|
||||
|
||||
var/picker = null
|
||||
if (L.len == 1)
|
||||
picker = L[1]
|
||||
else if (L.len > 1)
|
||||
picker = input(usr,"Select gloves:","Job Creator",null) as null|anything in L
|
||||
else
|
||||
usr.show_text("No gloves matching that name", "red")
|
||||
return
|
||||
|
||||
src.job_creator.slot_glov = picker
|
||||
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["EditShoes"])
|
||||
switch(alert("Clear or reselect slotted item?","Job Creator","Clear","Reselect"))
|
||||
if("Clear")
|
||||
src.job_creator.slot_foot = null
|
||||
|
||||
if("Reselect")
|
||||
var/list/L = list()
|
||||
var/search_for = input(usr, "Search for shoes (or leave blank for complete list)", "Select shoes") as null|text
|
||||
if (search_for)
|
||||
for (var/R in typesof(/obj/item/clothing/shoes))
|
||||
if (findtext("[R]", search_for)) L += R
|
||||
else
|
||||
L = typesof(/obj/item/clothing/shoes)
|
||||
|
||||
var/picker = null
|
||||
if (L.len == 1)
|
||||
picker = L[1]
|
||||
else if (L.len > 1)
|
||||
picker = input(usr,"Select shoes:","Job Creator",null) as null|anything in L
|
||||
else
|
||||
usr.show_text("No shoes matching that name", "red")
|
||||
return
|
||||
|
||||
src.job_creator.slot_foot = picker
|
||||
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["EditBack"])
|
||||
switch(alert("Clear or reselect slotted item?","Job Creator","Clear","Reselect"))
|
||||
if("Clear")
|
||||
src.job_creator.slot_back = null
|
||||
|
||||
if("Reselect")
|
||||
var/list/L = list()
|
||||
var/search_for = input(usr, "Search for backslot item (or leave blank for complete list)", "Select backslot item") as null|text
|
||||
if (search_for)
|
||||
for (var/R in typesof(/obj/item/))
|
||||
if (findtext("[R]", search_for)) L += R
|
||||
else
|
||||
L = typesof(/obj/item/)
|
||||
|
||||
var/picker = null
|
||||
if (L.len == 1)
|
||||
picker = L[1]
|
||||
else if (L.len > 1)
|
||||
picker = input(usr,"Select backslot item:","Job Creator",null) as null|anything in L
|
||||
else
|
||||
usr.show_text("No backslot item matching that name", "red")
|
||||
return
|
||||
|
||||
// I wish there would be a better way to filter this stuff, typesof() just doesn't cut it.
|
||||
// I suppose this is still slightly more elegant than the fixed (and outdated) list that
|
||||
// used to be here. Anway, the job controller will not spawn unsuitable items (Convair880).
|
||||
if (picker)
|
||||
var/obj/item/check = new picker
|
||||
if (!(check.flags & ONBACK))
|
||||
usr.show_text("This item cannot be worn on the back slot.", "red")
|
||||
qdel(check)
|
||||
return
|
||||
qdel(check)
|
||||
|
||||
src.job_creator.slot_back = picker
|
||||
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["EditBelt"])
|
||||
switch(alert("Clear or reselect slotted item?","Job Creator","Clear","Reselect"))
|
||||
if("Clear")
|
||||
src.job_creator.slot_belt = null
|
||||
|
||||
if("Reselect")
|
||||
var/list/L = list()
|
||||
var/search_for = input(usr, "Search for beltslot item (or leave blank for complete list)", "Select beltslot item") as null|text
|
||||
if (search_for)
|
||||
for (var/R in typesof(/obj/item/))
|
||||
if (findtext("[R]", search_for)) L += R
|
||||
else
|
||||
L = typesof(/obj/item/)
|
||||
|
||||
var/picker = null
|
||||
if (L.len == 1)
|
||||
picker = L[1]
|
||||
else if (L.len > 1)
|
||||
picker = input(usr,"Select beltslot item:","Job Creator",null) as null|anything in L
|
||||
else
|
||||
usr.show_text("No beltslot item matching that name", "red")
|
||||
return
|
||||
|
||||
// Ditto (Convair880).
|
||||
if (picker)
|
||||
var/obj/item/check = new picker
|
||||
if (!(check.flags & ONBELT))
|
||||
usr.show_text("This item cannot be worn on the belt slot.", "red")
|
||||
qdel(check)
|
||||
return
|
||||
qdel(check)
|
||||
|
||||
src.job_creator.slot_belt = picker
|
||||
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["EditPock1"])
|
||||
switch(alert("Clear or reselect slotted item?","Job Creator","Clear","Reselect"))
|
||||
if("Clear")
|
||||
src.job_creator.slot_poc1 = null
|
||||
|
||||
if("Reselect")
|
||||
var/list/L = list()
|
||||
var/search_for = input(usr, "Search for item (or leave blank for complete list)", "Select pocket #1") as null|text
|
||||
if (search_for)
|
||||
for (var/R in typesof(/obj/item/))
|
||||
if (findtext("[R]", search_for)) L += R
|
||||
else
|
||||
L = typesof(/obj/item/)
|
||||
|
||||
var/picker = null
|
||||
if (L.len == 1)
|
||||
picker = L[1]
|
||||
else if (L.len > 1)
|
||||
picker = input(usr,"Select item:","Job Creator",null) as null|anything in L
|
||||
else
|
||||
usr.show_text("No item matching that name", "red")
|
||||
return
|
||||
|
||||
// Ditto (Convair880).
|
||||
if (picker)
|
||||
var/obj/item/check = new picker
|
||||
if (check.w_class > 2)
|
||||
usr.show_text("This item is too large to fit in a jumpsuit pocket.", "red")
|
||||
qdel(check)
|
||||
return
|
||||
qdel(check)
|
||||
|
||||
src.job_creator.slot_poc1 = picker
|
||||
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["EditPock2"])
|
||||
switch(alert("Clear or reselect slotted item?","Job Creator","Clear","Reselect"))
|
||||
if("Clear")
|
||||
src.job_creator.slot_poc2 = null
|
||||
|
||||
if("Reselect")
|
||||
var/list/L = list()
|
||||
var/search_for = input(usr, "Search for item (or leave blank for complete list)", "Select pocket #2") as null|text
|
||||
if (search_for)
|
||||
for (var/R in typesof(/obj/item/))
|
||||
if (findtext("[R]", search_for)) L += R
|
||||
else
|
||||
L = typesof(/obj/item/)
|
||||
|
||||
var/picker = null
|
||||
if (L.len == 1)
|
||||
picker = L[1]
|
||||
else if (L.len > 1)
|
||||
picker = input(usr,"Select item:","Job Creator",null) as null|anything in L
|
||||
else
|
||||
usr.show_text("No item matching that name", "red")
|
||||
return
|
||||
|
||||
// Ditto (Convair880).
|
||||
if (picker)
|
||||
var/obj/item/check = new picker
|
||||
if (check.w_class > 2)
|
||||
usr.show_text("This item is too large to fit in a jumpsuit pocket.", "red")
|
||||
qdel(check)
|
||||
return
|
||||
qdel(check)
|
||||
|
||||
src.job_creator.slot_poc2 = picker
|
||||
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["EditLhand"])
|
||||
switch(alert("Clear or reselect slotted item?","Job Creator","Clear","Reselect"))
|
||||
if("Clear")
|
||||
src.job_creator.slot_lhan = null
|
||||
|
||||
if("Reselect")
|
||||
var/list/L = list()
|
||||
var/search_for = input(usr, "Search for item (or leave blank for complete list)", "Select left hand") as null|text
|
||||
if (search_for)
|
||||
for (var/R in typesof(/obj/item/))
|
||||
if (findtext("[R]", search_for)) L += R
|
||||
else
|
||||
L = typesof(/obj/item/)
|
||||
|
||||
var/picker = null
|
||||
if (L.len == 1)
|
||||
picker = L[1]
|
||||
else if (L.len > 1)
|
||||
picker = input(usr,"Select item:","Job Creator",null) as null|anything in L
|
||||
else
|
||||
usr.show_text("No item matching that name", "red")
|
||||
return
|
||||
|
||||
src.job_creator.slot_lhan = picker
|
||||
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["EditRhand"])
|
||||
switch(alert("Clear or reselect slotted item?","Job Creator","Clear","Reselect"))
|
||||
if("Clear")
|
||||
src.job_creator.slot_rhan = null
|
||||
|
||||
if("Reselect")
|
||||
var/list/L = list()
|
||||
var/search_for = input(usr, "Search for item (or leave blank for complete list)", "Select right hand") as null|text
|
||||
if (search_for)
|
||||
for (var/R in typesof(/obj/item/))
|
||||
if (findtext("[R]", search_for)) L += R
|
||||
else
|
||||
L = typesof(/obj/item/)
|
||||
|
||||
var/picker = null
|
||||
if (L.len == 1)
|
||||
picker = L[1]
|
||||
else if (L.len > 1)
|
||||
picker = input(usr,"Select item:","Job Creator",null) as null|anything in L
|
||||
else
|
||||
usr.show_text("No item matching that name", "red")
|
||||
return
|
||||
|
||||
src.job_creator.slot_rhan = picker
|
||||
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["GetAccess"])
|
||||
var/picker = input("Make this job's access comparable to which job?","Job Creator") in list("Captain","Head of Security",
|
||||
"Head of Personnel","Chief Engineer","Research Director","Security Officer","Detective","Geneticist","Roboticist","Scientist",
|
||||
"Medical Doctor","Quartermaster","Miner","Mechanic","Engineer","Chef","Barman","Botanist","Janitor","Chaplain","Staff Assistant","No Access")
|
||||
src.job_creator.access = get_access(picker)
|
||||
src.job_creator()
|
||||
|
||||
if(href_list["CreateJob"])
|
||||
var/datum/job/match_check = find_job_in_controller_by_string(src.job_creator.name)
|
||||
if (match_check)
|
||||
boutput(usr, "<span style=\"color:red\"><b>A job with this name already exists. It cannot be created.</b></span>")
|
||||
return
|
||||
else
|
||||
var/datum/job/created/JOB = new /datum/job/created(src)
|
||||
src.special_jobs += JOB
|
||||
JOB.name = src.job_creator.name
|
||||
JOB.wages = src.job_creator.wages
|
||||
JOB.limit = src.job_creator.limit
|
||||
JOB.mob_type = src.job_creator.mob_type
|
||||
JOB.slot_head = src.job_creator.slot_head
|
||||
JOB.slot_mask = src.job_creator.slot_mask
|
||||
JOB.slot_ears = src.job_creator.slot_ears
|
||||
JOB.slot_eyes = src.job_creator.slot_eyes
|
||||
JOB.slot_glov = src.job_creator.slot_glov
|
||||
JOB.slot_foot = src.job_creator.slot_foot
|
||||
JOB.slot_card = src.job_creator.slot_card
|
||||
JOB.slot_jump = src.job_creator.slot_jump
|
||||
JOB.slot_suit = src.job_creator.slot_suit
|
||||
JOB.slot_back = src.job_creator.slot_back
|
||||
JOB.slot_belt = src.job_creator.slot_belt
|
||||
JOB.slot_poc1 = src.job_creator.slot_poc1
|
||||
JOB.slot_poc2 = src.job_creator.slot_poc2
|
||||
JOB.slot_lhan = src.job_creator.slot_lhan
|
||||
JOB.slot_rhan = src.job_creator.slot_rhan
|
||||
JOB.access = JOB.access | src.job_creator.access
|
||||
message_admins("Admin [key_name(usr)] created special job [JOB.name]")
|
||||
logTheThing("admin", usr, null, "created special job [JOB.name]")
|
||||
logTheThing("diary", usr, null, "created special job [JOB.name]", "admin")
|
||||
src.job_creator()
|
||||
|
||||
/proc/find_job_in_controller_by_string(var/string,var/staple_only = 0)
|
||||
if (!string || !istext(string))
|
||||
logTheThing("debug", null, null, "<b>Job Controller:</b> Attempt to find job with bad string in controller detected")
|
||||
return null
|
||||
var/list/excluded_strings = list("Special Respawn","Custom Names","Everything Except Assistant",
|
||||
"Engineering Department","Security Department","Heads of Staff")
|
||||
if (string in excluded_strings)
|
||||
return null
|
||||
for (var/datum/job/J in job_controls.staple_jobs)
|
||||
if (J.name == string)
|
||||
return J
|
||||
if (!staple_only)
|
||||
for (var/datum/job/J in job_controls.special_jobs)
|
||||
if (J.name == string)
|
||||
return J
|
||||
logTheThing("debug", null, null, "<b>Job Controller:</b> Attempt to find job by string \"[string]\" in controller failed")
|
||||
return null
|
||||
|
||||
/proc/find_job_in_controller_by_path(var/path)
|
||||
if (!path || !ispath(path) || !istype(path,/datum/job/))
|
||||
logTheThing("debug", null, null, "<b>Job Controller:</b> Attempt to find job with bad path in controller detected")
|
||||
return null
|
||||
for (var/datum/job/J in job_controls.staple_jobs)
|
||||
if (J.type == path)
|
||||
return J
|
||||
for (var/datum/job/J in job_controls.special_jobs)
|
||||
if (J.type == path)
|
||||
return J
|
||||
logTheThing("debug", null, null, "<b>Job Controller:</b> Attempt to find job by path \"[path]\" in controller failed")
|
||||
return null
|
||||
|
||||
/client/proc/cmd_job_controls()
|
||||
set category = "Debug"
|
||||
set name = "Job Controls"
|
||||
|
||||
if (job_controls == null) boutput(src, "UH OH! Shit's broken as fuck!")
|
||||
else src.debug_variables(job_controls)
|
||||
@@ -0,0 +1,53 @@
|
||||
var/datum/manufacturing_controller/manuf_controls
|
||||
|
||||
/datum/manufacturing_controller
|
||||
var/list/manufacturing_units = list()
|
||||
var/list/normal_schematics = list()
|
||||
var/list/custom_schematics = list()
|
||||
|
||||
proc/set_up()
|
||||
for (var/M in typesof(/datum/manufacture) - /datum/manufacture)
|
||||
src.normal_schematics += new M
|
||||
for (var/obj/machinery/manufacturer/M in world)
|
||||
src.manufacturing_units += M
|
||||
M.set_up_schematics()
|
||||
M.claim_free_resources()
|
||||
|
||||
/proc/get_schematic_from_path(var/schematic_path)
|
||||
if (!ispath(schematic_path))
|
||||
logTheThing("debug", null, null, "<b>Manufacturer:</b> Attempt to find schematic with null path")
|
||||
return null
|
||||
if (!manuf_controls.normal_schematics.len)
|
||||
logTheThing("debug", null, null, "<b>Manufacturer:</b> Cant find schematic due to empty schematic list")
|
||||
return null
|
||||
for (var/datum/manufacture/M in manuf_controls.normal_schematics)
|
||||
if (schematic_path == M.type)
|
||||
return M
|
||||
logTheThing("debug", null, null, "<b>Manufacturer:</b> Schematic \"[schematic_path]\" not found")
|
||||
return null
|
||||
|
||||
/proc/get_schematic_from_name(var/schematic_name)
|
||||
if (!istext(schematic_name))
|
||||
logTheThing("debug", null, null, "<b>Manufacturer:</b> Attempt to find schematic with non-string")
|
||||
return null
|
||||
if (!manuf_controls.normal_schematics.len && !manuf_controls.custom_schematics.len)
|
||||
logTheThing("debug", null, null, "<b>Manufacturer:</b> Cant find schematic due to empty schematic lists")
|
||||
return null
|
||||
for (var/datum/manufacture/M in (manuf_controls.normal_schematics + manuf_controls.custom_schematics))
|
||||
if (schematic_name == M.name)
|
||||
return M
|
||||
logTheThing("debug", null, null, "<b>Manufacturer:</b> Schematic with name \"[schematic_name]\" not found")
|
||||
return null
|
||||
|
||||
/proc/get_schematic_from_name_in_custom(var/schematic_name)
|
||||
if (!istext(schematic_name))
|
||||
logTheThing("debug", null, null, "<b>Manufacturer:</b> Attempt to find schematic with non-string")
|
||||
return null
|
||||
if (!manuf_controls.custom_schematics.len)
|
||||
logTheThing("debug", null, null, "<b>Manufacturer:</b> Cant find schematic due to empty schematic lists")
|
||||
return null
|
||||
for (var/datum/manufacture/M in manuf_controls.custom_schematics)
|
||||
if (schematic_name == M.name)
|
||||
return M
|
||||
logTheThing("debug", null, null, "<b>Manufacturer:</b> Schematic with name \"[schematic_name]\" not found")
|
||||
return null
|
||||
@@ -0,0 +1,73 @@
|
||||
var/datum/mechanic_controller/mechanic_controls
|
||||
|
||||
/datum/mechanic_controller
|
||||
var/list/scanned_items = list()
|
||||
var/list/rkit_addresses = list()
|
||||
|
||||
proc
|
||||
scan_in(var/N,var/T,var/M)
|
||||
var/datum/electronics/scanned_item/S = new/datum/electronics/scanned_item
|
||||
S.name = N
|
||||
S.item_type = T
|
||||
S.item_mats = M
|
||||
S.create_partslist(M)
|
||||
S.create_blueprint(M)
|
||||
src.scanned_items += S
|
||||
return 1
|
||||
|
||||
/datum/electronics/scanned_item
|
||||
var
|
||||
name = "Unknown"
|
||||
item_type = ""
|
||||
var/list/item_mats
|
||||
var/finish_time = 0
|
||||
var/datum/manufacture/mechanics/blueprint = null
|
||||
|
||||
proc
|
||||
create_partslist(var/mats_number = 10)
|
||||
if (!isnum(mats_number))
|
||||
mats_number = 10
|
||||
item_mats = list("battery"=0,"fuse"=0,"switch"=0,"capacitor"=0,"resistor"=0,"bulb"=0,"relay"=0,"board"=0,"keypad"=0,"screen"=0,"buzzer"=0)
|
||||
var/number_of_parts = mats_number
|
||||
var/advanced_chance = 20
|
||||
var/advanced_max = 0
|
||||
|
||||
if(number_of_parts >= 6)
|
||||
advanced_max = round(number_of_parts/6)
|
||||
advanced_chance = round(20*(number_of_parts/6))
|
||||
|
||||
for(var/tracker = 1, tracker <= number_of_parts, tracker ++)
|
||||
var/part
|
||||
if(prob(advanced_chance)&&(advanced_max))
|
||||
part = pick("board","keypad","screen","buzzer")
|
||||
advanced_max --
|
||||
else
|
||||
part = pick("battery","fuse","switch","capacitor","resistor","bulb","relay")
|
||||
|
||||
item_mats[part] = item_mats[part] + 1
|
||||
return
|
||||
|
||||
create_blueprint(var/mats_number = 10)
|
||||
if (istype(src.blueprint,/datum/manufacture/mechanics/))
|
||||
return
|
||||
if (get_schematic_from_name_in_custom(src.name))
|
||||
return
|
||||
if (!isnum(mats_number))
|
||||
mats_number = 10
|
||||
|
||||
var/datum/manufacture/mechanics/M = new /datum/manufacture/mechanics(manuf_controls)
|
||||
manuf_controls.custom_schematics += M
|
||||
M.name = src.name
|
||||
M.time = mats_number * 2
|
||||
M.frame_path = src.item_type
|
||||
|
||||
if (mats_number > 3)
|
||||
mats_number -= 3
|
||||
// to cover the base materials
|
||||
|
||||
if (mats_number > 0)
|
||||
for(var/tracker = 1, tracker <= mats_number, tracker ++)
|
||||
M.item_amounts[rand(1,3)] += 1
|
||||
|
||||
src.blueprint = M
|
||||
return
|
||||
@@ -0,0 +1,221 @@
|
||||
var/datum/mining_controller/mining_controls
|
||||
|
||||
var/list/asteroid_blocked_turfs = list()
|
||||
var/turf_spawn_edge_limit = 5
|
||||
|
||||
/datum/mining_controller
|
||||
var/list/ore_types_common = list()
|
||||
var/list/ore_types_uncommon = list()
|
||||
var/list/ore_types_rare = list()
|
||||
var/list/events = list()
|
||||
// magnet vars
|
||||
var/turf/magnetic_center = null
|
||||
var/area/mining/magnet/magnet_area = null
|
||||
var/list/magnet_shields = list()
|
||||
var/max_magnet_spawn_size = 7
|
||||
var/min_magnet_spawn_size = 4
|
||||
var/list/mining_encounters_common = list()
|
||||
var/list/mining_encounters_uncommon = list()
|
||||
var/list/mining_encounters_rare = list()
|
||||
var/list/small_encounters = list()
|
||||
|
||||
var/list/magnet_do_not_erase = list(/obj/securearea,/obj/forcefield/mining,/obj/grille/catwalk)
|
||||
|
||||
New()
|
||||
..()
|
||||
for (var/X in typesof(/datum/ore) - /datum/ore - /datum/ore/event)
|
||||
var/datum/ore/O = new X
|
||||
ore_types_common += O
|
||||
|
||||
for (var/X in typesof(/datum/mining_encounter) - /datum/mining_encounter)
|
||||
var/datum/mining_encounter/MC = new X
|
||||
mining_encounters_common += MC
|
||||
|
||||
for (var/datum/ore/O in src.ore_types_common)
|
||||
if (istype(O, /datum/ore/event/))
|
||||
events += O
|
||||
ore_types_common -= O
|
||||
if (O.rarity_tier == 2)
|
||||
ore_types_uncommon += O
|
||||
ore_types_common -= O
|
||||
else if (O.rarity_tier == 3)
|
||||
ore_types_rare += O
|
||||
ore_types_common -= O
|
||||
O.set_up()
|
||||
|
||||
for (var/datum/mining_encounter/MC in mining_encounters_common)
|
||||
if (MC.rarity_tier == 3)
|
||||
mining_encounters_rare += MC
|
||||
mining_encounters_common -= MC
|
||||
else if (MC.rarity_tier == 2)
|
||||
mining_encounters_uncommon += MC
|
||||
mining_encounters_common -= MC
|
||||
else if (MC.rarity_tier == -1)
|
||||
small_encounters += MC
|
||||
mining_encounters_common -= MC
|
||||
else if (MC.rarity_tier != 1)
|
||||
mining_encounters_common -= MC
|
||||
qdel(MC)
|
||||
|
||||
for (var/obj/landmark/magnet_center/MC in world)
|
||||
magnetic_center = get_turf(MC)
|
||||
magnet_area = get_area(MC)
|
||||
MC.dispose()
|
||||
break
|
||||
|
||||
for (var/obj/landmark/magnet_shield/MS in world)
|
||||
var/obj/forcefield/mining/S = new /obj/forcefield/mining(get_turf(MS))
|
||||
magnet_shields += S
|
||||
MS.dispose()
|
||||
|
||||
proc/get_ore_from_string(var/string)
|
||||
if (!istext(string))
|
||||
return
|
||||
for (var/datum/ore/O in ore_types_common + ore_types_uncommon + ore_types_rare)
|
||||
if (O.name == string)
|
||||
return O
|
||||
return null
|
||||
|
||||
proc/get_ore_from_path(var/path)
|
||||
if (!ispath(path))
|
||||
return
|
||||
for (var/datum/ore/O in ore_types_common + ore_types_uncommon + ore_types_rare)
|
||||
if (O.type == path)
|
||||
return O
|
||||
return null
|
||||
|
||||
proc/select_encounter(var/rarity_mod)
|
||||
if (!isnum(rarity_mod))
|
||||
rarity_mod = 0
|
||||
var/chosen = RarityClassRoll(100,rarity_mod,list(95,70))
|
||||
|
||||
var/list/category = mining_controls.mining_encounters_common
|
||||
switch(chosen)
|
||||
if (2)
|
||||
category = mining_controls.mining_encounters_uncommon
|
||||
if (3)
|
||||
category = mining_controls.mining_encounters_rare
|
||||
|
||||
if (category.len < 1)
|
||||
category = mining_controls.mining_encounters_common
|
||||
|
||||
return pick(category)
|
||||
|
||||
proc/select_small_encounter(var/rarity_mod)
|
||||
return pick(small_encounters)
|
||||
|
||||
/area/mining/magnet
|
||||
name = "Magnet Area"
|
||||
icon_state = "purple"
|
||||
RL_Lighting = 0
|
||||
requires_power = 0
|
||||
luminosity = 1
|
||||
|
||||
proc/check_for_unacceptable_content()
|
||||
for (var/mob/living/L in src.contents)
|
||||
return 1
|
||||
for (var/obj/machinery/vehicle in src.contents)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/forcefield/mining
|
||||
name = "magnetic forcefield"
|
||||
desc = "A powerful field used by the mining magnet to attract minerals."
|
||||
icon = 'icons/misc/old_or_unused.dmi'
|
||||
icon_state = "noise6"
|
||||
color = "#BF12DE"
|
||||
alpha = 175
|
||||
opacity = 0
|
||||
density = 0
|
||||
invisibility = 101
|
||||
anchored = 1
|
||||
|
||||
/// *** MISC *** ///
|
||||
|
||||
/proc/getOreQualityName(var/quality)
|
||||
switch(quality)
|
||||
if(-INFINITY to -101)
|
||||
return "worthless"
|
||||
if(-100 to -51)
|
||||
return "terrible"
|
||||
if(-50 to -41)
|
||||
return "awful"
|
||||
if(-40 to -31)
|
||||
return "bad"
|
||||
if(-30 to -21)
|
||||
return "low-grade"
|
||||
if(-20 to -11)
|
||||
return "poor"
|
||||
if(-10 to -1)
|
||||
return "impure"
|
||||
if(0)
|
||||
return ""
|
||||
if(1 to 10)
|
||||
return "decent"
|
||||
if(11 to 20)
|
||||
return "fine"
|
||||
if(21 to 30)
|
||||
return "good"
|
||||
if(31 to 40)
|
||||
return "high-quality"
|
||||
if(41 to 50)
|
||||
return "excellent"
|
||||
if(51 to 60)
|
||||
return "fantastic"
|
||||
if(61 to 70)
|
||||
return "amazing"
|
||||
if(71 to 80)
|
||||
return "incredible"
|
||||
if(81 to 90)
|
||||
return "supreme"
|
||||
if(91 to 100)
|
||||
return "pure"
|
||||
if(101 to INFINITY)
|
||||
return "perfect"
|
||||
else
|
||||
return "strange"
|
||||
return
|
||||
|
||||
/proc/getGemQualityName(var/quality)
|
||||
switch(quality)
|
||||
if(-INFINITY to -101)
|
||||
return "worthless"
|
||||
if(-100 to -51)
|
||||
return "awful"
|
||||
if(-50 to -41)
|
||||
return "shattered"
|
||||
if(-40 to -31)
|
||||
return "broken"
|
||||
if(-30 to -21)
|
||||
return "cracked"
|
||||
if(-20 to -11)
|
||||
return "flawed"
|
||||
if(-10 to -1)
|
||||
return "dull"
|
||||
if(0)
|
||||
return ""
|
||||
if(1 to 10)
|
||||
return "pretty"
|
||||
if(11 to 20)
|
||||
return "shiny"
|
||||
if(21 to 30)
|
||||
return "gleaming"
|
||||
if(31 to 40)
|
||||
return "sparkling"
|
||||
if(41 to 50)
|
||||
return "glittering"
|
||||
if(51 to 60)
|
||||
return "beautiful"
|
||||
if(61 to 70)
|
||||
return "lustrous"
|
||||
if(71 to 80)
|
||||
return "iridescent"
|
||||
if(81 to 90)
|
||||
return "radiant"
|
||||
if(91 to 100)
|
||||
return "pristine"
|
||||
if(101 to INFINITY)
|
||||
return "perfect"
|
||||
else
|
||||
return "strange"
|
||||
return
|
||||
@@ -0,0 +1,12 @@
|
||||
// handles timed player actions
|
||||
datum/controller/process/actions
|
||||
var/action_controler
|
||||
|
||||
setup()
|
||||
name = "Actions"
|
||||
schedule_interval = 5
|
||||
|
||||
action_controler = actions
|
||||
|
||||
doWork()
|
||||
actions.process()
|
||||
@@ -0,0 +1,12 @@
|
||||
datum/controller/process/ai_tracking
|
||||
|
||||
setup()
|
||||
name = "AI Tracking"
|
||||
schedule_interval = 10
|
||||
sleep_interval = 0.1
|
||||
|
||||
doWork()
|
||||
for(var/datum/ai_camera_tracker/T in global.tracking_list)
|
||||
T.process()
|
||||
|
||||
scheck()
|
||||
@@ -0,0 +1,16 @@
|
||||
// handles air processing.
|
||||
datum/controller/process/air_system
|
||||
setup()
|
||||
name = "Atmos"
|
||||
schedule_interval = 25 // 2.5 seconds
|
||||
|
||||
if(!air_master)
|
||||
air_master = new /datum/controller/air_system()
|
||||
air_master.setup(src)
|
||||
air_master.set_controller(src)
|
||||
|
||||
doWork()
|
||||
air_master.process()
|
||||
|
||||
copyStateFrom(var/datum/controller/process/target)
|
||||
air_master.set_controller(src)
|
||||
@@ -0,0 +1,16 @@
|
||||
datum/controller/process/arena
|
||||
var/list/arenas = list()
|
||||
|
||||
setup()
|
||||
name = "Arena"
|
||||
schedule_interval = 8 // 0.8 seconds
|
||||
|
||||
arenas += gauntlet_controller
|
||||
arenas += colosseum_controller
|
||||
|
||||
doWork()
|
||||
for (var/datum/arena/A in arenas)
|
||||
A.tick()
|
||||
|
||||
tickDetail()
|
||||
boutput(usr, "No statistics available.")
|
||||
@@ -0,0 +1,39 @@
|
||||
//Handles blobs without being pissy about it
|
||||
datum/controller/process/blob
|
||||
var/list/blobs = list()
|
||||
|
||||
var/tmp/list/detailed_count
|
||||
var/tmp/datum/updateQueue/blobUpdateQueue
|
||||
|
||||
setup()
|
||||
name = "Blob"
|
||||
schedule_interval = 31 // 3.1 seconds
|
||||
|
||||
detailed_count = new
|
||||
blobUpdateQueue = new
|
||||
|
||||
doWork()
|
||||
|
||||
for (var/obj/blob/B in blobs)
|
||||
if (B.runOnLife || B.poison)
|
||||
B.Life()
|
||||
scheck()
|
||||
|
||||
/*var/currentTick = ticks
|
||||
|
||||
for(var/obj/blob/B in blobs)
|
||||
if (prob (B.life_prob))
|
||||
B.Life()
|
||||
|
||||
detailed_count["[B.type]"]++
|
||||
|
||||
scheck(currentTick)*/
|
||||
|
||||
tickDetail()
|
||||
if (detailed_count && detailed_count.len)
|
||||
var/stats = "<b>Blob Stats:</b><br>"
|
||||
var/count
|
||||
for (var/thing in detailed_count)
|
||||
count = detailed_count[thing]
|
||||
stats += "[thing] processed [count] times. Total blobs: [blobs.len]<br>"
|
||||
boutput(usr, "<br>[stats]")
|
||||
@@ -0,0 +1,9 @@
|
||||
datum/controller/process/camnets
|
||||
|
||||
setup()
|
||||
name = "Camera Networks"
|
||||
schedule_interval = 30
|
||||
sleep_interval = 0.5
|
||||
|
||||
doWork()
|
||||
rebuild_camera_network() //Will only actually do something if it needs to.
|
||||
@@ -0,0 +1,12 @@
|
||||
datum/controller/process/chemistry
|
||||
var/tmp/datum/updateQueue/chemistryUpdateQueue
|
||||
|
||||
setup()
|
||||
name = "Chemistry"
|
||||
schedule_interval = 10
|
||||
chemistryUpdateQueue = new
|
||||
|
||||
doWork()
|
||||
for(var/datum/d in active_reagent_holders)
|
||||
d:process_reactions()
|
||||
scheck()
|
||||
@@ -0,0 +1,41 @@
|
||||
// handles critters
|
||||
datum/controller/process/critters
|
||||
var/tmp/list/detailed_count
|
||||
var/tmp/tick_counter
|
||||
var/tmp/list/critters
|
||||
|
||||
setup()
|
||||
name = "Critter"
|
||||
schedule_interval = 16 // 1.6 seconds
|
||||
|
||||
detailed_count = new
|
||||
src.critters = global.critters
|
||||
|
||||
doWork()
|
||||
var/i
|
||||
for(var/datum/c in global.critters)
|
||||
c:process()
|
||||
if (!(i++ % 10))
|
||||
scheck()
|
||||
|
||||
/*var/currentTick = ticks
|
||||
for(var/obj/critter in critters)
|
||||
tick_counter = world.timeofday
|
||||
|
||||
critter:process()
|
||||
|
||||
tick_counter = world.timeofday - tick_counter
|
||||
if (critter && tick_counter > 0)
|
||||
detailed_count["[critter.type]"] += tick_counter
|
||||
|
||||
scheck(currentTick)*/
|
||||
|
||||
tickDetail()
|
||||
if (detailed_count && detailed_count.len)
|
||||
var/stats = "<b>[name] ticks:</b>"
|
||||
var/count
|
||||
for (var/thing in detailed_count)
|
||||
count = detailed_count[thing]
|
||||
if (count > 4)
|
||||
stats += "[thing] used [count] ticks.<br>"
|
||||
boutput(usr, "<br>[stats]")
|
||||
@@ -0,0 +1,101 @@
|
||||
datum/controller/process/delete_queue
|
||||
var/tmp/delcount = 0
|
||||
var/tmp/gccount = 0
|
||||
var/tmp/deleteChunkSize = MIN_DELETE_CHUNK_SIZE
|
||||
//var/tmp/delpause = 1
|
||||
|
||||
// Timing vars
|
||||
var/tmp/start = 0
|
||||
var/tmp/list/timeTaken = new
|
||||
|
||||
setup()
|
||||
name = "DeleteQueue"
|
||||
schedule_interval = 1
|
||||
sleep_interval = 1
|
||||
|
||||
doWork()
|
||||
if(!global.delete_queue)
|
||||
boutput(world, "Error: there is no delete queue!")
|
||||
return 0
|
||||
|
||||
//var/datum/dynamicQueue/queue =
|
||||
if(global.delete_queue.isEmpty())
|
||||
return
|
||||
|
||||
start = world.timeofday
|
||||
|
||||
var/list/toDeleteRefs = delete_queue.dequeueMany(deleteChunkSize)
|
||||
var/numItems = toDeleteRefs.len
|
||||
#ifdef DELETE_QUEUE_DEBUG
|
||||
var/t
|
||||
#endif
|
||||
for(var/r in toDeleteRefs)
|
||||
var/datum/D = locate(r)
|
||||
|
||||
if (!istype(D) || !D.qdeled)
|
||||
// If we can't locate it, it got garbage collected.
|
||||
// If it isn't disposed, it got garbage collected and then a new thing used its ref.
|
||||
gccount++
|
||||
continue
|
||||
|
||||
#ifdef DELETE_QUEUE_DEBUG
|
||||
t = D.type
|
||||
// If we have been forced to delete the object, we do the following:
|
||||
detailed_delete_count[t]++
|
||||
detailed_delete_gc_count[t]--
|
||||
// Because we have already logged it into the gc count in qdel.
|
||||
#endif
|
||||
|
||||
// Delete that bitch
|
||||
delcount++
|
||||
D.qdeled = 0
|
||||
del(D)
|
||||
|
||||
scheck(0)
|
||||
|
||||
//if (delpause)
|
||||
//sleep(delpause)
|
||||
|
||||
// The amount of time taken for this run is recorded only if
|
||||
// the number of items considered is equal to the chunk size
|
||||
if(numItems == deleteChunkSize)
|
||||
timeTaken.len++
|
||||
timeTaken[timeTaken.len] = world.timeofday - start
|
||||
|
||||
// If the number of items processed is equal to the chunk size
|
||||
// and the average time taken by the delete queue is greater than the scheduled interval
|
||||
if (numItems == deleteChunkSize && averageTimeTaken() > schedule_interval && deleteChunkSize > MIN_DELETE_CHUNK_SIZE)
|
||||
deleteChunkSize--
|
||||
else if (numItems == deleteChunkSize && averageTimeTaken() < schedule_interval)
|
||||
deleteChunkSize++
|
||||
|
||||
proc
|
||||
averageTimeTaken()
|
||||
var/t = 0
|
||||
var/c = 0
|
||||
for(var/time in timeTaken)
|
||||
t += time
|
||||
c++
|
||||
|
||||
if (timeTaken.len > 10)
|
||||
timeTaken.Cut(1, 2)
|
||||
|
||||
if(c > 0)
|
||||
return t / c
|
||||
return c
|
||||
|
||||
tickDetail()
|
||||
#ifdef DELETE_QUEUE_DEBUG
|
||||
if (detailed_delete_count && detailed_delete_count.len)
|
||||
var/stats = "<b>Delete Stats:</b><br>"
|
||||
var/count
|
||||
for (var/thing in detailed_delete_count)
|
||||
count = detailed_delete_count[thing]
|
||||
stats += "[thing] deleted [count] times.<br>"
|
||||
for (var/thing in detailed_delete_gc_count)
|
||||
count = detailed_delete_gc_count[thing]
|
||||
stats += "[thing] gracefully deleted [count] times.<br>"
|
||||
boutput(usr, "<br>[stats]")
|
||||
#endif
|
||||
boutput(usr, "<b>Current Queue Length:</b> [delete_queue.count()]")
|
||||
boutput(usr, "<b>Total Items Deleted:</b> [delcount] (Explictly) [gccount] (Gracefully GC'd)")
|
||||
@@ -0,0 +1,44 @@
|
||||
// handles items
|
||||
datum/controller/process/items
|
||||
var/tmp/list/detailed_count
|
||||
var/tmp/tick_counter
|
||||
var/tmp/list/processing_items
|
||||
|
||||
setup()
|
||||
name = "Item"
|
||||
schedule_interval = 29
|
||||
|
||||
for(var/obj/object in world)
|
||||
object.initialize()
|
||||
|
||||
detailed_count = new
|
||||
|
||||
src.processing_items = global.processing_items
|
||||
|
||||
doWork()
|
||||
var/c
|
||||
for(var/datum/i in global.processing_items)
|
||||
i:process()
|
||||
if (!(c++ % 20))
|
||||
scheck()
|
||||
|
||||
/*for(var/obj/item/item in processing_items)
|
||||
tick_counter = world.timeofday
|
||||
|
||||
item.process()
|
||||
|
||||
tick_counter = world.timeofday - tick_counter
|
||||
if (item && tick_counter > 0)
|
||||
detailed_count["[item.type]"] += tick_counter
|
||||
|
||||
scheck(currentTick)
|
||||
*/
|
||||
tickDetail()
|
||||
if (detailed_count && detailed_count.len)
|
||||
var/stats = "<b>[name] ticks:</b><br>"
|
||||
var/count
|
||||
for (var/thing in detailed_count)
|
||||
count = detailed_count[thing]
|
||||
if (count > 4)
|
||||
stats += "[thing] used [count] ticks.<br>"
|
||||
boutput(usr, "<br>[stats]")
|
||||
@@ -0,0 +1,7 @@
|
||||
datum/controller/process/lighting
|
||||
setup()
|
||||
name = "Lighting"
|
||||
schedule_interval = 22
|
||||
|
||||
doWork()
|
||||
// TODO
|
||||
@@ -0,0 +1,81 @@
|
||||
// handles machines
|
||||
datum/controller/process/machines
|
||||
var/tmp/list/machines
|
||||
var/tmp/list/pipe_networks
|
||||
var/tmp/list/powernets
|
||||
var/tmp/list/atmos_machines
|
||||
|
||||
setup()
|
||||
name = "Machine"
|
||||
schedule_interval = 33
|
||||
|
||||
Station_VNet = new /datum/v_space/v_space_network()
|
||||
|
||||
doWork()
|
||||
src.atmos_machines = global.atmos_machines
|
||||
var/c = 0
|
||||
for(var/obj/machinery/atmospherics/machine in atmos_machines)
|
||||
#ifdef MACHINE_PROCESSING_DEBUG
|
||||
var/t = world.time
|
||||
#endif
|
||||
machine.process()
|
||||
#ifdef MACHINE_PROCESSING_DEBUG
|
||||
register_machine_time(machine, world.time - t)
|
||||
#endif
|
||||
|
||||
if (!(c++ % 100))
|
||||
scheck()
|
||||
|
||||
src.pipe_networks = global.pipe_networks
|
||||
for(var/datum/pipe_network/network in src.pipe_networks)
|
||||
#ifdef MACHINE_PROCESSING_DEBUG
|
||||
var/t = world.time
|
||||
#endif
|
||||
network.process()
|
||||
#ifdef MACHINE_PROCESSING_DEBUG
|
||||
register_machine_time(network, world.time - t)
|
||||
#endif
|
||||
if (!(c++ % 100))
|
||||
scheck()
|
||||
|
||||
src.powernets = global.powernets
|
||||
for(var/datum/powernet/PN in src.powernets)
|
||||
#ifdef MACHINE_PROCESSING_DEBUG
|
||||
var/t = world.time
|
||||
#endif
|
||||
PN.reset()
|
||||
#ifdef MACHINE_PROCESSING_DEBUG
|
||||
register_machine_time(PN, world.time - t)
|
||||
#endif
|
||||
if (!(c++ % 100))
|
||||
scheck()
|
||||
|
||||
src.machines = global.machines
|
||||
for(var/obj/machinery/machine in src.machines)
|
||||
#ifdef MACHINE_PROCESSING_DEBUG
|
||||
var/t = world.time
|
||||
#endif
|
||||
machine.process()
|
||||
#ifdef MACHINE_PROCESSING_DEBUG
|
||||
register_machine_time(machine, world.time - t)
|
||||
#endif
|
||||
if (!(c++ % 100))
|
||||
scheck()
|
||||
|
||||
|
||||
#ifdef MACHINE_PROCESSING_DEBUG
|
||||
proc/register_machine_time(var/datum/machine, var/time)
|
||||
if(!machine) return
|
||||
var/list/mtl = detailed_machine_timings[machine.type]
|
||||
if(!mtl)
|
||||
mtl = list()
|
||||
mtl.len = 2
|
||||
mtl[1] = 0 //The amount of time spent processing this machine in total
|
||||
mtl[2] = 0 //The amount of times this machine has been processed
|
||||
detailed_machine_timings[machine.type] = mtl
|
||||
|
||||
mtl[1] += time
|
||||
mtl[2]++
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
// handles critters
|
||||
datum/controller/process/mob_ai
|
||||
setup()
|
||||
name = "Mob AI"
|
||||
schedule_interval = 16 // 1.6 seconds
|
||||
|
||||
doWork()
|
||||
for(var/mob/living/carbon/human/H in mobs)
|
||||
H.ai_process()
|
||||
scheck()
|
||||
|
||||
/*var/currentTick = ticks
|
||||
for(var/obj/critter in critters)
|
||||
tick_counter = world.timeofday
|
||||
|
||||
critter:process()
|
||||
|
||||
tick_counter = world.timeofday - tick_counter
|
||||
if (critter && tick_counter > 0)
|
||||
detailed_count["[critter.type]"] += tick_counter
|
||||
|
||||
scheck(currentTick)*/
|
||||
@@ -0,0 +1,66 @@
|
||||
// handles mobs
|
||||
datum/controller/process/mobs
|
||||
var/tmp/list/detailed_count
|
||||
var/tmp/tick_counter
|
||||
var/list/mobs
|
||||
|
||||
var/list/living = list()
|
||||
var/list/wraiths = list()
|
||||
var/list/adminghosts = list()
|
||||
|
||||
setup()
|
||||
name = "Mob"
|
||||
schedule_interval = 20
|
||||
detailed_count = new
|
||||
src.mobs = global.mobs
|
||||
|
||||
copyStateFrom(var/datum/controller/process/mobs/other)
|
||||
detailed_count = other.detailed_count
|
||||
|
||||
doWork()
|
||||
var/currentTick = ticks
|
||||
|
||||
src.mobs = global.mobs
|
||||
var/c
|
||||
|
||||
for(var/mob/living/M in src.mobs)
|
||||
M.Life(src)
|
||||
if (!(c++ % 5))
|
||||
scheck(currentTick)
|
||||
|
||||
for(var/mob/wraith/W in src.mobs)
|
||||
W.Life(src)
|
||||
scheck(currentTick)
|
||||
|
||||
// For periodic antag overlay updates (Convair880).
|
||||
for (var/mob/dead/G in src.mobs)
|
||||
if (isadminghost(G))
|
||||
G:Life(src)
|
||||
scheck(currentTick)
|
||||
|
||||
/*
|
||||
for(var/mob/living/M in src.mobs)
|
||||
tick_counter = world.timeofday
|
||||
|
||||
M.Life(src)
|
||||
|
||||
tick_counter = world.timeofday - tick_counter
|
||||
if (M && tick_counter > 0)
|
||||
detailed_count["[M.type]-[M.name]"] += tick_counter
|
||||
|
||||
scheck(currentTick)
|
||||
|
||||
// a r g h
|
||||
for (var/mob/wraith/W in src.mobs)
|
||||
W.Life(src)
|
||||
scheck(currentTick)
|
||||
*/
|
||||
tickDetail()
|
||||
if (detailed_count && detailed_count.len)
|
||||
var/stats = "<b>[name] ticks:</b><br>"
|
||||
var/count
|
||||
for (var/thing in detailed_count)
|
||||
count = detailed_count[thing]
|
||||
if (count > 4)
|
||||
stats += "[thing] used [count] ticks.<br>"
|
||||
boutput(usr, "<br>[stats]")
|
||||
@@ -0,0 +1,17 @@
|
||||
datum/controller/process/networks
|
||||
var/tmp/datum/updateQueue/networkUpdateQueue
|
||||
|
||||
setup()
|
||||
name = "Networks"
|
||||
schedule_interval = 11
|
||||
networkUpdateQueue = new
|
||||
|
||||
doWork()
|
||||
for(var/datum/n in node_networks)
|
||||
n:update()
|
||||
scheck()
|
||||
/*
|
||||
var/currentTick = ticks
|
||||
for (var/datum/node_network/network in node_networks)
|
||||
network.update()
|
||||
scheck(currentTick)*/
|
||||
@@ -0,0 +1,18 @@
|
||||
datum/controller/process/particles
|
||||
var/datum/particleMaster/master
|
||||
|
||||
setup()
|
||||
name = "Particles"
|
||||
schedule_interval = 12
|
||||
|
||||
// putting this in a var so main loop varedit can get into the particleMaster
|
||||
master = particleMaster
|
||||
|
||||
doWork()
|
||||
// TODO roll the "loop" code from particleMaster back into this system
|
||||
master.Tick()
|
||||
|
||||
// regular timing doesn't really apply since particles abuse the shit out of spawn and sleep
|
||||
tickDetail()
|
||||
return "particle types: [master.particleTypes.len], particle systems: [master.particleSystems.len]<br>"
|
||||
|
||||
@@ -0,0 +1,317 @@
|
||||
// Process
|
||||
|
||||
/datum/controller/process
|
||||
/**
|
||||
* State vars
|
||||
*/
|
||||
// Main controller ref
|
||||
var/tmp/datum/controller/processScheduler/main
|
||||
|
||||
// 1 if process is not running or queued
|
||||
var/tmp/idle = 1
|
||||
|
||||
// 1 if process is queued
|
||||
var/tmp/queued = 0
|
||||
|
||||
// 1 if process is running
|
||||
var/tmp/running = 0
|
||||
|
||||
// 1 if process is blocked up
|
||||
var/tmp/hung = 0
|
||||
|
||||
// 1 if process was killed
|
||||
var/tmp/killed = 0
|
||||
|
||||
// Status text var
|
||||
var/tmp/status
|
||||
|
||||
// Previous status text var
|
||||
var/tmp/previousStatus
|
||||
|
||||
// 1 if process is disabled
|
||||
var/tmp/disabled = 0
|
||||
|
||||
/**
|
||||
* Config vars
|
||||
*/
|
||||
// Process name
|
||||
var/name
|
||||
|
||||
// Process schedule interval
|
||||
// This controls how often the process would run under ideal conditions.
|
||||
// If the process scheduler sees that the process has finished, it will wait until
|
||||
// this amount of time has elapsed from the start of the previous run to start the
|
||||
// process running again.
|
||||
var/tmp/schedule_interval = PROCESS_DEFAULT_SCHEDULE_INTERVAL // run every 50 ticks
|
||||
|
||||
// Process sleep interval
|
||||
// This controls how often the process will yield (call sleep(0)) while it is running.
|
||||
// Every concurrent process should sleep periodically while running in order to allow other
|
||||
// processes to execute concurrently.
|
||||
var/tmp/sleep_interval
|
||||
|
||||
// hang_warning_time - this is the time (in 1/10 seconds) after which the server will begin to show "maybe hung" in the context window
|
||||
var/tmp/hang_warning_time = PROCESS_DEFAULT_HANG_WARNING_TIME
|
||||
|
||||
// hang_alert_time - After this much time(in 1/10 seconds), the server will send an admin debug message saying the process may be hung
|
||||
var/tmp/hang_alert_time = PROCESS_DEFAULT_HANG_ALERT_TIME
|
||||
|
||||
// hang_restart_time - After this much time(in 1/10 seconds), the server will automatically kill and restart the process.
|
||||
var/tmp/hang_restart_time = PROCESS_DEFAULT_HANG_RESTART_TIME
|
||||
|
||||
// cpu_threshold - if world.cpu >= cpu_threshold, scheck() will call sleep(1) to defer further work until the next tick. This keeps a process from driving a tick into overtime (causing perceptible lag)
|
||||
var/tmp/cpu_threshold = PROCESS_DEFAULT_CPU_THRESHOLD
|
||||
|
||||
// How many times in the current run has the process deferred work till the next tick?
|
||||
var/tmp/cpu_defer_count = 0
|
||||
|
||||
/**
|
||||
* recordkeeping vars
|
||||
*/
|
||||
|
||||
// Records the time (1/10s timeofday) at which the process last finished sleeping
|
||||
var/tmp/last_slept = 0
|
||||
|
||||
// Records the time (1/10s timeofday) at which the process last began running
|
||||
var/tmp/run_start = 0
|
||||
|
||||
// Records the number of times this process has been killed and restarted
|
||||
var/tmp/times_killed
|
||||
|
||||
// Tick count
|
||||
var/tmp/ticks = 0
|
||||
|
||||
var/tmp/last_task = ""
|
||||
|
||||
var/tmp/last_object
|
||||
|
||||
datum/controller/process/New(var/datum/controller/processScheduler/scheduler)
|
||||
..()
|
||||
main = scheduler
|
||||
previousStatus = "idle"
|
||||
idle()
|
||||
name = "process"
|
||||
schedule_interval = 50
|
||||
sleep_interval = world.tick_lag / PROCESS_DEFAULT_SLEEP_INTERVAL
|
||||
last_slept = 0
|
||||
run_start = 0
|
||||
ticks = 0
|
||||
last_task = 0
|
||||
last_object = null
|
||||
|
||||
datum/controller/process/proc/started()
|
||||
// Initialize last_slept so we can know when to sleep
|
||||
last_slept = TimeOfHour
|
||||
|
||||
// Initialize run_start so we can detect hung processes.
|
||||
run_start = TimeOfHour
|
||||
|
||||
// Initialize defer count
|
||||
cpu_defer_count = 0
|
||||
|
||||
running()
|
||||
main.processStarted(src)
|
||||
|
||||
onStart()
|
||||
|
||||
datum/controller/process/proc/finished()
|
||||
ticks++
|
||||
idle()
|
||||
main.processFinished(src)
|
||||
|
||||
onFinish()
|
||||
|
||||
datum/controller/process/proc/doWork()
|
||||
|
||||
datum/controller/process/proc/setup()
|
||||
|
||||
datum/controller/process/proc/process()
|
||||
started()
|
||||
doWork()
|
||||
finished()
|
||||
|
||||
datum/controller/process/proc/running()
|
||||
idle = 0
|
||||
queued = 0
|
||||
running = 1
|
||||
hung = 0
|
||||
setStatus(PROCESS_STATUS_RUNNING)
|
||||
|
||||
datum/controller/process/proc/idle()
|
||||
queued = 0
|
||||
running = 0
|
||||
idle = 1
|
||||
hung = 0
|
||||
setStatus(PROCESS_STATUS_IDLE)
|
||||
|
||||
datum/controller/process/proc/queued()
|
||||
idle = 0
|
||||
running = 0
|
||||
queued = 1
|
||||
hung = 0
|
||||
setStatus(PROCESS_STATUS_QUEUED)
|
||||
|
||||
datum/controller/process/proc/hung()
|
||||
hung = 1
|
||||
setStatus(PROCESS_STATUS_HUNG)
|
||||
|
||||
datum/controller/process/proc/handleHung()
|
||||
var/datum/lastObj = last_object
|
||||
var/lastObjType = "null"
|
||||
if(istype(lastObj))
|
||||
lastObjType = lastObj.type
|
||||
|
||||
// If world.timeofday has rolled over, then we need to adjust.
|
||||
if (TimeOfHour < run_start)
|
||||
run_start -= 36000
|
||||
var/msg = "[name] process hung at tick #[ticks]. Process was unresponsive for [(TimeOfHour - run_start) / 10] seconds and was restarted. Last task: [last_task]. Last Object Type: [lastObjType]"
|
||||
logTheThing("debug", null, null, msg)
|
||||
logTheThing("diary", null, null, msg, "debug")
|
||||
message_admins(msg)
|
||||
|
||||
main.restartProcess(src.name)
|
||||
|
||||
datum/controller/process/proc/kill()
|
||||
if (!killed)
|
||||
var/msg = "[name] process was killed at tick #[ticks]."
|
||||
logTheThing("debug", null, null, msg)
|
||||
logTheThing("diary", null, null, msg, "debug")
|
||||
//finished()
|
||||
|
||||
// Allow inheritors to clean up if needed
|
||||
onKill()
|
||||
|
||||
// This should del
|
||||
del(src)
|
||||
|
||||
datum/controller/process/proc/scheck(var/tickId = 0)
|
||||
if (killed)
|
||||
// The kill proc is the only place where killed is set.
|
||||
// The kill proc should have deleted this datum, and all sleeping procs that are
|
||||
// owned by it.
|
||||
CRASH("A killed process is still running somehow...")
|
||||
if (hung)
|
||||
// This will only really help if the doWork proc ends up in an infinite loop.
|
||||
handleHung()
|
||||
CRASH("Process [name] hung and was restarted.")
|
||||
|
||||
// For each tick the process defers, it increments the cpu_defer_count so we don't
|
||||
// defer indefinitely
|
||||
if (main.getCurrentTickElapsedTime() > main.timeAllowance)
|
||||
sleep(world.tick_lag*1)
|
||||
cpu_defer_count++
|
||||
last_slept = TimeOfHour
|
||||
else
|
||||
var/t = TimeOfHour
|
||||
// If world.timeofday has rolled over, then we need to adjust.
|
||||
if (t < last_slept)
|
||||
last_slept -= 36000
|
||||
|
||||
if (t > last_slept + sleep_interval)
|
||||
// If we haven't slept in sleep_interval deciseconds, sleep to allow other work to proceed.
|
||||
sleep(0)
|
||||
last_slept = TimeOfHour
|
||||
|
||||
datum/controller/process/proc/update()
|
||||
// Clear delta
|
||||
if(previousStatus != status)
|
||||
setStatus(status)
|
||||
|
||||
var/elapsedTime = getElapsedTime()
|
||||
|
||||
if (hung)
|
||||
handleHung()
|
||||
return
|
||||
else if (elapsedTime > hang_restart_time)
|
||||
hung()
|
||||
else if (elapsedTime > hang_alert_time)
|
||||
setStatus(PROCESS_STATUS_PROBABLY_HUNG)
|
||||
else if (elapsedTime > hang_warning_time)
|
||||
setStatus(PROCESS_STATUS_MAYBE_HUNG)
|
||||
|
||||
|
||||
datum/controller/process/proc/getElapsedTime()
|
||||
if (TimeOfHour < run_start)
|
||||
return TimeOfHour - (run_start - 36000)
|
||||
return TimeOfHour - run_start
|
||||
|
||||
datum/controller/process/proc/tickDetail()
|
||||
return
|
||||
|
||||
datum/controller/process/proc/getContext()
|
||||
return "<tr><td>[name]</td><td>[main.averageRunTime(src)]</td><td>[main.last_run_time[src]]</td><td>[main.highest_run_time[src]]</td><td>[ticks]</td></tr>\n"
|
||||
|
||||
datum/controller/process/proc/getContextData()
|
||||
return list(
|
||||
"name" = name,
|
||||
"averageRunTime" = main.averageRunTime(src),
|
||||
"lastRunTime" = main.last_run_time[src],
|
||||
"highestRunTime" = main.highest_run_time[src],
|
||||
"ticks" = ticks,
|
||||
"schedule" = schedule_interval,
|
||||
"status" = getStatusText(),
|
||||
"disabled" = disabled
|
||||
)
|
||||
|
||||
datum/controller/process/proc/getStatus()
|
||||
return status
|
||||
|
||||
datum/controller/process/proc/getStatusText(var/s = 0)
|
||||
if(!s)
|
||||
s = status
|
||||
switch(s)
|
||||
if(PROCESS_STATUS_IDLE)
|
||||
return "idle"
|
||||
if(PROCESS_STATUS_QUEUED)
|
||||
return "queued"
|
||||
if(PROCESS_STATUS_RUNNING)
|
||||
return "running"
|
||||
if(PROCESS_STATUS_MAYBE_HUNG)
|
||||
return "maybe hung"
|
||||
if(PROCESS_STATUS_PROBABLY_HUNG)
|
||||
return "probably hung"
|
||||
if(PROCESS_STATUS_HUNG)
|
||||
return "HUNG"
|
||||
else
|
||||
return "UNKNOWN"
|
||||
|
||||
datum/controller/process/proc/getPreviousStatus()
|
||||
return previousStatus
|
||||
|
||||
datum/controller/process/proc/getPreviousStatusText()
|
||||
return getStatusText(previousStatus)
|
||||
|
||||
datum/controller/process/proc/setStatus(var/newStatus)
|
||||
previousStatus = status
|
||||
status = newStatus
|
||||
|
||||
datum/controller/process/proc/setLastTask(var/task, var/object)
|
||||
last_task = task
|
||||
last_object = object
|
||||
|
||||
datum/controller/process/proc/_copyStateFrom(var/datum/controller/process/target)
|
||||
main = target.main
|
||||
name = target.name
|
||||
schedule_interval = target.schedule_interval
|
||||
sleep_interval = target.sleep_interval
|
||||
last_slept = 0
|
||||
run_start = 0
|
||||
times_killed = target.times_killed
|
||||
ticks = target.ticks
|
||||
last_task = target.last_task
|
||||
last_object = target.last_object
|
||||
copyStateFrom(target)
|
||||
|
||||
datum/controller/process/proc/copyStateFrom(var/datum/controller/process/target)
|
||||
|
||||
datum/controller/process/proc/onKill()
|
||||
|
||||
datum/controller/process/proc/onStart()
|
||||
|
||||
datum/controller/process/proc/onFinish()
|
||||
|
||||
datum/controller/process/proc/disable()
|
||||
disabled = 1
|
||||
|
||||
datum/controller/process/proc/enable()
|
||||
disabled = 0
|
||||
@@ -0,0 +1,14 @@
|
||||
datum/controller/process/railway
|
||||
var/tmp/list/vehicles
|
||||
|
||||
setup()
|
||||
name = "Railways"
|
||||
schedule_interval = 5
|
||||
vehicles = global.railway_vehicles
|
||||
|
||||
doWork()
|
||||
var/c
|
||||
for(var/obj/railway_vehicle/v in global.railway_vehicles)
|
||||
v.process()
|
||||
if (!(c++ % 10))
|
||||
scheck()
|
||||
@@ -0,0 +1,19 @@
|
||||
// handles only materials research right now.
|
||||
datum/controller/process/research
|
||||
var/datum/materialResearchHolder/researchMaster
|
||||
|
||||
setup()
|
||||
name = "Research"
|
||||
schedule_interval = 10
|
||||
researchMaster = materialsResearch
|
||||
|
||||
doWork()
|
||||
researchMaster = materialsResearch
|
||||
if(researchMaster)
|
||||
for(var/x in researchMaster.research)
|
||||
var/datum/materialResearch/R = researchMaster.research[x]
|
||||
if(!R.completed)
|
||||
R.process()
|
||||
if(R.completed)
|
||||
researchMaster.completed.Add(R.id)
|
||||
researchMaster.completed[R.id] = R
|
||||
@@ -0,0 +1,9 @@
|
||||
/datum/controller/process/stock_market
|
||||
setup()
|
||||
name = "Stock Market"
|
||||
schedule_interval = 15
|
||||
|
||||
doWork()
|
||||
if (stockExchange)
|
||||
stockExchange.process()
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// handles telescope signals and whatnot
|
||||
datum/controller/process/telescope
|
||||
var/datum/telescope_manager/manager
|
||||
|
||||
setup()
|
||||
name = "Telescope"
|
||||
schedule_interval = 100
|
||||
|
||||
doWork()
|
||||
if(tele_man)
|
||||
if(!manager) manager = tele_man
|
||||
tele_man.tick()
|
||||
@@ -0,0 +1,14 @@
|
||||
// handles the game ticker
|
||||
datum/controller/process/ticker
|
||||
setup()
|
||||
name = "Game"
|
||||
schedule_interval = 5
|
||||
|
||||
if(!ticker)
|
||||
ticker = new /datum/controller/gameticker()
|
||||
|
||||
// start the pregame process
|
||||
spawn(1)
|
||||
ticker.pregame()
|
||||
doWork()
|
||||
ticker.process()
|
||||
@@ -0,0 +1,29 @@
|
||||
// handles various global init and the position of the sun.
|
||||
datum/controller/process/world
|
||||
var/shuttle
|
||||
|
||||
setup()
|
||||
name = "World"
|
||||
schedule_interval = 23
|
||||
|
||||
setupgenetics()
|
||||
if(genResearch) genResearch.setup()
|
||||
|
||||
setup_radiocodes()
|
||||
|
||||
emergency_shuttle = new /datum/shuttle_controller/emergency_shuttle()
|
||||
src.shuttle = emergency_shuttle
|
||||
|
||||
generate_access_name_lookup()
|
||||
|
||||
doWork()
|
||||
sun.calc_position()
|
||||
|
||||
if(genResearch) genResearch.progress()
|
||||
|
||||
for (var/byondkey in muted_keys)
|
||||
var/value = muted_keys[byondkey]
|
||||
if (value > 1)
|
||||
muted_keys[byondkey] = value - 1
|
||||
else if (value == 1 || value == 0)
|
||||
muted_keys -= byondkey
|
||||
@@ -0,0 +1,354 @@
|
||||
// Singleton instance of game_controller_new, setup in world.New()
|
||||
var/global/datum/controller/processScheduler/processScheduler
|
||||
|
||||
/datum/controller/processScheduler
|
||||
// Processes known by the scheduler
|
||||
var/tmp/datum/controller/process/list/processes = new
|
||||
|
||||
// Processes that are currently running
|
||||
var/tmp/datum/controller/process/list/running = new
|
||||
|
||||
// Processes that are idle
|
||||
var/tmp/datum/controller/process/list/idle = new
|
||||
|
||||
// Processes that are queued to run
|
||||
var/tmp/datum/controller/process/list/queued = new
|
||||
|
||||
// Process name -> process object map
|
||||
var/tmp/datum/controller/process/list/nameToProcessMap = new
|
||||
|
||||
// Process last start times
|
||||
var/tmp/datum/controller/process/list/last_start = new
|
||||
|
||||
// Process last run durations
|
||||
var/tmp/datum/controller/process/list/last_run_time = new
|
||||
|
||||
// Per process list of the last 20 durations
|
||||
var/tmp/datum/controller/process/list/last_twenty_run_times = new
|
||||
|
||||
// Process highest run time
|
||||
var/tmp/datum/controller/process/list/highest_run_time = new
|
||||
|
||||
// Sleep 1 tick -- This may be too aggressive.
|
||||
var/tmp/scheduler_sleep_interval = 1
|
||||
|
||||
// Controls whether the scheduler is running or not
|
||||
var/tmp/isRunning = 0
|
||||
|
||||
// Setup for these processes will be deferred until all the other processes are set up.
|
||||
var/tmp/list/deferredSetupList = new
|
||||
|
||||
var/tmp/currentTick = 0
|
||||
|
||||
var/tmp/currentTickStart = 0
|
||||
|
||||
var/tmp/timeAllowance = 0
|
||||
|
||||
var/tmp/cpuAverage = 0
|
||||
|
||||
var/tmp/timeAllowanceMax = 0
|
||||
|
||||
/datum/controller/processScheduler/New()
|
||||
..()
|
||||
scheduler_sleep_interval = world.tick_lag
|
||||
timeAllowance = world.tick_lag * 0.5
|
||||
timeAllowanceMax = world.tick_lag
|
||||
|
||||
/**
|
||||
* deferSetupFor
|
||||
* @param path processPath
|
||||
* If a process needs to be initialized after everything else, add it to
|
||||
* the deferred setup list. On goonstation, only the ticker needs to have
|
||||
* this treatment.
|
||||
*/
|
||||
/datum/controller/processScheduler/proc/deferSetupFor(var/processPath)
|
||||
if (!(processPath in deferredSetupList))
|
||||
deferredSetupList += processPath
|
||||
|
||||
/datum/controller/processScheduler/proc/setup()
|
||||
// There can be only one
|
||||
if(processScheduler && (processScheduler != src))
|
||||
del(src)
|
||||
return 0
|
||||
|
||||
var/process
|
||||
// Add all the processes we can find, except for the ticker
|
||||
for (process in typesof(/datum/controller/process) - /datum/controller/process)
|
||||
if (!(process in deferredSetupList))
|
||||
addProcess(new process(src))
|
||||
|
||||
for (process in deferredSetupList)
|
||||
addProcess(new process(src))
|
||||
|
||||
/datum/controller/processScheduler/proc/start()
|
||||
isRunning = 1
|
||||
spawn(0)
|
||||
process()
|
||||
|
||||
/datum/controller/processScheduler/proc/process()
|
||||
updateCurrentTickData()
|
||||
|
||||
for(var/i=world.tick_lag,i<world.tick_lag*50,i+=world.tick_lag)
|
||||
spawn(i) updateCurrentTickData()
|
||||
while(isRunning)
|
||||
// Hopefully spawning this for 50 ticks in the future will make it the first thing in the queue.
|
||||
spawn(world.tick_lag*50) updateCurrentTickData()
|
||||
checkRunningProcesses()
|
||||
queueProcesses()
|
||||
runQueuedProcesses()
|
||||
sleep(scheduler_sleep_interval)
|
||||
|
||||
/datum/controller/processScheduler/proc/stop()
|
||||
isRunning = 0
|
||||
|
||||
/datum/controller/processScheduler/proc/checkRunningProcesses()
|
||||
for(var/datum/controller/process/p in running)
|
||||
p.update()
|
||||
|
||||
if (isnull(p)) // Process was killed
|
||||
continue
|
||||
|
||||
var/status = p.getStatus()
|
||||
var/previousStatus = p.getPreviousStatus()
|
||||
|
||||
// Check status changes
|
||||
if(status != previousStatus)
|
||||
//Status changed.
|
||||
switch(status)
|
||||
if(PROCESS_STATUS_PROBABLY_HUNG)
|
||||
message_admins("Process '[p.name]' may be hung.")
|
||||
if(PROCESS_STATUS_HUNG)
|
||||
message_admins("Process '[p.name]' is hung and will be restarted.")
|
||||
|
||||
/datum/controller/processScheduler/proc/queueProcesses()
|
||||
for(var/datum/controller/process/p in processes)
|
||||
// Don't double-queue, don't queue running processes
|
||||
if (p.disabled || p.running || p.queued || !p.idle)
|
||||
continue
|
||||
|
||||
// If world.timeofday has rolled over, then we need to adjust.
|
||||
if (TimeOfHour < last_start[p])
|
||||
last_start[p] -= 36000
|
||||
|
||||
// If the process should be running by now, go ahead and queue it
|
||||
if (TimeOfHour > last_start[p] + p.schedule_interval)
|
||||
setQueuedProcessState(p)
|
||||
|
||||
/datum/controller/processScheduler/proc/runQueuedProcesses()
|
||||
for(var/datum/controller/process/p in queued)
|
||||
runProcess(p)
|
||||
|
||||
/datum/controller/processScheduler/proc/addProcess(var/datum/controller/process/process)
|
||||
processes.Add(process)
|
||||
process.idle()
|
||||
idle.Add(process)
|
||||
|
||||
// init recordkeeping vars
|
||||
last_start.Add(process)
|
||||
last_start[process] = 0
|
||||
last_run_time.Add(process)
|
||||
last_run_time[process] = 0
|
||||
last_twenty_run_times.Add(process)
|
||||
last_twenty_run_times[process] = list()
|
||||
highest_run_time.Add(process)
|
||||
highest_run_time[process] = 0
|
||||
|
||||
// init starts and stops record starts
|
||||
recordStart(process, 0)
|
||||
recordEnd(process, 0)
|
||||
|
||||
// Set up process
|
||||
process.setup()
|
||||
|
||||
// Save process in the name -> process map
|
||||
nameToProcessMap[process.name] = process
|
||||
|
||||
/datum/controller/processScheduler/proc/replaceProcess(var/datum/controller/process/oldProcess, var/datum/controller/process/newProcess)
|
||||
processes.Remove(oldProcess)
|
||||
processes.Add(newProcess)
|
||||
|
||||
newProcess.idle()
|
||||
idle.Remove(oldProcess)
|
||||
running.Remove(oldProcess)
|
||||
queued.Remove(oldProcess)
|
||||
idle.Add(newProcess)
|
||||
|
||||
last_start.Remove(oldProcess)
|
||||
last_start.Add(newProcess)
|
||||
last_start[newProcess] = 0
|
||||
|
||||
last_run_time.Add(newProcess)
|
||||
last_run_time[newProcess] = last_run_time[oldProcess]
|
||||
last_run_time.Remove(oldProcess)
|
||||
|
||||
last_twenty_run_times.Add(newProcess)
|
||||
last_twenty_run_times[newProcess] = last_twenty_run_times[oldProcess]
|
||||
last_twenty_run_times.Remove(oldProcess)
|
||||
|
||||
highest_run_time.Add(newProcess)
|
||||
highest_run_time[newProcess] = highest_run_time[oldProcess]
|
||||
highest_run_time.Remove(oldProcess)
|
||||
|
||||
recordStart(newProcess, 0)
|
||||
recordEnd(newProcess, 0)
|
||||
|
||||
nameToProcessMap[newProcess.name] = newProcess
|
||||
|
||||
|
||||
/datum/controller/processScheduler/proc/runProcess(var/datum/controller/process/process)
|
||||
spawn(0)
|
||||
process.process()
|
||||
|
||||
/datum/controller/processScheduler/proc/processStarted(var/datum/controller/process/process)
|
||||
setRunningProcessState(process)
|
||||
recordStart(process)
|
||||
|
||||
/datum/controller/processScheduler/proc/processFinished(var/datum/controller/process/process)
|
||||
setIdleProcessState(process)
|
||||
recordEnd(process)
|
||||
|
||||
/datum/controller/processScheduler/proc/setIdleProcessState(var/datum/controller/process/process)
|
||||
if (process in running)
|
||||
running -= process
|
||||
if (process in queued)
|
||||
queued -= process
|
||||
if (!(process in idle))
|
||||
idle += process
|
||||
|
||||
/datum/controller/processScheduler/proc/setQueuedProcessState(var/datum/controller/process/process)
|
||||
if (process in running)
|
||||
running -= process
|
||||
if (process in idle)
|
||||
idle -= process
|
||||
if (!(process in queued))
|
||||
queued += process
|
||||
|
||||
// The other state transitions are handled internally by the process.
|
||||
process.queued()
|
||||
|
||||
/datum/controller/processScheduler/proc/setRunningProcessState(var/datum/controller/process/process)
|
||||
if (process in queued)
|
||||
queued -= process
|
||||
if (process in idle)
|
||||
idle -= process
|
||||
if (!(process in running))
|
||||
running += process
|
||||
|
||||
/datum/controller/processScheduler/proc/recordStart(var/datum/controller/process/process, var/time = null)
|
||||
if (isnull(time))
|
||||
time = TimeOfHour
|
||||
|
||||
last_start[process] = time
|
||||
|
||||
/datum/controller/processScheduler/proc/recordEnd(var/datum/controller/process/process, var/time = null)
|
||||
if (isnull(time))
|
||||
time = TimeOfHour
|
||||
|
||||
// If world.timeofday has rolled over, then we need to adjust.
|
||||
if (time < last_start[process])
|
||||
last_start[process] -= 36000
|
||||
|
||||
var/lastRunTime = time - last_start[process]
|
||||
|
||||
if(lastRunTime < 0)
|
||||
lastRunTime = 0
|
||||
|
||||
recordRunTime(process, lastRunTime)
|
||||
|
||||
/**
|
||||
* recordRunTime
|
||||
* Records a run time for a process
|
||||
*/
|
||||
/datum/controller/processScheduler/proc/recordRunTime(var/datum/controller/process/process, time)
|
||||
last_run_time[process] = time
|
||||
if(time > highest_run_time[process])
|
||||
highest_run_time[process] = time
|
||||
|
||||
var/list/lastTwenty = last_twenty_run_times[process]
|
||||
if (lastTwenty.len == 20)
|
||||
lastTwenty.Cut(1, 2)
|
||||
lastTwenty.len++
|
||||
lastTwenty[lastTwenty.len] = time
|
||||
|
||||
/**
|
||||
* averageRunTime
|
||||
* returns the average run time (over the last 20) of the process
|
||||
*/
|
||||
/datum/controller/processScheduler/proc/averageRunTime(var/datum/controller/process/process)
|
||||
var/lastTwenty = last_twenty_run_times[process]
|
||||
|
||||
var/t = 0
|
||||
var/c = 0
|
||||
for(var/time in lastTwenty)
|
||||
t += time
|
||||
c++
|
||||
|
||||
if(c > 0)
|
||||
return t / c
|
||||
return c
|
||||
|
||||
/datum/controller/processScheduler/proc/getStatusData()
|
||||
var/list/data = new
|
||||
|
||||
for (var/datum/controller/process/p in processes)
|
||||
data.len++
|
||||
data[data.len] = p.getContextData()
|
||||
|
||||
return data
|
||||
|
||||
/datum/controller/processScheduler/proc/getProcessCount()
|
||||
return processes.len
|
||||
|
||||
/datum/controller/processScheduler/proc/hasProcess(var/processName as text)
|
||||
if (nameToProcessMap[processName])
|
||||
return 1
|
||||
|
||||
/datum/controller/processScheduler/proc/killProcess(var/processName as text)
|
||||
restartProcess(processName)
|
||||
|
||||
/datum/controller/processScheduler/proc/restartProcess(var/processName as text)
|
||||
if (hasProcess(processName))
|
||||
var/datum/controller/process/oldInstance = nameToProcessMap[processName]
|
||||
var/datum/controller/process/newInstance = new oldInstance.type(src)
|
||||
newInstance._copyStateFrom(oldInstance)
|
||||
replaceProcess(oldInstance, newInstance)
|
||||
oldInstance.kill()
|
||||
|
||||
/datum/controller/processScheduler/proc/enableProcess(var/processName as text)
|
||||
if (hasProcess(processName))
|
||||
var/datum/controller/process/process = nameToProcessMap[processName]
|
||||
process.enable()
|
||||
|
||||
/datum/controller/processScheduler/proc/disableProcess(var/processName as text)
|
||||
if (hasProcess(processName))
|
||||
var/datum/controller/process/process = nameToProcessMap[processName]
|
||||
process.disable()
|
||||
|
||||
/datum/controller/processScheduler/proc/getCurrentTickElapsedTime()
|
||||
if (world.time > currentTick)
|
||||
updateCurrentTickData()
|
||||
return 0
|
||||
else
|
||||
return TimeOfHour - currentTickStart
|
||||
|
||||
/datum/controller/processScheduler/proc/updateCurrentTickData()
|
||||
if (world.time > currentTick)
|
||||
// New tick!
|
||||
currentTick = world.time
|
||||
currentTickStart = TimeOfHour
|
||||
updateTimeAllowance()
|
||||
cpuAverage = (world.cpu + cpuAverage + cpuAverage) / 3
|
||||
|
||||
|
||||
/datum/controller/processScheduler/proc/updateTimeAllowance()
|
||||
// Time allowance goes down linearly with world.cpu.
|
||||
var/tmp/error = cpuAverage - 100
|
||||
var/tmp/timeAllowanceDelta = sign(error) * -0.5 * world.tick_lag * max(0, 0.01 * abs(error))
|
||||
|
||||
//timeAllowance = world.tick_lag * min(1, 0.5 * ((200/max(1,cpuAverage)) - 1))
|
||||
timeAllowance = min(timeAllowanceMax, max(0, timeAllowance + timeAllowanceDelta))
|
||||
|
||||
/datum/controller/processScheduler/proc/sign(var/x)
|
||||
if (x == 0)
|
||||
return 1
|
||||
return x / abs(x)
|
||||
Reference in New Issue
Block a user