|
- Changeling Evolution Menu - Hover over a power to see more information - Current ability choices remaining: [changeling.geneticpoints] - By rendering a lifeform to a husk, we gain enough power to alter and adapt our evolutions. - (Readapt) - - |
-
| - Search: - | -
|
-
-
- Evolve [P][ownsthis ? " - Purchased" : ((P.dna_cost > 1) ? " - Cost: [P.dna_cost]" : "")]
-
- - |
-
|
+ Changeling Evolution Menu + Hover over a power to see more information + Current ability choices remaining: [changeling.geneticpoints] + By rendering a lifeform to a husk, we gain enough power to alter and adapt our evolutions. + (Readapt) + + |
+
| + Search: + | +
|
+
+
+ Evolve [P][ownsthis ? " - Purchased" : ((P.dna_cost > 1) ? " - Cost: [P.dna_cost]" : "")]
+
+ + |
+
| [nicename] |

"
- else
- dat+="None"
- else
- dat+="No current wanted issue found.
"
- else
- dat+="None"
- else
- dat+="Apart from some uninteresting Classified ads, there's nothing on this page..."
- if(scribble_page==curr_page)
- dat+="
"
+ else
+ dat+="None"
+ else
+ dat+="No current wanted issue found.
"
+ else
+ dat+="None"
+ else
+ dat+="Apart from some uninteresting Classified ads, there's nothing on this page..."
+ if(scribble_page==curr_page)
+ dat+="| [capitalize(ore)] | [value] |
| [prize.equipment_name] | [prize.cost] | Purchase |
| [capitalize(ore)] | [value] |
| [prize.equipment_name] | [prize.cost] | Purchase |
| [capitalize(ore)] | [value] |
| [capitalize(ore)] | [value] |
"
- for(var/t in typesof(/area))
- master += text("[]\n", t)
- //Foreach goto(26)
- src << browse(master)
- return
-*/
-
-/mob/verb/memory()
- set name = "Notes"
- set category = "IC"
- if(mind)
- mind.show_memory(src)
- else
- src << "The game appears to have misplaced your mind datum, so we can't show you your notes."
-
-/mob/verb/add_memory(msg as message)
- set name = "Add Note"
- set category = "IC"
-
- msg = copytext(msg, 1, MAX_MESSAGE_LEN)
- msg = sanitize(msg)
-
- if(mind)
- mind.store_memory(msg)
- else
- src << "The game appears to have misplaced your mind datum, so we can't show you your notes."
-
-/mob/proc/store_memory(msg as message, popup, sane = 1)
- msg = copytext(msg, 1, MAX_MESSAGE_LEN)
-
- if (sane)
- msg = sanitize(msg)
-
- if (length(memory) == 0)
- memory += msg
- else
- memory += "
[msg]"
-
- if (popup)
- memory()
-
-/*
-/mob/verb/help()
- set name = "Help"
- src << browse('html/help.html', "window=help")
- return
-*/
-
-/mob/verb/abandon_mob()
- set name = "Respawn"
- set category = "OOC"
-
- if (!( abandon_allowed ))
- return
- if ((stat != 2 || !( ticker )))
- usr << "\blue You must be dead to use this!"
- return
-
- log_game("[usr.name]/[usr.key] used abandon mob.")
-
- usr << "\blue Please roleplay correctly!"
-
- if(!client)
- log_game("[usr.key] AM failed due to disconnect.")
- return
- client.screen.Cut()
- if(!client)
- log_game("[usr.key] AM failed due to disconnect.")
- return
-
- var/mob/new_player/M = new /mob/new_player()
- if(!client)
- log_game("[usr.key] AM failed due to disconnect.")
- qdel(M)
- return
-
- M.key = key
-// M.Login() //wat
- return
-
-/client/verb/changes()
- set name = "Changelog"
- set category = "OOC"
- getFiles(
- 'html/postcardsmall.jpg',
- 'html/somerights20.png',
- 'html/88x31.png',
- 'html/bug-minus.png',
- 'html/cross-circle.png',
- 'html/hard-hat-exclamation.png',
- 'html/image-minus.png',
- 'html/image-plus.png',
- 'html/music-minus.png',
- 'html/music-plus.png',
- 'html/tick-circle.png',
- 'html/wrench-screwdriver.png',
- 'html/spell-check.png',
- 'html/burn-exclamation.png',
- 'html/chevron.png',
- 'html/chevron-expand.png',
- 'html/changelog.css',
- 'html/changelog.js',
- 'html/changelog.html'
- )
- src << browse('html/changelog.html', "window=changes;size=675x650")
- if(prefs.lastchangelog != changelog_hash)
- prefs.lastchangelog = changelog_hash
- prefs.save_preferences()
- winset(src, "rpane.changelog", "background-color=none;font-style=;")
-
-/mob/verb/observe()
- set name = "Observe"
- set category = "OOC"
- var/is_admin = 0
-
- if(check_rights_for(client,R_ADMIN))
- is_admin = 1
- else if(stat != DEAD || istype(src, /mob/new_player))
- usr << "\blue You must be observing to use this!"
- return
-
- if(is_admin && stat == DEAD)
- is_admin = 0
-
- var/list/names = list()
- var/list/namecounts = list()
- var/list/creatures = list()
-
- for(var/obj/O in world) //EWWWWWWWWWWWWWWWWWWWWWWWW ~needs to be optimised
- if(!O.loc)
- continue
- if(istype(O, /obj/item/weapon/disk/nuclear))
- var/name = "Nuclear Disk"
- if (names.Find(name))
- namecounts[name]++
- name = "[name] ([namecounts[name]])"
- else
- names.Add(name)
- namecounts[name] = 1
- creatures[name] = O
-
- if(istype(O, /obj/machinery/singularity))
- var/name = "Singularity"
- if (names.Find(name))
- namecounts[name]++
- name = "[name] ([namecounts[name]])"
- else
- names.Add(name)
- namecounts[name] = 1
- creatures[name] = O
-
- if(istype(O, /obj/machinery/bot))
- var/name = "BOT: [O.name]"
- if (names.Find(name))
- namecounts[name]++
- name = "[name] ([namecounts[name]])"
- else
- names.Add(name)
- namecounts[name] = 1
- creatures[name] = O
-
-
- for(var/mob/M in sortAtom(mob_list))
- var/name = M.name
- if (names.Find(name))
- namecounts[name]++
- name = "[name] ([namecounts[name]])"
- else
- names.Add(name)
- namecounts[name] = 1
-
- creatures[name] = M
-
-
- client.perspective = EYE_PERSPECTIVE
-
- var/eye_name = null
-
- var/ok = "[is_admin ? "Admin Observe" : "Observe"]"
- eye_name = input("Please, select a player!", ok, null, null) as null|anything in creatures
-
- if (!eye_name)
- return
-
- var/mob/mob_eye = creatures[eye_name]
-
- if(client && mob_eye)
- client.eye = mob_eye
- if (is_admin)
- client.adminobs = 1
- if(mob_eye == client.mob || client.eye == client.mob)
- client.adminobs = 0
-
-/mob/verb/cancel_camera()
- set name = "Cancel Camera View"
- set category = "OOC"
- reset_view(null)
- unset_machine()
- if(istype(src, /mob/living))
- if(src:cameraFollow)
- src:cameraFollow = null
-
-/mob/Topic(href, href_list)
- if(href_list["mach_close"])
- var/t1 = text("window=[href_list["mach_close"]]")
- unset_machine()
- src << browse(null, t1)
-
- if(href_list["refresh"])
- if(machine && in_range(src, usr))
- show_inv(machine)
-
- if(!usr.stat && usr.canmove && !usr.restrained() && Adjacent(usr))
- if(href_list["item"])
- var/slot = text2num(href_list["item"])
- var/obj/item/what = get_item_by_slot(slot)
-
- if(what)
- if(what.flags & NODROP)
- usr << "You can't remove \the [what.name], it appears to be stuck!"
- return
- visible_message("[usr] tries to remove [src]'s [what.name].", \
- "[usr] tries to remove [src]'s [what.name].")
- what.add_fingerprint(usr)
- if(do_mob(usr, src, STRIP_DELAY))
- if(what && Adjacent(usr))
- unEquip(what)
- else
- what = usr.get_active_hand()
- if(what && (what.flags & NODROP))
- usr << "You can't put \the [what.name] on [src], it's stuck to your hand!"
- return
- if(what && what.mob_can_equip(src, slot, 1))
- visible_message("[usr] tries to put [what] on [src].")
- if(do_mob(usr, src, STRIP_DELAY * 0.5))
- if(what && Adjacent(usr))
- usr.unEquip(what)
- equip_to_slot_if_possible(what, slot, 0, 1)
-
- if(usr.machine == src)
- if(Adjacent(usr))
- show_inv(usr)
- else
- usr << browse(null,"window=mob\ref[src]")
-
-
-/mob/MouseDrop(mob/M)
- ..()
- if(M != usr) return
- if(usr == src) return
- if(!Adjacent(usr)) return
- if(istype(M, /mob/living/silicon/ai)) return
- show_inv(usr)
-
-
-/mob/verb/stop_pulling()
-
- set name = "Stop Pulling"
- set category = "IC"
-
- if(pulling)
- pulling.pulledby = null
- pulling = null
-
-/mob/proc/start_pulling(var/atom/movable/AM)
- if ( !AM || !usr || src==AM || !isturf(src.loc) ) //if there's no person pulling OR the person is pulling themself OR the object being pulled is inside something: abort!
- return
- if (!( AM.anchored ))
- AM.add_fingerprint(src)
-
- // If we're pulling something then drop what we're currently pulling and pull this instead.
- if(pulling)
- // Are we trying to pull something we are already pulling? Then just stop here, no need to continue.
- if(AM == pulling)
- return
- stop_pulling()
-
- src.pulling = AM
- AM.pulledby = src
- if(ismob(AM))
- var/mob/M = AM
- if(!iscarbon(src))
- M.LAssailant = null
- else
- M.LAssailant = usr
-
-
-/mob/proc/can_use_hands()
- return
-
-/mob/proc/is_active()
- return (0 >= usr.stat)
-
-/mob/proc/see(message)
- if(!is_active())
- return 0
- src << message
- return 1
-
-/mob/proc/show_viewers(message)
- for(var/mob/M in viewers())
- M.see(message)
-
-/mob/Stat()
- ..()
-
- if(client && client.holder)
-
- if(statpanel("Status")) //not looking at that panel
- stat(null,"Location:\t([x], [y], [z])")
- stat(null,"CPU:\t[world.cpu]")
- stat(null,"Instances:\t[world.contents.len]")
-
- if(master_controller)
- stat(null,"MasterController-[last_tick_duration] ([master_controller.processing?"On":"Off"]-[controller_iteration])")
- stat(null,"Air-[master_controller.air_cost]\t#[global_activeturfs]")
- stat(null,"Sun-[master_controller.sun_cost]")
- stat(null,"Mob-[master_controller.mobs_cost]\t#[mob_list.len]")
- stat(null,"Dis-[master_controller.diseases_cost]\t#[active_diseases.len]")
- stat(null,"Mch-[master_controller.machines_cost]\t#[machines.len]")
- stat(null,"Obj-[master_controller.objects_cost]\t#[processing_objects.len]")
- stat(null,"Net-[master_controller.networks_cost]\tPnet-[master_controller.powernets_cost]")
- stat(null,"NanoUI-[master_controller.nano_cost]\t#[nanomanager.processing_uis.len]")
- stat(null,"GC-[master_controller.gc_cost]\t#[garbage.destroyed.len + garbage.queue.len]-#dels[garbage.dels]")
- stat(null,"Tick-[master_controller.ticker_cost]\tALL-[master_controller.total_cost]")
- else
- stat(null,"MasterController-ERROR")
-
- if(listed_turf && client)
- if(!TurfAdjacent(listed_turf))
- listed_turf = null
- else
- statpanel(listed_turf.name, null, listed_turf)
- for(var/atom/A in listed_turf)
- if(A.invisibility > see_invisible)
- continue
- statpanel(listed_turf.name, null, A)
-
-
- if(mind)
- add_spells_to_statpanel(mind.spell_list)
- if(mind.changeling)
- add_stings_to_statpanel(mind.changeling.purchasedpowers)
- add_spells_to_statpanel(mob_spell_list)
-
-/mob/proc/add_spells_to_statpanel(var/list/spells)
- for(var/obj/effect/proc_holder/spell/S in spells)
- if(S.can_be_cast_by(src))
- switch(S.charge_type)
- if("recharge")
- statpanel("[S.panel]","[S.charge_counter/10.0]/[S.charge_max/10]",S)
- if("charges")
- statpanel("[S.panel]","[S.charge_counter]/[S.charge_max]",S)
- if("holdervar")
- statpanel("[S.panel]","[S.holder_var_type] [S.holder_var_amount]",S)
-
-/mob/proc/add_stings_to_statpanel(var/list/stings)
- for(var/obj/effect/proc_holder/changeling/S in stings)
- if(S.chemical_cost >=0 && S.can_be_used_by(src))
- statpanel("[S.panel]",((S.chemical_cost > 0) ? "[S.chemical_cost]" : ""),S)
-
-// facing verbs
-/mob/proc/canface()
- if(!canmove) return 0
- if(client.moving) return 0
- if(world.time < client.move_delay) return 0
- if(stat==2) return 0
- if(anchored) return 0
- if(notransform) return 0
- if(restrained()) return 0
- return 1
-
-//Updates canmove, lying and icons. Could perhaps do with a rename but I can't think of anything to describe it.
-//Robots and brains have their own version so don't worry about them
-/mob/proc/update_canmove()
- var/ko = weakened || paralysis || stat || (status_flags & FAKEDEATH)
- var/bed = !(buckled && istype(buckled, /obj/structure/stool/bed/chair))
- if(ko || resting || stunned)
- drop_r_hand()
- drop_l_hand()
- else
- lying = 0
- canmove = 1
- if(buckled)
- lying = 90 * bed
- else
- if((ko || resting) && !lying)
- fall(ko)
- anchored = buckled
- canmove = !(ko || resting || stunned || buckled)
- density = !lying
- update_transform()
- lying_prev = lying
- if(update_icon) //forces a full overlay update
- update_icon = 0
- regenerate_icons()
- return canmove
-
-/mob/proc/fall(var/forced)
- drop_l_hand()
- drop_r_hand()
-
-/mob/verb/eastface()
- set hidden = 1
- if(!canface()) return 0
- dir = EAST
- client.move_delay += movement_delay()
- return 1
-
-
-/mob/verb/westface()
- set hidden = 1
- if(!canface()) return 0
- dir = WEST
- client.move_delay += movement_delay()
- return 1
-
-
-/mob/verb/northface()
- set hidden = 1
- if(!canface()) return 0
- dir = NORTH
- client.move_delay += movement_delay()
- return 1
-
-
-/mob/verb/southface()
- set hidden = 1
- if(!canface()) return 0
- dir = SOUTH
- client.move_delay += movement_delay()
- return 1
-
-
-/mob/proc/IsAdvancedToolUser()//This might need a rename but it should replace the can this mob use things check
- return 0
-
-/mob/proc/Jitter(amount)
- jitteriness = max(jitteriness,amount,0)
-
-/mob/proc/Dizzy(amount)
- dizziness = max(dizziness,amount,0)
-
-/mob/proc/Stun(amount)
- if(status_flags & CANSTUN)
- stunned = max(max(stunned,amount),0) //can't go below 0, getting a low amount of stun doesn't lower your current stun
- update_canmove()
- return
-
-/mob/proc/SetStunned(amount) //if you REALLY need to set stun to a set amount without the whole "can't go below current stunned"
- if(status_flags & CANSTUN)
- stunned = max(amount,0)
- update_canmove()
- return
-
-/mob/proc/AdjustStunned(amount)
- if(status_flags & CANSTUN)
- stunned = max(stunned + amount,0)
- update_canmove()
- return
-
-/mob/proc/Weaken(amount)
- if(status_flags & CANWEAKEN)
- weakened = max(max(weakened,amount),0)
- update_canmove() //updates lying, canmove and icons
- return
-
-/mob/proc/SetWeakened(amount)
- if(status_flags & CANWEAKEN)
- weakened = max(amount,0)
- update_canmove() //updates lying, canmove and icons
- return
-
-/mob/proc/AdjustWeakened(amount)
- if(status_flags & CANWEAKEN)
- weakened = max(weakened + amount,0)
- update_canmove() //updates lying, canmove and icons
- return
-
-/mob/proc/Paralyse(amount)
- if(status_flags & CANPARALYSE)
- paralysis = max(max(paralysis,amount),0)
- update_canmove()
- return
-
-/mob/proc/SetParalysis(amount)
- if(status_flags & CANPARALYSE)
- paralysis = max(amount,0)
- update_canmove()
- return
-
-/mob/proc/AdjustParalysis(amount)
- if(status_flags & CANPARALYSE)
- paralysis = max(paralysis + amount,0)
- update_canmove()
- return
-
-/mob/proc/Sleeping(amount)
- sleeping = max(max(sleeping,amount),0)
- update_canmove()
- return
-
-/mob/proc/SetSleeping(amount)
- sleeping = max(amount,0)
- update_canmove()
- return
-
-/mob/proc/AdjustSleeping(amount)
- sleeping = max(sleeping + amount,0)
- update_canmove()
- return
-
-/mob/proc/Resting(amount)
- resting = max(max(resting,amount),0)
- update_canmove()
- return
-
-/mob/proc/SetResting(amount)
- resting = max(amount,0)
- update_canmove()
- return
-
-/mob/proc/AdjustResting(amount)
- resting = max(resting + amount,0)
- update_canmove()
- return
\ No newline at end of file
+/mob/Destroy()//This makes sure that mobs with clients/keys are not just deleted from the game.
+ mob_list -= src
+ dead_mob_list -= src
+ living_mob_list -= src
+ //Set the mob up for GC. Mobs have lots of references
+ if(client)
+ for(var/atom/movable/AM in client.screen)
+ qdel(AM)
+ client.screen = list()
+ del(hud_used)
+ spellremove(src)
+ for(var/infection in viruses)
+ del(infection)
+ ghostize()
+ ..()
+
+var/next_mob_id = 0
+/mob/New()
+ tag = "mob_[next_mob_id++]"
+ mob_list += src
+ if(stat == DEAD)
+ dead_mob_list += src
+ else
+ living_mob_list += src
+ ..()
+
+/mob/proc/Cell()
+ set category = "Admin"
+ set hidden = 1
+
+ if(!loc) return 0
+
+ var/datum/gas_mixture/environment = loc.return_air()
+
+ var/t = "\blue Coordinates: [x],[y] \n"
+ t+= "\red Temperature: [environment.temperature] \n"
+ t+= "\blue Nitrogen: [environment.nitrogen] \n"
+ t+= "\blue Oxygen: [environment.oxygen] \n"
+ t+= "\blue Plasma : [environment.toxins] \n"
+ t+= "\blue Carbon Dioxide: [environment.carbon_dioxide] \n"
+ for(var/datum/gas/trace_gas in environment.trace_gases)
+ usr << "\blue [trace_gas.type]: [trace_gas.moles] \n"
+
+ usr.show_message(t, 1)
+
+/mob/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
+
+ if(!client) return
+
+ msg = copytext(msg, 1, MAX_MESSAGE_LEN)
+
+ if (type)
+ if(type & 1 && (sdisabilities & BLIND || blinded || paralysis) )//Vision related
+ if (!( alt ))
+ return
+ else
+ msg = alt
+ type = alt_type
+ if (type & 2 && (sdisabilities & DEAF || ear_deaf))//Hearing related
+ if (!( alt ))
+ return
+ else
+ msg = alt
+ type = alt_type
+ if ((type & 1 && sdisabilities & BLIND))
+ return
+ // Added voice muffling for Issue 41.
+ if(stat == UNCONSCIOUS || sleeping > 0)
+ src << "... You can almost hear someone talking ..."
+ else
+ src << msg
+ return
+
+// Show a message to all mobs in sight of this one
+// This would be for visible actions by the src mob
+// message is the message output to anyone who can see e.g. "[src] does something!"
+// self_message (optional) is what the src mob sees e.g. "You do something!"
+// blind_message (optional) is what blind people will hear e.g. "You hear something!"
+
+/mob/visible_message(var/message, var/self_message, var/blind_message)
+ for(var/mob/M in viewers(src))
+ var/msg = message
+ if(self_message && M==src)
+ msg = self_message
+ M.show_message( msg, 1, blind_message, 2)
+
+// Show a message to all mobs in sight of this atom
+// Use for objects performing visible actions
+// message is output to anyone who can see, e.g. "The [src] does something!"
+// blind_message (optional) is what blind people will hear e.g. "You hear something!"
+/atom/proc/visible_message(var/message, var/blind_message)
+ for(var/mob/M in viewers(src))
+ M.show_message( message, 1, blind_message, 2)
+
+
+/mob/proc/movement_delay()
+ return 0
+
+/mob/proc/Life()
+ return
+
+/mob/proc/get_item_by_slot(slot_id)
+ switch(slot_id)
+ if(slot_l_hand)
+ return l_hand
+ if(slot_r_hand)
+ return r_hand
+ return null
+
+/mob/proc/ret_grab(obj/effect/list_container/mobl/L as obj, flag)
+ if ((!( istype(l_hand, /obj/item/weapon/grab) ) && !( istype(r_hand, /obj/item/weapon/grab) )))
+ if (!( L ))
+ return null
+ else
+ return L.container
+ else
+ if (!( L ))
+ L = new /obj/effect/list_container/mobl( null )
+ L.container += src
+ L.master = src
+ if (istype(l_hand, /obj/item/weapon/grab))
+ var/obj/item/weapon/grab/G = l_hand
+ if (!( L.container.Find(G.affecting) ))
+ L.container += G.affecting
+ if (G.affecting)
+ G.affecting.ret_grab(L, 1)
+ if (istype(r_hand, /obj/item/weapon/grab))
+ var/obj/item/weapon/grab/G = r_hand
+ if (!( L.container.Find(G.affecting) ))
+ L.container += G.affecting
+ if (G.affecting)
+ G.affecting.ret_grab(L, 1)
+ if (!( flag ))
+ if (L.master == src)
+ var/list/temp = list( )
+ temp += L.container
+ //L = null
+ qdel(L)
+ return temp
+ else
+ return L.container
+ return
+
+/mob/proc/restrained()
+ return
+
+//This proc is called whenever someone clicks an inventory ui slot.
+/mob/proc/attack_ui(slot)
+ var/obj/item/W = get_active_hand()
+
+ if(istype(W))
+ if(equip_to_slot_if_possible(W, slot,0,0,0))
+ return 1
+
+ if(!W)
+ // Activate the item
+ var/obj/item/I = get_item_by_slot(slot)
+ if(istype(I))
+ I.attack_hand(src)
+
+ return 0
+
+/mob/proc/put_in_any_hand_if_possible(obj/item/W as obj, qdel_on_fail = 0, disable_warning = 1, redraw_mob = 1)
+ if(equip_to_slot_if_possible(W, slot_l_hand, qdel_on_fail, disable_warning, redraw_mob))
+ return 1
+ else if(equip_to_slot_if_possible(W, slot_r_hand, qdel_on_fail, disable_warning, redraw_mob))
+ return 1
+ return 0
+
+//This is a SAFE proc. Use this instead of equip_to_splot()!
+//set qdel_on_fail to have it delete W if it fails to equip
+//set disable_warning to disable the 'you are unable to equip that' warning.
+//unset redraw_mob to prevent the mob from being redrawn at the end.
+/mob/proc/equip_to_slot_if_possible(obj/item/W as obj, slot, qdel_on_fail = 0, disable_warning = 0, redraw_mob = 1)
+ if(!istype(W)) return 0
+ if(!W.mob_can_equip(src, slot, disable_warning))
+ if(qdel_on_fail)
+ qdel(W)
+ else
+ if(!disable_warning)
+ src << "\red You are unable to equip that." //Only print if qdel_on_fail is false
+ return 0
+ equip_to_slot(W, slot, redraw_mob) //This proc should not ever fail.
+ return 1
+
+//This is an UNSAFE proc. It merely handles the actual job of equipping. All the checks on whether you can or can't eqip need to be done before! Use mob_can_equip() for that task.
+//In most cases you will want to use equip_to_slot_if_possible()
+/mob/proc/equip_to_slot(obj/item/W as obj, slot)
+ return
+
+//This is just a commonly used configuration for the equip_to_slot_if_possible() proc, used to equip people when the rounds tarts and when events happen and such.
+/mob/proc/equip_to_slot_or_del(obj/item/W as obj, slot)
+ equip_to_slot_if_possible(W, slot, 1, 1, 0)
+
+//The list of slots by priority. equip_to_appropriate_slot() uses this list. Doesn't matter if a mob type doesn't have a slot.
+var/list/slot_equipment_priority = list( \
+ slot_back,\
+ slot_wear_id,\
+ slot_w_uniform,\
+ slot_wear_suit,\
+ slot_wear_mask,\
+ slot_head,\
+ slot_shoes,\
+ slot_gloves,\
+ slot_ears,\
+ slot_glasses,\
+ slot_belt,\
+ slot_s_store,\
+ slot_l_store,\
+ slot_r_store\
+ )
+
+//puts the item "W" into an appropriate slot in a human's inventory
+//returns 0 if it cannot, 1 if successful
+/mob/proc/equip_to_appropriate_slot(obj/item/W)
+ if(!istype(W)) return 0
+
+ for(var/slot in slot_equipment_priority)
+ if(equip_to_slot_if_possible(W, slot, 0, 1, 1)) //qdel_on_fail = 0; disable_warning = 0; redraw_mob = 1
+ return 1
+
+ return 0
+
+/mob/proc/reset_view(atom/A)
+ if (client)
+ if (istype(A, /atom/movable))
+ client.perspective = EYE_PERSPECTIVE
+ client.eye = A
+ else
+ if (isturf(loc))
+ client.eye = client.mob
+ client.perspective = MOB_PERSPECTIVE
+ else
+ client.perspective = EYE_PERSPECTIVE
+ client.eye = loc
+ return
+
+
+/mob/proc/show_inv(mob/user)
+ user.set_machine(src)
+ var/dat = {"
+
+ [name]
+
+
Left Hand: [(l_hand&&!(l_hand.flags&ABSTRACT)) ? l_hand : "Nothing"]
+
Right Hand: [(r_hand&&!(r_hand.flags&ABSTRACT)) ? r_hand : "Nothing"]
+
Close
+ "}
+ user << browse(dat, "window=mob\ref[src];size=325x500")
+ onclose(user, "mob\ref[src]")
+
+
+/mob/verb/mode()
+ set name = "Activate Held Object"
+ set category = "Object"
+ set src = usr
+
+ if(istype(loc,/obj/mecha)) return
+
+ if(hand)
+ var/obj/item/W = l_hand
+ if (W)
+ W.attack_self(src)
+ update_inv_l_hand(0)
+ else
+ var/obj/item/W = r_hand
+ if (W)
+ W.attack_self(src)
+ update_inv_r_hand(0)
+ return
+
+/*
+/mob/verb/dump_source()
+
+ var/master = ""
+ for(var/t in typesof(/area))
+ master += text("[]\n", t)
+ //Foreach goto(26)
+ src << browse(master)
+ return
+*/
+
+/mob/verb/memory()
+ set name = "Notes"
+ set category = "IC"
+ if(mind)
+ mind.show_memory(src)
+ else
+ src << "The game appears to have misplaced your mind datum, so we can't show you your notes."
+
+/mob/verb/add_memory(msg as message)
+ set name = "Add Note"
+ set category = "IC"
+
+ msg = copytext(msg, 1, MAX_MESSAGE_LEN)
+ msg = sanitize(msg)
+
+ if(mind)
+ mind.store_memory(msg)
+ else
+ src << "The game appears to have misplaced your mind datum, so we can't show you your notes."
+
+/mob/proc/store_memory(msg as message, popup, sane = 1)
+ msg = copytext(msg, 1, MAX_MESSAGE_LEN)
+
+ if (sane)
+ msg = sanitize(msg)
+
+ if (length(memory) == 0)
+ memory += msg
+ else
+ memory += "
[msg]"
+
+ if (popup)
+ memory()
+
+/*
+/mob/verb/help()
+ set name = "Help"
+ src << browse('html/help.html', "window=help")
+ return
+*/
+
+/mob/verb/abandon_mob()
+ set name = "Respawn"
+ set category = "OOC"
+
+ if (!( abandon_allowed ))
+ return
+ if ((stat != 2 || !( ticker )))
+ usr << "\blue You must be dead to use this!"
+ return
+
+ log_game("[usr.name]/[usr.key] used abandon mob.")
+
+ usr << "\blue Please roleplay correctly!"
+
+ if(!client)
+ log_game("[usr.key] AM failed due to disconnect.")
+ return
+ client.screen.Cut()
+ if(!client)
+ log_game("[usr.key] AM failed due to disconnect.")
+ return
+
+ var/mob/new_player/M = new /mob/new_player()
+ if(!client)
+ log_game("[usr.key] AM failed due to disconnect.")
+ qdel(M)
+ return
+
+ M.key = key
+// M.Login() //wat
+ return
+
+/client/verb/changes()
+ set name = "Changelog"
+ set category = "OOC"
+ getFiles(
+ 'html/postcardsmall.jpg',
+ 'html/somerights20.png',
+ 'html/88x31.png',
+ 'html/bug-minus.png',
+ 'html/cross-circle.png',
+ 'html/hard-hat-exclamation.png',
+ 'html/image-minus.png',
+ 'html/image-plus.png',
+ 'html/music-minus.png',
+ 'html/music-plus.png',
+ 'html/tick-circle.png',
+ 'html/wrench-screwdriver.png',
+ 'html/spell-check.png',
+ 'html/burn-exclamation.png',
+ 'html/chevron.png',
+ 'html/chevron-expand.png',
+ 'html/changelog.css',
+ 'html/changelog.js',
+ 'html/changelog.html'
+ )
+ src << browse('html/changelog.html', "window=changes;size=675x650")
+ if(prefs.lastchangelog != changelog_hash)
+ prefs.lastchangelog = changelog_hash
+ prefs.save_preferences()
+ winset(src, "rpane.changelog", "background-color=none;font-style=;")
+
+/mob/verb/observe()
+ set name = "Observe"
+ set category = "OOC"
+ var/is_admin = 0
+
+ if(check_rights_for(client,R_ADMIN))
+ is_admin = 1
+ else if(stat != DEAD || istype(src, /mob/new_player))
+ usr << "\blue You must be observing to use this!"
+ return
+
+ if(is_admin && stat == DEAD)
+ is_admin = 0
+
+ var/list/names = list()
+ var/list/namecounts = list()
+ var/list/creatures = list()
+
+ for(var/obj/O in world) //EWWWWWWWWWWWWWWWWWWWWWWWW ~needs to be optimised
+ if(!O.loc)
+ continue
+ if(istype(O, /obj/item/weapon/disk/nuclear))
+ var/name = "Nuclear Disk"
+ if (names.Find(name))
+ namecounts[name]++
+ name = "[name] ([namecounts[name]])"
+ else
+ names.Add(name)
+ namecounts[name] = 1
+ creatures[name] = O
+
+ if(istype(O, /obj/machinery/singularity))
+ var/name = "Singularity"
+ if (names.Find(name))
+ namecounts[name]++
+ name = "[name] ([namecounts[name]])"
+ else
+ names.Add(name)
+ namecounts[name] = 1
+ creatures[name] = O
+
+ if(istype(O, /obj/machinery/bot))
+ var/name = "BOT: [O.name]"
+ if (names.Find(name))
+ namecounts[name]++
+ name = "[name] ([namecounts[name]])"
+ else
+ names.Add(name)
+ namecounts[name] = 1
+ creatures[name] = O
+
+
+ for(var/mob/M in sortAtom(mob_list))
+ var/name = M.name
+ if (names.Find(name))
+ namecounts[name]++
+ name = "[name] ([namecounts[name]])"
+ else
+ names.Add(name)
+ namecounts[name] = 1
+
+ creatures[name] = M
+
+
+ client.perspective = EYE_PERSPECTIVE
+
+ var/eye_name = null
+
+ var/ok = "[is_admin ? "Admin Observe" : "Observe"]"
+ eye_name = input("Please, select a player!", ok, null, null) as null|anything in creatures
+
+ if (!eye_name)
+ return
+
+ var/mob/mob_eye = creatures[eye_name]
+
+ if(client && mob_eye)
+ client.eye = mob_eye
+ if (is_admin)
+ client.adminobs = 1
+ if(mob_eye == client.mob || client.eye == client.mob)
+ client.adminobs = 0
+
+/mob/verb/cancel_camera()
+ set name = "Cancel Camera View"
+ set category = "OOC"
+ reset_view(null)
+ unset_machine()
+ if(istype(src, /mob/living))
+ if(src:cameraFollow)
+ src:cameraFollow = null
+
+/mob/Topic(href, href_list)
+ if(href_list["mach_close"])
+ var/t1 = text("window=[href_list["mach_close"]]")
+ unset_machine()
+ src << browse(null, t1)
+
+ if(href_list["refresh"])
+ if(machine && in_range(src, usr))
+ show_inv(machine)
+
+ if(!usr.stat && usr.canmove && !usr.restrained() && Adjacent(usr))
+ if(href_list["item"])
+ var/slot = text2num(href_list["item"])
+ var/obj/item/what = get_item_by_slot(slot)
+
+ if(what)
+ if(what.flags & NODROP)
+ usr << "You can't remove \the [what.name], it appears to be stuck!"
+ return
+ visible_message("[usr] tries to remove [src]'s [what.name].", \
+ "[usr] tries to remove [src]'s [what.name].")
+ what.add_fingerprint(usr)
+ if(do_mob(usr, src, STRIP_DELAY))
+ if(what && Adjacent(usr))
+ unEquip(what)
+ else
+ what = usr.get_active_hand()
+ if(what && (what.flags & NODROP))
+ usr << "You can't put \the [what.name] on [src], it's stuck to your hand!"
+ return
+ if(what && what.mob_can_equip(src, slot, 1))
+ visible_message("[usr] tries to put [what] on [src].")
+ if(do_mob(usr, src, STRIP_DELAY * 0.5))
+ if(what && Adjacent(usr))
+ usr.unEquip(what)
+ equip_to_slot_if_possible(what, slot, 0, 1)
+
+ if(usr.machine == src)
+ if(Adjacent(usr))
+ show_inv(usr)
+ else
+ usr << browse(null,"window=mob\ref[src]")
+
+
+/mob/MouseDrop(mob/M)
+ ..()
+ if(M != usr) return
+ if(usr == src) return
+ if(!Adjacent(usr)) return
+ if(istype(M, /mob/living/silicon/ai)) return
+ show_inv(usr)
+
+
+/mob/verb/stop_pulling()
+
+ set name = "Stop Pulling"
+ set category = "IC"
+
+ if(pulling)
+ pulling.pulledby = null
+ pulling = null
+
+/mob/proc/start_pulling(var/atom/movable/AM)
+ if ( !AM || !usr || src==AM || !isturf(src.loc) ) //if there's no person pulling OR the person is pulling themself OR the object being pulled is inside something: abort!
+ return
+ if (!( AM.anchored ))
+ AM.add_fingerprint(src)
+
+ // If we're pulling something then drop what we're currently pulling and pull this instead.
+ if(pulling)
+ // Are we trying to pull something we are already pulling? Then just stop here, no need to continue.
+ if(AM == pulling)
+ return
+ stop_pulling()
+
+ src.pulling = AM
+ AM.pulledby = src
+ if(ismob(AM))
+ var/mob/M = AM
+ if(!iscarbon(src))
+ M.LAssailant = null
+ else
+ M.LAssailant = usr
+
+
+/mob/proc/can_use_hands()
+ return
+
+/mob/proc/is_active()
+ return (0 >= usr.stat)
+
+/mob/proc/see(message)
+ if(!is_active())
+ return 0
+ src << message
+ return 1
+
+/mob/proc/show_viewers(message)
+ for(var/mob/M in viewers())
+ M.see(message)
+
+/mob/Stat()
+ ..()
+
+ if(client && client.holder)
+
+ if(statpanel("Status")) //not looking at that panel
+ stat(null,"Location:\t([x], [y], [z])")
+ stat(null,"CPU:\t[world.cpu]")
+ stat(null,"Instances:\t[world.contents.len]")
+
+ if(master_controller)
+ stat(null,"MasterController-[last_tick_duration] ([master_controller.processing?"On":"Off"]-[controller_iteration])")
+ stat(null,"Air-[master_controller.air_cost]\t#[global_activeturfs]")
+ stat(null,"Sun-[master_controller.sun_cost]")
+ stat(null,"Mob-[master_controller.mobs_cost]\t#[mob_list.len]")
+ stat(null,"Dis-[master_controller.diseases_cost]\t#[active_diseases.len]")
+ stat(null,"Mch-[master_controller.machines_cost]\t#[machines.len]")
+ stat(null,"Obj-[master_controller.objects_cost]\t#[processing_objects.len]")
+ stat(null,"Net-[master_controller.networks_cost]\tPnet-[master_controller.powernets_cost]")
+ stat(null,"NanoUI-[master_controller.nano_cost]\t#[nanomanager.processing_uis.len]")
+ stat(null,"GC-[master_controller.gc_cost]\t#[garbage.destroyed.len]-#dels[garbage.dels]")
+ stat(null,"Tick-[master_controller.ticker_cost]\tALL-[master_controller.total_cost]")
+ else
+ stat(null,"MasterController-ERROR")
+
+ if(listed_turf && client)
+ if(!TurfAdjacent(listed_turf))
+ listed_turf = null
+ else
+ statpanel(listed_turf.name, null, listed_turf)
+ for(var/atom/A in listed_turf)
+ if(A.invisibility > see_invisible)
+ continue
+ statpanel(listed_turf.name, null, A)
+
+
+ if(mind)
+ add_spells_to_statpanel(mind.spell_list)
+ if(mind.changeling)
+ add_stings_to_statpanel(mind.changeling.purchasedpowers)
+ add_spells_to_statpanel(mob_spell_list)
+
+/mob/proc/add_spells_to_statpanel(var/list/spells)
+ for(var/obj/effect/proc_holder/spell/S in spells)
+ if(S.can_be_cast_by(src))
+ switch(S.charge_type)
+ if("recharge")
+ statpanel("[S.panel]","[S.charge_counter/10.0]/[S.charge_max/10]",S)
+ if("charges")
+ statpanel("[S.panel]","[S.charge_counter]/[S.charge_max]",S)
+ if("holdervar")
+ statpanel("[S.panel]","[S.holder_var_type] [S.holder_var_amount]",S)
+
+/mob/proc/add_stings_to_statpanel(var/list/stings)
+ for(var/obj/effect/proc_holder/changeling/S in stings)
+ if(S.chemical_cost >=0 && S.can_be_used_by(src))
+ statpanel("[S.panel]",((S.chemical_cost > 0) ? "[S.chemical_cost]" : ""),S)
+
+// facing verbs
+/mob/proc/canface()
+ if(!canmove) return 0
+ if(client.moving) return 0
+ if(world.time < client.move_delay) return 0
+ if(stat==2) return 0
+ if(anchored) return 0
+ if(notransform) return 0
+ if(restrained()) return 0
+ return 1
+
+//Updates canmove, lying and icons. Could perhaps do with a rename but I can't think of anything to describe it.
+//Robots and brains have their own version so don't worry about them
+/mob/proc/update_canmove()
+ var/ko = weakened || paralysis || stat || (status_flags & FAKEDEATH)
+ var/bed = !(buckled && istype(buckled, /obj/structure/stool/bed/chair))
+ if(ko || resting || stunned)
+ drop_r_hand()
+ drop_l_hand()
+ else
+ lying = 0
+ canmove = 1
+ if(buckled)
+ lying = 90 * bed
+ else
+ if((ko || resting) && !lying)
+ fall(ko)
+ anchored = buckled
+ canmove = !(ko || resting || stunned || buckled)
+ density = !lying
+ update_transform()
+ lying_prev = lying
+ if(update_icon) //forces a full overlay update
+ update_icon = 0
+ regenerate_icons()
+ return canmove
+
+/mob/proc/fall(var/forced)
+ drop_l_hand()
+ drop_r_hand()
+
+/mob/verb/eastface()
+ set hidden = 1
+ if(!canface()) return 0
+ dir = EAST
+ client.move_delay += movement_delay()
+ return 1
+
+
+/mob/verb/westface()
+ set hidden = 1
+ if(!canface()) return 0
+ dir = WEST
+ client.move_delay += movement_delay()
+ return 1
+
+
+/mob/verb/northface()
+ set hidden = 1
+ if(!canface()) return 0
+ dir = NORTH
+ client.move_delay += movement_delay()
+ return 1
+
+
+/mob/verb/southface()
+ set hidden = 1
+ if(!canface()) return 0
+ dir = SOUTH
+ client.move_delay += movement_delay()
+ return 1
+
+
+/mob/proc/IsAdvancedToolUser()//This might need a rename but it should replace the can this mob use things check
+ return 0
+
+/mob/proc/Jitter(amount)
+ jitteriness = max(jitteriness,amount,0)
+
+/mob/proc/Dizzy(amount)
+ dizziness = max(dizziness,amount,0)
+
+/mob/proc/Stun(amount)
+ if(status_flags & CANSTUN)
+ stunned = max(max(stunned,amount),0) //can't go below 0, getting a low amount of stun doesn't lower your current stun
+ update_canmove()
+ return
+
+/mob/proc/SetStunned(amount) //if you REALLY need to set stun to a set amount without the whole "can't go below current stunned"
+ if(status_flags & CANSTUN)
+ stunned = max(amount,0)
+ update_canmove()
+ return
+
+/mob/proc/AdjustStunned(amount)
+ if(status_flags & CANSTUN)
+ stunned = max(stunned + amount,0)
+ update_canmove()
+ return
+
+/mob/proc/Weaken(amount)
+ if(status_flags & CANWEAKEN)
+ weakened = max(max(weakened,amount),0)
+ update_canmove() //updates lying, canmove and icons
+ return
+
+/mob/proc/SetWeakened(amount)
+ if(status_flags & CANWEAKEN)
+ weakened = max(amount,0)
+ update_canmove() //updates lying, canmove and icons
+ return
+
+/mob/proc/AdjustWeakened(amount)
+ if(status_flags & CANWEAKEN)
+ weakened = max(weakened + amount,0)
+ update_canmove() //updates lying, canmove and icons
+ return
+
+/mob/proc/Paralyse(amount)
+ if(status_flags & CANPARALYSE)
+ paralysis = max(max(paralysis,amount),0)
+ update_canmove()
+ return
+
+/mob/proc/SetParalysis(amount)
+ if(status_flags & CANPARALYSE)
+ paralysis = max(amount,0)
+ update_canmove()
+ return
+
+/mob/proc/AdjustParalysis(amount)
+ if(status_flags & CANPARALYSE)
+ paralysis = max(paralysis + amount,0)
+ update_canmove()
+ return
+
+/mob/proc/Sleeping(amount)
+ sleeping = max(max(sleeping,amount),0)
+ update_canmove()
+ return
+
+/mob/proc/SetSleeping(amount)
+ sleeping = max(amount,0)
+ update_canmove()
+ return
+
+/mob/proc/AdjustSleeping(amount)
+ sleeping = max(sleeping + amount,0)
+ update_canmove()
+ return
+
+/mob/proc/Resting(amount)
+ resting = max(max(resting,amount),0)
+ update_canmove()
+ return
+
+/mob/proc/SetResting(amount)
+ resting = max(amount,0)
+ update_canmove()
+ return
+
+/mob/proc/AdjustResting(amount)
+ resting = max(resting + amount,0)
+ update_canmove()
+ return
diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm
index 8f7c703591f..48b279a587d 100644
--- a/code/modules/mob/mob_grab.dm
+++ b/code/modules/mob/mob_grab.dm
@@ -163,7 +163,7 @@
assailant.visible_message("[assailant] has tightened \his grip on [affecting]'s neck!")
add_logs(assailant, affecting, "strangled")
- assailant.next_move = world.time + 10
+ assailant.changeNext_move(10)
affecting.losebreath += 1
else
assailant.visible_message("[assailant] was unable to tighten \his grip on [affecting]'s neck!")
diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm
index 7bdc77290ab..8682335817e 100644
--- a/code/modules/mob/new_player/sprite_accessories.dm
+++ b/code/modules/mob/new_player/sprite_accessories.dm
@@ -282,6 +282,40 @@
name = "Side Part"
icon_state = "hair_part"
+ braid
+ name = "Braided"
+ icon_state = "hair_braid"
+
+ bun
+ name = "Bun Head"
+ icon_state = "hair_bun"
+ gender = FEMALE
+
+ side_tail
+ name = "Side Pony"
+ icon_state = "hair_sidetail"
+
+ long_over_eye
+ name = "Over eye"
+ icon_state = "hair_longovereye"
+
+ front_braid
+ name = "Braided front"
+ icon_state = "hair_braidfront"
+
+ antenna
+ name = "Ahoge"
+ icon_state = "hair_antenna"
+
+ pigtail
+ name = "Pig tails"
+ icon_state = "hair_pigtails"
+ gender = FEMALE
+
+ protagonist
+ name = "Slightly long"
+ icon_state = "hair_protagonist"
+
/////////////////////////////
// Facial Hair Definitions //
/////////////////////////////
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 0b0f1e3a6bb..bceb9ce2152 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -1,513 +1,513 @@
-/mob/living/carbon/proc/monkeyize(tr_flags = (TR_KEEPITEMS | TR_KEEPVIRUS | TR_DEFAULTMSG), newname = null)
- if (notransform)
- return
- //Handle items on mob
-
- //first implants
- var/list/implants = list()
- if (tr_flags & TR_KEEPIMPLANTS)
- for(var/obj/item/weapon/implant/W in src)
- implants += W
-
- if(tr_flags & TR_KEEPITEMS)
- for(var/obj/item/W in (src.contents-implants))
- unEquip(W)
-
- //Make mob invisible and spawn animation
- regenerate_icons()
- notransform = 1
- canmove = 0
- stunned = 1
- icon = null
- invisibility = 101
- var/atom/movable/overlay/animation = new /atom/movable/overlay( loc )
- animation.icon_state = "blank"
- animation.icon = 'icons/mob/mob.dmi'
- animation.master = src
- flick("h2monkey", animation)
- sleep(22)
- //animation = null
- var/mob/living/carbon/monkey/O = new /mob/living/carbon/monkey( loc )
- qdel(animation)
-
-
-
- // hash the original name?
- if (tr_flags & TR_HASHNAME)
- O.name = "monkey ([copytext(md5(real_name), 2, 6)])"
- O.real_name = "monkey ([copytext(md5(real_name), 2, 6)])"
- if (newname) //if there's a name as an argument, always take that one over the current name
- O.name = newname
- O.real_name = newname
-
- //handle DNA and other attributes
- O.dna = dna
- dna = null
- if (!(tr_flags & TR_KEEPSE))
- O.dna.struc_enzymes = setblock(O.dna.struc_enzymes, RACEBLOCK, construct_block(BAD_MUTATION_DIFFICULTY,BAD_MUTATION_DIFFICULTY))
- if(suiciding)
- O.suiciding = suiciding
- O.loc = loc
- O.a_intent = "harm"
-
- //keep viruses?
- if (tr_flags & TR_KEEPVIRUS)
- O.viruses = viruses
- viruses = list()
- for(var/datum/disease/D in O.viruses)
- D.affected_mob = O
-
- //keep damage?
- if (tr_flags & TR_KEEPDAMAGE)
- O.setToxLoss(getToxLoss())
- O.adjustBruteLoss(getBruteLoss())
- O.setOxyLoss(getOxyLoss())
- O.adjustFireLoss(getFireLoss())
-
- //re-add implants to new mob
- for(var/obj/item/weapon/implant/I in implants)
- I.loc = O
- I.implanted = O
-
- //transfer mind and delete old mob
- if(mind)
- mind.transfer_to(O)
- if (tr_flags & TR_DEFAULTMSG)
- O << "You are now a monkey."
- updateappearance(O)
- . = O
- if ( !(tr_flags & TR_KEEPSRC) ) //flag should be used if monkeyize() is called inside another proc of src so that one does not crash
- qdel(src)
- return
-
-
-
-////////////////////////// Humanize //////////////////////////////
-//Could probably be merged with monkeyize but other transformations got their own procs, too
-
-/mob/living/carbon/proc/humanize(tr_flags = (TR_KEEPITEMS | TR_KEEPVIRUS | TR_DEFAULTMSG), newname = null)
- if (notransform)
- return
- //Handle items on mob
-
- //first implants
- var/list/implants = list()
- if (tr_flags & TR_KEEPIMPLANTS)
- for(var/obj/item/weapon/implant/W in src)
- implants += W
-
- //now the rest
- if (tr_flags & TR_KEEPITEMS)
- for(var/obj/item/W in (src.contents-implants))
- unEquip(W)
- if (client)
- client.screen -= W
- if (W)
- W.loc = loc
- W.dropped(src)
- W.layer = initial(W.layer)
-
- // for(var/obj/item/W in src)
- // unEquip(W)
-
- //Make mob invisible and spawn animation
- regenerate_icons()
- notransform = 1
- canmove = 0
- stunned = 1
- icon = null
- invisibility = 101
- var/atom/movable/overlay/animation = new( loc )
- animation.icon_state = "blank"
- animation.icon = 'icons/mob/mob.dmi'
- animation.master = src
- flick("monkey2h", animation)
- sleep(22)
- var/mob/living/carbon/human/O = new( loc )
- for(var/obj/item/C in O.loc)
- O.equip_to_appropriate_slot(C)
- qdel(animation)
-
-
- O.gender = (deconstruct_block(getblock(dna.uni_identity, DNA_GENDER_BLOCK), 2)-1) ? FEMALE : MALE
- O.dna = dna
- dna = null
- if (newname) //if there's a name as an argument, always take that one over the current name
- O.real_name = newname
- else
- if ( !(cmptext ("monkey",copytext(O.dna.real_name,1,7)) ) )
- O.real_name = O.dna.real_name
- else
- O.real_name = random_name(O.gender)
- O.name = O.real_name
-
- if (!(tr_flags & TR_KEEPSE))
- O.dna.struc_enzymes = setblock(O.dna.struc_enzymes, RACEBLOCK, construct_block(1,BAD_MUTATION_DIFFICULTY))
-
- if(suiciding)
- O.suiciding = suiciding
-
- O.loc = loc
-
- //keep viruses?
- if (tr_flags & TR_KEEPVIRUS)
- O.viruses = viruses
- viruses = list()
- for(var/datum/disease/D in O.viruses)
- D.affected_mob = O
-
- //keep damage?
- if (tr_flags & TR_KEEPDAMAGE)
- O.setToxLoss(getToxLoss())
- O.adjustBruteLoss(getBruteLoss())
- O.setOxyLoss(getOxyLoss())
- O.adjustFireLoss(getFireLoss())
-
- //re-add implants to new mob
- for(var/obj/item/weapon/implant/I in implants)
- I.loc = O
- I.implanted = O
-
- if(mind)
- mind.transfer_to(O)
- O.a_intent = "help"
- if (tr_flags & TR_DEFAULTMSG)
- O << "You are now a human."
- updateappearance(O)
- . = O
- if ( !(tr_flags & TR_KEEPSRC) ) //don't delete src yet if it's needed to finish calling proc
- qdel(src)
- return
-
-/mob/new_player/AIize()
- spawning = 1
- return ..()
-
-/mob/living/carbon/human/AIize()
- if (notransform)
- return
- for(var/t in organs)
- qdel(t)
-
- return ..()
-
-/mob/living/carbon/AIize()
- if (notransform)
- return
- for(var/obj/item/W in src)
- unEquip(W)
- regenerate_icons()
- notransform = 1
- canmove = 0
- icon = null
- invisibility = 101
- return ..()
-
-/mob/proc/AIize()
- if(client)
- src << sound(null, repeat = 0, wait = 0, volume = 85, channel = 1) // stop the jams for AIs
- var/mob/living/silicon/ai/O = new (loc,,,1)//No MMI but safety is in effect.
- O.invisibility = 0
- O.aiRestorePowerRoutine = 0
-
- if(mind)
- mind.transfer_to(O)
- else
- O.key = key
-
- var/obj/loc_landmark
- for(var/obj/effect/landmark/start/sloc in landmarks_list)
- if (sloc.name != "AI")
- continue
- if (locate(/mob/living) in sloc.loc)
- continue
- loc_landmark = sloc
- if (!loc_landmark)
- for(var/obj/effect/landmark/tripai in landmarks_list)
- if (tripai.name == "tripai")
- if(locate(/mob/living) in tripai.loc)
- continue
- loc_landmark = tripai
- if (!loc_landmark)
- O << "Oh god sorry we can't find an unoccupied AI spawn location, so we're spawning you on top of someone."
- for(var/obj/effect/landmark/start/sloc in landmarks_list)
- if (sloc.name == "AI")
- loc_landmark = sloc
-
- O.loc = loc_landmark.loc
- for (var/obj/item/device/radio/intercom/comm in O.loc)
- comm.ai += O
-
- O << "You are playing the station's AI. The AI cannot move, but can interact with many objects while viewing them (through cameras)."
- O << "To look at other parts of the station, click on yourself to get a camera menu."
- O << "While observing through a camera, you can use most (networked) devices which you can see, such as computers, APCs, intercoms, doors, etc."
- O << "To use something, simply click on it."
- O << {"Use say ":b to speak to your cyborgs through binary."}
- if (!(ticker && ticker.mode && (O.mind in ticker.mode.malf_ai)))
- O.show_laws()
- O << "These laws may be changed by other players, or by you being the traitor."
-
- O.verbs += /mob/living/silicon/ai/proc/ai_call_shuttle
- O.verbs += /mob/living/silicon/ai/proc/show_laws_verb
- O.verbs += /mob/living/silicon/ai/proc/ai_camera_track
- O.verbs += /mob/living/silicon/ai/proc/ai_alerts
- O.verbs += /mob/living/silicon/ai/proc/ai_camera_list
- O.verbs += /mob/living/silicon/ai/proc/ai_statuschange
- O.verbs += /mob/living/silicon/ai/proc/ai_roster
-
- O.job = "AI"
-
- O.rename_self("ai",1)
- . = O
- qdel(src)
- return
-
-
-//human -> robot
-/mob/living/carbon/human/proc/Robotize(var/delete_items = 0)
- if (notransform)
- return
- for(var/obj/item/W in src)
- if(delete_items)
- qdel(W)
- else
- unEquip(W)
- regenerate_icons()
- notransform = 1
- canmove = 0
- icon = null
- invisibility = 101
- for(var/t in organs)
- qdel(t)
-
- var/mob/living/silicon/robot/O = new /mob/living/silicon/robot( loc )
-
- if (config.rename_cyborg)
- O.rename_self("cyborg", 1)
-
- // cyborgs produced by Robotize get an automatic power cell
- O.cell = new(O)
- O.cell.maxcharge = 7500
- O.cell.charge = 7500
-
-
- O.gender = gender
- O.invisibility = 0
-
-
- if(mind) //TODO
- mind.transfer_to(O)
- if(mind.special_role)
- O.mind.store_memory("In case you look at this after being borged, the objectives are only here until I find a way to make them not show up for you, as I can't simply delete them without screwing up round-end reporting. --NeoFite")
- else
- O.key = key
-
- O.loc = loc
- O.job = "Cyborg"
-
- O.mmi = new /obj/item/device/mmi(O)
- O.mmi.transfer_identity(src)//Does not transfer key/client.
-
- . = O
- qdel(src)
-
-//human -> alien
-/mob/living/carbon/human/proc/Alienize()
- if (notransform)
- return
- for(var/obj/item/W in src)
- unEquip(W)
- regenerate_icons()
- notransform = 1
- canmove = 0
- icon = null
- invisibility = 101
- for(var/t in organs)
- qdel(t)
-
- var/alien_caste = pick("Hunter","Sentinel","Drone")
- var/mob/living/carbon/alien/humanoid/new_xeno
- switch(alien_caste)
- if("Hunter")
- new_xeno = new /mob/living/carbon/alien/humanoid/hunter(loc)
- if("Sentinel")
- new_xeno = new /mob/living/carbon/alien/humanoid/sentinel(loc)
- if("Drone")
- new_xeno = new /mob/living/carbon/alien/humanoid/drone(loc)
-
- new_xeno.a_intent = "harm"
- new_xeno.key = key
-
- new_xeno << "You are now an alien."
- . = new_xeno
- qdel(src)
-
-/mob/living/carbon/human/proc/slimeize(reproduce as num)
- if (notransform)
- return
- for(var/obj/item/W in src)
- unEquip(W)
- regenerate_icons()
- notransform = 1
- canmove = 0
- icon = null
- invisibility = 101
- for(var/t in organs)
- qdel(t)
-
- var/mob/living/carbon/slime/new_slime
- if(reproduce)
- var/number = pick(14;2,3,4) //reproduce (has a small chance of producing 3 or 4 offspring)
- var/list/babies = list()
- for(var/i=1,i<=number,i++)
- var/mob/living/carbon/slime/M = new/mob/living/carbon/slime(loc)
- M.nutrition = round(nutrition/number)
- step_away(M,src)
- babies += M
- new_slime = pick(babies)
- else
- new_slime = new /mob/living/carbon/slime(loc)
- new_slime.a_intent = "harm"
- new_slime.key = key
-
- new_slime << "You are now a slime. Skreee!"
- . = new_slime
- qdel(src)
-
-/mob/living/carbon/human/proc/Blobize()
- if (notransform)
- return
- var/obj/effect/blob/core/new_blob = new /obj/effect/blob/core (loc)
- if(!client)
- for(var/mob/dead/observer/G in player_list)
- if(ckey == "@[G.ckey]")
- new_blob.create_overmind(G.client , 1)
- break
- else
- new_blob.create_overmind(src.client , 1)
- gib(src)
-
-
-
-/mob/living/carbon/human/proc/corgize()
- if (notransform)
- return
- for(var/obj/item/W in src)
- unEquip(W)
- regenerate_icons()
- notransform = 1
- canmove = 0
- icon = null
- invisibility = 101
- for(var/t in organs) //this really should not be necessary
- qdel(t)
-
- var/mob/living/simple_animal/corgi/new_corgi = new /mob/living/simple_animal/corgi (loc)
- new_corgi.a_intent = "harm"
- new_corgi.key = key
-
- new_corgi << "You are now a Corgi. Yap Yap!"
- . = new_corgi
- qdel(src)
-
-/mob/living/carbon/human/Animalize()
-
- var/list/mobtypes = typesof(/mob/living/simple_animal)
- var/mobpath = input("Which type of mob should [src] turn into?", "Choose a type") in mobtypes
-
- if(!safe_animal(mobpath))
- usr << "\red Sorry but this mob type is currently unavailable."
- return
-
- if(notransform)
- return
- for(var/obj/item/W in src)
- unEquip(W)
-
- regenerate_icons()
- notransform = 1
- canmove = 0
- icon = null
- invisibility = 101
-
- for(var/t in organs)
- qdel(t)
-
- var/mob/new_mob = new mobpath(src.loc)
-
- new_mob.key = key
- new_mob.a_intent = "harm"
-
-
- new_mob << "You suddenly feel more... animalistic."
- . = new_mob
- qdel(src)
-
-/mob/proc/Animalize()
-
- var/list/mobtypes = typesof(/mob/living/simple_animal)
- var/mobpath = input("Which type of mob should [src] turn into?", "Choose a type") in mobtypes
-
- if(!safe_animal(mobpath))
- usr << "\red Sorry but this mob type is currently unavailable."
- return
-
- var/mob/new_mob = new mobpath(src.loc)
-
- new_mob.key = key
- new_mob.a_intent = "harm"
- new_mob << "You feel more... animalistic"
-
- . = new_mob
- qdel(src)
-
-/* Certain mob types have problems and should not be allowed to be controlled by players.
- *
- * This proc is here to force coders to manually place their mob in this list, hopefully tested.
- * This also gives a place to explain -why- players shouldnt be turn into certain mobs and hopefully someone can fix them.
- */
-/mob/proc/safe_animal(var/MP)
-
-//Bad mobs! - Remember to add a comment explaining what's wrong with the mob
- if(!MP)
- return 0 //Sanity, this should never happen.
-
-// if(ispath(MP, /mob/living/simple_animal/space_worm)) //Goodbye Space Worms 2014
-// return 0 //Unfinished. Very buggy, they seem to just spawn additional space worms everywhere and eating your own tail results in new worms spawning.
-
- if(ispath(MP, /mob/living/simple_animal/construct/behemoth))
- return 0 //I think this may have been an unfinished WiP or something. These constructs should really have their own class simple_animal/construct/subtype
-
- if(ispath(MP, /mob/living/simple_animal/construct/armoured))
- return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype
-
- if(ispath(MP, /mob/living/simple_animal/construct/wraith))
- return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype
-
- if(ispath(MP, /mob/living/simple_animal/construct/builder))
- return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype
-
-//Good mobs!
- if(ispath(MP, /mob/living/simple_animal/cat))
- return 1
- if(ispath(MP, /mob/living/simple_animal/corgi))
- return 1
- if(ispath(MP, /mob/living/simple_animal/crab))
- return 1
- if(ispath(MP, /mob/living/simple_animal/hostile/carp))
- return 1
- if(ispath(MP, /mob/living/simple_animal/hostile/mushroom))
- return 1
- if(ispath(MP, /mob/living/simple_animal/shade))
- return 1
- if(ispath(MP, /mob/living/simple_animal/tomato))
- return 1
- if(ispath(MP, /mob/living/simple_animal/mouse))
- return 1 //It is impossible to pull up the player panel for mice (Fixed! - Nodrak)
- if(ispath(MP, /mob/living/simple_animal/hostile/bear))
- return 1 //Bears will auto-attack mobs, even if they're player controlled (Fixed! - Nodrak)
- if(ispath(MP, /mob/living/simple_animal/parrot))
- return 1 //Parrots are no longer unfinished! -Nodrak
-
- //Not in here? Must be untested!
- return 0
+/mob/living/carbon/proc/monkeyize(tr_flags = (TR_KEEPITEMS | TR_KEEPVIRUS | TR_DEFAULTMSG), newname = null)
+ if (notransform)
+ return
+ //Handle items on mob
+
+ //first implants
+ var/list/implants = list()
+ if (tr_flags & TR_KEEPIMPLANTS)
+ for(var/obj/item/weapon/implant/W in src)
+ implants += W
+
+ if(tr_flags & TR_KEEPITEMS)
+ for(var/obj/item/W in (src.contents-implants))
+ unEquip(W)
+
+ //Make mob invisible and spawn animation
+ regenerate_icons()
+ notransform = 1
+ canmove = 0
+ stunned = 1
+ icon = null
+ invisibility = 101
+ var/atom/movable/overlay/animation = new /atom/movable/overlay( loc )
+ animation.icon_state = "blank"
+ animation.icon = 'icons/mob/mob.dmi'
+ animation.master = src
+ flick("h2monkey", animation)
+ sleep(22)
+ //animation = null
+ var/mob/living/carbon/monkey/O = new /mob/living/carbon/monkey( loc )
+ qdel(animation)
+
+
+
+ // hash the original name?
+ if (tr_flags & TR_HASHNAME)
+ O.name = "monkey ([copytext(md5(real_name), 2, 6)])"
+ O.real_name = "monkey ([copytext(md5(real_name), 2, 6)])"
+ if (newname) //if there's a name as an argument, always take that one over the current name
+ O.name = newname
+ O.real_name = newname
+
+ //handle DNA and other attributes
+ O.dna = dna
+ dna = null
+ if (!(tr_flags & TR_KEEPSE))
+ O.dna.struc_enzymes = setblock(O.dna.struc_enzymes, RACEBLOCK, construct_block(BAD_MUTATION_DIFFICULTY,BAD_MUTATION_DIFFICULTY))
+ if(suiciding)
+ O.suiciding = suiciding
+ O.loc = loc
+ O.a_intent = "harm"
+
+ //keep viruses?
+ if (tr_flags & TR_KEEPVIRUS)
+ O.viruses = viruses
+ viruses = list()
+ for(var/datum/disease/D in O.viruses)
+ D.affected_mob = O
+
+ //keep damage?
+ if (tr_flags & TR_KEEPDAMAGE)
+ O.setToxLoss(getToxLoss())
+ O.adjustBruteLoss(getBruteLoss())
+ O.setOxyLoss(getOxyLoss())
+ O.adjustFireLoss(getFireLoss())
+
+ //re-add implants to new mob
+ for(var/obj/item/weapon/implant/I in implants)
+ I.loc = O
+ I.implanted = O
+
+ //transfer mind and delete old mob
+ if(mind)
+ mind.transfer_to(O)
+ if (tr_flags & TR_DEFAULTMSG)
+ O << "You are now a monkey."
+ updateappearance(O)
+ . = O
+ if ( !(tr_flags & TR_KEEPSRC) ) //flag should be used if monkeyize() is called inside another proc of src so that one does not crash
+ qdel(src)
+ return
+
+
+
+////////////////////////// Humanize //////////////////////////////
+//Could probably be merged with monkeyize but other transformations got their own procs, too
+
+/mob/living/carbon/proc/humanize(tr_flags = (TR_KEEPITEMS | TR_KEEPVIRUS | TR_DEFAULTMSG), newname = null)
+ if (notransform)
+ return
+ //Handle items on mob
+
+ //first implants
+ var/list/implants = list()
+ if (tr_flags & TR_KEEPIMPLANTS)
+ for(var/obj/item/weapon/implant/W in src)
+ implants += W
+
+ //now the rest
+ if (tr_flags & TR_KEEPITEMS)
+ for(var/obj/item/W in (src.contents-implants))
+ unEquip(W)
+ if (client)
+ client.screen -= W
+ if (W)
+ W.loc = loc
+ W.dropped(src)
+ W.layer = initial(W.layer)
+
+ // for(var/obj/item/W in src)
+ // unEquip(W)
+
+ //Make mob invisible and spawn animation
+ regenerate_icons()
+ notransform = 1
+ canmove = 0
+ stunned = 1
+ icon = null
+ invisibility = 101
+ var/atom/movable/overlay/animation = new( loc )
+ animation.icon_state = "blank"
+ animation.icon = 'icons/mob/mob.dmi'
+ animation.master = src
+ flick("monkey2h", animation)
+ sleep(22)
+ var/mob/living/carbon/human/O = new( loc )
+ for(var/obj/item/C in O.loc)
+ O.equip_to_appropriate_slot(C)
+ qdel(animation)
+
+
+ O.gender = (deconstruct_block(getblock(dna.uni_identity, DNA_GENDER_BLOCK), 2)-1) ? FEMALE : MALE
+ O.dna = dna
+ dna = null
+ if (newname) //if there's a name as an argument, always take that one over the current name
+ O.real_name = newname
+ else
+ if ( !(cmptext ("monkey",copytext(O.dna.real_name,1,7)) ) )
+ O.real_name = O.dna.real_name
+ else
+ O.real_name = random_name(O.gender)
+ O.name = O.real_name
+
+ if (!(tr_flags & TR_KEEPSE))
+ O.dna.struc_enzymes = setblock(O.dna.struc_enzymes, RACEBLOCK, construct_block(1,BAD_MUTATION_DIFFICULTY))
+
+ if(suiciding)
+ O.suiciding = suiciding
+
+ O.loc = loc
+
+ //keep viruses?
+ if (tr_flags & TR_KEEPVIRUS)
+ O.viruses = viruses
+ viruses = list()
+ for(var/datum/disease/D in O.viruses)
+ D.affected_mob = O
+
+ //keep damage?
+ if (tr_flags & TR_KEEPDAMAGE)
+ O.setToxLoss(getToxLoss())
+ O.adjustBruteLoss(getBruteLoss())
+ O.setOxyLoss(getOxyLoss())
+ O.adjustFireLoss(getFireLoss())
+
+ //re-add implants to new mob
+ for(var/obj/item/weapon/implant/I in implants)
+ I.loc = O
+ I.implanted = O
+
+ if(mind)
+ mind.transfer_to(O)
+ O.a_intent = "help"
+ if (tr_flags & TR_DEFAULTMSG)
+ O << "You are now a human."
+ updateappearance(O)
+ . = O
+ if ( !(tr_flags & TR_KEEPSRC) ) //don't delete src yet if it's needed to finish calling proc
+ qdel(src)
+ return
+
+/mob/new_player/AIize()
+ spawning = 1
+ return ..()
+
+/mob/living/carbon/human/AIize()
+ if (notransform)
+ return
+ for(var/t in organs)
+ qdel(t)
+
+ return ..()
+
+/mob/living/carbon/AIize()
+ if (notransform)
+ return
+ for(var/obj/item/W in src)
+ unEquip(W)
+ regenerate_icons()
+ notransform = 1
+ canmove = 0
+ icon = null
+ invisibility = 101
+ return ..()
+
+/mob/proc/AIize()
+ if(client)
+ src << sound(null, repeat = 0, wait = 0, volume = 85, channel = 1) // stop the jams for AIs
+ var/mob/living/silicon/ai/O = new (loc,,,1)//No MMI but safety is in effect.
+ O.invisibility = 0
+ O.aiRestorePowerRoutine = 0
+
+ if(mind)
+ mind.transfer_to(O)
+ else
+ O.key = key
+
+ var/obj/loc_landmark
+ for(var/obj/effect/landmark/start/sloc in landmarks_list)
+ if (sloc.name != "AI")
+ continue
+ if (locate(/mob/living) in sloc.loc)
+ continue
+ loc_landmark = sloc
+ if (!loc_landmark)
+ for(var/obj/effect/landmark/tripai in landmarks_list)
+ if (tripai.name == "tripai")
+ if(locate(/mob/living) in tripai.loc)
+ continue
+ loc_landmark = tripai
+ if (!loc_landmark)
+ O << "Oh god sorry we can't find an unoccupied AI spawn location, so we're spawning you on top of someone."
+ for(var/obj/effect/landmark/start/sloc in landmarks_list)
+ if (sloc.name == "AI")
+ loc_landmark = sloc
+
+ O.loc = loc_landmark.loc
+ for (var/obj/item/device/radio/intercom/comm in O.loc)
+ comm.ai += O
+
+ O << "You are playing the station's AI. The AI cannot move, but can interact with many objects while viewing them (through cameras)."
+ O << "To look at other parts of the station, click on yourself to get a camera menu."
+ O << "While observing through a camera, you can use most (networked) devices which you can see, such as computers, APCs, intercoms, doors, etc."
+ O << "To use something, simply click on it."
+ O << {"Use say ":b to speak to your cyborgs through binary."}
+ if (!(ticker && ticker.mode && (O.mind in ticker.mode.malf_ai)))
+ O.show_laws()
+ O << "These laws may be changed by other players, or by you being the traitor."
+
+ O.verbs += /mob/living/silicon/ai/proc/ai_call_shuttle
+ O.verbs += /mob/living/silicon/ai/proc/show_laws_verb
+ O.verbs += /mob/living/silicon/ai/proc/ai_camera_track
+ O.verbs += /mob/living/silicon/ai/proc/ai_alerts
+ O.verbs += /mob/living/silicon/ai/proc/ai_camera_list
+ O.verbs += /mob/living/silicon/ai/proc/ai_statuschange
+ O.verbs += /mob/living/silicon/ai/proc/ai_roster
+
+ O.job = "AI"
+
+ O.rename_self("ai",1)
+ . = O
+ qdel(src)
+ return
+
+
+//human -> robot
+/mob/living/carbon/human/proc/Robotize(var/delete_items = 0)
+ if (notransform)
+ return
+ for(var/obj/item/W in src)
+ if(delete_items)
+ qdel(W)
+ else
+ unEquip(W)
+ regenerate_icons()
+ notransform = 1
+ canmove = 0
+ icon = null
+ invisibility = 101
+ for(var/t in organs)
+ qdel(t)
+
+ var/mob/living/silicon/robot/O = new /mob/living/silicon/robot( loc )
+
+ if (config.rename_cyborg)
+ O.rename_self("cyborg", 1)
+
+ // cyborgs produced by Robotize get an automatic power cell
+ O.cell = new(O)
+ O.cell.maxcharge = 7500
+ O.cell.charge = 7500
+
+
+ O.gender = gender
+ O.invisibility = 0
+
+
+ if(mind) //TODO
+ mind.transfer_to(O)
+ if(mind.special_role)
+ O.mind.store_memory("In case you look at this after being borged, the objectives are only here until I find a way to make them not show up for you, as I can't simply delete them without screwing up round-end reporting. --NeoFite")
+ else
+ O.key = key
+
+ O.loc = loc
+ O.job = "Cyborg"
+
+ O.mmi = new /obj/item/device/mmi(O)
+ O.mmi.transfer_identity(src)//Does not transfer key/client.
+
+ . = O
+ qdel(src)
+
+//human -> alien
+/mob/living/carbon/human/proc/Alienize()
+ if (notransform)
+ return
+ for(var/obj/item/W in src)
+ unEquip(W)
+ regenerate_icons()
+ notransform = 1
+ canmove = 0
+ icon = null
+ invisibility = 101
+ for(var/t in organs)
+ qdel(t)
+
+ var/alien_caste = pick("Hunter","Sentinel","Drone")
+ var/mob/living/carbon/alien/humanoid/new_xeno
+ switch(alien_caste)
+ if("Hunter")
+ new_xeno = new /mob/living/carbon/alien/humanoid/hunter(loc)
+ if("Sentinel")
+ new_xeno = new /mob/living/carbon/alien/humanoid/sentinel(loc)
+ if("Drone")
+ new_xeno = new /mob/living/carbon/alien/humanoid/drone(loc)
+
+ new_xeno.a_intent = "harm"
+ new_xeno.key = key
+
+ new_xeno << "You are now an alien."
+ . = new_xeno
+ qdel(src)
+
+/mob/living/carbon/human/proc/slimeize(reproduce as num)
+ if (notransform)
+ return
+ for(var/obj/item/W in src)
+ unEquip(W)
+ regenerate_icons()
+ notransform = 1
+ canmove = 0
+ icon = null
+ invisibility = 101
+ for(var/t in organs)
+ qdel(t)
+
+ var/mob/living/carbon/slime/new_slime
+ if(reproduce)
+ var/number = pick(14;2,3,4) //reproduce (has a small chance of producing 3 or 4 offspring)
+ var/list/babies = list()
+ for(var/i=1,i<=number,i++)
+ var/mob/living/carbon/slime/M = new/mob/living/carbon/slime(loc)
+ M.nutrition = round(nutrition/number)
+ step_away(M,src)
+ babies += M
+ new_slime = pick(babies)
+ else
+ new_slime = new /mob/living/carbon/slime(loc)
+ new_slime.a_intent = "harm"
+ new_slime.key = key
+
+ new_slime << "You are now a slime. Skreee!"
+ . = new_slime
+ qdel(src)
+
+/mob/living/carbon/human/proc/Blobize()
+ if (notransform)
+ return
+ var/obj/effect/blob/core/new_blob = new /obj/effect/blob/core (loc)
+ if(!client)
+ for(var/mob/dead/observer/G in player_list)
+ if(ckey == "@[G.ckey]")
+ new_blob.create_overmind(G.client , 1)
+ break
+ else
+ new_blob.create_overmind(src.client , 1)
+ gib(src)
+
+
+
+/mob/living/carbon/human/proc/corgize()
+ if (notransform)
+ return
+ for(var/obj/item/W in src)
+ unEquip(W)
+ regenerate_icons()
+ notransform = 1
+ canmove = 0
+ icon = null
+ invisibility = 101
+ for(var/t in organs) //this really should not be necessary
+ qdel(t)
+
+ var/mob/living/simple_animal/corgi/new_corgi = new /mob/living/simple_animal/corgi (loc)
+ new_corgi.a_intent = "harm"
+ new_corgi.key = key
+
+ new_corgi << "You are now a Corgi. Yap Yap!"
+ . = new_corgi
+ qdel(src)
+
+/mob/living/carbon/human/Animalize()
+
+ var/list/mobtypes = typesof(/mob/living/simple_animal)
+ var/mobpath = input("Which type of mob should [src] turn into?", "Choose a type") in mobtypes
+
+ if(!safe_animal(mobpath))
+ usr << "\red Sorry but this mob type is currently unavailable."
+ return
+
+ if(notransform)
+ return
+ for(var/obj/item/W in src)
+ unEquip(W)
+
+ regenerate_icons()
+ notransform = 1
+ canmove = 0
+ icon = null
+ invisibility = 101
+
+ for(var/t in organs)
+ qdel(t)
+
+ var/mob/new_mob = new mobpath(src.loc)
+
+ new_mob.key = key
+ new_mob.a_intent = "harm"
+
+
+ new_mob << "You suddenly feel more... animalistic."
+ . = new_mob
+ qdel(src)
+
+/mob/proc/Animalize()
+
+ var/list/mobtypes = typesof(/mob/living/simple_animal)
+ var/mobpath = input("Which type of mob should [src] turn into?", "Choose a type") in mobtypes
+
+ if(!safe_animal(mobpath))
+ usr << "\red Sorry but this mob type is currently unavailable."
+ return
+
+ var/mob/new_mob = new mobpath(src.loc)
+
+ new_mob.key = key
+ new_mob.a_intent = "harm"
+ new_mob << "You feel more... animalistic"
+
+ . = new_mob
+ qdel(src)
+
+/* Certain mob types have problems and should not be allowed to be controlled by players.
+ *
+ * This proc is here to force coders to manually place their mob in this list, hopefully tested.
+ * This also gives a place to explain -why- players shouldnt be turn into certain mobs and hopefully someone can fix them.
+ */
+/mob/proc/safe_animal(var/MP)
+
+//Bad mobs! - Remember to add a comment explaining what's wrong with the mob
+ if(!MP)
+ return 0 //Sanity, this should never happen.
+
+// if(ispath(MP, /mob/living/simple_animal/space_worm)) //Goodbye Space Worms 2014
+// return 0 //Unfinished. Very buggy, they seem to just spawn additional space worms everywhere and eating your own tail results in new worms spawning.
+
+ if(ispath(MP, /mob/living/simple_animal/construct/behemoth))
+ return 0 //I think this may have been an unfinished WiP or something. These constructs should really have their own class simple_animal/construct/subtype
+
+ if(ispath(MP, /mob/living/simple_animal/construct/armoured))
+ return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype
+
+ if(ispath(MP, /mob/living/simple_animal/construct/wraith))
+ return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype
+
+ if(ispath(MP, /mob/living/simple_animal/construct/builder))
+ return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype
+
+//Good mobs!
+ if(ispath(MP, /mob/living/simple_animal/cat))
+ return 1
+ if(ispath(MP, /mob/living/simple_animal/corgi))
+ return 1
+ if(ispath(MP, /mob/living/simple_animal/crab))
+ return 1
+ if(ispath(MP, /mob/living/simple_animal/hostile/carp))
+ return 1
+ if(ispath(MP, /mob/living/simple_animal/hostile/mushroom))
+ return 1
+ if(ispath(MP, /mob/living/simple_animal/shade))
+ return 1
+ if(ispath(MP, /mob/living/simple_animal/tomato))
+ return 1
+ if(ispath(MP, /mob/living/simple_animal/mouse))
+ return 1 //It is impossible to pull up the player panel for mice (Fixed! - Nodrak)
+ if(ispath(MP, /mob/living/simple_animal/hostile/bear))
+ return 1 //Bears will auto-attack mobs, even if they're player controlled (Fixed! - Nodrak)
+ if(ispath(MP, /mob/living/simple_animal/parrot))
+ return 1 //Parrots are no longer unfinished! -Nodrak
+
+ //Not in here? Must be untested!
+ return 0
diff --git a/code/modules/nano/JSON Reader.dm b/code/modules/nano/JSON Reader.dm
index 12edf1dd5c0..638ff937a3f 100644
--- a/code/modules/nano/JSON Reader.dm
+++ b/code/modules/nano/JSON Reader.dm
@@ -1,205 +1,205 @@
-json_token
- var
- value
- New(v)
- src.value = v
- text
- number
- word
- symbol
- eof
-
-json_reader
- var
- list
- string = list("'", "\"")
- symbols = list("{", "}", "\[", "]", ":", "\"", "'", ",")
- sequences = list("b" = 8, "t" = 9, "n" = 10, "f" = 12, "r" = 13)
- tokens
- json
- i = 1
-
-
- proc
- // scanner
- ScanJson(json)
- src.json = json
- . = new/list()
- src.i = 1
- while(src.i <= lentext(json))
- var/char = get_char()
- if(is_whitespace(char))
- i++
- continue
- if(string.Find(char))
- . += read_string(char)
- else if(symbols.Find(char))
- . += new/json_token/symbol(char)
- else if(is_digit(char))
- . += read_number()
- else
- . += read_word()
- i++
- . += new/json_token/eof()
-
- read_word()
- var/val = ""
- while(i <= lentext(json))
- var/char = get_char()
- if(is_whitespace(char) || symbols.Find(char))
- i-- // let scanner handle this character
- return new/json_token/word(val)
- val += char
- i++
-
- read_string(delim)
- var
- escape = FALSE
- val = ""
- while(++i <= lentext(json))
- var/char = get_char()
- if(escape)
- switch(char)
- if("\\", "'", "\"", "/", "u")
- val += char
- else
- // TODO: support octal, hex, unicode sequences
- ASSERT(sequences.Find(char))
- val += ascii2text(sequences[char])
- else
- if(char == delim)
- return new/json_token/text(val)
- else if(char == "\\")
- escape = TRUE
- else
- val += char
- CRASH("Unterminated string.")
-
- read_number()
- var/val = ""
- var/char = get_char()
- while(is_digit(char) || char == "." || lowertext(char) == "e")
- val += char
- i++
- char = get_char()
- i-- // allow scanner to read the first non-number character
- return new/json_token/number(text2num(val))
-
- check_char()
- ASSERT(args.Find(get_char()))
-
- get_char()
- return copytext(json, i, i+1)
-
- is_whitespace(char)
- return char == " " || char == "\t" || char == "\n" || text2ascii(char) == 13
-
- is_digit(char)
- var/c = text2ascii(char)
- return 48 <= c && c <= 57 || char == "+" || char == "-"
-
-
- // parser
- ReadObject(list/tokens)
- src.tokens = tokens
- . = new/list()
- i = 1
- read_token("{", /json_token/symbol)
- while(i <= tokens.len)
- var/json_token/K = get_token()
- check_type(/json_token/word, /json_token/text)
- next_token()
- read_token(":", /json_token/symbol)
-
- .[K.value] = read_value()
-
- var/json_token/S = get_token()
- check_type(/json_token/symbol)
- switch(S.value)
- if(",")
- next_token()
- continue
- if("}")
- next_token()
- return
- else
- die()
-
- get_token()
- return tokens[i]
-
- next_token()
- return tokens[++i]
-
- read_token(val, type)
- var/json_token/T = get_token()
- if(!(T.value == val && istype(T, type)))
- CRASH("Expected '[val]', found '[T.value]'.")
- next_token()
- return T
-
- check_type(...)
- var/json_token/T = get_token()
- for(var/type in args)
- if(istype(T, type))
- return
- CRASH("Bad token type: [T.type].")
-
- check_value(...)
- var/json_token/T = get_token()
- ASSERT(args.Find(T.value))
-
- read_key()
- var/char = get_char()
- if(char == "\"" || char == "'")
- return read_string(char)
-
- read_value()
- var/json_token/T = get_token()
- switch(T.type)
- if(/json_token/text, /json_token/number)
- next_token()
- return T.value
- if(/json_token/word)
- next_token()
- switch(T.value)
- if("true")
- return TRUE
- if("false")
- return FALSE
- if("null")
- return null
- if(/json_token/symbol)
- switch(T.value)
- if("\[")
- return read_array()
- if("{")
- return ReadObject(tokens.Copy(i))
- die()
-
- read_array()
- read_token("\[", /json_token/symbol)
- . = new/list()
- var/list/L = .
- while(i <= tokens.len)
- // Avoid using Add() or += in case a list is returned.
- L.len++
- L[L.len] = read_value()
- var/json_token/T = get_token()
- check_type(/json_token/symbol)
- switch(T.value)
- if(",")
- next_token()
- continue
- if("]")
- next_token()
- return
- else
- die()
- next_token()
- CRASH("Unterminated array.")
-
-
- die(json_token/T)
- if(!T) T = get_token()
+json_token
+ var
+ value
+ New(v)
+ src.value = v
+ text
+ number
+ word
+ symbol
+ eof
+
+json_reader
+ var
+ list
+ string = list("'", "\"")
+ symbols = list("{", "}", "\[", "]", ":", "\"", "'", ",")
+ sequences = list("b" = 8, "t" = 9, "n" = 10, "f" = 12, "r" = 13)
+ tokens
+ json
+ i = 1
+
+
+ proc
+ // scanner
+ ScanJson(json)
+ src.json = json
+ . = new/list()
+ src.i = 1
+ while(src.i <= lentext(json))
+ var/char = get_char()
+ if(is_whitespace(char))
+ i++
+ continue
+ if(string.Find(char))
+ . += read_string(char)
+ else if(symbols.Find(char))
+ . += new/json_token/symbol(char)
+ else if(is_digit(char))
+ . += read_number()
+ else
+ . += read_word()
+ i++
+ . += new/json_token/eof()
+
+ read_word()
+ var/val = ""
+ while(i <= lentext(json))
+ var/char = get_char()
+ if(is_whitespace(char) || symbols.Find(char))
+ i-- // let scanner handle this character
+ return new/json_token/word(val)
+ val += char
+ i++
+
+ read_string(delim)
+ var
+ escape = FALSE
+ val = ""
+ while(++i <= lentext(json))
+ var/char = get_char()
+ if(escape)
+ switch(char)
+ if("\\", "'", "\"", "/", "u")
+ val += char
+ else
+ // TODO: support octal, hex, unicode sequences
+ ASSERT(sequences.Find(char))
+ val += ascii2text(sequences[char])
+ else
+ if(char == delim)
+ return new/json_token/text(val)
+ else if(char == "\\")
+ escape = TRUE
+ else
+ val += char
+ CRASH("Unterminated string.")
+
+ read_number()
+ var/val = ""
+ var/char = get_char()
+ while(is_digit(char) || char == "." || lowertext(char) == "e")
+ val += char
+ i++
+ char = get_char()
+ i-- // allow scanner to read the first non-number character
+ return new/json_token/number(text2num(val))
+
+ check_char()
+ ASSERT(args.Find(get_char()))
+
+ get_char()
+ return copytext(json, i, i+1)
+
+ is_whitespace(char)
+ return char == " " || char == "\t" || char == "\n" || text2ascii(char) == 13
+
+ is_digit(char)
+ var/c = text2ascii(char)
+ return 48 <= c && c <= 57 || char == "+" || char == "-"
+
+
+ // parser
+ ReadObject(list/tokens)
+ src.tokens = tokens
+ . = new/list()
+ i = 1
+ read_token("{", /json_token/symbol)
+ while(i <= tokens.len)
+ var/json_token/K = get_token()
+ check_type(/json_token/word, /json_token/text)
+ next_token()
+ read_token(":", /json_token/symbol)
+
+ .[K.value] = read_value()
+
+ var/json_token/S = get_token()
+ check_type(/json_token/symbol)
+ switch(S.value)
+ if(",")
+ next_token()
+ continue
+ if("}")
+ next_token()
+ return
+ else
+ die()
+
+ get_token()
+ return tokens[i]
+
+ next_token()
+ return tokens[++i]
+
+ read_token(val, type)
+ var/json_token/T = get_token()
+ if(!(T.value == val && istype(T, type)))
+ CRASH("Expected '[val]', found '[T.value]'.")
+ next_token()
+ return T
+
+ check_type(...)
+ var/json_token/T = get_token()
+ for(var/type in args)
+ if(istype(T, type))
+ return
+ CRASH("Bad token type: [T.type].")
+
+ check_value(...)
+ var/json_token/T = get_token()
+ ASSERT(args.Find(T.value))
+
+ read_key()
+ var/char = get_char()
+ if(char == "\"" || char == "'")
+ return read_string(char)
+
+ read_value()
+ var/json_token/T = get_token()
+ switch(T.type)
+ if(/json_token/text, /json_token/number)
+ next_token()
+ return T.value
+ if(/json_token/word)
+ next_token()
+ switch(T.value)
+ if("true")
+ return TRUE
+ if("false")
+ return FALSE
+ if("null")
+ return null
+ if(/json_token/symbol)
+ switch(T.value)
+ if("\[")
+ return read_array()
+ if("{")
+ return ReadObject(tokens.Copy(i))
+ die()
+
+ read_array()
+ read_token("\[", /json_token/symbol)
+ . = new/list()
+ var/list/L = .
+ while(i <= tokens.len)
+ // Avoid using Add() or += in case a list is returned.
+ L.len++
+ L[L.len] = read_value()
+ var/json_token/T = get_token()
+ check_type(/json_token/symbol)
+ switch(T.value)
+ if(",")
+ next_token()
+ continue
+ if("]")
+ next_token()
+ return
+ else
+ die()
+ next_token()
+ CRASH("Unterminated array.")
+
+
+ die(json_token/T)
+ if(!T) T = get_token()
CRASH("Unexpected token: [T.value].")
\ No newline at end of file
diff --git a/code/modules/nano/JSON Writer.dm b/code/modules/nano/JSON Writer.dm
index 3cd3520f177..4398e5b8970 100644
--- a/code/modules/nano/JSON Writer.dm
+++ b/code/modules/nano/JSON Writer.dm
@@ -1,59 +1,59 @@
-
-json_writer
- proc
- WriteObject(list/L)
- . = "{"
- var/i = 1
- for(var/k in L)
- var/val = L[k]
- . += {"\"[k]\":[write(val)]"}
- if(i++ < L.len)
- . += ","
- .+= "}"
-
- write(val)
- if(isnum(val))
- return num2text(val, 100)
- else if(isnull(val))
- return "null"
- else if(istype(val, /list))
- if(is_associative(val))
- return WriteObject(val)
- else
- return write_array(val)
- else
- . += write_string("[val]")
-
- write_array(list/L)
- . = "\["
- for(var/i = 1 to L.len)
- . += write(L[i])
- if(i < L.len)
- . += ","
- . += "]"
-
- write_string(txt)
- var/static/list/json_escape = list("\\", "\"", "'", "\n")
- for(var/targ in json_escape)
- var/start = 1
- while(start <= lentext(txt))
- var/i = findtext(txt, targ, start)
- if(!i)
- break
- if(targ == "\n")
- txt = copytext(txt, 1, i) + "\\n" + copytext(txt, i+2)
- start = i + 1 // 1 character added
- if(targ == "'")
- txt = copytext(txt, 1, i) + "`" + copytext(txt, i+1) // apostrophies fuck shit up...
- start = i + 1 // 1 character added
- else
- txt = copytext(txt, 1, i) + "\\" + copytext(txt, i)
- start = i + 2 // 2 characters added
-
- return {""[txt]""}
-
- is_associative(list/L)
- for(var/key in L)
- // if the key is a list that means it's actually an array of lists (stupid Byond...)
- if(!isnum(key) && !istype(key, /list))
- return TRUE
+
+json_writer
+ proc
+ WriteObject(list/L)
+ . = "{"
+ var/i = 1
+ for(var/k in L)
+ var/val = L[k]
+ . += {"\"[k]\":[write(val)]"}
+ if(i++ < L.len)
+ . += ","
+ .+= "}"
+
+ write(val)
+ if(isnum(val))
+ return num2text(val, 100)
+ else if(isnull(val))
+ return "null"
+ else if(istype(val, /list))
+ if(is_associative(val))
+ return WriteObject(val)
+ else
+ return write_array(val)
+ else
+ . += write_string("[val]")
+
+ write_array(list/L)
+ . = "\["
+ for(var/i = 1 to L.len)
+ . += write(L[i])
+ if(i < L.len)
+ . += ","
+ . += "]"
+
+ write_string(txt)
+ var/static/list/json_escape = list("\\", "\"", "'", "\n")
+ for(var/targ in json_escape)
+ var/start = 1
+ while(start <= lentext(txt))
+ var/i = findtext(txt, targ, start)
+ if(!i)
+ break
+ if(targ == "\n")
+ txt = copytext(txt, 1, i) + "\\n" + copytext(txt, i+2)
+ start = i + 1 // 1 character added
+ if(targ == "'")
+ txt = copytext(txt, 1, i) + "`" + copytext(txt, i+1) // apostrophies fuck shit up...
+ start = i + 1 // 1 character added
+ else
+ txt = copytext(txt, 1, i) + "\\" + copytext(txt, i)
+ start = i + 2 // 2 characters added
+
+ return {""[txt]""}
+
+ is_associative(list/L)
+ for(var/key in L)
+ // if the key is a list that means it's actually an array of lists (stupid Byond...)
+ if(!isnum(key) && !istype(key, /list))
+ return TRUE
diff --git a/code/modules/nano/_JSON.dm b/code/modules/nano/_JSON.dm
index 5692e643baa..ee8b9bdf499 100644
--- a/code/modules/nano/_JSON.dm
+++ b/code/modules/nano/_JSON.dm
@@ -1,12 +1,12 @@
-/*
-n_Json v11.3.21
-*/
-
-proc
- json2list(json)
- var/static/json_reader/_jsonr = new()
- return _jsonr.ReadObject(_jsonr.ScanJson(json))
-
- list2json(list/L)
- var/static/json_writer/_jsonw = new()
- return _jsonw.WriteObject(L)
+/*
+n_Json v11.3.21
+*/
+
+proc
+ json2list(json)
+ var/static/json_reader/_jsonr = new()
+ return _jsonr.ReadObject(_jsonr.ScanJson(json))
+
+ list2json(list/L)
+ var/static/json_writer/_jsonw = new()
+ return _jsonw.WriteObject(L)
diff --git a/code/modules/nano/nanoexternal.dm b/code/modules/nano/nanoexternal.dm
index 2331debd9be..a6b2485f665 100644
--- a/code/modules/nano/nanoexternal.dm
+++ b/code/modules/nano/nanoexternal.dm
@@ -1,43 +1,43 @@
- // This file contains all Nano procs/definitions for external classes/objects
-
- /**
- * Called when a Nano UI window is closed
- * This is how Nano handles closed windows
- * It must be a verb so that it can be called using winset
- *
- * @return nothing
- */
-/client/verb/nanoclose(var/uiref as text)
- set hidden = 1 // hide this verb from the user's panel
- set name = "nanoclose"
-
- var/datum/nanoui/ui = locate(uiref)
-
- if (istype(ui))
- ui.close()
-
- if(ui.ref)
- var/href = "close=1"
- src.Topic(href, params2list(href), ui.ref) // this will direct to the atom's Topic() proc via client.Topic()
- else if (ui.on_close_logic)
- // no atomref specified (or not found)
- // so just reset the user mob's machine var
- if(src && src.mob)
- src.mob.unset_machine()
-
- /**
- * The ui_interact proc is used to open and update Nano UIs
- * If ui_interact is not used then the UI will not update correctly
- * ui_interact is currently defined for /atom/movable
- *
- * @param user /mob The mob who is interacting with this ui
- * @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
- * @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
- *
- * @return nothing
- */
-/atom/movable/proc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
- return
-
-// Used by the Nano UI Manager (/datum/nanomanager) to track UIs opened by this mob
-/mob/var/list/open_uis = list()
+ // This file contains all Nano procs/definitions for external classes/objects
+
+ /**
+ * Called when a Nano UI window is closed
+ * This is how Nano handles closed windows
+ * It must be a verb so that it can be called using winset
+ *
+ * @return nothing
+ */
+/client/verb/nanoclose(var/uiref as text)
+ set hidden = 1 // hide this verb from the user's panel
+ set name = "nanoclose"
+
+ var/datum/nanoui/ui = locate(uiref)
+
+ if (istype(ui))
+ ui.close()
+
+ if(ui.ref)
+ var/href = "close=1"
+ src.Topic(href, params2list(href), ui.ref) // this will direct to the atom's Topic() proc via client.Topic()
+ else if (ui.on_close_logic)
+ // no atomref specified (or not found)
+ // so just reset the user mob's machine var
+ if(src && src.mob)
+ src.mob.unset_machine()
+
+ /**
+ * The ui_interact proc is used to open and update Nano UIs
+ * If ui_interact is not used then the UI will not update correctly
+ * ui_interact is currently defined for /atom/movable
+ *
+ * @param user /mob The mob who is interacting with this ui
+ * @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
+ * @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
+ *
+ * @return nothing
+ */
+/atom/movable/proc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
+ return
+
+// Used by the Nano UI Manager (/datum/nanomanager) to track UIs opened by this mob
+/mob/var/list/open_uis = list()
diff --git a/code/modules/nano/nanomanager.dm b/code/modules/nano/nanomanager.dm
index b7b45060bb7..9b8be6ce99e 100644
--- a/code/modules/nano/nanomanager.dm
+++ b/code/modules/nano/nanomanager.dm
@@ -1,200 +1,200 @@
-// This is the window/UI manager for Nano UI
-// There should only ever be one (global) instance of nanomanger
-/datum/nanomanager
- // a list of current open /nanoui UIs, grouped by src_object and ui_key
- var/open_uis[0]
- // a list of current open /nanoui UIs, not grouped, for use in processing
- var/list/processing_uis = list()
-
- /**
- * Create a new nanomanager instance.
- *
- * @return /nanomanager new nanomanager object
- */
-/datum/nanomanager/New()
- return
-
- /**
- * Get an open /nanoui ui for the current user, src_object and ui_key and try to update it with data
- *
- * @param user /mob The mob who opened/owns the ui
- * @param src_object /obj|/mob The obj or mob which the ui belongs to
- * @param ui_key string A string key used for the ui
- * @param ui /datum/nanoui An existing instance of the ui (can be null)
- * @param data list The data to be passed to the ui, if it exists
- *
- * @return /nanoui Returns the found ui, for null if none exists
- */
-/datum/nanomanager/proc/try_update_ui(var/mob/user, src_object, ui_key, var/datum/nanoui/ui, data)
- if (isnull(ui)) // no ui has been passed, so we'll search for one
- {
- ui = get_open_ui(user, src_object, ui_key)
- }
- if (!isnull(ui))
- // The UI is already open so push the data to it
- ui.push_data(data)
- return ui
-
- return null
-
- /**
- * Get an open /nanoui ui for the current user, src_object and ui_key
- *
- * @param user /mob The mob who opened/owns the ui
- * @param src_object /obj|/mob The obj or mob which the ui belongs to
- * @param ui_key string A string key used for the ui
- *
- * @return /nanoui Returns the found ui, or null if none exists
- */
-/datum/nanomanager/proc/get_open_ui(var/mob/user, src_object, ui_key)
- var/src_object_key = "\ref[src_object]"
- if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
- return null
- else if (isnull(open_uis[src_object_key][ui_key]) || !istype(open_uis[src_object_key][ui_key], /list))
- return null
-
- for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key])
- if (ui.user == user)
- return ui
-
- return null
-
- /**
- * Update all /nanoui uis attached to src_object
- *
- * @param src_object /obj|/mob The obj or mob which the uis are attached to
- *
- * @return int The number of uis updated
- */
-/datum/nanomanager/proc/update_uis(src_object)
- var/src_object_key = "\ref[src_object]"
- if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
- return 0
-
- var/update_count = 0
- for (var/ui_key in open_uis[src_object_key])
- for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key])
- if(ui && ui.src_object && ui.user)
- ui.process(1)
- update_count++
- return update_count
-
- /**
- * Update /nanoui uis belonging to user
- *
- * @param user /mob The mob who owns the uis
- * @param src_object /obj|/mob If src_object is provided, only update uis which are attached to src_object (optional)
- * @param ui_key string If ui_key is provided, only update uis with a matching ui_key (optional)
- *
- * @return int The number of uis updated
- */
-/datum/nanomanager/proc/update_user_uis(var/mob/user, src_object = null, ui_key = null)
- if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0)
- return 0 // has no open uis
-
- var/update_count = 0
- for (var/datum/nanoui/ui in user.open_uis)
- if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
- ui.process(1)
- update_count++
-
- return update_count
-
- /**
- * Close /nanoui uis belonging to user
- *
- * @param user /mob The mob who owns the uis
- * @param src_object /obj|/mob If src_object is provided, only close uis which are attached to src_object (optional)
- * @param ui_key string If ui_key is provided, only close uis with a matching ui_key (optional)
- *
- * @return int The number of uis closed
- */
-/datum/nanomanager/proc/close_user_uis(var/mob/user, src_object = null, ui_key = null)
- if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0)
- return 0 // has no open uis
-
- var/close_count = 0
- for (var/datum/nanoui/ui in user.open_uis)
- if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
- ui.close()
- close_count++
-
- return close_count
-
- /**
- * Add a /nanoui ui to the list of open uis
- * This is called by the /nanoui open() proc
- *
- * @param ui /nanoui The ui to add
- *
- * @return nothing
- */
-/datum/nanomanager/proc/ui_opened(var/datum/nanoui/ui)
- var/src_object_key = "\ref[ui.src_object]"
- if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
- open_uis[src_object_key] = list(ui.ui_key = list())
- else if (isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list))
- open_uis[src_object_key][ui.ui_key] = list();
-
- ui.user.open_uis.Add(ui)
- var/list/uis = open_uis[src_object_key][ui.ui_key]
- uis.Add(ui)
- processing_uis.Add(ui)
-
- /**
- * Remove a /nanoui ui from the list of open uis
- * This is called by the /nanoui close() proc
- *
- * @param ui /nanoui The ui to remove
- *
- * @return int 0 if no ui was removed, 1 if removed successfully
- */
-/datum/nanomanager/proc/ui_closed(var/datum/nanoui/ui)
- var/src_object_key = "\ref[ui.src_object]"
- if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
- return 0 // wasn't open
- else if (isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list))
- return 0 // wasn't open
-
- processing_uis.Remove(ui)
- ui.user.open_uis.Remove(ui)
- var/list/uis = open_uis[src_object_key][ui.ui_key]
- return uis.Remove(ui)
-
- /**
- * This is called on user logout
- * Closes/clears all uis attached to the user's /mob
- *
- * @param user /mob The user's mob
- *
- * @return nothing
- */
-
-//
-/datum/nanomanager/proc/user_logout(var/mob/user)
- return close_user_uis(user)
-
- /**
- * This is called when a player transfers from one mob to another
- * Transfers all open UIs to the new mob
- *
- * @param oldMob /mob The user's old mob
- * @param newMob /mob The user's new mob
- *
- * @return nothing
- */
-/datum/nanomanager/proc/user_transferred(var/mob/oldMob, var/mob/newMob)
- if (isnull(oldMob.open_uis) || !istype(oldMob.open_uis, /list) || open_uis.len == 0)
- return 0 // has no open uis
-
- if (isnull(newMob.open_uis) || !istype(newMob.open_uis, /list))
- newMob.open_uis = list()
-
- for (var/datum/nanoui/ui in oldMob.open_uis)
- ui.user = newMob
- newMob.open_uis.Add(ui)
-
- oldMob.open_uis.Cut()
-
- return 1 // success
-
+// This is the window/UI manager for Nano UI
+// There should only ever be one (global) instance of nanomanger
+/datum/nanomanager
+ // a list of current open /nanoui UIs, grouped by src_object and ui_key
+ var/open_uis[0]
+ // a list of current open /nanoui UIs, not grouped, for use in processing
+ var/list/processing_uis = list()
+
+ /**
+ * Create a new nanomanager instance.
+ *
+ * @return /nanomanager new nanomanager object
+ */
+/datum/nanomanager/New()
+ return
+
+ /**
+ * Get an open /nanoui ui for the current user, src_object and ui_key and try to update it with data
+ *
+ * @param user /mob The mob who opened/owns the ui
+ * @param src_object /obj|/mob The obj or mob which the ui belongs to
+ * @param ui_key string A string key used for the ui
+ * @param ui /datum/nanoui An existing instance of the ui (can be null)
+ * @param data list The data to be passed to the ui, if it exists
+ *
+ * @return /nanoui Returns the found ui, for null if none exists
+ */
+/datum/nanomanager/proc/try_update_ui(var/mob/user, src_object, ui_key, var/datum/nanoui/ui, data)
+ if (isnull(ui)) // no ui has been passed, so we'll search for one
+ {
+ ui = get_open_ui(user, src_object, ui_key)
+ }
+ if (!isnull(ui))
+ // The UI is already open so push the data to it
+ ui.push_data(data)
+ return ui
+
+ return null
+
+ /**
+ * Get an open /nanoui ui for the current user, src_object and ui_key
+ *
+ * @param user /mob The mob who opened/owns the ui
+ * @param src_object /obj|/mob The obj or mob which the ui belongs to
+ * @param ui_key string A string key used for the ui
+ *
+ * @return /nanoui Returns the found ui, or null if none exists
+ */
+/datum/nanomanager/proc/get_open_ui(var/mob/user, src_object, ui_key)
+ var/src_object_key = "\ref[src_object]"
+ if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
+ return null
+ else if (isnull(open_uis[src_object_key][ui_key]) || !istype(open_uis[src_object_key][ui_key], /list))
+ return null
+
+ for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key])
+ if (ui.user == user)
+ return ui
+
+ return null
+
+ /**
+ * Update all /nanoui uis attached to src_object
+ *
+ * @param src_object /obj|/mob The obj or mob which the uis are attached to
+ *
+ * @return int The number of uis updated
+ */
+/datum/nanomanager/proc/update_uis(src_object)
+ var/src_object_key = "\ref[src_object]"
+ if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
+ return 0
+
+ var/update_count = 0
+ for (var/ui_key in open_uis[src_object_key])
+ for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key])
+ if(ui && ui.src_object && ui.user)
+ ui.process(1)
+ update_count++
+ return update_count
+
+ /**
+ * Update /nanoui uis belonging to user
+ *
+ * @param user /mob The mob who owns the uis
+ * @param src_object /obj|/mob If src_object is provided, only update uis which are attached to src_object (optional)
+ * @param ui_key string If ui_key is provided, only update uis with a matching ui_key (optional)
+ *
+ * @return int The number of uis updated
+ */
+/datum/nanomanager/proc/update_user_uis(var/mob/user, src_object = null, ui_key = null)
+ if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0)
+ return 0 // has no open uis
+
+ var/update_count = 0
+ for (var/datum/nanoui/ui in user.open_uis)
+ if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
+ ui.process(1)
+ update_count++
+
+ return update_count
+
+ /**
+ * Close /nanoui uis belonging to user
+ *
+ * @param user /mob The mob who owns the uis
+ * @param src_object /obj|/mob If src_object is provided, only close uis which are attached to src_object (optional)
+ * @param ui_key string If ui_key is provided, only close uis with a matching ui_key (optional)
+ *
+ * @return int The number of uis closed
+ */
+/datum/nanomanager/proc/close_user_uis(var/mob/user, src_object = null, ui_key = null)
+ if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0)
+ return 0 // has no open uis
+
+ var/close_count = 0
+ for (var/datum/nanoui/ui in user.open_uis)
+ if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
+ ui.close()
+ close_count++
+
+ return close_count
+
+ /**
+ * Add a /nanoui ui to the list of open uis
+ * This is called by the /nanoui open() proc
+ *
+ * @param ui /nanoui The ui to add
+ *
+ * @return nothing
+ */
+/datum/nanomanager/proc/ui_opened(var/datum/nanoui/ui)
+ var/src_object_key = "\ref[ui.src_object]"
+ if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
+ open_uis[src_object_key] = list(ui.ui_key = list())
+ else if (isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list))
+ open_uis[src_object_key][ui.ui_key] = list();
+
+ ui.user.open_uis.Add(ui)
+ var/list/uis = open_uis[src_object_key][ui.ui_key]
+ uis.Add(ui)
+ processing_uis.Add(ui)
+
+ /**
+ * Remove a /nanoui ui from the list of open uis
+ * This is called by the /nanoui close() proc
+ *
+ * @param ui /nanoui The ui to remove
+ *
+ * @return int 0 if no ui was removed, 1 if removed successfully
+ */
+/datum/nanomanager/proc/ui_closed(var/datum/nanoui/ui)
+ var/src_object_key = "\ref[ui.src_object]"
+ if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
+ return 0 // wasn't open
+ else if (isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list))
+ return 0 // wasn't open
+
+ processing_uis.Remove(ui)
+ ui.user.open_uis.Remove(ui)
+ var/list/uis = open_uis[src_object_key][ui.ui_key]
+ return uis.Remove(ui)
+
+ /**
+ * This is called on user logout
+ * Closes/clears all uis attached to the user's /mob
+ *
+ * @param user /mob The user's mob
+ *
+ * @return nothing
+ */
+
+//
+/datum/nanomanager/proc/user_logout(var/mob/user)
+ return close_user_uis(user)
+
+ /**
+ * This is called when a player transfers from one mob to another
+ * Transfers all open UIs to the new mob
+ *
+ * @param oldMob /mob The user's old mob
+ * @param newMob /mob The user's new mob
+ *
+ * @return nothing
+ */
+/datum/nanomanager/proc/user_transferred(var/mob/oldMob, var/mob/newMob)
+ if (isnull(oldMob.open_uis) || !istype(oldMob.open_uis, /list) || open_uis.len == 0)
+ return 0 // has no open uis
+
+ if (isnull(newMob.open_uis) || !istype(newMob.open_uis, /list))
+ newMob.open_uis = list()
+
+ for (var/datum/nanoui/ui in oldMob.open_uis)
+ ui.user = newMob
+ newMob.open_uis.Add(ui)
+
+ oldMob.open_uis.Cut()
+
+ return 1 // success
+
diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm
index 7b684aefb25..496f79b55ba 100644
--- a/code/modules/nano/nanoui.dm
+++ b/code/modules/nano/nanoui.dm
@@ -1,414 +1,414 @@
-/**********************************************************
-NANO UI FRAMEWORK
-
-nanoui class (or whatever Byond calls classes)
-
-nanoui is used to open and update nano browser uis
-**********************************************************/
-
-
-#define STATUS_INTERACTIVE 2 // GREEN Visability
-#define STATUS_UPDATE 1 // ORANGE Visability
-#define STATUS_DISABLED 0 // RED Visability
-
-/datum/nanoui
- // the user who opened this ui
- var/mob/user
- // the object this ui "belongs" to
- var/atom/movable/src_object
- // the title of this ui
- var/title
- // the key of this ui, this is to allow multiple (different) uis for each src_object
- var/ui_key
- // window_id is used as the window name/identifier for browse and onclose
- var/window_id
- // the browser window width
- var/width = 0
- // the browser window height
- var/height = 0
- // whether to use extra logic when window closes
- var/on_close_logic = 1
- // an extra ref to use when the window is closed, usually null
- var/atom/ref = null
- // options for modifying window behaviour
- var/window_options = "focus=0;can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id
- // the list of stylesheets to apply to this ui
- var/list/stylesheets = list()
- // the list of javascript scripts to use for this ui
- var/list/scripts = list()
- // the list of templates to use with this ui (usually just one)
- var/templates[0]
- // the body content for this ui, do not change unless you know what you're doing
- // the #mainTemplate div will contain the compiled "main" template html
- var/content = ""
- // initial data, containing the full data structure, must be sent to the ui (the data structure cannot be extended later on)
- var/list/initial_data[0]
- // set to 1 to update the ui automatically every master_controller tick
- var/is_auto_updating = 0
- // the current status/visibility of the ui
- var/status = STATUS_INTERACTIVE
-
- // Only allow users with a certain user.stat to get updates. Defaults to 0 (concious)
- var/allowed_user_stat = 0 // -1 = ignore, 0 = alive, 1 = unconcious or alive, 2 = dead concious or alive
-
- /**
- * Create a new nanoui instance.
- *
- * @param nuser /mob The mob who has opened/owns this ui
- * @param nsrc_object /obj|/mob The obj or mob which this ui belongs to
- * @param nui_key string A string key to use for this ui. Allows for multiple unique uis on one src_oject
- * @param ntemplate string The name of the template file from /nano/templates (e.g. "my_template.tmpl")
- * @param ntitle string The title of this ui
- * @param nwidth int the width of the ui window
- * @param nheight int the height of the ui window
- * @param nref /atom A custom ref to use if "on_close_logic" is set to 1
- *
- * @return /nanoui new nanoui object
- */
-/datum/nanoui/New(nuser, nsrc_object, nui_key, ntemplate, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null)
- user = nuser
- src_object = nsrc_object
- ui_key = nui_key
- window_id = "[ui_key]\ref[src_object]"
-
- // Add the passed template as the 'main' template, this is required
- add_template("main", ntemplate)
-
- if (ntitle)
- title = ntitle
- if (nwidth)
- width = nwidth
- if (nheight)
- height = nheight
- if (nref)
- ref = nref
-
- add_common_assets()
-
- /**
- * Use this proc to add assets which are common to all nano uis
- *
- * @return nothing
- */
-/datum/nanoui/proc/add_common_assets()
- add_script("libraries.min.js") // The jQuery library
- add_script("nano_config.js") // The NanoConfig JS, this is used to store configuration values.
- add_script("nano_update.js") // The NanoUpdate JS, this is used to receive updates and apply them.
- add_script("nano_base_helpers.js") // The NanoBaseHelpers JS, this is used to set up template helpers which are common to all templates
- add_stylesheet("shared.css") // this CSS sheet is common to all UIs
- add_stylesheet("icons.css") // this CSS sheet is common to all UIs
-
- /**
- * Set the current status (also known as visibility) of this ui.
- *
- * @param state int The status to set, see the defines at the top of this file
- * @param push_update int (bool) Push an update to the ui to update it's status (an update is always sent if the status has changed to red (0))
- *
- * @return nothing
- */
-/datum/nanoui/proc/set_status(state, push_update)
- if (state != status)
- status = state
- if (push_update || !status)
- push_data(list(), 1) // Update the UI, force the update in case the status is 0
- else
- status = state
-
- /**
- * Update the status (visibility) of this ui based on the user's status
- *
- * @param push_update int (bool) Push an update to the ui to update it's status. This is set to 0/false if an update is going to be pushed anyway (to avoid unnessary updates)
- *
- * @return nothing
- */
-/datum/nanoui/proc/update_status(push_update = 0)
- if (istype(user, /mob/living/silicon/ai))
- set_status(STATUS_INTERACTIVE, push_update) // interactive (green visibility)
- else if (istype(user, /mob/living/silicon/robot))
- if (src_object in view(7, user)) // robots can see and interact with things they can see within 7 tiles
- set_status(STATUS_INTERACTIVE, push_update) // interactive (green visibility)
- else
- set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility)
- else
- var/dist = get_dist(src_object, user)
-
- if (dist > 4)
- close()
- return
-
- if ((allowed_user_stat > -1) && (user.stat > allowed_user_stat))
- set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility)
- else if (user.restrained() || user.lying)
- set_status(STATUS_UPDATE, push_update) // update only (orange visibility)
- else if (!(src_object in view(4, user))) // If the src object is not in visable, set status to 0
- set_status(STATUS_DISABLED, push_update) // interactive (green visibility)
- else if (dist <= 1)
- set_status(STATUS_INTERACTIVE, push_update) // interactive (green visibility)
- else if (dist <= 2)
- set_status(STATUS_UPDATE, push_update) // update only (orange visibility)
- else if (dist <= 4)
- set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility)
-
- /**
- * Set the ui to auto update (every master_controller tick)
- *
- * @param state int (bool) Set auto update to 1 or 0 (true/false)
- *
- * @return nothing
- */
-/datum/nanoui/proc/set_auto_update(state = 1)
- is_auto_updating = state
-
- /**
- * Set the initial data for the ui. This is vital as the data structure set here cannot be changed when pushing new updates.
- *
- * @param data /list The list of data for this ui
- *
- * @return nothing
- */
-/datum/nanoui/proc/set_initial_data(list/data)
- initial_data = add_default_data(data)
-
- /**
- * Add default data to the data being sent to the ui.
- *
- * @param data /list The list of data to be modified
- *
- * @return /list modified data
- */
-/datum/nanoui/proc/add_default_data(list/data)
- data["ui"] = list(
- "status" = status,
- "user" = list("name" = user.name)
- )
- return data
-
- /**
- * Set the browser window options for this ui
- *
- * @param nwindow_options string The new window options
- *
- * @return nothing
- */
-/datum/nanoui/proc/set_window_options(nwindow_options)
- window_options = nwindow_options
-
- /**
- * Add a CSS stylesheet to this UI
- *
- * @param file string The name of the CSS file from /nano/css (e.g. "my_style.css")
- *
- * @return nothing
- */
-/datum/nanoui/proc/add_stylesheet(file)
- stylesheets.Add(file)
-
- /**
- * Add a JavsScript script to this UI
- *
- * @param file string The name of the JavaScript file from /nano/js (e.g. "my_script.js")
- *
- * @return nothing
- */
-/datum/nanoui/proc/add_script(file)
- scripts.Add(file)
-
- /**
- * Add a template to this UI
- * Templates are combined with the data sent to the UI to create the rendered view
- * Each template needs a div in ui.content to contain the rendered content.
- * The div format is '' where is replaced with the templater's key.
- * All UIs are set up by default to use a 'main' template, so only use this proc if you want to add advanced functionality.
- *
- * @param key string The key name for this template, used to identify the div to render this template into ('')
- * @param file string The name of the template file from /nano/templates (e.g. "my_template.tmpl")
- *
- * @return nothing
- */
-/datum/nanoui/proc/add_template(key, file)
- templates[key] = file
-
- /**
- * Set the HTML content of the UI
- * This should only really be used to add more template divs (see the add_template() proc)
- *
- * @param ncontent string The new HTML content for this UI
- *
- * @return nothing
- */
-/datum/nanoui/proc/set_content(ncontent)
- content = ncontent
-
- /**
- * Set whether or not to use the "old" on close logic (mainly unset_machine())
- *
- * @param state int (bool) Set on_close_logic to 1 or 0 (true/false)
- *
- * @return nothing
- */
-/datum/nanoui/proc/use_on_close_logic(state)
- on_close_logic = state
-
- /**
- * Return the HTML header content for this UI
- *
- * @return string HTML header content
- */
-/datum/nanoui/proc/get_header()
- var/head_content = ""
-
- for (var/filename in scripts)
- head_content += " "
-
- for (var/filename in stylesheets)
- head_content += " "
-
- var/templatel_data[0]
- for (var/key in templates)
- templatel_data[key] = templates[key];
-
- var/template_data_json = "{}" // An empty JSON object
- if (templatel_data.len > 0)
- template_data_json = list2json(templatel_data)
-
- var/initial_data_json = "{}" // An empty JSON object
- if (initial_data.len > 0)
- initial_data_json = list2json(initial_data)
-
- var/url_parameters_json = list2json(list("src" = "\ref[src]"))
-
- return {"
-
-
-
-
- [head_content]
-
-
-
- [title ? "[title]" : ""]
-
- Initiating...
- "}
-
- /**
- * Return the HTML footer content for this UI
- *
- * @return string HTML footer content
- */
-/datum/nanoui/proc/get_footer()
-
- return {"
-
-
-
-"}
-
- /**
- * Return the HTML for this UI
- *
- * @return string HTML for the UI
- */
-/datum/nanoui/proc/get_html()
- return {"
- [get_header()]
- [content]
- [get_footer()]
- "}
-
- /**
- * Open this UI
- *
- * @return nothing
- */
-/datum/nanoui/proc/open()
- var/window_size = ""
- if (width && height)
- window_size = "size=[width]x[height];"
- update_status(0)
- user << browse(get_html(), "window=[window_id];[window_size][window_options]")
- winset(user, "mapwindow.map", "focus=true") // return keyboard focus to map
- on_close_winset()
- //onclose(user, window_id)
- nanomanager.ui_opened(src)
-
- /**
- * Close this UI
- *
- * @return nothing
- */
-/datum/nanoui/proc/close()
- is_auto_updating = 0
- nanomanager.ui_closed(src)
- user << browse(null, "window=[window_id]")
-
- /**
- * Set the UI window to call the nanoclose verb when the window is closed
- * This allows Nano to handle closed windows
- *
- * @return nothing
- */
-/datum/nanoui/proc/on_close_winset()
- if(!user.client)
- return
- var/params = "\ref[src]"
-
- winset(user, window_id, "on-close=\"nanoclose [params]\"")
-
- /**
- * Push data to an already open UI window
- *
- * @return nothing
- */
-/datum/nanoui/proc/push_data(data, force_push = 0)
- update_status(0)
- if (status == STATUS_DISABLED && !force_push)
- return // Cannot update UI, no visibility
-
- data = add_default_data(data)
- //user << list2json(data) // used for debugging
- user << output(list2params(list(list2json(data))),"[window_id].browser:receiveUpdateData")
-
- /**
- * This Topic() proc is called whenever a user clicks on a link within a Nano UI
- * If the UI status is currently STATUS_INTERACTIVE then call the src_object Topic()
- * If the src_object Topic() returns 1 (true) then update all UIs attached to src_object
- *
- * @return nothing
- */
-/datum/nanoui/Topic(href, href_list)
- update_status(0) // update the status
- if (status != STATUS_INTERACTIVE || user != usr) // If UI is not interactive or usr calling Topic is not the UI user
- return
-
- if (src_object && src_object.Topic(href, href_list))
- nanomanager.update_uis(src_object) // update all UIs attached to src_object
-
- /**
- * Process this UI, updating the entire UI or just the status (aka visibility)
- * This process proc is called by the master_controller
- *
- * @param update string For this UI to update
- *
- * @return nothing
- */
-/datum/nanoui/proc/process(update = 0)
- if (!src_object || !user)
- close()
- return
-
- if (status && (update || is_auto_updating))
- src_object.ui_interact(user, ui_key, src) // Update the UI (update_status() is called whenever a UI is updated)
- else
- update_status(1) // Not updating UI, so lets check here if status has changed
-
+/**********************************************************
+NANO UI FRAMEWORK
+
+nanoui class (or whatever Byond calls classes)
+
+nanoui is used to open and update nano browser uis
+**********************************************************/
+
+
+#define STATUS_INTERACTIVE 2 // GREEN Visability
+#define STATUS_UPDATE 1 // ORANGE Visability
+#define STATUS_DISABLED 0 // RED Visability
+
+/datum/nanoui
+ // the user who opened this ui
+ var/mob/user
+ // the object this ui "belongs" to
+ var/atom/movable/src_object
+ // the title of this ui
+ var/title
+ // the key of this ui, this is to allow multiple (different) uis for each src_object
+ var/ui_key
+ // window_id is used as the window name/identifier for browse and onclose
+ var/window_id
+ // the browser window width
+ var/width = 0
+ // the browser window height
+ var/height = 0
+ // whether to use extra logic when window closes
+ var/on_close_logic = 1
+ // an extra ref to use when the window is closed, usually null
+ var/atom/ref = null
+ // options for modifying window behaviour
+ var/window_options = "focus=0;can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id
+ // the list of stylesheets to apply to this ui
+ var/list/stylesheets = list()
+ // the list of javascript scripts to use for this ui
+ var/list/scripts = list()
+ // the list of templates to use with this ui (usually just one)
+ var/templates[0]
+ // the body content for this ui, do not change unless you know what you're doing
+ // the #mainTemplate div will contain the compiled "main" template html
+ var/content = ""
+ // initial data, containing the full data structure, must be sent to the ui (the data structure cannot be extended later on)
+ var/list/initial_data[0]
+ // set to 1 to update the ui automatically every master_controller tick
+ var/is_auto_updating = 0
+ // the current status/visibility of the ui
+ var/status = STATUS_INTERACTIVE
+
+ // Only allow users with a certain user.stat to get updates. Defaults to 0 (concious)
+ var/allowed_user_stat = 0 // -1 = ignore, 0 = alive, 1 = unconcious or alive, 2 = dead concious or alive
+
+ /**
+ * Create a new nanoui instance.
+ *
+ * @param nuser /mob The mob who has opened/owns this ui
+ * @param nsrc_object /obj|/mob The obj or mob which this ui belongs to
+ * @param nui_key string A string key to use for this ui. Allows for multiple unique uis on one src_oject
+ * @param ntemplate string The name of the template file from /nano/templates (e.g. "my_template.tmpl")
+ * @param ntitle string The title of this ui
+ * @param nwidth int the width of the ui window
+ * @param nheight int the height of the ui window
+ * @param nref /atom A custom ref to use if "on_close_logic" is set to 1
+ *
+ * @return /nanoui new nanoui object
+ */
+/datum/nanoui/New(nuser, nsrc_object, nui_key, ntemplate, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null)
+ user = nuser
+ src_object = nsrc_object
+ ui_key = nui_key
+ window_id = "[ui_key]\ref[src_object]"
+
+ // Add the passed template as the 'main' template, this is required
+ add_template("main", ntemplate)
+
+ if (ntitle)
+ title = ntitle
+ if (nwidth)
+ width = nwidth
+ if (nheight)
+ height = nheight
+ if (nref)
+ ref = nref
+
+ add_common_assets()
+
+ /**
+ * Use this proc to add assets which are common to all nano uis
+ *
+ * @return nothing
+ */
+/datum/nanoui/proc/add_common_assets()
+ add_script("libraries.min.js") // The jQuery library
+ add_script("nano_config.js") // The NanoConfig JS, this is used to store configuration values.
+ add_script("nano_update.js") // The NanoUpdate JS, this is used to receive updates and apply them.
+ add_script("nano_base_helpers.js") // The NanoBaseHelpers JS, this is used to set up template helpers which are common to all templates
+ add_stylesheet("shared.css") // this CSS sheet is common to all UIs
+ add_stylesheet("icons.css") // this CSS sheet is common to all UIs
+
+ /**
+ * Set the current status (also known as visibility) of this ui.
+ *
+ * @param state int The status to set, see the defines at the top of this file
+ * @param push_update int (bool) Push an update to the ui to update it's status (an update is always sent if the status has changed to red (0))
+ *
+ * @return nothing
+ */
+/datum/nanoui/proc/set_status(state, push_update)
+ if (state != status)
+ status = state
+ if (push_update || !status)
+ push_data(list(), 1) // Update the UI, force the update in case the status is 0
+ else
+ status = state
+
+ /**
+ * Update the status (visibility) of this ui based on the user's status
+ *
+ * @param push_update int (bool) Push an update to the ui to update it's status. This is set to 0/false if an update is going to be pushed anyway (to avoid unnessary updates)
+ *
+ * @return nothing
+ */
+/datum/nanoui/proc/update_status(push_update = 0)
+ if (istype(user, /mob/living/silicon/ai))
+ set_status(STATUS_INTERACTIVE, push_update) // interactive (green visibility)
+ else if (istype(user, /mob/living/silicon/robot))
+ if (src_object in view(7, user)) // robots can see and interact with things they can see within 7 tiles
+ set_status(STATUS_INTERACTIVE, push_update) // interactive (green visibility)
+ else
+ set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility)
+ else
+ var/dist = get_dist(src_object, user)
+
+ if (dist > 4)
+ close()
+ return
+
+ if ((allowed_user_stat > -1) && (user.stat > allowed_user_stat))
+ set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility)
+ else if (user.restrained() || user.lying)
+ set_status(STATUS_UPDATE, push_update) // update only (orange visibility)
+ else if (!(src_object in view(4, user))) // If the src object is not in visable, set status to 0
+ set_status(STATUS_DISABLED, push_update) // interactive (green visibility)
+ else if (dist <= 1)
+ set_status(STATUS_INTERACTIVE, push_update) // interactive (green visibility)
+ else if (dist <= 2)
+ set_status(STATUS_UPDATE, push_update) // update only (orange visibility)
+ else if (dist <= 4)
+ set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility)
+
+ /**
+ * Set the ui to auto update (every master_controller tick)
+ *
+ * @param state int (bool) Set auto update to 1 or 0 (true/false)
+ *
+ * @return nothing
+ */
+/datum/nanoui/proc/set_auto_update(state = 1)
+ is_auto_updating = state
+
+ /**
+ * Set the initial data for the ui. This is vital as the data structure set here cannot be changed when pushing new updates.
+ *
+ * @param data /list The list of data for this ui
+ *
+ * @return nothing
+ */
+/datum/nanoui/proc/set_initial_data(list/data)
+ initial_data = add_default_data(data)
+
+ /**
+ * Add default data to the data being sent to the ui.
+ *
+ * @param data /list The list of data to be modified
+ *
+ * @return /list modified data
+ */
+/datum/nanoui/proc/add_default_data(list/data)
+ data["ui"] = list(
+ "status" = status,
+ "user" = list("name" = user.name)
+ )
+ return data
+
+ /**
+ * Set the browser window options for this ui
+ *
+ * @param nwindow_options string The new window options
+ *
+ * @return nothing
+ */
+/datum/nanoui/proc/set_window_options(nwindow_options)
+ window_options = nwindow_options
+
+ /**
+ * Add a CSS stylesheet to this UI
+ *
+ * @param file string The name of the CSS file from /nano/css (e.g. "my_style.css")
+ *
+ * @return nothing
+ */
+/datum/nanoui/proc/add_stylesheet(file)
+ stylesheets.Add(file)
+
+ /**
+ * Add a JavsScript script to this UI
+ *
+ * @param file string The name of the JavaScript file from /nano/js (e.g. "my_script.js")
+ *
+ * @return nothing
+ */
+/datum/nanoui/proc/add_script(file)
+ scripts.Add(file)
+
+ /**
+ * Add a template to this UI
+ * Templates are combined with the data sent to the UI to create the rendered view
+ * Each template needs a div in ui.content to contain the rendered content.
+ * The div format is '' where is replaced with the templater's key.
+ * All UIs are set up by default to use a 'main' template, so only use this proc if you want to add advanced functionality.
+ *
+ * @param key string The key name for this template, used to identify the div to render this template into ('')
+ * @param file string The name of the template file from /nano/templates (e.g. "my_template.tmpl")
+ *
+ * @return nothing
+ */
+/datum/nanoui/proc/add_template(key, file)
+ templates[key] = file
+
+ /**
+ * Set the HTML content of the UI
+ * This should only really be used to add more template divs (see the add_template() proc)
+ *
+ * @param ncontent string The new HTML content for this UI
+ *
+ * @return nothing
+ */
+/datum/nanoui/proc/set_content(ncontent)
+ content = ncontent
+
+ /**
+ * Set whether or not to use the "old" on close logic (mainly unset_machine())
+ *
+ * @param state int (bool) Set on_close_logic to 1 or 0 (true/false)
+ *
+ * @return nothing
+ */
+/datum/nanoui/proc/use_on_close_logic(state)
+ on_close_logic = state
+
+ /**
+ * Return the HTML header content for this UI
+ *
+ * @return string HTML header content
+ */
+/datum/nanoui/proc/get_header()
+ var/head_content = ""
+
+ for (var/filename in scripts)
+ head_content += " "
+
+ for (var/filename in stylesheets)
+ head_content += " "
+
+ var/templatel_data[0]
+ for (var/key in templates)
+ templatel_data[key] = templates[key];
+
+ var/template_data_json = "{}" // An empty JSON object
+ if (templatel_data.len > 0)
+ template_data_json = list2json(templatel_data)
+
+ var/initial_data_json = "{}" // An empty JSON object
+ if (initial_data.len > 0)
+ initial_data_json = list2json(initial_data)
+
+ var/url_parameters_json = list2json(list("src" = "\ref[src]"))
+
+ return {"
+
+
+
+
+ [head_content]
+
+
+
+ [title ? "[title]" : ""]
+
+ Initiating...
+ "}
+
+ /**
+ * Return the HTML footer content for this UI
+ *
+ * @return string HTML footer content
+ */
+/datum/nanoui/proc/get_footer()
+
+ return {"
+
+
+
+"}
+
+ /**
+ * Return the HTML for this UI
+ *
+ * @return string HTML for the UI
+ */
+/datum/nanoui/proc/get_html()
+ return {"
+ [get_header()]
+ [content]
+ [get_footer()]
+ "}
+
+ /**
+ * Open this UI
+ *
+ * @return nothing
+ */
+/datum/nanoui/proc/open()
+ var/window_size = ""
+ if (width && height)
+ window_size = "size=[width]x[height];"
+ update_status(0)
+ user << browse(get_html(), "window=[window_id];[window_size][window_options]")
+ winset(user, "mapwindow.map", "focus=true") // return keyboard focus to map
+ on_close_winset()
+ //onclose(user, window_id)
+ nanomanager.ui_opened(src)
+
+ /**
+ * Close this UI
+ *
+ * @return nothing
+ */
+/datum/nanoui/proc/close()
+ is_auto_updating = 0
+ nanomanager.ui_closed(src)
+ user << browse(null, "window=[window_id]")
+
+ /**
+ * Set the UI window to call the nanoclose verb when the window is closed
+ * This allows Nano to handle closed windows
+ *
+ * @return nothing
+ */
+/datum/nanoui/proc/on_close_winset()
+ if(!user.client)
+ return
+ var/params = "\ref[src]"
+
+ winset(user, window_id, "on-close=\"nanoclose [params]\"")
+
+ /**
+ * Push data to an already open UI window
+ *
+ * @return nothing
+ */
+/datum/nanoui/proc/push_data(data, force_push = 0)
+ update_status(0)
+ if (status == STATUS_DISABLED && !force_push)
+ return // Cannot update UI, no visibility
+
+ data = add_default_data(data)
+ //user << list2json(data) // used for debugging
+ user << output(list2params(list(list2json(data))),"[window_id].browser:receiveUpdateData")
+
+ /**
+ * This Topic() proc is called whenever a user clicks on a link within a Nano UI
+ * If the UI status is currently STATUS_INTERACTIVE then call the src_object Topic()
+ * If the src_object Topic() returns 1 (true) then update all UIs attached to src_object
+ *
+ * @return nothing
+ */
+/datum/nanoui/Topic(href, href_list)
+ update_status(0) // update the status
+ if (status != STATUS_INTERACTIVE || user != usr) // If UI is not interactive or usr calling Topic is not the UI user
+ return
+
+ if (src_object && src_object.Topic(href, href_list))
+ nanomanager.update_uis(src_object) // update all UIs attached to src_object
+
+ /**
+ * Process this UI, updating the entire UI or just the status (aka visibility)
+ * This process proc is called by the master_controller
+ *
+ * @param update string For this UI to update
+ *
+ * @return nothing
+ */
+/datum/nanoui/proc/process(update = 0)
+ if (!src_object || !user)
+ close()
+ return
+
+ if (status && (update || is_auto_updating))
+ src_object.ui_interact(user, ui_key, src) // Update the UI (update_status() is called whenever a UI is updated)
+ else
+ update_status(1) // Not updating UI, so lets check here if status has changed
+
diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm
index 65ced77af37..fb4741480ab 100644
--- a/code/modules/paperwork/photography.dm
+++ b/code/modules/paperwork/photography.dm
@@ -1,355 +1,355 @@
-/* Photography!
- * Contains:
- * Camera
- * Camera Film
- * Photos
- * Photo Albums
- */
-
-/*
- * Film
- */
-/obj/item/device/camera_film
- name = "film cartridge"
- icon = 'icons/obj/items.dmi'
- desc = "A camera film cartridge. Insert it into a camera to reload it."
- icon_state = "film"
- item_state = "electropack"
- w_class = 1.0
-
-
-/*
- * Photo
- */
-/obj/item/weapon/photo
- name = "photo"
- icon = 'icons/obj/items.dmi'
- icon_state = "photo"
- item_state = "paper"
- w_class = 1.0
- var/icon/img //Big photo image
- var/scribble //Scribble on the back.
- var/blueprints = 0 //Does it include the blueprints?
-
-
-/obj/item/weapon/photo/attack_self(mob/user)
- examine()
-
-
-/obj/item/weapon/photo/attackby(obj/item/weapon/P, mob/user)
- if(istype(P, /obj/item/weapon/pen) || istype(P, /obj/item/toy/crayon))
- var/txt = sanitize(input(user, "What would you like to write on the back?", "Photo Writing", null) as text)
- txt = copytext(txt, 1, 128)
- if(loc == user && user.stat == 0)
- scribble = txt
- ..()
-
-
-/obj/item/weapon/photo/examine()
- set src in oview(1)
- if(is_blind(usr)) return
-
- if(in_range(usr, src))
- show(usr)
- usr << desc
- else
- usr << "It is too far away."
-
-
-/obj/item/weapon/photo/proc/show(mob/user)
- user << browse_rsc(img, "tmp_photo.png")
- user << browse("[name] " \
- + "" \
- + "
" \
- + "[scribble ? "
Written on the back:
[scribble]" : ""]"\
- + "", "window=book;size=192x[scribble ? 400 : 192]")
- onclose(user, "[name]")
-
-
-/obj/item/weapon/photo/verb/rename()
- set name = "Rename photo"
- set category = "Object"
- set src in usr
-
- var/n_name = copytext(sanitize(input(usr, "What would you like to label the photo?", "Photo Labelling", null) as text), 1, MAX_NAME_LEN)
- //loc.loc check is for making possible renaming photos in clipboards
- if((loc == usr || loc.loc && loc.loc == usr) && usr.stat == 0)
- name = "photo[(n_name ? text("- '[n_name]'") : null)]"
- add_fingerprint(usr)
-
-
-/*
- * Photo album
- */
-/obj/item/weapon/storage/photo_album
- name = "photo album"
- icon = 'icons/obj/items.dmi'
- icon_state = "album"
- item_state = "briefcase"
- can_hold = list("/obj/item/weapon/photo",)
-
-
-/*
- * Camera
- */
-/obj/item/device/camera
- name = "camera"
- icon = 'icons/obj/items.dmi'
- desc = "A polaroid camera. 10 photos left."
- icon_state = "camera"
- item_state = "electropack"
- w_class = 2.0
- flags = CONDUCT
- slot_flags = SLOT_BELT
- m_amt = 2000
- var/pictures_max = 10
- var/pictures_left = 10
- var/on = 1
- var/blueprints = 0 //are blueprints visible in the current photo being created?
- var/list/aipictures = list() //Allows for storage of pictures taken by AI, in a similar manner the datacore stores info
-
-
-/obj/item/device/camera/ai_camera //camera AI can take pictures with
- name = "AI photo camera"
- var/in_camera_mode = 0
-
- verb/picture()
- set category ="AI Commands"
- set name = "Take Image"
- set src in usr
-
- toggle_camera_mode()
-
- verb/viewpicture()
- set category ="AI Commands"
- set name = "View Images"
- set src in usr
-
- viewpictures()
-
-
-/obj/item/device/camera/attack(mob/living/carbon/human/M, mob/user)
- return
-
-
-/obj/item/device/camera/attackby(obj/item/I, mob/user)
- if(istype(I, /obj/item/device/camera_film))
- if(pictures_left)
- user << "[src] still has some film in it!"
- return
- user << "You insert [I] into [src]."
- user.drop_item()
- qdel(I)
- pictures_left = pictures_max
- return
- ..()
-
-
-/obj/item/device/camera/proc/camera_get_icon(list/turfs, turf/center)
- var/atoms[] = list()
- for(var/turf/T in turfs)
- atoms.Add(T)
- for(var/atom/movable/A in T)
- if(A.invisibility) continue
- atoms.Add(A)
-
- var/list/sorted = list()
- var/j
- for(var/i = 1 to atoms.len)
- var/atom/c = atoms[i]
- for(j = sorted.len, j > 0, --j)
- var/atom/c2 = sorted[j]
- if(c2.layer <= c.layer)
- break
- sorted.Insert(j+1, c)
-
- var/icon/res = icon('icons/effects/96x96.dmi', "")
-
- for(var/atom/A in sorted)
- var/icon/img = getFlatIcon(A)
- if(istype(A, /mob/living) && A:lying)
- img.Turn(A:lying)
-
- var/offX = 32 * (A.x - center.x) + A.pixel_x + 33
- var/offY = 32 * (A.y - center.y) + A.pixel_y + 33
- if(istype(A, /atom/movable))
- offX += A:step_x
- offY += A:step_y
-
- res.Blend(img, blendMode2iconMode(A.blend_mode), offX, offY)
-
- if(istype(A, /obj/item/blueprints))
- blueprints = 1
-
- for(var/turf/T in turfs)
- res.Blend(getFlatIcon(T.loc), blendMode2iconMode(T.blend_mode), 32 * (T.x - center.x) + 33, 32 * (T.y - center.y) + 33)
-
- return res
-
-
-/obj/item/device/camera/proc/camera_get_mobs(turf/the_turf)
- var/mob_detail
- for(var/mob/living/carbon/A in the_turf)
- if(A.invisibility) continue
- var/holding = null
- if(A.l_hand || A.r_hand)
- if(A.l_hand) holding = "They are holding \a [A.l_hand]"
- if(A.r_hand)
- if(holding)
- holding += " and \a [A.r_hand]"
- else
- holding = "They are holding \a [A.r_hand]"
-
- if(!mob_detail)
- mob_detail = "You can see [A] on the photo[A:health < 75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]. "
- else
- mob_detail += "You can also see [A] on the photo[A:health < 75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]."
- return mob_detail
-
-
-/obj/item/device/camera/proc/captureimage(atom/target, mob/user, flag) //Proc for both regular and AI-based camera to take the image
- var/mobs = ""
- var/isAi = istype(user, /mob/living/silicon/ai)
- var/list/seen
- if(!isAi) //crappy check, but without it AI photos would be subject to line of sight from the AI Eye object. Made the best of it by moving the sec camera check inside
- if(user.client) //To make shooting through security cameras possible
- seen = hear(world.view, user.client.eye) //To make shooting through security cameras possible
- else
- seen = hear(world.view, user)
- else
- seen = hear(world.view, target)
-
- var/list/turfs = list()
- for(var/turf/T in range(1, target))
- if(T in seen)
- if(isAi && !cameranet.checkTurfVis(T))
- continue
- else
- turfs += T
- mobs += camera_get_mobs(T)
-
- var/icon/temp = icon('icons/effects/96x96.dmi',"")
- temp.Blend("#000", ICON_OVERLAY)
- temp.Blend(camera_get_icon(turfs, target), ICON_OVERLAY)
-
- if(!isAi)
- printpicture(user, temp, mobs, flag)
- else
- aipicture(user, temp, mobs, blueprints)
-
-
-
-
-/obj/item/device/camera/proc/printpicture(mob/user, icon/temp, mobs, flag) //Normal camera proc for creating photos
- var/obj/item/weapon/photo/P = new/obj/item/weapon/photo()
- user.put_in_hands(P)
- var/icon/small_img = icon(temp)
- var/icon/ic = icon('icons/obj/items.dmi',"photo")
- small_img.Scale(8, 8)
- ic.Blend(small_img,ICON_OVERLAY, 10, 13)
- P.icon = ic
- P.img = temp
- P.desc = mobs
- P.pixel_x = rand(-10, 10)
- P.pixel_y = rand(-10, 10)
-
- if(blueprints)
- P.blueprints = 1
- blueprints = 0
-
-
-/obj/item/device/camera/proc/aipicture(mob/user, icon/temp, mobs) //instead of printing a picture like a regular camera would, we do this instead for the AI
-
- var/icon/small_img = icon(temp)
- var/icon/ic = icon('icons/obj/items.dmi',"photo")
- small_img.Scale(8, 8)
- ic.Blend(small_img,ICON_OVERLAY, 10, 13)
- var/icon = ic
- var/img = temp
- var/desc = mobs
- var/pixel_x = rand(-10, 10)
- var/pixel_y = rand(-10, 10)
-
- var/injectblueprints = 1
- if(blueprints)
- injectblueprints = 1
- blueprints = 0
-
- injectaialbum(icon, img, desc, pixel_x, pixel_y, injectblueprints)
-
-
-/datum/picture
- var/name = "image"
- var/list/fields = list()
-
-
-/obj/item/device/camera/proc/injectaialbum(var/icon, var/img, var/desc, var/pixel_x, var/pixel_y, var/blueprintsinject) //stores image information to a list similar to that of the datacore
- var/numberer = 1
- for(var/datum/picture in src.aipictures)
- numberer++
- var/datum/picture/P = new()
- P.fields["name"] = "Image [numberer]"
- P.fields["icon"] = icon
- P.fields["img"] = img
- P.fields["desc"] = desc
- P.fields["pixel_x"] = pixel_x
- P.fields["pixel_y"] = pixel_y
- P.fields["blueprints"] = blueprintsinject
-
- aipictures += P
- usr << "Image recorded" //feedback to the AI player that the picture was taken
-
-
-/obj/item/device/camera/ai_camera/proc/viewpictures() //AI proc for viewing pictures they have taken
- var/list/nametemp = list()
- var/find
- var/datum/picture/selection
- if(src.aipictures.len == 0)
- usr << "No images saved"
- return
- for(var/datum/picture/t in src.aipictures)
- nametemp += t.fields["name"]
- find = input("Select image (numbered in order taken)") in nametemp
- var/obj/item/weapon/photo/P = new/obj/item/weapon/photo()
- for(var/datum/picture/q in src.aipictures)
- if(q.fields["name"] == find)
- selection = q
- break // just in case some AI decides to take 10 thousand pictures in a round
- P.icon = selection.fields["icon"]
- P.img = selection.fields["img"]
- P.desc = selection.fields["desc"]
- P.pixel_x = selection.fields["pixel_x"]
- P.pixel_y = selection.fields["pixel_y"]
-
- P.show(usr)
- usr << P.desc
- qdel(src) //so 10 thousdand pictures items are not left in memory should an AI take them and then view them all.
-
-/obj/item/device/camera/afterattack(atom/target, mob/user, flag)
- if(!on || !pictures_left || ismob(target.loc)) return
- captureimage(target, user, flag)
-
- playsound(loc, pick('sound/items/polaroid1.ogg', 'sound/items/polaroid2.ogg'), 75, 1, -3)
-
- pictures_left--
- desc = "A polaroid camera. It has [pictures_left] photos left."
- user << "[pictures_left] photos left."
- icon_state = "camera_off"
- on = 0
- spawn(64)
- icon_state = "camera"
- on = 1
-
-/obj/item/device/camera/ai_camera/proc/toggle_camera_mode()
- if(in_camera_mode)
- camera_mode_off()
- else
- camera_mode_on()
-
-/obj/item/device/camera/ai_camera/proc/camera_mode_off()
- src.in_camera_mode = 0
- usr << "Camera Mode deactivated"
-
-/obj/item/device/camera/ai_camera/proc/camera_mode_on()
- src.in_camera_mode = 1
+/* Photography!
+ * Contains:
+ * Camera
+ * Camera Film
+ * Photos
+ * Photo Albums
+ */
+
+/*
+ * Film
+ */
+/obj/item/device/camera_film
+ name = "film cartridge"
+ icon = 'icons/obj/items.dmi'
+ desc = "A camera film cartridge. Insert it into a camera to reload it."
+ icon_state = "film"
+ item_state = "electropack"
+ w_class = 1.0
+
+
+/*
+ * Photo
+ */
+/obj/item/weapon/photo
+ name = "photo"
+ icon = 'icons/obj/items.dmi'
+ icon_state = "photo"
+ item_state = "paper"
+ w_class = 1.0
+ var/icon/img //Big photo image
+ var/scribble //Scribble on the back.
+ var/blueprints = 0 //Does it include the blueprints?
+
+
+/obj/item/weapon/photo/attack_self(mob/user)
+ examine()
+
+
+/obj/item/weapon/photo/attackby(obj/item/weapon/P, mob/user)
+ if(istype(P, /obj/item/weapon/pen) || istype(P, /obj/item/toy/crayon))
+ var/txt = sanitize(input(user, "What would you like to write on the back?", "Photo Writing", null) as text)
+ txt = copytext(txt, 1, 128)
+ if(loc == user && user.stat == 0)
+ scribble = txt
+ ..()
+
+
+/obj/item/weapon/photo/examine()
+ set src in oview(1)
+ if(is_blind(usr)) return
+
+ if(in_range(usr, src))
+ show(usr)
+ usr << desc
+ else
+ usr << "It is too far away."
+
+
+/obj/item/weapon/photo/proc/show(mob/user)
+ user << browse_rsc(img, "tmp_photo.png")
+ user << browse("[name] " \
+ + "" \
+ + "
" \
+ + "[scribble ? "
Written on the back:
[scribble]" : ""]"\
+ + "", "window=book;size=192x[scribble ? 400 : 192]")
+ onclose(user, "[name]")
+
+
+/obj/item/weapon/photo/verb/rename()
+ set name = "Rename photo"
+ set category = "Object"
+ set src in usr
+
+ var/n_name = copytext(sanitize(input(usr, "What would you like to label the photo?", "Photo Labelling", null) as text), 1, MAX_NAME_LEN)
+ //loc.loc check is for making possible renaming photos in clipboards
+ if((loc == usr || loc.loc && loc.loc == usr) && usr.stat == 0)
+ name = "photo[(n_name ? text("- '[n_name]'") : null)]"
+ add_fingerprint(usr)
+
+
+/*
+ * Photo album
+ */
+/obj/item/weapon/storage/photo_album
+ name = "photo album"
+ icon = 'icons/obj/items.dmi'
+ icon_state = "album"
+ item_state = "briefcase"
+ can_hold = list("/obj/item/weapon/photo",)
+
+
+/*
+ * Camera
+ */
+/obj/item/device/camera
+ name = "camera"
+ icon = 'icons/obj/items.dmi'
+ desc = "A polaroid camera. 10 photos left."
+ icon_state = "camera"
+ item_state = "electropack"
+ w_class = 2.0
+ flags = CONDUCT
+ slot_flags = SLOT_BELT
+ m_amt = 2000
+ var/pictures_max = 10
+ var/pictures_left = 10
+ var/on = 1
+ var/blueprints = 0 //are blueprints visible in the current photo being created?
+ var/list/aipictures = list() //Allows for storage of pictures taken by AI, in a similar manner the datacore stores info
+
+
+/obj/item/device/camera/ai_camera //camera AI can take pictures with
+ name = "AI photo camera"
+ var/in_camera_mode = 0
+
+ verb/picture()
+ set category ="AI Commands"
+ set name = "Take Image"
+ set src in usr
+
+ toggle_camera_mode()
+
+ verb/viewpicture()
+ set category ="AI Commands"
+ set name = "View Images"
+ set src in usr
+
+ viewpictures()
+
+
+/obj/item/device/camera/attack(mob/living/carbon/human/M, mob/user)
+ return
+
+
+/obj/item/device/camera/attackby(obj/item/I, mob/user)
+ if(istype(I, /obj/item/device/camera_film))
+ if(pictures_left)
+ user << "[src] still has some film in it!"
+ return
+ user << "You insert [I] into [src]."
+ user.drop_item()
+ qdel(I)
+ pictures_left = pictures_max
+ return
+ ..()
+
+
+/obj/item/device/camera/proc/camera_get_icon(list/turfs, turf/center)
+ var/atoms[] = list()
+ for(var/turf/T in turfs)
+ atoms.Add(T)
+ for(var/atom/movable/A in T)
+ if(A.invisibility) continue
+ atoms.Add(A)
+
+ var/list/sorted = list()
+ var/j
+ for(var/i = 1 to atoms.len)
+ var/atom/c = atoms[i]
+ for(j = sorted.len, j > 0, --j)
+ var/atom/c2 = sorted[j]
+ if(c2.layer <= c.layer)
+ break
+ sorted.Insert(j+1, c)
+
+ var/icon/res = icon('icons/effects/96x96.dmi', "")
+
+ for(var/atom/A in sorted)
+ var/icon/img = getFlatIcon(A)
+ if(istype(A, /mob/living) && A:lying)
+ img.Turn(A:lying)
+
+ var/offX = 32 * (A.x - center.x) + A.pixel_x + 33
+ var/offY = 32 * (A.y - center.y) + A.pixel_y + 33
+ if(istype(A, /atom/movable))
+ offX += A:step_x
+ offY += A:step_y
+
+ res.Blend(img, blendMode2iconMode(A.blend_mode), offX, offY)
+
+ if(istype(A, /obj/item/blueprints))
+ blueprints = 1
+
+ for(var/turf/T in turfs)
+ res.Blend(getFlatIcon(T.loc), blendMode2iconMode(T.blend_mode), 32 * (T.x - center.x) + 33, 32 * (T.y - center.y) + 33)
+
+ return res
+
+
+/obj/item/device/camera/proc/camera_get_mobs(turf/the_turf)
+ var/mob_detail
+ for(var/mob/living/carbon/A in the_turf)
+ if(A.invisibility) continue
+ var/holding = null
+ if(A.l_hand || A.r_hand)
+ if(A.l_hand) holding = "They are holding \a [A.l_hand]"
+ if(A.r_hand)
+ if(holding)
+ holding += " and \a [A.r_hand]"
+ else
+ holding = "They are holding \a [A.r_hand]"
+
+ if(!mob_detail)
+ mob_detail = "You can see [A] on the photo[A:health < 75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]. "
+ else
+ mob_detail += "You can also see [A] on the photo[A:health < 75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]."
+ return mob_detail
+
+
+/obj/item/device/camera/proc/captureimage(atom/target, mob/user, flag) //Proc for both regular and AI-based camera to take the image
+ var/mobs = ""
+ var/isAi = istype(user, /mob/living/silicon/ai)
+ var/list/seen
+ if(!isAi) //crappy check, but without it AI photos would be subject to line of sight from the AI Eye object. Made the best of it by moving the sec camera check inside
+ if(user.client) //To make shooting through security cameras possible
+ seen = hear(world.view, user.client.eye) //To make shooting through security cameras possible
+ else
+ seen = hear(world.view, user)
+ else
+ seen = hear(world.view, target)
+
+ var/list/turfs = list()
+ for(var/turf/T in range(1, target))
+ if(T in seen)
+ if(isAi && !cameranet.checkTurfVis(T))
+ continue
+ else
+ turfs += T
+ mobs += camera_get_mobs(T)
+
+ var/icon/temp = icon('icons/effects/96x96.dmi',"")
+ temp.Blend("#000", ICON_OVERLAY)
+ temp.Blend(camera_get_icon(turfs, target), ICON_OVERLAY)
+
+ if(!isAi)
+ printpicture(user, temp, mobs, flag)
+ else
+ aipicture(user, temp, mobs, blueprints)
+
+
+
+
+/obj/item/device/camera/proc/printpicture(mob/user, icon/temp, mobs, flag) //Normal camera proc for creating photos
+ var/obj/item/weapon/photo/P = new/obj/item/weapon/photo()
+ user.put_in_hands(P)
+ var/icon/small_img = icon(temp)
+ var/icon/ic = icon('icons/obj/items.dmi',"photo")
+ small_img.Scale(8, 8)
+ ic.Blend(small_img,ICON_OVERLAY, 10, 13)
+ P.icon = ic
+ P.img = temp
+ P.desc = mobs
+ P.pixel_x = rand(-10, 10)
+ P.pixel_y = rand(-10, 10)
+
+ if(blueprints)
+ P.blueprints = 1
+ blueprints = 0
+
+
+/obj/item/device/camera/proc/aipicture(mob/user, icon/temp, mobs) //instead of printing a picture like a regular camera would, we do this instead for the AI
+
+ var/icon/small_img = icon(temp)
+ var/icon/ic = icon('icons/obj/items.dmi',"photo")
+ small_img.Scale(8, 8)
+ ic.Blend(small_img,ICON_OVERLAY, 10, 13)
+ var/icon = ic
+ var/img = temp
+ var/desc = mobs
+ var/pixel_x = rand(-10, 10)
+ var/pixel_y = rand(-10, 10)
+
+ var/injectblueprints = 1
+ if(blueprints)
+ injectblueprints = 1
+ blueprints = 0
+
+ injectaialbum(icon, img, desc, pixel_x, pixel_y, injectblueprints)
+
+
+/datum/picture
+ var/name = "image"
+ var/list/fields = list()
+
+
+/obj/item/device/camera/proc/injectaialbum(var/icon, var/img, var/desc, var/pixel_x, var/pixel_y, var/blueprintsinject) //stores image information to a list similar to that of the datacore
+ var/numberer = 1
+ for(var/datum/picture in src.aipictures)
+ numberer++
+ var/datum/picture/P = new()
+ P.fields["name"] = "Image [numberer]"
+ P.fields["icon"] = icon
+ P.fields["img"] = img
+ P.fields["desc"] = desc
+ P.fields["pixel_x"] = pixel_x
+ P.fields["pixel_y"] = pixel_y
+ P.fields["blueprints"] = blueprintsinject
+
+ aipictures += P
+ usr << "Image recorded" //feedback to the AI player that the picture was taken
+
+
+/obj/item/device/camera/ai_camera/proc/viewpictures() //AI proc for viewing pictures they have taken
+ var/list/nametemp = list()
+ var/find
+ var/datum/picture/selection
+ if(src.aipictures.len == 0)
+ usr << "No images saved"
+ return
+ for(var/datum/picture/t in src.aipictures)
+ nametemp += t.fields["name"]
+ find = input("Select image (numbered in order taken)") in nametemp
+ var/obj/item/weapon/photo/P = new/obj/item/weapon/photo()
+ for(var/datum/picture/q in src.aipictures)
+ if(q.fields["name"] == find)
+ selection = q
+ break // just in case some AI decides to take 10 thousand pictures in a round
+ P.icon = selection.fields["icon"]
+ P.img = selection.fields["img"]
+ P.desc = selection.fields["desc"]
+ P.pixel_x = selection.fields["pixel_x"]
+ P.pixel_y = selection.fields["pixel_y"]
+
+ P.show(usr)
+ usr << P.desc
+ qdel(P) //so 10 thousdand pictures items are not left in memory should an AI take them and then view them all.
+
+/obj/item/device/camera/afterattack(atom/target, mob/user, flag)
+ if(!on || !pictures_left || ismob(target.loc)) return
+ captureimage(target, user, flag)
+
+ playsound(loc, pick('sound/items/polaroid1.ogg', 'sound/items/polaroid2.ogg'), 75, 1, -3)
+
+ pictures_left--
+ desc = "A polaroid camera. It has [pictures_left] photos left."
+ user << "[pictures_left] photos left."
+ icon_state = "camera_off"
+ on = 0
+ spawn(64)
+ icon_state = "camera"
+ on = 1
+
+/obj/item/device/camera/ai_camera/proc/toggle_camera_mode()
+ if(in_camera_mode)
+ camera_mode_off()
+ else
+ camera_mode_on()
+
+/obj/item/device/camera/ai_camera/proc/camera_mode_off()
+ src.in_camera_mode = 0
+ usr << "Camera Mode deactivated"
+
+/obj/item/device/camera/ai_camera/proc/camera_mode_on()
+ src.in_camera_mode = 1
usr << "Camera Mode activated"
\ No newline at end of file
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 0e6e3d032ea..603b4a7e060 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -1,1285 +1,1285 @@
-#define APC_WIRE_IDSCAN 1
-#define APC_WIRE_MAIN_POWER1 2
-#define APC_WIRE_MAIN_POWER2 3
-#define APC_WIRE_AI_CONTROL 4
-
-//update_state
-#define UPSTATE_CELL_IN 1
-#define UPSTATE_OPENED1 2
-#define UPSTATE_OPENED2 4
-#define UPSTATE_MAINT 8
-#define UPSTATE_BROKE 16
-#define UPSTATE_BLUESCREEN 32
-#define UPSTATE_WIREEXP 64
-#define UPSTATE_ALLGOOD 128
-
-//update_overlay
-#define APC_UPOVERLAY_CHARGEING0 1
-#define APC_UPOVERLAY_CHARGEING1 2
-#define APC_UPOVERLAY_CHARGEING2 4
-#define APC_UPOVERLAY_EQUIPMENT0 8
-#define APC_UPOVERLAY_EQUIPMENT1 16
-#define APC_UPOVERLAY_EQUIPMENT2 32
-#define APC_UPOVERLAY_LIGHTING0 64
-#define APC_UPOVERLAY_LIGHTING1 128
-#define APC_UPOVERLAY_LIGHTING2 256
-#define APC_UPOVERLAY_ENVIRON0 512
-#define APC_UPOVERLAY_ENVIRON1 1024
-#define APC_UPOVERLAY_ENVIRON2 2048
-#define APC_UPOVERLAY_LOCKED 4096
-#define APC_UPOVERLAY_OPERATING 8192
-
-
-#define APC_UPDATE_ICON_COOLDOWN 200 // 20 seconds
-
-// the Area Power Controller (APC), formerly Power Distribution Unit (PDU)
-// one per area, needs wire conection to power network
-
-// controls power to devices in that area
-// may be opened to change power cell
-// three different channels (lighting/equipment/environ) - may each be set to on, off, or auto
-
-
-//NOTE: STUFF STOLEN FROM AIRLOCK.DM thx
-
-
-/obj/machinery/power/apc
- name = "area power controller"
- desc = "A control terminal for the area electrical systems."
-
- icon_state = "apc0"
- anchored = 1
- use_power = 0
- req_access = list(access_engine_equip)
- var/area/area
- var/areastring = null
- var/obj/item/weapon/stock_parts/cell/cell
- var/start_charge = 90 // initial cell charge %
- var/cell_type = 2500 // 0=no cell, 1=regular, 2=high-cap (x5) <- old, now it's just 0=no cell, otherwise dictate cellcapacity by changing this value. 1 used to be 1000, 2 was 2500
- var/opened = 0 //0=closed, 1=opened, 2=cover removed
- var/shorted = 0
- var/lighting = 3
- var/equipment = 3
- var/environ = 3
- var/operating = 1
- var/charging = 0
- var/chargemode = 1
- var/chargecount = 0
- var/locked = 1
- var/coverlocked = 1
- var/aidisabled = 0
- var/tdir = null
- var/obj/machinery/power/terminal/terminal = null
- var/lastused_light = 0
- var/lastused_equip = 0
- var/lastused_environ = 0
- var/lastused_total = 0
- var/main_status = 0
- var/wiresexposed = 0
- powernet = 0 // set so that APCs aren't found as powernet nodes //Hackish, Horrible, was like this before I changed it :(
- var/malfhack = 0 //New var for my changes to AI malf. --NeoFite
- var/mob/living/silicon/ai/malfai = null //See above --NeoFite
-// luminosity = 1
- var/has_electronics = 0 // 0 - none, 1 - plugged in, 2 - secured by screwdriver
- var/overload = 1 //used for the Blackout malf module
- var/beenhit = 0 // used for counting how many times it has been hit, used for Aliens at the moment
- var/mob/living/silicon/ai/occupier = null
- var/longtermpower = 10
- var/datum/wires/apc/wires = null
- var/auto_name = 0
- var/update_state = -1
- var/update_overlay = -1
- var/global/status_overlays = 0
- var/updating_icon = 0
- var/global/list/status_overlays_lock
- var/global/list/status_overlays_charging
- var/global/list/status_overlays_equipment
- var/global/list/status_overlays_lighting
- var/global/list/status_overlays_environ
-
-/obj/machinery/power/apc/updateDialog()
- if (stat & (BROKEN|MAINT))
- return
- ..()
-
-/obj/machinery/power/apc/connect_to_network()
- //Override because the APC does not directly connect to the network; it goes through a terminal.
- //The terminal is what the power computer looks for anyway.
- if(!terminal)
- make_terminal()
- if(terminal)
- terminal.connect_to_network()
-
-/obj/machinery/power/apc/New(turf/loc, var/ndir, var/building=0)
- ..()
- wires = new(src)
- // offset 24 pixels in direction of dir
- // this allows the APC to be embedded in a wall, yet still inside an area
- if (building)
- dir = ndir
- src.tdir = dir // to fix Vars bug
- dir = SOUTH
-
- if(auto_name)
- name = "[get_area(src)] APC"
-
- pixel_x = (src.tdir & 3)? 0 : (src.tdir == 4 ? 24 : -24)
- pixel_y = (src.tdir & 3)? (src.tdir ==1 ? 24 : -24) : 0
- if (building==0)
- init()
- else
- area = src.loc.loc:master
- opened = 1
- operating = 0
- name = "[area.name] APC"
- stat |= MAINT
- src.update_icon()
- spawn(5)
- src.update()
-
-/obj/machinery/power/apc/Destroy()
- if(malfai && operating)
- if (ticker.mode.config_tag == "malfunction")
- if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
- ticker.mode:apcs--
- area.power_light = 0
- area.power_equip = 0
- area.power_environ = 0
- area.power_change()
- if(occupier)
- malfvacate(1)
- del(wires)
- if(cell)
- qdel(cell)
- if(terminal)
- disconnect_terminal()
- ..()
-
-/obj/machinery/power/apc/proc/make_terminal()
- // create a terminal object at the same position as original turf loc
- // wires will attach to this
- terminal = new/obj/machinery/power/terminal(src.loc)
- terminal.dir = tdir
- terminal.master = src
-
-/obj/machinery/power/apc/proc/init()
- has_electronics = 2 //installed and secured
- // is starting with a power cell installed, create it and set its charge level
- if(cell_type)
- src.cell = new/obj/item/weapon/stock_parts/cell(src)
- cell.maxcharge = cell_type // cell_type is maximum charge (old default was 1000 or 2500 (values one and two respectively)
- cell.charge = start_charge * cell.maxcharge / 100.0 // (convert percentage to actual value)
-
- var/area/A = src.loc.loc
-
- //if area isn't specified use current
- if(isarea(A) && src.areastring == null)
- src.area = A
- else
- src.area = get_area_name(areastring)
- update_icon()
-
- make_terminal()
-
- spawn(5)
- src.update()
-
-/obj/machinery/power/apc/examine()
- set src in oview(1)
-
- if(usr /*&& !usr.stat*/)
- ..()
- if(stat & BROKEN)
- usr << "Looks broken."
- return
- if(opened)
- if(has_electronics && terminal)
- usr << "The cover is [opened==2?"removed":"open"] and the power cell is [ cell ? "installed" : "missing"]."
- else if (!has_electronics && terminal)
- usr << "There are some wires but no any electronics."
- else if (has_electronics && !terminal)
- usr << "Electronics installed but not wired."
- else /* if (!has_electronics && !terminal) */
- usr << "There is no electronics nor connected wires."
-
- else
- if (stat & MAINT)
- usr << "The cover is closed. Something wrong with it: it doesn't work."
- else if (malfhack)
- usr << "The cover is broken. It may be hard to force it open."
- else
- usr << "The cover is closed."
-
-
-// update the APC icon to show the three base states
-// also add overlays for indicator lights
-/obj/machinery/power/apc/update_icon()
- if (!status_overlays)
- status_overlays = 1
- status_overlays_lock = new
- status_overlays_charging = new
- status_overlays_equipment = new
- status_overlays_lighting = new
- status_overlays_environ = new
-
- status_overlays_lock.len = 2
- status_overlays_charging.len = 3
- status_overlays_equipment.len = 4
- status_overlays_lighting.len = 4
- status_overlays_environ.len = 4
-
- status_overlays_lock[1] = image(icon, "apcox-0") // 0=blue 1=red
- status_overlays_lock[2] = image(icon, "apcox-1")
-
- status_overlays_charging[1] = image(icon, "apco3-0")
- status_overlays_charging[2] = image(icon, "apco3-1")
- status_overlays_charging[3] = image(icon, "apco3-2")
-
- status_overlays_equipment[1] = image(icon, "apco0-0")
- status_overlays_equipment[2] = image(icon, "apco0-1")
- status_overlays_equipment[3] = image(icon, "apco0-2")
- status_overlays_equipment[4] = image(icon, "apco0-3")
-
- status_overlays_lighting[1] = image(icon, "apco1-0")
- status_overlays_lighting[2] = image(icon, "apco1-1")
- status_overlays_lighting[3] = image(icon, "apco1-2")
- status_overlays_lighting[4] = image(icon, "apco1-3")
-
- status_overlays_environ[1] = image(icon, "apco2-0")
- status_overlays_environ[2] = image(icon, "apco2-1")
- status_overlays_environ[3] = image(icon, "apco2-2")
- status_overlays_environ[4] = image(icon, "apco2-3")
-
- var/update = check_updates() //returns 0 if no need to update icons.
- // 1 if we need to update the icon_state
- // 2 if we need to update the overlays
- if(!update)
- return
-
- if(update & 1) // Updating the icon state
- if(update_state & UPSTATE_ALLGOOD)
- icon_state = "apc0"
- else if(update_state & (UPSTATE_OPENED1|UPSTATE_OPENED2))
- var/basestate = "apc[ cell ? "2" : "1" ]"
- if(update_state & UPSTATE_OPENED1)
- if(update_state & (UPSTATE_MAINT|UPSTATE_BROKE))
- icon_state = "apcmaint" //disabled APC cannot hold cell
- else
- icon_state = basestate
- else if(update_state & UPSTATE_OPENED2)
- if (update_state & UPSTATE_BROKE || malfhack)
- icon_state = "[basestate]-b-nocover"
- else
- icon_state = "[basestate]-nocover"
- else if(update_state & UPSTATE_BROKE)
- icon_state = "apc-b"
- else if(update_state & UPSTATE_BLUESCREEN)
- icon_state = "apcemag"
- else if(update_state & UPSTATE_WIREEXP)
- icon_state = "apcewires"
-
- if(!(update_state & UPSTATE_ALLGOOD))
- if(overlays.len)
- overlays = 0
-
- if(update & 2)
- if(overlays.len)
- overlays.len = 0
- if(!(stat & (BROKEN|MAINT)) && update_state & UPSTATE_ALLGOOD)
- overlays += status_overlays_lock[locked+1]
- overlays += status_overlays_charging[charging+1]
- if(operating)
- overlays += status_overlays_equipment[equipment+1]
- overlays += status_overlays_lighting[lighting+1]
- overlays += status_overlays_environ[environ+1]
-
-
-/obj/machinery/power/apc/proc/check_updates()
-
- var/last_update_state = update_state
- var/last_update_overlay = update_overlay
- update_state = 0
- update_overlay = 0
-
- if(cell)
- update_state |= UPSTATE_CELL_IN
- if(stat & BROKEN)
- update_state |= UPSTATE_BROKE
- if(stat & MAINT)
- update_state |= UPSTATE_MAINT
- if(opened)
- if(opened==1)
- update_state |= UPSTATE_OPENED1
- if(opened==2)
- update_state |= UPSTATE_OPENED2
- else if(emagged || malfai)
- update_state |= UPSTATE_BLUESCREEN
- else if(wiresexposed)
- update_state |= UPSTATE_WIREEXP
- if(update_state <= 1)
- update_state |= UPSTATE_ALLGOOD
-
- if(operating)
- update_overlay |= APC_UPOVERLAY_OPERATING
-
- if(update_state & UPSTATE_ALLGOOD)
- if(locked)
- update_overlay |= APC_UPOVERLAY_LOCKED
-
- if(!charging)
- update_overlay |= APC_UPOVERLAY_CHARGEING0
- else if(charging == 1)
- update_overlay |= APC_UPOVERLAY_CHARGEING1
- else if(charging == 2)
- update_overlay |= APC_UPOVERLAY_CHARGEING2
-
- if (!equipment)
- update_overlay |= APC_UPOVERLAY_EQUIPMENT0
- else if(equipment == 1)
- update_overlay |= APC_UPOVERLAY_EQUIPMENT1
- else if(equipment == 2)
- update_overlay |= APC_UPOVERLAY_EQUIPMENT2
-
- if(!lighting)
- update_overlay |= APC_UPOVERLAY_LIGHTING0
- else if(lighting == 1)
- update_overlay |= APC_UPOVERLAY_LIGHTING1
- else if(lighting == 2)
- update_overlay |= APC_UPOVERLAY_LIGHTING2
-
- if(!environ)
- update_overlay |= APC_UPOVERLAY_ENVIRON0
- else if(environ==1)
- update_overlay |= APC_UPOVERLAY_ENVIRON1
- else if(environ==2)
- update_overlay |= APC_UPOVERLAY_ENVIRON2
-
-
- var/results = 0
- if(last_update_state == update_state && last_update_overlay == update_overlay)
- return 0
- if(last_update_state != update_state)
- results += 1
- if(last_update_overlay != update_overlay)
- results += 2
- return results
-
-// Used in process so it doesn't update the icon too much
-/obj/machinery/power/apc/proc/queue_icon_update()
-
- if(!updating_icon)
- updating_icon = 1
- // Start the update
- spawn(APC_UPDATE_ICON_COOLDOWN)
- update_icon()
- updating_icon = 0
-
-//attack with an item - open/close cover, insert cell, or (un)lock interface
-
-/obj/machinery/power/apc/attackby(obj/item/W, mob/user)
-
- if (istype(user, /mob/living/silicon) && get_dist(src,user)>1)
- return src.attack_hand(user)
- if (istype(W, /obj/item/weapon/crowbar) && opened)
- if (has_electronics==1)
- if (terminal)
- user << "\red Disconnect wires first."
- return
- playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1)
- user << "You are trying to remove the power control board..." //lpeters - fixed grammar issues
- if(do_after(user, 50))
- has_electronics = 0
- if ((stat & BROKEN) || malfhack)
- user.visible_message(\
- "\red [user.name] has broken the power control board inside [src.name]!",\
- "You broke the charred power control board and remove the remains.",
- "You hear a crack!")
- //ticker.mode:apcs-- //XSI said no and I agreed. -rastaf0
- else
- user.visible_message(\
- "\red [user.name] has removed the power control board from [src.name]!",\
- "You remove the power control board.")
- new /obj/item/weapon/module/power_control(loc)
- else if (opened!=2) //cover isn't removed
- opened = 0
- update_icon()
- else if (istype(W, /obj/item/weapon/crowbar) && !((stat & BROKEN) || malfhack) )
- if(coverlocked && !(stat & MAINT))
- user << "\red The cover is locked and cannot be opened."
- return
- else
- opened = 1
- update_icon()
- else if (istype(W, /obj/item/weapon/stock_parts/cell) && opened) // trying to put a cell inside
- if(cell)
- user << "There is a power cell already installed."
- return
- else
- if (stat & MAINT)
- user << "\red There is no connector for your power cell."
- return
- user.drop_item()
- W.loc = src
- cell = W
- user.visible_message(\
- "\red [user.name] has inserted the power cell to [src.name]!",\
- "You insert the power cell.")
- chargecount = 0
- update_icon()
- else if (istype(W, /obj/item/weapon/screwdriver)) // haxing
- if(opened)
- if (cell)
- user << "\red Close the APC first." //Less hints more mystery!
- return
- else
- if (has_electronics==1 && terminal)
- has_electronics = 2
- stat &= ~MAINT
- playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
- user << "You screw the circuit electronics into place."
- else if (has_electronics==2)
- has_electronics = 1
- stat |= MAINT
- playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
- user << "You unfasten the electronics."
- else /* has_electronics==0 */
- user << "\red There is nothing to secure."
- return
- update_icon()
- else if(emagged)
- user << "The interface is broken."
- else
- wiresexposed = !wiresexposed
- user << "The wires have been [wiresexposed ? "exposed" : "unexposed"]"
- update_icon()
-
- else if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) // trying to unlock the interface with an ID card
- if(emagged)
- user << "The interface is broken."
- else if(opened)
- user << "You must close the cover to swipe an ID card."
- else if(wiresexposed)
- user << "You must close the panel"
- else if(stat & (BROKEN|MAINT))
- user << "Nothing happens."
- else
- if(src.allowed(usr) && !isWireCut(APC_WIRE_IDSCAN))
- locked = !locked
- user << "You [ locked ? "lock" : "unlock"] the APC interface."
- update_icon()
- else
- user << "\red Access denied."
- else if (istype(W, /obj/item/weapon/card/emag) && !(emagged || malfhack)) // trying to unlock with an emag card
- if(opened)
- user << "You must close the cover to swipe an ID card."
- else if(wiresexposed)
- user << "You must close the panel first"
- else if(stat & (BROKEN|MAINT))
- user << "Nothing happens."
- else
- flick("apc-spark", src)
- if (do_after(user,6))
- if(prob(50))
- emagged = 1
- locked = 0
- user << "You emag the APC interface."
- update_icon()
- else
- user << "You fail to [ locked ? "unlock" : "lock"] the APC interface."
- else if (istype(W, /obj/item/stack/cable_coil) && !terminal && opened && has_electronics!=2)
- if (src.loc:intact)
- user << "\red You must remove the floor plating in front of the APC first."
- return
- var/obj/item/stack/cable_coil/C = W
- if(C.amount < 10)
- user << "\red You need more wires."
- return
- user << "You start adding cables to the APC frame..."
- playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
- if(do_after(user, 20) && C.amount >= 10)
- var/turf/T = get_turf(src)
- var/obj/structure/cable/N = T.get_cable_node()
- if (prob(50) && electrocute_mob(usr, N, N))
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(5, 1, src)
- s.start()
- return
- C.use(10)
- user.visible_message(\
- "\red [user.name] has added cables to the APC frame!",\
- "You add cables to the APC frame.")
- make_terminal()
- terminal.connect_to_network()
- else if (istype(W, /obj/item/weapon/wirecutters) && terminal && opened && has_electronics!=2)
- if (src.loc:intact)
- user << "\red You must remove the floor plating in front of the APC first."
- return
- user << "You begin to cut the cables..."
- playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
- if(do_after(user, 50))
- if (prob(50) && electrocute_mob(usr, terminal.powernet, terminal))
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(5, 1, src)
- s.start()
- return
- new /obj/item/stack/cable_coil(loc,10)
- user.visible_message(\
- "\red [user.name] cut the cables and dismantled the power terminal.",\
- "You cut the cables and dismantle the power terminal.")
- qdel(terminal)
- else if (istype(W, /obj/item/weapon/module/power_control) && opened && has_electronics==0 && !((stat & BROKEN) || malfhack))
- user << "You trying to insert the power control board into the frame..."
- playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
- if(do_after(user, 10))
- has_electronics = 1
- user << "You place the power control board inside the frame."
- qdel(W)
- else if (istype(W, /obj/item/weapon/module/power_control) && opened && has_electronics==0 && ((stat & BROKEN) || malfhack))
- user << "\red You cannot put the board inside, the frame is damaged."
- return
- else if (istype(W, /obj/item/weapon/weldingtool) && opened && has_electronics==0 && !terminal)
- var/obj/item/weapon/weldingtool/WT = W
- if (WT.get_fuel() < 3)
- user << "\blue You need more welding fuel to complete this task."
- return
- user << "You start welding the APC frame..."
- playsound(src.loc, 'sound/items/Welder.ogg', 50, 1)
- if(do_after(user, 50))
- if(!src || !WT.remove_fuel(3, user)) return
- if (emagged || malfhack || (stat & BROKEN) || opened==2)
- new /obj/item/stack/sheet/metal(loc)
- user.visible_message(\
- "\red [src] has been cut apart by [user.name] with the weldingtool.",\
- "You disassembled the broken APC frame.",\
- "\red You hear welding.")
- else
- new /obj/item/apc_frame(loc)
- user.visible_message(\
- "\red [src] has been cut from the wall by [user.name] with the weldingtool.",\
- "You cut the APC frame from the wall.",\
- "\red You hear welding.")
- qdel(src)
- return
- else if (istype(W, /obj/item/apc_frame) && opened && emagged)
- emagged = 0
- if (opened==2)
- opened = 1
- user.visible_message(\
- "\red [user.name] has replaced the damaged APC frontal panel with a new one.",\
- "You replace the damaged APC frontal panel with a new one.")
- qdel(W)
- update_icon()
- else if (istype(W, /obj/item/apc_frame) && opened && ((stat & BROKEN) || malfhack))
- if (has_electronics)
- user << "You cannot repair this APC until you remove the electronics still inside."
- return
- user << "You begin to replace the damaged APC frame..."
- if(do_after(user, 50))
- user.visible_message(\
- "\red [user.name] has replaced the damaged APC frame with new one.",\
- "You replace the damaged APC frame with new one.")
- qdel(W)
- stat &= ~BROKEN
- malfai = null
- malfhack = 0
- if (opened==2)
- opened = 1
- update_icon()
- else
- if ( ((stat & BROKEN) || malfhack) \
- && !opened \
- && W.force >= 5 \
- && W.w_class >= 3.0 \
- && prob(20) )
- opened = 2
- user.visible_message("\red The APC cover was knocked down with the [W.name] by [user.name]!", \
- "\red You knock down the APC cover with your [W.name]!", \
- "You hear bang")
- update_icon()
- else
- if (istype(user, /mob/living/silicon))
- return src.attack_hand(user)
- if (!opened && wiresexposed && \
- (istype(W, /obj/item/device/multitool) || \
- istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/device/assembly/signaler)))
- return src.attack_hand(user)
- user.visible_message("\red The [src.name] has been hit with the [W.name] by [user.name]!", \
- "\red You hit the [src.name] with your [W.name]!", \
- "You hear bang")
-
-// attack with hand - remove cell (if cover open) or interact with the APC
-
-/obj/machinery/power/apc/attack_hand(mob/user)
-// if (!can_use(user)) This already gets called in interact() and in topic()
-// return
- if(!user)
- return
- src.add_fingerprint(user)
- if(usr == user && opened && (!issilicon(user)))
- if(cell)
- user.put_in_hands(cell)
- cell.add_fingerprint(user)
- cell.updateicon()
-
- src.cell = null
- user.visible_message("\red [user.name] removes the power cell from [src.name]!", "You remove the power cell.")
- //user << "You remove the power cell."
- charging = 0
- src.update_icon()
- return
- if(stat & (BROKEN|MAINT))
- return
- // do APC interaction
- src.interact(user)
-
-/obj/machinery/power/apc/attack_alien(mob/living/carbon/alien/humanoid/user)
- if(!user)
- return
- user.visible_message("\red [user.name] slashes at the [src.name]!", "\blue You slash at the [src.name]!")
- playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1)
-
- var/allcut = wires.IsAllCut()
-
- if(beenhit >= pick(3, 4) && wiresexposed != 1)
- wiresexposed = 1
- src.update_icon()
- src.visible_message("\red The [src.name]'s cover flies open, exposing the wires!")
-
- else if(wiresexposed == 1 && allcut == 0)
- wires.CutAll()
- src.update_icon()
- src.visible_message("\red The [src.name]'s wires are shredded!")
- else
- beenhit += 1
- return
-
-
-/obj/machinery/power/apc/interact(mob/user)
- if(!user)
- return
-
- if(wiresexposed /*&& (!istype(user, /mob/living/silicon))*/) //Commented out the typecheck to allow engiborgs to repair damaged apcs.
- wires.Interact(user)
-
- return ui_interact(user)
-
-
-/obj/machinery/power/apc/proc/get_malf_status(mob/user)
- if (ticker && ticker.mode && (user.mind in ticker.mode.malf_ai) && istype(user, /mob/living/silicon/ai))
- if (src.malfai == (user:parent ? user:parent : user))
- if (src.occupier == user)
- return 3 // 3 = User is shunted in this APC
- else if (istype(user.loc, /obj/machinery/power/apc))
- return 4 // 4 = User is shunted in another APC
- else
- return 2 // 2 = APC hacked by user, and user is in its core.
- else
- return 1 // 1 = APC not hacked.
- else
- return 0 // 0 = User is not a Malf AI
-
-
-/obj/machinery/power/apc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
- if(!user)
- return
-
- var/list/data = list(
- "locked" = locked,
- "isOperating" = operating,
- "externalPower" = main_status,
- "powerCellStatus" = cell ? cell.percent() : null,
- "chargeMode" = chargemode,
- "chargingStatus" = charging,
- "totalLoad" = lastused_equip + lastused_light + lastused_environ,
- "coverLocked" = coverlocked,
- "siliconUser" = istype(user, /mob/living/silicon),
- "malfStatus" = get_malf_status(user),
-
- "powerChannels" = list(
- list(
- "title" = "Equipment",
- "powerLoad" = lastused_equip,
- "status" = equipment,
- "topicParams" = list(
- "auto" = list("eqp" = 3),
- "on" = list("eqp" = 2),
- "off" = list("eqp" = 1)
- )
- ),
- list(
- "title" = "Lighting",
- "powerLoad" = lastused_light,
- "status" = lighting,
- "topicParams" = list(
- "auto" = list("lgt" = 3),
- "on" = list("lgt" = 2),
- "off" = list("lgt" = 1)
- )
- ),
- list(
- "title" = "Environment",
- "powerLoad" = lastused_environ,
- "status" = environ,
- "topicParams" = list(
- "auto" = list("env" = 3),
- "on" = list("env" = 2),
- "off" = list("env" = 1)
- )
- )
- )
- )
-
- // update the ui if it exists, returns null if no ui is passed/found
- ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
- if (!ui)
- // the ui does not exist, so we'll create a new() one
- // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
- ui = new(user, src, ui_key, "apc.tmpl", "[area.name] - APC", 520, data["siliconUser"] ? 465 : 420)
- // when the ui is first opened this is the data it will use
- ui.set_initial_data(data)
- // open the new ui window
- ui.open()
- // auto update every Master Controller tick
- ui.set_auto_update(1)
-
-/obj/machinery/power/apc/proc/report()
- return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])"
-
-/obj/machinery/power/apc/proc/update()
- if(operating && !shorted)
- area.power_light = (lighting > 1)
- area.power_equip = (equipment > 1)
- area.power_environ = (environ > 1)
-// if (area.name == "AI Chamber")
-// spawn(10)
-// world << " [area.name] [area.power_equip]"
- else
- area.power_light = 0
- area.power_equip = 0
- area.power_environ = 0
-// if (area.name == "AI Chamber")
-// world << "[area.power_equip]"
- area.power_change()
-
-/obj/machinery/power/apc/proc/isWireCut(var/wireIndex)
- return wires.IsIndexCut(wireIndex)
-
-
-/obj/machinery/power/apc/proc/can_use(mob/user as mob, var/loud = 0) //used by attack_hand() and Topic()
- if (user.stat)
- user << "\red You must be conscious to use this [src]!"
- return 0
- if(!user.client)
- return 0
- if ( ! (istype(user, /mob/living/carbon/human) || \
- istype(user, /mob/living/silicon) || \
- istype(user, /mob/living/carbon/monkey) /*&& ticker && ticker.mode.name == "monkey"*/) )
- user << "\red You don't have the dexterity to use this [src]!"
- return 0
- if(user.restrained())
- user << "\red You must have free hands to use this [src]"
- return 0
- if(user.lying)
- user << "\red You must stand to use this [src]!"
- return 0
- if (istype(user, /mob/living/silicon))
- var/mob/living/silicon/ai/AI = user
- var/mob/living/silicon/robot/robot = user
- if ( \
- src.aidisabled || \
- malfhack && istype(malfai) && \
- ( \
- (istype(AI) && (malfai!=AI && malfai != AI.parent)) || \
- (istype(robot) && (robot in malfai.connected_robots)) \
- ) \
- )
- if(!loud)
- user << "\red \The [src] have AI control disabled!"
- return 0
- else
- if ((!in_range(src, user) || !istype(src.loc, /turf)))
- return 0
-
- var/mob/living/carbon/human/H = user
- if (istype(H))
- if(H.getBrainLoss() >= 60)
- for(var/mob/M in viewers(src, null))
- M << "\red [H] stares cluelessly at [src] and drools."
- return 0
- else if(prob(H.getBrainLoss()))
- user << "\red You momentarily forget how to use [src]."
- return 0
- return 1
-
-/obj/machinery/power/apc/Topic(href, href_list)
- if(..())
- return 0
-
- if(!can_use(usr, 1))
- return 0
-
- if (href_list["lock"])
- coverlocked = !coverlocked
-
- else if (href_list["breaker"])
- toggle_breaker()
-
- else if (href_list["cmode"])
- chargemode = !chargemode
- if(!chargemode)
- charging = 0
- update_icon()
-
- else if (href_list["eqp"])
- var/val = text2num(href_list["eqp"])
- equipment = setsubsystem(val)
- update_icon()
- update()
-
- else if (href_list["lgt"])
- var/val = text2num(href_list["lgt"])
- lighting = setsubsystem(val)
- update_icon()
- update()
-
- else if (href_list["env"])
- var/val = text2num(href_list["env"])
- environ = setsubsystem(val)
- update_icon()
- update()
-
- else if (href_list["overload"])
- if(istype(usr, /mob/living/silicon))
- src.overload_lighting()
-
- else if (href_list["malfhack"])
- var/mob/living/silicon/ai/malfai = usr
- if(get_malf_status(malfai)==1)
- if (malfai.malfhacking)
- malfai << "You are already hacking an APC."
- return 1
- malfai << "Beginning override of APC systems. This takes some time, and you cannot perform other actions during the process."
- malfai.malfhack = src
- malfai.malfhacking = 1
- sleep(600)
- if(src)
- if (!src.aidisabled)
- malfai.malfhack = null
- malfai.malfhacking = 0
- locked = 1
- if (ticker.mode.config_tag == "malfunction")
- if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
- ticker.mode:apcs++
- if(usr:parent)
- src.malfai = usr:parent
- else
- src.malfai = usr
- malfai << "Hack complete. The APC is now under your exclusive control."
- update_icon()
-
- else if (href_list["occupyapc"])
- if(get_malf_status(usr))
- malfoccupy(usr)
-
- else if (href_list["deoccupyapc"])
- if(get_malf_status(usr))
- malfvacate()
-
- else if (href_list["toggleaccess"])
- if(istype(usr, /mob/living/silicon))
- if(emagged || (stat & (BROKEN|MAINT)))
- usr << "The APC does not respond to the command."
- else
- locked = !locked
- update_icon()
-
- return 1
-
-/obj/machinery/power/apc/proc/toggle_breaker()
- operating = !operating
-
- if(malfai)
- if (ticker.mode.config_tag == "malfunction")
- if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
- operating ? ticker.mode:apcs++ : ticker.mode:apcs--
-
- src.update()
- update_icon()
-
-/obj/machinery/power/apc/proc/malfoccupy(var/mob/living/silicon/ai/malf)
- if(!istype(malf))
- return
- if(istype(malf.loc, /obj/machinery/power/apc)) // Already in an APC
- malf << "You must evacuate your current apc first."
- return
- if(!malf.can_shunt)
- malf << "You cannot shunt."
- return
- if(src.z != 1)
- return
- src.occupier = new /mob/living/silicon/ai(src,malf.laws,null,1)
- src.occupier.adjustOxyLoss(malf.getOxyLoss())
- if(!findtext(src.occupier.name,"APC Copy"))
- src.occupier.name = "[malf.name] APC Copy"
- if(malf.parent)
- src.occupier.parent = malf.parent
- else
- src.occupier.parent = malf
- malf.mind.transfer_to(src.occupier)
- src.occupier.eyeobj.name = "[src.occupier.name] (AI Eye)"
- if(malf.parent)
- qdel(malf)
- src.occupier.verbs += /mob/living/silicon/ai/proc/corereturn
- src.occupier.verbs += /datum/game_mode/malfunction/proc/takeover
- src.occupier.cancel_camera()
- if (seclevel2num(get_security_level()) == SEC_LEVEL_DELTA)
- for(var/obj/item/weapon/pinpointer/point in world)
- point.the_disk = src //the pinpointer will detect the shunted AI
-
-
-/obj/machinery/power/apc/proc/malfvacate(var/forced)
- if(!src.occupier)
- return
- if(src.occupier.parent && src.occupier.parent.stat != 2)
- src.occupier.mind.transfer_to(src.occupier.parent)
- src.occupier.parent.adjustOxyLoss(src.occupier.getOxyLoss())
- src.occupier.parent.cancel_camera()
- qdel(src.occupier)
- if (seclevel2num(get_security_level()) == SEC_LEVEL_DELTA)
- for(var/obj/item/weapon/pinpointer/point in world)
- for(var/datum/mind/AI_mind in ticker.mode.malf_ai)
- var/mob/living/silicon/ai/A = AI_mind.current // the current mob the mind owns
- if(A.stat != DEAD)
- point.the_disk = A //The pinpointer tracks the AI back into its core.
-
- else
- src.occupier << "\red Primary core damaged, unable to return core processes."
- if(forced)
- src.occupier.loc = src.loc
- src.occupier.death()
- src.occupier.gib()
- for(var/obj/item/weapon/pinpointer/point in world)
- point.the_disk = null //the pinpointer will go back to pointing at the nuke disc.
-
-
-/obj/machinery/power/apc/proc/ion_act()
- //intended to be exactly the same as an AI malf attack
- if(!src.malfhack && src.z == 1)
- if(prob(3))
- src.locked = 1
- if (src.cell.charge > 0)
-// world << "\red blew APC in [src.loc.loc]"
- src.cell.charge = 0
- cell.corrupt()
- src.malfhack = 1
- update_icon()
- var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread()
- smoke.set_up(3, 0, src.loc)
- smoke.attach(src)
- smoke.start()
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(3, 1, src)
- s.start()
- for(var/mob/M in viewers(src))
- M.show_message("\red The [src.name] suddenly lets out a blast of smoke and some sparks!", 3, "\red You hear sizzling electronics.", 2)
-
-
-/obj/machinery/power/apc/surplus()
- if(terminal)
- return terminal.surplus()
- else
- return 0
-
-/obj/machinery/power/apc/add_load(var/amount)
- if(terminal && terminal.powernet)
- terminal.powernet.newload += amount
-
-/obj/machinery/power/apc/avail()
- if(terminal)
- return terminal.avail()
- else
- return 0
-
-/obj/machinery/power/apc/process()
-
- if(stat & (BROKEN|MAINT))
- return
- if(!area.requires_power)
- return
-
-
- /*
- if (equipment > 1) // off=0, off auto=1, on=2, on auto=3
- use_power(src.equip_consumption, EQUIP)
- if (lighting > 1) // off=0, off auto=1, on=2, on auto=3
- use_power(src.light_consumption, LIGHT)
- if (environ > 1) // off=0, off auto=1, on=2, on auto=3
- use_power(src.environ_consumption, ENVIRON)
-
- area.calc_lighting() */
-
- lastused_light = area.usage(LIGHT)
- lastused_equip = area.usage(EQUIP)
- lastused_environ = area.usage(ENVIRON)
- area.clear_usage()
-
- lastused_total = lastused_light + lastused_equip + lastused_environ
-
- //store states to update icon if any change
- var/last_lt = lighting
- var/last_eq = equipment
- var/last_en = environ
- var/last_ch = charging
-
- var/excess = surplus()
-
- if(!src.avail())
- main_status = 0
- else if(excess < 0)
- main_status = 1
- else
- main_status = 2
-
- var/perapc = 0
- if(terminal && terminal.powernet)
- perapc = terminal.powernet.perapc
-
- //if(debug)
- // world.log << "Status: [main_status] - Excess: [excess] - Last Equip: [lastused_equip] - Last Light: [lastused_light] - Longterm: [longtermpower]"
-
- if(cell && !shorted)
-
-
- // draw power from cell as before
- var/cellused = min(cell.charge, CELLRATE * lastused_total) // clamp deduction to a max, amount left in cell
- cell.use(cellused)
-
- if(excess > 0 || perapc > lastused_total) // if power excess, or enough anyway, recharge the cell
- // by the same amount just used
- cell.give(cellused)
- add_load(cellused/CELLRATE) // add the load used to recharge the cell
-
-
- else // no excess, and not enough per-apc
-
- if( (cell.charge/CELLRATE+perapc) >= lastused_total) // can we draw enough from cell+grid to cover last usage?
-
- cell.charge = min(cell.maxcharge, cell.charge + CELLRATE * perapc) //recharge with what we can
- add_load(perapc) // so draw what we can from the grid
- charging = 0
-
- else // not enough power available to run the last tick!
- charging = 0
- chargecount = 0
- // This turns everything off in the case that there is still a charge left on the battery, just not enough to run the room.
- equipment = autoset(equipment, 0)
- lighting = autoset(lighting, 0)
- environ = autoset(environ, 0)
-
-
- // set channels depending on how much charge we have left
-
- // Allow the APC to operate as normal if the cell can charge
- if(charging && longtermpower < 10)
- longtermpower += 1
- else if(longtermpower > -10)
- longtermpower -= 2
-
- if(cell.charge <= 0) // zero charge, turn all off
- equipment = autoset(equipment, 0)
- lighting = autoset(lighting, 0)
- environ = autoset(environ, 0)
- area.poweralert(0, src)
- else if(cell.percent() < 15 && longtermpower < 0) // <15%, turn off lighting & equipment
- equipment = autoset(equipment, 2)
- lighting = autoset(lighting, 2)
- environ = autoset(environ, 1)
- area.poweralert(0, src)
- else if(cell.percent() < 30 && longtermpower < 0) // <30%, turn off equipment
- equipment = autoset(equipment, 2)
- lighting = autoset(lighting, 1)
- environ = autoset(environ, 1)
- area.poweralert(0, src)
- else // otherwise all can be on
- equipment = autoset(equipment, 1)
- lighting = autoset(lighting, 1)
- environ = autoset(environ, 1)
- area.poweralert(1, src)
- if(cell.percent() > 75)
- area.poweralert(1, src)
-
- // now trickle-charge the cell
-
- if(chargemode && charging == 1 && operating)
- if(excess > 0) // check to make sure we have enough to charge
- // Max charge is perapc share, capped to cell capacity, or % per second constant (Whichever is smallest)
-/* var/ch = min(perapc, (cell.maxcharge - cell.charge), (cell.maxcharge*CHARGELEVEL))
- add_load(ch) // Removes the power we're taking from the grid
- cell.give(ch) // actually recharge the cell
-*/
- var/ch = min(perapc*CELLRATE, (cell.maxcharge - cell.charge), (cell.maxcharge*CHARGELEVEL))
- add_load(ch/CELLRATE) // Removes the power we're taking from the grid
- cell.give(ch) // actually recharge the cell
-
- else
- charging = 0 // stop charging
- chargecount = 0
-
- // show cell as fully charged if so
-
- if(cell.charge >= cell.maxcharge)
- charging = 2
-
- if(chargemode)
- if(!charging)
- if(excess > cell.maxcharge*CHARGELEVEL)
- chargecount++
- else
- chargecount = 0
-
- if(chargecount == 10)
-
- chargecount = 0
- charging = 1
-
- else // chargemode off
- charging = 0
- chargecount = 0
-
- else // no cell, switch everything off
-
- charging = 0
- chargecount = 0
- equipment = autoset(equipment, 0)
- lighting = autoset(lighting, 0)
- environ = autoset(environ, 0)
- area.poweralert(0, src)
-
- // update icon & area power if anything changed
-
- if(last_lt != lighting || last_eq != equipment || last_en != environ)
- queue_icon_update()
- update()
- else if (last_ch != charging)
- queue_icon_update()
-
-// val 0=off, 1=off(auto) 2=on 3=on(auto)
-// on 0=off, 1=on, 2=autooff
-
-obj/machinery/power/apc/proc/autoset(var/val, var/on)
- if(on==0)
- if(val==2) // if on, return off
- return 0
- else if(val==3) // if auto-on, return auto-off
- return 1
-
- else if(on==1)
- if(val==1) // if auto-off, return auto-on
- return 3
-
- else if(on==2)
- if(val==3) // if auto-on, return auto-off
- return 1
-
- return val
-
-// damage and destruction acts
-
-/obj/machinery/power/apc/meteorhit(var/obj/O as obj)
-
- set_broken()
- return
-
-/obj/machinery/power/apc/emp_act(severity)
- if(cell)
- cell.emp_act(severity)
- if(occupier)
- occupier.emp_act(severity)
- lighting = 0
- equipment = 0
- environ = 0
- spawn(600)
- equipment = 3
- environ = 3
- ..()
-
-/obj/machinery/power/apc/ex_act(severity)
-
- switch(severity)
- if(1.0)
- //set_broken() //now Del() do what we need
- if (cell)
- cell.ex_act(1.0) // more lags woohoo
- qdel(src)
- return
- if(2.0)
- if (prob(50))
- set_broken()
- if (cell && prob(50))
- cell.ex_act(2.0)
- if(3.0)
- if (prob(25))
- set_broken()
- if (cell && prob(25))
- cell.ex_act(3.0)
- return
-
-/obj/machinery/power/apc/blob_act()
- if (prob(75))
- set_broken()
- if (cell && prob(5))
- cell.blob_act()
-
-/obj/machinery/power/apc/disconnect_terminal()
- if(terminal)
- terminal.master = null
- terminal = null
-
-/obj/machinery/power/apc/proc/set_broken()
- if(malfai && operating)
- if (ticker.mode.config_tag == "malfunction")
- if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
- ticker.mode:apcs--
- stat |= BROKEN
- operating = 0
- if(occupier)
- malfvacate(1)
- update_icon()
- update()
-
-// overload all the lights in this APC area
-
-/obj/machinery/power/apc/proc/overload_lighting()
- if(/* !get_connection() || */ !operating || shorted)
- return
- if( cell && cell.charge>=20)
- cell.use(20);
- spawn(0)
- for(var/area/A in area.related)
- for(var/obj/machinery/light/L in A)
- L.on = 1
- L.broken()
- sleep(1)
-
-/obj/machinery/power/apc/proc/shock(mob/user, prb)
- if(!prob(prb))
- return 0
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(5, 1, src)
- s.start()
- if(isalien(user))
- return 0
- if (electrocute_mob(user, src, src))
- return 1
- else
- return 0
-
-/obj/machinery/power/apc/proc/setsubsystem(val)
- if(cell && cell.charge > 0)
- return (val==1) ? 0 : val
- else if(val == 3)
- return 1
- else
- return 0
-
-#undef APC_UPDATE_ICON_COOLDOWN
+#define APC_WIRE_IDSCAN 1
+#define APC_WIRE_MAIN_POWER1 2
+#define APC_WIRE_MAIN_POWER2 3
+#define APC_WIRE_AI_CONTROL 4
+
+//update_state
+#define UPSTATE_CELL_IN 1
+#define UPSTATE_OPENED1 2
+#define UPSTATE_OPENED2 4
+#define UPSTATE_MAINT 8
+#define UPSTATE_BROKE 16
+#define UPSTATE_BLUESCREEN 32
+#define UPSTATE_WIREEXP 64
+#define UPSTATE_ALLGOOD 128
+
+//update_overlay
+#define APC_UPOVERLAY_CHARGEING0 1
+#define APC_UPOVERLAY_CHARGEING1 2
+#define APC_UPOVERLAY_CHARGEING2 4
+#define APC_UPOVERLAY_EQUIPMENT0 8
+#define APC_UPOVERLAY_EQUIPMENT1 16
+#define APC_UPOVERLAY_EQUIPMENT2 32
+#define APC_UPOVERLAY_LIGHTING0 64
+#define APC_UPOVERLAY_LIGHTING1 128
+#define APC_UPOVERLAY_LIGHTING2 256
+#define APC_UPOVERLAY_ENVIRON0 512
+#define APC_UPOVERLAY_ENVIRON1 1024
+#define APC_UPOVERLAY_ENVIRON2 2048
+#define APC_UPOVERLAY_LOCKED 4096
+#define APC_UPOVERLAY_OPERATING 8192
+
+
+#define APC_UPDATE_ICON_COOLDOWN 200 // 20 seconds
+
+// the Area Power Controller (APC), formerly Power Distribution Unit (PDU)
+// one per area, needs wire conection to power network
+
+// controls power to devices in that area
+// may be opened to change power cell
+// three different channels (lighting/equipment/environ) - may each be set to on, off, or auto
+
+
+//NOTE: STUFF STOLEN FROM AIRLOCK.DM thx
+
+
+/obj/machinery/power/apc
+ name = "area power controller"
+ desc = "A control terminal for the area electrical systems."
+
+ icon_state = "apc0"
+ anchored = 1
+ use_power = 0
+ req_access = list(access_engine_equip)
+ var/area/area
+ var/areastring = null
+ var/obj/item/weapon/stock_parts/cell/cell
+ var/start_charge = 90 // initial cell charge %
+ var/cell_type = 2500 // 0=no cell, 1=regular, 2=high-cap (x5) <- old, now it's just 0=no cell, otherwise dictate cellcapacity by changing this value. 1 used to be 1000, 2 was 2500
+ var/opened = 0 //0=closed, 1=opened, 2=cover removed
+ var/shorted = 0
+ var/lighting = 3
+ var/equipment = 3
+ var/environ = 3
+ var/operating = 1
+ var/charging = 0
+ var/chargemode = 1
+ var/chargecount = 0
+ var/locked = 1
+ var/coverlocked = 1
+ var/aidisabled = 0
+ var/tdir = null
+ var/obj/machinery/power/terminal/terminal = null
+ var/lastused_light = 0
+ var/lastused_equip = 0
+ var/lastused_environ = 0
+ var/lastused_total = 0
+ var/main_status = 0
+ var/wiresexposed = 0
+ powernet = 0 // set so that APCs aren't found as powernet nodes //Hackish, Horrible, was like this before I changed it :(
+ var/malfhack = 0 //New var for my changes to AI malf. --NeoFite
+ var/mob/living/silicon/ai/malfai = null //See above --NeoFite
+// luminosity = 1
+ var/has_electronics = 0 // 0 - none, 1 - plugged in, 2 - secured by screwdriver
+ var/overload = 1 //used for the Blackout malf module
+ var/beenhit = 0 // used for counting how many times it has been hit, used for Aliens at the moment
+ var/mob/living/silicon/ai/occupier = null
+ var/longtermpower = 10
+ var/datum/wires/apc/wires = null
+ var/auto_name = 0
+ var/update_state = -1
+ var/update_overlay = -1
+ var/global/status_overlays = 0
+ var/updating_icon = 0
+ var/global/list/status_overlays_lock
+ var/global/list/status_overlays_charging
+ var/global/list/status_overlays_equipment
+ var/global/list/status_overlays_lighting
+ var/global/list/status_overlays_environ
+
+/obj/machinery/power/apc/updateDialog()
+ if (stat & (BROKEN|MAINT))
+ return
+ ..()
+
+/obj/machinery/power/apc/connect_to_network()
+ //Override because the APC does not directly connect to the network; it goes through a terminal.
+ //The terminal is what the power computer looks for anyway.
+ if(!terminal)
+ make_terminal()
+ if(terminal)
+ terminal.connect_to_network()
+
+/obj/machinery/power/apc/New(turf/loc, var/ndir, var/building=0)
+ ..()
+ wires = new(src)
+ // offset 24 pixels in direction of dir
+ // this allows the APC to be embedded in a wall, yet still inside an area
+ if (building)
+ dir = ndir
+ src.tdir = dir // to fix Vars bug
+ dir = SOUTH
+
+ if(auto_name)
+ name = "[get_area(src)] APC"
+
+ pixel_x = (src.tdir & 3)? 0 : (src.tdir == 4 ? 24 : -24)
+ pixel_y = (src.tdir & 3)? (src.tdir ==1 ? 24 : -24) : 0
+ if (building==0)
+ init()
+ else
+ area = src.loc.loc:master
+ opened = 1
+ operating = 0
+ name = "[area.name] APC"
+ stat |= MAINT
+ src.update_icon()
+ spawn(5)
+ src.update()
+
+/obj/machinery/power/apc/Destroy()
+ if(malfai && operating)
+ if (ticker.mode.config_tag == "malfunction")
+ if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
+ ticker.mode:apcs--
+ area.power_light = 0
+ area.power_equip = 0
+ area.power_environ = 0
+ area.power_change()
+ if(occupier)
+ malfvacate(1)
+ del(wires)
+ if(cell)
+ qdel(cell)
+ if(terminal)
+ disconnect_terminal()
+ ..()
+
+/obj/machinery/power/apc/proc/make_terminal()
+ // create a terminal object at the same position as original turf loc
+ // wires will attach to this
+ terminal = new/obj/machinery/power/terminal(src.loc)
+ terminal.dir = tdir
+ terminal.master = src
+
+/obj/machinery/power/apc/proc/init()
+ has_electronics = 2 //installed and secured
+ // is starting with a power cell installed, create it and set its charge level
+ if(cell_type)
+ src.cell = new/obj/item/weapon/stock_parts/cell(src)
+ cell.maxcharge = cell_type // cell_type is maximum charge (old default was 1000 or 2500 (values one and two respectively)
+ cell.charge = start_charge * cell.maxcharge / 100.0 // (convert percentage to actual value)
+
+ var/area/A = src.loc.loc
+
+ //if area isn't specified use current
+ if(isarea(A) && src.areastring == null)
+ src.area = A
+ else
+ src.area = get_area_name(areastring)
+ update_icon()
+
+ make_terminal()
+
+ spawn(5)
+ src.update()
+
+/obj/machinery/power/apc/examine()
+ set src in oview(1)
+
+ if(usr /*&& !usr.stat*/)
+ ..()
+ if(stat & BROKEN)
+ usr << "Looks broken."
+ return
+ if(opened)
+ if(has_electronics && terminal)
+ usr << "The cover is [opened==2?"removed":"open"] and the power cell is [ cell ? "installed" : "missing"]."
+ else if (!has_electronics && terminal)
+ usr << "There are some wires but no any electronics."
+ else if (has_electronics && !terminal)
+ usr << "Electronics installed but not wired."
+ else /* if (!has_electronics && !terminal) */
+ usr << "There is no electronics nor connected wires."
+
+ else
+ if (stat & MAINT)
+ usr << "The cover is closed. Something wrong with it: it doesn't work."
+ else if (malfhack)
+ usr << "The cover is broken. It may be hard to force it open."
+ else
+ usr << "The cover is closed."
+
+
+// update the APC icon to show the three base states
+// also add overlays for indicator lights
+/obj/machinery/power/apc/update_icon()
+ if (!status_overlays)
+ status_overlays = 1
+ status_overlays_lock = new
+ status_overlays_charging = new
+ status_overlays_equipment = new
+ status_overlays_lighting = new
+ status_overlays_environ = new
+
+ status_overlays_lock.len = 2
+ status_overlays_charging.len = 3
+ status_overlays_equipment.len = 4
+ status_overlays_lighting.len = 4
+ status_overlays_environ.len = 4
+
+ status_overlays_lock[1] = image(icon, "apcox-0") // 0=blue 1=red
+ status_overlays_lock[2] = image(icon, "apcox-1")
+
+ status_overlays_charging[1] = image(icon, "apco3-0")
+ status_overlays_charging[2] = image(icon, "apco3-1")
+ status_overlays_charging[3] = image(icon, "apco3-2")
+
+ status_overlays_equipment[1] = image(icon, "apco0-0")
+ status_overlays_equipment[2] = image(icon, "apco0-1")
+ status_overlays_equipment[3] = image(icon, "apco0-2")
+ status_overlays_equipment[4] = image(icon, "apco0-3")
+
+ status_overlays_lighting[1] = image(icon, "apco1-0")
+ status_overlays_lighting[2] = image(icon, "apco1-1")
+ status_overlays_lighting[3] = image(icon, "apco1-2")
+ status_overlays_lighting[4] = image(icon, "apco1-3")
+
+ status_overlays_environ[1] = image(icon, "apco2-0")
+ status_overlays_environ[2] = image(icon, "apco2-1")
+ status_overlays_environ[3] = image(icon, "apco2-2")
+ status_overlays_environ[4] = image(icon, "apco2-3")
+
+ var/update = check_updates() //returns 0 if no need to update icons.
+ // 1 if we need to update the icon_state
+ // 2 if we need to update the overlays
+ if(!update)
+ return
+
+ if(update & 1) // Updating the icon state
+ if(update_state & UPSTATE_ALLGOOD)
+ icon_state = "apc0"
+ else if(update_state & (UPSTATE_OPENED1|UPSTATE_OPENED2))
+ var/basestate = "apc[ cell ? "2" : "1" ]"
+ if(update_state & UPSTATE_OPENED1)
+ if(update_state & (UPSTATE_MAINT|UPSTATE_BROKE))
+ icon_state = "apcmaint" //disabled APC cannot hold cell
+ else
+ icon_state = basestate
+ else if(update_state & UPSTATE_OPENED2)
+ if (update_state & UPSTATE_BROKE || malfhack)
+ icon_state = "[basestate]-b-nocover"
+ else
+ icon_state = "[basestate]-nocover"
+ else if(update_state & UPSTATE_BROKE)
+ icon_state = "apc-b"
+ else if(update_state & UPSTATE_BLUESCREEN)
+ icon_state = "apcemag"
+ else if(update_state & UPSTATE_WIREEXP)
+ icon_state = "apcewires"
+
+ if(!(update_state & UPSTATE_ALLGOOD))
+ if(overlays.len)
+ overlays = 0
+
+ if(update & 2)
+ if(overlays.len)
+ overlays.len = 0
+ if(!(stat & (BROKEN|MAINT)) && update_state & UPSTATE_ALLGOOD)
+ overlays += status_overlays_lock[locked+1]
+ overlays += status_overlays_charging[charging+1]
+ if(operating)
+ overlays += status_overlays_equipment[equipment+1]
+ overlays += status_overlays_lighting[lighting+1]
+ overlays += status_overlays_environ[environ+1]
+
+
+/obj/machinery/power/apc/proc/check_updates()
+
+ var/last_update_state = update_state
+ var/last_update_overlay = update_overlay
+ update_state = 0
+ update_overlay = 0
+
+ if(cell)
+ update_state |= UPSTATE_CELL_IN
+ if(stat & BROKEN)
+ update_state |= UPSTATE_BROKE
+ if(stat & MAINT)
+ update_state |= UPSTATE_MAINT
+ if(opened)
+ if(opened==1)
+ update_state |= UPSTATE_OPENED1
+ if(opened==2)
+ update_state |= UPSTATE_OPENED2
+ else if(emagged || malfai)
+ update_state |= UPSTATE_BLUESCREEN
+ else if(wiresexposed)
+ update_state |= UPSTATE_WIREEXP
+ if(update_state <= 1)
+ update_state |= UPSTATE_ALLGOOD
+
+ if(operating)
+ update_overlay |= APC_UPOVERLAY_OPERATING
+
+ if(update_state & UPSTATE_ALLGOOD)
+ if(locked)
+ update_overlay |= APC_UPOVERLAY_LOCKED
+
+ if(!charging)
+ update_overlay |= APC_UPOVERLAY_CHARGEING0
+ else if(charging == 1)
+ update_overlay |= APC_UPOVERLAY_CHARGEING1
+ else if(charging == 2)
+ update_overlay |= APC_UPOVERLAY_CHARGEING2
+
+ if (!equipment)
+ update_overlay |= APC_UPOVERLAY_EQUIPMENT0
+ else if(equipment == 1)
+ update_overlay |= APC_UPOVERLAY_EQUIPMENT1
+ else if(equipment == 2)
+ update_overlay |= APC_UPOVERLAY_EQUIPMENT2
+
+ if(!lighting)
+ update_overlay |= APC_UPOVERLAY_LIGHTING0
+ else if(lighting == 1)
+ update_overlay |= APC_UPOVERLAY_LIGHTING1
+ else if(lighting == 2)
+ update_overlay |= APC_UPOVERLAY_LIGHTING2
+
+ if(!environ)
+ update_overlay |= APC_UPOVERLAY_ENVIRON0
+ else if(environ==1)
+ update_overlay |= APC_UPOVERLAY_ENVIRON1
+ else if(environ==2)
+ update_overlay |= APC_UPOVERLAY_ENVIRON2
+
+
+ var/results = 0
+ if(last_update_state == update_state && last_update_overlay == update_overlay)
+ return 0
+ if(last_update_state != update_state)
+ results += 1
+ if(last_update_overlay != update_overlay)
+ results += 2
+ return results
+
+// Used in process so it doesn't update the icon too much
+/obj/machinery/power/apc/proc/queue_icon_update()
+
+ if(!updating_icon)
+ updating_icon = 1
+ // Start the update
+ spawn(APC_UPDATE_ICON_COOLDOWN)
+ update_icon()
+ updating_icon = 0
+
+//attack with an item - open/close cover, insert cell, or (un)lock interface
+
+/obj/machinery/power/apc/attackby(obj/item/W, mob/user)
+
+ if (istype(user, /mob/living/silicon) && get_dist(src,user)>1)
+ return src.attack_hand(user)
+ if (istype(W, /obj/item/weapon/crowbar) && opened)
+ if (has_electronics==1)
+ if (terminal)
+ user << "\red Disconnect wires first."
+ return
+ playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1)
+ user << "You are trying to remove the power control board..." //lpeters - fixed grammar issues
+ if(do_after(user, 50))
+ has_electronics = 0
+ if ((stat & BROKEN) || malfhack)
+ user.visible_message(\
+ "\red [user.name] has broken the power control board inside [src.name]!",\
+ "You broke the charred power control board and remove the remains.",
+ "You hear a crack!")
+ //ticker.mode:apcs-- //XSI said no and I agreed. -rastaf0
+ else
+ user.visible_message(\
+ "\red [user.name] has removed the power control board from [src.name]!",\
+ "You remove the power control board.")
+ new /obj/item/weapon/module/power_control(loc)
+ else if (opened!=2) //cover isn't removed
+ opened = 0
+ update_icon()
+ else if (istype(W, /obj/item/weapon/crowbar) && !((stat & BROKEN) || malfhack) )
+ if(coverlocked && !(stat & MAINT))
+ user << "\red The cover is locked and cannot be opened."
+ return
+ else
+ opened = 1
+ update_icon()
+ else if (istype(W, /obj/item/weapon/stock_parts/cell) && opened) // trying to put a cell inside
+ if(cell)
+ user << "There is a power cell already installed."
+ return
+ else
+ if (stat & MAINT)
+ user << "\red There is no connector for your power cell."
+ return
+ user.drop_item()
+ W.loc = src
+ cell = W
+ user.visible_message(\
+ "\red [user.name] has inserted the power cell to [src.name]!",\
+ "You insert the power cell.")
+ chargecount = 0
+ update_icon()
+ else if (istype(W, /obj/item/weapon/screwdriver)) // haxing
+ if(opened)
+ if (cell)
+ user << "\red Close the APC first." //Less hints more mystery!
+ return
+ else
+ if (has_electronics==1 && terminal)
+ has_electronics = 2
+ stat &= ~MAINT
+ playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
+ user << "You screw the circuit electronics into place."
+ else if (has_electronics==2)
+ has_electronics = 1
+ stat |= MAINT
+ playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
+ user << "You unfasten the electronics."
+ else /* has_electronics==0 */
+ user << "\red There is nothing to secure."
+ return
+ update_icon()
+ else if(emagged)
+ user << "The interface is broken."
+ else
+ wiresexposed = !wiresexposed
+ user << "The wires have been [wiresexposed ? "exposed" : "unexposed"]"
+ update_icon()
+
+ else if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) // trying to unlock the interface with an ID card
+ if(emagged)
+ user << "The interface is broken."
+ else if(opened)
+ user << "You must close the cover to swipe an ID card."
+ else if(wiresexposed)
+ user << "You must close the panel"
+ else if(stat & (BROKEN|MAINT))
+ user << "Nothing happens."
+ else
+ if(src.allowed(usr) && !isWireCut(APC_WIRE_IDSCAN))
+ locked = !locked
+ user << "You [ locked ? "lock" : "unlock"] the APC interface."
+ update_icon()
+ else
+ user << "\red Access denied."
+ else if (istype(W, /obj/item/weapon/card/emag) && !(emagged || malfhack)) // trying to unlock with an emag card
+ if(opened)
+ user << "You must close the cover to swipe an ID card."
+ else if(wiresexposed)
+ user << "You must close the panel first"
+ else if(stat & (BROKEN|MAINT))
+ user << "Nothing happens."
+ else
+ flick("apc-spark", src)
+ if (do_after(user,6))
+ if(prob(50))
+ emagged = 1
+ locked = 0
+ user << "You emag the APC interface."
+ update_icon()
+ else
+ user << "You fail to [ locked ? "unlock" : "lock"] the APC interface."
+ else if (istype(W, /obj/item/stack/cable_coil) && !terminal && opened && has_electronics!=2)
+ if (src.loc:intact)
+ user << "\red You must remove the floor plating in front of the APC first."
+ return
+ var/obj/item/stack/cable_coil/C = W
+ if(C.amount < 10)
+ user << "\red You need more wires."
+ return
+ user << "You start adding cables to the APC frame..."
+ playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
+ if(do_after(user, 20) && C.amount >= 10)
+ var/turf/T = get_turf(src)
+ var/obj/structure/cable/N = T.get_cable_node()
+ if (prob(50) && electrocute_mob(usr, N, N))
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(5, 1, src)
+ s.start()
+ return
+ C.use(10)
+ user.visible_message(\
+ "\red [user.name] has added cables to the APC frame!",\
+ "You add cables to the APC frame.")
+ make_terminal()
+ terminal.connect_to_network()
+ else if (istype(W, /obj/item/weapon/wirecutters) && terminal && opened && has_electronics!=2)
+ if (src.loc:intact)
+ user << "\red You must remove the floor plating in front of the APC first."
+ return
+ user << "You begin to cut the cables..."
+ playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
+ if(do_after(user, 50))
+ if (prob(50) && electrocute_mob(usr, terminal.powernet, terminal))
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(5, 1, src)
+ s.start()
+ return
+ new /obj/item/stack/cable_coil(loc,10)
+ user.visible_message(\
+ "\red [user.name] cut the cables and dismantled the power terminal.",\
+ "You cut the cables and dismantle the power terminal.")
+ qdel(terminal)
+ else if (istype(W, /obj/item/weapon/module/power_control) && opened && has_electronics==0 && !((stat & BROKEN) || malfhack))
+ user << "You trying to insert the power control board into the frame..."
+ playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
+ if(do_after(user, 10))
+ has_electronics = 1
+ user << "You place the power control board inside the frame."
+ qdel(W)
+ else if (istype(W, /obj/item/weapon/module/power_control) && opened && has_electronics==0 && ((stat & BROKEN) || malfhack))
+ user << "\red You cannot put the board inside, the frame is damaged."
+ return
+ else if (istype(W, /obj/item/weapon/weldingtool) && opened && has_electronics==0 && !terminal)
+ var/obj/item/weapon/weldingtool/WT = W
+ if (WT.get_fuel() < 3)
+ user << "\blue You need more welding fuel to complete this task."
+ return
+ user << "You start welding the APC frame..."
+ playsound(src.loc, 'sound/items/Welder.ogg', 50, 1)
+ if(do_after(user, 50))
+ if(!src || !WT.remove_fuel(3, user)) return
+ if (emagged || malfhack || (stat & BROKEN) || opened==2)
+ new /obj/item/stack/sheet/metal(loc)
+ user.visible_message(\
+ "\red [src] has been cut apart by [user.name] with the weldingtool.",\
+ "You disassembled the broken APC frame.",\
+ "\red You hear welding.")
+ else
+ new /obj/item/apc_frame(loc)
+ user.visible_message(\
+ "\red [src] has been cut from the wall by [user.name] with the weldingtool.",\
+ "You cut the APC frame from the wall.",\
+ "\red You hear welding.")
+ qdel(src)
+ return
+ else if (istype(W, /obj/item/apc_frame) && opened && emagged)
+ emagged = 0
+ if (opened==2)
+ opened = 1
+ user.visible_message(\
+ "\red [user.name] has replaced the damaged APC frontal panel with a new one.",\
+ "You replace the damaged APC frontal panel with a new one.")
+ qdel(W)
+ update_icon()
+ else if (istype(W, /obj/item/apc_frame) && opened && ((stat & BROKEN) || malfhack))
+ if (has_electronics)
+ user << "You cannot repair this APC until you remove the electronics still inside."
+ return
+ user << "You begin to replace the damaged APC frame..."
+ if(do_after(user, 50))
+ user.visible_message(\
+ "\red [user.name] has replaced the damaged APC frame with new one.",\
+ "You replace the damaged APC frame with new one.")
+ qdel(W)
+ stat &= ~BROKEN
+ malfai = null
+ malfhack = 0
+ if (opened==2)
+ opened = 1
+ update_icon()
+ else
+ if ( ((stat & BROKEN) || malfhack) \
+ && !opened \
+ && W.force >= 5 \
+ && W.w_class >= 3.0 \
+ && prob(20) )
+ opened = 2
+ user.visible_message("\red The APC cover was knocked down with the [W.name] by [user.name]!", \
+ "\red You knock down the APC cover with your [W.name]!", \
+ "You hear bang")
+ update_icon()
+ else
+ if (istype(user, /mob/living/silicon))
+ return src.attack_hand(user)
+ if (!opened && wiresexposed && \
+ (istype(W, /obj/item/device/multitool) || \
+ istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/device/assembly/signaler)))
+ return src.attack_hand(user)
+ user.visible_message("\red The [src.name] has been hit with the [W.name] by [user.name]!", \
+ "\red You hit the [src.name] with your [W.name]!", \
+ "You hear bang")
+
+// attack with hand - remove cell (if cover open) or interact with the APC
+
+/obj/machinery/power/apc/attack_hand(mob/user)
+// if (!can_use(user)) This already gets called in interact() and in topic()
+// return
+ if(!user)
+ return
+ src.add_fingerprint(user)
+ if(usr == user && opened && (!issilicon(user)))
+ if(cell)
+ user.put_in_hands(cell)
+ cell.add_fingerprint(user)
+ cell.updateicon()
+
+ src.cell = null
+ user.visible_message("\red [user.name] removes the power cell from [src.name]!", "You remove the power cell.")
+ //user << "You remove the power cell."
+ charging = 0
+ src.update_icon()
+ return
+ if(stat & (BROKEN|MAINT))
+ return
+ // do APC interaction
+ src.interact(user)
+
+/obj/machinery/power/apc/attack_alien(mob/living/carbon/alien/humanoid/user)
+ if(!user)
+ return
+ user.visible_message("\red [user.name] slashes at the [src.name]!", "\blue You slash at the [src.name]!")
+ playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1)
+
+ var/allcut = wires.IsAllCut()
+
+ if(beenhit >= pick(3, 4) && wiresexposed != 1)
+ wiresexposed = 1
+ src.update_icon()
+ src.visible_message("\red The [src.name]'s cover flies open, exposing the wires!")
+
+ else if(wiresexposed == 1 && allcut == 0)
+ wires.CutAll()
+ src.update_icon()
+ src.visible_message("\red The [src.name]'s wires are shredded!")
+ else
+ beenhit += 1
+ return
+
+
+/obj/machinery/power/apc/interact(mob/user)
+ if(!user)
+ return
+
+ if(wiresexposed /*&& (!istype(user, /mob/living/silicon))*/) //Commented out the typecheck to allow engiborgs to repair damaged apcs.
+ wires.Interact(user)
+
+ return ui_interact(user)
+
+
+/obj/machinery/power/apc/proc/get_malf_status(mob/user)
+ if (ticker && ticker.mode && (user.mind in ticker.mode.malf_ai) && istype(user, /mob/living/silicon/ai))
+ if (src.malfai == (user:parent ? user:parent : user))
+ if (src.occupier == user)
+ return 3 // 3 = User is shunted in this APC
+ else if (istype(user.loc, /obj/machinery/power/apc))
+ return 4 // 4 = User is shunted in another APC
+ else
+ return 2 // 2 = APC hacked by user, and user is in its core.
+ else
+ return 1 // 1 = APC not hacked.
+ else
+ return 0 // 0 = User is not a Malf AI
+
+
+/obj/machinery/power/apc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
+ if(!user)
+ return
+
+ var/list/data = list(
+ "locked" = locked,
+ "isOperating" = operating,
+ "externalPower" = main_status,
+ "powerCellStatus" = cell ? cell.percent() : null,
+ "chargeMode" = chargemode,
+ "chargingStatus" = charging,
+ "totalLoad" = lastused_equip + lastused_light + lastused_environ,
+ "coverLocked" = coverlocked,
+ "siliconUser" = istype(user, /mob/living/silicon),
+ "malfStatus" = get_malf_status(user),
+
+ "powerChannels" = list(
+ list(
+ "title" = "Equipment",
+ "powerLoad" = lastused_equip,
+ "status" = equipment,
+ "topicParams" = list(
+ "auto" = list("eqp" = 3),
+ "on" = list("eqp" = 2),
+ "off" = list("eqp" = 1)
+ )
+ ),
+ list(
+ "title" = "Lighting",
+ "powerLoad" = lastused_light,
+ "status" = lighting,
+ "topicParams" = list(
+ "auto" = list("lgt" = 3),
+ "on" = list("lgt" = 2),
+ "off" = list("lgt" = 1)
+ )
+ ),
+ list(
+ "title" = "Environment",
+ "powerLoad" = lastused_environ,
+ "status" = environ,
+ "topicParams" = list(
+ "auto" = list("env" = 3),
+ "on" = list("env" = 2),
+ "off" = list("env" = 1)
+ )
+ )
+ )
+ )
+
+ // update the ui if it exists, returns null if no ui is passed/found
+ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
+ if (!ui)
+ // the ui does not exist, so we'll create a new() one
+ // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
+ ui = new(user, src, ui_key, "apc.tmpl", "[area.name] - APC", 520, data["siliconUser"] ? 465 : 420)
+ // when the ui is first opened this is the data it will use
+ ui.set_initial_data(data)
+ // open the new ui window
+ ui.open()
+ // auto update every Master Controller tick
+ ui.set_auto_update(1)
+
+/obj/machinery/power/apc/proc/report()
+ return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])"
+
+/obj/machinery/power/apc/proc/update()
+ if(operating && !shorted)
+ area.power_light = (lighting > 1)
+ area.power_equip = (equipment > 1)
+ area.power_environ = (environ > 1)
+// if (area.name == "AI Chamber")
+// spawn(10)
+// world << " [area.name] [area.power_equip]"
+ else
+ area.power_light = 0
+ area.power_equip = 0
+ area.power_environ = 0
+// if (area.name == "AI Chamber")
+// world << "[area.power_equip]"
+ area.power_change()
+
+/obj/machinery/power/apc/proc/isWireCut(var/wireIndex)
+ return wires.IsIndexCut(wireIndex)
+
+
+/obj/machinery/power/apc/proc/can_use(mob/user as mob, var/loud = 0) //used by attack_hand() and Topic()
+ if (user.stat)
+ user << "\red You must be conscious to use this [src]!"
+ return 0
+ if(!user.client)
+ return 0
+ if ( ! (istype(user, /mob/living/carbon/human) || \
+ istype(user, /mob/living/silicon) || \
+ istype(user, /mob/living/carbon/monkey) /*&& ticker && ticker.mode.name == "monkey"*/) )
+ user << "\red You don't have the dexterity to use this [src]!"
+ return 0
+ if(user.restrained())
+ user << "\red You must have free hands to use this [src]"
+ return 0
+ if(user.lying)
+ user << "\red You must stand to use this [src]!"
+ return 0
+ if (istype(user, /mob/living/silicon))
+ var/mob/living/silicon/ai/AI = user
+ var/mob/living/silicon/robot/robot = user
+ if ( \
+ src.aidisabled || \
+ malfhack && istype(malfai) && \
+ ( \
+ (istype(AI) && (malfai!=AI && malfai != AI.parent)) || \
+ (istype(robot) && (robot in malfai.connected_robots)) \
+ ) \
+ )
+ if(!loud)
+ user << "\red \The [src] have AI control disabled!"
+ return 0
+ else
+ if ((!in_range(src, user) || !istype(src.loc, /turf)))
+ return 0
+
+ var/mob/living/carbon/human/H = user
+ if (istype(H))
+ if(H.getBrainLoss() >= 60)
+ for(var/mob/M in viewers(src, null))
+ M << "\red [H] stares cluelessly at [src] and drools."
+ return 0
+ else if(prob(H.getBrainLoss()))
+ user << "\red You momentarily forget how to use [src]."
+ return 0
+ return 1
+
+/obj/machinery/power/apc/Topic(href, href_list)
+ if(..())
+ return 0
+
+ if(!can_use(usr, 1))
+ return 0
+
+ if (href_list["lock"])
+ coverlocked = !coverlocked
+
+ else if (href_list["breaker"])
+ toggle_breaker()
+
+ else if (href_list["cmode"])
+ chargemode = !chargemode
+ if(!chargemode)
+ charging = 0
+ update_icon()
+
+ else if (href_list["eqp"])
+ var/val = text2num(href_list["eqp"])
+ equipment = setsubsystem(val)
+ update_icon()
+ update()
+
+ else if (href_list["lgt"])
+ var/val = text2num(href_list["lgt"])
+ lighting = setsubsystem(val)
+ update_icon()
+ update()
+
+ else if (href_list["env"])
+ var/val = text2num(href_list["env"])
+ environ = setsubsystem(val)
+ update_icon()
+ update()
+
+ else if (href_list["overload"])
+ if(istype(usr, /mob/living/silicon))
+ src.overload_lighting()
+
+ else if (href_list["malfhack"])
+ var/mob/living/silicon/ai/malfai = usr
+ if(get_malf_status(malfai)==1)
+ if (malfai.malfhacking)
+ malfai << "You are already hacking an APC."
+ return 1
+ malfai << "Beginning override of APC systems. This takes some time, and you cannot perform other actions during the process."
+ malfai.malfhack = src
+ malfai.malfhacking = 1
+ sleep(600)
+ if(src)
+ if (!src.aidisabled)
+ malfai.malfhack = null
+ malfai.malfhacking = 0
+ locked = 1
+ if (ticker.mode.config_tag == "malfunction")
+ if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
+ ticker.mode:apcs++
+ if(usr:parent)
+ src.malfai = usr:parent
+ else
+ src.malfai = usr
+ malfai << "Hack complete. The APC is now under your exclusive control."
+ update_icon()
+
+ else if (href_list["occupyapc"])
+ if(get_malf_status(usr))
+ malfoccupy(usr)
+
+ else if (href_list["deoccupyapc"])
+ if(get_malf_status(usr))
+ malfvacate()
+
+ else if (href_list["toggleaccess"])
+ if(istype(usr, /mob/living/silicon))
+ if(emagged || (stat & (BROKEN|MAINT)))
+ usr << "The APC does not respond to the command."
+ else
+ locked = !locked
+ update_icon()
+
+ return 1
+
+/obj/machinery/power/apc/proc/toggle_breaker()
+ operating = !operating
+
+ if(malfai)
+ if (ticker.mode.config_tag == "malfunction")
+ if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
+ operating ? ticker.mode:apcs++ : ticker.mode:apcs--
+
+ src.update()
+ update_icon()
+
+/obj/machinery/power/apc/proc/malfoccupy(var/mob/living/silicon/ai/malf)
+ if(!istype(malf))
+ return
+ if(istype(malf.loc, /obj/machinery/power/apc)) // Already in an APC
+ malf << "You must evacuate your current apc first."
+ return
+ if(!malf.can_shunt)
+ malf << "You cannot shunt."
+ return
+ if(src.z != 1)
+ return
+ src.occupier = new /mob/living/silicon/ai(src,malf.laws,null,1)
+ src.occupier.adjustOxyLoss(malf.getOxyLoss())
+ if(!findtext(src.occupier.name,"APC Copy"))
+ src.occupier.name = "[malf.name] APC Copy"
+ if(malf.parent)
+ src.occupier.parent = malf.parent
+ else
+ src.occupier.parent = malf
+ malf.mind.transfer_to(src.occupier)
+ src.occupier.eyeobj.name = "[src.occupier.name] (AI Eye)"
+ if(malf.parent)
+ qdel(malf)
+ src.occupier.verbs += /mob/living/silicon/ai/proc/corereturn
+ src.occupier.verbs += /datum/game_mode/malfunction/proc/takeover
+ src.occupier.cancel_camera()
+ if (seclevel2num(get_security_level()) == SEC_LEVEL_DELTA)
+ for(var/obj/item/weapon/pinpointer/point in world)
+ point.the_disk = src //the pinpointer will detect the shunted AI
+
+
+/obj/machinery/power/apc/proc/malfvacate(var/forced)
+ if(!src.occupier)
+ return
+ if(src.occupier.parent && src.occupier.parent.stat != 2)
+ src.occupier.mind.transfer_to(src.occupier.parent)
+ src.occupier.parent.adjustOxyLoss(src.occupier.getOxyLoss())
+ src.occupier.parent.cancel_camera()
+ qdel(src.occupier)
+ if (seclevel2num(get_security_level()) == SEC_LEVEL_DELTA)
+ for(var/obj/item/weapon/pinpointer/point in world)
+ for(var/datum/mind/AI_mind in ticker.mode.malf_ai)
+ var/mob/living/silicon/ai/A = AI_mind.current // the current mob the mind owns
+ if(A.stat != DEAD)
+ point.the_disk = A //The pinpointer tracks the AI back into its core.
+
+ else
+ src.occupier << "\red Primary core damaged, unable to return core processes."
+ if(forced)
+ src.occupier.loc = src.loc
+ src.occupier.death()
+ src.occupier.gib()
+ for(var/obj/item/weapon/pinpointer/point in world)
+ point.the_disk = null //the pinpointer will go back to pointing at the nuke disc.
+
+
+/obj/machinery/power/apc/proc/ion_act()
+ //intended to be exactly the same as an AI malf attack
+ if(!src.malfhack && src.z == 1)
+ if(prob(3))
+ src.locked = 1
+ if (src.cell.charge > 0)
+// world << "\red blew APC in [src.loc.loc]"
+ src.cell.charge = 0
+ cell.corrupt()
+ src.malfhack = 1
+ update_icon()
+ var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread()
+ smoke.set_up(3, 0, src.loc)
+ smoke.attach(src)
+ smoke.start()
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(3, 1, src)
+ s.start()
+ for(var/mob/M in viewers(src))
+ M.show_message("\red The [src.name] suddenly lets out a blast of smoke and some sparks!", 3, "\red You hear sizzling electronics.", 2)
+
+
+/obj/machinery/power/apc/surplus()
+ if(terminal)
+ return terminal.surplus()
+ else
+ return 0
+
+/obj/machinery/power/apc/add_load(var/amount)
+ if(terminal && terminal.powernet)
+ terminal.powernet.newload += amount
+
+/obj/machinery/power/apc/avail()
+ if(terminal)
+ return terminal.avail()
+ else
+ return 0
+
+/obj/machinery/power/apc/process()
+
+ if(stat & (BROKEN|MAINT))
+ return
+ if(!area.requires_power)
+ return
+
+
+ /*
+ if (equipment > 1) // off=0, off auto=1, on=2, on auto=3
+ use_power(src.equip_consumption, EQUIP)
+ if (lighting > 1) // off=0, off auto=1, on=2, on auto=3
+ use_power(src.light_consumption, LIGHT)
+ if (environ > 1) // off=0, off auto=1, on=2, on auto=3
+ use_power(src.environ_consumption, ENVIRON)
+
+ area.calc_lighting() */
+
+ lastused_light = area.usage(LIGHT)
+ lastused_equip = area.usage(EQUIP)
+ lastused_environ = area.usage(ENVIRON)
+ area.clear_usage()
+
+ lastused_total = lastused_light + lastused_equip + lastused_environ
+
+ //store states to update icon if any change
+ var/last_lt = lighting
+ var/last_eq = equipment
+ var/last_en = environ
+ var/last_ch = charging
+
+ var/excess = surplus()
+
+ if(!src.avail())
+ main_status = 0
+ else if(excess < 0)
+ main_status = 1
+ else
+ main_status = 2
+
+ var/perapc = 0
+ if(terminal && terminal.powernet)
+ perapc = terminal.powernet.perapc
+
+ //if(debug)
+ // world.log << "Status: [main_status] - Excess: [excess] - Last Equip: [lastused_equip] - Last Light: [lastused_light] - Longterm: [longtermpower]"
+
+ if(cell && !shorted)
+
+
+ // draw power from cell as before
+ var/cellused = min(cell.charge, CELLRATE * lastused_total) // clamp deduction to a max, amount left in cell
+ cell.use(cellused)
+
+ if(excess > 0 || perapc > lastused_total) // if power excess, or enough anyway, recharge the cell
+ // by the same amount just used
+ cell.give(cellused)
+ add_load(cellused/CELLRATE) // add the load used to recharge the cell
+
+
+ else // no excess, and not enough per-apc
+
+ if( (cell.charge/CELLRATE+perapc) >= lastused_total) // can we draw enough from cell+grid to cover last usage?
+
+ cell.charge = min(cell.maxcharge, cell.charge + CELLRATE * perapc) //recharge with what we can
+ add_load(perapc) // so draw what we can from the grid
+ charging = 0
+
+ else // not enough power available to run the last tick!
+ charging = 0
+ chargecount = 0
+ // This turns everything off in the case that there is still a charge left on the battery, just not enough to run the room.
+ equipment = autoset(equipment, 0)
+ lighting = autoset(lighting, 0)
+ environ = autoset(environ, 0)
+
+
+ // set channels depending on how much charge we have left
+
+ // Allow the APC to operate as normal if the cell can charge
+ if(charging && longtermpower < 10)
+ longtermpower += 1
+ else if(longtermpower > -10)
+ longtermpower -= 2
+
+ if(cell.charge <= 0) // zero charge, turn all off
+ equipment = autoset(equipment, 0)
+ lighting = autoset(lighting, 0)
+ environ = autoset(environ, 0)
+ area.poweralert(0, src)
+ else if(cell.percent() < 15 && longtermpower < 0) // <15%, turn off lighting & equipment
+ equipment = autoset(equipment, 2)
+ lighting = autoset(lighting, 2)
+ environ = autoset(environ, 1)
+ area.poweralert(0, src)
+ else if(cell.percent() < 30 && longtermpower < 0) // <30%, turn off equipment
+ equipment = autoset(equipment, 2)
+ lighting = autoset(lighting, 1)
+ environ = autoset(environ, 1)
+ area.poweralert(0, src)
+ else // otherwise all can be on
+ equipment = autoset(equipment, 1)
+ lighting = autoset(lighting, 1)
+ environ = autoset(environ, 1)
+ area.poweralert(1, src)
+ if(cell.percent() > 75)
+ area.poweralert(1, src)
+
+ // now trickle-charge the cell
+
+ if(chargemode && charging == 1 && operating)
+ if(excess > 0) // check to make sure we have enough to charge
+ // Max charge is perapc share, capped to cell capacity, or % per second constant (Whichever is smallest)
+/* var/ch = min(perapc, (cell.maxcharge - cell.charge), (cell.maxcharge*CHARGELEVEL))
+ add_load(ch) // Removes the power we're taking from the grid
+ cell.give(ch) // actually recharge the cell
+*/
+ var/ch = min(perapc*CELLRATE, (cell.maxcharge - cell.charge), (cell.maxcharge*CHARGELEVEL))
+ add_load(ch/CELLRATE) // Removes the power we're taking from the grid
+ cell.give(ch) // actually recharge the cell
+
+ else
+ charging = 0 // stop charging
+ chargecount = 0
+
+ // show cell as fully charged if so
+
+ if(cell.charge >= cell.maxcharge)
+ charging = 2
+
+ if(chargemode)
+ if(!charging)
+ if(excess > cell.maxcharge*CHARGELEVEL)
+ chargecount++
+ else
+ chargecount = 0
+
+ if(chargecount == 10)
+
+ chargecount = 0
+ charging = 1
+
+ else // chargemode off
+ charging = 0
+ chargecount = 0
+
+ else // no cell, switch everything off
+
+ charging = 0
+ chargecount = 0
+ equipment = autoset(equipment, 0)
+ lighting = autoset(lighting, 0)
+ environ = autoset(environ, 0)
+ area.poweralert(0, src)
+
+ // update icon & area power if anything changed
+
+ if(last_lt != lighting || last_eq != equipment || last_en != environ)
+ queue_icon_update()
+ update()
+ else if (last_ch != charging)
+ queue_icon_update()
+
+// val 0=off, 1=off(auto) 2=on 3=on(auto)
+// on 0=off, 1=on, 2=autooff
+
+obj/machinery/power/apc/proc/autoset(var/val, var/on)
+ if(on==0)
+ if(val==2) // if on, return off
+ return 0
+ else if(val==3) // if auto-on, return auto-off
+ return 1
+
+ else if(on==1)
+ if(val==1) // if auto-off, return auto-on
+ return 3
+
+ else if(on==2)
+ if(val==3) // if auto-on, return auto-off
+ return 1
+
+ return val
+
+// damage and destruction acts
+
+/obj/machinery/power/apc/meteorhit(var/obj/O as obj)
+
+ set_broken()
+ return
+
+/obj/machinery/power/apc/emp_act(severity)
+ if(cell)
+ cell.emp_act(severity)
+ if(occupier)
+ occupier.emp_act(severity)
+ lighting = 0
+ equipment = 0
+ environ = 0
+ spawn(600)
+ equipment = 3
+ environ = 3
+ ..()
+
+/obj/machinery/power/apc/ex_act(severity)
+
+ switch(severity)
+ if(1.0)
+ //set_broken() //now Del() do what we need
+ if (cell)
+ cell.ex_act(1.0) // more lags woohoo
+ qdel(src)
+ return
+ if(2.0)
+ if (prob(50))
+ set_broken()
+ if (cell && prob(50))
+ cell.ex_act(2.0)
+ if(3.0)
+ if (prob(25))
+ set_broken()
+ if (cell && prob(25))
+ cell.ex_act(3.0)
+ return
+
+/obj/machinery/power/apc/blob_act()
+ if (prob(75))
+ set_broken()
+ if (cell && prob(5))
+ cell.blob_act()
+
+/obj/machinery/power/apc/disconnect_terminal()
+ if(terminal)
+ terminal.master = null
+ terminal = null
+
+/obj/machinery/power/apc/proc/set_broken()
+ if(malfai && operating)
+ if (ticker.mode.config_tag == "malfunction")
+ if (src.z == 1) //if (is_type_in_list(get_area(src), the_station_areas))
+ ticker.mode:apcs--
+ stat |= BROKEN
+ operating = 0
+ if(occupier)
+ malfvacate(1)
+ update_icon()
+ update()
+
+// overload all the lights in this APC area
+
+/obj/machinery/power/apc/proc/overload_lighting()
+ if(/* !get_connection() || */ !operating || shorted)
+ return
+ if( cell && cell.charge>=20)
+ cell.use(20);
+ spawn(0)
+ for(var/area/A in area.related)
+ for(var/obj/machinery/light/L in A)
+ L.on = 1
+ L.broken()
+ sleep(1)
+
+/obj/machinery/power/apc/proc/shock(mob/user, prb)
+ if(!prob(prb))
+ return 0
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(5, 1, src)
+ s.start()
+ if(isalien(user))
+ return 0
+ if (electrocute_mob(user, src, src))
+ return 1
+ else
+ return 0
+
+/obj/machinery/power/apc/proc/setsubsystem(val)
+ if(cell && cell.charge > 0)
+ return (val==1) ? 0 : val
+ else if(val == 3)
+ return 1
+ else
+ return 0
+
+#undef APC_UPDATE_ICON_COOLDOWN
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 8adf3ec6d29..ba011c6777c 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -1,635 +1,635 @@
-// attach a wire to a power machine - leads from the turf you are standing on
-
-/obj/machinery/power/attackby(obj/item/weapon/W, mob/user)
-
- if(istype(W, /obj/item/stack/cable_coil))
-
- var/obj/item/stack/cable_coil/coil = W
-
- var/turf/T = user.loc
-
- if(T.intact || !istype(T, /turf/simulated/floor))
- return
-
- if(get_dist(src, user) > 1)
- return
-
- if(!directwired) // only for attaching to directwired machines
- return
-
- coil.turf_place(T, user)
- return
- else
- ..()
- return
-
-/obj/structure/cable
- level = 1
- anchored =1
- var/datum/powernet/powernet
- name = "power cable"
- desc = "A flexible superconducting cable for heavy-duty power transfer"
- icon = 'icons/obj/power_cond/power_cond_red.dmi'
- icon_state = "0-1"
- var/d1 = 0
- var/d2 = 1
- layer = 2.44 //Just below unary stuff, which is at 2.45 and above pipes, which are at 2.4
- var/cable_color = "red"
-
-/obj/structure/cable/yellow
- cable_color = "yellow"
- icon = 'icons/obj/power_cond/power_cond_yellow.dmi'
-
-/obj/structure/cable/green
- cable_color = "green"
- icon = 'icons/obj/power_cond/power_cond_green.dmi'
-
-/obj/structure/cable/blue
- cable_color = "blue"
- icon = 'icons/obj/power_cond/power_cond_blue.dmi'
-
-/obj/structure/cable/pink
- cable_color = "pink"
- icon = 'icons/obj/power_cond/power_cond_pink.dmi'
-
-/obj/structure/cable/orange
- cable_color = "orange"
- icon = 'icons/obj/power_cond/power_cond_orange.dmi'
-
-/obj/structure/cable/cyan
- cable_color = "cyan"
- icon = 'icons/obj/power_cond/power_cond_cyan.dmi'
-
-/obj/structure/cable/white
- cable_color = "white"
- icon = 'icons/obj/power_cond/power_cond_white.dmi'
-
-// the power cable object
-
-/obj/structure/cable/New()
- ..()
-
-
- // ensure d1 & d2 reflect the icon_state for entering and exiting cable
-
- var/dash = findtext(icon_state, "-")
-
- d1 = text2num( copytext( icon_state, 1, dash ) )
-
- d2 = text2num( copytext( icon_state, dash+1 ) )
-
- var/turf/T = src.loc // hide if turf is not intact
-
- if(level==1) hide(T.intact)
- cable_list += src
-
-
-/obj/structure/cable/Destroy() // called when a cable is deleted
-// if(!defer_powernet_rebuild) // set if network will be rebuilt manually
- if(powernet)
- powernet.cut_cable(src) // update the powernets
- cable_list -= src
- ..() // then go ahead and delete the cable
-
-/obj/structure/cable/hide(var/i)
-
- if(level == 1 && istype(loc, /turf))
- invisibility = i ? 101 : 0
- updateicon()
-
-/obj/structure/cable/proc/updateicon()
- if(invisibility)
- icon_state = "[d1]-[d2]-f"
- else
- icon_state = "[d1]-[d2]"
-
-
-// returns the powernet this cable belongs to
-/obj/structure/cable/proc/get_powernet() //TODO: remove this as it is obsolete
- return powernet
-
-/obj/structure/cable/attack_tk(mob/user)
- return
-
-/obj/structure/cable/attackby(obj/item/W, mob/user)
-
- var/turf/T = src.loc
- if(T.intact)
- return
-
- if(istype(W, /obj/item/weapon/wirecutters))
-
- if (shock(user, 50))
- return
-
- if(src.d1) // 0-X cables are 1 unit, X-X cables are 2 units long
- new/obj/item/stack/cable_coil(T, 2, cable_color)
- else
- new/obj/item/stack/cable_coil(T, 1, cable_color)
-
- for(var/mob/O in viewers(src, null))
- O.show_message("\red [user] cuts the cable.", 1)
-
- investigate_log("was cut by [key_name(usr, usr.client)] in [user.loc.loc]","wires")
-
- qdel(src)
- return
-
-
- else if(istype(W, /obj/item/stack/cable_coil))
- var/obj/item/stack/cable_coil/coil = W
- coil.cable_join(src, user)
-
- else if(istype(W, /obj/item/device/multitool))
-
- var/datum/powernet/PN = get_powernet() // find the powernet
-
- if(PN && (PN.avail > 0)) // is it powered?
- user << "\red [PN.avail]W in power network."
-
- else
- user << "\red The cable is not powered."
-
- shock(user, 5, 0.2)
-
- else
- if (W.flags & CONDUCT)
- shock(user, 50, 0.7)
-
- src.add_fingerprint(user)
-
-// shock the user with probability prb
-
-/obj/structure/cable/proc/shock(mob/user, prb, var/siemens_coeff = 1.0)
- if(!prob(prb))
- return 0
- if (electrocute_mob(user, powernet, src, siemens_coeff))
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(5, 1, src)
- s.start()
- return 1
- else
- return 0
-
-/obj/structure/cable/ex_act(severity)
- switch(severity)
- if(1.0)
- qdel(src)
- if(2.0)
- if (prob(50))
- new/obj/item/stack/cable_coil(src.loc, src.d1 ? 2 : 1, cable_color)
- qdel(src)
-
- if(3.0)
- if (prob(25))
- new/obj/item/stack/cable_coil(src.loc, src.d1 ? 2 : 1, cable_color)
- qdel(src)
- return
-
-// the cable coil object, used for laying cable
-
-#define MAXCOIL 30
-/obj/item/stack/cable_coil
- name = "cable coil"
- icon = 'icons/obj/power.dmi'
- icon_state = "coil_red"
- item_state = "coil_red"
- amount = MAXCOIL
- item_color = "red"
- desc = "A coil of power cable."
- throwforce = 0
- w_class = 2.0
- throw_speed = 3
- throw_range = 5
- m_amt = 50
- g_amt = 20
- flags = CONDUCT
- slot_flags = SLOT_BELT
- attack_verb = list("whipped", "lashed", "disciplined", "flogged")
-
- suicide_act(mob/user)
- if(locate(/obj/structure/stool) in user.loc)
- viewers(user) << "[user] is making a noose with the [src.name]! It looks like \he's trying to commit suicide."
- else
- viewers(user) << "[user] is strangling \himself with the [src.name]! It looks like \he's trying to commit suicide."
- return(OXYLOSS)
-
-/obj/item/stack/cable_coil/attack(mob/living/carbon/human/H, mob/user)
- if(!istype(H))
- return ..()
-
- var/obj/item/organ/limb/affecting = H.get_organ(check_zone(user.zone_sel.selecting))
- if(affecting.status == ORGAN_ROBOTIC)
- src.item_heal_robotic(H, user, 0, 30)
- src.use(1)
- return
- else
- return ..()
-
-/obj/item/stack/cable_coil/New(loc, amount = MAXCOIL, var/param_color = null)
- ..()
- src.amount = amount
- if (param_color)
- item_color = param_color
- pixel_x = rand(-2,2)
- pixel_y = rand(-2,2)
- update_icon()
-
-/obj/item/stack/cable_coil/update_icon()
- if (!item_color)
- item_color = pick("red", "yellow", "blue", "green")
- if(amount == 1)
- icon_state = "coil_[item_color]1"
- name = "cable piece"
- else if(amount == 2)
- icon_state = "coil_[item_color]2"
- name = "cable piece"
- else
- icon_state = "coil_[item_color]"
- name = "cable coil"
-
-/obj/item/stack/cable_coil/examine()
- set src in view(1)
-
- if(amount == 1)
- usr << "A short piece of power cable."
- else if(amount == 2)
- usr << "A piece of power cable."
- else
- usr << "A coil of power cable. There are [amount] lengths of cable in the coil."
-
-/obj/item/stack/cable_coil/verb/make_restraint()
- set name = "Make Cable Restraints"
- set category = "Object"
- var/mob/M = usr
-
- if(ishuman(M) && !M.restrained() && !M.stat && !M.paralysis && ! M.stunned)
- if(!istype(usr.loc,/turf)) return
- if(src.amount <= 14)
- usr << "\red You need at least 15 lengths to make restraints!"
- return
- var/obj/item/weapon/handcuffs/cable/B = new /obj/item/weapon/handcuffs/cable(usr.loc)
- B.icon_state = "cuff_[item_color]"
- usr << "\blue You wind some cable together to make some restraints."
- src.use(15)
- else
- usr << "\blue You cannot do that."
- ..()
-
-/obj/item/stack/cable_coil/attackby(obj/item/weapon/W, mob/user)
- ..()
- if( istype(W, /obj/item/weapon/wirecutters) && src.amount > 1)
- src.amount--
- new/obj/item/stack/cable_coil(user.loc, 1,item_color)
- user << "You cut a piece off the cable coil."
- src.update_icon()
- return
-
- else if( istype(W, /obj/item/stack/cable_coil) )
- var/obj/item/stack/cable_coil/C = W
- if(C.amount >= MAXCOIL)
- user << "The coil is too long, you cannot add any more cable to it."
- return
-
- if( (C.amount + src.amount <= MAXCOIL) )
- user << "You join the cable coils together."
- C.give(src.amount) // give it cable
- src.use(src.amount) // make sure this one cleans up right
- return
-
- else
- var/amt = MAXCOIL - C.amount
- user << "You transfer [amt] length\s of cable from one coil to the other."
- C.give(amt)
- src.use(amt)
- return
-
-/obj/item/stack/cable_coil/use(var/used)
- if(src.amount < used)
- return 0
- else if (src.amount == used)
- if(ismob(loc)) //handle mob icon update
- var/mob/M = loc
- M.unEquip(src)
- qdel(src)
- return 1
- else
- amount -= used
- update_icon()
- return 1
-
-/obj/item/stack/cable_coil/proc/give(var/extra)
- if(amount + extra > MAXCOIL)
- amount = MAXCOIL
- else
- amount += extra
- update_icon()
-
-// called when cable_coil is clicked on a turf/simulated/floor
-
-/obj/item/stack/cable_coil/proc/turf_place(turf/simulated/floor/F, mob/user)
-
- if(!isturf(user.loc))
- return
-
- if(get_dist(F,user) > 1)
- user << "You can't lay cable at a place that far away."
- return
-
- if(F.intact) // if floor is intact, complain
- user << "You can't lay cable there unless the floor tiles are removed."
- return
-
- else
- var/dirn
-
- if(user.loc == F)
- dirn = user.dir // if laying on the tile we're on, lay in the direction we're facing
- else
- dirn = get_dir(F, user)
-
- for(var/obj/structure/cable/LC in F)
- if((LC.d1 == dirn && LC.d2 == 0 ) || ( LC.d2 == dirn && LC.d1 == 0))
- user << "There's already a cable at that position."
- return
-
- var/obj/structure/cable/C = new(F)
-
- C.cableColor(item_color)
-
- C.d1 = 0
- C.d2 = dirn
- C.add_fingerprint(user)
- C.updateicon()
-
- C.powernet = new()
- powernets += C.powernet
- C.powernet.cables += C
-
- C.mergeConnectedNetworks(C.d2)
- C.mergeConnectedNetworksOnTurf()
-
-
- use(1)
- if (C.shock(user, 50))
- if (prob(50)) //fail
- new/obj/item/stack/cable_coil(C.loc, 1, C.cable_color)
- qdel(C)
- //src.laying = 1
- //last = C
-
-
-// called when cable_coil is click on an installed obj/cable
-
-/obj/item/stack/cable_coil/proc/cable_join(obj/structure/cable/C, mob/user)
-
- var/turf/U = user.loc
- if(!isturf(U))
- return
-
- var/turf/T = C.loc
-
- if(!isturf(T) || T.intact) // sanity checks, also stop use interacting with T-scanner revealed cable
- return
-
- if(get_dist(C, user) > 1) // make sure it's close enough
- user << "You can't lay cable at a place that far away."
- return
-
-
- if(U == T) // do nothing if we clicked a cable we're standing on
- return // may change later if can think of something logical to do
-
- var/dirn = get_dir(C, user)
-
- if(C.d1 == dirn || C.d2 == dirn) // one end of the clicked cable is pointing towards us
- if(U.intact) // can't place a cable if the floor is complete
- user << "You can't lay cable there unless the floor tiles are removed."
- return
- else
- // cable is pointing at us, we're standing on an open tile
- // so create a stub pointing at the clicked cable on our tile
-
- var/fdirn = turn(dirn, 180) // the opposite direction
-
- for(var/obj/structure/cable/LC in U) // check to make sure there's not a cable there already
- if(LC.d1 == fdirn || LC.d2 == fdirn)
- user << "There's already a cable at that position."
- return
-
- var/obj/structure/cable/NC = new(U)
- NC.cableColor(item_color)
-
- NC.d1 = 0
- NC.d2 = fdirn
- NC.add_fingerprint()
- NC.updateicon()
-
- if(C.powernet)
- NC.powernet = C.powernet
- NC.powernet.cables += NC
- NC.mergeConnectedNetworks(NC.d2)
- NC.mergeConnectedNetworksOnTurf()
- use(1)
- if (NC.shock(user, 50))
- if (prob(50)) //fail
- new/obj/item/stack/cable_coil(NC.loc, 1, NC.cable_color)
- qdel(NC)
-
- return
- else if(C.d1 == 0) // exisiting cable doesn't point at our position, so see if it's a stub
- // if so, make it a full cable pointing from it's old direction to our dirn
- var/nd1 = C.d2 // these will be the new directions
- var/nd2 = dirn
-
-
- if(nd1 > nd2) // swap directions to match icons/states
- nd1 = dirn
- nd2 = C.d2
-
-
- for(var/obj/structure/cable/LC in T) // check to make sure there's no matching cable
- if(LC == C) // skip the cable we're interacting with
- continue
- if((LC.d1 == nd1 && LC.d2 == nd2) || (LC.d1 == nd2 && LC.d2 == nd1) ) // make sure no cable matches either direction
- user << "There's already a cable at that position."
- return
-
-
- C.cableColor(item_color)
-
- C.d1 = nd1
- C.d2 = nd2
-
- C.add_fingerprint()
- C.updateicon()
-
-
- C.mergeConnectedNetworks(C.d1)
- C.mergeConnectedNetworks(C.d2)
- C.mergeConnectedNetworksOnTurf()
-
- use(1)
- if (C.shock(user, 50))
- if (prob(50)) //fail
- new/obj/item/stack/cable_coil(C.loc, 2, C.cable_color)
- qdel(C)
- return
-
- C.denode()// this call may have disconnected some cables that terminated on the centre of the turf, if so split the powernets.
- return
-
-/obj/structure/cable/proc/mergeConnectedNetworks(var/direction)
- var/turf/TB
- if(!(d1 == direction || d2 == direction))
- return
- TB = get_step(src, direction)
-
- for(var/obj/structure/cable/TC in TB)
-
- if(!TC)
- continue
-
- if(src == TC)
- continue
-
- var/fdir = (!direction)? 0 : turn(direction, 180)
-
- if(TC.d1 == fdir || TC.d2 == fdir)
-
- if(!TC.powernet)
- TC.powernet = new()
- powernets += TC.powernet
- TC.powernet.cables += TC
-
- if(powernet)
- merge_powernets(powernet,TC.powernet)
- else
- powernet = TC.powernet
- powernet.cables += src
-
-
-
-
-/obj/structure/cable/proc/mergeConnectedNetworksOnTurf()
- if(!powernet)
- powernet = new()
- powernets += powernet
- powernet.cables += src
-
- for(var/AM in loc)
- if(istype(AM,/obj/structure/cable))
- var/obj/structure/cable/C = AM
- if(C.d1 == 0 && d1==0) //only connected if they are both "nodes"
- if(C.powernet == powernet) continue
- if(C.powernet)
- merge_powernets(powernet, C.powernet)
- else
- C.powernet = powernet
- powernet.cables += C
-
- else if(istype(AM,/obj/machinery/power/apc))
- var/obj/machinery/power/apc/N = AM
- if(!N.terminal) continue
- if(N.terminal.powernet)
- merge_powernets(powernet, N.terminal.powernet)
- else
- N.terminal.powernet = powernet
- powernet.nodes[N.terminal] = N.terminal
-
- else if(istype(AM,/obj/machinery/power))
- var/obj/machinery/power/M = AM
- if(M.powernet == powernet) continue
- if(M.powernet)
- merge_powernets(powernet, M.powernet)
- else
- M.powernet = powernet
- powernet.nodes[M] = M
-
-
-obj/structure/cable/proc/cableColor(var/colorC)
- var/color_n = "red"
- if(colorC)
- color_n = colorC
- cable_color = color_n
- switch(colorC)
- if("red")
- icon = 'icons/obj/power_cond/power_cond_red.dmi'
- if("yellow")
- icon = 'icons/obj/power_cond/power_cond_yellow.dmi'
- if("green")
- icon = 'icons/obj/power_cond/power_cond_green.dmi'
- if("blue")
- icon = 'icons/obj/power_cond/power_cond_blue.dmi'
- if("pink")
- icon = 'icons/obj/power_cond/power_cond_pink.dmi'
- if("orange")
- icon = 'icons/obj/power_cond/power_cond_orange.dmi'
- if("cyan")
- icon = 'icons/obj/power_cond/power_cond_cyan.dmi'
- if("white")
- icon = 'icons/obj/power_cond/power_cond_white.dmi'
-
-obj/structure/cable/proc/add_avail(var/amount)
- if(powernet)
- powernet.newavail += amount
-
-obj/structure/cable/proc/add_load(var/amount)
- if(powernet)
- powernet.newload += amount
-
-obj/structure/cable/proc/surplus()
- if(powernet)
- return powernet.avail-powernet.load
- else
- return 0
-
-obj/structure/cable/proc/avail()
- if(powernet)
- return powernet.avail
- else
- return 0
-
-/obj/item/stack/cable_coil/cut
- item_state = "coil_red2"
-
-/obj/item/stack/cable_coil/cut/New(loc)
- ..()
- src.amount = rand(1,2)
- pixel_x = rand(-2,2)
- pixel_y = rand(-2,2)
- update_icon()
-
-/obj/item/stack/cable_coil/yellow
- item_color = "yellow"
- icon_state = "coil_yellow"
-
-/obj/item/stack/cable_coil/blue
- item_color = "blue"
- icon_state = "coil_blue"
- item_state = "coil_blue"
-
-/obj/item/stack/cable_coil/green
- item_color = "green"
- icon_state = "coil_green"
-
-/obj/item/stack/cable_coil/pink
- item_color = "pink"
- icon_state = "coil_pink"
-
-/obj/item/stack/cable_coil/orange
- item_color = "orange"
- icon_state = "coil_orange"
-
-/obj/item/stack/cable_coil/cyan
- item_color = "cyan"
- icon_state = "coil_cyan"
-
-/obj/item/stack/cable_coil/white
- item_color = "white"
- icon_state = "coil_white"
-
-/obj/item/stack/cable_coil/random/New()
- item_color = pick("red","yellow","green","blue","pink")
- icon_state = "coil_[item_color]"
- ..()
+// attach a wire to a power machine - leads from the turf you are standing on
+
+/obj/machinery/power/attackby(obj/item/weapon/W, mob/user)
+
+ if(istype(W, /obj/item/stack/cable_coil))
+
+ var/obj/item/stack/cable_coil/coil = W
+
+ var/turf/T = user.loc
+
+ if(T.intact || !istype(T, /turf/simulated/floor))
+ return
+
+ if(get_dist(src, user) > 1)
+ return
+
+ if(!directwired) // only for attaching to directwired machines
+ return
+
+ coil.turf_place(T, user)
+ return
+ else
+ ..()
+ return
+
+/obj/structure/cable
+ level = 1
+ anchored =1
+ var/datum/powernet/powernet
+ name = "power cable"
+ desc = "A flexible superconducting cable for heavy-duty power transfer"
+ icon = 'icons/obj/power_cond/power_cond_red.dmi'
+ icon_state = "0-1"
+ var/d1 = 0
+ var/d2 = 1
+ layer = 2.44 //Just below unary stuff, which is at 2.45 and above pipes, which are at 2.4
+ var/cable_color = "red"
+
+/obj/structure/cable/yellow
+ cable_color = "yellow"
+ icon = 'icons/obj/power_cond/power_cond_yellow.dmi'
+
+/obj/structure/cable/green
+ cable_color = "green"
+ icon = 'icons/obj/power_cond/power_cond_green.dmi'
+
+/obj/structure/cable/blue
+ cable_color = "blue"
+ icon = 'icons/obj/power_cond/power_cond_blue.dmi'
+
+/obj/structure/cable/pink
+ cable_color = "pink"
+ icon = 'icons/obj/power_cond/power_cond_pink.dmi'
+
+/obj/structure/cable/orange
+ cable_color = "orange"
+ icon = 'icons/obj/power_cond/power_cond_orange.dmi'
+
+/obj/structure/cable/cyan
+ cable_color = "cyan"
+ icon = 'icons/obj/power_cond/power_cond_cyan.dmi'
+
+/obj/structure/cable/white
+ cable_color = "white"
+ icon = 'icons/obj/power_cond/power_cond_white.dmi'
+
+// the power cable object
+
+/obj/structure/cable/New()
+ ..()
+
+
+ // ensure d1 & d2 reflect the icon_state for entering and exiting cable
+
+ var/dash = findtext(icon_state, "-")
+
+ d1 = text2num( copytext( icon_state, 1, dash ) )
+
+ d2 = text2num( copytext( icon_state, dash+1 ) )
+
+ var/turf/T = src.loc // hide if turf is not intact
+
+ if(level==1) hide(T.intact)
+ cable_list += src
+
+
+/obj/structure/cable/Destroy() // called when a cable is deleted
+// if(!defer_powernet_rebuild) // set if network will be rebuilt manually
+ if(powernet)
+ powernet.cut_cable(src) // update the powernets
+ cable_list -= src
+ ..() // then go ahead and delete the cable
+
+/obj/structure/cable/hide(var/i)
+
+ if(level == 1 && istype(loc, /turf))
+ invisibility = i ? 101 : 0
+ updateicon()
+
+/obj/structure/cable/proc/updateicon()
+ if(invisibility)
+ icon_state = "[d1]-[d2]-f"
+ else
+ icon_state = "[d1]-[d2]"
+
+
+// returns the powernet this cable belongs to
+/obj/structure/cable/proc/get_powernet() //TODO: remove this as it is obsolete
+ return powernet
+
+/obj/structure/cable/attack_tk(mob/user)
+ return
+
+/obj/structure/cable/attackby(obj/item/W, mob/user)
+
+ var/turf/T = src.loc
+ if(T.intact)
+ return
+
+ if(istype(W, /obj/item/weapon/wirecutters))
+
+ if (shock(user, 50))
+ return
+
+ if(src.d1) // 0-X cables are 1 unit, X-X cables are 2 units long
+ new/obj/item/stack/cable_coil(T, 2, cable_color)
+ else
+ new/obj/item/stack/cable_coil(T, 1, cable_color)
+
+ for(var/mob/O in viewers(src, null))
+ O.show_message("\red [user] cuts the cable.", 1)
+
+ investigate_log("was cut by [key_name(usr, usr.client)] in [user.loc.loc]","wires")
+
+ qdel(src)
+ return
+
+
+ else if(istype(W, /obj/item/stack/cable_coil))
+ var/obj/item/stack/cable_coil/coil = W
+ coil.cable_join(src, user)
+
+ else if(istype(W, /obj/item/device/multitool))
+
+ var/datum/powernet/PN = get_powernet() // find the powernet
+
+ if(PN && (PN.avail > 0)) // is it powered?
+ user << "\red [PN.avail]W in power network."
+
+ else
+ user << "\red The cable is not powered."
+
+ shock(user, 5, 0.2)
+
+ else
+ if (W.flags & CONDUCT)
+ shock(user, 50, 0.7)
+
+ src.add_fingerprint(user)
+
+// shock the user with probability prb
+
+/obj/structure/cable/proc/shock(mob/user, prb, var/siemens_coeff = 1.0)
+ if(!prob(prb))
+ return 0
+ if (electrocute_mob(user, powernet, src, siemens_coeff))
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(5, 1, src)
+ s.start()
+ return 1
+ else
+ return 0
+
+/obj/structure/cable/ex_act(severity)
+ switch(severity)
+ if(1.0)
+ qdel(src)
+ if(2.0)
+ if (prob(50))
+ new/obj/item/stack/cable_coil(src.loc, src.d1 ? 2 : 1, cable_color)
+ qdel(src)
+
+ if(3.0)
+ if (prob(25))
+ new/obj/item/stack/cable_coil(src.loc, src.d1 ? 2 : 1, cable_color)
+ qdel(src)
+ return
+
+// the cable coil object, used for laying cable
+
+#define MAXCOIL 30
+/obj/item/stack/cable_coil
+ name = "cable coil"
+ icon = 'icons/obj/power.dmi'
+ icon_state = "coil_red"
+ item_state = "coil_red"
+ amount = MAXCOIL
+ item_color = "red"
+ desc = "A coil of power cable."
+ throwforce = 0
+ w_class = 2.0
+ throw_speed = 3
+ throw_range = 5
+ m_amt = 50
+ g_amt = 20
+ flags = CONDUCT
+ slot_flags = SLOT_BELT
+ attack_verb = list("whipped", "lashed", "disciplined", "flogged")
+
+ suicide_act(mob/user)
+ if(locate(/obj/structure/stool) in user.loc)
+ viewers(user) << "[user] is making a noose with the [src.name]! It looks like \he's trying to commit suicide."
+ else
+ viewers(user) << "[user] is strangling \himself with the [src.name]! It looks like \he's trying to commit suicide."
+ return(OXYLOSS)
+
+/obj/item/stack/cable_coil/attack(mob/living/carbon/human/H, mob/user)
+ if(!istype(H))
+ return ..()
+
+ var/obj/item/organ/limb/affecting = H.get_organ(check_zone(user.zone_sel.selecting))
+ if(affecting.status == ORGAN_ROBOTIC)
+ src.item_heal_robotic(H, user, 0, 30)
+ src.use(1)
+ return
+ else
+ return ..()
+
+/obj/item/stack/cable_coil/New(loc, amount = MAXCOIL, var/param_color = null)
+ ..()
+ src.amount = amount
+ if (param_color)
+ item_color = param_color
+ pixel_x = rand(-2,2)
+ pixel_y = rand(-2,2)
+ update_icon()
+
+/obj/item/stack/cable_coil/update_icon()
+ if (!item_color)
+ item_color = pick("red", "yellow", "blue", "green")
+ if(amount == 1)
+ icon_state = "coil_[item_color]1"
+ name = "cable piece"
+ else if(amount == 2)
+ icon_state = "coil_[item_color]2"
+ name = "cable piece"
+ else
+ icon_state = "coil_[item_color]"
+ name = "cable coil"
+
+/obj/item/stack/cable_coil/examine()
+ set src in view(1)
+
+ if(amount == 1)
+ usr << "A short piece of power cable."
+ else if(amount == 2)
+ usr << "A piece of power cable."
+ else
+ usr << "A coil of power cable. There are [amount] lengths of cable in the coil."
+
+/obj/item/stack/cable_coil/verb/make_restraint()
+ set name = "Make Cable Restraints"
+ set category = "Object"
+ var/mob/M = usr
+
+ if(ishuman(M) && !M.restrained() && !M.stat && !M.paralysis && ! M.stunned)
+ if(!istype(usr.loc,/turf)) return
+ if(src.amount <= 14)
+ usr << "\red You need at least 15 lengths to make restraints!"
+ return
+ var/obj/item/weapon/handcuffs/cable/B = new /obj/item/weapon/handcuffs/cable(usr.loc)
+ B.icon_state = "cuff_[item_color]"
+ usr << "\blue You wind some cable together to make some restraints."
+ src.use(15)
+ else
+ usr << "\blue You cannot do that."
+ ..()
+
+/obj/item/stack/cable_coil/attackby(obj/item/weapon/W, mob/user)
+ ..()
+ if( istype(W, /obj/item/weapon/wirecutters) && src.amount > 1)
+ src.amount--
+ new/obj/item/stack/cable_coil(user.loc, 1,item_color)
+ user << "You cut a piece off the cable coil."
+ src.update_icon()
+ return
+
+ else if( istype(W, /obj/item/stack/cable_coil) )
+ var/obj/item/stack/cable_coil/C = W
+ if(C.amount >= MAXCOIL)
+ user << "The coil is too long, you cannot add any more cable to it."
+ return
+
+ if( (C.amount + src.amount <= MAXCOIL) )
+ user << "You join the cable coils together."
+ C.give(src.amount) // give it cable
+ src.use(src.amount) // make sure this one cleans up right
+ return
+
+ else
+ var/amt = MAXCOIL - C.amount
+ user << "You transfer [amt] length\s of cable from one coil to the other."
+ C.give(amt)
+ src.use(amt)
+ return
+
+/obj/item/stack/cable_coil/use(var/used)
+ if(src.amount < used)
+ return 0
+ else if (src.amount == used)
+ if(ismob(loc)) //handle mob icon update
+ var/mob/M = loc
+ M.unEquip(src)
+ qdel(src)
+ return 1
+ else
+ amount -= used
+ update_icon()
+ return 1
+
+/obj/item/stack/cable_coil/proc/give(var/extra)
+ if(amount + extra > MAXCOIL)
+ amount = MAXCOIL
+ else
+ amount += extra
+ update_icon()
+
+// called when cable_coil is clicked on a turf/simulated/floor
+
+/obj/item/stack/cable_coil/proc/turf_place(turf/simulated/floor/F, mob/user)
+
+ if(!isturf(user.loc))
+ return
+
+ if(get_dist(F,user) > 1)
+ user << "You can't lay cable at a place that far away."
+ return
+
+ if(F.intact) // if floor is intact, complain
+ user << "You can't lay cable there unless the floor tiles are removed."
+ return
+
+ else
+ var/dirn
+
+ if(user.loc == F)
+ dirn = user.dir // if laying on the tile we're on, lay in the direction we're facing
+ else
+ dirn = get_dir(F, user)
+
+ for(var/obj/structure/cable/LC in F)
+ if((LC.d1 == dirn && LC.d2 == 0 ) || ( LC.d2 == dirn && LC.d1 == 0))
+ user << "There's already a cable at that position."
+ return
+
+ var/obj/structure/cable/C = new(F)
+
+ C.cableColor(item_color)
+
+ C.d1 = 0
+ C.d2 = dirn
+ C.add_fingerprint(user)
+ C.updateicon()
+
+ C.powernet = new()
+ powernets += C.powernet
+ C.powernet.cables += C
+
+ C.mergeConnectedNetworks(C.d2)
+ C.mergeConnectedNetworksOnTurf()
+
+
+ use(1)
+ if (C.shock(user, 50))
+ if (prob(50)) //fail
+ new/obj/item/stack/cable_coil(C.loc, 1, C.cable_color)
+ qdel(C)
+ //src.laying = 1
+ //last = C
+
+
+// called when cable_coil is click on an installed obj/cable
+
+/obj/item/stack/cable_coil/proc/cable_join(obj/structure/cable/C, mob/user)
+
+ var/turf/U = user.loc
+ if(!isturf(U))
+ return
+
+ var/turf/T = C.loc
+
+ if(!isturf(T) || T.intact) // sanity checks, also stop use interacting with T-scanner revealed cable
+ return
+
+ if(get_dist(C, user) > 1) // make sure it's close enough
+ user << "You can't lay cable at a place that far away."
+ return
+
+
+ if(U == T) // do nothing if we clicked a cable we're standing on
+ return // may change later if can think of something logical to do
+
+ var/dirn = get_dir(C, user)
+
+ if(C.d1 == dirn || C.d2 == dirn) // one end of the clicked cable is pointing towards us
+ if(U.intact) // can't place a cable if the floor is complete
+ user << "You can't lay cable there unless the floor tiles are removed."
+ return
+ else
+ // cable is pointing at us, we're standing on an open tile
+ // so create a stub pointing at the clicked cable on our tile
+
+ var/fdirn = turn(dirn, 180) // the opposite direction
+
+ for(var/obj/structure/cable/LC in U) // check to make sure there's not a cable there already
+ if(LC.d1 == fdirn || LC.d2 == fdirn)
+ user << "There's already a cable at that position."
+ return
+
+ var/obj/structure/cable/NC = new(U)
+ NC.cableColor(item_color)
+
+ NC.d1 = 0
+ NC.d2 = fdirn
+ NC.add_fingerprint()
+ NC.updateicon()
+
+ if(C.powernet)
+ NC.powernet = C.powernet
+ NC.powernet.cables += NC
+ NC.mergeConnectedNetworks(NC.d2)
+ NC.mergeConnectedNetworksOnTurf()
+ use(1)
+ if (NC.shock(user, 50))
+ if (prob(50)) //fail
+ new/obj/item/stack/cable_coil(NC.loc, 1, NC.cable_color)
+ qdel(NC)
+
+ return
+ else if(C.d1 == 0) // exisiting cable doesn't point at our position, so see if it's a stub
+ // if so, make it a full cable pointing from it's old direction to our dirn
+ var/nd1 = C.d2 // these will be the new directions
+ var/nd2 = dirn
+
+
+ if(nd1 > nd2) // swap directions to match icons/states
+ nd1 = dirn
+ nd2 = C.d2
+
+
+ for(var/obj/structure/cable/LC in T) // check to make sure there's no matching cable
+ if(LC == C) // skip the cable we're interacting with
+ continue
+ if((LC.d1 == nd1 && LC.d2 == nd2) || (LC.d1 == nd2 && LC.d2 == nd1) ) // make sure no cable matches either direction
+ user << "There's already a cable at that position."
+ return
+
+
+ C.cableColor(item_color)
+
+ C.d1 = nd1
+ C.d2 = nd2
+
+ C.add_fingerprint()
+ C.updateicon()
+
+
+ C.mergeConnectedNetworks(C.d1)
+ C.mergeConnectedNetworks(C.d2)
+ C.mergeConnectedNetworksOnTurf()
+
+ use(1)
+ if (C.shock(user, 50))
+ if (prob(50)) //fail
+ new/obj/item/stack/cable_coil(C.loc, 2, C.cable_color)
+ qdel(C)
+ return
+
+ C.denode()// this call may have disconnected some cables that terminated on the centre of the turf, if so split the powernets.
+ return
+
+/obj/structure/cable/proc/mergeConnectedNetworks(var/direction)
+ var/turf/TB
+ if(!(d1 == direction || d2 == direction))
+ return
+ TB = get_step(src, direction)
+
+ for(var/obj/structure/cable/TC in TB)
+
+ if(!TC)
+ continue
+
+ if(src == TC)
+ continue
+
+ var/fdir = (!direction)? 0 : turn(direction, 180)
+
+ if(TC.d1 == fdir || TC.d2 == fdir)
+
+ if(!TC.powernet)
+ TC.powernet = new()
+ powernets += TC.powernet
+ TC.powernet.cables += TC
+
+ if(powernet)
+ merge_powernets(powernet,TC.powernet)
+ else
+ powernet = TC.powernet
+ powernet.cables += src
+
+
+
+
+/obj/structure/cable/proc/mergeConnectedNetworksOnTurf()
+ if(!powernet)
+ powernet = new()
+ powernets += powernet
+ powernet.cables += src
+
+ for(var/AM in loc)
+ if(istype(AM,/obj/structure/cable))
+ var/obj/structure/cable/C = AM
+ if(C.d1 == 0 && d1==0) //only connected if they are both "nodes"
+ if(C.powernet == powernet) continue
+ if(C.powernet)
+ merge_powernets(powernet, C.powernet)
+ else
+ C.powernet = powernet
+ powernet.cables += C
+
+ else if(istype(AM,/obj/machinery/power/apc))
+ var/obj/machinery/power/apc/N = AM
+ if(!N.terminal) continue
+ if(N.terminal.powernet)
+ merge_powernets(powernet, N.terminal.powernet)
+ else
+ N.terminal.powernet = powernet
+ powernet.nodes[N.terminal] = N.terminal
+
+ else if(istype(AM,/obj/machinery/power))
+ var/obj/machinery/power/M = AM
+ if(M.powernet == powernet) continue
+ if(M.powernet)
+ merge_powernets(powernet, M.powernet)
+ else
+ M.powernet = powernet
+ powernet.nodes[M] = M
+
+
+obj/structure/cable/proc/cableColor(var/colorC)
+ var/color_n = "red"
+ if(colorC)
+ color_n = colorC
+ cable_color = color_n
+ switch(colorC)
+ if("red")
+ icon = 'icons/obj/power_cond/power_cond_red.dmi'
+ if("yellow")
+ icon = 'icons/obj/power_cond/power_cond_yellow.dmi'
+ if("green")
+ icon = 'icons/obj/power_cond/power_cond_green.dmi'
+ if("blue")
+ icon = 'icons/obj/power_cond/power_cond_blue.dmi'
+ if("pink")
+ icon = 'icons/obj/power_cond/power_cond_pink.dmi'
+ if("orange")
+ icon = 'icons/obj/power_cond/power_cond_orange.dmi'
+ if("cyan")
+ icon = 'icons/obj/power_cond/power_cond_cyan.dmi'
+ if("white")
+ icon = 'icons/obj/power_cond/power_cond_white.dmi'
+
+obj/structure/cable/proc/add_avail(var/amount)
+ if(powernet)
+ powernet.newavail += amount
+
+obj/structure/cable/proc/add_load(var/amount)
+ if(powernet)
+ powernet.newload += amount
+
+obj/structure/cable/proc/surplus()
+ if(powernet)
+ return powernet.avail-powernet.load
+ else
+ return 0
+
+obj/structure/cable/proc/avail()
+ if(powernet)
+ return powernet.avail
+ else
+ return 0
+
+/obj/item/stack/cable_coil/cut
+ item_state = "coil_red2"
+
+/obj/item/stack/cable_coil/cut/New(loc)
+ ..()
+ src.amount = rand(1,2)
+ pixel_x = rand(-2,2)
+ pixel_y = rand(-2,2)
+ update_icon()
+
+/obj/item/stack/cable_coil/yellow
+ item_color = "yellow"
+ icon_state = "coil_yellow"
+
+/obj/item/stack/cable_coil/blue
+ item_color = "blue"
+ icon_state = "coil_blue"
+ item_state = "coil_blue"
+
+/obj/item/stack/cable_coil/green
+ item_color = "green"
+ icon_state = "coil_green"
+
+/obj/item/stack/cable_coil/pink
+ item_color = "pink"
+ icon_state = "coil_pink"
+
+/obj/item/stack/cable_coil/orange
+ item_color = "orange"
+ icon_state = "coil_orange"
+
+/obj/item/stack/cable_coil/cyan
+ item_color = "cyan"
+ icon_state = "coil_cyan"
+
+/obj/item/stack/cable_coil/white
+ item_color = "white"
+ icon_state = "coil_white"
+
+/obj/item/stack/cable_coil/random/New()
+ item_color = pick("red","yellow","green","blue","pink")
+ icon_state = "coil_[item_color]"
+ ..()
diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm
index 701198c2db5..f0e7168ad13 100644
--- a/code/modules/power/gravitygenerator.dm
+++ b/code/modules/power/gravitygenerator.dm
@@ -89,6 +89,14 @@ var/const/GRAV_NEEDS_WRENCH = 3
middle.overlays += "activated"
update_list()
+//
+// Generator an admin can spawn
+//
+
+/obj/machinery/gravity_generator/main/station/admin/New()
+ ..()
+ initialize()
+
//
// Main Generator with the main code
//
@@ -111,6 +119,7 @@ var/const/GRAV_NEEDS_WRENCH = 3
var/broken_state = 0
/obj/machinery/gravity_generator/main/Destroy() // If we somehow get deleted, remove all of our other parts.
+ investigate_log("was destroyed!", "gravity")
on = 0
update_list()
for(var/obj/machinery/gravity_generator/part/O in parts)
@@ -148,6 +157,7 @@ var/const/GRAV_NEEDS_WRENCH = 3
breaker = 0
set_power()
set_state(0)
+ investigate_log("has broken down.", "gravity")
/obj/machinery/gravity_generator/main/set_fix()
..()
@@ -231,6 +241,7 @@ var/const/GRAV_NEEDS_WRENCH = 3
if(href_list["gentoggle"])
breaker = !breaker
+ investigate_log("was toggled [breaker ? "ON" : "OFF"] by [usr.key].", "gravity")
set_power()
src.updateUsrDialog()
@@ -238,6 +249,7 @@ var/const/GRAV_NEEDS_WRENCH = 3
/obj/machinery/gravity_generator/main/power_change()
..()
+ investigate_log("has [stat & NOPOWER ? "lost" : "regained"] power.", "gravity")
set_power()
/obj/machinery/gravity_generator/main/get_status()
@@ -259,6 +271,7 @@ var/const/GRAV_NEEDS_WRENCH = 3
new_state = 1
charging_state = new_state ? POWER_UP : POWER_DOWN // Startup sequence animation.
+ investigate_log("is now [charging_state == POWER_UP ? "charging" : "discharging"].", "gravity")
update_icon()
// Set the state of the gravity.
@@ -268,12 +281,17 @@ var/const/GRAV_NEEDS_WRENCH = 3
use_power = on ? 2 : 1
// Sound the alert if gravity was just enabled or disabled.
var/alert = 0
+ var/area/area = get_area(src)
if(new_state) // If we turned on
if(gravity_in_level() == 0)
alert = 1
+ investigate_log("was brought online and is now producing gravity for this level.", "gravity")
+ message_admins("The gravity generator was brought online. ([area.name])")
else
if(gravity_in_level() == 1)
alert = 1
+ investigate_log("was brought offline and there is now no gravity for this level.", "gravity")
+ message_admins("The gravity generator was brought offline with no backup generator. ([area.name])")
update_icon()
update_list()
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index 2af337929b7..36789ac7d87 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -1,742 +1,742 @@
-// The lighting system
-//
-// consists of light fixtures (/obj/machinery/light) and light tube/bulb items (/obj/item/weapon/light)
-
-
-// status values shared between lighting fixtures and items
-#define LIGHT_OK 0
-#define LIGHT_EMPTY 1
-#define LIGHT_BROKEN 2
-#define LIGHT_BURNED 3
-
-
-
-/obj/item/light_fixture_frame
- name = "light fixture frame"
- desc = "Used for building lights."
- icon = 'icons/obj/lighting.dmi'
- icon_state = "tube-construct-item"
- flags = CONDUCT
- var/fixture_type = "tube"
- var/obj/machinery/light/newlight = null
- var/sheets_refunded = 2
-
-/obj/item/light_fixture_frame/attackby(obj/item/weapon/W as obj, mob/user as mob)
- if (istype(W, /obj/item/weapon/wrench))
- new /obj/item/stack/sheet/metal( get_turf(src.loc), sheets_refunded )
- qdel(src)
- return
- ..()
-
-/obj/item/light_fixture_frame/proc/try_build(turf/on_wall)
- if (get_dist(on_wall,usr)>1)
- return
- var/ndir = get_dir(usr,on_wall)
- if (!(ndir in cardinal))
- return
- var/turf/loc = get_turf(usr)
- if (!istype(loc, /turf/simulated/floor))
- usr << "\red [src.name] cannot be placed on this spot."
- return
- usr << "Attaching [src] to the wall."
- playsound(src.loc, 'sound/machines/click.ogg', 75, 1)
- var/constrdir = usr.dir
- var/constrloc = usr.loc
- if (!do_after(usr, 30))
- return
- switch(fixture_type)
- if("bulb")
- newlight = new /obj/machinery/light_construct/small(constrloc)
- if("tube")
- newlight = new /obj/machinery/light_construct(constrloc)
- newlight.dir = constrdir
- newlight.fingerprints = src.fingerprints
- newlight.fingerprintshidden = src.fingerprintshidden
- newlight.fingerprintslast = src.fingerprintslast
-
- usr.visible_message("[usr.name] attaches [src] to the wall.", \
- "You attach [src] to the wall.")
- qdel(src)
-
-/obj/item/light_fixture_frame/small
- name = "small light fixture frame"
- desc = "Used for building small lights."
- icon = 'icons/obj/lighting.dmi'
- icon_state = "bulb-construct-item"
- flags = CONDUCT
- fixture_type = "bulb"
- sheets_refunded = 1
-
-/obj/machinery/light_construct
- name = "light fixture frame"
- desc = "A light fixture under construction."
- icon = 'icons/obj/lighting.dmi'
- icon_state = "tube-construct-stage1"
- anchored = 1
- layer = 5
- var/stage = 1
- var/fixture_type = "tube"
- var/sheets_refunded = 2
- var/obj/machinery/light/newlight = null
-
-/obj/machinery/light_construct/New()
- ..()
- if (fixture_type == "bulb")
- icon_state = "bulb-construct-stage1"
-
-/obj/machinery/light_construct/examine()
- set src in view()
- ..()
- if (!(usr in view(2))) return
- switch(src.stage)
- if(1)
- usr << "It's an empty frame."
- return
- if(2)
- usr << "It's wired."
- return
- if(3)
- usr << "The casing is closed."
- return
-
-/obj/machinery/light_construct/attackby(obj/item/weapon/W as obj, mob/user as mob)
- src.add_fingerprint(user)
- if (istype(W, /obj/item/weapon/wrench))
- if (src.stage == 1)
- playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
- usr << "You begin deconstructing [src]."
- if (!do_after(usr, 30))
- return
- new /obj/item/stack/sheet/metal( get_turf(src.loc), sheets_refunded )
- user.visible_message("[user.name] deconstructs [src].", \
- "You deconstruct [src].", "You hear a noise.")
- playsound(src.loc, 'sound/items/Deconstruct.ogg', 75, 1)
- qdel(src)
- if (src.stage == 2)
- usr << "You have to remove the wires first."
- return
-
- if (src.stage == 3)
- usr << "You have to unscrew the case first."
- return
-
- if(istype(W, /obj/item/weapon/wirecutters))
- if (src.stage != 2) return
- src.stage = 1
- switch(fixture_type)
- if ("tube")
- src.icon_state = "tube-construct-stage1"
- if("bulb")
- src.icon_state = "bulb-construct-stage1"
- new /obj/item/stack/cable_coil(get_turf(src.loc), 1, "red")
- user.visible_message("[user.name] removes the wiring from [src].", \
- "You remove the wiring from [src].", "You hear a noise.")
- playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1)
- return
-
- if(istype(W, /obj/item/stack/cable_coil))
- if (src.stage != 1) return
- var/obj/item/stack/cable_coil/coil = W
- coil.use(1)
- switch(fixture_type)
- if ("tube")
- src.icon_state = "tube-construct-stage2"
- if("bulb")
- src.icon_state = "bulb-construct-stage2"
- src.stage = 2
- user.visible_message("[user.name] adds wires to [src].", \
- "You add wires to [src].")
- return
-
- if(istype(W, /obj/item/weapon/screwdriver))
- if (src.stage == 2)
- switch(fixture_type)
- if ("tube")
- src.icon_state = "tube-empty"
- if("bulb")
- src.icon_state = "bulb-empty"
- src.stage = 3
- user.visible_message("[user.name] closes [src]'s casing.", \
- "You close [src]'s casing.", "You hear a noise.")
- playsound(src.loc, 'sound/items/Screwdriver.ogg', 75, 1)
-
- switch(fixture_type)
-
- if("tube")
- newlight = new /obj/machinery/light/built(src.loc)
- if ("bulb")
- newlight = new /obj/machinery/light/small/built(src.loc)
-
- newlight.dir = src.dir
- src.transfer_fingerprints_to(newlight)
- qdel(src)
- return
- ..()
-
-/obj/machinery/light_construct/small
- name = "small light fixture frame"
- desc = "A small light fixture under construction."
- icon = 'icons/obj/lighting.dmi'
- icon_state = "bulb-construct-stage1"
- anchored = 1
- layer = 5
- stage = 1
- fixture_type = "bulb"
- sheets_refunded = 1
-
-// the standard tube light fixture
-/obj/machinery/light
- name = "light fixture"
- icon = 'icons/obj/lighting.dmi'
- var/base_state = "tube" // base description and icon_state
- icon_state = "tube1"
- desc = "A lighting fixture."
- anchored = 1
- layer = 5 // They were appearing under mobs which is a little weird - Ostaf
- use_power = 2
- idle_power_usage = 2
- active_power_usage = 20
- power_channel = LIGHT //Lights are calc'd via area so they dont need to be in the machine list
- var/on = 0 // 1 if on, 0 if off
- var/on_gs = 0
- var/brightness = 8 // luminosity when on, also used in power calculation
- var/status = LIGHT_OK // LIGHT_OK, _EMPTY, _BURNED or _BROKEN
- var/flickering = 0
- var/light_type = /obj/item/weapon/light/tube // the type of light item
- var/fitting = "tube"
- var/switchcount = 0 // count of number of times switched on/off
- // this is used to calc the probability the light burns out
-
- var/rigged = 0 // true if rigged to explode
-
-// the smaller bulb light fixture
-
-/obj/machinery/light/small
- icon_state = "bulb1"
- base_state = "bulb"
- fitting = "bulb"
- brightness = 4
- desc = "A small lighting fixture."
- light_type = /obj/item/weapon/light/bulb
-
-
-/obj/machinery/light/Move()
- if(status != LIGHT_BROKEN) broken(1)
- return ..()
-
-/obj/machinery/light/built/New()
- status = LIGHT_EMPTY
- update(0)
- ..()
-
-/obj/machinery/light/small/built/New()
- status = LIGHT_EMPTY
- update(0)
- ..()
-
-
-// create a new lighting fixture
-/obj/machinery/light/New()
- ..()
- spawn(2)
- switch(fitting)
- if("tube")
- brightness = 8
- if(prob(2))
- broken(1)
- if("bulb")
- brightness = 4
- if(prob(5))
- broken(1)
- spawn(1)
- update(0)
-
-/obj/machinery/light/Destroy()
- var/area/A = get_area(src)
- if(A)
- on = 0
-// A.update_lights()
- ..()
-
-/obj/machinery/light/update_icon()
-
- switch(status) // set icon_states
- if(LIGHT_OK)
- icon_state = "[base_state][on]"
- if(LIGHT_EMPTY)
- icon_state = "[base_state]-empty"
- on = 0
- if(LIGHT_BURNED)
- icon_state = "[base_state]-burned"
- on = 0
- if(LIGHT_BROKEN)
- icon_state = "[base_state]-broken"
- on = 0
- return
-
-// update the icon_state and luminosity of the light depending on its state
-/obj/machinery/light/proc/update(var/trigger = 1)
-
- update_icon()
- if(on)
- if(luminosity != brightness)
- switchcount++
- if(rigged)
- if(status == LIGHT_OK && trigger)
- explode()
- else if( prob( min(60, switchcount*switchcount*0.01) ) )
- if(status == LIGHT_OK && trigger)
- status = LIGHT_BURNED
- icon_state = "[base_state]-burned"
- on = 0
- SetLuminosity(0)
- else
- use_power = 2
- SetLuminosity(brightness)
- else
- use_power = 1
- SetLuminosity(0)
-
- active_power_usage = (luminosity * 10)
- if(on != on_gs)
- on_gs = on
-
-
-// attempt to set the light's on/off status
-// will not switch on if broken/burned/empty
-/obj/machinery/light/proc/seton(var/s)
- on = (s && status == LIGHT_OK)
- update()
-
-// examine verb
-/obj/machinery/light/examine()
- set src in oview(1)
- ..()
- if(usr && !usr.stat)
- switch(status)
- if(LIGHT_OK)
- usr << "It is turned [on? "on" : "off"]."
- if(LIGHT_EMPTY)
- usr << "The [fitting] has been removed."
- if(LIGHT_BURNED)
- usr << "The [fitting] is burnt out."
- if(LIGHT_BROKEN)
- usr << "The [fitting] has been smashed."
-
-
-
-// attack with item - insert light (if right type), otherwise try to break the light
-
-/obj/machinery/light/attackby(obj/item/W, mob/user)
-
- //Light replacer code
- if(istype(W, /obj/item/device/lightreplacer))
- var/obj/item/device/lightreplacer/LR = W
- if(isliving(user))
- var/mob/living/U = user
- LR.ReplaceLight(src, U)
- return
-
- // attempt to insert light
- if(istype(W, /obj/item/weapon/light))
- if(status != LIGHT_EMPTY)
- user << "There is a [fitting] already inserted."
- return
- else
- src.add_fingerprint(user)
- var/obj/item/weapon/light/L = W
- if(istype(L, light_type))
- status = L.status
- user << "You insert the [L.name]."
- switchcount = L.switchcount
- rigged = L.rigged
- brightness = L.brightness
- on = has_power()
- update()
-
- user.drop_item() //drop the item to update overlays and such
- qdel(L)
-
- if(on && rigged)
- explode()
- else
- user << "This type of light requires a [fitting]."
- return
-
- // attempt to break the light
- //If xenos decide they want to smash a light bulb with a toolbox, who am I to stop them? /N
-
- else if(status != LIGHT_BROKEN && status != LIGHT_EMPTY)
-
-
- if(prob(1+W.force * 5))
-
- user << "You hit the light, and it smashes!"
- for(var/mob/M in viewers(src))
- if(M == user)
- continue
- M.show_message("[user.name] smashed the light!", 3, "You hear a tinkle of breaking glass", 2)
- if(on && (W.flags & CONDUCT))
- //if(!user.mutations & COLD_RESISTANCE)
- if (prob(12))
- electrocute_mob(user, get_area(src), src, 0.3)
- broken()
-
- else
- user << "You hit the light!"
-
- // attempt to stick weapon into light socket
- else if(status == LIGHT_EMPTY)
- if(istype(W, /obj/item/weapon/screwdriver)) //If it's a screwdriver open it.
- playsound(src.loc, 'sound/items/Screwdriver.ogg', 75, 1)
- user.visible_message("[user.name] opens [src]'s casing.", \
- "You open [src]'s casing.", "You hear a noise.")
- var/obj/machinery/light_construct/newlight = null
- switch(fitting)
- if("tube")
- newlight = new /obj/machinery/light_construct(src.loc)
- newlight.icon_state = "tube-construct-stage2"
-
- if("bulb")
- newlight = new /obj/machinery/light_construct/small(src.loc)
- newlight.icon_state = "bulb-construct-stage2"
- newlight.dir = src.dir
- newlight.stage = 2
- newlight.fingerprints = src.fingerprints
- newlight.fingerprintshidden = src.fingerprintshidden
- newlight.fingerprintslast = src.fingerprintslast
- qdel(src)
- return
-
- user << "You stick \the [W] into the light socket!"
- if(has_power() && (W.flags & CONDUCT))
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(3, 1, src)
- s.start()
- //if(!user.mutations & COLD_RESISTANCE)
- if (prob(75))
- electrocute_mob(user, get_area(src), src, rand(0.7,1.0))
-
-
-// returns whether this light has power
-// true if area has power and lightswitch is on
-/obj/machinery/light/proc/has_power()
- var/area/A = src.loc.loc
- return A.master.lightswitch && A.master.power_light
-
-/obj/machinery/light/proc/flicker(var/amount = rand(10, 20))
- if(flickering) return
- flickering = 1
- spawn(0)
- if(on && status == LIGHT_OK)
- for(var/i = 0; i < amount; i++)
- if(status != LIGHT_OK) break
- on = !on
- update(0)
- sleep(rand(5, 15))
- on = (status == LIGHT_OK)
- update(0)
- flickering = 0
-
-// ai attack - make lights flicker, because why not
-
-/obj/machinery/light/attack_ai(mob/user)
- src.flicker(1)
- return
-
-// Aliens smash the bulb but do not get electrocuted./N
-/obj/machinery/light/attack_alien(mob/living/carbon/alien/humanoid/user)//So larva don't go breaking light bulbs.
- if(status == LIGHT_EMPTY||status == LIGHT_BROKEN)
- user << "\green That object is useless to you."
- return
- else if (status == LIGHT_OK||status == LIGHT_BURNED)
- for(var/mob/M in viewers(src))
- M.show_message("\red [user.name] smashed the light!", 3, "You hear a tinkle of breaking glass", 2)
- broken()
- return
-
-/obj/machinery/light/attack_animal(mob/living/simple_animal/M)
- if(M.melee_damage_upper == 0) return
- if(status == LIGHT_EMPTY||status == LIGHT_BROKEN)
- M << "\red That object is useless to you."
- return
- else if (status == LIGHT_OK||status == LIGHT_BURNED)
- for(var/mob/O in viewers(src))
- O.show_message("\red [M.name] smashed the light!", 3, "You hear a tinkle of breaking glass", 2)
- broken()
- return
-// attack with hand - remove tube/bulb
-// if hands aren't protected and the light is on, burn the player
-
-/obj/machinery/light/attack_hand(mob/user)
-
- add_fingerprint(user)
-
- if(status == LIGHT_EMPTY)
- user << "There is no [fitting] in this light."
- return
-
- // make it burn hands if not wearing fire-insulated gloves
- if(on)
- var/prot = 0
- var/mob/living/carbon/human/H = user
-
- if(istype(H))
-
- if(H.gloves)
- var/obj/item/clothing/gloves/G = H.gloves
- if(G.max_heat_protection_temperature)
- prot = (G.max_heat_protection_temperature > 360)
- else
- prot = 1
-
- if(prot > 0 || (COLD_RESISTANCE in user.mutations))
- user << "You remove the light [fitting]"
- else if(TK in user.mutations)
- user << "You telekinetically remove the light [fitting]."
- else
- user << "You try to remove the light [fitting], but you burn your hand on it!"
-
- var/obj/item/organ/limb/affecting = H.get_organ("[user.hand ? "l" : "r" ]_arm")
- if(affecting.take_damage( 0, 5 )) // 5 burn damage
- H.update_damage_overlays(0)
- H.updatehealth()
- return // if burned, don't remove the light
- else
- user << "You remove the light [fitting]."
- // create a light tube/bulb item and put it in the user's hand
- var/obj/item/weapon/light/L = new light_type()
- L.status = status
- L.rigged = rigged
- L.brightness = brightness
-
- // light item inherits the switchcount, then zero it
- L.switchcount = switchcount
- switchcount = 0
-
- L.update()
- L.add_fingerprint(user)
- L.loc = loc
-
- user.put_in_active_hand(L) //puts it in our active hand
-
- status = LIGHT_EMPTY
- update()
-
-/obj/machinery/light/attack_tk(mob/user)
- if(status == LIGHT_EMPTY)
- user << "There is no [fitting] in this light."
- return
-
- user << "You telekinetically remove the light [fitting]."
- // create a light tube/bulb item and put it in the user's hand
- var/obj/item/weapon/light/L = new light_type()
- L.status = status
- L.rigged = rigged
- L.brightness = brightness
-
- // light item inherits the switchcount, then zero it
- L.switchcount = switchcount
- switchcount = 0
-
- L.update()
- L.add_fingerprint(user)
- L.loc = loc
-
- status = LIGHT_EMPTY
- update()
-
-// break the light and make sparks if was on
-
-/obj/machinery/light/proc/broken(var/skip_sound_and_sparks = 0)
- if(status == LIGHT_EMPTY)
- return
-
- if(!skip_sound_and_sparks)
- if(status == LIGHT_OK || status == LIGHT_BURNED)
- playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
- if(on)
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(3, 1, src)
- s.start()
- status = LIGHT_BROKEN
- update()
-
-/obj/machinery/light/proc/fix()
- if(status == LIGHT_OK)
- return
- status = LIGHT_OK
- brightness = initial(brightness)
- on = 1
- update()
-
-// explosion effect
-// destroy the whole light fixture or just shatter it
-
-/obj/machinery/light/ex_act(severity)
- switch(severity)
- if(1.0)
- qdel(src)
- return
- if(2.0)
- if (prob(75))
- broken()
- if(3.0)
- if (prob(50))
- broken()
- return
-
-//blob effect
-
-/obj/machinery/light/blob_act()
- if(prob(75))
- broken()
-
-
-// timed process
-// use power
-
-#define LIGHTING_POWER_FACTOR 20 //20W per unit luminosity
-
-/obj/machinery/light/process()//TODO: remove/add this from machines to save on processing as needed ~Carn PRIORITY
- if(on)
- use_power(luminosity * LIGHTING_POWER_FACTOR, LIGHT)
-
-// called when area power state changes
-/obj/machinery/light/power_change()
- var/area/A = get_area(src)
- A = A.master
- seton(A.lightswitch && A.power_light)
-
-// called when on fire
-
-/obj/machinery/light/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(prob(max(0, exposed_temperature - 673))) //0% at <400C, 100% at >500C
- broken()
-
-// explode the light
-
-/obj/machinery/light/proc/explode()
- var/turf/T = get_turf(src.loc)
- spawn(0)
- broken() // break it first to give a warning
- sleep(2)
- explosion(T, 0, 0, 2, 2)
- sleep(1)
- qdel(src)
-
-// the light item
-// can be tube or bulb subtypes
-// will fit into empty /obj/machinery/light of the corresponding type
-
-/obj/item/weapon/light
- icon = 'icons/obj/lighting.dmi'
- force = 2
- throwforce = 5
- w_class = 1
- var/status = 0 // LIGHT_OK, LIGHT_BURNED or LIGHT_BROKEN
- var/base_state
- var/switchcount = 0 // number of times switched
- m_amt = 60
- var/rigged = 0 // true if rigged to explode
- var/brightness = 2 //how much light it gives off
-
-/obj/item/weapon/light/tube
- name = "light tube"
- desc = "A replacement light tube."
- icon_state = "ltube"
- base_state = "ltube"
- item_state = "c_tube"
- g_amt = 100
- brightness = 8
-
-/obj/item/weapon/light/tube/large
- w_class = 2
- name = "large light tube"
- brightness = 15
-
-/obj/item/weapon/light/bulb
- name = "light bulb"
- desc = "A replacement light bulb."
- icon_state = "lbulb"
- base_state = "lbulb"
- item_state = "contvapour"
- g_amt = 100
- brightness = 5
-
-/obj/item/weapon/light/throw_impact(atom/hit_atom)
- ..()
- shatter()
-
-/obj/item/weapon/light/bulb/fire
- name = "fire bulb"
- desc = "A replacement fire bulb."
- icon_state = "fbulb"
- base_state = "fbulb"
- item_state = "egg4"
- g_amt = 100
- brightness = 5
-
-// update the icon state and description of the light
-
-/obj/item/weapon/light/proc/update()
- switch(status)
- if(LIGHT_OK)
- icon_state = base_state
- desc = "A replacement [name]."
- if(LIGHT_BURNED)
- icon_state = "[base_state]-burned"
- desc = "A burnt-out [name]."
- if(LIGHT_BROKEN)
- icon_state = "[base_state]-broken"
- desc = "A broken [name]."
-
-
-/obj/item/weapon/light/New()
- ..()
- switch(name)
- if("light tube")
- brightness = rand(6,9)
- if("light bulb")
- brightness = rand(4,6)
- update()
-
-
-// attack bulb/tube with object
-// if a syringe, can inject plasma to make it explode
-/obj/item/weapon/light/attackby(var/obj/item/I, var/mob/user)
- ..()
- if(istype(I, /obj/item/weapon/reagent_containers/syringe))
- var/obj/item/weapon/reagent_containers/syringe/S = I
-
- user << "You inject the solution into the [src]."
-
- if(S.reagents.has_reagent("plasma", 5))
-
- rigged = 1
-
- S.reagents.clear_reagents()
- else
- ..()
- return
-
-// called after an attack with a light item
-// shatter light, unless it was an attempt to put it in a light socket
-// now only shatter if the intent was harm
-
-/obj/item/weapon/light/afterattack(atom/target, mob/user,proximity)
- if(!proximity) return
- if(istype(target, /obj/machinery/light))
- return
- if(user.a_intent != "harm")
- return
-
- shatter()
-
-/obj/item/weapon/light/proc/shatter()
- if(status == LIGHT_OK || status == LIGHT_BURNED)
- src.visible_message("\red [name] shatters.","\red You hear a small glass object shatter.")
- status = LIGHT_BROKEN
- force = 5
- playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
- update()
+// The lighting system
+//
+// consists of light fixtures (/obj/machinery/light) and light tube/bulb items (/obj/item/weapon/light)
+
+
+// status values shared between lighting fixtures and items
+#define LIGHT_OK 0
+#define LIGHT_EMPTY 1
+#define LIGHT_BROKEN 2
+#define LIGHT_BURNED 3
+
+
+
+/obj/item/light_fixture_frame
+ name = "light fixture frame"
+ desc = "Used for building lights."
+ icon = 'icons/obj/lighting.dmi'
+ icon_state = "tube-construct-item"
+ flags = CONDUCT
+ var/fixture_type = "tube"
+ var/obj/machinery/light/newlight = null
+ var/sheets_refunded = 2
+
+/obj/item/light_fixture_frame/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if (istype(W, /obj/item/weapon/wrench))
+ new /obj/item/stack/sheet/metal( get_turf(src.loc), sheets_refunded )
+ qdel(src)
+ return
+ ..()
+
+/obj/item/light_fixture_frame/proc/try_build(turf/on_wall)
+ if (get_dist(on_wall,usr)>1)
+ return
+ var/ndir = get_dir(usr,on_wall)
+ if (!(ndir in cardinal))
+ return
+ var/turf/loc = get_turf(usr)
+ if (!istype(loc, /turf/simulated/floor))
+ usr << "\red [src.name] cannot be placed on this spot."
+ return
+ usr << "Attaching [src] to the wall."
+ playsound(src.loc, 'sound/machines/click.ogg', 75, 1)
+ var/constrdir = usr.dir
+ var/constrloc = usr.loc
+ if (!do_after(usr, 30))
+ return
+ switch(fixture_type)
+ if("bulb")
+ newlight = new /obj/machinery/light_construct/small(constrloc)
+ if("tube")
+ newlight = new /obj/machinery/light_construct(constrloc)
+ newlight.dir = constrdir
+ newlight.fingerprints = src.fingerprints
+ newlight.fingerprintshidden = src.fingerprintshidden
+ newlight.fingerprintslast = src.fingerprintslast
+
+ usr.visible_message("[usr.name] attaches [src] to the wall.", \
+ "You attach [src] to the wall.")
+ qdel(src)
+
+/obj/item/light_fixture_frame/small
+ name = "small light fixture frame"
+ desc = "Used for building small lights."
+ icon = 'icons/obj/lighting.dmi'
+ icon_state = "bulb-construct-item"
+ flags = CONDUCT
+ fixture_type = "bulb"
+ sheets_refunded = 1
+
+/obj/machinery/light_construct
+ name = "light fixture frame"
+ desc = "A light fixture under construction."
+ icon = 'icons/obj/lighting.dmi'
+ icon_state = "tube-construct-stage1"
+ anchored = 1
+ layer = 5
+ var/stage = 1
+ var/fixture_type = "tube"
+ var/sheets_refunded = 2
+ var/obj/machinery/light/newlight = null
+
+/obj/machinery/light_construct/New()
+ ..()
+ if (fixture_type == "bulb")
+ icon_state = "bulb-construct-stage1"
+
+/obj/machinery/light_construct/examine()
+ set src in view()
+ ..()
+ if (!(usr in view(2))) return
+ switch(src.stage)
+ if(1)
+ usr << "It's an empty frame."
+ return
+ if(2)
+ usr << "It's wired."
+ return
+ if(3)
+ usr << "The casing is closed."
+ return
+
+/obj/machinery/light_construct/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ src.add_fingerprint(user)
+ if (istype(W, /obj/item/weapon/wrench))
+ if (src.stage == 1)
+ playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
+ usr << "You begin deconstructing [src]."
+ if (!do_after(usr, 30))
+ return
+ new /obj/item/stack/sheet/metal( get_turf(src.loc), sheets_refunded )
+ user.visible_message("[user.name] deconstructs [src].", \
+ "You deconstruct [src].", "You hear a noise.")
+ playsound(src.loc, 'sound/items/Deconstruct.ogg', 75, 1)
+ qdel(src)
+ if (src.stage == 2)
+ usr << "You have to remove the wires first."
+ return
+
+ if (src.stage == 3)
+ usr << "You have to unscrew the case first."
+ return
+
+ if(istype(W, /obj/item/weapon/wirecutters))
+ if (src.stage != 2) return
+ src.stage = 1
+ switch(fixture_type)
+ if ("tube")
+ src.icon_state = "tube-construct-stage1"
+ if("bulb")
+ src.icon_state = "bulb-construct-stage1"
+ new /obj/item/stack/cable_coil(get_turf(src.loc), 1, "red")
+ user.visible_message("[user.name] removes the wiring from [src].", \
+ "You remove the wiring from [src].", "You hear a noise.")
+ playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1)
+ return
+
+ if(istype(W, /obj/item/stack/cable_coil))
+ if (src.stage != 1) return
+ var/obj/item/stack/cable_coil/coil = W
+ coil.use(1)
+ switch(fixture_type)
+ if ("tube")
+ src.icon_state = "tube-construct-stage2"
+ if("bulb")
+ src.icon_state = "bulb-construct-stage2"
+ src.stage = 2
+ user.visible_message("[user.name] adds wires to [src].", \
+ "You add wires to [src].")
+ return
+
+ if(istype(W, /obj/item/weapon/screwdriver))
+ if (src.stage == 2)
+ switch(fixture_type)
+ if ("tube")
+ src.icon_state = "tube-empty"
+ if("bulb")
+ src.icon_state = "bulb-empty"
+ src.stage = 3
+ user.visible_message("[user.name] closes [src]'s casing.", \
+ "You close [src]'s casing.", "You hear a noise.")
+ playsound(src.loc, 'sound/items/Screwdriver.ogg', 75, 1)
+
+ switch(fixture_type)
+
+ if("tube")
+ newlight = new /obj/machinery/light/built(src.loc)
+ if ("bulb")
+ newlight = new /obj/machinery/light/small/built(src.loc)
+
+ newlight.dir = src.dir
+ src.transfer_fingerprints_to(newlight)
+ qdel(src)
+ return
+ ..()
+
+/obj/machinery/light_construct/small
+ name = "small light fixture frame"
+ desc = "A small light fixture under construction."
+ icon = 'icons/obj/lighting.dmi'
+ icon_state = "bulb-construct-stage1"
+ anchored = 1
+ layer = 5
+ stage = 1
+ fixture_type = "bulb"
+ sheets_refunded = 1
+
+// the standard tube light fixture
+/obj/machinery/light
+ name = "light fixture"
+ icon = 'icons/obj/lighting.dmi'
+ var/base_state = "tube" // base description and icon_state
+ icon_state = "tube1"
+ desc = "A lighting fixture."
+ anchored = 1
+ layer = 5 // They were appearing under mobs which is a little weird - Ostaf
+ use_power = 2
+ idle_power_usage = 2
+ active_power_usage = 20
+ power_channel = LIGHT //Lights are calc'd via area so they dont need to be in the machine list
+ var/on = 0 // 1 if on, 0 if off
+ var/on_gs = 0
+ var/brightness = 8 // luminosity when on, also used in power calculation
+ var/status = LIGHT_OK // LIGHT_OK, _EMPTY, _BURNED or _BROKEN
+ var/flickering = 0
+ var/light_type = /obj/item/weapon/light/tube // the type of light item
+ var/fitting = "tube"
+ var/switchcount = 0 // count of number of times switched on/off
+ // this is used to calc the probability the light burns out
+
+ var/rigged = 0 // true if rigged to explode
+
+// the smaller bulb light fixture
+
+/obj/machinery/light/small
+ icon_state = "bulb1"
+ base_state = "bulb"
+ fitting = "bulb"
+ brightness = 4
+ desc = "A small lighting fixture."
+ light_type = /obj/item/weapon/light/bulb
+
+
+/obj/machinery/light/Move()
+ if(status != LIGHT_BROKEN) broken(1)
+ return ..()
+
+/obj/machinery/light/built/New()
+ status = LIGHT_EMPTY
+ update(0)
+ ..()
+
+/obj/machinery/light/small/built/New()
+ status = LIGHT_EMPTY
+ update(0)
+ ..()
+
+
+// create a new lighting fixture
+/obj/machinery/light/New()
+ ..()
+ spawn(2)
+ switch(fitting)
+ if("tube")
+ brightness = 8
+ if(prob(2))
+ broken(1)
+ if("bulb")
+ brightness = 4
+ if(prob(5))
+ broken(1)
+ spawn(1)
+ update(0)
+
+/obj/machinery/light/Destroy()
+ var/area/A = get_area(src)
+ if(A)
+ on = 0
+// A.update_lights()
+ ..()
+
+/obj/machinery/light/update_icon()
+
+ switch(status) // set icon_states
+ if(LIGHT_OK)
+ icon_state = "[base_state][on]"
+ if(LIGHT_EMPTY)
+ icon_state = "[base_state]-empty"
+ on = 0
+ if(LIGHT_BURNED)
+ icon_state = "[base_state]-burned"
+ on = 0
+ if(LIGHT_BROKEN)
+ icon_state = "[base_state]-broken"
+ on = 0
+ return
+
+// update the icon_state and luminosity of the light depending on its state
+/obj/machinery/light/proc/update(var/trigger = 1)
+
+ update_icon()
+ if(on)
+ if(luminosity != brightness)
+ switchcount++
+ if(rigged)
+ if(status == LIGHT_OK && trigger)
+ explode()
+ else if( prob( min(60, switchcount*switchcount*0.01) ) )
+ if(status == LIGHT_OK && trigger)
+ status = LIGHT_BURNED
+ icon_state = "[base_state]-burned"
+ on = 0
+ SetLuminosity(0)
+ else
+ use_power = 2
+ SetLuminosity(brightness)
+ else
+ use_power = 1
+ SetLuminosity(0)
+
+ active_power_usage = (luminosity * 10)
+ if(on != on_gs)
+ on_gs = on
+
+
+// attempt to set the light's on/off status
+// will not switch on if broken/burned/empty
+/obj/machinery/light/proc/seton(var/s)
+ on = (s && status == LIGHT_OK)
+ update()
+
+// examine verb
+/obj/machinery/light/examine()
+ set src in oview(1)
+ ..()
+ if(usr && !usr.stat)
+ switch(status)
+ if(LIGHT_OK)
+ usr << "It is turned [on? "on" : "off"]."
+ if(LIGHT_EMPTY)
+ usr << "The [fitting] has been removed."
+ if(LIGHT_BURNED)
+ usr << "The [fitting] is burnt out."
+ if(LIGHT_BROKEN)
+ usr << "The [fitting] has been smashed."
+
+
+
+// attack with item - insert light (if right type), otherwise try to break the light
+
+/obj/machinery/light/attackby(obj/item/W, mob/user)
+
+ //Light replacer code
+ if(istype(W, /obj/item/device/lightreplacer))
+ var/obj/item/device/lightreplacer/LR = W
+ if(isliving(user))
+ var/mob/living/U = user
+ LR.ReplaceLight(src, U)
+ return
+
+ // attempt to insert light
+ if(istype(W, /obj/item/weapon/light))
+ if(status != LIGHT_EMPTY)
+ user << "There is a [fitting] already inserted."
+ return
+ else
+ src.add_fingerprint(user)
+ var/obj/item/weapon/light/L = W
+ if(istype(L, light_type))
+ status = L.status
+ user << "You insert the [L.name]."
+ switchcount = L.switchcount
+ rigged = L.rigged
+ brightness = L.brightness
+ on = has_power()
+ update()
+
+ user.drop_item() //drop the item to update overlays and such
+ qdel(L)
+
+ if(on && rigged)
+ explode()
+ else
+ user << "This type of light requires a [fitting]."
+ return
+
+ // attempt to break the light
+ //If xenos decide they want to smash a light bulb with a toolbox, who am I to stop them? /N
+
+ else if(status != LIGHT_BROKEN && status != LIGHT_EMPTY)
+
+
+ if(prob(1+W.force * 5))
+
+ user << "You hit the light, and it smashes!"
+ for(var/mob/M in viewers(src))
+ if(M == user)
+ continue
+ M.show_message("[user.name] smashed the light!", 3, "You hear a tinkle of breaking glass", 2)
+ if(on && (W.flags & CONDUCT))
+ //if(!user.mutations & COLD_RESISTANCE)
+ if (prob(12))
+ electrocute_mob(user, get_area(src), src, 0.3)
+ broken()
+
+ else
+ user << "You hit the light!"
+
+ // attempt to stick weapon into light socket
+ else if(status == LIGHT_EMPTY)
+ if(istype(W, /obj/item/weapon/screwdriver)) //If it's a screwdriver open it.
+ playsound(src.loc, 'sound/items/Screwdriver.ogg', 75, 1)
+ user.visible_message("[user.name] opens [src]'s casing.", \
+ "You open [src]'s casing.", "You hear a noise.")
+ var/obj/machinery/light_construct/newlight = null
+ switch(fitting)
+ if("tube")
+ newlight = new /obj/machinery/light_construct(src.loc)
+ newlight.icon_state = "tube-construct-stage2"
+
+ if("bulb")
+ newlight = new /obj/machinery/light_construct/small(src.loc)
+ newlight.icon_state = "bulb-construct-stage2"
+ newlight.dir = src.dir
+ newlight.stage = 2
+ newlight.fingerprints = src.fingerprints
+ newlight.fingerprintshidden = src.fingerprintshidden
+ newlight.fingerprintslast = src.fingerprintslast
+ qdel(src)
+ return
+
+ user << "You stick \the [W] into the light socket!"
+ if(has_power() && (W.flags & CONDUCT))
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(3, 1, src)
+ s.start()
+ //if(!user.mutations & COLD_RESISTANCE)
+ if (prob(75))
+ electrocute_mob(user, get_area(src), src, rand(0.7,1.0))
+
+
+// returns whether this light has power
+// true if area has power and lightswitch is on
+/obj/machinery/light/proc/has_power()
+ var/area/A = src.loc.loc
+ return A.master.lightswitch && A.master.power_light
+
+/obj/machinery/light/proc/flicker(var/amount = rand(10, 20))
+ if(flickering) return
+ flickering = 1
+ spawn(0)
+ if(on && status == LIGHT_OK)
+ for(var/i = 0; i < amount; i++)
+ if(status != LIGHT_OK) break
+ on = !on
+ update(0)
+ sleep(rand(5, 15))
+ on = (status == LIGHT_OK)
+ update(0)
+ flickering = 0
+
+// ai attack - make lights flicker, because why not
+
+/obj/machinery/light/attack_ai(mob/user)
+ src.flicker(1)
+ return
+
+// Aliens smash the bulb but do not get electrocuted./N
+/obj/machinery/light/attack_alien(mob/living/carbon/alien/humanoid/user)//So larva don't go breaking light bulbs.
+ if(status == LIGHT_EMPTY||status == LIGHT_BROKEN)
+ user << "\green That object is useless to you."
+ return
+ else if (status == LIGHT_OK||status == LIGHT_BURNED)
+ for(var/mob/M in viewers(src))
+ M.show_message("\red [user.name] smashed the light!", 3, "You hear a tinkle of breaking glass", 2)
+ broken()
+ return
+
+/obj/machinery/light/attack_animal(mob/living/simple_animal/M)
+ if(M.melee_damage_upper == 0) return
+ if(status == LIGHT_EMPTY||status == LIGHT_BROKEN)
+ M << "\red That object is useless to you."
+ return
+ else if (status == LIGHT_OK||status == LIGHT_BURNED)
+ for(var/mob/O in viewers(src))
+ O.show_message("\red [M.name] smashed the light!", 3, "You hear a tinkle of breaking glass", 2)
+ broken()
+ return
+// attack with hand - remove tube/bulb
+// if hands aren't protected and the light is on, burn the player
+
+/obj/machinery/light/attack_hand(mob/user)
+
+ add_fingerprint(user)
+
+ if(status == LIGHT_EMPTY)
+ user << "There is no [fitting] in this light."
+ return
+
+ // make it burn hands if not wearing fire-insulated gloves
+ if(on)
+ var/prot = 0
+ var/mob/living/carbon/human/H = user
+
+ if(istype(H))
+
+ if(H.gloves)
+ var/obj/item/clothing/gloves/G = H.gloves
+ if(G.max_heat_protection_temperature)
+ prot = (G.max_heat_protection_temperature > 360)
+ else
+ prot = 1
+
+ if(prot > 0 || (COLD_RESISTANCE in user.mutations))
+ user << "You remove the light [fitting]"
+ else if(TK in user.mutations)
+ user << "You telekinetically remove the light [fitting]."
+ else
+ user << "You try to remove the light [fitting], but you burn your hand on it!"
+
+ var/obj/item/organ/limb/affecting = H.get_organ("[user.hand ? "l" : "r" ]_arm")
+ if(affecting.take_damage( 0, 5 )) // 5 burn damage
+ H.update_damage_overlays(0)
+ H.updatehealth()
+ return // if burned, don't remove the light
+ else
+ user << "You remove the light [fitting]."
+ // create a light tube/bulb item and put it in the user's hand
+ var/obj/item/weapon/light/L = new light_type()
+ L.status = status
+ L.rigged = rigged
+ L.brightness = brightness
+
+ // light item inherits the switchcount, then zero it
+ L.switchcount = switchcount
+ switchcount = 0
+
+ L.update()
+ L.add_fingerprint(user)
+ L.loc = loc
+
+ user.put_in_active_hand(L) //puts it in our active hand
+
+ status = LIGHT_EMPTY
+ update()
+
+/obj/machinery/light/attack_tk(mob/user)
+ if(status == LIGHT_EMPTY)
+ user << "There is no [fitting] in this light."
+ return
+
+ user << "You telekinetically remove the light [fitting]."
+ // create a light tube/bulb item and put it in the user's hand
+ var/obj/item/weapon/light/L = new light_type()
+ L.status = status
+ L.rigged = rigged
+ L.brightness = brightness
+
+ // light item inherits the switchcount, then zero it
+ L.switchcount = switchcount
+ switchcount = 0
+
+ L.update()
+ L.add_fingerprint(user)
+ L.loc = loc
+
+ status = LIGHT_EMPTY
+ update()
+
+// break the light and make sparks if was on
+
+/obj/machinery/light/proc/broken(var/skip_sound_and_sparks = 0)
+ if(status == LIGHT_EMPTY)
+ return
+
+ if(!skip_sound_and_sparks)
+ if(status == LIGHT_OK || status == LIGHT_BURNED)
+ playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
+ if(on)
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(3, 1, src)
+ s.start()
+ status = LIGHT_BROKEN
+ update()
+
+/obj/machinery/light/proc/fix()
+ if(status == LIGHT_OK)
+ return
+ status = LIGHT_OK
+ brightness = initial(brightness)
+ on = 1
+ update()
+
+// explosion effect
+// destroy the whole light fixture or just shatter it
+
+/obj/machinery/light/ex_act(severity)
+ switch(severity)
+ if(1.0)
+ qdel(src)
+ return
+ if(2.0)
+ if (prob(75))
+ broken()
+ if(3.0)
+ if (prob(50))
+ broken()
+ return
+
+//blob effect
+
+/obj/machinery/light/blob_act()
+ if(prob(75))
+ broken()
+
+
+// timed process
+// use power
+
+#define LIGHTING_POWER_FACTOR 20 //20W per unit luminosity
+
+/obj/machinery/light/process()//TODO: remove/add this from machines to save on processing as needed ~Carn PRIORITY
+ if(on)
+ use_power(luminosity * LIGHTING_POWER_FACTOR, LIGHT)
+
+// called when area power state changes
+/obj/machinery/light/power_change()
+ var/area/A = get_area(src)
+ A = A.master
+ seton(A.lightswitch && A.power_light)
+
+// called when on fire
+
+/obj/machinery/light/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ if(prob(max(0, exposed_temperature - 673))) //0% at <400C, 100% at >500C
+ broken()
+
+// explode the light
+
+/obj/machinery/light/proc/explode()
+ var/turf/T = get_turf(src.loc)
+ spawn(0)
+ broken() // break it first to give a warning
+ sleep(2)
+ explosion(T, 0, 0, 2, 2)
+ sleep(1)
+ qdel(src)
+
+// the light item
+// can be tube or bulb subtypes
+// will fit into empty /obj/machinery/light of the corresponding type
+
+/obj/item/weapon/light
+ icon = 'icons/obj/lighting.dmi'
+ force = 2
+ throwforce = 5
+ w_class = 1
+ var/status = 0 // LIGHT_OK, LIGHT_BURNED or LIGHT_BROKEN
+ var/base_state
+ var/switchcount = 0 // number of times switched
+ m_amt = 60
+ var/rigged = 0 // true if rigged to explode
+ var/brightness = 2 //how much light it gives off
+
+/obj/item/weapon/light/tube
+ name = "light tube"
+ desc = "A replacement light tube."
+ icon_state = "ltube"
+ base_state = "ltube"
+ item_state = "c_tube"
+ g_amt = 100
+ brightness = 8
+
+/obj/item/weapon/light/tube/large
+ w_class = 2
+ name = "large light tube"
+ brightness = 15
+
+/obj/item/weapon/light/bulb
+ name = "light bulb"
+ desc = "A replacement light bulb."
+ icon_state = "lbulb"
+ base_state = "lbulb"
+ item_state = "contvapour"
+ g_amt = 100
+ brightness = 5
+
+/obj/item/weapon/light/throw_impact(atom/hit_atom)
+ ..()
+ shatter()
+
+/obj/item/weapon/light/bulb/fire
+ name = "fire bulb"
+ desc = "A replacement fire bulb."
+ icon_state = "fbulb"
+ base_state = "fbulb"
+ item_state = "egg4"
+ g_amt = 100
+ brightness = 5
+
+// update the icon state and description of the light
+
+/obj/item/weapon/light/proc/update()
+ switch(status)
+ if(LIGHT_OK)
+ icon_state = base_state
+ desc = "A replacement [name]."
+ if(LIGHT_BURNED)
+ icon_state = "[base_state]-burned"
+ desc = "A burnt-out [name]."
+ if(LIGHT_BROKEN)
+ icon_state = "[base_state]-broken"
+ desc = "A broken [name]."
+
+
+/obj/item/weapon/light/New()
+ ..()
+ switch(name)
+ if("light tube")
+ brightness = rand(6,9)
+ if("light bulb")
+ brightness = rand(4,6)
+ update()
+
+
+// attack bulb/tube with object
+// if a syringe, can inject plasma to make it explode
+/obj/item/weapon/light/attackby(var/obj/item/I, var/mob/user)
+ ..()
+ if(istype(I, /obj/item/weapon/reagent_containers/syringe))
+ var/obj/item/weapon/reagent_containers/syringe/S = I
+
+ user << "You inject the solution into the [src]."
+
+ if(S.reagents.has_reagent("plasma", 5))
+
+ rigged = 1
+
+ S.reagents.clear_reagents()
+ else
+ ..()
+ return
+
+// called after an attack with a light item
+// shatter light, unless it was an attempt to put it in a light socket
+// now only shatter if the intent was harm
+
+/obj/item/weapon/light/afterattack(atom/target, mob/user,proximity)
+ if(!proximity) return
+ if(istype(target, /obj/machinery/light))
+ return
+ if(user.a_intent != "harm")
+ return
+
+ shatter()
+
+/obj/item/weapon/light/proc/shatter()
+ if(status == LIGHT_OK || status == LIGHT_BURNED)
+ src.visible_message("\red [name] shatters.","\red You hear a small glass object shatter.")
+ status = LIGHT_BROKEN
+ force = 5
+ playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
+ update()
diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm
index 9a7f1bc443f..92db2f7aaf8 100644
--- a/code/modules/power/port_gen.dm
+++ b/code/modules/power/port_gen.dm
@@ -1,337 +1,337 @@
-//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
-
-/* new portable generator - work in progress
-
-/obj/machinery/power/port_gen
- name = "portable generator"
- desc = "A portable generator used for emergency backup power."
- icon = 'generator.dmi'
- icon_state = "off"
- density = 1
- anchored = 0
- directwired = 0
- var/t_status = 0
- var/t_per = 5000
- var/filter = 1
- var/tank = null
- var/turf/inturf
- var/starter = 0
- var/rpm = 0
- var/rpmtarget = 0
- var/capacity = 1e6
- var/turf/outturf
- var/lastgen
-
-
-/obj/machinery/power/port_gen/process()
-ideally we're looking to generate 5000
-
-/obj/machinery/power/port_gen/attackby(obj/item/weapon/W, mob/user)
-tank [un]loading stuff
-
-/obj/machinery/power/port_gen/attack_hand(mob/user)
-turn on/off
-
-/obj/machinery/power/port_gen/examine()
-display round(lastgen) and plasmatank amount
-
-*/
-
-//Previous code been here forever, adding new framework for portable generators
-
-
-//Baseline portable generator. Has all the default handling. Not intended to be used on it's own (since it generates unlimited power).
-/obj/machinery/power/port_gen
- name = "portable generator"
- desc = "A portable generator for emergency backup power"
- icon = 'icons/obj/power.dmi'
- icon_state = "portgen0"
- density = 1
- anchored = 0
- directwired = 0
- use_power = 0
-
- var/active = 0
- var/power_gen = 5000
- var/recent_fault = 0
- var/power_output = 1
- var/consumption = 0
-
-/obj/machinery/power/port_gen/proc/HasFuel() //Placeholder for fuel check.
- return 1
-
-/obj/machinery/power/port_gen/proc/UseFuel() //Placeholder for fuel use.
- return
-
-/obj/machinery/power/port_gen/proc/DropFuel()
- return
-
-/obj/machinery/power/port_gen/proc/handleInactive()
- return
-
-/obj/machinery/power/port_gen/process()
- if(active && HasFuel() && !crit_fail && anchored && powernet)
- add_avail(power_gen * power_output)
- UseFuel()
- src.updateDialog()
-
- else
- active = 0
- icon_state = initial(icon_state)
- handleInactive()
-
-/obj/machinery/power/port_gen/attack_hand(mob/user as mob)
- if(..())
- return
- if(!anchored)
- return
-
-/obj/machinery/power/port_gen/examine()
- set src in oview(1)
- ..()
- if(active)
- usr << "It is running."
- else
- usr << "It isn't running."
-
-/obj/machinery/power/port_gen/pacman
- name = "\improper P.A.C.M.A.N.-type portable generator"
- var/sheets = 0
- var/max_sheets = 100
- var/sheet_name = ""
- var/sheet_path = /obj/item/stack/sheet/mineral/plasma
- var/board_path = "/obj/item/weapon/circuitboard/pacman"
- var/sheet_left = 0 // How much is left of the sheet
- var/time_per_sheet = 260
- var/heat = 0
-
-/obj/machinery/power/port_gen/pacman/initialize()
- ..()
- if(anchored)
- connect_to_network()
-
-/obj/machinery/power/port_gen/pacman/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- component_parts += new /obj/item/stack/cable_coil(src, 1)
- component_parts += new /obj/item/stack/cable_coil(src, 1)
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new board_path(src)
- var/obj/sheet = new sheet_path(null)
- sheet_name = sheet.name
- RefreshParts()
-
-/obj/machinery/power/port_gen/pacman/Destroy()
- DropFuel()
- ..()
-
-/obj/machinery/power/port_gen/pacman/RefreshParts()
- var/temp_rating = 0
- var/temp_reliability = 0
- var/consumption_coeff = 0
- for(var/obj/item/weapon/stock_parts/SP in component_parts)
- if(istype(SP, /obj/item/weapon/stock_parts/matter_bin))
- max_sheets = SP.rating * SP.rating * 50
- else if(istype(SP, /obj/item/weapon/stock_parts/capacitor))
- temp_rating += SP.rating
- else
- consumption_coeff += SP.rating
- for(var/obj/item/weapon/CP in component_parts)
- temp_reliability += CP.reliability
- reliability = min(round(temp_reliability / 4), 100)
- power_gen = round(initial(power_gen) * temp_rating * 2)
- consumption = consumption_coeff
-
-/obj/machinery/power/port_gen/pacman/examine()
- ..()
- usr << "\blue The generator has [sheets] units of [sheet_name] fuel left, producing [power_gen] per cycle."
- if(crit_fail) usr << "\red The generator seems to have broken down."
-
-/obj/machinery/power/port_gen/pacman/HasFuel()
- if(sheets >= 1 / (time_per_sheet / power_output) - sheet_left)
- return 1
- return 0
-
-/obj/machinery/power/port_gen/pacman/DropFuel()
- if(sheets)
- var/fail_safe = 0
- while(sheets > 0 && fail_safe < 100)
- fail_safe += 1
- var/obj/item/stack/sheet/S = new sheet_path(loc)
- var/amount = min(sheets, S.max_amount)
- S.amount = amount
- sheets -= amount
-
-/obj/machinery/power/port_gen/pacman/UseFuel()
- var/needed_sheets = 1 / (time_per_sheet * consumption / power_output)
- var/temp = min(needed_sheets, sheet_left)
- needed_sheets -= temp
- sheet_left -= temp
- sheets -= round(needed_sheets)
- needed_sheets -= round(needed_sheets)
- if (sheet_left <= 0 && sheets > 0)
- sheet_left = 1 - needed_sheets
- sheets--
-
- var/lower_limit = 56 + power_output * 10
- var/upper_limit = 76 + power_output * 10
- var/bias = 0
- if (power_output > 4)
- upper_limit = 400
- bias = power_output - consumption * (4 - consumption)
- if (heat < lower_limit)
- heat += 4 - consumption
- else
- heat += rand(-7 + bias, 7 + bias)
- if (heat < lower_limit)
- heat = lower_limit
- if (heat > upper_limit)
- heat = upper_limit
-
- if (heat > 300)
- overheat()
- qdel(src)
- return
-
-/obj/machinery/power/port_gen/pacman/handleInactive()
-
- if (heat > 0)
- heat = max(heat - 2, 0)
- src.updateDialog()
-
-/obj/machinery/power/port_gen/pacman/proc/overheat()
- explosion(src.loc, 2, 5, 2, -1)
-
-/obj/machinery/power/port_gen/pacman/attackby(var/obj/item/O as obj, var/mob/user as mob)
- if(istype(O, sheet_path))
- var/obj/item/stack/addstack = O
- var/amount = min((max_sheets - sheets), addstack.amount)
- if(amount < 1)
- user << "\blue The [src.name] is full!"
- return
- user << "\blue You add [amount] sheets to the [src.name]."
- sheets += amount
- addstack.use(amount)
- updateUsrDialog()
- return
- else if (istype(O, /obj/item/weapon/card/emag))
- emagged = 1
- emp_act(1)
- else if(!active)
-
- if(exchange_parts(user, O))
- return
-
- if(istype(O, /obj/item/weapon/wrench))
-
- if(!anchored && !isinspace())
- connect_to_network()
- user << "\blue You secure the generator to the floor."
- anchored = 1
- else if(anchored)
- disconnect_from_network()
- user << "\blue You unsecure the generator from the floor."
- anchored = 0
-
- playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
-
- else if(istype(O, /obj/item/weapon/screwdriver))
- panel_open = !panel_open
- playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
- if(panel_open)
- user << "\blue You open the access panel."
- else
- user << "\blue You close the access panel."
- else if(istype(O, /obj/item/weapon/crowbar) && panel_open)
- default_deconstruction_crowbar(O)
-
-/obj/machinery/power/port_gen/pacman/attack_hand(mob/user as mob)
- ..()
- if (!anchored)
- return
-
- interact(user)
-
-/obj/machinery/power/port_gen/pacman/attack_ai(mob/user as mob)
- interact(user)
-
-/obj/machinery/power/port_gen/pacman/attack_paw(mob/user as mob)
- interact(user)
-
-/obj/machinery/power/port_gen/pacman/interact(mob/user)
- if (get_dist(src, user) > 1 )
- if (!istype(user, /mob/living/silicon/ai))
- user.unset_machine()
- user << browse(null, "window=port_gen")
- return
-
- user.set_machine(src)
-
- var/dat = text("[name]
")
- if (active)
- dat += text("Generator: On
")
- else
- dat += text("Generator: Off
")
- dat += text("[capitalize(sheet_name)]: [sheets] - Eject
")
- var/stack_percent = round(sheet_left * 100, 1)
- dat += text("Current stack: [stack_percent]%
")
- dat += text("Power output: - [power_gen * power_output] +
")
- dat += text("Power current: [(powernet == null ? "Unconnected" : "[avail()]")]
")
- dat += text("Heat: [heat]
")
- dat += "
Close"
- user << browse("[dat]", "window=port_gen")
- onclose(user, "port_gen")
-
-/obj/machinery/power/port_gen/pacman/Topic(href, href_list)
- if(..())
- return
-
- src.add_fingerprint(usr)
- if(href_list["action"])
- if(href_list["action"] == "enable")
- if(!active && HasFuel() && !crit_fail)
- active = 1
- icon_state = "portgen1"
- src.updateUsrDialog()
- if(href_list["action"] == "disable")
- if (active)
- active = 0
- icon_state = "portgen0"
- src.updateUsrDialog()
- if(href_list["action"] == "eject")
- if(!active)
- DropFuel()
- src.updateUsrDialog()
- if(href_list["action"] == "lower_power")
- if (power_output > 1)
- power_output--
- src.updateUsrDialog()
- if (href_list["action"] == "higher_power")
- if (power_output < 4 || emagged)
- power_output++
- src.updateUsrDialog()
- if (href_list["action"] == "close")
- usr << browse(null, "window=port_gen")
- usr.unset_machine()
-
-/obj/machinery/power/port_gen/pacman/super
- name = "\improper S.U.P.E.R.P.A.C.M.A.N.-type portable generator"
- icon_state = "portgen1"
- sheet_path = /obj/item/stack/sheet/mineral/uranium
- power_gen = 15000
- time_per_sheet = 85
- board_path = "/obj/item/weapon/circuitboard/pacman/super"
- overheat()
- explosion(src.loc, 3, 3, 3, -1)
-
-/obj/machinery/power/port_gen/pacman/mrs
- name = "\improper M.R.S.P.A.C.M.A.N.-type portable generator"
- icon_state = "portgen2"
- sheet_path = /obj/item/stack/sheet/mineral/diamond
- power_gen = 40000
- time_per_sheet = 80
- board_path = "/obj/item/weapon/circuitboard/pacman/mrs"
- overheat()
- explosion(src.loc, 4, 4, 4, -1)
+//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
+
+/* new portable generator - work in progress
+
+/obj/machinery/power/port_gen
+ name = "portable generator"
+ desc = "A portable generator used for emergency backup power."
+ icon = 'generator.dmi'
+ icon_state = "off"
+ density = 1
+ anchored = 0
+ directwired = 0
+ var/t_status = 0
+ var/t_per = 5000
+ var/filter = 1
+ var/tank = null
+ var/turf/inturf
+ var/starter = 0
+ var/rpm = 0
+ var/rpmtarget = 0
+ var/capacity = 1e6
+ var/turf/outturf
+ var/lastgen
+
+
+/obj/machinery/power/port_gen/process()
+ideally we're looking to generate 5000
+
+/obj/machinery/power/port_gen/attackby(obj/item/weapon/W, mob/user)
+tank [un]loading stuff
+
+/obj/machinery/power/port_gen/attack_hand(mob/user)
+turn on/off
+
+/obj/machinery/power/port_gen/examine()
+display round(lastgen) and plasmatank amount
+
+*/
+
+//Previous code been here forever, adding new framework for portable generators
+
+
+//Baseline portable generator. Has all the default handling. Not intended to be used on it's own (since it generates unlimited power).
+/obj/machinery/power/port_gen
+ name = "portable generator"
+ desc = "A portable generator for emergency backup power"
+ icon = 'icons/obj/power.dmi'
+ icon_state = "portgen0"
+ density = 1
+ anchored = 0
+ directwired = 0
+ use_power = 0
+
+ var/active = 0
+ var/power_gen = 5000
+ var/recent_fault = 0
+ var/power_output = 1
+ var/consumption = 0
+
+/obj/machinery/power/port_gen/proc/HasFuel() //Placeholder for fuel check.
+ return 1
+
+/obj/machinery/power/port_gen/proc/UseFuel() //Placeholder for fuel use.
+ return
+
+/obj/machinery/power/port_gen/proc/DropFuel()
+ return
+
+/obj/machinery/power/port_gen/proc/handleInactive()
+ return
+
+/obj/machinery/power/port_gen/process()
+ if(active && HasFuel() && !crit_fail && anchored && powernet)
+ add_avail(power_gen * power_output)
+ UseFuel()
+ src.updateDialog()
+
+ else
+ active = 0
+ icon_state = initial(icon_state)
+ handleInactive()
+
+/obj/machinery/power/port_gen/attack_hand(mob/user as mob)
+ if(..())
+ return
+ if(!anchored)
+ return
+
+/obj/machinery/power/port_gen/examine()
+ set src in oview(1)
+ ..()
+ if(active)
+ usr << "It is running."
+ else
+ usr << "It isn't running."
+
+/obj/machinery/power/port_gen/pacman
+ name = "\improper P.A.C.M.A.N.-type portable generator"
+ var/sheets = 0
+ var/max_sheets = 100
+ var/sheet_name = ""
+ var/sheet_path = /obj/item/stack/sheet/mineral/plasma
+ var/board_path = "/obj/item/weapon/circuitboard/pacman"
+ var/sheet_left = 0 // How much is left of the sheet
+ var/time_per_sheet = 260
+ var/heat = 0
+
+/obj/machinery/power/port_gen/pacman/initialize()
+ ..()
+ if(anchored)
+ connect_to_network()
+
+/obj/machinery/power/port_gen/pacman/New()
+ ..()
+ component_parts = list()
+ component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
+ component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
+ component_parts += new /obj/item/stack/cable_coil(src, 1)
+ component_parts += new /obj/item/stack/cable_coil(src, 1)
+ component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
+ component_parts += new board_path(src)
+ var/obj/sheet = new sheet_path(null)
+ sheet_name = sheet.name
+ RefreshParts()
+
+/obj/machinery/power/port_gen/pacman/Destroy()
+ DropFuel()
+ ..()
+
+/obj/machinery/power/port_gen/pacman/RefreshParts()
+ var/temp_rating = 0
+ var/temp_reliability = 0
+ var/consumption_coeff = 0
+ for(var/obj/item/weapon/stock_parts/SP in component_parts)
+ if(istype(SP, /obj/item/weapon/stock_parts/matter_bin))
+ max_sheets = SP.rating * SP.rating * 50
+ else if(istype(SP, /obj/item/weapon/stock_parts/capacitor))
+ temp_rating += SP.rating
+ else
+ consumption_coeff += SP.rating
+ for(var/obj/item/weapon/CP in component_parts)
+ temp_reliability += CP.reliability
+ reliability = min(round(temp_reliability / 4), 100)
+ power_gen = round(initial(power_gen) * temp_rating * 2)
+ consumption = consumption_coeff
+
+/obj/machinery/power/port_gen/pacman/examine()
+ ..()
+ usr << "\blue The generator has [sheets] units of [sheet_name] fuel left, producing [power_gen] per cycle."
+ if(crit_fail) usr << "\red The generator seems to have broken down."
+
+/obj/machinery/power/port_gen/pacman/HasFuel()
+ if(sheets >= 1 / (time_per_sheet / power_output) - sheet_left)
+ return 1
+ return 0
+
+/obj/machinery/power/port_gen/pacman/DropFuel()
+ if(sheets)
+ var/fail_safe = 0
+ while(sheets > 0 && fail_safe < 100)
+ fail_safe += 1
+ var/obj/item/stack/sheet/S = new sheet_path(loc)
+ var/amount = min(sheets, S.max_amount)
+ S.amount = amount
+ sheets -= amount
+
+/obj/machinery/power/port_gen/pacman/UseFuel()
+ var/needed_sheets = 1 / (time_per_sheet * consumption / power_output)
+ var/temp = min(needed_sheets, sheet_left)
+ needed_sheets -= temp
+ sheet_left -= temp
+ sheets -= round(needed_sheets)
+ needed_sheets -= round(needed_sheets)
+ if (sheet_left <= 0 && sheets > 0)
+ sheet_left = 1 - needed_sheets
+ sheets--
+
+ var/lower_limit = 56 + power_output * 10
+ var/upper_limit = 76 + power_output * 10
+ var/bias = 0
+ if (power_output > 4)
+ upper_limit = 400
+ bias = power_output - consumption * (4 - consumption)
+ if (heat < lower_limit)
+ heat += 4 - consumption
+ else
+ heat += rand(-7 + bias, 7 + bias)
+ if (heat < lower_limit)
+ heat = lower_limit
+ if (heat > upper_limit)
+ heat = upper_limit
+
+ if (heat > 300)
+ overheat()
+ qdel(src)
+ return
+
+/obj/machinery/power/port_gen/pacman/handleInactive()
+
+ if (heat > 0)
+ heat = max(heat - 2, 0)
+ src.updateDialog()
+
+/obj/machinery/power/port_gen/pacman/proc/overheat()
+ explosion(src.loc, 2, 5, 2, -1)
+
+/obj/machinery/power/port_gen/pacman/attackby(var/obj/item/O as obj, var/mob/user as mob)
+ if(istype(O, sheet_path))
+ var/obj/item/stack/addstack = O
+ var/amount = min((max_sheets - sheets), addstack.amount)
+ if(amount < 1)
+ user << "\blue The [src.name] is full!"
+ return
+ user << "\blue You add [amount] sheets to the [src.name]."
+ sheets += amount
+ addstack.use(amount)
+ updateUsrDialog()
+ return
+ else if (istype(O, /obj/item/weapon/card/emag))
+ emagged = 1
+ emp_act(1)
+ else if(!active)
+
+ if(exchange_parts(user, O))
+ return
+
+ if(istype(O, /obj/item/weapon/wrench))
+
+ if(!anchored && !isinspace())
+ connect_to_network()
+ user << "\blue You secure the generator to the floor."
+ anchored = 1
+ else if(anchored)
+ disconnect_from_network()
+ user << "\blue You unsecure the generator from the floor."
+ anchored = 0
+
+ playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
+
+ else if(istype(O, /obj/item/weapon/screwdriver))
+ panel_open = !panel_open
+ playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
+ if(panel_open)
+ user << "\blue You open the access panel."
+ else
+ user << "\blue You close the access panel."
+ else if(istype(O, /obj/item/weapon/crowbar) && panel_open)
+ default_deconstruction_crowbar(O)
+
+/obj/machinery/power/port_gen/pacman/attack_hand(mob/user as mob)
+ ..()
+ if (!anchored)
+ return
+
+ interact(user)
+
+/obj/machinery/power/port_gen/pacman/attack_ai(mob/user as mob)
+ interact(user)
+
+/obj/machinery/power/port_gen/pacman/attack_paw(mob/user as mob)
+ interact(user)
+
+/obj/machinery/power/port_gen/pacman/interact(mob/user)
+ if (get_dist(src, user) > 1 )
+ if (!istype(user, /mob/living/silicon/ai))
+ user.unset_machine()
+ user << browse(null, "window=port_gen")
+ return
+
+ user.set_machine(src)
+
+ var/dat = text("[name]
")
+ if (active)
+ dat += text("Generator: On
")
+ else
+ dat += text("Generator: Off
")
+ dat += text("[capitalize(sheet_name)]: [sheets] - Eject
")
+ var/stack_percent = round(sheet_left * 100, 1)
+ dat += text("Current stack: [stack_percent]%
")
+ dat += text("Power output: - [power_gen * power_output] +
")
+ dat += text("Power current: [(powernet == null ? "Unconnected" : "[avail()]")]
")
+ dat += text("Heat: [heat]
")
+ dat += "
Close"
+ user << browse("[dat]", "window=port_gen")
+ onclose(user, "port_gen")
+
+/obj/machinery/power/port_gen/pacman/Topic(href, href_list)
+ if(..())
+ return
+
+ src.add_fingerprint(usr)
+ if(href_list["action"])
+ if(href_list["action"] == "enable")
+ if(!active && HasFuel() && !crit_fail)
+ active = 1
+ icon_state = "portgen1"
+ src.updateUsrDialog()
+ if(href_list["action"] == "disable")
+ if (active)
+ active = 0
+ icon_state = "portgen0"
+ src.updateUsrDialog()
+ if(href_list["action"] == "eject")
+ if(!active)
+ DropFuel()
+ src.updateUsrDialog()
+ if(href_list["action"] == "lower_power")
+ if (power_output > 1)
+ power_output--
+ src.updateUsrDialog()
+ if (href_list["action"] == "higher_power")
+ if (power_output < 4 || emagged)
+ power_output++
+ src.updateUsrDialog()
+ if (href_list["action"] == "close")
+ usr << browse(null, "window=port_gen")
+ usr.unset_machine()
+
+/obj/machinery/power/port_gen/pacman/super
+ name = "\improper S.U.P.E.R.P.A.C.M.A.N.-type portable generator"
+ icon_state = "portgen1"
+ sheet_path = /obj/item/stack/sheet/mineral/uranium
+ power_gen = 15000
+ time_per_sheet = 85
+ board_path = "/obj/item/weapon/circuitboard/pacman/super"
+ overheat()
+ explosion(src.loc, 3, 3, 3, -1)
+
+/obj/machinery/power/port_gen/pacman/mrs
+ name = "\improper M.R.S.P.A.C.M.A.N.-type portable generator"
+ icon_state = "portgen2"
+ sheet_path = /obj/item/stack/sheet/mineral/diamond
+ power_gen = 40000
+ time_per_sheet = 80
+ board_path = "/obj/item/weapon/circuitboard/pacman/mrs"
+ overheat()
+ explosion(src.loc, 4, 4, 4, -1)
diff --git a/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm b/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm
index 929fdc1fb2a..2e037f8e76e 100644
--- a/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm
+++ b/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm
@@ -1,416 +1,416 @@
-//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
-
-/*Composed of 7 parts
-3 Particle emitters
-proc
-emit_particle()
-
-1 power box
-the only part of this thing that uses power, can hack to mess with the pa/make it better
-
-1 fuel chamber
-contains procs for mixing gas and whatever other fuel it uses
-mix_gas()
-
-1 gas holder WIP
-acts like a tank valve on the ground that you wrench gas tanks onto
-proc
-extract_gas()
-return_gas()
-attach_tank()
-remove_tank()
-get_available_mix()
-
-1 End Cap
-
-1 Control computer
-interface for the pa, acts like a computer with an html menu for diff parts and a status report
-all other parts contain only a ref to this
-a /machine/, tells the others to do work
-contains ref for all parts
-proc
-process()
-check_build()
-
-Setup map
- |EC|
-CC|FC|
- |PB|
-PE|PE|PE
-
-
-Icon Addemdum
-Icon system is much more robust, and the icons are all variable based.
-Each part has a reference string, powered, strength, and contruction values.
-Using this the update_icon() proc is simplified a bit (using for absolutely was problematic with naming),
-so the icon_state comes out be:
-"[reference][strength]", with a switch controlling construction_states and ensuring that it doesn't
-power on while being contructed, and all these variables are set by the computer through it's scan list
-Essential order of the icons:
-Standard - [reference]
-Wrenched - [reference]
-Wired - [reference]w
-Closed - [reference]c
-Powered - [reference]p[strength]
-Strength being set by the computer and a null strength (Computer is powered off or inactive) returns a 'null', counting as empty
-So, hopefully this is helpful if any more icons are to be added/changed/wondering what the hell is going on here
-
-*/
-
-/obj/structure/particle_accelerator
- name = "Particle Accelerator"
- desc = "Part of a Particle Accelerator."
- icon = 'icons/obj/machines/particle_accelerator.dmi'
- icon_state = "none"
- anchored = 0
- density = 1
- var/obj/machinery/particle_accelerator/control_box/master = null
- var/construction_state = 0
- var/reference = null
- var/powered = 0
- var/strength = null
- var/desc_holder = null
-
-/obj/structure/particle_accelerator/Destroy()
- construction_state = 0
- if(master)
- master.part_scan()
- ..()
-
-/obj/structure/particle_accelerator/end_cap
- name = "Alpha Particle Generation Array"
- desc_holder = "This is where Alpha particles are generated from \[REDACTED\]"
- icon_state = "end_cap"
- reference = "end_cap"
-
-/obj/structure/particle_accelerator/update_icon()
- ..()
- return
-
-
-/obj/structure/particle_accelerator/verb/rotate()
- set name = "Rotate Clockwise"
- set category = "Object"
- set src in oview(1)
-
- if (src.anchored || usr:stat)
- usr << "It is fastened to the floor!"
- return 0
- src.dir = turn(src.dir, 270)
- return 1
-
-/obj/structure/particle_accelerator/verb/rotateccw()
- set name = "Rotate Counter Clockwise"
- set category = "Object"
- set src in oview(1)
-
- if (src.anchored || usr:stat)
- usr << "It is fastened to the floor!"
- return 0
- src.dir = turn(src.dir, 90)
- return 1
-
-/obj/structure/particle_accelerator/examine()
- switch(src.construction_state)
- if(0)
- src.desc = text("A [name], looks like it's not attached to the flooring")
- if(1)
- src.desc = text("A [name], it is missing some cables")
- if(2)
- src.desc = text("A [name], the panel is open")
- if(3)
- src.desc = text("The [name] is assembled")
- if(powered)
- src.desc = src.desc_holder
- ..()
- return
-
-
-/obj/structure/particle_accelerator/attackby(obj/item/W, mob/user)
- if(istool(W))
- if(src.process_tool_hit(W,user))
- return
- ..()
- return
-
-
-/obj/structure/particle_accelerator/Move()
- ..()
- if(master && master.active)
- master.toggle_power()
- investigate_log("was moved whilst active; it powered down.","singulo")
-
-/obj/structure/particle_accelerator/ex_act(severity)
- switch(severity)
- if(1.0)
- qdel(src)
- return
- if(2.0)
- if (prob(50))
- qdel(src)
- return
- if(3.0)
- if (prob(25))
- qdel(src)
- return
- else
- return
-
-
-/obj/structure/particle_accelerator/blob_act()
- if(prob(50))
- qdel(src)
- return
-
-
-/obj/structure/particle_accelerator/meteorhit()
- if(prob(50))
- qdel(src)
- return
-
-/obj/structure/particle_accelerator/update_icon()
- switch(construction_state)
- if(0,1)
- icon_state="[reference]"
- if(2)
- icon_state="[reference]w"
- if(3)
- if(powered)
- icon_state="[reference]p[strength]"
- else
- icon_state="[reference]c"
- return
-
-/obj/structure/particle_accelerator/proc/update_state()
- if(master)
- master.update_state()
- return 0
-
-
-/obj/structure/particle_accelerator/proc/report_ready(var/obj/O)
- if(O && (O == master))
- if(construction_state >= 3)
- return 1
- return 0
-
-
-/obj/structure/particle_accelerator/proc/report_master()
- if(master)
- return master
- return 0
-
-
-/obj/structure/particle_accelerator/proc/connect_master(var/obj/O)
- if(O && istype(O,/obj/machinery/particle_accelerator/control_box))
- if(O.dir == src.dir)
- master = O
- return 1
- return 0
-
-
-/obj/structure/particle_accelerator/proc/process_tool_hit(var/obj/O, var/mob/user)
- if(!(O) || !(user))
- return 0
- if(!ismob(user) || !isobj(O))
- return 0
- var/temp_state = src.construction_state
-
- switch(src.construction_state)//TODO:Might be more interesting to have it need several parts rather than a single list of steps
- if(0)
- if(istype(O, /obj/item/weapon/wrench) && !isinspace())
- playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
- src.anchored = 1
- user.visible_message("[user.name] secures the [src.name] to the floor.", \
- "You secure the external bolts.")
- temp_state++
- if(1)
- if(istype(O, /obj/item/weapon/wrench))
- playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
- src.anchored = 0
- user.visible_message("[user.name] detaches the [src.name] from the floor.", \
- "You remove the external bolts.")
- temp_state--
- else if(istype(O, /obj/item/stack/cable_coil))
- if(O:use(1,user))
- user.visible_message("[user.name] adds wires to the [src.name].", \
- "You add some wires.")
- temp_state++
- if(2)
- if(istype(O, /obj/item/weapon/wirecutters))//TODO:Shock user if its on?
- user.visible_message("[user.name] removes some wires from the [src.name].", \
- "You remove some wires.")
- temp_state--
- else if(istype(O, /obj/item/weapon/screwdriver))
- user.visible_message("[user.name] closes the [src.name]'s access panel.", \
- "You close the access panel.")
- temp_state++
- if(3)
- if(istype(O, /obj/item/weapon/screwdriver))
- user.visible_message("[user.name] opens the [src.name]'s access panel.", \
- "You open the access panel.")
- temp_state--
- if(temp_state == src.construction_state)//Nothing changed
- return 0
- else
- src.construction_state = temp_state
- if(src.construction_state < 3)//Was taken apart, update state
- update_state()
- update_icon()
- return 1
- return 0
-
-
-
-/obj/machinery/particle_accelerator
- name = "Particle Accelerator"
- desc = "Part of a Particle Accelerator."
- icon = 'icons/obj/machines/particle_accelerator.dmi'
- icon_state = "none"
- anchored = 0
- density = 1
- use_power = 0
- idle_power_usage = 0
- active_power_usage = 0
- var/construction_state = 0
- var/active = 0
- var/reference = null
- var/powered = null
- var/strength = 0
- var/desc_holder = null
-
-
-/obj/machinery/particle_accelerator/verb/rotate()
- set name = "Rotate Clockwise"
- set category = "Object"
- set src in oview(1)
-
- if (src.anchored || usr:stat)
- usr << "It is fastened to the floor!"
- return 0
- src.dir = turn(src.dir, 270)
- return 1
-
-/obj/machinery/particle_accelerator/verb/rotateccw()
- set name = "Rotate Counter-Clockwise"
- set category = "Object"
- set src in oview(1)
-
- if (src.anchored || usr:stat)
- usr << "It is fastened to the floor!"
- return 0
- src.dir = turn(src.dir, 90)
- return 1
-
-/obj/machinery/particle_accelerator/update_icon()
- return
-
-/obj/machinery/particle_accelerator/examine()
- switch(src.construction_state)
- if(0)
- src.desc = text("A [name], looks like it's not attached to the flooring")
- if(1)
- src.desc = text("A [name], it is missing some cables")
- if(2)
- src.desc = text("A [name], the panel is open")
- if(3)
- src.desc = text("The [name] is assembled")
- if(powered)
- src.desc = src.desc_holder
- ..()
- return
-
-
-/obj/machinery/particle_accelerator/attackby(obj/item/W, mob/user)
- if(istool(W))
- if(src.process_tool_hit(W,user))
- return
- ..()
- return
-
-/obj/machinery/particle_accelerator/ex_act(severity)
- switch(severity)
- if(1.0)
- qdel(src)
- return
- if(2.0)
- if (prob(50))
- qdel(src)
- return
- if(3.0)
- if (prob(25))
- qdel(src)
- return
- else
- return
-
-
-/obj/machinery/particle_accelerator/blob_act()
- if(prob(50))
- qdel(src)
- return
-
-
-/obj/machinery/particle_accelerator/meteorhit()
- if(prob(50))
- qdel(src)
- return
-
-
-/obj/machinery/particle_accelerator/proc/update_state()
- return 0
-
-
-/obj/machinery/particle_accelerator/proc/process_tool_hit(var/obj/O, var/mob/user)
- if(!(O) || !(user))
- return 0
- if(!ismob(user) || !isobj(O))
- return 0
- var/temp_state = src.construction_state
- switch(src.construction_state)//TODO:Might be more interesting to have it need several parts rather than a single list of steps
- if(0)
- if(istype(O, /obj/item/weapon/wrench))
- playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
- src.anchored = 1
- user.visible_message("[user.name] secures the [src.name] to the floor.", \
- "You secure the external bolts.")
- temp_state++
- if(1)
- if(istype(O, /obj/item/weapon/wrench))
- playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
- src.anchored = 0
- user.visible_message("[user.name] detaches the [src.name] from the floor.", \
- "You remove the external bolts.")
- temp_state--
- else if(istype(O, /obj/item/stack/cable_coil))
- if(O:use(1))
- user.visible_message("[user.name] adds wires to the [src.name].", \
- "You add some wires.")
- temp_state++
- if(2)
- if(istype(O, /obj/item/weapon/wirecutters))//TODO:Shock user if its on?
- user.visible_message("[user.name] removes some wires from the [src.name].", \
- "You remove some wires.")
- temp_state--
- else if(istype(O, /obj/item/weapon/screwdriver))
- user.visible_message("[user.name] closes the [src.name]'s access panel.", \
- "You close the access panel.")
- temp_state++
- if(3)
- if(istype(O, /obj/item/weapon/screwdriver))
- user.visible_message("[user.name] opens the [src.name]'s access panel.", \
- "You open the access panel.")
- temp_state--
- active = 0
- if(temp_state == src.construction_state)//Nothing changed
- return 0
- else
- if(src.construction_state < 3)//Was taken apart, update state
- update_state()
- if(use_power)
- use_power = 0
- src.construction_state = temp_state
- if(src.construction_state >= 3)
- use_power = 1
- update_icon()
- return 1
- return 0
+//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
+
+/*Composed of 7 parts
+3 Particle emitters
+proc
+emit_particle()
+
+1 power box
+the only part of this thing that uses power, can hack to mess with the pa/make it better
+
+1 fuel chamber
+contains procs for mixing gas and whatever other fuel it uses
+mix_gas()
+
+1 gas holder WIP
+acts like a tank valve on the ground that you wrench gas tanks onto
+proc
+extract_gas()
+return_gas()
+attach_tank()
+remove_tank()
+get_available_mix()
+
+1 End Cap
+
+1 Control computer
+interface for the pa, acts like a computer with an html menu for diff parts and a status report
+all other parts contain only a ref to this
+a /machine/, tells the others to do work
+contains ref for all parts
+proc
+process()
+check_build()
+
+Setup map
+ |EC|
+CC|FC|
+ |PB|
+PE|PE|PE
+
+
+Icon Addemdum
+Icon system is much more robust, and the icons are all variable based.
+Each part has a reference string, powered, strength, and contruction values.
+Using this the update_icon() proc is simplified a bit (using for absolutely was problematic with naming),
+so the icon_state comes out be:
+"[reference][strength]", with a switch controlling construction_states and ensuring that it doesn't
+power on while being contructed, and all these variables are set by the computer through it's scan list
+Essential order of the icons:
+Standard - [reference]
+Wrenched - [reference]
+Wired - [reference]w
+Closed - [reference]c
+Powered - [reference]p[strength]
+Strength being set by the computer and a null strength (Computer is powered off or inactive) returns a 'null', counting as empty
+So, hopefully this is helpful if any more icons are to be added/changed/wondering what the hell is going on here
+
+*/
+
+/obj/structure/particle_accelerator
+ name = "Particle Accelerator"
+ desc = "Part of a Particle Accelerator."
+ icon = 'icons/obj/machines/particle_accelerator.dmi'
+ icon_state = "none"
+ anchored = 0
+ density = 1
+ var/obj/machinery/particle_accelerator/control_box/master = null
+ var/construction_state = 0
+ var/reference = null
+ var/powered = 0
+ var/strength = null
+ var/desc_holder = null
+
+/obj/structure/particle_accelerator/Destroy()
+ construction_state = 0
+ if(master)
+ master.part_scan()
+ ..()
+
+/obj/structure/particle_accelerator/end_cap
+ name = "Alpha Particle Generation Array"
+ desc_holder = "This is where Alpha particles are generated from \[REDACTED\]"
+ icon_state = "end_cap"
+ reference = "end_cap"
+
+/obj/structure/particle_accelerator/update_icon()
+ ..()
+ return
+
+
+/obj/structure/particle_accelerator/verb/rotate()
+ set name = "Rotate Clockwise"
+ set category = "Object"
+ set src in oview(1)
+
+ if (src.anchored || usr:stat)
+ usr << "It is fastened to the floor!"
+ return 0
+ src.dir = turn(src.dir, 270)
+ return 1
+
+/obj/structure/particle_accelerator/verb/rotateccw()
+ set name = "Rotate Counter Clockwise"
+ set category = "Object"
+ set src in oview(1)
+
+ if (src.anchored || usr:stat)
+ usr << "It is fastened to the floor!"
+ return 0
+ src.dir = turn(src.dir, 90)
+ return 1
+
+/obj/structure/particle_accelerator/examine()
+ switch(src.construction_state)
+ if(0)
+ src.desc = text("A [name], looks like it's not attached to the flooring")
+ if(1)
+ src.desc = text("A [name], it is missing some cables")
+ if(2)
+ src.desc = text("A [name], the panel is open")
+ if(3)
+ src.desc = text("The [name] is assembled")
+ if(powered)
+ src.desc = src.desc_holder
+ ..()
+ return
+
+
+/obj/structure/particle_accelerator/attackby(obj/item/W, mob/user)
+ if(istool(W))
+ if(src.process_tool_hit(W,user))
+ return
+ ..()
+ return
+
+
+/obj/structure/particle_accelerator/Move()
+ ..()
+ if(master && master.active)
+ master.toggle_power()
+ investigate_log("was moved whilst active; it powered down.","singulo")
+
+/obj/structure/particle_accelerator/ex_act(severity)
+ switch(severity)
+ if(1.0)
+ qdel(src)
+ return
+ if(2.0)
+ if (prob(50))
+ qdel(src)
+ return
+ if(3.0)
+ if (prob(25))
+ qdel(src)
+ return
+ else
+ return
+
+
+/obj/structure/particle_accelerator/blob_act()
+ if(prob(50))
+ qdel(src)
+ return
+
+
+/obj/structure/particle_accelerator/meteorhit()
+ if(prob(50))
+ qdel(src)
+ return
+
+/obj/structure/particle_accelerator/update_icon()
+ switch(construction_state)
+ if(0,1)
+ icon_state="[reference]"
+ if(2)
+ icon_state="[reference]w"
+ if(3)
+ if(powered)
+ icon_state="[reference]p[strength]"
+ else
+ icon_state="[reference]c"
+ return
+
+/obj/structure/particle_accelerator/proc/update_state()
+ if(master)
+ master.update_state()
+ return 0
+
+
+/obj/structure/particle_accelerator/proc/report_ready(var/obj/O)
+ if(O && (O == master))
+ if(construction_state >= 3)
+ return 1
+ return 0
+
+
+/obj/structure/particle_accelerator/proc/report_master()
+ if(master)
+ return master
+ return 0
+
+
+/obj/structure/particle_accelerator/proc/connect_master(var/obj/O)
+ if(O && istype(O,/obj/machinery/particle_accelerator/control_box))
+ if(O.dir == src.dir)
+ master = O
+ return 1
+ return 0
+
+
+/obj/structure/particle_accelerator/proc/process_tool_hit(var/obj/O, var/mob/user)
+ if(!(O) || !(user))
+ return 0
+ if(!ismob(user) || !isobj(O))
+ return 0
+ var/temp_state = src.construction_state
+
+ switch(src.construction_state)//TODO:Might be more interesting to have it need several parts rather than a single list of steps
+ if(0)
+ if(istype(O, /obj/item/weapon/wrench) && !isinspace())
+ playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
+ src.anchored = 1
+ user.visible_message("[user.name] secures the [src.name] to the floor.", \
+ "You secure the external bolts.")
+ temp_state++
+ if(1)
+ if(istype(O, /obj/item/weapon/wrench))
+ playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
+ src.anchored = 0
+ user.visible_message("[user.name] detaches the [src.name] from the floor.", \
+ "You remove the external bolts.")
+ temp_state--
+ else if(istype(O, /obj/item/stack/cable_coil))
+ if(O:use(1,user))
+ user.visible_message("[user.name] adds wires to the [src.name].", \
+ "You add some wires.")
+ temp_state++
+ if(2)
+ if(istype(O, /obj/item/weapon/wirecutters))//TODO:Shock user if its on?
+ user.visible_message("[user.name] removes some wires from the [src.name].", \
+ "You remove some wires.")
+ temp_state--
+ else if(istype(O, /obj/item/weapon/screwdriver))
+ user.visible_message("[user.name] closes the [src.name]'s access panel.", \
+ "You close the access panel.")
+ temp_state++
+ if(3)
+ if(istype(O, /obj/item/weapon/screwdriver))
+ user.visible_message("[user.name] opens the [src.name]'s access panel.", \
+ "You open the access panel.")
+ temp_state--
+ if(temp_state == src.construction_state)//Nothing changed
+ return 0
+ else
+ src.construction_state = temp_state
+ if(src.construction_state < 3)//Was taken apart, update state
+ update_state()
+ update_icon()
+ return 1
+ return 0
+
+
+
+/obj/machinery/particle_accelerator
+ name = "Particle Accelerator"
+ desc = "Part of a Particle Accelerator."
+ icon = 'icons/obj/machines/particle_accelerator.dmi'
+ icon_state = "none"
+ anchored = 0
+ density = 1
+ use_power = 0
+ idle_power_usage = 0
+ active_power_usage = 0
+ var/construction_state = 0
+ var/active = 0
+ var/reference = null
+ var/powered = null
+ var/strength = 0
+ var/desc_holder = null
+
+
+/obj/machinery/particle_accelerator/verb/rotate()
+ set name = "Rotate Clockwise"
+ set category = "Object"
+ set src in oview(1)
+
+ if (src.anchored || usr:stat)
+ usr << "It is fastened to the floor!"
+ return 0
+ src.dir = turn(src.dir, 270)
+ return 1
+
+/obj/machinery/particle_accelerator/verb/rotateccw()
+ set name = "Rotate Counter-Clockwise"
+ set category = "Object"
+ set src in oview(1)
+
+ if (src.anchored || usr:stat)
+ usr << "It is fastened to the floor!"
+ return 0
+ src.dir = turn(src.dir, 90)
+ return 1
+
+/obj/machinery/particle_accelerator/update_icon()
+ return
+
+/obj/machinery/particle_accelerator/examine()
+ switch(src.construction_state)
+ if(0)
+ src.desc = text("A [name], looks like it's not attached to the flooring")
+ if(1)
+ src.desc = text("A [name], it is missing some cables")
+ if(2)
+ src.desc = text("A [name], the panel is open")
+ if(3)
+ src.desc = text("The [name] is assembled")
+ if(powered)
+ src.desc = src.desc_holder
+ ..()
+ return
+
+
+/obj/machinery/particle_accelerator/attackby(obj/item/W, mob/user)
+ if(istool(W))
+ if(src.process_tool_hit(W,user))
+ return
+ ..()
+ return
+
+/obj/machinery/particle_accelerator/ex_act(severity)
+ switch(severity)
+ if(1.0)
+ qdel(src)
+ return
+ if(2.0)
+ if (prob(50))
+ qdel(src)
+ return
+ if(3.0)
+ if (prob(25))
+ qdel(src)
+ return
+ else
+ return
+
+
+/obj/machinery/particle_accelerator/blob_act()
+ if(prob(50))
+ qdel(src)
+ return
+
+
+/obj/machinery/particle_accelerator/meteorhit()
+ if(prob(50))
+ qdel(src)
+ return
+
+
+/obj/machinery/particle_accelerator/proc/update_state()
+ return 0
+
+
+/obj/machinery/particle_accelerator/proc/process_tool_hit(var/obj/O, var/mob/user)
+ if(!(O) || !(user))
+ return 0
+ if(!ismob(user) || !isobj(O))
+ return 0
+ var/temp_state = src.construction_state
+ switch(src.construction_state)//TODO:Might be more interesting to have it need several parts rather than a single list of steps
+ if(0)
+ if(istype(O, /obj/item/weapon/wrench))
+ playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
+ src.anchored = 1
+ user.visible_message("[user.name] secures the [src.name] to the floor.", \
+ "You secure the external bolts.")
+ temp_state++
+ if(1)
+ if(istype(O, /obj/item/weapon/wrench))
+ playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
+ src.anchored = 0
+ user.visible_message("[user.name] detaches the [src.name] from the floor.", \
+ "You remove the external bolts.")
+ temp_state--
+ else if(istype(O, /obj/item/stack/cable_coil))
+ if(O:use(1))
+ user.visible_message("[user.name] adds wires to the [src.name].", \
+ "You add some wires.")
+ temp_state++
+ if(2)
+ if(istype(O, /obj/item/weapon/wirecutters))//TODO:Shock user if its on?
+ user.visible_message("[user.name] removes some wires from the [src.name].", \
+ "You remove some wires.")
+ temp_state--
+ else if(istype(O, /obj/item/weapon/screwdriver))
+ user.visible_message("[user.name] closes the [src.name]'s access panel.", \
+ "You close the access panel.")
+ temp_state++
+ if(3)
+ if(istype(O, /obj/item/weapon/screwdriver))
+ user.visible_message("[user.name] opens the [src.name]'s access panel.", \
+ "You open the access panel.")
+ temp_state--
+ active = 0
+ if(temp_state == src.construction_state)//Nothing changed
+ return 0
+ else
+ if(src.construction_state < 3)//Was taken apart, update state
+ update_state()
+ if(use_power)
+ use_power = 0
+ src.construction_state = temp_state
+ if(src.construction_state >= 3)
+ use_power = 1
+ update_icon()
+ return 1
+ return 0
diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm
index fa40707236e..ae5cf652a07 100644
--- a/code/modules/power/solar.dm
+++ b/code/modules/power/solar.dm
@@ -5,16 +5,6 @@
var/list/solars_list = list()
-// This will choose whether to get the solar list from the powernet or the powernet nodes,
-// depending on the size of the nodes.
-/obj/machinery/power/proc/get_solars_powernet()
- if(!powernet)
- return list()
- if(solars_list.len < powernet.nodes)
- return solars_list
- else
- return powernet.nodes
-
/obj/machinery/power/solar
name = "solar panel"
desc = "A solar electrical generator."
@@ -271,8 +261,7 @@ var/list/solars_list = list()
density = 1
directwired = 1
use_power = 1
- idle_power_usage = 5
- active_power_usage = 20
+ idle_power_usage = 250
var/id = 0
var/cdir = 0
var/gen = 0
@@ -318,18 +307,31 @@ var/list/solars_list = list()
overlays += image('icons/obj/computer.dmi', "solcon-o", FLY_LAYER, angle2dir(cdir))
return
-
-/obj/machinery/power/solar_control/attack_ai(mob/user)
- add_fingerprint(user)
- if(stat & (BROKEN | NOPOWER)) return
- interact(user)
-
-
/obj/machinery/power/solar_control/attack_hand(mob/user)
- add_fingerprint(user)
- if(stat & (BROKEN | NOPOWER)) return
- interact(user)
+ if(!..())
+ interact(user)
+/obj/machinery/power/solar_control/interact(mob/user)
+
+ var/t = "Generated power : [round(lastgen)] W
"
+ t += "Orientation: [rate_control(src,"cdir","[cdir]°",1,15)] ([angle2text(cdir)])
"
+ t += "Tracking:"
+ switch(track)
+ if(0)
+ t += "Off Timed Auto
"
+ if(1)
+ t += "Off Timed Auto
"
+ if(2)
+ t += "Off Timed Auto
"
+
+ t += "Tracking Rate: [rate_control(src,"tdir","[trackrate] deg/h ([trackrate<0 ? "CCW" : "CW"])",5,30,180)]
"
+ t += "Close"
+
+ var/datum/browser/popup = new(user, "solar", name)
+ popup.set_content(t)
+ popup.open()
+
+ return
/obj/machinery/power/solar_control/attackby(I as obj, user as mob)
if(istype(I, /obj/item/weapon/screwdriver))
@@ -370,7 +372,6 @@ var/list/solars_list = list()
if(stat & (NOPOWER | BROKEN))
return
- use_power(250)
if(track==1 && nexttime < world.timeofday && trackrate)
nexttime = world.timeofday + 3600/abs(trackrate)
cdir = (cdir+trackrate/abs(trackrate)+360)%360
@@ -388,37 +389,6 @@ var/list/solars_list = list()
src.updateDialog()
-/obj/machinery/power/solar_control/interact(mob/user)
- if(stat & (BROKEN | NOPOWER)) return
- if ( (get_dist(src, user) > 1 ))
- if (!istype(user, /mob/living/silicon/ai))
- user.unset_machine()
- user << browse(null, "window=solcon")
- return
-
- add_fingerprint(user)
- user.set_machine(src)
-
- var/t = "Solar Generator Control
"
- t += "Generated power : [round(lastgen)] W
"
- t += "Orientation: [rate_control(src,"cdir","[cdir]°",1,15)] ([angle2text(cdir)])
"
- t += "
"
- t += "Tracking: "
- switch(track)
- if(0)
- t += "Off Timed Auto
"
- if(1)
- t += "Off Timed Auto
"
- if(2)
- t += "Off Timed Auto
"
-
- t += "Tracking Rate: [rate_control(src,"tdir","[trackrate] deg/h ([trackrate<0 ? "CCW" : "CW"])",5,30,180)]
"
- t += "Close
"
- user << browse(t, "window=solcon")
- onclose(user, "solcon")
- return
-
-
/obj/machinery/power/solar_control/Topic(href, href_list)
if(..())
usr << browse(null, "window=solcon")
@@ -446,7 +416,7 @@ var/list/solars_list = list()
if(src.trackrate) nexttime = world.timeofday + 3600/abs(trackrate)
track = text2num(href_list["track"])
if(powernet && (track == 2))
- for(var/obj/machinery/power/tracker/T in get_solars_powernet())
+ for(var/obj/machinery/power/tracker/T in powernet.nodes)
if(powernet.nodes[T])
cdir = T.sun_angle
break
@@ -458,7 +428,7 @@ var/list/solars_list = list()
/obj/machinery/power/solar_control/proc/set_panels(var/cdir)
if(!powernet) return
- for(var/obj/machinery/power/solar/S in get_solars_powernet())
+ for(var/obj/machinery/power/solar/S in powernet.nodes)
if(powernet.nodes[S])
if(get_dist(S, src) < SOLAR_MAX_DIST)
if(!S.control)
@@ -468,13 +438,8 @@ var/list/solars_list = list()
/obj/machinery/power/solar_control/power_change()
- if(powered())
- stat &= ~NOPOWER
- update_icon()
- else
- spawn(rand(0, 15))
- stat |= NOPOWER
- update_icon()
+ ..()
+ update_icon()
/obj/machinery/power/solar_control/proc/broken()
diff --git a/code/modules/power/tracker.dm b/code/modules/power/tracker.dm
index 29f715b368d..64ce3f474d7 100644
--- a/code/modules/power/tracker.dm
+++ b/code/modules/power/tracker.dm
@@ -40,15 +40,11 @@
//set icon dir to show sun illumination
dir = turn(NORTH, -angle - 22.5) // 22.5 deg bias ensures, e.g. 67.5-112.5 is EAST
- // check we can draw power
- if(stat & NOPOWER)
- return
-
// find all solar controls and update them
// currently, just update all controllers in world
// ***TODO: better communication system using network
if(powernet)
- for(var/obj/machinery/power/solar_control/C in get_solars_powernet())
+ for(var/obj/machinery/power/solar_control/C in powernet.nodes)
if(powernet.nodes[C])
if(get_dist(C, src) < SOLAR_MAX_DIST)
C.tracker_update(angle)
@@ -69,19 +65,6 @@
return
..()
-// timed process
-// make sure we can draw power from the powernet
-/obj/machinery/power/tracker/process()
-
- var/avail = surplus()
-
- if(avail > 500)
- add_load(500)
- stat &= ~NOPOWER
- else
- stat |= NOPOWER
-
-
// Tracker Electronic
/obj/item/weapon/tracker_electronics
diff --git a/code/modules/projectiles/ammunition/energy.dm b/code/modules/projectiles/ammunition/energy.dm
index 90834ff8489..aa0d1f84412 100644
--- a/code/modules/projectiles/ammunition/energy.dm
+++ b/code/modules/projectiles/ammunition/energy.dm
@@ -1,118 +1,118 @@
-/obj/item/ammo_casing/energy
- name = "energy weapon lens"
- desc = "The part of the gun that makes the laser go pew"
- caliber = "energy"
- projectile_type = /obj/item/projectile/energy
- var/e_cost = 100 //The amount of energy a cell needs to expend to create this shot.
- var/select_name = "energy"
- var/mod_name = null
- var/fire_sound = 'sound/weapons/Laser.ogg'
-
-/obj/item/ammo_casing/energy/laser
- projectile_type = /obj/item/projectile/beam
- select_name = "kill"
-
-/obj/item/ammo_casing/energy/laser/practice
- projectile_type = /obj/item/projectile/practice
- select_name = "practice"
-
-/obj/item/ammo_casing/energy/laser/scatter
- projectile_type = /obj/item/projectile/beam/scatter
- pellets = 5
- variance = 0.8
- select_name = "scatter"
-
-/obj/item/ammo_casing/energy/laser/heavy
- projectile_type = /obj/item/projectile/beam/heavylaser
- select_name = "anti-vehicle"
- fire_sound = 'sound/weapons/lasercannonfire.ogg'
-
-/obj/item/ammo_casing/energy/laser/pulse
- projectile_type = /obj/item/projectile/beam/pulse
- e_cost = 200
- select_name = "DESTROY"
- fire_sound = 'sound/weapons/pulse.ogg'
-
-/obj/item/ammo_casing/energy/laser/bluetag
- projectile_type = /obj/item/projectile/lasertag/bluetag
- select_name = "bluetag"
-
-/obj/item/ammo_casing/energy/laser/redtag
- projectile_type = /obj/item/projectile/lasertag/redtag
- select_name = "redtag"
-
-/obj/item/ammo_casing/energy/bolt
- projectile_type = /obj/item/projectile/energy/bolt
- select_name = "bolt"
- fire_sound = 'sound/weapons/Genhit.ogg'
-
-/obj/item/ammo_casing/energy/bolt/large
- projectile_type = /obj/item/projectile/energy/bolt/large
- select_name = "heavy bolt"
-
-/obj/item/ammo_casing/energy/xray
- projectile_type = /obj/item/projectile/beam/xray
- e_cost = 50
- fire_sound = 'sound/weapons/laser3.ogg'
-
-/obj/item/ammo_casing/energy/electrode
- projectile_type = /obj/item/projectile/energy/electrode
- select_name = "stun"
- fire_sound = 'sound/weapons/taser.ogg'
-
-/obj/item/ammo_casing/energy/electrode/gun
- fire_sound = 'sound/weapons/gunshot.ogg'
-
-/obj/item/ammo_casing/energy/ion
- projectile_type = /obj/item/projectile/ion
- select_name = "ion"
- fire_sound = 'sound/weapons/Laser.ogg'
-
-/obj/item/ammo_casing/energy/declone
- projectile_type = /obj/item/projectile/energy/declone
- select_name = "declone"
- fire_sound = 'sound/weapons/pulse3.ogg'
-
-/obj/item/ammo_casing/energy/mindflayer
- projectile_type = /obj/item/projectile/beam/mindflayer
- select_name = "MINDFUCK"
- fire_sound = 'sound/weapons/Laser.ogg'
-
-/obj/item/ammo_casing/energy/flora
- fire_sound = 'sound/effects/stealthoff.ogg'
-
-/obj/item/ammo_casing/energy/flora/yield
- projectile_type = /obj/item/projectile/energy/florayield
- select_name = "increase yield"
- mod_name = "yield"
-
-/obj/item/ammo_casing/energy/flora/mut
- projectile_type = /obj/item/projectile/energy/floramut
- select_name = "induce mutations"
- mod_name = "mut"
-
-/obj/item/ammo_casing/energy/temp
- projectile_type = /obj/item/projectile/temp
- select_name = "freeze"
- e_cost = 250
- fire_sound = 'sound/weapons/pulse3.ogg'
-
-/obj/item/ammo_casing/energy/temp/hot
- projectile_type = /obj/item/projectile/temp/hot
- select_name = "bake"
-
-/obj/item/ammo_casing/energy/meteor
- projectile_type = /obj/item/projectile/meteor
- select_name = "goddamn meteor"
-
-/obj/item/ammo_casing/energy/kinetic
- projectile_type = /obj/item/projectile/kinetic
- select_name = "kinetic"
- e_cost = 500
- fire_sound = 'sound/weapons/Gunshot4.ogg'
-
-/obj/item/ammo_casing/energy/disabler
- projectile_type = /obj/item/projectile/energy/disabler
- select_name = "disable"
- e_cost = 50
+/obj/item/ammo_casing/energy
+ name = "energy weapon lens"
+ desc = "The part of the gun that makes the laser go pew"
+ caliber = "energy"
+ projectile_type = /obj/item/projectile/energy
+ var/e_cost = 100 //The amount of energy a cell needs to expend to create this shot.
+ var/select_name = "energy"
+ var/mod_name = null
+ var/fire_sound = 'sound/weapons/Laser.ogg'
+
+/obj/item/ammo_casing/energy/laser
+ projectile_type = /obj/item/projectile/beam
+ select_name = "kill"
+
+/obj/item/ammo_casing/energy/laser/practice
+ projectile_type = /obj/item/projectile/practice
+ select_name = "practice"
+
+/obj/item/ammo_casing/energy/laser/scatter
+ projectile_type = /obj/item/projectile/beam/scatter
+ pellets = 5
+ variance = 0.8
+ select_name = "scatter"
+
+/obj/item/ammo_casing/energy/laser/heavy
+ projectile_type = /obj/item/projectile/beam/heavylaser
+ select_name = "anti-vehicle"
+ fire_sound = 'sound/weapons/lasercannonfire.ogg'
+
+/obj/item/ammo_casing/energy/laser/pulse
+ projectile_type = /obj/item/projectile/beam/pulse
+ e_cost = 200
+ select_name = "DESTROY"
+ fire_sound = 'sound/weapons/pulse.ogg'
+
+/obj/item/ammo_casing/energy/laser/bluetag
+ projectile_type = /obj/item/projectile/lasertag/bluetag
+ select_name = "bluetag"
+
+/obj/item/ammo_casing/energy/laser/redtag
+ projectile_type = /obj/item/projectile/lasertag/redtag
+ select_name = "redtag"
+
+/obj/item/ammo_casing/energy/bolt
+ projectile_type = /obj/item/projectile/energy/bolt
+ select_name = "bolt"
+ fire_sound = 'sound/weapons/Genhit.ogg'
+
+/obj/item/ammo_casing/energy/bolt/large
+ projectile_type = /obj/item/projectile/energy/bolt/large
+ select_name = "heavy bolt"
+
+/obj/item/ammo_casing/energy/xray
+ projectile_type = /obj/item/projectile/beam/xray
+ e_cost = 50
+ fire_sound = 'sound/weapons/laser3.ogg'
+
+/obj/item/ammo_casing/energy/electrode
+ projectile_type = /obj/item/projectile/energy/electrode
+ select_name = "stun"
+ fire_sound = 'sound/weapons/taser.ogg'
+
+/obj/item/ammo_casing/energy/electrode/gun
+ fire_sound = 'sound/weapons/gunshot.ogg'
+
+/obj/item/ammo_casing/energy/ion
+ projectile_type = /obj/item/projectile/ion
+ select_name = "ion"
+ fire_sound = 'sound/weapons/Laser.ogg'
+
+/obj/item/ammo_casing/energy/declone
+ projectile_type = /obj/item/projectile/energy/declone
+ select_name = "declone"
+ fire_sound = 'sound/weapons/pulse3.ogg'
+
+/obj/item/ammo_casing/energy/mindflayer
+ projectile_type = /obj/item/projectile/beam/mindflayer
+ select_name = "MINDFUCK"
+ fire_sound = 'sound/weapons/Laser.ogg'
+
+/obj/item/ammo_casing/energy/flora
+ fire_sound = 'sound/effects/stealthoff.ogg'
+
+/obj/item/ammo_casing/energy/flora/yield
+ projectile_type = /obj/item/projectile/energy/florayield
+ select_name = "increase yield"
+ mod_name = "yield"
+
+/obj/item/ammo_casing/energy/flora/mut
+ projectile_type = /obj/item/projectile/energy/floramut
+ select_name = "induce mutations"
+ mod_name = "mut"
+
+/obj/item/ammo_casing/energy/temp
+ projectile_type = /obj/item/projectile/temp
+ select_name = "freeze"
+ e_cost = 250
+ fire_sound = 'sound/weapons/pulse3.ogg'
+
+/obj/item/ammo_casing/energy/temp/hot
+ projectile_type = /obj/item/projectile/temp/hot
+ select_name = "bake"
+
+/obj/item/ammo_casing/energy/meteor
+ projectile_type = /obj/item/projectile/meteor
+ select_name = "goddamn meteor"
+
+/obj/item/ammo_casing/energy/kinetic
+ projectile_type = /obj/item/projectile/kinetic
+ select_name = "kinetic"
+ e_cost = 500
+ fire_sound = 'sound/weapons/Gunshot4.ogg'
+
+/obj/item/ammo_casing/energy/disabler
+ projectile_type = /obj/item/projectile/energy/disabler
+ select_name = "disable"
+ e_cost = 50
fire_sound = "sound/weapons/taser.ogg"
\ No newline at end of file
diff --git a/code/modules/projectiles/ammunition/magazines.dm b/code/modules/projectiles/ammunition/magazines.dm
index 81b6af92124..1e44c1c7c73 100644
--- a/code/modules/projectiles/ammunition/magazines.dm
+++ b/code/modules/projectiles/ammunition/magazines.dm
@@ -1,161 +1,161 @@
-////////////////INTERNAL MAGAZINES//////////////////////
-/obj/item/ammo_box/magazine/internal/cylinder
- name = "revolver cylinder"
- desc = "Oh god, this shouldn't be here"
- ammo_type = /obj/item/ammo_casing/a357
- caliber = "357"
- max_ammo = 7
-
-/obj/item/ammo_box/magazine/internal/cylinder/ammo_count(var/countempties = 1)
- if (!countempties)
- var/boolets = 0
- for (var/i = 1, i <= stored_ammo.len, i++)
- var/obj/item/ammo_casing/bullet = stored_ammo[i]
- if (bullet.BB)
- boolets++
- return boolets
- else
- return ..()
-
-/obj/item/ammo_box/magazine/internal/cylinder/rus357
- name = "russian revolver cylinder"
- desc = "Oh god, this shouldn't be here"
- ammo_type = /obj/item/ammo_casing/a357
- caliber = "357"
- max_ammo = 6
- multiload = 0
-
-/obj/item/ammo_box/magazine/internal/cylinder/rus357/New()
- stored_ammo += new ammo_type(src)
-
-/obj/item/ammo_box/magazine/internal/cylinder/rev38
- name = "d-tiv revolver cylinder"
- desc = "Oh god, this shouldn't be here"
- ammo_type = /obj/item/ammo_casing/c38
- caliber = "38"
- max_ammo = 6
-
-/obj/item/ammo_box/magazine/internal/shot
- name = "shotgun internal magazine"
- desc = "Oh god, this shouldn't be here"
- ammo_type = /obj/item/ammo_casing/shotgun/beanbag
- caliber = "shotgun"
- max_ammo = 4
- multiload = 0
-
-/obj/item/ammo_box/magazine/internal/shotcom
- name = "combat shotgun internal magazine"
- desc = "Oh god, this shouldn't be here"
- ammo_type = /obj/item/ammo_casing/shotgun/buckshot
- caliber = "shotgun"
- max_ammo = 8
- multiload = 0
-
-/obj/item/ammo_box/magazine/internal/cylinder/dualshot
- name = "double-barrel shotgun internal magazine"
- desc = "This doesn't even exist"
- ammo_type = /obj/item/ammo_casing/shotgun/beanbag
- caliber = "shotgun"
- max_ammo = 2
- multiload = 0
-
-///////////EXTERNAL MAGAZINES////////////////
-/obj/item/ammo_box/magazine/m9mm
- name = "magazine (9mm)"
- icon_state = "9x19p"
- origin_tech = "combat=2"
- ammo_type = /obj/item/ammo_casing/c9mm
- caliber = "9mm"
- max_ammo = 8
- multiple_sprites = 2
-
-/obj/item/ammo_box/magazine/msmg9mm
- name = "SMG magazine (9mm)"
- icon_state = "smg9mm"
- ammo_type = /obj/item/ammo_casing/c9mm
- caliber = "9mm"
- max_ammo = 18
-
-/obj/item/ammo_box/magazine/msmg9mm/update_icon()
- ..()
- icon_state = "[initial(icon_state)]-[round(ammo_count(),3)]"
-
-/obj/item/ammo_box/magazine/m10mm
- name = "magazine (10mm)"
- icon_state = "9x19p"
- origin_tech = "combat=2"
- ammo_type = /obj/item/ammo_casing/c10mm
- caliber = "10mm"
- max_ammo = 8
- multiple_sprites = 2
-
-/obj/item/ammo_box/magazine/m12mm
- name = "magazine (12mm)"
- icon_state = "12mm"
- origin_tech = "combat=2"
- ammo_type = /obj/item/ammo_casing/a12mm
- caliber = "12mm"
- max_ammo = 20
-
-/obj/item/ammo_box/magazine/m12mm/update_icon()
- ..()
- icon_state = "[initial(icon_state)]-[round(ammo_count(),2)]"
-
-/obj/item/ammo_box/magazine/sm45
- name = "magazine (.45)"
- icon_state = "9x19p"
- ammo_type = /obj/item/ammo_casing/c45
- caliber = ".45"
- max_ammo = 12
-
-/obj/item/ammo_box/magazine/sm45/update_icon()
- ..()
- icon_state = "[initial(icon_state)]-[ammo_count() ? "8" : "0"]"
-
-/obj/item/ammo_box/magazine/uzim45
- name = "Uzi magazine (.45)"
- icon_state = "uzi45"
- ammo_type = /obj/item/ammo_casing/c45
- caliber = ".45"
- max_ammo = 16
-
-/obj/item/ammo_box/magazine/uzim45/update_icon()
- ..()
- icon_state = "[initial(icon_state)]-[round(ammo_count(),2)]"
-
-obj/item/ammo_box/magazine/tommygunm45
- name = "tommy gun drum (.45)"
- icon_state = "drum45"
- ammo_type = /obj/item/ammo_casing/c45
- caliber = ".45"
- max_ammo = 50
-
-/obj/item/ammo_box/magazine/m50
- name = "magazine (.50ae)"
- icon_state = "50ae"
- origin_tech = "combat=2"
- ammo_type = /obj/item/ammo_casing/a50
- caliber = ".50"
- max_ammo = 7
- multiple_sprites = 1
-
-/obj/item/ammo_box/magazine/m75
- name = "magazine (.75)"
- icon_state = "75"
- ammo_type = /obj/item/ammo_casing/caseless/a75
- caliber = "75"
- multiple_sprites = 2
- max_ammo = 8
-
-/obj/item/ammo_box/magazine/m762
- name = "magazine (7.62mm)"
- icon_state = "a762"
- origin_tech = "combat=2"
- ammo_type = /obj/item/ammo_casing/a762
- caliber = "a762"
- max_ammo = 50
-
-
-/obj/item/ammo_box/magazine/m762/update_icon()
- ..()
+////////////////INTERNAL MAGAZINES//////////////////////
+/obj/item/ammo_box/magazine/internal/cylinder
+ name = "revolver cylinder"
+ desc = "Oh god, this shouldn't be here"
+ ammo_type = /obj/item/ammo_casing/a357
+ caliber = "357"
+ max_ammo = 7
+
+/obj/item/ammo_box/magazine/internal/cylinder/ammo_count(var/countempties = 1)
+ if (!countempties)
+ var/boolets = 0
+ for (var/i = 1, i <= stored_ammo.len, i++)
+ var/obj/item/ammo_casing/bullet = stored_ammo[i]
+ if (bullet.BB)
+ boolets++
+ return boolets
+ else
+ return ..()
+
+/obj/item/ammo_box/magazine/internal/cylinder/rus357
+ name = "russian revolver cylinder"
+ desc = "Oh god, this shouldn't be here"
+ ammo_type = /obj/item/ammo_casing/a357
+ caliber = "357"
+ max_ammo = 6
+ multiload = 0
+
+/obj/item/ammo_box/magazine/internal/cylinder/rus357/New()
+ stored_ammo += new ammo_type(src)
+
+/obj/item/ammo_box/magazine/internal/cylinder/rev38
+ name = "d-tiv revolver cylinder"
+ desc = "Oh god, this shouldn't be here"
+ ammo_type = /obj/item/ammo_casing/c38
+ caliber = "38"
+ max_ammo = 6
+
+/obj/item/ammo_box/magazine/internal/shot
+ name = "shotgun internal magazine"
+ desc = "Oh god, this shouldn't be here"
+ ammo_type = /obj/item/ammo_casing/shotgun/beanbag
+ caliber = "shotgun"
+ max_ammo = 4
+ multiload = 0
+
+/obj/item/ammo_box/magazine/internal/shotcom
+ name = "combat shotgun internal magazine"
+ desc = "Oh god, this shouldn't be here"
+ ammo_type = /obj/item/ammo_casing/shotgun/buckshot
+ caliber = "shotgun"
+ max_ammo = 8
+ multiload = 0
+
+/obj/item/ammo_box/magazine/internal/cylinder/dualshot
+ name = "double-barrel shotgun internal magazine"
+ desc = "This doesn't even exist"
+ ammo_type = /obj/item/ammo_casing/shotgun/beanbag
+ caliber = "shotgun"
+ max_ammo = 2
+ multiload = 0
+
+///////////EXTERNAL MAGAZINES////////////////
+/obj/item/ammo_box/magazine/m9mm
+ name = "magazine (9mm)"
+ icon_state = "9x19p"
+ origin_tech = "combat=2"
+ ammo_type = /obj/item/ammo_casing/c9mm
+ caliber = "9mm"
+ max_ammo = 8
+ multiple_sprites = 2
+
+/obj/item/ammo_box/magazine/msmg9mm
+ name = "SMG magazine (9mm)"
+ icon_state = "smg9mm"
+ ammo_type = /obj/item/ammo_casing/c9mm
+ caliber = "9mm"
+ max_ammo = 18
+
+/obj/item/ammo_box/magazine/msmg9mm/update_icon()
+ ..()
+ icon_state = "[initial(icon_state)]-[round(ammo_count(),3)]"
+
+/obj/item/ammo_box/magazine/m10mm
+ name = "magazine (10mm)"
+ icon_state = "9x19p"
+ origin_tech = "combat=2"
+ ammo_type = /obj/item/ammo_casing/c10mm
+ caliber = "10mm"
+ max_ammo = 8
+ multiple_sprites = 2
+
+/obj/item/ammo_box/magazine/m12mm
+ name = "magazine (12mm)"
+ icon_state = "12mm"
+ origin_tech = "combat=2"
+ ammo_type = /obj/item/ammo_casing/a12mm
+ caliber = "12mm"
+ max_ammo = 20
+
+/obj/item/ammo_box/magazine/m12mm/update_icon()
+ ..()
+ icon_state = "[initial(icon_state)]-[round(ammo_count(),2)]"
+
+/obj/item/ammo_box/magazine/sm45
+ name = "magazine (.45)"
+ icon_state = "9x19p"
+ ammo_type = /obj/item/ammo_casing/c45
+ caliber = ".45"
+ max_ammo = 12
+
+/obj/item/ammo_box/magazine/sm45/update_icon()
+ ..()
+ icon_state = "[initial(icon_state)]-[ammo_count() ? "8" : "0"]"
+
+/obj/item/ammo_box/magazine/uzim45
+ name = "Uzi magazine (.45)"
+ icon_state = "uzi45"
+ ammo_type = /obj/item/ammo_casing/c45
+ caliber = ".45"
+ max_ammo = 16
+
+/obj/item/ammo_box/magazine/uzim45/update_icon()
+ ..()
+ icon_state = "[initial(icon_state)]-[round(ammo_count(),2)]"
+
+obj/item/ammo_box/magazine/tommygunm45
+ name = "tommy gun drum (.45)"
+ icon_state = "drum45"
+ ammo_type = /obj/item/ammo_casing/c45
+ caliber = ".45"
+ max_ammo = 50
+
+/obj/item/ammo_box/magazine/m50
+ name = "magazine (.50ae)"
+ icon_state = "50ae"
+ origin_tech = "combat=2"
+ ammo_type = /obj/item/ammo_casing/a50
+ caliber = ".50"
+ max_ammo = 7
+ multiple_sprites = 1
+
+/obj/item/ammo_box/magazine/m75
+ name = "magazine (.75)"
+ icon_state = "75"
+ ammo_type = /obj/item/ammo_casing/caseless/a75
+ caliber = "75"
+ multiple_sprites = 2
+ max_ammo = 8
+
+/obj/item/ammo_box/magazine/m762
+ name = "magazine (7.62mm)"
+ icon_state = "a762"
+ origin_tech = "combat=2"
+ ammo_type = /obj/item/ammo_casing/a762
+ caliber = "a762"
+ max_ammo = 50
+
+
+/obj/item/ammo_box/magazine/m762/update_icon()
+ ..()
icon_state = "[initial(icon_state)]-[round(ammo_count(),10)]"
\ No newline at end of file
diff --git a/code/modules/projectiles/ammunition/special.dm b/code/modules/projectiles/ammunition/special.dm
index e530d7c2fca..fb68b624499 100644
--- a/code/modules/projectiles/ammunition/special.dm
+++ b/code/modules/projectiles/ammunition/special.dm
@@ -24,6 +24,13 @@
/obj/item/ammo_casing/magic/fireball
projectile_type = /obj/item/projectile/magic/fireball
+/obj/item/ammo_casing/magic/chaos
+ projectile_type = /obj/item/projectile/magic
+
+/obj/item/ammo_casing/magic/chaos/newshot()
+ projectile_type = pick(typesof(/obj/item/projectile/magic))
+ ..()
+
/obj/item/ammo_casing/syringegun
name = "syringe gun spring"
desc = "A high-power spring that throws syringes."
diff --git a/code/modules/projectiles/firing.dm b/code/modules/projectiles/firing.dm
index 88853f6378f..4e056555929 100644
--- a/code/modules/projectiles/firing.dm
+++ b/code/modules/projectiles/firing.dm
@@ -1,61 +1,61 @@
-/obj/item/ammo_casing/proc/fire(atom/target as mob|obj|turf, mob/living/user as mob|obj, params, var/distro, var/quiet)
- distro += variance
- for (var/i = max(1, pellets), i > 0, i--)
- var/curloc = user.loc
- var/targloc = get_turf(target)
- ready_proj(target, user, quiet)
- if(distro)
- targloc = spread(targloc, curloc, distro)
- if(!throw_proj(targloc, user, params))
- return 0
- if(i > 1)
- newshot()
- user.next_move = world.time + 4
- update_icon()
- return 1
-
-/obj/item/ammo_casing/proc/ready_proj(atom/target as mob|obj|turf, mob/living/user, var/quiet)
- if (!BB)
- return
- BB.original = target
- BB.firer = user
- BB.def_zone = user.zone_sel.selecting
- BB.silenced = quiet
-
- if(reagents && BB.reagents)
- reagents.trans_to(BB, reagents.total_volume) //For chemical darts/bullets
- reagents.delete()
- return
-
-/obj/item/ammo_casing/proc/throw_proj(var/turf/targloc, mob/living/user as mob|obj, params)
- var/turf/curloc = user.loc
- if (!istype(targloc) || !istype(curloc) || !BB)
- return 0
- if(targloc == curloc) //Fire the projectile
- user.bullet_act(BB)
- qdel(BB)
- return 1
- BB.loc = get_turf(user)
- BB.starting = get_turf(user)
- BB.current = curloc
- BB.yo = targloc.y - curloc.y
- BB.xo = targloc.x - curloc.x
-
- if(params)
- var/list/mouse_control = params2list(params)
- if(mouse_control["icon-x"])
- BB.p_x = text2num(mouse_control["icon-x"])
- if(mouse_control["icon-y"])
- BB.p_y = text2num(mouse_control["icon-y"])
-
- if(BB)
- BB.process()
- BB = null
- return 1
-
-/obj/item/ammo_casing/proc/spread(var/turf/target, var/turf/current, var/distro)
- var/dx = abs(target.x - current.x)
- var/dy = abs(target.y - current.y)
- return locate(target.x + round(gaussian(0, distro) * (dy+2)/8, 1), target.y + round(gaussian(0, distro) * (dx+2)/8, 1), target.z)
-
+/obj/item/ammo_casing/proc/fire(atom/target as mob|obj|turf, mob/living/user as mob|obj, params, var/distro, var/quiet)
+ distro += variance
+ for (var/i = max(1, pellets), i > 0, i--)
+ var/curloc = user.loc
+ var/targloc = get_turf(target)
+ ready_proj(target, user, quiet)
+ if(distro)
+ targloc = spread(targloc, curloc, distro)
+ if(!throw_proj(targloc, user, params))
+ return 0
+ if(i > 1)
+ newshot()
+ user.changeNext_move(4)
+ update_icon()
+ return 1
+
+/obj/item/ammo_casing/proc/ready_proj(atom/target as mob|obj|turf, mob/living/user, var/quiet)
+ if (!BB)
+ return
+ BB.original = target
+ BB.firer = user
+ BB.def_zone = user.zone_sel.selecting
+ BB.silenced = quiet
+
+ if(reagents && BB.reagents)
+ reagents.trans_to(BB, reagents.total_volume) //For chemical darts/bullets
+ reagents.delete()
+ return
+
+/obj/item/ammo_casing/proc/throw_proj(var/turf/targloc, mob/living/user as mob|obj, params)
+ var/turf/curloc = user.loc
+ if (!istype(targloc) || !istype(curloc) || !BB)
+ return 0
+ if(targloc == curloc) //Fire the projectile
+ user.bullet_act(BB)
+ qdel(BB)
+ return 1
+ BB.loc = get_turf(user)
+ BB.starting = get_turf(user)
+ BB.current = curloc
+ BB.yo = targloc.y - curloc.y
+ BB.xo = targloc.x - curloc.x
+
+ if(params)
+ var/list/mouse_control = params2list(params)
+ if(mouse_control["icon-x"])
+ BB.p_x = text2num(mouse_control["icon-x"])
+ if(mouse_control["icon-y"])
+ BB.p_y = text2num(mouse_control["icon-y"])
+
+ if(BB)
+ BB.process()
+ BB = null
+ return 1
+
+/obj/item/ammo_casing/proc/spread(var/turf/target, var/turf/current, var/distro)
+ var/dx = abs(target.x - current.x)
+ var/dy = abs(target.y - current.y)
+ return locate(target.x + round(gaussian(0, distro) * (dy+2)/8, 1), target.y + round(gaussian(0, distro) * (dx+2)/8, 1), target.z)
+
// gaussian(0, distro)
\ No newline at end of file
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 284c49f2f91..b9afac39484 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -1,99 +1,99 @@
-/obj/item/weapon/gun
- name = "gun"
- desc = "It's a gun. It's pretty terrible, though."
- icon = 'icons/obj/gun.dmi'
- icon_state = "detective"
- item_state = "gun"
- flags = CONDUCT
- slot_flags = SLOT_BELT
- m_amt = 2000
- w_class = 3.0
- throwforce = 5
- throw_speed = 3
- throw_range = 5
- force = 5.0
- origin_tech = "combat=1"
- attack_verb = list("struck", "hit", "bashed")
-
- var/fire_sound = "gunshot"
- var/silenced = 0
- var/recoil = 0
- var/clumsy_check = 1
- var/obj/item/ammo_casing/chambered = null
- var/trigger_guard = 1
-
- proc/process_chamber()
- return 0
-
- proc/special_check(var/mob/M) //Placeholder for any special checks, like detective's revolver.
- return 1
-
- proc/shoot_with_empty_chamber(mob/living/user as mob|obj)
- user << "*click*"
- return
-
- proc/shoot_live_shot(mob/living/user as mob|obj)
- if(recoil)
- spawn()
- shake_camera(user, recoil + 1, recoil)
-
- if(silenced)
- playsound(user, fire_sound, 10, 1)
- else
- playsound(user, fire_sound, 50, 1)
- user.visible_message("[user] fires [src]!", "You fire [src]!", "You hear a [istype(src, /obj/item/weapon/gun/energy) ? "laser blast" : "gunshot"]!")
-
- emp_act(severity)
- for(var/obj/O in contents)
- O.emp_act(severity)
-
-
- afterattack(atom/target as mob|obj|turf, mob/living/user as mob|obj, flag, params)//TODO: go over this
- if(flag) //It's adjacent, is the user, or is on the user's person
- return
-
- //Exclude lasertag guns from the CLUMSY check.
- if(clumsy_check)
- if(istype(user, /mob/living))
- var/mob/living/M = user
- if ((CLUMSY in M.mutations) && prob(40))
- M << "You shoot yourself in the foot with \the [src]!"
- afterattack(user, user)
- M.drop_item()
- return
-
- if (!user.IsAdvancedToolUser())
- user << "You don't have the dexterity to do this!"
- return
-
- if(trigger_guard)
- if(istype(user, /mob/living))
- var/mob/living/M = user
- if (HULK in M.mutations)
- M << "Your meaty finger is much too large for the trigger guard!"
- return
- if(ishuman(user))
- var/mob/living/carbon/human/H = user
- if(H.dna && H.dna.mutantrace == "adamantine")
- user << "Your metal fingers don't fit in the trigger guard!"
- return
-
- add_fingerprint(user)
-
- if(!special_check(user))
- return
- if(chambered)
- if(!chambered.fire(target, user, params, , silenced))
- shoot_with_empty_chamber(user)
- else
- shoot_live_shot(user)
- else
- shoot_with_empty_chamber(user)
- process_chamber()
- update_icon()
-
- if(user.hand)
- user.update_inv_l_hand(0)
- else
- user.update_inv_r_hand(0)
-
+/obj/item/weapon/gun
+ name = "gun"
+ desc = "It's a gun. It's pretty terrible, though."
+ icon = 'icons/obj/gun.dmi'
+ icon_state = "detective"
+ item_state = "gun"
+ flags = CONDUCT
+ slot_flags = SLOT_BELT
+ m_amt = 2000
+ w_class = 3.0
+ throwforce = 5
+ throw_speed = 3
+ throw_range = 5
+ force = 5.0
+ origin_tech = "combat=1"
+ attack_verb = list("struck", "hit", "bashed")
+
+ var/fire_sound = "gunshot"
+ var/silenced = 0
+ var/recoil = 0
+ var/clumsy_check = 1
+ var/obj/item/ammo_casing/chambered = null
+ var/trigger_guard = 1
+
+ proc/process_chamber()
+ return 0
+
+ proc/special_check(var/mob/M) //Placeholder for any special checks, like detective's revolver.
+ return 1
+
+ proc/shoot_with_empty_chamber(mob/living/user as mob|obj)
+ user << "*click*"
+ return
+
+ proc/shoot_live_shot(mob/living/user as mob|obj)
+ if(recoil)
+ spawn()
+ shake_camera(user, recoil + 1, recoil)
+
+ if(silenced)
+ playsound(user, fire_sound, 10, 1)
+ else
+ playsound(user, fire_sound, 50, 1)
+ user.visible_message("[user] fires [src]!", "You fire [src]!", "You hear a [istype(src, /obj/item/weapon/gun/energy) ? "laser blast" : "gunshot"]!")
+
+ emp_act(severity)
+ for(var/obj/O in contents)
+ O.emp_act(severity)
+
+
+ afterattack(atom/target as mob|obj|turf, mob/living/user as mob|obj, flag, params)//TODO: go over this
+ if(flag) //It's adjacent, is the user, or is on the user's person
+ return
+
+ //Exclude lasertag guns from the CLUMSY check.
+ if(clumsy_check)
+ if(istype(user, /mob/living))
+ var/mob/living/M = user
+ if ((CLUMSY in M.mutations) && prob(40))
+ M << "You shoot yourself in the foot with \the [src]!"
+ afterattack(user, user)
+ M.drop_item()
+ return
+
+ if (!user.IsAdvancedToolUser())
+ user << "You don't have the dexterity to do this!"
+ return
+
+ if(trigger_guard)
+ if(istype(user, /mob/living))
+ var/mob/living/M = user
+ if (HULK in M.mutations)
+ M << "Your meaty finger is much too large for the trigger guard!"
+ return
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if(H.dna && H.dna.mutantrace == "adamantine")
+ user << "Your metal fingers don't fit in the trigger guard!"
+ return
+
+ add_fingerprint(user)
+
+ if(!special_check(user))
+ return
+ if(chambered)
+ if(!chambered.fire(target, user, params, , silenced))
+ shoot_with_empty_chamber(user)
+ else
+ shoot_live_shot(user)
+ else
+ shoot_with_empty_chamber(user)
+ process_chamber()
+ update_icon()
+
+ if(user.hand)
+ user.update_inv_l_hand(0)
+ else
+ user.update_inv_r_hand(0)
+
diff --git a/code/modules/projectiles/guns/magic.dm b/code/modules/projectiles/guns/magic.dm
index 770b1ae5af0..570ae8e60f2 100644
--- a/code/modules/projectiles/guns/magic.dm
+++ b/code/modules/projectiles/guns/magic.dm
@@ -1,54 +1,54 @@
-/obj/item/weapon/gun/magic
- name = "staff of nothing"
- desc = "This staff is boring to watch because even though it came first you've seen everything it can do in other staves for years."
- icon = 'icons/obj/gun.dmi'
- icon_state = "staffofnothing"
- item_state = "staff"
- fire_sound = 'sound/weapons/emitter.ogg'
- flags = CONDUCT
- w_class = 5
- var/max_charges = 6
- var/charges = 0
- var/recharge_rate = 4
- var/charge_tick = 0
- var/can_charge = 1
- var/ammo_type
- origin_tech = null
- clumsy_check = 0
- trigger_guard = 0
-
-/obj/item/weapon/gun/magic/afterattack(atom/target as mob, mob/living/user as mob, flag)
- newshot()
- ..()
-
-/obj/item/weapon/gun/magic/proc/newshot()
- if (charges && chambered)
- chambered.newshot()
- charges--
- return
-
-/obj/item/weapon/gun/magic/New()
- ..()
- charges = max_charges
- chambered = new ammo_type(src)
- if(can_charge) processing_objects.Add(src)
-
-
-/obj/item/weapon/gun/magic/Destroy()
- if(can_charge) processing_objects.Remove(src)
- ..()
-
-
-/obj/item/weapon/gun/magic/process()
- charge_tick++
- if(charge_tick < recharge_rate || charges >= max_charges) return 0
- charge_tick = 0
- charges++
- return 1
-
-/obj/item/weapon/gun/magic/update_icon()
- return
-
-/obj/item/weapon/gun/magic/shoot_with_empty_chamber(mob/living/user as mob|obj)
- user << "The [name] whizzles quietly."
+/obj/item/weapon/gun/magic
+ name = "staff of nothing"
+ desc = "This staff is boring to watch because even though it came first you've seen everything it can do in other staves for years."
+ icon = 'icons/obj/gun.dmi'
+ icon_state = "staffofnothing"
+ item_state = "staff"
+ fire_sound = 'sound/weapons/emitter.ogg'
+ flags = CONDUCT
+ w_class = 5
+ var/max_charges = 6
+ var/charges = 0
+ var/recharge_rate = 4
+ var/charge_tick = 0
+ var/can_charge = 1
+ var/ammo_type
+ origin_tech = null
+ clumsy_check = 0
+ trigger_guard = 0
+
+/obj/item/weapon/gun/magic/afterattack(atom/target as mob, mob/living/user as mob, flag)
+ newshot()
+ ..()
+
+/obj/item/weapon/gun/magic/proc/newshot()
+ if (charges && chambered)
+ chambered.newshot()
+ charges--
+ return
+
+/obj/item/weapon/gun/magic/New()
+ ..()
+ charges = max_charges
+ chambered = new ammo_type(src)
+ if(can_charge) processing_objects.Add(src)
+
+
+/obj/item/weapon/gun/magic/Destroy()
+ if(can_charge) processing_objects.Remove(src)
+ ..()
+
+
+/obj/item/weapon/gun/magic/process()
+ charge_tick++
+ if(charge_tick < recharge_rate || charges >= max_charges) return 0
+ charge_tick = 0
+ charges++
+ return 1
+
+/obj/item/weapon/gun/magic/update_icon()
+ return
+
+/obj/item/weapon/gun/magic/shoot_with_empty_chamber(mob/living/user as mob|obj)
+ user << "The [name] whizzles quietly."
return
\ No newline at end of file
diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm
index a07ea02d7c9..9c6f0209e69 100644
--- a/code/modules/projectiles/guns/magic/staff.dm
+++ b/code/modules/projectiles/guns/magic/staff.dm
@@ -21,3 +21,22 @@ obj/item/weapon/gun/magic/staff/healing
ammo_type = /obj/item/ammo_casing/magic/heal
icon_state = "staffofhealing"
item_state = "staffofhealing"
+
+obj/item/weapon/gun/magic/staff/chaos
+ name = "staff of chaos"
+ desc = "An artefact that spits bolts of chaotic magic that can potentially do anything."
+ ammo_type = /obj/item/ammo_casing/magic/chaos
+ icon_state = "staffofhealing"
+ item_state = "staffofhealing"
+ max_charges = 10
+ recharge_rate = 2
+
+obj/item/weapon/gun/magic/staff/door
+ name = "staff of door creation"
+ desc = "An artefact that spits bolts of transformative magic that can create doors in walls."
+ ammo_type = /obj/item/ammo_casing/magic/door
+ icon_state = "staffofhealing"
+ item_state = "staffofhealing"
+ max_charges = 10
+ recharge_rate = 2
+
diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm
index b25e68c4aa6..4efb2c10d62 100644
--- a/code/modules/projectiles/guns/magic/wand.dm
+++ b/code/modules/projectiles/guns/magic/wand.dm
@@ -1,124 +1,124 @@
-/obj/item/weapon/gun/magic/wand/
- name = "wand of nothing"
- desc = "It's not just a stick, it's a MAGIC stick!"
- ammo_type = /obj/item/ammo_casing/magic
- icon_state = "nothingwand"
- item_state = "wand"
- w_class = 2
- can_charge = 0
- max_charges = 100 //100, 50, 50, 34 (max charge distribution by 25%ths)
- var/variable_charges = 1
-
-/obj/item/weapon/gun/magic/wand/New()
- if(prob(75) && variable_charges) //25% chance of listed max charges, 50% chance of 1/2 max charges, 25% chance of 1/3 max charges
- if(prob(33))
- max_charges = Ceiling(max_charges / 3)
- else
- max_charges = Ceiling(max_charges / 2)
- ..()
-
-/obj/item/weapon/gun/magic/wand/examine()
- ..()
- usr << "Has [charges] charge\s remaining."
- return
-
-/obj/item/weapon/gun/magic/wand/update_icon()
- icon_state = "[initial(icon_state)][charges ? "" : "-drained"]"
-
-/obj/item/weapon/gun/magic/wand/attack(atom/target as mob, mob/living/user as mob)
- if(target == user)
- return
- ..()
-
-/obj/item/weapon/gun/magic/wand/afterattack(atom/target as mob, mob/living/user as mob)
- if(!charges)
- shoot_with_empty_chamber(user)
- return
- if(target == user)
- zap_self(user)
- else
- ..()
- update_icon()
-
-
-/obj/item/weapon/gun/magic/wand/proc/zap_self(mob/living/user as mob)
- user.visible_message("[user] zaps \himself with [src]!")
- playsound(user, fire_sound, 50, 1)
- user.attack_log += "\[[time_stamp()]\] [user]/[user.ckey] zapped \himself with a [src]"
-
-/obj/item/weapon/gun/magic/wand/death
- name = "wand of death"
- desc = "This deadly wand overwhelms the victim's body with pure energy, slaying them without fail."
- ammo_type = /obj/item/ammo_casing/magic/death
- icon_state = "deathwand"
- max_charges = 3 //3, 2, 2, 1
-
-/obj/item/weapon/gun/magic/wand/death/zap_self(mob/living/user as mob)
- var/message ="You irradiate yourself with pure energy! "
- message += pick("Do not pass go. Do not collect 200 zorkmids.","You feel more confident in your spell casting skills.","You Die...","Do you want your possessions identified?")
- user << message
- user.adjustOxyLoss(500)
- charges--
- ..()
-
-/obj/item/weapon/gun/magic/wand/resurrection
- name = "wand of healing"
- desc = "This wand uses healing magics to heal and revive. They are rarely utilized within the Wizard Federation for some reason."
- ammo_type = /obj/item/ammo_casing/magic/heal
- icon_state = "revivewand"
- max_charges = 10 //10, 5, 5, 4
-
-/obj/item/weapon/gun/magic/wand/resurrection/zap_self(mob/living/user as mob)
- user.revive()
- user << "You feel great!"
- charges--
- ..()
-
-/obj/item/weapon/gun/magic/wand/polymorph
- name = "wand of polymorph"
- desc = "This wand is attuned to chaos and will radically alter the victim's form."
- ammo_type = /obj/item/ammo_casing/magic/change
- icon_state = "polywand"
- max_charges = 10 //10, 5, 5, 4
-
-/obj/item/weapon/gun/magic/wand/polymorph/zap_self(mob/living/user as mob)
- ..() //because the user mob ceases to exists by the time wabbajack fully resolves
- wabbajack(user)
- charges--
-
-/obj/item/weapon/gun/magic/wand/teleport
- name = "wand of teleportation"
- desc = "This wand will wrench targets through space and time to move them somewhere else."
- ammo_type = /obj/item/ammo_casing/magic/teleport
- icon_state = "telewand"
- max_charges = 10 //10, 5, 5, 4
-
-/obj/item/weapon/gun/magic/wand/teleport/zap_self(mob/living/user as mob)
- do_teleport(user, user, 10)
- var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread()
- smoke.set_up(10, 0, user.loc)
- smoke.start()
- charges--
- ..()
-
-/obj/item/weapon/gun/magic/wand/door
- name = "wand of door creation"
- desc = "This particular wand can create doors in any wall for the unscrupulous wizard who shuns teleportation magics."
- ammo_type = /obj/item/ammo_casing/magic/door
- icon_state = "doorwand"
- max_charges = 20 //20, 10, 10, 7
-
-/obj/item/weapon/gun/magic/wand/door/zap_self()
- return
-
-/obj/item/weapon/gun/magic/wand/fireball
- name = "wand of fireball"
- desc = "This wand shoots scorching balls of fire that explode into destructive flames."
- ammo_type = /obj/item/ammo_casing/magic/fireball
- icon_state = "firewand"
- max_charges = 8 //8, 4, 4, 3
-
-/obj/item/weapon/gun/magic/wand/fireball/zap_self(mob/living/user as mob)
- explosion(user.loc, -1, 0, 2, 3, 0, flame_range = 2)
- charges--
+/obj/item/weapon/gun/magic/wand/
+ name = "wand of nothing"
+ desc = "It's not just a stick, it's a MAGIC stick!"
+ ammo_type = /obj/item/ammo_casing/magic
+ icon_state = "nothingwand"
+ item_state = "wand"
+ w_class = 2
+ can_charge = 0
+ max_charges = 100 //100, 50, 50, 34 (max charge distribution by 25%ths)
+ var/variable_charges = 1
+
+/obj/item/weapon/gun/magic/wand/New()
+ if(prob(75) && variable_charges) //25% chance of listed max charges, 50% chance of 1/2 max charges, 25% chance of 1/3 max charges
+ if(prob(33))
+ max_charges = Ceiling(max_charges / 3)
+ else
+ max_charges = Ceiling(max_charges / 2)
+ ..()
+
+/obj/item/weapon/gun/magic/wand/examine()
+ ..()
+ usr << "Has [charges] charge\s remaining."
+ return
+
+/obj/item/weapon/gun/magic/wand/update_icon()
+ icon_state = "[initial(icon_state)][charges ? "" : "-drained"]"
+
+/obj/item/weapon/gun/magic/wand/attack(atom/target as mob, mob/living/user as mob)
+ if(target == user)
+ return
+ ..()
+
+/obj/item/weapon/gun/magic/wand/afterattack(atom/target as mob, mob/living/user as mob)
+ if(!charges)
+ shoot_with_empty_chamber(user)
+ return
+ if(target == user)
+ zap_self(user)
+ else
+ ..()
+ update_icon()
+
+
+/obj/item/weapon/gun/magic/wand/proc/zap_self(mob/living/user as mob)
+ user.visible_message("[user] zaps \himself with [src]!")
+ playsound(user, fire_sound, 50, 1)
+ user.attack_log += "\[[time_stamp()]\] [user]/[user.ckey] zapped \himself with a [src]"
+
+/obj/item/weapon/gun/magic/wand/death
+ name = "wand of death"
+ desc = "This deadly wand overwhelms the victim's body with pure energy, slaying them without fail."
+ ammo_type = /obj/item/ammo_casing/magic/death
+ icon_state = "deathwand"
+ max_charges = 3 //3, 2, 2, 1
+
+/obj/item/weapon/gun/magic/wand/death/zap_self(mob/living/user as mob)
+ var/message ="You irradiate yourself with pure energy! "
+ message += pick("Do not pass go. Do not collect 200 zorkmids.","You feel more confident in your spell casting skills.","You Die...