diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index a09e285f3d2..077215afa1c 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -147,6 +147,11 @@
var/assistantlimit = 0 //enables assistant limiting
var/assistantratio = 2 //how many assistants to security members
+ var/emag_energy = -1
+ var/emag_starts_charged = 1
+ var/emag_recharge_rate = 0
+ var/emag_recharge_ticks = 0
+
/datum/configuration/New()
. = ..()
var/list/L = typesof(/datum/game_mode) - /datum/game_mode
@@ -544,6 +549,14 @@
config.limbs_can_break = value
if("respawn_delay")
config.respawn_delay = value
+ if("emag_energy")
+ config.emag_energy = value
+ if("emag_starts_charged")
+ config.emag_starts_charged = value
+ if("emag_recharge_rate")
+ config.emag_recharge_rate = value
+ if("emag_recharge_ticks")
+ config.emag_recharge_ticks = value
else
diary << "Unknown setting in configuration: '[name]'"
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 6b2606cffcb..3a61c67f387 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -49,6 +49,8 @@
autoclose = 1
var/busy = 0
+ emag_cost = 1 // in MJ
+
/obj/machinery/door/airlock/Destroy()
if(wires)
wires.Destroy()
@@ -105,6 +107,7 @@
name = "Vault"
icon = 'icons/obj/doors/vault.dmi'
opacity = 1
+ emag_cost = 2 // in MJ
assembly_type = /obj/structure/door_assembly/door_assembly_highsecurity //Until somebody makes better sprites.
/obj/machinery/door/airlock/freezer
@@ -284,6 +287,7 @@
name = "High Tech Security Airlock"
icon = 'icons/obj/doors/hightechsecurity.dmi'
assembly_type = /obj/structure/door_assembly/door_assembly_highsecurity
+ emag_cost = 2 // in MJ
/*
About the new airlock wires panel:
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index 2f7c2e1ab40..ff36b3f0e85 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -116,7 +116,15 @@ Class Procs:
var/custom_aghost_alerts=0
var/panel_open = 0
- var/machine_flags = 0//this is what you use for flags.
+ /**
+ * Machine construction/destruction/emag flags.
+ */
+ var/machine_flags = 0 // This is what you use for flags.
+
+ /**
+ * Emag energy cost.
+ */
+ var/emag_cost = 0 // Emag energy cost.
var/inMachineList = 1 // For debugging.
@@ -447,29 +455,49 @@ Class Procs:
return 1
return -1
+/**
+ * Handle emags.
+ * @param user /mob The mob that used the emag.
+ */
/obj/machinery/proc/emag(mob/user as mob)
- return
+ // Disable emaggability.
+ machine_flags &= ~EMAGGABLE
+
+/**
+ * Returns the cost of emagging this machine (emag_cost by default)
+ * @param user /mob The mob that used the emag.
+ * @param emag /obj/item/weapon/card/emag The emag used on this device.
+ * @return number Cost to emag.
+ */
+/obj/machinery/proc/getEmagCost(var/mob/user, var/obj/item/weapon/card/emag/emag)
+ return emag_cost
/obj/machinery/attackby(var/obj/O, var/mob/user)
- if(istype(O, /obj/item/weapon/card/emag) && machine_flags &EMAGGABLE)
- emag(user)
- return
- if(istype(O, /obj/item/weapon/wrench) && machine_flags &WRENCHMOVE) //make sure this is BEFORE the fixed2work check
+ if(istype(O, /obj/item/weapon/card/emag) && machine_flags & EMAGGABLE)
+ var/obj/item/weapon/card/emag/E = O
+ if(E.canUse(user,src))
+ emag(user)
+ return
+
+ if(istype(O, /obj/item/weapon/wrench) && machine_flags & WRENCHMOVE) //make sure this is BEFORE the fixed2work check
if(!panel_open)
return wrenchAnchor(user)
else
user <<"\The [src]'s maintenance panel must be closed first!"
return -1 //we return -1 rather than 0 for the if(..()) checks
- if(istype(O, /obj/item/weapon/screwdriver) && machine_flags &SCREWTOGGLE)
+
+ if(istype(O, /obj/item/weapon/screwdriver) && machine_flags & SCREWTOGGLE)
return togglePanelOpen(O, user)
- if(istype(O, /obj/item/weapon/crowbar) && machine_flags &CROWDESTROY)
+
+ if(istype(O, /obj/item/weapon/crowbar) && machine_flags & CROWDESTROY)
if(panel_open)
if(crowbarDestroy(user) == 1)
qdel(src)
return 1
else
return -1
- if(!anchored && machine_flags &FIXED2WORK)
+
+ if(!anchored && machine_flags & FIXED2WORK)
return user << "\The [src] must be anchored first!"
/obj/machinery/proc/shock(mob/user, prb, var/siemenspassed = -1)
@@ -485,4 +513,4 @@ Class Procs:
if (electrocute_mob(user, get_area(src), src, siemenspassed))
return 1
else
- return -1
+ return -1
diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm
index 7152347ee52..c21dd101d4c 100644
--- a/code/game/objects/items/weapons/cards_ids.dm
+++ b/code/game/objects/items/weapons/cards_ids.dm
@@ -60,7 +60,99 @@
icon_state = "emag"
item_state = "card-id"
origin_tech = "magnets=2;syndicate=2"
- var/uses = 10
+
+ /**
+ * Number of uses left. -1 = infinite
+ * (Note: Some devices can use more than 1 use, so this is just called "energy")
+ * @since 10-28-2014
+ */
+ var/energy = -1
+
+ /**
+ * Max energy per emag. -1 = infinite
+ * @since 10-28-2014
+ */
+ var/max_energy = -1
+
+ /**
+ * Every X ticks, add [recharge_rate] energy.
+ * @since 10-28-2014
+ */
+ var/recharge_ticks = 0
+
+ /**
+ * Every [recharge_ticks] ticks, add X energy.
+ * @since 10-28-2014
+ */
+ var/recharge_rate = 0
+
+ var/nticks=0
+
+/obj/item/weapon/card/emag/New(var/loc, var/disable_tuning=0)
+ ..(loc)
+
+ // For standardized subtypes, once they're established.
+ if(disable_tuning)
+ return
+
+ // Tuning tools.
+ //////////////////
+ if(config.emag_energy != -1)
+ max_energy = config.emag_energy
+
+ if(config.emag_starts_charged)
+ energy = max_energy
+
+ if(config.emag_recharge_rate != 0)
+ recharge_rate = config.emag_recharge_rate
+
+ if(config.emag_recharge_ticks > 0)
+ recharge_ticks = config.emag_recharge_ticks
+
+/obj/item/weapon/card/emag/process()
+ if(energy < max_energy)
+ // Specified number of ticks has passed? Add charge.
+ if(nticks >= recharge_ticks)
+ nticks = 0
+ energy = min(energy + recharge_rate, max_energy)
+ nticks ++
+ else
+ nticks = 0
+ processing_objects.Remove(src)
+
+/obj/item/weapon/card/emag/proc/canUse(var/mob/user, var/obj/machinery/M)
+ // We've already checked for emaggability. All we do here is check cost.
+
+ // Infinite uses? Just return true.
+ if(energy < 0)
+ return 1
+
+ var/cost=M.getEmagCost(user,src)
+
+ // Free to emag? Return true every time.
+ if(cost == 0)
+ return 1
+
+ if(energy >= cost)
+ energy -= cost
+
+ // Start recharging, if we're supposed to.
+ if(energy < max_energy && recharge_rate && recharge_ticks)
+ if(!(src in processing_objects))
+ processing_objects.Add(src)
+
+ return 1
+
+ return 0
+
+/obj/item/weapon/card/emag/examine()
+ ..()
+ if(energy==-1)
+ usr << "\The [name] has a tiny fusion generator for power."
+ else
+ usr << "This [name] has [energy]MJ left in its capacitor ([max_energy]MJ capacity)."
+ if(recharge_rate && recharge_ticks)
+ usr << "A small label on a thermocouple notes that it recharges at a rate of [recharge_rate]MJ for every [recharge_ticks>1?"":recharge_ticks] oscillator tick[recharge_ticks>1?"s":""]."
/obj/item/weapon/card/id
name = "identification card"
diff --git a/config-example/game_options.txt b/config-example/game_options.txt
index 949dc9622e5..419d71714bd 100644
--- a/config-example/game_options.txt
+++ b/config-example/game_options.txt
@@ -58,4 +58,24 @@ ANIMAL_DELAY 0
# Define how large an explosion can be.
## DEFAULT: 14
-MAX_EXPLOSION_RANGE 14
\ No newline at end of file
+MAX_EXPLOSION_RANGE 14
+
+#################
+### EMAG SHIT ###
+#################
+
+# Max energy an emag can hold.
+## DEFAULT: -1 (infinite)
+EMAG_ENERGY -1
+
+# Whether an emag starts charged (1), or uncharged (0).
+## DEFAULT: 1 (charged)
+EMAG_STARTS_CHARGED 1
+
+# Amount of energy to add per recharge cycle.
+## DEFAULT: 0
+EMAG_RECHARGE_RATE 0
+
+# Number of ticks per recharge cycle
+## DEFAULT: 0 (no recharging)
+EMAG_RECHARGE_TICKS 0
\ No newline at end of file