diff --git a/.travis.yml b/.travis.yml
index 432d4093149..2ccfc698015 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,9 +3,9 @@ language: c
sudo: false
env:
- BYOND_MAJOR="510"
- BYOND_MINOR="1346"
- MACRO_COUNT=986
+ BYOND_MAJOR="511"
+ BYOND_MINOR="1381"
+ MACRO_COUNT=875
cache:
directories:
diff --git a/code/ZAS/Atom.dm b/code/ZAS/Atom.dm
index ce69ad71622..49613559409 100644
--- a/code/ZAS/Atom.dm
+++ b/code/ZAS/Atom.dm
@@ -57,11 +57,11 @@ turf/c_airblock(turf/other)
#ifdef ZASDBG
ASSERT(isturf(other))
#endif
- if(blocks_air || other.blocks_air)
+ if(((blocks_air & AIR_BLOCKED) || (other.blocks_air & AIR_BLOCKED)))
return BLOCKED
//Z-level handling code. Always block if there isn't an open space.
- #ifdef ZLEVELS
+ #ifdef MULTIZAS
if(other.z != src.z)
if(other.z < src.z)
if(!istype(src, /turf/simulated/open)) return BLOCKED
@@ -69,6 +69,12 @@ turf/c_airblock(turf/other)
if(!istype(other, /turf/simulated/open)) return BLOCKED
#endif
+ if(((blocks_air & ZONE_BLOCKED) || (other.blocks_air & ZONE_BLOCKED)))
+ if(z == other.z)
+ return ZONE_BLOCKED
+ else
+ return AIR_BLOCKED
+
var/result = 0
for(var/atom/movable/M in contents)
result |= M.c_airblock(other)
diff --git a/code/ZAS/ConnectionManager.dm b/code/ZAS/ConnectionManager.dm
index 1c101f4b45a..28ef3658304 100644
--- a/code/ZAS/ConnectionManager.dm
+++ b/code/ZAS/ConnectionManager.dm
@@ -37,7 +37,7 @@ Class Procs:
/connection_manager/var/connection/E
/connection_manager/var/connection/W
-#ifdef ZLEVELS
+#ifdef MULTIZAS
/connection_manager/var/connection/U
/connection_manager/var/connection/D
#endif
@@ -57,7 +57,7 @@ Class Procs:
if(check(W)) return W
else return null
- #ifdef ZLEVELS
+ #ifdef MULTIZAS
if(UP)
if(check(U)) return U
else return null
@@ -73,7 +73,7 @@ Class Procs:
if(EAST) E = c
if(WEST) W = c
- #ifdef ZLEVELS
+ #ifdef MULTIZAS
if(UP) U = c
if(DOWN) D = c
#endif
@@ -83,7 +83,7 @@ Class Procs:
if(check(S)) S.update()
if(check(E)) E.update()
if(check(W)) W.update()
- #ifdef ZLEVELS
+ #ifdef MULTIZAS
if(check(U)) U.update()
if(check(D)) D.update()
#endif
@@ -93,7 +93,7 @@ Class Procs:
if(check(S)) S.erase()
if(check(E)) E.erase()
if(check(W)) W.erase()
- #ifdef ZLEVELS
+ #ifdef MULTIZAS
if(check(U)) U.erase()
if(check(D)) D.erase()
#endif
diff --git a/code/ZAS/Controller.dm b/code/ZAS/Controller.dm
index cfd6cff4148..2469f7a36ff 100644
--- a/code/ZAS/Controller.dm
+++ b/code/ZAS/Controller.dm
@@ -158,6 +158,9 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun
//defer updating of self-zone-blocked turfs until after all other turfs have been updated.
//this hopefully ensures that non-self-zone-blocked turfs adjacent to self-zone-blocked ones
//have valid zones when the self-zone-blocked turfs update.
+
+ //This ensures that doorways don't form their own single-turf zones, since doorways are self-zone-blocked and
+ //can merge with an adjacent zone, whereas zones that are formed on adjacent turfs cannot merge with the doorway.
var/list/deferred = list()
for(var/turf/T in updating)
diff --git a/code/ZAS/Diagnostic.dm b/code/ZAS/Diagnostic.dm
index ed94b7d5825..10ec2e731b5 100644
--- a/code/ZAS/Diagnostic.dm
+++ b/code/ZAS/Diagnostic.dm
@@ -39,6 +39,10 @@ client/proc/Test_ZAS_Connection(var/turf/simulated/T as turf)
"South" = SOUTH,\
"East" = EAST,\
"West" = WEST,\
+ #ifdef MULTIZAS
+ "Up" = UP,\
+ "Down" = DOWN,\
+ #endif
"N/A" = null)
var/direction = input("What direction do you wish to test?","Set direction") as null|anything in direction_list
if(!direction)
diff --git a/code/ZAS/Turf.dm b/code/ZAS/Turf.dm
index 62cad5e469c..bb5eb5050eb 100644
--- a/code/ZAS/Turf.dm
+++ b/code/ZAS/Turf.dm
@@ -16,7 +16,7 @@
//dbg(blocked)
return 1
- #ifdef ZLEVELS
+ #ifdef MULTIZAS
for(var/d = 1, d < 64, d *= 2)
#else
for(var/d = 1, d < 16, d *= 2)
@@ -52,34 +52,40 @@
*/
/turf/simulated/proc/can_safely_remove_from_zone()
- #ifdef ZLEVELS
- return 0 //TODO generalize this to multiz.
- #else
-
+
+
if(!zone) return 1
-
+
var/check_dirs = get_zone_neighbours(src)
var/unconnected_dirs = check_dirs
-
- for(var/dir in list(NORTHWEST, NORTHEAST, SOUTHEAST, SOUTHWEST))
-
+
+ #ifdef MULTIZAS
+ var/to_check = cornerdirsz
+ #else
+ var/to_check = cornerdirs
+ #endif
+
+ for(var/dir in to_check)
//for each pair of "adjacent" cardinals (e.g. NORTH and WEST, but not NORTH and SOUTH)
if((dir & check_dirs) == dir)
//check that they are connected by the corner turf
var/connected_dirs = get_zone_neighbours(get_step(src, dir))
- if(connected_dirs && (dir & turn(connected_dirs, 180)) == dir)
+ if(connected_dirs && (dir & reverse_dir[connected_dirs]) == dir)
unconnected_dirs &= ~dir //they are, so unflag the cardinals in question
-
+
//it is safe to remove src from the zone if all cardinals are connected by corner turfs
return !unconnected_dirs
-
- #endif
//helper for can_safely_remove_from_zone()
/turf/simulated/proc/get_zone_neighbours(turf/simulated/T)
. = 0
if(istype(T) && T.zone)
- for(var/dir in cardinal)
+ #ifdef MULTIZAS
+ var/to_check = cardinalz
+ #else
+ var/to_check = cardinal
+ #endif
+ for(var/dir in to_check)
var/turf/simulated/other = get_step(T, dir)
if(istype(other) && other.zone == T.zone && !(other.c_airblock(T) & AIR_BLOCKED) && get_dist(src, other) <= 1)
. |= dir
@@ -98,7 +104,7 @@
#endif
if(zone)
var/zone/z = zone
-
+
if(can_safely_remove_from_zone()) //Helps normal airlocks avoid rebuilding zones all the time
z.remove(src)
else
@@ -110,7 +116,7 @@
open_directions = 0
var/list/postponed
- #ifdef ZLEVELS
+ #ifdef MULTIZAS
for(var/d = 1, d < 64, d *= 2)
#else
for(var/d = 1, d < 16, d *= 2)
@@ -161,7 +167,7 @@
//Might have assigned a zone, since this happens for each direction.
if(!zone)
- //We do not merge if
+ //We do not merge if
// they are blocking us and we are not blocking them, or if
// we are blocking them and not blocking ourselves - this prevents tiny zones from forming on doorways.
if(((block & ZONE_BLOCKED) && !(r_block & ZONE_BLOCKED)) || ((r_block & ZONE_BLOCKED) && !(s_block & ZONE_BLOCKED)))
diff --git a/code/ZAS/_docs.dm b/code/ZAS/_docs.dm
index 1f652ffaaba..4433478e321 100644
--- a/code/ZAS/_docs.dm
+++ b/code/ZAS/_docs.dm
@@ -28,8 +28,7 @@ Notes for people who used ZAS before:
*/
//#define ZASDBG
-//#define ZLEVELS
-
+//#define MULTIZAS
#define AIR_BLOCKED 1
#define ZONE_BLOCKED 2
#define BLOCKED 3
diff --git a/code/__defines/gamemode.dm b/code/__defines/gamemode.dm
index 8115790c506..cd0c9955c13 100644
--- a/code/__defines/gamemode.dm
+++ b/code/__defines/gamemode.dm
@@ -123,4 +123,6 @@ var/list/be_special_flags = list(
//casting costs
#define Sp_RECHARGE "recharge"
#define Sp_CHARGES "charges"
-#define Sp_HOLDVAR "holdervar"
\ No newline at end of file
+#define Sp_HOLDVAR "holdervar"
+
+#define CHANGELING_STASIS_COST 20
\ No newline at end of file
diff --git a/code/__defines/items_clothing.dm b/code/__defines/items_clothing.dm
index eb572aa0e29..0a8598d21f1 100644
--- a/code/__defines/items_clothing.dm
+++ b/code/__defines/items_clothing.dm
@@ -33,7 +33,7 @@
#define PROXMOVE 0x80 // Does this object require proximity checking in Enter()?
//Flags for items (equipment)
-#define THICKMATERIAL 0x1 // Prevents syringes, parapens and hyposprays if equiped to slot_suit or slot_head.
+#define THICKMATERIAL 0x1 // Prevents syringes, parapens and hyposprays if equipped to slot_suit or slot_head.
#define STOPPRESSUREDAMAGE 0x2 // Counts towards pressure protection. Note that like temperature protection, body_parts_covered is considered here as well.
#define AIRTIGHT 0x4 // Functions with internals.
#define NOSLIP 0x8 // Prevents from slipping on wet floors, in space, etc.
diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index 09f5e81ca00..f85ac5e7d4a 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -69,6 +69,11 @@
#define COLOR_PALE_RED_GRAY "#CC9090"
#define COLOR_PALE_PURPLE_GRAY "#BDA2BA"
#define COLOR_PURPLE_GRAY "#A2819E"
+#define COLOR_RED_LIGHT "#FF3333"
+#define COLOR_DEEP_SKY_BLUE "#00e1ff"
+
+
+
// Shuttles.
diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm
index 7180fe4c376..ef00eed3341 100644
--- a/code/__defines/mobs.dm
+++ b/code/__defines/mobs.dm
@@ -206,4 +206,10 @@
#define TASTE_SENSITIVE 2 //anything below 7%
#define TASTE_NORMAL 1 //anything below 15%
#define TASTE_DULL 0.5 //anything below 30%
-#define TASTE_NUMB 0.1 //anything below 150%
\ No newline at end of file
+#define TASTE_NUMB 0.1 //anything below 150%
+
+// If they're in an FBP, what braintype.
+#define FBP_NONE ""
+#define FBP_CYBORG "Cyborg"
+#define FBP_POSI "Positronic"
+#define FBP_DRONE "Drone"
\ No newline at end of file
diff --git a/code/_helpers/datum_pool.dm b/code/_helpers/datum_pool.dm
deleted file mode 100644
index b5bcea123fe..00000000000
--- a/code/_helpers/datum_pool.dm
+++ /dev/null
@@ -1,110 +0,0 @@
-
-/*
-/tg/station13 /atom/movable Pool:
----------------------------------
-By RemieRichards
-
-Creation/Deletion is laggy, so let's reduce reuse and recycle!
-
-*/
-#define ATOM_POOL_COUNT 100
-// "define DEBUG_ATOM_POOL 1
-var/global/list/GlobalPool = list()
-
-//You'll be using this proc 90% of the time.
-//It grabs a type from the pool if it can
-//And if it can't, it creates one
-//The pool is flexible and will expand to fit
-//The new created atom when it eventually
-//Goes into the pool
-
-//Second argument can be a new location, if the type is /atom/movable
-//Or a list of arguments
-//Either way it gets passed to new
-
-/proc/PoolOrNew(var/get_type,var/second_arg)
- var/datum/D
- D = GetFromPool(get_type,second_arg)
-
- if(!D)
- // So the GC knows we're pooling this type.
- if(!GlobalPool[get_type])
- GlobalPool[get_type] = list()
- if(islist(second_arg))
- return new get_type (arglist(second_arg))
- else
- return new get_type (second_arg)
- return D
-
-/proc/GetFromPool(var/get_type,var/second_arg)
- if(isnull(GlobalPool[get_type]))
- return 0
-
- if(length(GlobalPool[get_type]) == 0)
- return 0
-
- var/datum/D = pick_n_take(GlobalPool[get_type])
- if(D)
- D.ResetVars()
- D.Prepare(second_arg)
- return D
- return 0
-
-/proc/PlaceInPool(var/datum/D)
- if(!istype(D))
- return
-
- if(length(GlobalPool[D.type]) > ATOM_POOL_COUNT)
- #ifdef DEBUG_ATOM_POOL
- world << text("DEBUG_DATUM_POOL: PlaceInPool([]) exceeds []. Discarding.", D.type, ATOM_POOL_COUNT)
- #endif
- if(garbage_collector)
- garbage_collector.AddTrash(D)
- else
- del(D)
- return
-
- if(D in GlobalPool[D.type])
- return
-
- if(!GlobalPool[D.type])
- GlobalPool[D.type] = list()
-
- GlobalPool[D.type] += D
-
- D.Destroy()
- D.ResetVars()
-
-/proc/IsPooled(var/datum/D)
- if(isnull(GlobalPool[D.type]))
- return 0
- return 1
-
-/datum/proc/Prepare(args)
- if(islist(args))
- New(arglist(args))
- else
- New(args)
-
-/atom/movable/Prepare(args)
- var/list/args_list = args
- if(istype(args_list) && args_list.len)
- loc = args[1]
- else
- loc = args
- ..()
-
-/datum/proc/ResetVars(var/list/exlude = list())
- var/list/excluded = list("animate_movement", "loc", "locs", "parent_type", "vars", "verbs", "type") + exlude
-
- for(var/V in vars)
- if(V in excluded)
- continue
-
- vars[V] = initial(vars[V])
-
-/atom/movable/ResetVars()
- ..()
- vars["loc"] = null
-
-#undef ATOM_POOL_COUNT
diff --git a/code/_helpers/game.dm b/code/_helpers/game.dm
index 1531a67d5b4..b59857c8f6b 100644
--- a/code/_helpers/game.dm
+++ b/code/_helpers/game.dm
@@ -284,7 +284,7 @@
if(M.loc && M.locs[1] in hearturfs)
mobs |= M
- else if(M.stat == DEAD)
+ else if(M.stat == DEAD && !M.forbid_seeing_deadchat)
switch(type)
if(1) //Audio messages use ghost_ears
if(M.is_preference_enabled(/datum/client_preference/ghost_ears))
diff --git a/code/_onclick/hud/ability_screen_objects.dm b/code/_onclick/hud/ability_screen_objects.dm
index 1e6844b6ad1..2081e011b35 100644
--- a/code/_onclick/hud/ability_screen_objects.dm
+++ b/code/_onclick/hud/ability_screen_objects.dm
@@ -32,11 +32,6 @@
my_mob.client.screen -= src
my_mob = null
-/obj/screen/movable/ability_master/ResetVars()
- ..("ability_objects", args)
- remove_all_abilities()
-// ability_objects = list()
-
/obj/screen/movable/ability_master/MouseDrop()
if(showing)
return
diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm
index fd226eb70c9..a00fa6e10dc 100644
--- a/code/_onclick/hud/fullscreen.dm
+++ b/code/_onclick/hud/fullscreen.dm
@@ -20,7 +20,7 @@
return null
if(!screen)
- screen = PoolOrNew(type)
+ screen = new type()
screen.icon_state = "[initial(screen.icon_state)][severity]"
screen.severity = severity
diff --git a/code/_onclick/hud/movable_screen_objects.dm b/code/_onclick/hud/movable_screen_objects.dm
index 71eff4a3920..3602a524811 100644
--- a/code/_onclick/hud/movable_screen_objects.dm
+++ b/code/_onclick/hud/movable_screen_objects.dm
@@ -45,49 +45,61 @@
screen_loc = "[screen_loc_X[1]]:[pix_X],[screen_loc_Y[1]]:[pix_Y]"
/obj/screen/movable/proc/encode_screen_X(X)
- if(X > usr.client.view+1)
- . = "EAST-[usr.client.view*2 + 1-X]"
- else if(X < usr.client.view+1)
+ var/view_dist = world.view
+ if(view_dist)
+ view_dist = view_dist
+ if(X > view_dist+1)
+ . = "EAST-[view_dist *2 + 1-X]"
+ else if(X < view_dist +1)
. = "WEST+[X-1]"
else
. = "CENTER"
/obj/screen/movable/proc/decode_screen_X(X)
+ var/view_dist = world.view
+ if(view_dist)
+ view_dist = view_dist
//Find EAST/WEST implementations
if(findtext(X,"EAST-"))
var/num = text2num(copytext(X,6)) //Trim EAST-
if(!num)
num = 0
- . = usr.client.view*2 + 1 - num
+ . = view_dist*2 + 1 - num
else if(findtext(X,"WEST+"))
var/num = text2num(copytext(X,6)) //Trim WEST+
if(!num)
num = 0
. = num+1
else if(findtext(X,"CENTER"))
- . = usr.client.view+1
+ . = view_dist+1
/obj/screen/movable/proc/encode_screen_Y(Y)
- if(Y > usr.client.view+1)
- . = "NORTH-[usr.client.view*2 + 1-Y]"
- else if(Y < usr.client.view+1)
+ var/view_dist = world.view
+ if(view_dist)
+ view_dist = view_dist
+ if(Y > view_dist+1)
+ . = "NORTH-[view_dist*2 + 1-Y]"
+ else if(Y < view_dist+1)
. = "SOUTH+[Y-1]"
else
. = "CENTER"
/obj/screen/movable/proc/decode_screen_Y(Y)
+ var/view_dist = world.view
+ if(view_dist)
+ view_dist = view_dist
if(findtext(Y,"NORTH-"))
var/num = text2num(copytext(Y,7)) //Trim NORTH-
if(!num)
num = 0
- . = usr.client.view*2 + 1 - num
+ . = view_dist*2 + 1 - num
else if(findtext(Y,"SOUTH+"))
var/num = text2num(copytext(Y,7)) //Time SOUTH+
if(!num)
num = 0
. = num+1
else if(findtext(Y,"CENTER"))
- . = usr.client.view+1
+ . = view_dist+1
//Debug procs
/client/proc/test_movable_UI()
diff --git a/code/_onclick/hud/spell_screen_objects.dm b/code/_onclick/hud/spell_screen_objects.dm
index 262ece09e48..a599381730a 100644
--- a/code/_onclick/hud/spell_screen_objects.dm
+++ b/code/_onclick/hud/spell_screen_objects.dm
@@ -23,10 +23,6 @@
spell_holder.client.screen -= src
spell_holder = null
-/obj/screen/movable/spell_master/ResetVars()
- ..("spell_objects", args)
- spell_objects = list()
-
/obj/screen/movable/spell_master/MouseDrop()
if(showing)
return
@@ -93,7 +89,7 @@
if(spell.spell_flags & NO_BUTTON) //no button to add if we don't get one
return
- var/obj/screen/spell/newscreen = PoolOrNew(/obj/screen/spell)
+ var/obj/screen/spell/newscreen = new /obj/screen/spell()
newscreen.spellmaster = src
newscreen.spell = spell
diff --git a/code/_onclick/telekinesis.dm b/code/_onclick/telekinesis.dm
index 4c976f44585..f08727abf35 100644
--- a/code/_onclick/telekinesis.dm
+++ b/code/_onclick/telekinesis.dm
@@ -149,7 +149,7 @@ var/const/tk_maxrange = 15
/obj/item/tk_grab/proc/apply_focus_overlay()
if(!focus) return
- var/obj/effect/overlay/O = PoolOrNew(/obj/effect/overlay, locate(focus.x,focus.y,focus.z))
+ var/obj/effect/overlay/O = new /obj/effect/overlay(locate(focus.x,focus.y,focus.z))
O.name = "sparkles"
O.anchored = 1
O.density = 0
diff --git a/code/controllers/Processes/garbage.dm b/code/controllers/Processes/garbage.dm
index 2d56dde1a26..02f04113320 100644
--- a/code/controllers/Processes/garbage.dm
+++ b/code/controllers/Processes/garbage.dm
@@ -152,19 +152,13 @@ world/loop_checks = 0
A.finalize_qdel()
/datum/proc/finalize_qdel()
- if(IsPooled(src))
- PlaceInPool(src)
- else
- del(src)
+ del(src)
/atom/finalize_qdel()
- if(IsPooled(src))
- PlaceInPool(src)
+ if(garbage_collector)
+ garbage_collector.AddTrash(src)
else
- if(garbage_collector)
- garbage_collector.AddTrash(src)
- else
- delayed_garbage |= src
+ delayed_garbage |= src
/icon/finalize_qdel()
del(src)
@@ -180,7 +174,7 @@ world/loop_checks = 0
// Default implementation of clean-up code.
// This should be overridden to remove all references pointing to the object being destroyed.
-// Return true if the the GC controller should allow the object to continue existing. (Useful if pooling objects.)
+// Return true if the the GC controller should allow the object to continue existing.
/datum/proc/Destroy()
nanomanager.close_uis(src)
tag = null
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 57f22472551..5021453462e 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -166,6 +166,7 @@ var/list/gamemode_cache = list()
var/simultaneous_pm_warning_timeout = 100
var/use_recursive_explosions //Defines whether the server uses recursive or circular explosions.
+ var/multi_z_explosion_scalar = 0.5 //Multiplier for how much weaker explosions are on neighboring z levels.
var/assistant_maint = 0 //Do assistants get maint access?
var/gateway_delay = 18000 //How long the gateway takes before it activates. Default is half an hour.
@@ -283,6 +284,9 @@ var/list/gamemode_cache = list()
if ("use_recursive_explosions")
use_recursive_explosions = 1
+ if ("multi_z_explosion_scalar")
+ multi_z_explosion_scalar = text2num(value)
+
if ("log_ooc")
config.log_ooc = 1
diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm
index d40fd4fa5a3..274c0c0903d 100644
--- a/code/datums/datacore.dm
+++ b/code/datums/datacore.dm
@@ -184,6 +184,10 @@
G.fields["real_rank"] = H.mind.assigned_role
G.fields["rank"] = assignment
G.fields["age"] = H.age
+ if(H.get_FBP_type())
+ G.fields["brain_type"] = H.get_FBP_type()
+ else
+ G.fields["brain_type"] = "Organic"
G.fields["fingerprint"] = md5(H.dna.uni_identity)
G.fields["p_stat"] = "Active"
G.fields["m_stat"] = "Stable"
@@ -201,11 +205,19 @@
M.fields["b_type"] = H.b_type
M.fields["b_dna"] = H.dna.unique_enzymes
M.fields["id_gender"] = gender2text(H.identifying_gender)
+ if(H.get_FBP_type())
+ M.fields["brain_type"] = H.get_FBP_type()
+ else
+ M.fields["brain_type"] = "Organic"
if(H.med_record && !jobban_isbanned(H, "Records"))
M.fields["notes"] = H.med_record
//Security Record
var/datum/data/record/S = CreateSecurityRecord(H.real_name, id)
+ if(H.get_FBP_type())
+ S.fields["brain_type"] = H.get_FBP_type()
+ else
+ S.fields["brain_type"] = "Organic"
if(H.sec_record && !jobban_isbanned(H, "Records"))
S.fields["notes"] = H.sec_record
@@ -218,6 +230,10 @@
L.fields["fingerprint"] = md5(H.dna.uni_identity)
L.fields["sex"] = gender2text(H.gender)
L.fields["id_gender"] = gender2text(H.identifying_gender)
+ if(H.get_FBP_type())
+ L.fields["brain_type"] = H.get_FBP_type()
+ else
+ L.fields["brain_type"] = "Organic"
L.fields["b_type"] = H.b_type
L.fields["b_dna"] = H.dna.unique_enzymes
L.fields["enzymes"] = H.dna.SE // Used in respawning
@@ -426,6 +442,7 @@
G.fields["real_rank"] = "Unassigned"
G.fields["sex"] = "Unknown"
G.fields["age"] = "Unknown"
+ G.fields["brain_type"] = "Unknown"
G.fields["fingerprint"] = "Unknown"
G.fields["p_stat"] = "Active"
G.fields["m_stat"] = "Stable"
@@ -447,6 +464,7 @@
R.name = "Security Record #[id]"
R.fields["name"] = name
R.fields["id"] = id
+ R.fields["brain_type"] = "Unknown"
R.fields["criminal"] = "None"
R.fields["mi_crim"] = "None"
R.fields["mi_crim_d"] = "No minor crime convictions."
@@ -467,6 +485,7 @@
M.fields["b_type"] = "AB+"
M.fields["b_dna"] = md5(name)
M.fields["id_gender"] = "Unknown"
+ M.fields["brain_type"] = "Unknown"
M.fields["mi_dis"] = "None"
M.fields["mi_dis_d"] = "No minor disabilities have been declared."
M.fields["ma_dis"] = "None"
diff --git a/code/datums/repositories/decls.dm b/code/datums/repositories/decls.dm
new file mode 100644
index 00000000000..e87be74f531
--- /dev/null
+++ b/code/datums/repositories/decls.dm
@@ -0,0 +1,39 @@
+/var/repository/decls/decls_repository = new()
+
+/repository/decls
+ var/list/fetched_decls
+ var/list/fetched_decl_types
+ var/list/fetched_decl_subtypes
+
+/repository/decls/New()
+ ..()
+ fetched_decls = list()
+ fetched_decl_types = list()
+ fetched_decl_subtypes = list()
+
+/repository/decls/proc/decls_of_type(var/decl_prototype)
+ . = fetched_decl_types[decl_prototype]
+ if(!.)
+ . = get_decls(typesof(decl_prototype))
+ fetched_decl_types[decl_prototype] = .
+
+/repository/decls/proc/decls_of_subtype(var/decl_prototype)
+ . = fetched_decl_subtypes[decl_prototype]
+ if(!.)
+ . = get_decls(subtypesof(decl_prototype))
+ fetched_decl_subtypes[decl_prototype] = .
+
+/repository/decls/proc/get_decl(var/decl_type)
+ . = fetched_decls[decl_type]
+ if(!.)
+ . = new decl_type()
+ fetched_decls[decl_type] = .
+
+/repository/decls/proc/get_decls(var/list/decl_types)
+ . = list()
+ for(var/decl_type in decl_types)
+ .[decl_type] = get_decl(decl_type)
+
+/decls/Destroy()
+ crash_with("Prevented attempt to delete a decl instance: [log_info_line(src)]")
+ return 1 // Prevents Decl destruction
\ No newline at end of file
diff --git a/code/datums/repositories/repository.dm b/code/datums/repositories/repository.dm
index 6267099c930..04eee505401 100644
--- a/code/datums/repositories/repository.dm
+++ b/code/datums/repositories/repository.dm
@@ -1,4 +1,19 @@
+/repository/New()
+ return
+
/datum/cache_entry
var/timestamp
var/data
+/datum/cache_entry/New()
+ timestamp = world.time
+
+/datum/cache_entry/proc/is_valid()
+ return FALSE
+
+/datum/cache_entry/valid_until/New(var/valid_duration)
+ ..()
+ timestamp += valid_duration
+
+/datum/cache_entry/valid_until/is_valid()
+ return world.time < timestamp
\ No newline at end of file
diff --git a/code/datums/supplypacks/contraband.dm b/code/datums/supplypacks/contraband.dm
index d6427f063f2..0c7fd3f4eda 100644
--- a/code/datums/supplypacks/contraband.dm
+++ b/code/datums/supplypacks/contraband.dm
@@ -32,6 +32,17 @@
containername = "Special Ops crate"
contraband = 1
+/datum/supply_packs/supply/moghes
+ name = "Moghes imports"
+ contains = list(
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/redeemersbrew = 2,
+ /obj/item/weapon/reagent_containers/food/snacks/unajerky = 4
+ )
+ cost = 25
+ containertype = /obj/structure/closet/crate
+ containername = "Moghes imports crate"
+ contraband = 1
+
/datum/supply_packs/security/bolt_rifles_mosin
name = "Surplus militia rifles"
contains = list(
diff --git a/code/datums/supplypacks/security.dm b/code/datums/supplypacks/security.dm
index 1ec25bc28d0..e248acc46c0 100644
--- a/code/datums/supplypacks/security.dm
+++ b/code/datums/supplypacks/security.dm
@@ -200,6 +200,7 @@
/obj/item/clothing/under/det/black = 2,
/obj/item/clothing/under/det/grey = 2,
/obj/item/clothing/head/det/grey = 2,
+ /obj/item/clothing/under/det/skirt = 2,
/obj/item/clothing/under/det = 2,
/obj/item/clothing/head/det = 2,
/obj/item/clothing/suit/storage/det_trench,
diff --git a/code/datums/underwear/undershirts.dm b/code/datums/underwear/undershirts.dm
index 83cae026cec..59f33be094a 100644
--- a/code/datums/underwear/undershirts.dm
+++ b/code/datums/underwear/undershirts.dm
@@ -8,11 +8,6 @@
icon_state = "undershirt"
has_color = TRUE
-/datum/category_item/underwear/undershirt/shirt_long
- name = "Long Shirt"
- icon_state = "undershirt_long"
- has_color = TRUE
-
/datum/category_item/underwear/undershirt/shirt_fem
name = "Babydoll shirt"
icon_state = "undershirt_fem"
@@ -23,11 +18,22 @@
icon_state = "undershirt_long"
has_color = TRUE
+/datum/category_item/underwear/undershirt/shirt_long_s
+ name = "Shirt, button-down"
+ icon_state = "shirt_long_s"
+ has_color = TRUE
+
/datum/category_item/underwear/undershirt/shirt_long_fem
name = "Longsleeve Shirt, feminine"
icon_state = "undershirt_long_fem"
has_color = TRUE
+/datum/category_item/underwear/undershirt/shirt_long_female_s
+ name = "Button-down Shirt, feminine"
+ icon_state = "shirt_long_female_s"
+ has_color = TRUE
+
+
/datum/category_item/underwear/undershirt/tank_top
name = "Tank top"
icon_state = "tanktop"
diff --git a/code/datums/uplink/medical.dm b/code/datums/uplink/medical.dm
index eab9d9cd021..0c616793ca1 100644
--- a/code/datums/uplink/medical.dm
+++ b/code/datums/uplink/medical.dm
@@ -22,12 +22,12 @@
/datum/uplink_item/item/medical/clotting
name = "Clotting Medicine injector"
item_cost = 10
- path = /obj/item/weapon/reagent_containers/hypospray/autoinjector/clotting
+ path = /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/clotting
/datum/uplink_item/item/medical/bonemeds
name = "Bone Repair injector"
item_cost = 10
- path = /obj/item/weapon/reagent_containers/hypospray/autoinjector/bonemed
+ path = /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/bonemed
/datum/uplink_item/item/medical/ambrosiadeusseeds
name = "Box of 7x ambrosia deus seed packets"
diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm
index 01e95e5716a..b98b2370ce1 100755
--- a/code/game/area/Space Station 13 areas.dm
+++ b/code/game/area/Space Station 13 areas.dm
@@ -49,7 +49,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
var/no_air = null
// var/list/lights // list of all lights on this area
var/list/all_doors = list() //Added by Strumpetplaya - Alarm Change - Contains a list of doors adjacent to this area
- var/air_doors_activated = 0
+ var/firedoors_closed = 0
var/list/ambience = list('sound/ambience/ambigen1.ogg','sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambigen12.ogg','sound/ambience/ambigen14.ogg')
var/list/forced_ambience = null
var/sound_env = STANDARD_STATION
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index f1520509902..32a58c5dbea 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -53,22 +53,28 @@
danger_level = max(danger_level, AA.danger_level)
if(danger_level != atmosalm)
- if (danger_level < 1 && atmosalm >= 1)
- //closing the doors on red and opening on green provides a bit of hysteresis that will hopefully prevent fire doors from opening and closing repeatedly due to noise
- air_doors_open()
- else if (danger_level >= 2 && atmosalm < 2)
- air_doors_close()
-
atmosalm = danger_level
+ //closing the doors on red and opening on green provides a bit of hysteresis that will hopefully prevent fire doors from opening and closing repeatedly due to noise
+ if (danger_level < 1 || danger_level >= 2)
+ firedoors_update()
+
for (var/obj/machinery/alarm/AA in src)
AA.update_icon()
return 1
return 0
-/area/proc/air_doors_close()
- if(!air_doors_activated)
- air_doors_activated = 1
+// Either close or open firedoors depending on current alert statuses
+/area/proc/firedoors_update()
+ if(fire || party || atmosalm)
+ firedoors_close()
+ else
+ firedoors_open()
+
+// Close all firedoors in the area
+/area/proc/firedoors_close()
+ if(!firedoors_closed)
+ firedoors_closed = TRUE
for(var/obj/machinery/door/firedoor/E in all_doors)
if(!E.blocked)
if(E.operating)
@@ -77,9 +83,10 @@
spawn(0)
E.close()
-/area/proc/air_doors_open()
- if(air_doors_activated)
- air_doors_activated = 0
+// Open all firedoors in the area
+/area/proc/firedoors_open()
+ if(firedoors_closed)
+ firedoors_closed = FALSE
for(var/obj/machinery/door/firedoor/E in all_doors)
if(!E.blocked)
if(E.operating)
@@ -93,27 +100,13 @@
if(!fire)
fire = 1 //used for firedoor checks
updateicon()
- mouse_opacity = 0
- for(var/obj/machinery/door/firedoor/D in all_doors)
- if(!D.blocked)
- if(D.operating)
- D.nextstate = FIREDOOR_CLOSED
- else if(!D.density)
- spawn()
- D.close()
+ firedoors_update()
/area/proc/fire_reset()
if (fire)
fire = 0 //used for firedoor checks
updateicon()
- mouse_opacity = 0
- for(var/obj/machinery/door/firedoor/D in all_doors)
- if(!D.blocked)
- if(D.operating)
- D.nextstate = FIREDOOR_OPEN
- else if(D.density)
- spawn(0)
- D.open()
+ firedoors_update()
/area/proc/readyalert()
if(!eject)
@@ -131,21 +124,14 @@
if (!( party ))
party = 1
updateicon()
- mouse_opacity = 0
+ firedoors_update()
return
/area/proc/partyreset()
if (party)
party = 0
- mouse_opacity = 0
updateicon()
- for(var/obj/machinery/door/firedoor/D in src)
- if(!D.blocked)
- if(D.operating)
- D.nextstate = FIREDOOR_OPEN
- else if(D.density)
- spawn(0)
- D.open()
+ firedoors_update()
return
/area/proc/updateicon()
diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm
index 2234e0a540a..e54eb3c1cd0 100644
--- a/code/game/gamemodes/changeling/changeling_powers.dm
+++ b/code/game/gamemodes/changeling/changeling_powers.dm
@@ -21,6 +21,7 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
var/armor_deployed = 0 //This is only used for changeling_generic_equip_all_slots() at the moment.
var/recursive_enhancement = 0 //Used to power up other abilities from the ling power with the same name.
var/list/purchased_powers_history = list() //Used for round-end report, includes respec uses too.
+ var/last_shriek = null // world.time when the ling last used a shriek.
/datum/changeling/New(var/gender=FEMALE)
..()
@@ -156,6 +157,46 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
//STINGS// //They get a pretty header because there's just so fucking many of them ;_;
//////////
+turf/proc/AdjacentTurfsRangedSting()
+ //Yes this is snowflakey, but I couldn't get it to work any other way.. -Luke
+ var/list/allowed = list(
+ /obj/structure/table,
+ /obj/structure/closet,
+ /obj/structure/frame,
+ /obj/structure/target_stake,
+ /obj/structure/cable,
+ /obj/structure/disposalpipe,
+ /obj/machinery/
+ )
+
+ var/L[] = new()
+ for(var/turf/simulated/t in oview(src,1))
+ var/add = 1
+ if(t.density)
+ add = 0
+ if(add && LinkBlocked(src,t))
+ add = 0
+ if(add && TurfBlockedNonWindow(t))
+ add = 0
+ for(var/obj/O in t)
+ if(!O.density)
+ add = 1
+ break
+ if(istype(O, /obj/machinery/door))
+ //not sure why this doesn't fire on LinkBlocked()
+ add = 0
+ break
+ for(var/type in allowed)
+ if (istype(O, type))
+ add = 1
+ break
+ if(!add)
+ break
+ if(add)
+ L.Add(t)
+ return L
+
+
/mob/proc/sting_can_reach(mob/M as mob, sting_range = 1)
if(M.loc == src.loc)
return 1 //target and source are in the same thing
@@ -163,7 +204,7 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
src << "We cannot reach \the [M] with a sting!"
return 0 //One is inside, the other is outside something.
// Maximum queued turfs set to 25; I don't *think* anything raises sting_range above 2, but if it does the 25 may need raising
- if(!AStar(src.loc, M.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance, max_nodes=25, max_node_depth=sting_range)) //If we can't find a path, fail
+ if(!AStar(src.loc, M.loc, /turf/proc/AdjacentTurfsRangedSting, /turf/proc/Distance, max_nodes=25, max_node_depth=sting_range)) //If we can't find a path, fail
src << "We cannot find a path to sting \the [M] by!"
return 0
return 1
diff --git a/code/game/gamemodes/changeling/generic_equip_procs.dm b/code/game/gamemodes/changeling/generic_equip_procs.dm
index e8ed12a446b..9c73a4e3d22 100644
--- a/code/game/gamemodes/changeling/generic_equip_procs.dm
+++ b/code/game/gamemodes/changeling/generic_equip_procs.dm
@@ -32,7 +32,7 @@
return 1
if(M.head || M.wear_suit) //Make sure our slots aren't full
- src << "We require nothing to be on our head, and we cannot wear any external suits."
+ src << "We require nothing to be on our head, and we cannot wear any external suits, or shoes."
return 0
var/obj/item/clothing/suit/A = new armor_type(src)
@@ -140,7 +140,7 @@
playsound(src, 'sound/effects/blobattack.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
t = stuff_to_equip["w_uniform"]
if(!M.w_uniform && t)
@@ -150,7 +150,7 @@
playsound(src, 'sound/effects/blobattack.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
t = stuff_to_equip["gloves"]
if(!M.gloves && t)
@@ -160,7 +160,7 @@
playsound(src, 'sound/effects/splat.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
t = stuff_to_equip["shoes"]
if(!M.shoes && t)
@@ -170,7 +170,7 @@
playsound(src, 'sound/effects/splat.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
t = stuff_to_equip["belt"]
if(!M.belt && t)
@@ -180,7 +180,7 @@
playsound(src, 'sound/effects/splat.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
t = stuff_to_equip["glasses"]
if(!M.glasses && t)
@@ -190,7 +190,7 @@
playsound(src, 'sound/effects/splat.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
t = stuff_to_equip["wear_mask"]
if(!M.wear_mask && t)
@@ -200,7 +200,7 @@
playsound(src, 'sound/effects/splat.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
t = stuff_to_equip["back"]
if(!M.back && t)
@@ -210,7 +210,7 @@
playsound(src, 'sound/effects/blobattack.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
t = stuff_to_equip["wear_suit"]
if(!M.wear_suit && t)
@@ -220,7 +220,7 @@
playsound(src, 'sound/effects/blobattack.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
t = stuff_to_equip["wear_id"]
if(!M.wear_id && t)
@@ -230,7 +230,7 @@
playsound(src, 'sound/effects/splat.ogg', 30, 1)
M.update_icons()
success = 1
- sleep(20)
+ sleep(1 SECOND)
var/feedback = english_list(grown_items_list, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" )
diff --git a/code/game/gamemodes/changeling/powers/boost_range.dm b/code/game/gamemodes/changeling/powers/boost_range.dm
index fd15d94daec..a22130484ca 100644
--- a/code/game/gamemodes/changeling/powers/boost_range.dm
+++ b/code/game/gamemodes/changeling/powers/boost_range.dm
@@ -18,11 +18,11 @@
if(!changeling)
return 0
changeling.chem_charges -= 10
- src << "Your throat adjusts to launch the sting."
+ to_chat(src, "Your throat adjusts to launch the sting.")
var/range = 2
if(src.mind.changeling.recursive_enhancement)
range = range + 3
- src << "We can fire our next sting from five squares away."
+ to_chat(src, "We can fire our next sting from five squares away.")
changeling.sting_range = range
src.verbs -= /mob/proc/changeling_boost_range
spawn(5)
diff --git a/code/game/gamemodes/changeling/powers/fabricate_clothing.dm b/code/game/gamemodes/changeling/powers/fabricate_clothing.dm
index f106d9167fb..138cd156e38 100644
--- a/code/game/gamemodes/changeling/powers/fabricate_clothing.dm
+++ b/code/game/gamemodes/changeling/powers/fabricate_clothing.dm
@@ -18,7 +18,7 @@ var/global/list/changeling_fabricated_clothing = list(
helptext = "The disguise we create offers no defensive ability. Each equipment slot that is empty will be filled with fabricated equipment. \
To remove our new fabricated clothing, use this ability again."
ability_icon_state = "ling_fabricate_clothing"
- genomecost = 2
+ genomecost = 1
verbpath = /mob/proc/changeling_fabricate_clothing
//Grows biological versions of chameleon clothes.
diff --git a/code/game/gamemodes/changeling/powers/fake_death.dm b/code/game/gamemodes/changeling/powers/fake_death.dm
index dee603fc4a9..765dbb51e61 100644
--- a/code/game/gamemodes/changeling/powers/fake_death.dm
+++ b/code/game/gamemodes/changeling/powers/fake_death.dm
@@ -12,7 +12,7 @@
set category = "Changeling"
set name = "Regenerative Stasis (20)"
- var/datum/changeling/changeling = changeling_power(20,1,100,DEAD)
+ var/datum/changeling/changeling = changeling_power(CHANGELING_STASIS_COST,1,100,DEAD)
if(!changeling)
return
@@ -28,6 +28,7 @@
C.update_canmove()
C.remove_changeling_powers()
+ changeling.chem_charges -= CHANGELING_STASIS_COST
if(C.suiciding)
C.suiciding = 0
@@ -35,7 +36,9 @@
if(C.stat != DEAD)
C.adjustOxyLoss(C.maxHealth * 2)
- spawn(rand(800,2000))
+ C.forbid_seeing_deadchat = TRUE
+
+ spawn(rand(2 MINUTES, 4 MINUTES))
//The ling will now be able to choose when to revive
src.verbs += /mob/proc/changeling_revive
src << "We are ready to rise. Use the Revive verb when you are ready."
diff --git a/code/game/gamemodes/changeling/powers/respec.dm b/code/game/gamemodes/changeling/powers/respec.dm
index d984083aba9..66f13e720f1 100644
--- a/code/game/gamemodes/changeling/powers/respec.dm
+++ b/code/game/gamemodes/changeling/powers/respec.dm
@@ -29,6 +29,3 @@
src << "We have removed our evolutions from this form, and are now ready to readapt."
ling_datum.purchased_powers_history.Add("Re-adapt (Reset to [ling_datum.max_geneticpoints])")
-
- //Now to lose the verb, so no unlimited resets.
-
diff --git a/code/game/gamemodes/changeling/powers/revive.dm b/code/game/gamemodes/changeling/powers/revive.dm
index 2f0b9c57e75..c640e353925 100644
--- a/code/game/gamemodes/changeling/powers/revive.dm
+++ b/code/game/gamemodes/changeling/powers/revive.dm
@@ -41,6 +41,10 @@
current_limb.undislocate()
current_limb.open = 0
+ BITSET(H.hud_updateflag, HEALTH_HUD)
+ BITSET(H.hud_updateflag, STATUS_HUD)
+ BITSET(H.hud_updateflag, LIFE_HUD)
+
C.halloss = 0
C.shock_stage = 0 //Pain
C << "We have regenerated."
@@ -48,8 +52,12 @@
C.mind.changeling.purchased_powers -= C
feedback_add_details("changeling_powers","CR")
C.stat = CONSCIOUS
+ C.forbid_seeing_deadchat = FALSE
C.timeofdeath = null
src.verbs -= /mob/proc/changeling_revive
// re-add our changeling powers
C.make_changeling()
+
+
+
return 1
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/shriek.dm b/code/game/gamemodes/changeling/powers/shriek.dm
index ded66148fa4..37e7f67fe04 100644
--- a/code/game/gamemodes/changeling/powers/shriek.dm
+++ b/code/game/gamemodes/changeling/powers/shriek.dm
@@ -35,6 +35,14 @@
src << "You can't speak!"
return 0
+ if(world.time < (changeling.last_shriek + 10 SECONDS) )
+ to_chat(src, "We are still recovering from our last shriek...")
+ return 0
+
+ if(!isturf(loc))
+ to_chat(src, "Shrieking here would be a bad idea.")
+ return 0
+
src.break_cloak() //No more invisible shrieking
changeling.chem_charges -= 20
@@ -47,6 +55,8 @@
message_admins("[key_name(src)] used Resonant Shriek ([src.x],[src.y],[src.z]) (JMP).")
log_game("[key_name(src)] used Resonant Shriek.")
+ visible_message("[src] appears to shout.")
+
for(var/mob/living/M in range(range, src))
if(iscarbon(M))
if(!M.mind || !M.mind.changeling)
@@ -73,11 +83,7 @@
L.on = 1
L.broken()
-/* src.verbs -= /mob/proc/changeling_resonant_shriek
- spawn(30 SECONDS)
- src << "We are ready to use our resonant shriek once more."
- src.verbs |= /mob/proc/changeling_resonant_shriek
-Ability Cooldowns don't work properly right now, need to redo this when they are */
+ changeling.last_shriek = world.time
feedback_add_details("changeling_powers","RS")
return 1
@@ -101,6 +107,14 @@ Ability Cooldowns don't work properly right now, need to redo this when they are
src << "You can't speak!"
return 0
+ if(world.time < (changeling.last_shriek + 10 SECONDS) )
+ to_chat(src, "We are still recovering from our last shriek...")
+ return 0
+
+ if(!isturf(loc))
+ to_chat(src, "Shrieking here would be a bad idea.")
+ return 0
+
src.break_cloak() //No more invisible shrieking
changeling.chem_charges -= 20
@@ -117,6 +131,8 @@ Ability Cooldowns don't work properly right now, need to redo this when they are
src << "We are extra loud."
src.mind.changeling.recursive_enhancement = 0
+ visible_message("[src] appears to shout.")
+
src.attack_log += text("\[[time_stamp()]\] Used Dissonant Shriek.")
message_admins("[key_name(src)] used Dissonant Shriek ([src.x],[src.y],[src.z]) (JMP).")
log_game("[key_name(src)] used Dissonant Shriek.")
@@ -126,9 +142,6 @@ Ability Cooldowns don't work properly right now, need to redo this when they are
L.broken()
empulse(get_turf(src), range_heavy, range_light, 1)
-/* src.verbs -= /mob/proc/changeling_dissonant_shriek
- spawn(30 SECONDS)
- src << "We are ready to use our dissonant shriek once more."
- src.verbs |= /mob/proc/changeling_dissonant_shriek
-Ability Cooldowns don't work properly right now, need to redo this when they are */
+ changeling.last_shriek = world.time
+
return 1
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/transform.dm b/code/game/gamemodes/changeling/powers/transform.dm
index 236af69f5fd..37a99452102 100644
--- a/code/game/gamemodes/changeling/powers/transform.dm
+++ b/code/game/gamemodes/changeling/powers/transform.dm
@@ -13,6 +13,10 @@
var/datum/changeling/changeling = changeling_power(5,1,0)
if(!changeling) return
+ if(!isturf(loc))
+ to_chat(src, "Transforming here would be a bad idea.")
+ return 0
+
var/list/names = list()
for(var/datum/absorbed_dna/DNA in changeling.absorbed_dna)
names += "[DNA.name]"
diff --git a/code/game/gamemodes/changeling/powers/visible_camouflage.dm b/code/game/gamemodes/changeling/powers/visible_camouflage.dm
index 00e31cc932d..167f6f41b9b 100644
--- a/code/game/gamemodes/changeling/powers/visible_camouflage.dm
+++ b/code/game/gamemodes/changeling/powers/visible_camouflage.dm
@@ -3,7 +3,7 @@
desc = "We rapidly shape the color of our skin and secrete easily reversible dye on our clothes, to blend in with our surroundings. \
We are undetectable, so long as we move slowly.(Toggle)"
helptext = "Running, and performing most acts will reveal us. Our chemical regeneration is halted while we are hidden."
- enhancedtext = "True invisiblity while cloaked."
+ enhancedtext = "Can run while hidden."
ability_icon_state = "ling_camoflage"
genomecost = 3
verbpath = /mob/proc/changeling_visible_camouflage
@@ -31,20 +31,35 @@
var/old_regen_rate = H.mind.changeling.chem_recharge_rate
H << "We vanish from sight, and will remain hidden, so long as we move carefully."
- H.set_m_intent("walk")
H.mind.changeling.cloaked = 1
H.mind.changeling.chem_recharge_rate = 0
animate(src,alpha = 255, alpha = 10, time = 10)
+ var/must_walk = TRUE
if(src.mind.changeling.recursive_enhancement)
- H.invisibility = INVISIBILITY_OBSERVER
- src << "We are now truly invisible."
+ must_walk = FALSE
+ to_chat(src, "We may move at our normal speed while hidden.")
+
+ if(must_walk)
+ H.set_m_intent("walk")
+
+ var/remain_cloaked = TRUE
+ while(remain_cloaked) //This loop will keep going until the player uncloaks.
+ sleep(1 SECOND) // Sleep at the start so that if something invalidates a cloak, it will drop immediately after the check and not in one second.
+
+ if(H.m_intent != "walk" && must_walk) // Moving too fast uncloaks you.
+ remain_cloaked = 0
+ if(!H.mind.changeling.cloaked)
+ remain_cloaked = 0
+ if(H.stat) // Dead or unconscious lings can't stay cloaked.
+ remain_cloaked = 0
+ if(H.incapacitated(INCAPACITATION_DISABLED)) // Stunned lings also can't stay cloaked.
+ remain_cloaked = 0
- while(H.m_intent == "walk" && H.mind.changeling.cloaked && !H.stat) //This loop will keep going until the player uncloaks.
if(mind.changeling.chem_recharge_rate != 0) //Without this, there is an exploit that can be done, if one buys engorged chem sacks while cloaked.
old_regen_rate += mind.changeling.chem_recharge_rate //Unfortunately, it has to occupy this part of the proc. This fixes it while at the same time
mind.changeling.chem_recharge_rate = 0 //making sure nobody loses out on their bonus regeneration after they're done hiding.
- sleep(10)
+
H.invisibility = initial(invisibility)
diff --git a/code/game/gamemodes/events/holidays/Holidays.dm b/code/game/gamemodes/events/holidays/Holidays.dm
index 7838ba3dd39..8392002a362 100644
--- a/code/game/gamemodes/events/holidays/Holidays.dm
+++ b/code/game/gamemodes/events/holidays/Holidays.dm
@@ -59,7 +59,7 @@ var/global/list/Holiday = list() //Holidays are lists now, so we can have more t
if(14)
Holiday["Pi Day"] = "An unoffical holiday celebrating the mathematical constant Pi. It is celebrated on \
March 14th, as the digits form 3 14, the first three significant digits of Pi. Observance of Pi Day generally \
- imvolve eating (or throwing) pie, due to a pun. Pies also tend to be round, and thus relatable to Pi."
+ involve eating (or throwing) pie, due to a pun. Pies also tend to be round, and thus relatable to Pi."
if(17)
Holiday["St. Patrick's Day"] = "An old holiday originating from Earth, Sol, celebrating the color green, \
shamrocks, attending parades, and drinking alcohol."
@@ -93,6 +93,12 @@ var/global/list/Holiday = list() //Holidays are lists now, so we can have more t
switch(DD)
if(1)
Holiday["Interstellar Workers' Day"] = "This holiday celebrates the work of laborers and the working class."
+ if(18)
+ Holiday["Remembrance Day"] = "Remembrance Day (or, as it is more informally known, Armistice Day) is a confederation-wide holiday \
+ mostly observed by its member states since late 2520. Officially, it is a day of remembering the men and women who died in various armed conflicts \
+ throughout human history. Unofficially, however, it is commonly treated as a holiday honoring the victims of the Human-Unathi war. \
+ Observance of this day varies throughout human space, but most common traditions are the act of bringing flowers to graves,\
+ attending parades, and the wearing of poppies (either paper or real) in one's clothing."
if(28)
Holiday["Jiql-tes"] = "A Skrellian holiday that translates to 'Day of Celebration', Skrell communities \
gather for a grand feast and give gifts to friends and close relatives."
@@ -105,6 +111,9 @@ var/global/list/Holiday = list() //Holidays are lists now, so we can have more t
if(14)
Holiday["Blood Donor Day"] = "This holiday was created to raise awareness of the need for safe blood and blood products, \
and to thank blood donors for their voluntary, life-saving gifts of blood."
+ if(20)
+ Holiday["Civil Servant's Day"] = "Civil Servant's Day is a holiday observed in SCG member states that honors civil servants everywhere,\
++ (especially those who are members of the armed forces and the emergency services), or have been or have been civil servants in the past."
if(7) //Jul
switch(DD)
diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm
index 2d43e67f243..b9418bfea9b 100644
--- a/code/game/gamemodes/heist/heist.dm
+++ b/code/game/gamemodes/heist/heist.dm
@@ -7,20 +7,13 @@ var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind'
/datum/game_mode/heist
name = "Heist"
config_tag = "heist"
- required_players = 8
- required_players_secret = 8
- required_enemies = 3
+ required_players = 15
+ required_players_secret = 15
+ required_enemies = 4
round_description = "An unidentified bluespace signature is approaching the station!"
extended_round_description = "The Company's majority control of phoron in the system has marked the \
station to be a highly valuable target for many competing organizations and individuals. Being a \
colony of sizable population and considerable wealth causes it to often be the target of various \
attempts of robbery, fraud and other malicious actions."
end_on_antag_death = 0
- antag_tags = list(MODE_RAIDER)
-
-/datum/game_mode/heist/check_finished()
- if(!..())
- var/datum/shuttle/multi_shuttle/skipjack = shuttle_controller.shuttles["Skipjack"]
- if (skipjack && skipjack.returned_home)
- return 1
- return 0
+ antag_tags = list(MODE_RAIDER)
\ No newline at end of file
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index e2f6b8a56cc..098f9fd3292 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -12,9 +12,9 @@ var/list/nuke_disks = list()
colony of sizable population and considerable wealth causes it to often be the target of various \
attempts of robbery, fraud and other malicious actions."
config_tag = "mercenary"
- required_players = 8
- required_players_secret = 8
- required_enemies = 3
+ required_players = 15
+ required_players_secret = 15
+ required_enemies = 4
end_on_antag_death = 0
var/nuke_off_station = 0 //Used for tracking if the syndies actually haul the nuke to the station
var/syndies_didnt_escape = 0 //Used for tracking if the syndies got the shuttle off of the z-level
diff --git a/code/game/gamemodes/technomancer/assistance/assistance.dm b/code/game/gamemodes/technomancer/assistance/assistance.dm
index 3cdf7014ade..8b060429e8f 100644
--- a/code/game/gamemodes/technomancer/assistance/assistance.dm
+++ b/code/game/gamemodes/technomancer/assistance/assistance.dm
@@ -30,7 +30,7 @@
/obj/item/weapon/antag_spawner/technomancer_apprentice/New()
..()
- sparks = PoolOrNew(/datum/effect/effect/system/spark_spread)
+ sparks = new /datum/effect/effect/system/spark_spread()
sparks.set_up(5, 0, src)
sparks.attach(loc)
@@ -98,8 +98,8 @@
/datum/technomancer/assistance/golem
name = "Friendly GOLEM unit"
desc = "Teleports a specially designed synthetic unit to you, which is very durable, has an advanced AI, and can also use \
- functions. It knows Shield, Targeted Blink, Beam, Flame Tongue, Mend Wounds, and Mend Burns. It also has a large storage \
- capacity for energy, and due to it's synthetic nature, instability is less of an issue for them."
+ functions. It knows Shield, Targeted Blink, Beam, Mend Life, Mend Synthetic, Lightning, Repel Missiles, Corona, Ionic Bolt, Dispel, and Chain Lightning. \
+ It also has a large storage capacity for energy, and due to it's synthetic nature, instability is less of an issue for them."
cost = 350
obj_path = null //TODO
one_use_only = 1
diff --git a/code/game/gamemodes/technomancer/assistance/golem.dm b/code/game/gamemodes/technomancer/assistance/golem.dm
index 8bb6ef2ea0c..e0a0a5fd716 100644
--- a/code/game/gamemodes/technomancer/assistance/golem.dm
+++ b/code/game/gamemodes/technomancer/assistance/golem.dm
@@ -1,9 +1,9 @@
//An AI-controlled 'companion' for the Technomancer. It's tough, strong, and can also use spells.
-/mob/living/simple_animal/hostile/technomancer_golem
+/mob/living/simple_animal/technomancer_golem
name = "G.O.L.E.M."
desc = "A rather unusual looking synthetic."
- icon = 'icons/mob/robots.dmi'
- icon_state = "Security"
+ icon = 'icons/mob/mob.dmi'
+ icon_state = "technomancer_golem"
health = 250
maxHealth = 250
stop_automated_movement = 1
@@ -27,46 +27,137 @@
unsuitable_atoms_damage = 0
speed = 0
- melee_damage_lower = 10
- melee_damage_upper = 10
- attacktext = "pummeled"
+ melee_damage_lower = 30 // It has a built in esword.
+ melee_damage_upper = 30
+ attacktext = "slashed"
attack_sound = null
friendly = "hugs"
resistance = 0
- var/obj/item/weapon/technomancer_core/core = null
- var/obj/item/weapon/spell/active_spell = null
+ var/obj/item/weapon/technomancer_core/golem/core = null
+ var/obj/item/weapon/spell/active_spell = null // Shield and ranged spells
var/mob/living/master = null
-/mob/living/simple_animal/hostile/technomancer_golem/New()
- ..()
- core = new core(src)
+ var/list/known_spells = list(
+ "reflect" = /obj/item/weapon/spell/reflect,
+ "shield" = /obj/item/weapon/spell/shield,
+ "dispel" = /obj/item/weapon/spell/dispel,
+ "mend life" = /obj/item/weapon/spell/modifier/mend_life,
+ "mend synthetic" = /obj/item/weapon/spell/modifier/mend_synthetic,
+ "repel missiles" = /obj/item/weapon/spell/modifier/repel_missiles,
+ "corona" = /obj/item/weapon/spell/modifier/corona,
+ "beam" = /obj/item/weapon/spell/projectile/beam,
+ "chain lightning" = /obj/item/weapon/spell/projectile/chain_lightning,
+ "force missile" = /obj/item/weapon/spell/projectile/force_missile,
+ "ionic bolt" = /obj/item/weapon/spell/projectile/ionic_bolt,
+ "lightning" = /obj/item/weapon/spell/projectile/lightning
+ )
-/mob/living/simple_animal/hostile/technomancer_golem/Destroy()
+/mob/living/simple_animal/technomancer_golem/New()
+ ..()
+ core = new(src)
+ update_icon()
+
+/mob/living/simple_animal/technomancer_golem/Destroy()
qdel(core)
..()
-/mob/living/simple_animal/hostile/technomancer_golem/proc/bind_to_mob(mob/user)
+/mob/living/simple_animal/technomancer_golem/update_icon()
+ overlays.Cut()
+ overlays.Add(image(icon, src, "golem_sword"))
+ overlays.Add(image(icon, src, "golem_spell"))
+
+/mob/living/simple_animal/technomancer_golem/isSynthetic()
+ return TRUE // So Mend Synthetic will work on them.
+
+/mob/living/simple_animal/technomancer_golem/place_spell_in_hand(var/path)
+ if(!path || !ispath(path))
+ return 0
+
+ if(active_spell)
+ qdel(active_spell) // Get rid of our old spell.
+
+ var/obj/item/weapon/spell/S = new path(src)
+ active_spell = S
+
+/mob/living/simple_animal/technomancer_golem/verb/test_giving_spells()
+ var/choice = input(usr, "What spell?", "Give spell") as null|anything in known_spells
+ if(choice)
+ place_spell_in_hand(known_spells[choice])
+
+// Used to cast spells.
+/mob/living/simple_animal/technomancer_golem/RangedAttack(var/atom/A, var/params)
+ if(active_spell)
+ if(active_spell.cast_methods & CAST_RANGED)
+ active_spell.on_ranged_cast(A, src)
+
+/mob/living/simple_animal/technomancer_golem/UnarmedAttack(var/atom/A, var/proximity)
+ if(proximity)
+ if(active_spell)
+ if(active_spell.cast_methods & CAST_MELEE)
+ active_spell.on_melee_cast(A, src)
+ else if(active_spell.cast_methods & CAST_RANGED)
+ active_spell.on_ranged_cast(A, src)
+ var/effective_cooldown = round(active_spell.cooldown * core.cooldown_modifier, 5)
+ src.setClickCooldown(effective_cooldown)
+ else
+ ..()
+
+/mob/living/simple_animal/technomancer_golem/get_technomancer_core()
+ return core
+
+/mob/living/simple_animal/technomancer_golem/proc/bind_to_mob(mob/user)
if(!user || master)
return
master = user
name = "[master]'s [initial(name)]"
-/mob/living/simple_animal/hostile/technomancer_golem/examine(mob/user)
+/mob/living/simple_animal/technomancer_golem/examine(mob/user)
..()
if(user.mind && technomancers.is_antagonist(user.mind))
user << "Your pride and joy. It's a very special synthetic robot, capable of using functions similar to you, and you built it \
yourself! It'll always stand by your side, ready to help you out. You have no idea what GOLEM stands for, however..."
-/mob/living/simple_animal/hostile/technomancer_golem/Life()
+/mob/living/simple_animal/technomancer_golem/Life()
+ ..()
handle_ai()
-/mob/living/simple_animal/hostile/technomancer_golem/proc/handle_ai()
+// This is where the real spaghetti begins.
+/mob/living/simple_animal/technomancer_golem/proc/handle_ai()
if(!master)
return
if(get_dist(src, master) > 6 || src.z != master.z)
- recall_to_master()
+ targeted_blink(master)
+
+ // Give our allies buffs and heals.
+ for(var/mob/living/L in view(src))
+ if(L in friends)
+ support_friend(L)
+ return
+
+/mob/living/simple_animal/technomancer_golem/proc/support_friend(var/mob/living/L)
+ if(L.getBruteLoss() >= 10 || L.getFireLoss() >= 10)
+ if(L.isSynthetic() && !L.has_modifier_of_type(/datum/modifier/technomancer/mend_synthetic))
+ place_spell_in_hand(known_spells["mend synthetic"])
+ targeted_blink(L)
+ UnarmedAttack(L, 1)
+ else if(!L.has_modifier_of_type(/datum/modifier/technomancer/mend_life))
+ place_spell_in_hand(known_spells["mend life"])
+ targeted_blink(L)
+ UnarmedAttack(L, 1)
+ return
-/mob/living/simple_animal/hostile/technomancer_golem/proc/recall_to_master()
+ // Give them repel missiles if they lack it.
+ if(!L.has_modifier_of_type(/datum/modifier/technomancer/repel_missiles))
+ place_spell_in_hand(known_spells["repel missiles"])
+ RangedAttack(L)
+ return
+
+/mob/living/simple_animal/technomancer_golem/proc/targeted_blink(var/atom/target)
+ var/datum/effect/effect/system/spark_spread/spark_system = new()
+ spark_system.set_up(5, 0, get_turf(src))
+ spark_system.start()
+ src.visible_message("\The [src] vanishes!")
+ src.forceMove(get_turf(target))
return
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/core_obj.dm b/code/game/gamemodes/technomancer/core_obj.dm
index 079db9a90be..7cea66660e4 100644
--- a/code/game/gamemodes/technomancer/core_obj.dm
+++ b/code/game/gamemodes/technomancer/core_obj.dm
@@ -330,6 +330,18 @@
spell_power_modifier = 1.75
energy_cost_modifier = 2.0
+// For use only for the GOLEM.
+/obj/item/weapon/technomancer_core/golem
+ name = "integrated core"
+ desc = "A bewilderingly complex 'black box' that allows the wearer to accomplish amazing feats. This type is not meant \
+ to be worn on the back like other cores. Instead it is meant to be installed inside a synthetic shell. As a result, it's \
+ a lot more robust."
+ energy = 25000
+ max_energy = 25000
+ regen_rate = 100 //250 seconds to full
+ instability_modifier = 0.75
+
+
/obj/item/weapon/technomancer_core/verb/toggle_lock()
set name = "Toggle Core Lock"
set category = "Object"
diff --git a/code/game/gamemodes/technomancer/devices/hypos.dm b/code/game/gamemodes/technomancer/devices/hypos.dm
index b54ce5e35c8..dd0fa4436ac 100644
--- a/code/game/gamemodes/technomancer/devices/hypos.dm
+++ b/code/game/gamemodes/technomancer/devices/hypos.dm
@@ -5,12 +5,11 @@
amount_per_transfer_from_this = 15
volume = 15
origin_tech = list(TECH_BIO = 4)
+ filled_reagents = list("inaprovaline" = 15)
/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/New()
..()
- reagents.remove_reagent("inaprovaline", 5)
- update_icon()
- return
+
/datum/technomancer/consumable/hypo_brute
name = "Trauma Hypo"
@@ -66,127 +65,44 @@
name = "trauma hypo"
desc = "A refined version of the standard autoinjector, allowing greater capacity. This one is made to be used on victims of \
moderate blunt trauma."
- icon_state = "autoinjector"
- amount_per_transfer_from_this = 15
- volume = 15
- origin_tech = list(TECH_BIO = 4)
-
-/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/brute/New()
- ..()
- reagents.add_reagent("bicaridine", 15)
- update_icon()
- return
+ filled_reagents = list("bicaridine" = 15)
/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/burn
name = "burn hypo"
desc = "A refined version of the standard autoinjector, allowing greater capacity. This one is made to be used on burn victims, \
featuring an optimized chemical mixture to allow for rapid healing."
- icon_state = "autoinjector"
- amount_per_transfer_from_this = 15
- volume = 15
- origin_tech = list(TECH_BIO = 4)
-
-/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/burn/New()
- ..()
- reagents.add_reagent("kelotane", 7.5)
- reagents.add_reagent("dermaline", 7.5)
- update_icon()
- return
+ filled_reagents = list("kelotane" = 7.5, "dermaline" = 7.5)
/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/toxin
name = "toxin hypo"
desc = "A refined version of the standard autoinjector, allowing greater capacity. This one is made to counteract toxins."
- icon_state = "autoinjector"
- amount_per_transfer_from_this = 15
- volume = 15
- origin_tech = list(TECH_BIO = 4)
-
-/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/toxin/New()
- ..()
- reagents.add_reagent("anti_toxin", 15)
- update_icon()
- return
+ filled_reagents = list("anti_toxin" = 15)
/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/oxy
name = "oxy hypo"
desc = "A refined version of the standard autoinjector, allowing greater capacity. This one is made to counteract oxygen \
deprivation."
- icon_state = "autoinjector"
- amount_per_transfer_from_this = 15
- volume = 15
- origin_tech = list(TECH_BIO = 4)
-
-/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/oxy/New()
- ..()
- reagents.add_reagent("dexalinp", 10)
- reagents.add_reagent("tricordrazine", 5) //Dex+ ODs above 10, so we add tricord to pad it out somewhat.
- update_icon()
- return
+ filled_reagents = list("dexalinp" = 10, "tricordrazine" = 5)
/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/purity
name = "purity hypo"
desc = "A refined version of the standard autoinjector, allowing greater capacity. This varient excels at \
resolving viruses, infections, radiation, and genetic maladies."
- icon_state = "autoinjector"
- amount_per_transfer_from_this = 15
- volume = 15
- origin_tech = list(TECH_BIO = 4)
-
-/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/purity/New()
- ..()
- reagents.add_reagent("spaceacillin", 9)
- reagents.add_reagent("arithrazine", 5)
- reagents.add_reagent("ryetalyn", 1)
- update_icon()
- return
+ filled_reagents = list("spaceacillin" = 9, "arithrazine" = 5, "ryetalyn" = 1)
/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain
name = "pain hypo"
desc = "A refined version of the standard autoinjector, allowing greater capacity. This one contains potent painkillers."
- icon_state = "autoinjector"
- amount_per_transfer_from_this = 15
- volume = 15
- origin_tech = list(TECH_BIO = 4)
-
-/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain/New()
- ..()
- reagents.add_reagent("tramadol", 15)
- update_icon()
- return
+ filled_reagents = list("tramadol" = 15)
/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ
name = "organ hypo"
desc = "A refined version of the standard autoinjector, allowing greater capacity. Organ damage is resolved by this varient."
- icon_state = "autoinjector"
- amount_per_transfer_from_this = 15
- volume = 15
- origin_tech = list(TECH_BIO = 4)
-
-/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ/New()
- ..()
- reagents.add_reagent("alkysine", 1)
- reagents.add_reagent("imidazoline", 1)
- reagents.add_reagent("peridaxon", 13)
- update_icon()
- return
+ filled_reagents = list("alkysine" = 1, "imidazoline" = 1, "peridaxon" = 13)
/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat
name = "combat hypo"
desc = "A refined version of the standard autoinjector, allowing greater capacity. This is a more dangerous and potentially \
addictive hypo compared to others, as it contains a potent cocktail of various chemicals to optimize the recipient's combat \
ability."
- icon_state = "autoinjector"
- amount_per_transfer_from_this = 15
- volume = 15
- origin_tech = list(TECH_BIO = 4)
-
-/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat/New()
- ..()
- reagents.add_reagent("bicaridine", 3)
- reagents.add_reagent("kelotane", 1.5)
- reagents.add_reagent("dermaline", 1.5)
- reagents.add_reagent("oxycodone", 3)
- reagents.add_reagent("hyperzine", 3)
- reagents.add_reagent("tricordrazine", 3)
- update_icon()
- return
+ filled_reagents = list("bicaridine" = 3, "kelotane" = 1.5, "dermaline" = 1.5, "oxycodone" = 3, "hyperzine" = 3, "tricordrazine" = 3)
diff --git a/code/game/gamemodes/technomancer/devices/shield_armor.dm b/code/game/gamemodes/technomancer/devices/shield_armor.dm
index bacb2c60ed2..0bbb6ef0850 100644
--- a/code/game/gamemodes/technomancer/devices/shield_armor.dm
+++ b/code/game/gamemodes/technomancer/devices/shield_armor.dm
@@ -26,7 +26,7 @@
/obj/item/clothing/suit/armor/shield/New()
..()
- spark_system = PoolOrNew(/datum/effect/effect/system/spark_spread)
+ spark_system = new /datum/effect/effect/system/spark_spread()
spark_system.set_up(5, 0, src)
/obj/item/clothing/suit/armor/shield/Destroy()
diff --git a/code/game/gamemodes/technomancer/devices/tesla_armor.dm b/code/game/gamemodes/technomancer/devices/tesla_armor.dm
index 6b981aa8eb0..2e9a60a8e63 100644
--- a/code/game/gamemodes/technomancer/devices/tesla_armor.dm
+++ b/code/game/gamemodes/technomancer/devices/tesla_armor.dm
@@ -1,8 +1,8 @@
/datum/technomancer/equipment/tesla_armor
name = "Tesla Armor"
desc = "This piece of armor offers a retaliation-based defense. When the armor is 'ready', it will completely protect you from \
- the next attack you suffer, and strike the attacker with a strong bolt of lightning. This effect requires twenty seconds to \
- recharge. If you are attacked while this is recharging, a weaker lightning bolt is sent out, however you won't be protected from \
+ the next attack you suffer, and strike the attacker with a strong bolt of lightning, provided they are close enough. This effect requires \
+ fifteen seconds to recharge. If you are attacked while this is recharging, a weaker lightning bolt is sent out, however you won't be protected from \
the person beating you."
cost = 150
obj_path = /obj/item/clothing/suit/armor/tesla
@@ -10,23 +10,33 @@
/obj/item/clothing/suit/armor/tesla
name = "tesla armor"
desc = "This rather dangerous looking armor will hopefully shock your enemies, and not you in the process."
- icon_state = "reactiveoff" //wip
- item_state = "reactiveoff"
+ icon_state = "reactive" //wip
+ item_state = "reactive"
blood_overlay_type = "armor"
slowdown = 1
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0)
var/ready = 1 //Determines if the next attack will be blocked, as well if a strong lightning bolt is sent out at the attacker.
var/ready_icon_state = "reactive" //also wip
- var/cooldown_to_charge = 20 SECONDS
+ var/normal_icon_state = "reactiveoff"
+ var/cooldown_to_charge = 15 SECONDS
/obj/item/clothing/suit/armor/tesla/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
//First, some retaliation.
- if(attacker && attacker != user)
- if(get_dist(user, attacker) <= 3) //Anyone farther away than three tiles is too far to shoot lightning at.
+ if(istype(damage_source, /obj/item/projectile))
+ var/obj/item/projectile/P = damage_source
+ if(P.firer && get_dist(user, P.firer) <= 3)
if(ready)
- shoot_lightning(attacker, 40)
+ shoot_lightning(P.firer, 40)
else
- shoot_lightning(attacker, 15)
+ shoot_lightning(P.firer, 15)
+
+ else
+ if(attacker && attacker != user)
+ if(get_dist(user, attacker) <= 3) //Anyone farther away than three tiles is too far to shoot lightning at.
+ if(ready)
+ shoot_lightning(attacker, 40)
+ else
+ shoot_lightning(attacker, 15)
//Deal with protecting our wearer now.
if(ready)
@@ -45,10 +55,14 @@
if(ready)
icon_state = ready_icon_state
else
- icon_state = initial(icon_state)
+ icon_state = normal_icon_state
+ if(ishuman(loc))
+ var/mob/living/carbon/human/H = loc
+ H.update_inv_wear_suit(0)
/obj/item/clothing/suit/armor/tesla/proc/shoot_lightning(var/mob/target, var/power)
var/obj/item/projectile/beam/lightning/lightning = new(src)
lightning.power = power
lightning.launch(target)
- visible_message("\The [src] strikes \the [target] with lightning!")
\ No newline at end of file
+ visible_message("\The [src] strikes \the [target] with lightning!")
+ playsound(get_turf(src), 'sound/weapons/gauss_shoot.ogg', 75, 1)
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/equipment.dm b/code/game/gamemodes/technomancer/equipment.dm
index 5c440d0dcd8..8d1fb4c6ad1 100644
--- a/code/game/gamemodes/technomancer/equipment.dm
+++ b/code/game/gamemodes/technomancer/equipment.dm
@@ -191,6 +191,7 @@
icon_state = "scepter"
force = 15
slot_flags = SLOT_BELT
+ attack_verb = list("beaten", "smashed", "struck", "whacked")
/obj/item/weapon/scepter/attack_self(mob/living/carbon/human/user)
var/obj/item/item_to_test = user.get_other_hand(src)
diff --git a/code/game/gamemodes/technomancer/instability.dm b/code/game/gamemodes/technomancer/instability.dm
index fa9985b1b6b..21d746742ff 100644
--- a/code/game/gamemodes/technomancer/instability.dm
+++ b/code/game/gamemodes/technomancer/instability.dm
@@ -44,25 +44,25 @@
// Description: Makes instability decay. instability_effects() handles the bad effects for having instability. It will also hold back
// from causing bad effects more than one every ten seconds, to prevent sudden death from angry RNG.
/mob/living/proc/handle_instability()
- instability = round(Clamp(instability, 0, 200))
+ instability = Ceiling(Clamp(instability, 0, 200))
//This should cushon against really bad luck.
if(instability && last_instability_event < (world.time - 10 SECONDS) && prob(20))
instability_effects()
switch(instability)
if(1 to 10)
- adjust_instability(-2)
+ adjust_instability(-1)
if(11 to 20)
- adjust_instability(-4)
+ adjust_instability(-2)
if(21 to 30)
- adjust_instability(-6)
+ adjust_instability(-3)
if(31 to 40)
- adjust_instability(-8)
+ adjust_instability(-4)
if(41 to 50)
- adjust_instability(-10)
+ adjust_instability(-5)
if(51 to 100)
- adjust_instability(-20)
+ adjust_instability(-10)
if(101 to 200)
- adjust_instability(-40)
+ adjust_instability(-20)
/mob/living/carbon/human/handle_instability()
..()
@@ -102,7 +102,7 @@
rng = rand(0,1)
switch(rng)
if(0)
- var/datum/effect/effect/system/spark_spread/sparks = PoolOrNew(/datum/effect/effect/system/spark_spread)
+ var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread()
sparks.set_up(5, 0, src)
sparks.attach(loc)
sparks.start()
@@ -167,10 +167,10 @@
rng = rand(0,1)
switch(rng)
if(0)
- var/datum/effect/effect/system/spark_spread/sparks = PoolOrNew(/datum/effect/effect/system/spark_spread)
+ var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread()
sparks.set_up(5, 0, src)
sparks.attach(loc)
-// var/datum/effect/effect/system/spark_spread/spark_system = PoolOrNew(/datum/effect/effect/system/spark_spread)
+// var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread()
// spark_system.set_up(5, 0, get_turf(src))
// spark_system.attach(src)
sparks.start()
@@ -277,12 +277,17 @@
// People next to the source take a third of the instability. Further distance decreases the amount absorbed.
var/outgoing_instability = (instability / 3) * ( 1 / (radius**2) )
- // Energy armor like from the AMI RIG can protect from this.
- var/armor = getarmor(null, "energy")
- var/armor_factor = abs( (armor - 100) / 100)
- outgoing_instability = outgoing_instability * armor_factor
- if(outgoing_instability)
- to_chat(H, "The purple glow makes you feel strange...")
- H.adjust_instability(outgoing_instability)
- set_light(distance, distance * 2, l_color = "#C26DDE")
+ H.receive_radiated_instability(outgoing_instability)
+
+ set_light(distance, distance * 4, l_color = "#C26DDE")
+
+// This should only be used for EXTERNAL sources of instability, such as from someone or something glowing.
+/mob/living/proc/receive_radiated_instability(amount)
+ // Energy armor like from the AMI RIG can protect from this.
+ var/armor = getarmor(null, "energy")
+ var/armor_factor = abs( (armor - 100) / 100)
+ amount = amount * armor_factor
+ if(amount && prob(10))
+ to_chat(src, "The purple glow makes you feel strange...")
+ adjust_instability(amount)
diff --git a/code/game/gamemodes/technomancer/spell_objs.dm b/code/game/gamemodes/technomancer/spell_objs.dm
index fb22001d309..2dede11a942 100644
--- a/code/game/gamemodes/technomancer/spell_objs.dm
+++ b/code/game/gamemodes/technomancer/spell_objs.dm
@@ -31,7 +31,8 @@
)
throwforce = 0
force = 0
- var/mob/living/carbon/human/owner = null
+// var/mob/living/carbon/human/owner = null
+ var/mob/living/owner = null
var/obj/item/weapon/technomancer_core/core = null
var/cast_methods = null // Controls how the spell is casted.
var/aspect = null // Used for combining spells.
@@ -115,16 +116,33 @@
amount = round(amount * core.instability_modifier, 0.1)
owner.adjust_instability(amount)
+// Proc: get_technomancer_core()
+// Parameters: 0
+// Description: Returns the technomancer's core, assuming it is being worn properly.
+/mob/living/proc/get_technomancer_core()
+ return null
+
+/mob/living/carbon/human/get_technomancer_core()
+ var/obj/item/weapon/technomancer_core/core = back
+ if(istype(core))
+ return core
+ return null
+
// Proc: New()
// Parameters: 0
// Description: Sets owner to equal its loc, links to the owner's core, then applies overlays if needed.
/obj/item/weapon/spell/New()
..()
- if(ishuman(loc))
+ if(isliving(loc))
owner = loc
if(owner)
- if(istype(/obj/item/weapon/technomancer_core, owner.back))
- core = owner.back
+ core = owner.get_technomancer_core()
+ if(!core)
+ to_chat(owner, "You need a Core to do that.")
+ qdel(src)
+ return
+// if(istype(/obj/item/weapon/technomancer_core, owner.back))
+// core = owner.back
update_icon()
// Proc: Destroy()
@@ -247,7 +265,7 @@
if(!path || !ispath(path))
return 0
- //var/obj/item/weapon/spell/S = PoolOrNew(path, src)
+ //var/obj/item/weapon/spell/S = new path(src)
var/obj/item/weapon/spell/S = new path(src)
//No hands needed for innate casts.
diff --git a/code/game/gamemodes/technomancer/spells/aura/fire_aura.dm b/code/game/gamemodes/technomancer/spells/aura/fire_aura.dm
index 952fd5d43d2..6111784d6f4 100644
--- a/code/game/gamemodes/technomancer/spells/aura/fire_aura.dm
+++ b/code/game/gamemodes/technomancer/spells/aura/fire_aura.dm
@@ -13,17 +13,18 @@
/obj/item/weapon/spell/aura/fire
name = "Fire Storm"
desc = "Things are starting to heat up."
- icon_state = "generic"
+ icon_state = "fire_bolt"
aspect = ASPECT_FIRE
glow_color = "#FF6A00"
/obj/item/weapon/spell/aura/fire/process()
if(!pay_energy(100))
qdel(src)
- var/list/nearby_things = range(calculate_spell_power(4),owner)
+ var/list/nearby_things = range(round(calculate_spell_power(4)),owner)
- var/temp_change = calculate_spell_power(80)
- var/temp_cap = calculate_spell_power(600)
+ var/temp_change = calculate_spell_power(150)
+ var/datum/species/baseline = all_species["Human"]
+ var/temp_cap = baseline.heat_level_3 * 2
var/fire_power = calculate_spell_power(2)
if(check_for_scepter())
@@ -38,7 +39,8 @@
var/protection = H.get_heat_protection(1000)
if(protection < 1)
var/heat_factor = abs(protection - 1)
- H.bodytemperature = min( (H.bodytemperature + temp_change) * heat_factor, temp_cap)
+ temp_change *= heat_factor
+ H.bodytemperature = min(H.bodytemperature + temp_change, temp_cap)
turf_check:
for(var/turf/simulated/T in nearby_things)
diff --git a/code/game/gamemodes/technomancer/spells/aura/frost_aura.dm b/code/game/gamemodes/technomancer/spells/aura/frost_aura.dm
index c2106d5aa33..7e788de96e4 100644
--- a/code/game/gamemodes/technomancer/spells/aura/frost_aura.dm
+++ b/code/game/gamemodes/technomancer/spells/aura/frost_aura.dm
@@ -2,7 +2,7 @@
name = "Chilling Aura"
desc = "Lowers the core body temperature of everyone around you (except for your friends), causing them to become very slow if \
they stay within four meters of you."
- enhancement_desc = "The chill becomes lethal."
+ enhancement_desc = "Will make nearby entities even slower."
spell_power_desc = "Radius and rate of cooling are scaled."
cost = 100
obj_path = /obj/item/weapon/spell/aura/frost
@@ -20,14 +20,16 @@
/obj/item/weapon/spell/aura/frost/process()
if(!pay_energy(100))
qdel(src)
- var/list/nearby_mobs = range(calculate_spell_power(4),owner)
+ var/list/nearby_mobs = range(round(calculate_spell_power(4)),owner)
var/temp_change = calculate_spell_power(40)
- var/temp_cap = 260 // Just above the damage threshold, for humans. Unathi are less fortunate.
+ var/datum/species/baseline = all_species["Human"]
+ var/temp_cap = baseline.cold_level_2 - 5
if(check_for_scepter())
temp_change *= 2
- temp_cap = 200
+ temp_cap = baseline.cold_level_3 - 5
+
for(var/mob/living/carbon/human/H in nearby_mobs)
if(is_ally(H))
continue
@@ -35,6 +37,7 @@
var/protection = H.get_cold_protection(1000)
if(protection < 1)
var/cold_factor = abs(protection - 1)
- H.bodytemperature = max( (H.bodytemperature - temp_change) * cold_factor, temp_cap)
+ temp_change *= cold_factor
+ H.bodytemperature = max(H.bodytemperature - temp_change, temp_cap)
adjust_instability(1)
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/condensation.dm b/code/game/gamemodes/technomancer/spells/condensation.dm
index c02e1c1ac54..c303c2a5fb0 100644
--- a/code/game/gamemodes/technomancer/spells/condensation.dm
+++ b/code/game/gamemodes/technomancer/spells/condensation.dm
@@ -24,7 +24,7 @@
spawn(1)
var/turf/desired_turf = get_step(T,direction)
if(desired_turf) // This shouldn't fail but...
- var/obj/effect/effect/water/W = PoolOrNew(/obj/effect/effect/water, get_turf(T))
+ var/obj/effect/effect/water/W = new /obj/effect/effect/water(get_turf(T))
W.create_reagents(60)
W.reagents.add_reagent(id = "water", amount = 60, data = null, safety = 0)
W.set_color()
diff --git a/code/game/gamemodes/technomancer/spells/dispel.dm b/code/game/gamemodes/technomancer/spells/dispel.dm
index 87edf6a6212..60266426cb5 100644
--- a/code/game/gamemodes/technomancer/spells/dispel.dm
+++ b/code/game/gamemodes/technomancer/spells/dispel.dm
@@ -18,8 +18,6 @@
/obj/item/weapon/spell/dispel/on_ranged_cast(atom/hit_atom, mob/living/user)
if(isliving(hit_atom) && within_range(hit_atom) && pay_energy(1000))
var/mob/living/target = hit_atom
- for(var/obj/item/weapon/inserted_spell/I in target)
- I.on_expire(dispelled = 1)
- log_and_message_admins("dispelled [I] on [target].")
+ target.remove_modifiers_of_type(/datum/modifier/technomancer)
user.adjust_instability(10)
qdel(src)
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/gambit.dm b/code/game/gamemodes/technomancer/spells/gambit.dm
index 0541e5473ed..e0116073dc7 100644
--- a/code/game/gamemodes/technomancer/spells/gambit.dm
+++ b/code/game/gamemodes/technomancer/spells/gambit.dm
@@ -1,6 +1,9 @@
/datum/technomancer/spell/gambit
name = "Gambit"
desc = "This function causes you to receive a random function, including those which you haven't purchased."
+// enhancement_desc = "Makes results less random and more biased towards what the function thinks you need in your current situation."
+ enhancement_desc = "Instead of a purely random spell, it will give you a \"random\" spell."
+ spell_power_desc = "Makes certain rare functions possible to acquire via Gambit which cannot be obtained otherwise, if above 100%."
ability_icon_state = "tech_gambit"
cost = 50
obj_path = /obj/item/weapon/spell/gambit
@@ -11,9 +14,10 @@
/obj/item/weapon/spell/gambit,
/obj/item/weapon/spell/projectile,
/obj/item/weapon/spell/aura,
- /obj/item/weapon/spell/insert,
+// /obj/item/weapon/spell/insert,
/obj/item/weapon/spell/spawner,
- /obj/item/weapon/spell/summon)
+ /obj/item/weapon/spell/summon,
+ /obj/item/weapon/spell/modifier)
/obj/item/weapon/spell/gambit
name = "gambit"
@@ -21,12 +25,110 @@
icon_state = "gambit"
cast_methods = CAST_USE
aspect = ASPECT_UNSTABLE
+ var/list/rare_spells = list(
+ /obj/item/weapon/spell/modifier/mend_all
+ )
+
/obj/item/weapon/spell/gambit/on_use_cast(mob/living/carbon/human/user)
if(pay_energy(200))
adjust_instability(3)
- var/obj/item/weapon/spell/random_spell = pick(all_technomancer_gambit_spells)
- if(random_spell)
- user.drop_from_inventory(src, null)
- user.place_spell_in_hand(random_spell)
+ if(check_for_scepter())
+ give_new_spell(biased_random_spell())
+ else
+ give_new_spell(random_spell())
qdel(src)
+
+/obj/item/weapon/spell/gambit/proc/give_new_spell(var/spell_type)
+ owner.drop_from_inventory(src, null)
+ owner.place_spell_in_hand(spell_type)
+
+// Gives a random spell.
+/obj/item/weapon/spell/gambit/proc/random_spell()
+ var/list/potential_spells = all_technomancer_gambit_spells.Copy()
+ var/rare_spell_chance = between(0, calculate_spell_power(100) - 100, 100) // Having 120% spellpower means a 20% chance to get to roll for rare spells.
+ if(prob(rare_spell_chance))
+ potential_spells += rare_spells.Copy()
+ to_chat(owner, "You feel a bit luckier...")
+ return pick(potential_spells)
+
+// Gives a "random" spell.
+/obj/item/weapon/spell/gambit/proc/biased_random_spell()
+ var/list/potential_spells = list()
+ var/rare_spell_chance = between(0, calculate_spell_power(100) - 100, 100)
+ var/give_rare_spells = FALSE
+ if(prob(rare_spell_chance))
+ give_rare_spells = TRUE
+ to_chat(owner, "You feel a bit luckier...")
+
+ // First the spell will concern itself with the health of the technomancer.
+ if(prob(owner.getBruteLoss() + owner.getBruteLoss() * 2)) // Having 20 brute means a 40% chance of being added to the pool.
+ if(!owner.isSynthetic())
+ potential_spells |= /obj/item/weapon/spell/modifier/mend_life
+ else
+ potential_spells |= /obj/item/weapon/spell/modifier/mend_synthetic
+ if(give_rare_spells)
+ potential_spells |= /obj/item/weapon/spell/modifier/mend_all
+
+ // Second, the spell will try to prepare the technomancer for threats.
+ var/hostile_mobs = 0 // Counts how many hostile mobs. Higher numbers make it more likely for AoE spells to be chosen.
+
+ for(var/mob/living/L in view(owner))
+ // Spiders, carp... bears.
+ if(istype(L, /mob/living/simple_animal))
+ var/mob/living/simple_animal/SM = L
+ if(!is_ally(SM) && SM.hostile)
+ hostile_mobs++
+ if(SM.summoned || SM.supernatural) // Our creations might be trying to kill us.
+ potential_spells |= /obj/item/weapon/spell/abjuration
+
+ // Always assume borgs are hostile.
+ if(istype(L, /mob/living/silicon/robot))
+ if(!istype(L, /mob/living/silicon/robot/drone)) // Drones are okay, however.
+ hostile_mobs++
+ potential_spells |= /obj/item/weapon/spell/projectile/ionic_bolt
+
+ // Finally we get to humanoids.
+ if(istype(L, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = L
+ if(is_ally(H)) // Don't get scared by our apprentice.
+ continue
+
+ for(var/obj/item/I in list(H.l_hand, H.r_hand))
+ // Guns are scary.
+ if(istype(I, /obj/item/weapon/gun)) // Toy guns will count as well but oh well.
+ hostile_mobs++
+ continue
+ // Strong melee weapons are scary as well.
+ else if(I.force >= 15)
+ hostile_mobs++
+ continue
+
+ if(hostile_mobs)
+ potential_spells |= /obj/item/weapon/spell/shield
+ potential_spells |= /obj/item/weapon/spell/reflect
+ potential_spells |= /obj/item/weapon/spell/targeting_matrix
+ potential_spells |= /obj/item/weapon/spell/warp_strike
+
+ if(hostile_mobs >= 3) // Lots of baddies, give them AoE.
+ potential_spells |= /obj/item/weapon/spell/projectile/chain_lightning
+ potential_spells |= /obj/item/weapon/spell/projectile/chain_lightning/lesser
+ potential_spells |= /obj/item/weapon/spell/spawner/fire_blast
+ potential_spells |= /obj/item/weapon/spell/condensation
+ potential_spells |= /obj/item/weapon/spell/aura/frost
+ else
+ potential_spells |= /obj/item/weapon/spell/projectile/beam
+ potential_spells |= /obj/item/weapon/spell/projectile/overload
+ potential_spells |= /obj/item/weapon/spell/projectile/force_missile
+ potential_spells |= /obj/item/weapon/spell/projectile/lightning
+
+ // Third priority is recharging the core.
+ if(core.energy / core.max_energy <= 0.5)
+ potential_spells |= /obj/item/weapon/spell/energy_siphon
+ potential_spells |= /obj/item/weapon/spell/instability_tap
+
+ // Fallback method in case nothing gets added.
+ if(!potential_spells.len)
+ potential_spells = all_technomancer_gambit_spells.Copy()
+
+ return pick(potential_spells)
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/illusion.dm b/code/game/gamemodes/technomancer/spells/illusion.dm
index 12f04db48c2..50a9bf5da74 100644
--- a/code/game/gamemodes/technomancer/spells/illusion.dm
+++ b/code/game/gamemodes/technomancer/spells/illusion.dm
@@ -93,6 +93,9 @@
var/walking = 0
var/step_delay = 10
+/mob/living/simple_animal/illusion/update_icon() // We don't want the appearance changing AT ALL unless by copy_appearance().
+ return
+
/mob/living/simple_animal/illusion/proc/copy_appearance(var/atom/movable/thing_to_copy)
if(!thing_to_copy)
return 0
diff --git a/code/game/gamemodes/technomancer/spells/insert/corona.dm b/code/game/gamemodes/technomancer/spells/insert/corona.dm
deleted file mode 100644
index 0ecd700732f..00000000000
--- a/code/game/gamemodes/technomancer/spells/insert/corona.dm
+++ /dev/null
@@ -1,42 +0,0 @@
-/datum/technomancer/spell/corona
- name = "Corona"
- desc = "Causes the victim to glow very brightly, which while harmless in itself, makes it easier for them to be hit. The \
- bright glow also makes it very difficult to be stealthy. The effect lasts for one minute."
- spell_power_desc = "Enemies become even easier to hit."
- cost = 50
- obj_path = /obj/item/weapon/spell/insert/corona
- ability_icon_state = "tech_corona"
- category = SUPPORT_SPELLS
-
-/obj/item/weapon/spell/insert/corona
- name = "corona"
- desc = "How brillient!"
- icon_state = "radiance"
- cast_methods = CAST_RANGED
- aspect = ASPECT_LIGHT
- light_color = "#D9D900"
- spell_light_intensity = 5
- spell_light_range = 3
- inserting = /obj/item/weapon/inserted_spell/corona
-
-
-/obj/item/weapon/inserted_spell/corona
- var/evasion_reduction = 2 // We store this here because spell power may change when the spell expires.
-
-/obj/item/weapon/inserted_spell/corona/on_insert()
- spawn(1)
- if(isliving(host))
- var/mob/living/L = host
- evasion_reduction = round(2 * spell_power_at_creation, 1)
- L.evasion -= evasion_reduction
- L.visible_message("You start to glow very brightly!")
- spawn(1 MINUTE)
- if(src)
- on_expire()
-
-/obj/item/weapon/inserted_spell/corona/on_expire()
- if(isliving(host))
- var/mob/living/L = host
- L.evasion += evasion_reduction
- L << "Your glow has ended."
- ..()
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/insert/haste.dm b/code/game/gamemodes/technomancer/spells/insert/haste.dm
deleted file mode 100644
index 30422cef3f4..00000000000
--- a/code/game/gamemodes/technomancer/spells/insert/haste.dm
+++ /dev/null
@@ -1,36 +0,0 @@
-/datum/technomancer/spell/haste
- name = "Haste"
- desc = "Allows the target to run at speeds that should not be possible for an ordinary being. For five seconds, the target \
- runs extremly fast, and cannot be slowed by any means."
- spell_power_desc = "Duration is scaled up."
- cost = 100
- obj_path = /obj/item/weapon/spell/insert/haste
- ability_icon_state = "tech_haste"
- category = SUPPORT_SPELLS
-
-/obj/item/weapon/spell/insert/haste
- name = "haste"
- desc = "Now you can outrun a Teshari!"
- icon_state = "haste"
- cast_methods = CAST_RANGED
- aspect = ASPECT_FORCE
- light_color = "#FF5C5C"
- inserting = /obj/item/weapon/inserted_spell/haste
-
-/obj/item/weapon/inserted_spell/haste/on_insert()
- spawn(1)
- if(isliving(host))
- var/mob/living/L = host
- L.force_max_speed = 1
- L << "You suddenly find it much easier to move."
- L.adjust_instability(10)
- spawn(round(5 SECONDS * spell_power_at_creation, 1))
- if(src)
- on_expire()
-
-/obj/item/weapon/inserted_spell/haste/on_expire()
- if(isliving(host))
- var/mob/living/L = host
- L.force_max_speed = 0
- L << "You feel slow again."
- ..()
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/insert/mend_burns.dm b/code/game/gamemodes/technomancer/spells/insert/mend_burns.dm
deleted file mode 100644
index 2201787d34a..00000000000
--- a/code/game/gamemodes/technomancer/spells/insert/mend_burns.dm
+++ /dev/null
@@ -1,30 +0,0 @@
-/datum/technomancer/spell/mend_burns
- name = "Mend Burns"
- desc = "Heals minor burns, such as from exposure to flame, electric shock, or lasers."
- spell_power_desc = "Healing amount increased."
- cost = 50
- obj_path = /obj/item/weapon/spell/insert/mend_burns
- ability_icon_state = "tech_mendburns"
- category = SUPPORT_SPELLS
-
-/obj/item/weapon/spell/insert/mend_burns
- name = "mend burns"
- desc = "Ointment is a thing of the past."
- icon_state = "mend_burns"
- cast_methods = CAST_MELEE
- aspect = ASPECT_BIOMED
- light_color = "#FF5C5C"
- inserting = /obj/item/weapon/inserted_spell/mend_burns
-
-/obj/item/weapon/inserted_spell/mend_burns/on_insert()
- spawn(1)
- if(ishuman(host))
- var/mob/living/carbon/human/H = host
- var/heal_power = host == origin ? 10 : 30
- heal_power = round(heal_power * spell_power_at_creation, 1)
- origin.adjust_instability(10)
- for(var/i = 0, i<5,i++)
- if(H)
- H.adjustFireLoss(-heal_power / 5)
- sleep(1 SECOND)
- on_expire()
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/insert/mend_metal.dm b/code/game/gamemodes/technomancer/spells/insert/mend_metal.dm
deleted file mode 100644
index 376ab8df1ce..00000000000
--- a/code/game/gamemodes/technomancer/spells/insert/mend_metal.dm
+++ /dev/null
@@ -1,33 +0,0 @@
-/datum/technomancer/spell/mend_metal
- name = "Mend Metal"
- desc = "Restores integrity to external robotic components."
- spell_power_desc = "Healing amount increased."
- cost = 50
- obj_path = /obj/item/weapon/spell/insert/mend_metal
- ability_icon_state = "tech_mendwounds"
- category = SUPPORT_SPELLS
-
-/obj/item/weapon/spell/insert/mend_metal
- name = "mend metal"
- desc = "A roboticist is now obsolete."
- icon_state = "mend_wounds"
- cast_methods = CAST_MELEE
- aspect = ASPECT_BIOMED
- light_color = "#FF5C5C"
- inserting = /obj/item/weapon/inserted_spell/mend_metal
-
-/obj/item/weapon/inserted_spell/mend_metal/on_insert()
- spawn(1)
- if(ishuman(host))
- var/mob/living/carbon/human/H = host
- var/heal_power = host == origin ? 10 : 30
- heal_power = round(heal_power * spell_power_at_creation, 1)
- origin.adjust_instability(10)
- for(var/i = 0, i<5,i++)
- if(H)
- for(var/obj/item/organ/external/O in H.organs)
- if(O.robotic < ORGAN_ROBOT) // Robot parts only.
- continue
- O.heal_damage(heal_power / 5, 0, internal = 1, robo_repair = 1)
- sleep(1 SECOND)
- on_expire()
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/insert/mend_organs.dm b/code/game/gamemodes/technomancer/spells/insert/mend_organs.dm
deleted file mode 100644
index 4ac29658edb..00000000000
--- a/code/game/gamemodes/technomancer/spells/insert/mend_organs.dm
+++ /dev/null
@@ -1,56 +0,0 @@
-/datum/technomancer/spell/mend_organs
- name = "Great Mend Wounds"
- desc = "Greatly heals the target's wounds, both external and internal. Restores internal organs to functioning states, even if \
- robotic, reforms bones, patches internal bleeding, and restores missing blood."
- spell_power_desc = "Healing amount increased."
- cost = 100
- obj_path = /obj/item/weapon/spell/insert/mend_organs
- ability_icon_state = "tech_mendwounds"
- category = SUPPORT_SPELLS
-
-/obj/item/weapon/spell/insert/mend_organs
- name = "great mend wounds"
- desc = "A walking medbay is now you!"
- icon_state = "mend_wounds"
- cast_methods = CAST_MELEE
- aspect = ASPECT_BIOMED
- light_color = "#FF5C5C"
- inserting = /obj/item/weapon/inserted_spell/mend_organs
-
-/obj/item/weapon/inserted_spell/mend_organs/on_insert()
- spawn(1)
- if(ishuman(host))
- var/mob/living/carbon/human/H = host
- var/heal_power = host == origin ? 2 : 5
- heal_power = round(heal_power * spell_power_at_creation, 1)
- origin.adjust_instability(15)
-
- for(var/i = 0, i<5,i++)
- if(H)
- for(var/obj/item/organ/O in H.internal_organs)
- if(O.damage > 0) // Fix internal damage
- O.damage = max(O.damage - (heal_power / 5), 0)
- if(O.damage <= 5 && O.organ_tag == O_EYES) // Fix eyes
- H.sdisabilities &= ~BLIND
-
- for(var/obj/item/organ/external/O in H.organs) // Fix limbs
- if(!O.robotic < ORGAN_ROBOT) // No robot parts for this.
- continue
- O.heal_damage(0, heal_power / 5, internal = 1, robo_repair = 0)
-
- for(var/obj/item/organ/E in H.bad_external_organs) // Fix bones
- var/obj/item/organ/external/affected = E
- if((affected.damage < affected.min_broken_damage * config.organ_health_multiplier) && (affected.status & ORGAN_BROKEN))
- affected.status &= ~ORGAN_BROKEN
-
- for(var/datum/wound/W in affected.wounds) // Fix IB
- if(istype(W, /datum/wound/internal_bleeding))
- affected.wounds -= W
- affected.update_damages()
-
- H.restore_blood() // Fix bloodloss
-
- H.adjustBruteLoss(-heal_power)
-
- sleep(1 SECOND)
- on_expire()
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/insert/mend_wires.dm b/code/game/gamemodes/technomancer/spells/insert/mend_wires.dm
deleted file mode 100644
index aad59dc7c41..00000000000
--- a/code/game/gamemodes/technomancer/spells/insert/mend_wires.dm
+++ /dev/null
@@ -1,33 +0,0 @@
-/datum/technomancer/spell/mend_wires
- name = "Mend Wires"
- desc = "Binds the internal wiring of robotic limbs and components over time."
- spell_power_desc = "Healing amount increased."
- cost = 50
- obj_path = /obj/item/weapon/spell/insert/mend_wires
- ability_icon_state = "tech_mendwounds"
- category = SUPPORT_SPELLS
-
-/obj/item/weapon/spell/insert/mend_wires
- name = "mend wires"
- desc = "A roboticist is now obsolete."
- icon_state = "mend_wounds"
- cast_methods = CAST_MELEE
- aspect = ASPECT_BIOMED
- light_color = "#FF5C5C"
- inserting = /obj/item/weapon/inserted_spell/mend_wires
-
-/obj/item/weapon/inserted_spell/mend_wires/on_insert()
- spawn(1)
- if(ishuman(host))
- var/mob/living/carbon/human/H = host
- var/heal_power = host == origin ? 10 : 30
- heal_power = round(heal_power * spell_power_at_creation, 1)
- origin.adjust_instability(10)
- for(var/i = 0, i<5,i++)
- if(H)
- for(var/obj/item/organ/external/O in H.organs)
- if(O.robotic < ORGAN_ROBOT) // Robot parts only.
- continue
- O.heal_damage(0, heal_power / 5, internal = 1, robo_repair = 1)
- sleep(1 SECOND)
- on_expire()
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/insert/mend_wounds.dm b/code/game/gamemodes/technomancer/spells/insert/mend_wounds.dm
deleted file mode 100644
index 38f5b5dc55b..00000000000
--- a/code/game/gamemodes/technomancer/spells/insert/mend_wounds.dm
+++ /dev/null
@@ -1,31 +0,0 @@
-/datum/technomancer/spell/mend_wounds
- name = "Mend Wounds"
- desc = "Heals minor wounds, such as cuts, bruises, and other non-lifethreatening injuries. \
- Instability is split between the target and technomancer, if seperate."
- spell_power_desc = "Healing amount increased."
- cost = 50
- obj_path = /obj/item/weapon/spell/insert/mend_wounds
- ability_icon_state = "tech_mendwounds"
- category = SUPPORT_SPELLS
-
-/obj/item/weapon/spell/insert/mend_wounds
- name = "mend wounds"
- desc = "Watch your wounds close up before your eyes."
- icon_state = "mend_wounds"
- cast_methods = CAST_MELEE
- aspect = ASPECT_BIOMED
- light_color = "#FF5C5C"
- inserting = /obj/item/weapon/inserted_spell/mend_wounds
-
-/obj/item/weapon/inserted_spell/mend_wounds/on_insert()
- spawn(1)
- if(ishuman(host))
- var/mob/living/carbon/human/H = host
- var/heal_power = host == origin ? 10 : 30
- heal_power = round(heal_power * spell_power_at_creation, 1)
- origin.adjust_instability(10)
- for(var/i = 0, i<5,i++)
- if(H)
- H.adjustBruteLoss(-heal_power / 5)
- sleep(1 SECOND)
- on_expire()
diff --git a/code/game/gamemodes/technomancer/spells/insert/purify.dm b/code/game/gamemodes/technomancer/spells/insert/purify.dm
deleted file mode 100644
index 6ba36d44c66..00000000000
--- a/code/game/gamemodes/technomancer/spells/insert/purify.dm
+++ /dev/null
@@ -1,49 +0,0 @@
-/datum/technomancer/spell/purify
- name = "Purify"
- desc = "Clenses the body of harmful impurities, such as toxins, radiation, viruses, genetic damage, and such."
- spell_power_desc = "Healing amount increased."
- cost = 25
- obj_path = /obj/item/weapon/spell/insert/purify
- ability_icon_state = "tech_purify"
- category = SUPPORT_SPELLS
-
-/obj/item/weapon/spell/insert/purify
- name = "purify"
- desc = "Illness and toxins will be no more."
- icon_state = "purify"
- cast_methods = CAST_MELEE
- aspect = ASPECT_BIOMED
- light_color = "#03A728"
- inserting = /obj/item/weapon/inserted_spell/purify
-
-/obj/item/weapon/inserted_spell/purify/on_insert()
- spawn(1)
- if(ishuman(host))
- var/mob/living/carbon/human/H = host
- H.sdisabilities = 0
- H.disabilities = 0
-// for(var/datum/disease/D in H.viruses)
-// D.cure()
- var/heal_power = host == origin ? 10 : 30
- heal_power = round(heal_power * spell_power_at_creation, 1)
- origin.adjust_instability(10)
- for(var/i = 0, i<5,i++)
- if(H)
- H.adjustToxLoss(-heal_power / 5)
- H.adjustCloneLoss(-heal_power / 5)
- H.radiation = max(host.radiation - ( (heal_power * 2) / 5), 0)
-
- for(var/obj/item/organ/external/E in H.organs)
- var/obj/item/organ/external/G = E
- if(G.germ_level)
- var/germ_heal = heal_power * 10
- G.germ_level = min(0, G.germ_level - germ_heal)
-
- for(var/obj/item/organ/internal/I in H.internal_organs)
- var/obj/item/organ/internal/G = I
- if(G.germ_level)
- var/germ_heal = heal_power * 10
- G.germ_level = min(0, G.germ_level - germ_heal)
-
- sleep(1 SECOND)
- on_expire()
diff --git a/code/game/gamemodes/technomancer/spells/insert/repel_missiles.dm b/code/game/gamemodes/technomancer/spells/insert/repel_missiles.dm
deleted file mode 100644
index 38e4ef47205..00000000000
--- a/code/game/gamemodes/technomancer/spells/insert/repel_missiles.dm
+++ /dev/null
@@ -1,39 +0,0 @@
-/datum/technomancer/spell/repel_missiles
- name = "Repel Missiles"
- desc = "Places a repulsion field around you, which attempts to deflect incoming bullets and lasers, making them 30% less likely \
- to hit you. The field lasts for five minutes and can be granted to yourself or an ally."
- spell_power_desc = "Projectiles will be more likely to be deflected."
- cost = 25
- obj_path = /obj/item/weapon/spell/insert/repel_missiles
- ability_icon_state = "tech_repelmissiles"
- category = SUPPORT_SPELLS
-
-/obj/item/weapon/spell/insert/repel_missiles
- name = "repel missiles"
- desc = "Use it before they start shooting at you!"
- icon_state = "generic"
- cast_methods = CAST_RANGED
- aspect = ASPECT_FORCE
- light_color = "#FF5C5C"
- inserting = /obj/item/weapon/inserted_spell/repel_missiles
-
-/obj/item/weapon/inserted_spell/repel_missiles
- var/evasion_increased = 2 // We store this here because spell power may change when the spell expires.
-
-/obj/item/weapon/inserted_spell/repel_missiles/on_insert()
- spawn(1)
- if(isliving(host))
- var/mob/living/L = host
- evasion_increased = round(2 * spell_power_at_creation, 1)
- L.evasion += evasion_increased
- L << "You have a repulsion field around you, which will attempt to deflect projectiles."
- spawn(5 MINUTES)
- if(src)
- on_expire()
-
-/obj/item/weapon/inserted_spell/repel_missiles/on_expire()
- if(isliving(host))
- var/mob/living/L = host
- L.evasion -= evasion_increased
- L << "Your repulsion field has expired."
- ..()
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/instability_tap.dm b/code/game/gamemodes/technomancer/spells/instability_tap.dm
index 9092039165b..13a2b5e318b 100644
--- a/code/game/gamemodes/technomancer/spells/instability_tap.dm
+++ b/code/game/gamemodes/technomancer/spells/instability_tap.dm
@@ -1,8 +1,8 @@
/datum/technomancer/spell/instability_tap
name = "Instability Tap"
- desc = "Creates a large sum of energy, at the cost of a very large amount of instability afflicting you."
+ desc = "Creates a large sum of energy (5,000 at normal spell power), at the cost of a very large amount of instability afflicting you."
enhancement_desc = "50% more energy gained, 20% less instability gained."
- spell_power_desc = "Amount of energy gained scaled up with spell power."
+ spell_power_desc = "Amount of energy gained scaled with spell power."
cost = 100
obj_path = /obj/item/weapon/spell/instability_tap
ability_icon_state = "tech_instabilitytap"
@@ -26,4 +26,5 @@
else
core.give_energy(amount)
adjust_instability(50)
+ playsound(get_turf(src), 'sound/effects/supermatter.ogg', 75, 1)
qdel(src)
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/mend_organs.dm b/code/game/gamemodes/technomancer/spells/mend_organs.dm
new file mode 100644
index 00000000000..16c212f084d
--- /dev/null
+++ b/code/game/gamemodes/technomancer/spells/mend_organs.dm
@@ -0,0 +1,56 @@
+/datum/technomancer/spell/mend_organs
+ name = "Mend Internals"
+ desc = "Greatly heals the target's wounds, both external and internal. Restores internal organs to functioning states, even if \
+ robotic, reforms bones, patches internal bleeding, and restores missing blood."
+ spell_power_desc = "Healing amount increased."
+ cost = 100
+ obj_path = /obj/item/weapon/spell/mend_organs
+ ability_icon_state = "tech_mendwounds"
+ category = SUPPORT_SPELLS
+
+/obj/item/weapon/spell/mend_organs
+ name = "great mend wounds"
+ desc = "A walking medbay is now you!"
+ icon_state = "mend_wounds"
+ cast_methods = CAST_MELEE
+ aspect = ASPECT_BIOMED
+ light_color = "#FF5C5C"
+
+/obj/item/weapon/spell/mend_organs/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
+ if(isliving(hit_atom))
+ var/mob/living/L = hit_atom
+ var/heal_power = calculate_spell_power(40)
+ L.adjustBruteLoss(-heal_power)
+ L.adjustFireLoss(-heal_power)
+ user.adjust_instability(5)
+ L.adjust_instability(5)
+
+ if(ishuman(hit_atom))
+ var/mob/living/carbon/human/H = hit_atom
+
+ user.adjust_instability(5)
+ L.adjust_instability(5)
+
+ for(var/obj/item/organ/O in H.internal_organs)
+ if(O.damage > 0) // Fix internal damage
+ O.damage = max(O.damage - (heal_power / 2), 0)
+ if(O.damage <= 5 && O.organ_tag == O_EYES) // Fix eyes
+ H.sdisabilities &= ~BLIND
+
+ for(var/obj/item/organ/external/O in H.organs) // Fix limbs
+ if(!O.robotic < ORGAN_ROBOT) // No robot parts for this.
+ continue
+ O.heal_damage(0, heal_power / 4, internal = 1, robo_repair = 0)
+
+ for(var/obj/item/organ/E in H.bad_external_organs) // Fix bones
+ var/obj/item/organ/external/affected = E
+ if((affected.damage < affected.min_broken_damage * config.organ_health_multiplier) && (affected.status & ORGAN_BROKEN))
+ affected.status &= ~ORGAN_BROKEN
+
+ for(var/datum/wound/W in affected.wounds) // Fix IB
+ if(istype(W, /datum/wound/internal_bleeding))
+ affected.wounds -= W
+ affected.update_damages()
+
+ H.restore_blood() // Fix bloodloss
+ qdel(src)
diff --git a/code/game/gamemodes/technomancer/spells/modifier/corona.dm b/code/game/gamemodes/technomancer/spells/modifier/corona.dm
new file mode 100644
index 00000000000..74a06855d9f
--- /dev/null
+++ b/code/game/gamemodes/technomancer/spells/modifier/corona.dm
@@ -0,0 +1,33 @@
+/datum/technomancer/spell/corona
+ name = "Corona"
+ desc = "Causes the victim to glow very brightly, which while harmless in itself, makes it easier for them to be hit. The \
+ bright glow also makes it very difficult to be stealthy. The effect lasts for one minute."
+ cost = 50
+ obj_path = /obj/item/weapon/spell/modifier/corona
+ ability_icon_state = "tech_corona"
+ category = SUPPORT_SPELLS
+
+/obj/item/weapon/spell/modifier/corona
+ name = "corona"
+ desc = "How brillient!"
+ icon_state = "radiance"
+ cast_methods = CAST_RANGED
+ aspect = ASPECT_LIGHT
+ light_color = "#D9D900"
+ spell_light_intensity = 5
+ spell_light_range = 3
+ modifier_type = /datum/modifier/technomancer/corona
+ modifier_duration = 1 MINUTE
+
+/datum/modifier/technomancer/corona
+ name = "corona"
+ desc = "You appear to be glowing really bright. It doesn't seem to hurt, however hiding will be impossible."
+ mob_overlay_state = "corona"
+
+ on_created_text = "You start to glow very brightly!"
+ on_expired_text = "Your glow has ended."
+ evasion = -2
+ stacks = MODIFIER_STACK_EXTEND
+
+/datum/modifier/technomancer/corona/tick()
+ holder.break_cloak()
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/modifier/haste.dm b/code/game/gamemodes/technomancer/spells/modifier/haste.dm
new file mode 100644
index 00000000000..7f7c1045b36
--- /dev/null
+++ b/code/game/gamemodes/technomancer/spells/modifier/haste.dm
@@ -0,0 +1,28 @@
+/datum/technomancer/spell/haste
+ name = "Haste"
+ desc = "Allows the target to run at speeds that should not be possible for an ordinary being. For five seconds, the target \
+ runs extremly fast, and cannot be slowed by any means."
+ cost = 100
+ obj_path = /obj/item/weapon/spell/modifier/haste
+ ability_icon_state = "tech_haste"
+ category = SUPPORT_SPELLS
+
+/obj/item/weapon/spell/modifier/haste
+ name = "haste"
+ desc = "Now you can outrun a Teshari!"
+ icon_state = "haste"
+ cast_methods = CAST_RANGED
+ aspect = ASPECT_FORCE
+ light_color = "#FF5C5C"
+ modifier_type = /datum/modifier/technomancer/haste
+ modifier_duration = 5 SECONDS
+
+/datum/modifier/technomancer/haste
+ name = "haste"
+ desc = "Moving is almost effortless!"
+ mob_overlay_state = "haste"
+
+ on_created_text = "You suddenly find it much easier to move."
+ on_expired_text = "You feel slow again."
+ haste = TRUE
+ stacks = MODIFIER_STACK_EXTEND
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/modifier/mend_all.dm b/code/game/gamemodes/technomancer/spells/modifier/mend_all.dm
new file mode 100644
index 00000000000..1da3554573e
--- /dev/null
+++ b/code/game/gamemodes/technomancer/spells/modifier/mend_all.dm
@@ -0,0 +1,35 @@
+// Gambit only spell. Heals everything unconditionally.
+
+/obj/item/weapon/spell/modifier/mend_all
+ name = "mend all"
+ desc = "One function to heal them all."
+ icon_state = "mend_all"
+ cast_methods = CAST_MELEE
+ aspect = ASPECT_BIOMED
+ light_color = "#FF5C5C"
+ modifier_type = /datum/modifier/technomancer/mend_life
+ modifier_duration = 1 MINUTE
+
+/datum/modifier/technomancer/mend_all
+ name = "mend all"
+ desc = "You feel serene and well rested."
+ mob_overlay_state = "green_sparkles"
+
+ on_created_text = "Sparkles begin to appear around you, and all your ills seem to fade away."
+ on_expired_text = "The sparkles have faded, although you feel much healthier than before."
+ stacks = MODIFIER_STACK_EXTEND
+
+/datum/modifier/technomancer/mend_all/tick()
+ if(!holder.getBruteLoss() && !holder.getFireLoss() && !holder.getToxLoss() && !holder.getOxyLoss() && !holder.getCloneLoss()) // No point existing if the spell can't heal.
+ expire()
+ return
+ holder.adjustBruteLoss(-4 * spell_power) // Should heal roughly 120 damage over 1 minute, as tick() is run every 2 seconds.
+ holder.adjustFireLoss(-4 * spell_power)
+ holder.adjustToxLoss(-4 * spell_power)
+ holder.adjustOxyLoss(-4 * spell_power)
+ holder.adjustCloneLoss(-2 * spell_power) // 60 cloneloss
+ holder.adjust_instability(1)
+ if(origin)
+ var/mob/living/L = origin.resolve()
+ if(istype(L))
+ L.adjust_instability(1)
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/modifier/mend_life.dm b/code/game/gamemodes/technomancer/spells/modifier/mend_life.dm
new file mode 100644
index 00000000000..a766767b181
--- /dev/null
+++ b/code/game/gamemodes/technomancer/spells/modifier/mend_life.dm
@@ -0,0 +1,44 @@
+/datum/technomancer/spell/mend_life
+ name = "Mend Life"
+ desc = "Heals minor wounds, such as cuts, bruises, burns, and other non-lifethreatening injuries. \
+ Instability is split between the target and technomancer, if seperate. The function will end prematurely \
+ if the target is completely healthy, preventing further instability."
+ spell_power_desc = "Healing amount increased."
+ cost = 50
+ obj_path = /obj/item/weapon/spell/modifier/mend_life
+ ability_icon_state = "tech_mendwounds"
+ category = SUPPORT_SPELLS
+
+/obj/item/weapon/spell/modifier/mend_life
+ name = "mend life"
+ desc = "Watch your wounds close up before your eyes."
+ icon_state = "mend_life"
+ cast_methods = CAST_MELEE
+ aspect = ASPECT_BIOMED
+ light_color = "#FF5C5C"
+ modifier_type = /datum/modifier/technomancer/mend_life
+ modifier_duration = 10 SECONDS
+
+/datum/modifier/technomancer/mend_life
+ name = "mend life"
+ desc = "You feel rather refreshed."
+ mob_overlay_state = "green_sparkles"
+
+ on_created_text = "Sparkles begin to appear around you, and you feel really.. refreshed."
+ on_expired_text = "The sparkles have faded, although you feel healthier than before."
+ stacks = MODIFIER_STACK_EXTEND
+
+/datum/modifier/technomancer/mend_life/tick()
+ if(holder.isSynthetic()) // Don't heal synths!
+ expire()
+ return
+ if(!holder.getBruteLoss() && !holder.getFireLoss()) // No point existing if the spell can't heal.
+ expire()
+ return
+ holder.adjustBruteLoss(-4 * spell_power) // Should heal roughly 20 burn/brute over 10 seconds, as tick() is run every 2 seconds.
+ holder.adjustFireLoss(-4 * spell_power) // Ditto.
+ holder.adjust_instability(1)
+ if(origin)
+ var/mob/living/L = origin.resolve()
+ if(istype(L))
+ L.adjust_instability(1)
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/modifier/mend_synthetic.dm b/code/game/gamemodes/technomancer/spells/modifier/mend_synthetic.dm
new file mode 100644
index 00000000000..d91530b0c93
--- /dev/null
+++ b/code/game/gamemodes/technomancer/spells/modifier/mend_synthetic.dm
@@ -0,0 +1,44 @@
+/datum/technomancer/spell/mend_synthetic
+ name = "Mend Synthetic"
+ desc = "Repairs minor damages to robotic entities. \
+ Instability is split between the target and technomancer, if seperate. The function will end prematurely \
+ if the target is completely healthy, preventing further instability."
+ spell_power_desc = "Healing amount increased."
+ cost = 50
+ obj_path = /obj/item/weapon/spell/modifier/mend_synthetic
+ ability_icon_state = "tech_mendwounds"
+ category = SUPPORT_SPELLS
+
+/obj/item/weapon/spell/modifier/mend_synthetic
+ name = "mend synthetic"
+ desc = "You are the Robotics lab"
+ icon_state = "mend_synthetic"
+ cast_methods = CAST_MELEE
+ aspect = ASPECT_BIOMED // sorta??
+ light_color = "#FF5C5C"
+ modifier_type = /datum/modifier/technomancer/mend_synthetic
+ modifier_duration = 10 SECONDS
+
+/datum/modifier/technomancer/mend_synthetic
+ name = "mend synthetic"
+ desc = "Something seems to be repairing you."
+ mob_overlay_state = "cyan_sparkles"
+
+ on_created_text = "Sparkles begin to appear around you, and your systems report integrity rising."
+ on_expired_text = "The sparkles have faded, although your systems seem to be better than before."
+ stacks = MODIFIER_STACK_EXTEND
+
+/datum/modifier/technomancer/mend_synthetic/tick()
+ if(!holder.isSynthetic()) // Don't heal biologicals!
+ expire()
+ return
+ if(!holder.getBruteLoss() && !holder.getFireLoss()) // No point existing if the spell can't heal.
+ expire()
+ return
+ holder.adjustBruteLoss(-4 * spell_power) // Should heal roughly 20 burn/brute over 10 seconds, as tick() is run every 2 seconds.
+ holder.adjustFireLoss(-4 * spell_power) // Ditto.
+ holder.adjust_instability(1)
+ if(origin)
+ var/mob/living/L = origin.resolve()
+ if(istype(L))
+ L.adjust_instability(1)
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/modifier/modifier.dm b/code/game/gamemodes/technomancer/spells/modifier/modifier.dm
new file mode 100644
index 00000000000..a8b93069456
--- /dev/null
+++ b/code/game/gamemodes/technomancer/spells/modifier/modifier.dm
@@ -0,0 +1,38 @@
+/obj/item/weapon/spell/modifier
+ name = "modifier template"
+ desc = "Tell a coder if you can read this in-game."
+ icon_state = "purify"
+ cast_methods = CAST_MELEE
+ var/modifier_type = null
+ var/modifier_duration = null // Will last forever by default. Final duration may differ due to 'spell power'
+// var/spell_color = "#03A728"
+ var/spell_light_intensity = 2
+ var/spell_light_range = 3
+
+/obj/item/weapon/spell/modifier/New()
+ ..()
+ set_light(spell_light_range, spell_light_intensity, l_color = light_color)
+
+/obj/item/weapon/spell/modifier/on_melee_cast(atom/hit_atom, mob/user)
+ if(istype(hit_atom, /mob/living))
+ on_add_modifier(hit_atom)
+
+/obj/item/weapon/spell/modifier/on_ranged_cast(atom/hit_atom, mob/user)
+ if(istype(hit_atom, /mob/living))
+ on_add_modifier(hit_atom)
+
+
+/obj/item/weapon/spell/modifier/proc/on_add_modifier(var/mob/living/L)
+ var/duration = modifier_duration
+ if(duration)
+ duration = round(duration * calculate_spell_power(1.0), 1)
+ var/datum/modifier/M = L.add_modifier(modifier_type, duration, owner)
+ if(istype(M, /datum/modifier/technomancer))
+ var/datum/modifier/technomancer/MT = M
+ MT.spell_power = calculate_spell_power(1)
+ log_and_message_admins("has casted [src] on [L].")
+ qdel(src)
+
+// Technomancer specific subtype which keeps track of spell power and gets targeted specificially by Dispel.
+/datum/modifier/technomancer
+ var/spell_power = null // Set by on_add_modifier.
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/modifier/purify.dm b/code/game/gamemodes/technomancer/spells/modifier/purify.dm
new file mode 100644
index 00000000000..ae90a04cb1b
--- /dev/null
+++ b/code/game/gamemodes/technomancer/spells/modifier/purify.dm
@@ -0,0 +1,40 @@
+/datum/technomancer/spell/purify
+ name = "Purify"
+ desc = "Clenses the body of harmful impurities, such as toxins, radiation, viruses, genetic damage, and such. \
+ Instability is split between the target and technomancer, if seperate. The function will end prematurely \
+ if the target is completely healthy, preventing further instability."
+ spell_power_desc = "Healing amount increased."
+ cost = 25
+ obj_path = /obj/item/weapon/spell/modifier/purify
+ ability_icon_state = "tech_purify"
+ category = SUPPORT_SPELLS
+
+/obj/item/weapon/spell/modifier/purify
+ name = "mend life"
+ desc = "Watch your wounds close up before your eyes."
+ icon_state = "mend_life"
+ cast_methods = CAST_MELEE
+ aspect = ASPECT_BIOMED
+ light_color = "#FF5C5C"
+ modifier_type = /datum/modifier/technomancer/purify
+ modifier_duration = 10 SECONDS
+
+/datum/modifier/technomancer/purify
+ name = "purify"
+ desc = "You feel rather clean and pure."
+ mob_overlay_state = "green_sparkles"
+
+ on_created_text = "Sparkles begin to appear around you, and you feel really.. pure."
+ on_expired_text = "The sparkles have faded, although you feel healthier than before."
+ stacks = MODIFIER_STACK_EXTEND
+
+/datum/modifier/technomancer/purify/tick()
+ if(!holder.getToxLoss()) // No point existing if the spell can't heal.
+ expire()
+ return
+ holder.adjustToxLoss(-4 * spell_power) // Should heal roughly 120 damage over 1 minute, as tick() is run every 2 seconds.
+ holder.adjust_instability(1)
+ if(origin)
+ var/mob/living/L = origin.resolve()
+ if(istype(L))
+ L.adjust_instability(1)
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/modifier/repel_missiles.dm b/code/game/gamemodes/technomancer/spells/modifier/repel_missiles.dm
new file mode 100644
index 00000000000..6ead04f30cc
--- /dev/null
+++ b/code/game/gamemodes/technomancer/spells/modifier/repel_missiles.dm
@@ -0,0 +1,28 @@
+/datum/technomancer/spell/repel_missiles
+ name = "Repel Missiles"
+ desc = "Places a repulsion field around you, which attempts to deflect incoming bullets and lasers, making them 45% less likely \
+ to hit you. The field lasts for 10 minutes and can be granted to yourself or an ally."
+ cost = 25
+ obj_path = /obj/item/weapon/spell/modifier/repel_missiles
+ ability_icon_state = "tech_repelmissiles"
+ category = SUPPORT_SPELLS
+
+/obj/item/weapon/spell/modifier/repel_missiles
+ name = "repel missiles"
+ desc = "Use it before they start shooting at you!"
+ icon_state = "generic"
+ cast_methods = CAST_RANGED
+ aspect = ASPECT_FORCE
+ light_color = "#FF5C5C"
+ modifier_type = /datum/modifier/technomancer/repel_missiles
+ modifier_duration = 10 MINUTES
+
+/datum/modifier/technomancer/repel_missiles
+ name = "repel_missiles"
+ desc = "A repulsion field can always be useful to have."
+ mob_overlay_state = "repel_missiles"
+
+ on_created_text = "You have a repulsion field around you, which will attempt to deflect projectiles."
+ on_expired_text = "Your repulsion field has expired."
+ evasion = 3
+ stacks = MODIFIER_STACK_EXTEND
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/oxygenate.dm b/code/game/gamemodes/technomancer/spells/oxygenate.dm
index b121e6f4d4b..fcc2cbcecf8 100644
--- a/code/game/gamemodes/technomancer/spells/oxygenate.dm
+++ b/code/game/gamemodes/technomancer/spells/oxygenate.dm
@@ -2,7 +2,7 @@
name = "Oxygenate"
desc = "This function creates oxygen at a location of your chosing. If used on a humanoid entity, it heals oxygen deprivation. \
If casted on the envirnment, air (oxygen and nitrogen) is moved from a distant location to your target."
- cost = 50
+ cost = 25
obj_path = /obj/item/weapon/spell/oxygenate
ability_icon_state = "oxygenate"
category = SUPPORT_SPELLS
diff --git a/code/game/gamemodes/technomancer/spells/passwall.dm b/code/game/gamemodes/technomancer/spells/passwall.dm
index aa16a8a4fc6..e786134b4c0 100644
--- a/code/game/gamemodes/technomancer/spells/passwall.dm
+++ b/code/game/gamemodes/technomancer/spells/passwall.dm
@@ -39,7 +39,7 @@
visible_message("[user] rests a hand on \the [hit_atom].")
busy = 1
- var/datum/effect/effect/system/spark_spread/spark_system = PoolOrNew(/datum/effect/effect/system/spark_spread)
+ var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread()
spark_system.set_up(5, 0, our_turf)
while(i)
diff --git a/code/game/gamemodes/technomancer/spells/projectile/chain_lightning.dm b/code/game/gamemodes/technomancer/spells/projectile/chain_lightning.dm
index acb00a2c7f8..5614d04a888 100644
--- a/code/game/gamemodes/technomancer/spells/projectile/chain_lightning.dm
+++ b/code/game/gamemodes/technomancer/spells/projectile/chain_lightning.dm
@@ -32,7 +32,7 @@
var/bounces = 3 //How many times it 'chains'. Note that the first hit is not counted as it counts /bounces/.
var/list/hit_mobs = list() //Mobs which were already hit.
- var/power = 20 //How hard it will hit for with electrocute_act(), decreases with each bounce.
+ var/power = 35 //How hard it will hit for with electrocute_act(), decreases with each bounce.
/obj/item/projectile/beam/chain_lightning/attack_mob(var/mob/living/target_mob, var/distance, var/miss_modifier=0)
//First we shock the guy we just hit.
diff --git a/code/game/gamemodes/technomancer/spells/projectile/ionic_bolt.dm b/code/game/gamemodes/technomancer/spells/projectile/ionic_bolt.dm
index 68070d15c1e..d6665b2ee0d 100644
--- a/code/game/gamemodes/technomancer/spells/projectile/ionic_bolt.dm
+++ b/code/game/gamemodes/technomancer/spells/projectile/ionic_bolt.dm
@@ -2,7 +2,7 @@
name = "Ionic Bolt"
desc = "Shoots a bolt of ion energy at the target. If it hits something, it will generally drain energy, corrupt electronics, \
or otherwise ruin complex machinery."
- cost = 100
+ cost = 50
obj_path = /obj/item/weapon/spell/projectile/ionic_bolt
category = OFFENSIVE_SPELLS
diff --git a/code/game/gamemodes/technomancer/spells/projectile/lesser_chain_lightning.dm b/code/game/gamemodes/technomancer/spells/projectile/lesser_chain_lightning.dm
new file mode 100644
index 00000000000..85881fefb07
--- /dev/null
+++ b/code/game/gamemodes/technomancer/spells/projectile/lesser_chain_lightning.dm
@@ -0,0 +1,23 @@
+/datum/technomancer/spell/lesser_chain_lightning
+ name = "Lesser Chain Lightning"
+ desc = "This is very similar to the function Chain Lightning, however it is considerably less powerful. As a result, it's a lot \
+ more economical in terms of energy cost, as well as instability generation. Lightning functions cannot miss due to distance."
+ cost = 100
+ obj_path = /obj/item/weapon/spell/projectile/chain_lightning/lesser
+ ability_icon_state = "tech_chain_lightning"
+ category = OFFENSIVE_SPELLS
+
+/obj/item/weapon/spell/projectile/chain_lightning/lesser
+ name = "lesser chain lightning"
+ icon_state = "chain_lightning"
+ desc = "Now you can throw around lightning like it's nobody's business."
+ cast_methods = CAST_RANGED
+ aspect = ASPECT_SHOCK
+ spell_projectile = /obj/item/projectile/beam/chain_lightning
+ energy_cost_per_shot = 1000
+ instability_per_shot = 5
+ cooldown = 10
+
+/obj/item/projectile/beam/chain_lightning/lesser
+ bounces = 2
+ power = 20
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/reflect.dm b/code/game/gamemodes/technomancer/spells/reflect.dm
index d841db2accc..60abcee63fa 100644
--- a/code/game/gamemodes/technomancer/spells/reflect.dm
+++ b/code/game/gamemodes/technomancer/spells/reflect.dm
@@ -19,7 +19,7 @@
/obj/item/weapon/spell/reflect/New()
..()
set_light(3, 2, l_color = "#006AFF")
- spark_system = PoolOrNew(/datum/effect/effect/system/spark_spread)
+ spark_system = new /datum/effect/effect/system/spark_spread()
spark_system.set_up(5, 0, src)
owner << "Your shield will expire in 3 seconds!"
spawn(5 SECONDS)
diff --git a/code/game/gamemodes/technomancer/spells/shield.dm b/code/game/gamemodes/technomancer/spells/shield.dm
index a9514aaa29f..4ea507e9596 100644
--- a/code/game/gamemodes/technomancer/spells/shield.dm
+++ b/code/game/gamemodes/technomancer/spells/shield.dm
@@ -21,7 +21,7 @@
/obj/item/weapon/spell/shield/New()
..()
set_light(3, 2, l_color = "#006AFF")
- spark_system = PoolOrNew(/datum/effect/effect/system/spark_spread)
+ spark_system = new /datum/effect/effect/system/spark_spread()
spark_system.set_up(5, 0, src)
/obj/item/weapon/spell/shield/Destroy()
@@ -37,8 +37,10 @@
if(issmall(user)) // Smaller shields are more efficent.
damage_to_energy_cost *= 0.75
- if(istype(owner.get_other_hand(src), src.type)) // Two shields in both hands.
- damage_to_energy_cost *= 0.75
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ if(istype(H.get_other_hand(src), src.type)) // Two shields in both hands.
+ damage_to_energy_cost *= 0.75
else if(check_for_scepter())
damage_to_energy_cost *= 0.50
diff --git a/code/game/gamemodes/technomancer/spells/spawner/darkness.dm b/code/game/gamemodes/technomancer/spells/spawner/darkness.dm
index eafb167dd42..be978e7ee44 100644
--- a/code/game/gamemodes/technomancer/spells/spawner/darkness.dm
+++ b/code/game/gamemodes/technomancer/spells/spawner/darkness.dm
@@ -20,10 +20,10 @@
/obj/item/weapon/spell/spawner/darkness/New()
..()
- set_light(6, -5, l_color = "#FFFFFF")
+ set_light(6, -20, l_color = "#FFFFFF")
/obj/effect/temporary_effect/darkness
name = "darkness"
time_to_die = 2 MINUTES
new_light_range = 6
- new_light_power = -5
\ No newline at end of file
+ new_light_power = -20
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/spawner/destablize.dm b/code/game/gamemodes/technomancer/spells/spawner/destablize.dm
new file mode 100644
index 00000000000..38172b0d146
--- /dev/null
+++ b/code/game/gamemodes/technomancer/spells/spawner/destablize.dm
@@ -0,0 +1,53 @@
+/datum/technomancer/spell/destablize
+ name = "Destablize"
+ desc = "Creates an unstable disturbance at the targeted tile, which will afflict anyone nearby with instability who remains nearby. This can affect you \
+ and your allies as well. The disturbance lasts for twenty seconds."
+ cost = 100
+ obj_path = /obj/item/weapon/spell/spawner/destablize
+ category = OFFENSIVE_SPELLS
+
+/obj/item/weapon/spell/spawner/destablize
+ name = "destablize"
+ desc = "Now your enemies can feel what you go through when you have too much fun."
+ icon_state = "destablize"
+ cast_methods = CAST_RANGED
+ aspect = ASPECT_UNSTABLE
+ spawner_type = /obj/effect/temporary_effect/destablize
+
+/obj/item/weapon/spell/spawner/destablize/New()
+ ..()
+ set_light(3, 2, l_color = "#C26DDE")
+
+/obj/item/weapon/spell/spawner/destablize/on_ranged_cast(atom/hit_atom, mob/user)
+ if(within_range(hit_atom) && pay_energy(2000))
+ adjust_instability(15)
+ ..()
+
+/obj/effect/temporary_effect/destablize
+ name = "destablizing disturbance"
+ desc = "This can't be good..."
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "blueshatter"
+ time_to_die = null
+ invisibility = 0
+ new_light_range = 6
+ new_light_power = 20
+ new_light_color = "#C26DDE"
+ var/pulses_remaining = 40 // Lasts 20 seconds.
+ var/instability_power = 5
+ var/instability_range = 6
+
+/obj/effect/temporary_effect/destablize/New()
+ ..()
+ radiate_loop()
+
+/obj/effect/temporary_effect/destablize/proc/radiate_loop()
+ while(pulses_remaining)
+ sleep(5)
+ for(var/mob/living/L in range(src, instability_range) )
+ var/radius = max(get_dist(L, src), 1)
+ // Being farther away lessens the amount of instabity received.
+ var/outgoing_instability = instability_power * ( 1 / (radius**2) )
+ L.receive_radiated_instability(outgoing_instability)
+ pulses_remaining--
+ qdel(src)
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/warp_strike.dm b/code/game/gamemodes/technomancer/spells/warp_strike.dm
index 94074ffcf01..3f8939e0ba5 100644
--- a/code/game/gamemodes/technomancer/spells/warp_strike.dm
+++ b/code/game/gamemodes/technomancer/spells/warp_strike.dm
@@ -16,7 +16,7 @@
/obj/item/weapon/spell/warp_strike/New()
..()
- sparks = PoolOrNew(/datum/effect/effect/system/spark_spread)
+ sparks = new /datum/effect/effect/system/spark_spread()
sparks.set_up(5, 0, src)
sparks.attach(loc)
diff --git a/code/game/jobs/job/civilian.dm b/code/game/jobs/job/civilian.dm
index 1e4398546c5..5d105d6e874 100644
--- a/code/game/jobs/job/civilian.dm
+++ b/code/game/jobs/job/civilian.dm
@@ -27,11 +27,13 @@
H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/bartender(H), slot_w_uniform)
H.equip_to_slot_or_del(new /obj/item/device/pda/bar(H), slot_belt)
if(has_alt_title(H, alt_title,"Bartender"))
+ var/obj/item/weapon/permit/gun/bar/permit = new(H)
if(H.backbag == 1)
- H.equip_to_slot_or_del(new /obj/item/weapon/permit/gun/bar(H), slot_l_hand)
+ H.equip_to_slot_or_del(permit, slot_l_hand)
else
- H.equip_to_slot_or_del(new /obj/item/weapon/permit/gun/bar(H.back), slot_in_backpack)
- return 1
+ H.equip_to_slot_or_del(permit, slot_in_backpack)
+ permit.set_name(H.real_name)
+ return 1
@@ -264,6 +266,7 @@
economic_modifier = 7
access = list(access_lawyer, access_sec_doors, access_maint_tunnels, access_heads)
minimal_access = list(access_lawyer, access_sec_doors, access_heads)
+ minimal_player_age = 7
/datum/job/lawyer/equip(var/mob/living/carbon/human/H, var/alt_title)
diff --git a/code/game/jobs/job/engineering.dm b/code/game/jobs/job/engineering.dm
index e8b24b04460..e0efde55ad9 100644
--- a/code/game/jobs/job/engineering.dm
+++ b/code/game/jobs/job/engineering.dm
@@ -66,6 +66,7 @@
minimal_access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction)
alt_titles = list("Maintenance Technician","Engine Technician","Electrician")
+ minimal_player_age = 3
/datum/job/engineer/equip(var/mob/living/carbon/human/H, var/alt_title)
if(!H) return 0
diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm
index 9ca5c327fa9..8bfb5760a22 100644
--- a/code/game/jobs/job_controller.dm
+++ b/code/game/jobs/job_controller.dm
@@ -375,6 +375,7 @@ var/global/datum/controller/occupations/job_master
job.equip_backpack(H)
job.equip_survival(H)
job.apply_fingerprints(H)
+ H.equip_post_job()
//If some custom items could not be equipped before, try again now.
for(var/thing in custom_equip_leftovers)
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index f69f5f6b2ae..f54d069b9d4 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -68,10 +68,12 @@
anchored = 1
circuit = /obj/item/weapon/circuitboard/sleeper
var/mob/living/carbon/human/occupant = null
- var/list/available_chemicals = list("inaprovaline" = "Inaprovaline", "stoxin" = "Soporific", "paracetamol" = "Paracetamol", "anti_toxin" = "Dylovene", "dexalin" = "Dexalin")
+ var/list/available_chemicals = list("inaprovaline" = "Inaprovaline", "paracetamol" = "Paracetamol", "anti_toxin" = "Dylovene", "dexalin" = "Dexalin")
var/obj/item/weapon/reagent_containers/glass/beaker = null
var/filtering = 0
var/obj/machinery/sleep_console/console
+ var/stasis_level = 0 //Every 'this' life ticks are applied to the mob (when life_ticks%stasis_level == 1)
+ var/stasis_choices = list("Complete (1%)" = 100, "Deep (10%)" = 10, "Moderate (20%)" = 5, "Light (50%)" = 2, "None (100%)" = 0)
use_power = 1
idle_power_usage = 15
@@ -98,18 +100,23 @@
/obj/machinery/sleeper/process()
if(stat & (NOPOWER|BROKEN))
return
+ if(occupant)
+ occupant.Stasis(stasis_level)
+ if(stasis_level >= 100 && occupant.timeofdeath)
+ occupant.timeofdeath += 1 SECOND
+
+ if(filtering > 0)
+ if(beaker)
+ if(beaker.reagents.total_volume < beaker.reagents.maximum_volume)
+ var/pumped = 0
+ for(var/datum/reagent/x in occupant.reagents.reagent_list)
+ occupant.reagents.trans_to_obj(beaker, 3)
+ pumped++
+ if(ishuman(occupant))
+ occupant.vessel.trans_to_obj(beaker, pumped + 1)
+ else
+ toggle_filter()
- if(filtering > 0)
- if(beaker)
- if(beaker.reagents.total_volume < beaker.reagents.maximum_volume)
- var/pumped = 0
- for(var/datum/reagent/x in occupant.reagents.reagent_list)
- occupant.reagents.trans_to_obj(beaker, 3)
- pumped++
- if(ishuman(occupant))
- occupant.vessel.trans_to_obj(beaker, pumped + 1)
- else
- toggle_filter()
/obj/machinery/sleeper/update_icon()
icon_state = "sleeper_[occupant ? "1" : "0"]"
@@ -154,6 +161,13 @@
data["beaker"] = -1
data["filtering"] = filtering
+ var/stasis_level_name = "Error!"
+ for(var/N in stasis_choices)
+ if(stasis_choices[N] == stasis_level)
+ stasis_level_name = N
+ break
+ data["stasis"] = stasis_level_name
+
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
ui = new(user, src, ui_key, "sleeper.tmpl", "Sleeper UI", 600, 600, state = state)
@@ -182,12 +196,20 @@
if(occupant && occupant.stat != DEAD)
if(href_list["chemical"] in available_chemicals) // Your hacks are bad and you should feel bad
inject_chemical(usr, href_list["chemical"], text2num(href_list["amount"]))
+ if(href_list["change_stasis"])
+ var/new_stasis = input("Levels deeper than 50% stasis level will render the patient unconscious.","Stasis Level") as null|anything in stasis_choices
+ if(new_stasis && CanUseTopic(usr, default_state) == STATUS_INTERACTIVE)
+ stasis_level = stasis_choices[new_stasis]
return 1
/obj/machinery/sleeper/attackby(var/obj/item/I, var/mob/user)
add_fingerprint(user)
- if(default_deconstruction_screwdriver(user, I))
+ if(istype(I, /obj/item/weapon/grab))
+ var/obj/item/weapon/grab/G = I
+ if(G.affecting)
+ go_in(G.affecting, user)
+ else if(default_deconstruction_screwdriver(user, I))
return
else if(default_deconstruction_crowbar(user, I))
return
@@ -201,6 +223,28 @@
user << "\The [src] has a beaker already."
return
+/obj/machinery/sleeper/verb/move_eject()
+ set name = "Eject occupant"
+ set category = "Object"
+ set src in oview(1)
+ if(usr == occupant)
+ switch(usr.stat)
+ if(DEAD)
+ return
+ if(UNCONSCIOUS)
+ usr << "You struggle through the haze to hit the eject button. This will take a couple of minutes..."
+ sleep(2 MINUTES)
+ if(!src || !usr || !occupant || (occupant != usr)) //Check if someone's released/replaced/bombed him already
+ return
+ go_out()
+ if(CONSCIOUS)
+ go_out()
+ else
+ if(usr.stat != 0)
+ return
+ go_out()
+ add_fingerprint(usr)
+
/obj/machinery/sleeper/MouseDrop_T(var/mob/target, var/mob/user)
if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user)|| !ishuman(target))
return
@@ -261,6 +305,7 @@
if(occupant.client)
occupant.client.eye = occupant.client.mob
occupant.client.perspective = MOB_PERSPECTIVE
+ occupant.Stasis(0)
occupant.loc = src.loc
occupant = null
for(var/atom/movable/A in src) // In case an object was dropped inside or something
diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm
index bba12887a9b..b1cf9bac081 100644
--- a/code/game/machinery/adv_med.dm
+++ b/code/game/machinery/adv_med.dm
@@ -301,6 +301,15 @@
occupantData["reagents"] = reagentData
+ var/ingestedData[0]
+ if(H.ingested.reagent_list.len >= 1)
+ for(var/datum/reagent/R in H.ingested.reagent_list)
+ ingestedData[++ingestedData.len] = list("name" = R.name, "amount" = R.volume)
+ else
+ ingestedData = null
+
+ occupantData["ingested"] = ingestedData
+
var/extOrganData[0]
for(var/obj/item/organ/external/E in H.organs)
var/organData[0]
@@ -394,7 +403,7 @@
P.info += "Time of scan: [worldtime2stationtime(world.time)]
"
P.info += "[printing_text]"
P.info += "
Notes:
"
- P.name = "Body Scan - [href_list["name"]]"
+ P.name = "Body Scan - [href_list["name"]] ([worldtime2stationtime(world.time)])"
printing = null
printing_text = null
@@ -457,9 +466,13 @@
dat += "[extra_font]\tBlood Level %: [blood_percent] ([blood_volume] units)
"
if(occupant.reagents)
- for(var/datum/reagent/R in occupant.reagents)
+ for(var/datum/reagent/R in occupant.reagents.reagent_list)
dat += "Reagent: [R.name], Amount: [R.volume]
"
+ if(occupant.ingested)
+ for(var/datum/reagent/R in occupant.ingested.reagent_list)
+ dat += "Stomach: [R.name], Amount: [R.volume]
"
+
dat += "