Merge branch 'master' of https://github.com/tgstation/-tg-station into ClownNamePreferences

Conflicts:
	code/modules/mob/transform_procs.dm
This commit is contained in:
phil235
2015-04-27 00:11:49 +02:00
774 changed files with 22474 additions and 9523 deletions
+61 -5
View File
@@ -21,9 +21,19 @@ Pipelines + Other Objects -> Pipe network
var/pipe_color
var/obj/item/pipe/stored
var/welded = 0 //Used on pumps and scrubbers
var/global/list/iconsetids = list()
var/global/list/pipeimages = list()
/obj/machinery/atmospherics/Destroy()
for(var/mob/living/L in src)
L.remove_ventcrawl()
L.forceMove(get_turf(src))
..()
/obj/machinery/atmospherics/New()
..()
@@ -78,21 +88,21 @@ Pipelines + Other Objects -> Pipe network
if(can_unwrench && istype(W, /obj/item/weapon/wrench))
var/turf/T = src.loc
if (level==1 && isturf(T) && T.intact)
user << "<span class='danger'>You must remove the plating first.</span>"
user << "<span class='warning'>You must remove the plating first!</span>"
return 1
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
add_fingerprint(user)
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "<span class='danger'>You cannot unwrench this [src], it is too exerted due to internal pressure.</span>"
user << "<span class='warning'>You cannot unwrench this [src], it is too exerted due to internal pressure!</span>"
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "<span class='notice'>You begin to unfasten \the [src]...</span>"
if (do_after(user, 40) && !gc_destroyed)
user.visible_message( \
"[user] unfastens \the [src].", \
"<span class='notice'>You have unfastened \the [src].</span>", \
"You hear ratchet.")
"<span class='notice'>You unfasten \the [src].</span>", \
"<span class='italics'>You hear ratchet.</span>")
investigate_log("was <span class='warning'>REMOVED</span> by [key_name(usr)]", "atmos")
Deconstruct()
else
@@ -150,4 +160,50 @@ Pipelines + Other Objects -> Pipe network
/obj/machinery/atmospherics/singularity_pull(S, current_size)
if(current_size >= STAGE_FIVE)
Deconstruct()
Deconstruct()
//Find a connecting /obj/machinery/atmospherics in specified direction
/obj/machinery/atmospherics/proc/findConnecting(var/direction)
for(var/obj/machinery/atmospherics/target in get_step(src, direction))
if(target.initialize_directions & get_dir(target,src))
return target
#define VENT_SOUND_DELAY 30
/obj/machinery/atmospherics/relaymove(var/mob/living/user, var/direction)
if(!(direction & initialize_directions)) //cant go this way.
return
var/obj/machinery/atmospherics/target_move = findConnecting(direction)
if(target_move)
if(is_type_in_list(target_move, ventcrawl_machinery) && target_move.can_crawl_through())
user.remove_ventcrawl()
user.forceMove(target_move.loc) //handle entering and so on.
user.visible_message("<span class='notice'>You hear something squeezing through the ducts...</span>","<span class='notice'>You climb out the ventilation system.")
else if(target_move.can_crawl_through())
user.loc = target_move
user.client.eye = target_move //Byond only updates the eye every tick, This smooths out the movement
if(world.time - user.last_played_vent > VENT_SOUND_DELAY)
user.last_played_vent = world.time
playsound(src, 'sound/machines/ventcrawl.ogg', 50, 1, -3)
else
if((direction & initialize_directions) || is_type_in_list(src, ventcrawl_machinery) && can_crawl_through()) //if we move in a way the pipe can connect, but doesn't - or we're in a vent
user.remove_ventcrawl()
user.forceMove(src.loc)
user.visible_message("<span class='notice'>You hear something squeezing through the ducts...</span>","<span class='notice'>You climb out the ventilation system.")
user.canmove = 0
spawn(1)
user.canmove = 1
/obj/machinery/atmospherics/AltClick(var/mob/living/L)
if(is_type_in_list(src, ventcrawl_machinery))
L.handle_ventcrawl(src)
return
..()
/obj/machinery/atmospherics/proc/can_crawl_through()
return 1
@@ -171,6 +171,6 @@ Passive gate is similar to the regular pump except:
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (on)
user << "<span class='danger'>You cannot unwrench this [src], turn it off first.</span>"
user << "<span class='warning'>You cannot unwrench this [src], turn it off first!</span>"
return 1
return ..()
@@ -176,7 +176,7 @@ Thus, the two variables affect pump operation are set in New():
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (!(stat & NOPOWER) && on)
user << "<span class='danger'>You cannot unwrench this [src], turn it off first.</span>"
user << "<span class='warning'>You cannot unwrench this [src], turn it off first!</span>"
return 1
return ..()
@@ -175,6 +175,6 @@ Thus, the two variables affect pump operation are set in New():
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (!(stat & NOPOWER) && on)
user << "<span class='danger'>You cannot unwrench this [src], turn it off first.</span>"
user << "<span class='warning'>You cannot unwrench this [src], turn it off first!</span>"
return 1
return ..()
@@ -37,7 +37,7 @@
/obj/machinery/atmospherics/unary/portables_connector/attackby(obj/item/weapon/W, mob/user, params)
if(istype(W, /obj/item/weapon/wrench))
if(connected_device)
user << "<span class='danger'>You cannot unwrench this [src], dettach [connected_device] first.</span>"
user << "<span class='warning'>You cannot unwrench this [src], dettach [connected_device] first!</span>"
return 1
return ..()
@@ -23,8 +23,6 @@
//2: Do not pass internal_pressure_bound
//3: Do not pass either
var/welded = 0
var/frequency = 1439
var/datum/radio_frequency/radio_connection
@@ -267,22 +265,22 @@
/obj/machinery/atmospherics/unary/vent_pump/attackby(obj/item/W, mob/user, params)
if (istype(W, /obj/item/weapon/wrench)&& !(stat & NOPOWER) && on)
user << "<span class='danger'>You cannot unwrench this [src], turn it off first.</span>"
user << "<span class='warning'>You cannot unwrench this [src], turn it off first!</span>"
return 1
if(istype(W, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = W
if (WT.remove_fuel(0,user))
playsound(loc, 'sound/items/Welder.ogg', 40, 1)
user << "<span class='notice'>Now welding the vent.</span>"
user << "<span class='notice'>You begin welding the vent...</span>"
if(do_after(user, 20))
if(!src || !WT.isOn()) return
playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1)
if(!welded)
user.visible_message("[user] welds the vent shut.", "You weld the vent shut.", "You hear welding.")
user.visible_message("[user] welds the vent shut.", "<span class='notice'>You weld the vent shut.</span>", "<span class='italics'>You hear welding.</span>")
welded = 1
update_icon()
else
user.visible_message("[user] unwelds the vent.", "You unweld the vent.", "You hear welding.")
user.visible_message("[user] unwelds the vent.", "<span class='notice'>You unweld the vent.</span>", "<span class='italics'>You hear welding.</span>")
welded = 0
update_icon()
return 1
@@ -307,68 +305,6 @@
initial_loc.air_vent_names -= id_tag
..()
/*
Alt-click to ventcrawl
*/
/obj/machinery/atmospherics/unary/vent_pump/AltClick(var/mob/living/L)
if(!L.ventcrawler || !isliving(L) || !Adjacent(L))
return
if(L.stat)
L << "You must be conscious to do this!"
return
if(L.lying)
L << "You can't vent crawl while you're stunned!"
return
if(welded)
L << "That vent is welded shut."
return
var/list/vents = list()
for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in parent.other_atmosmch)
if(temp_vent.welded)
continue
if(temp_vent in loc)
continue
var/turf/T = get_turf(temp_vent)
if(!T || T.z != loc.z)
continue
var/i = 1
var/index = "[T.loc.name]\[[i]\]"
while(index in vents)
i++
index = "[T.loc.name]\[[i]\]"
vents[index] = temp_vent
if(!vents.len)
L << "<span class='warning'>There are no available vents to travel to, they could be welded. </span>"
return
var/obj/selection = input(L,"Select a destination.", "Duct System") as null|anything in sortList(vents)
if(!selection)
return
if(!Adjacent(L) || L.stat || L.lying || !L.ventcrawler || welded)
return
if(iscarbon(L) && L.ventcrawler < 2) // lesser ventcrawlers can't bring items
for(var/obj/item/carried_item in L.contents)
if(!istype(carried_item, /obj/item/weapon/implant))//If it's not an implant
L << "<span class='warning'>You can't be carrying items or have items equipped when vent crawling!</span>"
return
var/obj/machinery/atmospherics/unary/vent_pump/target_vent = vents[selection]
if(!target_vent)
return
L.visible_message("<span class='notice'>[L] scrambles into the ventilation ducts!</span>", \
"<span class='notice'>You scramble into the ventilation ducts.</span>")
target_vent.audible_message("<span class='notice'>You hear something squeezing through the ventilation ducts.</span>")
if(target_vent.welded) //the vent can be welded while they scrolled through the list.
target_vent = src
L << "<span class='warning'>The vent you were heading to appears to be welded.</span>"
L.loc = target_vent.loc
var/area/new_area = get_area(L.loc)
if(new_area)
new_area.Entered(L)
/obj/machinery/atmospherics/unary/vent_pump/can_crawl_through()
return !welded
@@ -27,6 +27,7 @@
var/radio_filter_out
var/radio_filter_in
/obj/machinery/atmospherics/unary/vent_scrubber/New()
..()
initial_loc = get_area(loc)
@@ -50,6 +51,10 @@
if(showpipe)
overlays += getpipeimage('icons/obj/atmospherics/unary_devices.dmi', "scrub_cap", initialize_directions)
if(welded)
icon_state = "scrub_welded"
return
if(!node || !on || stat & (NOPOWER|BROKEN))
icon_state = "scrub_off"
return
@@ -107,7 +112,7 @@
if (!node)
on = 0
//broadcast_status()
if(!on)
if(!on || welded)
return 0
@@ -238,15 +243,38 @@
update_icon_nopipes()
/obj/machinery/atmospherics/unary/vent_scrubber/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob, params)
if(istype(W, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = W
if(WT.remove_fuel(0,user))
playsound(loc, 'sound/items/Welder.ogg', 40, 1)
user << "<span class='notice'>Now welding the scrubber.</span>"
if(do_after(user, 20))
if(!src || !WT.isOn())
return
playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1)
if(!welded)
user.visible_message("[user] welds the scrubber shut.","You weld the scrubber shut.", "You hear welding.")
welded = 1
update_icon()
else
user.visible_message("[user] unwelds the scrubber.", "You unweld the scrubber.", "You hear welding.")
welded = 0
update_icon()
return 1
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (!(stat & NOPOWER) && on)
user << "<span class='danger'>You cannot unwrench this [src], turn it off first.</span>"
user << "<span class='warning'>You cannot unwrench this [src], turn it off first!</span>"
return 1
return ..()
/obj/machinery/atmospherics/unary/vent_scrubber/Destroy()
if(initial_loc)
initial_loc.air_scrub_info -= id_tag
initial_loc.air_scrub_names -= id_tag
..()
/obj/machinery/atmospherics/unary/vent_scrubber/can_crawl_through()
return !welded
+1 -3
View File
@@ -107,6 +107,4 @@
#define MAX_HIGH_PRESSURE_DAMAGE 4 //This used to be 20... I got this much random rage for some retarded decision by polymorph?! Polymorph now lies in a pool of blood with a katana jammed in his spleen. ~Errorage --PS: The katana did less than 20 damage to him :(
#define LOW_PRESSURE_DAMAGE 2 //The amounb of damage someone takes when in a low pressure area (The pressure threshold is so low that it doesn't make sense to do any calculations, so it just applies this flat value).
#define PRESSURE_SUIT_REDUCTION_COEFFICIENT 0.8 //This is how much (percentual) a suit with the flag STOPSPRESSUREDMAGE reduces pressure.
#define PRESSURE_HEAD_REDUCTION_COEFFICIENT 0.4 //This is how much (percentual) a helmet/hat with the flag STOPSPRESSUREDMAGE reduces pressure.
#define COLD_SLOWDOWN_FACTOR 20 //Humans are slowed by the difference between bodytemp and BODYTEMP_COLD_DAMAGE_LIMIT divided by this
+1
View File
@@ -68,6 +68,7 @@
#define NOGUNS 512
#define NOBLOOD 1024
#define NOFIRE 2048
#define VIRUSIMMUNE 4096
/*
These defines are used specifically with the atom/movable/languages bitmask.
+2 -1
View File
@@ -24,4 +24,5 @@
#define ANTAG_HUD_OPS 7
#define ANTAG_HUD_GANG_A 8
#define ANTAG_HUD_GANG_B 9
#define ANTAG_HUD_WIZ 10
#define ANTAG_HUD_WIZ 10
#define ANTAG_HUD_SHADOW 11
+3
View File
@@ -40,3 +40,6 @@
#define BE_NINJA 1024
#define BE_MONKEY 2048
#define BE_GANG 4096
#define BE_SHADOWLING 8192
#define BE_ABDUCTOR 16384
#define BE_REVENANT 32768
+4 -12
View File
@@ -53,18 +53,10 @@
return 0
return 1
//Magic constants obtained by using linear regression on right-angled triangles of sides 0<x<1, 0<y<1
//They should approximate pythagoras theorem well enough for our needs.
#define k1 0.934
#define k2 0.427
/proc/cheap_hypotenuse(Ax,Ay,Bx,By) // T is just the second atom to check distance to center with
var/dx = abs(Ax - Bx) //sides of right-angled triangle
var/dy = abs(Ay - By)
if(dx>=dy) return (k1*dx) + (k2*dy) //No sqrt or powers :)
else return (k2*dx) + (k1*dy)
#undef k1
#undef k2
//We used to use linear regression to approximate the answer, but Mloc realized this was actually faster.
//And lo and behold, it is, and it's more accurate to boot.
/proc/cheap_hypotenuse(Ax,Ay,Bx,By)
return sqrt(abs(Ax - Bx)**2 + abs(Ay - By)**2) //A squared + B squared = C squared
/proc/circlerange(center=usr,radius=3)
+2 -2
View File
@@ -185,8 +185,8 @@
return
L = L.Copy()
for(var/i=1, i<=L.len, ++i)
L.Swap(i,rand(1,L.len))
for(var/i=1, i<L.len, ++i)
L.Swap(i,rand(i,L.len))
return L
+1 -1
View File
@@ -131,11 +131,11 @@ var/syndicate_name = null
syndicate_name = name
return name
var/gang_name_pool = list("Clandestine", "Prima", "Blue", "Zero-G", "Max", "Blasto", "Waffle", "North", "Omni", "Newton", "Cyber", "Donk", "Gene", "Gib", "Tunnel")
var/gang_A_name = null
var/gang_B_name = null
/proc/gang_name(var/gang)
if(!gang_A_name || !gang_B_name)
var/gang_name_pool = list("Clandestine", "Prima", "Blue", "Zero-G", "Max", "Blasto", "Waffle", "North", "Omni", "Newton", "Cyber", "Donk", "Gene", "Gib", "Tunnel")
gang_A_name = pick(gang_name_pool)
gang_name_pool -= gang_A_name
gang_B_name = pick(gang_name_pool)
+18 -158
View File
@@ -781,27 +781,35 @@ Turf and target are seperate in case you want to teleport some distance from a t
return 1
/proc/do_after(mob/user, delay, numticks = 5, needhand = 1)
if(!user || isnull(user))
/proc/do_after(mob/user, delay, numticks = 5, needhand = 1, atom/target = null)
if(!user)
return 0
if(numticks == 0)
return 0
var/atom/Tloc = null
if(target)
Tloc = target.loc
var/delayfraction = round(delay/numticks)
var/turf/T = user.loc
var/atom/Uloc = user.loc
var/holding = user.get_active_hand()
var/holdingnull = 1
var/holdingnull = 1 //User is not holding anything
if(holding)
holdingnull = 0
holdingnull = 0 //User is holding a tool of some kind
for(var/i = 0, i<numticks, i++)
sleep(delayfraction)
if(!user || user.stat || user.weakened || user.stunned || !(user.loc == T))
if(!user || user.stat || user.weakened || user.stunned || !(user.loc == Uloc))
return 0
if(needhand) //Sometimes you don't want the user to have to keep their active hand
if(Tloc && (!target || Tloc != target.loc)) //Tloc not set when we don't want to track target
return 0 // Target no longer exists or has moved
if(needhand)
//This might seem like an odd check, but you can still need a hand even when it's empty
//i.e the hand is used to insert some item/tool into the construction
if(!holdingnull)
if(!holding)
return 0
@@ -820,8 +828,6 @@ Turf and target are seperate in case you want to teleport some distance from a t
//else populates the list first before returning it
/proc/SortAreas()
for(var/area/A in world)
if(A.lighting_subarea)
continue
sortedAreas.Add(A)
sortTim(sortedAreas, /proc/cmp_name_asc)
@@ -880,152 +886,6 @@ Turf and target are seperate in case you want to teleport some distance from a t
var/y_pos = null
var/z_pos = null
/area/proc/move_contents_to(var/area/A, var/turftoleave=null, var/direction = null)
//Takes: Area. Optional: turf type to leave behind.
//Returns: Nothing.
//Notes: Attempts to move the contents of one area to another area.
// Movement based on lower left corner. Tiles that do not fit
// into the new area will not be moved.
if(!A || !src) return 0
var/list/turfs_src = get_area_turfs(src.type)
var/list/turfs_trg = get_area_turfs(A.type)
var/src_min_x = 0
var/src_min_y = 0
for (var/turf/T in turfs_src)
if(T.x < src_min_x || !src_min_x) src_min_x = T.x
if(T.y < src_min_y || !src_min_y) src_min_y = T.y
var/trg_min_x = 0
var/trg_min_y = 0
for (var/turf/T in turfs_trg)
if(T.x < trg_min_x || !trg_min_x) trg_min_x = T.x
if(T.y < trg_min_y || !trg_min_y) trg_min_y = T.y
var/list/refined_src = new/list()
for(var/turf/T in turfs_src)
refined_src += T
refined_src[T] = new/datum/coords
var/datum/coords/C = refined_src[T]
C.x_pos = (T.x - src_min_x)
C.y_pos = (T.y - src_min_y)
var/list/refined_trg = new/list()
for(var/turf/T in turfs_trg)
refined_trg += T
refined_trg[T] = new/datum/coords
var/datum/coords/C = refined_trg[T]
C.x_pos = (T.x - trg_min_x)
C.y_pos = (T.y - trg_min_y)
var/list/fromupdate = new/list()
var/list/toupdate = new/list()
moving:
for (var/turf/T in refined_src)
var/datum/coords/C_src = refined_src[T]
for (var/turf/B in refined_trg)
var/datum/coords/C_trg = refined_trg[B]
if(C_src.x_pos == C_trg.x_pos && C_src.y_pos == C_trg.y_pos)
var/old_dir1 = T.dir
var/old_icon_state1 = T.icon_state
var/old_icon1 = T.icon
var/turf/X = new T.type(B)
X.dir = old_dir1
X.icon_state = old_icon_state1
X.icon = old_icon1 //Shuttle floors are in shuttle.dmi while the defaults are floors.dmi
// Give the new turf our air, if simulated
if(istype(X, /turf/simulated) && istype(T, /turf/simulated))
var/turf/simulated/sim = X
sim.copy_air_with_tile(T)
/* Quick visual fix for some weird shuttle corner artefacts when on transit space tiles */
if(direction && findtext(X.icon_state, "swall_s"))
// Spawn a new shuttle corner object
var/obj/corner = new()
corner.loc = X
corner.density = 1
corner.anchored = 1
corner.icon = X.icon
corner.icon_state = replacetext(X.icon_state, "_s", "_f")
corner.tag = "delete me"
corner.name = "wall"
// Find a new turf to take on the property of
var/turf/nextturf = get_step(corner, direction)
if(!nextturf || !istype(nextturf, /turf/space))
nextturf = get_step(corner, turn(direction, 180))
// Take on the icon of a neighboring scrolling space icon
X.icon = nextturf.icon
X.icon_state = nextturf.icon_state
for(var/obj/O in T)
// Reset the shuttle corners
if(O.tag == "delete me")
X.icon = 'icons/turf/shuttle.dmi'
X.icon_state = replacetext(O.icon_state, "_f", "_s") // revert the turf to the old icon_state
X.name = "wall"
qdel(O) // prevents multiple shuttle corners from stacking
continue
if(!istype(O,/obj)) continue
O.loc = X
for(var/mob/M in T)
if(!M.move_on_shuttle)
continue
M.loc = X
// var/area/AR = X.loc
// if(AR.lighting_use_dynamic) //TODO: rewrite this code so it's not messed by lighting ~Carn
// X.opacity = !X.opacity
// X.SetOpacity(!X.opacity)
toupdate += X
if(turftoleave)
var/turf/ttl = new turftoleave(T)
// var/area/AR2 = ttl.loc
// if(AR2.lighting_use_dynamic) //TODO: rewrite this code so it's not messed by lighting ~Carn
// ttl.opacity = !ttl.opacity
// ttl.sd_SetOpacity(!ttl.opacity)
fromupdate += ttl
else
T.ChangeTurf(/turf/space)
refined_src -= T
refined_trg -= B
continue moving
if(toupdate.len)
for(var/turf/simulated/T1 in toupdate)
SSair.remove_from_active(T1)
T1.CalculateAdjacentTurfs()
SSair.add_to_active(T1,1)
if(fromupdate.len)
for(var/turf/simulated/T2 in fromupdate)
SSair.remove_from_active(T2)
T2.CalculateAdjacentTurfs()
SSair.add_to_active(T2,1)
/proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0)
if(!original)
return null
@@ -1472,7 +1332,7 @@ var/list/WALLITEMS = list(
/obj/proc/atmosanalyzer_scan(var/datum/gas_mixture/air_contents, mob/user, var/obj/target = src)
var/obj/icon = target
user.visible_message("<span class='danger'>[user] has used the analyzer on \icon[icon] [target].</span>")
user.visible_message("[user] has used the analyzer on \icon[icon] [target].", "<span class='notice'>You use the analyzer on \icon[icon] [target].</span>")
var/pressure = air_contents.return_pressure()
var/total_moles = air_contents.total_moles()
+1 -1
View File
@@ -31,7 +31,7 @@
#define AGE_MAX 85 //oldest a character can be
#define SHOES_SLOWDOWN 0 //How much shoes slow you down by default. Negative values speed you up
#define POCKET_STRIP_DELAY 40 //time taken (in deciseconds) to search somebody's pockets
#define DOOR_CRUSH_DAMAGE 10 //the amount of damage that airlocks deal when they crush you
#define DOOR_CRUSH_DAMAGE 15 //the amount of damage that airlocks deal when they crush you
#define HUNGER_FACTOR 0.1 //factor at which mob nutrition decreases
#define REAGENTS_METABOLISM 0.4 //How many units of reagent are consumed per tick, by default.
+3 -1
View File
@@ -46,5 +46,7 @@ var/list/be_special_flags = list(
"Blob" = BE_BLOB,
"Ninja" = BE_NINJA,
"Monkey" = BE_MONKEY,
"Gang" = BE_GANG
"Gang" = BE_GANG,
"Abductor" = BE_ABDUCTOR,
"Revenant" = BE_REVENANT
)
-7
View File
@@ -17,13 +17,6 @@
Therefore, the top right corner (except during admin shenanigans) is at "15,15"
*/
//Upper left action buttons, displayed when you pick up an item that has this enabled.
#define ui_action_slot1 "WEST :6, NORTH-1:26"
#define ui_action_slot2 "WEST+1:8, NORTH-1:26"
#define ui_action_slot3 "WEST+2:10,NORTH-1:26"
#define ui_action_slot4 "WEST+3:12,NORTH-1:26"
#define ui_action_slot5 "WEST+4:14,NORTH-1:26"
//Lower left, persistant menu
#define ui_inventory "WEST:6,SOUTH:5"
+247
View File
@@ -0,0 +1,247 @@
#define AB_ITEM 1
#define AB_SPELL 2
#define AB_INNATE 3
#define AB_GENERIC 4
#define AB_CHECK_RESTRAINED 1
#define AB_CHECK_STUNNED 2
#define AB_CHECK_LYING 4
#define AB_CHECK_ALIVE 8
#define AB_CHECK_INSIDE 16
/datum/action
var/name = "Generic Action"
var/action_type = AB_ITEM
var/procname = null
var/atom/movable/target = null
var/check_flags = 0
var/processing = 0
var/active = 0
var/obj/screen/movable/action_button/button = null
var/button_icon = 'icons/mob/actions.dmi'
var/button_icon_state = "default"
var/background_icon_state = "bg_default"
var/mob/living/owner
/datum/action/New(var/Target)
target = Target
/datum/action/Destroy()
if(owner)
Remove(owner)
/datum/action/proc/Grant(mob/living/T)
if(owner)
if(owner == T)
return
Remove(owner)
owner = T
owner.actions.Add(src)
owner.update_action_buttons()
return
/datum/action/proc/Remove(mob/living/T)
if(button)
if(T.client)
T.client.screen -= button
del(button)
T.actions.Remove(src)
T.update_action_buttons()
owner = null
return
/datum/action/proc/Trigger()
if(!Checks())
return
switch(action_type)
if(AB_ITEM)
if(target)
var/obj/item/item = target
item.ui_action_click()
if(AB_SPELL)
if(target)
var/obj/effect/proc_holder/spell = target
spell.Click()
if(AB_INNATE)
if(!active)
Activate()
else
Deactivate()
if(AB_GENERIC)
if(target && procname)
call(target,procname)(usr)
return
/datum/action/proc/Activate()
return
/datum/action/proc/Deactivate()
return
/datum/action/proc/Process()
return
/datum/action/proc/CheckRemoval(mob/living/user) // 1 if action is no longer valid for this mob and should be removed
return 0
/datum/action/proc/IsAvailable()
return Checks()
/datum/action/proc/Checks()// returns 1 if all checks pass
if(!owner)
return 0
if(check_flags & AB_CHECK_RESTRAINED)
if(owner.restrained())
return 0
if(check_flags & AB_CHECK_STUNNED)
if(owner.stunned)
return 0
if(check_flags & AB_CHECK_LYING)
if(owner.lying)
return 0
if(check_flags & AB_CHECK_ALIVE)
if(owner.stat)
return 0
if(check_flags & AB_CHECK_INSIDE)
if(!(target in owner))
return 0
return 1
/datum/action/proc/UpdateName()
return name
/obj/screen/movable/action_button
var/datum/action/owner
screen_loc = "WEST,NORTH"
/obj/screen/movable/action_button/Click(location,control,params)
var/list/modifiers = params2list(params)
if(modifiers["shift"])
moved = 0
return 1
if(usr.next_move >= world.time) // Is this needed ?
return
owner.Trigger()
return 1
/obj/screen/movable/action_button/proc/UpdateIcon()
if(!owner)
return
icon = owner.button_icon
icon_state = owner.background_icon_state
overlays.Cut()
var/image/img
if(owner.action_type == AB_ITEM && owner.target)
var/obj/item/I = owner.target
img = image(I.icon, src , I.icon_state)
else if(owner.button_icon && owner.button_icon_state)
img = image(owner.button_icon,src,owner.button_icon_state)
img.pixel_x = 0
img.pixel_y = 0
overlays += img
if(!owner.IsAvailable())
color = rgb(128,0,0,128)
else
color = rgb(255,255,255,255)
//Hide/Show Action Buttons ... Button
/obj/screen/movable/action_button/hide_toggle
name = "Hide Buttons"
icon = 'icons/mob/actions.dmi'
icon_state = "bg_default"
var/hidden = 0
/obj/screen/movable/action_button/hide_toggle/Click()
usr.hud_used.action_buttons_hidden = !usr.hud_used.action_buttons_hidden
hidden = usr.hud_used.action_buttons_hidden
if(hidden)
name = "Show Buttons"
else
name = "Hide Buttons"
UpdateIcon()
usr.update_action_buttons()
/obj/screen/movable/action_button/hide_toggle/proc/InitialiseIcon(var/mob/living/user)
if(isalien(user))
icon_state = "bg_alien"
else
icon_state = "bg_default"
UpdateIcon()
return
/obj/screen/movable/action_button/hide_toggle/UpdateIcon()
overlays.Cut()
var/image/img = image(icon,src,hidden?"show":"hide")
overlays += img
return
//This is the proc used to update all the action buttons. Properly defined in /mob/living/
/mob/proc/update_action_buttons()
return
#define AB_WEST_OFFSET 4
#define AB_NORTH_OFFSET 26
#define AB_MAX_COLUMNS 10
/datum/hud/proc/ButtonNumberToScreenCoords(var/number) // TODO : Make this zero-indexed for readabilty
var/row = round((number-1)/AB_MAX_COLUMNS)
var/col = ((number - 1)%(AB_MAX_COLUMNS)) + 1
var/coord_col = "+[col-1]"
var/coord_col_offset = 4+2*col
var/coord_row = "[-1 - row]"
var/coord_row_offset = 26
return "WEST[coord_col]:[coord_col_offset],NORTH[coord_row]:[coord_row_offset]"
/datum/hud/proc/SetButtonCoords(var/obj/screen/button,var/number)
var/row = round((number-1)/AB_MAX_COLUMNS)
var/col = ((number - 1)%(AB_MAX_COLUMNS)) + 1
var/x_offset = 32*(col-1) + 4 + 2*col
var/y_offset = -32*(row+1) + 26
var/matrix/M = matrix()
M.Translate(x_offset,y_offset)
button.transform = M
//Presets for item actions
/datum/action/item_action
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_LYING|AB_CHECK_ALIVE|AB_CHECK_INSIDE
/datum/action/item_action/CheckRemoval(mob/living/user)
return !(target in user)
/datum/action/item_action/hands_free
check_flags = AB_CHECK_ALIVE|AB_CHECK_INSIDE
//Preset for spells
/datum/action/spell_action
action_type = AB_SPELL
check_flags = 0
background_icon_state = "bg_spell"
/datum/action/spell_action/UpdateName()
var/obj/effect/proc_holder/spell/spell = target
return spell.name
/datum/action/spell_action/IsAvailable()
if(!target)
return 0
var/obj/effect/proc_holder/spell/spell = target
if(usr)
return spell.can_cast(usr)
else
if(owner)
return spell.can_cast(owner)
return 1
/datum/action/spell_action/CheckRemoval()
if(owner.mind)
if(target in owner.mind.spell_list)
return 0
return !(target in owner.mob_spell_list)
+4 -2
View File
@@ -15,8 +15,10 @@
icon_state = "nightvision1"
/obj/screen/alien/nightvision/Click()
var/mob/living/carbon/alien/humanoid/A = usr
A.nightvisiontoggle()
var/mob/living/carbon/alien/A = usr
var/obj/effect/proc_holder/alien/nightvisiontoggle/T = locate() in A.abilities
if(T)
T.fire(A)
/datum/hud/proc/alien_hud()
+2 -6
View File
@@ -110,8 +110,8 @@ var/datum/global_hud/global_hud = new()
var/list/other
var/list/obj/screen/hotkeybuttons
var/list/obj/screen/item_action/item_action_list = list() //Used for the item action ui buttons.
var/obj/screen/movable/action_button/hide_toggle/hide_actions_toggle
var/action_buttons_hidden = 0
datum/hud/New(mob/owner)
mymob = owner
@@ -243,8 +243,6 @@ datum/hud/New(mob/owner)
mymob.client.screen -= other
if(hotkeybuttons)
mymob.client.screen -= hotkeybuttons
if(item_action_list)
mymob.client.screen -= item_action_list
//These ones are not a part of 'adding', 'other' or 'hotkeybuttons' but we want them gone.
mymob.client.screen -= mymob.zone_sel //zone_sel is a mob variable for some reason.
@@ -269,8 +267,6 @@ datum/hud/New(mob/owner)
mymob.client.screen -= other
if(hotkeybuttons)
mymob.client.screen -= hotkeybuttons
if(item_action_list)
mymob.client.screen -= item_action_list
//These ones are not a part of 'adding', 'other' or 'hotkeybuttons' but we want them gone.
mymob.client.screen -= mymob.zone_sel //zone_sel is a mob variable for some reason.
-47
View File
@@ -323,50 +323,3 @@
else
client.screen -= hud_used.hotkeybuttons
hud_used.hotkey_ui_hidden = 1
/mob/living/carbon/human/update_action_buttons()
var/num = 1
if(!hud_used) return
if(!client) return
if(hud_used.hud_shown != 1) //Hud toggled to minimal
return
client.screen -= hud_used.item_action_list
for(var/obj/item/I in src)
if(I.action_button_name)
if(hud_used.item_action_list.len < num)
var/obj/screen/item_action/N = new(hud_used)
hud_used.item_action_list += N
var/obj/screen/item_action/A = hud_used.item_action_list[num]
A.icon = ui_style2icon(client.prefs.UI_style)
A.icon_state = "template"
A.overlays = list()
var/image/img = image(I.icon, A, I.icon_state)
img.pixel_x = 0
img.pixel_y = 0
A.overlays += img
A.name = I.action_button_name
A.owner = I
client.screen += hud_used.item_action_list[num]
switch(num)
if(1)
A.screen_loc = ui_action_slot1
if(2)
A.screen_loc = ui_action_slot2
if(3)
A.screen_loc = ui_action_slot3
if(4)
A.screen_loc = ui_action_slot4
if(5)
A.screen_loc = ui_action_slot5
break //5 slots available, so no more can be added.
num++
+2 -1
View File
@@ -10,7 +10,7 @@
/obj/screen/movable
var/snap2grid = FALSE
var/moved = FALSE
//Snap Screen Object
//Tied to the grid, snaps to the nearest turf
@@ -43,6 +43,7 @@
var/pix_Y = text2num(screen_loc_Y[2]) - 16
screen_loc = "[screen_loc_X[1]]:[pix_X],[screen_loc_Y[1]]:[pix_Y]"
moved = TRUE
//Debug procs
+9 -29
View File
@@ -42,32 +42,6 @@
return 1
/obj/screen/item_action
var/obj/item/owner
/obj/screen/item_action/Click()
if(!usr || !owner)
return 1
if(usr.next_move >= world.time)
return
if(!owner.action_button_is_hands_free && (usr.restrained() || usr.stunned || usr.lying))
return 1
if(usr.stat)
return 1
if(!(owner in usr))
return 1
owner.ui_action_click()
return 1
//This is the proc used to update all the action buttons. It just returns for all mob types except humans.
/mob/proc/update_action_buttons()
return
/obj/screen/drop
name = "drop"
icon = 'icons/mob/screen_midnight.dmi'
@@ -126,13 +100,19 @@
if(!C.incapacitated())
if(C.internal)
C.internal = null
C << "<span class='notice'>No longer running on internals.</span>"
C << "<span class='notice'>You are no longer running on internals.</span>"
icon_state = "internal0"
else
if(!istype(C.wear_mask, /obj/item/clothing/mask))
C << "<span class='notice'>You are not wearing a mask.</span>"
C << "<span class='warning'>You are not wearing an internals mask!</span>"
return 1
else
var/obj/item/clothing/mask/M = C.wear_mask
if(M.mask_adjusted) // if mask on face but pushed down
M.adjustmask(C) // adjust it back
if( !(M.flags & MASKINTERNALS) )
C << "<span class='warning'>You are not wearing an internals mask!</span>"
return
if(istype(C.l_hand, /obj/item/weapon/tank))
C << "<span class='notice'>You are now running on internals from the [C.l_hand] on your left hand.</span>"
C.internal = C.l_hand
@@ -162,7 +142,7 @@
if(C.internal)
icon_state = "internal1"
else
C << "<span class='notice'>You don't have an oxygen tank.</span>"
C << "<span class='warning'>You don't have an oxygen tank!</span>"
/obj/screen/mov_intent
name = "run/walk toggle"
+5 -3
View File
@@ -11,6 +11,8 @@
user.do_attack_animation(src)
if(W && !(W.flags&NOBLUDGEON))
visible_message("<span class='danger'>[user] has hit [src] with [W].</span>")
user << "<span class='danger'>You hit [src] with [W].</span>"
src << "<span class='userdanger'>[user] has hit you with [W]!</span>"
/mob/living/attackby(obj/item/I, mob/user, params)
user.changeNext_move(CLICK_CD_MELEE)
@@ -42,12 +44,12 @@
/mob/living/simple_animal/attacked_by(var/obj/item/I, var/mob/living/user)
if(!I.force)
user.visible_message("<span class='warning'>[user] gently taps [src] with [I].</span>",\
"<span class='warning'>This weapon is ineffective, it does no damage.</span>")
"<span class='warning'>This weapon is ineffective, it does no damage!</span>")
else if(I.force >= force_threshold && I.damtype != STAMINA)
..()
else
visible_message("<span class='danger'>[I] bounces harmlessly off of [src].</span>",\
"<span class='userdanger'>[I] bounces harmlessly off of [src].</span>")
visible_message("<span class='warning'>[I] bounces harmlessly off of [src].</span>",\
"<span class='warning'>[I] bounces harmlessly off of [src]!</span>")
+4
View File
@@ -42,6 +42,10 @@
for(var/datum/mutation/human/HM in dna.mutations)
HM.on_ranged_attack(src, A)
var/turf/T = A
if(istype(T) && get_dist(src,T) <= 1)
src.Move_Pulled(T)
/*
Animals & All Unspecified
*/
-308
View File
@@ -1,308 +0,0 @@
/*
Modified DynamicAreaLighting for TGstation - Coded by Carnwennan
This is TG's 'new' lighting system. It's basically a heavily modified combination of Forum_Account's and
ShadowDarke's respective lighting libraries. Credits, where due, to them.
Like sd_DAL (what we used to use), it changes the shading overlays of areas by splitting each type of area into sub-areas
by using the var/tag variable and moving turfs into the contents list of the correct sub-area. This method is
much less costly than using overlays or objects.
Unlike sd_DAL however it uses a queueing system. Everytime we call a change to opacity or luminosity
(through SetOpacity() or SetLuminosity()) we are simply updating variables and scheduling certain lights/turfs for an
update. Actual updates are handled periodically by the SSlighting subsystem. This carries additional overheads, however it
means that each thing is changed only once per SSlighting.wait deciseconds. Allowing for greater control
over how much priority we'd like lighting updates to have.
UPDATE: we no longer postpone lighting updates by editting variables, there is now a subsystem/proc/postpone() procedure.
So you would do SSlighting.postpone()
Unlike our old system there are hardcoded maximum luminositys (different for certain atoms).
This is to cap the cost of creating lighting effects.
(without this, an atom with luminosity of 20 would have to update 41^2 turfs!) :s
Also, in order for the queueing system to work, each light remembers the effect it casts on each turf. This is going to
have larger memory requirements than our previous system but it's easily worth the hassle for the greater control we
gain. It also reduces cost of removing lighting effects by a lot!
Known Issues/TODO:
Shuttles still do not have support for dynamic lighting (I hope to fix this at some point)
No directional lighting support. (prototype looked ugly)
*/
#define USE_CIRCULAR_LIGHTING //comment this out to use old square lighting effects.
/datum/light_source
var/atom/owner
var/changed = 1
var/list/effect = list()
var/__x = 0 //x coordinate at last update
var/__y = 0 //y coordinate at last update
/datum/light_source/New(atom/A)
if(!istype(A))
CRASH("The first argument to the light object's constructor must be the atom that is the light source. Expected atom, received '[A]' instead.")
..()
owner = A
__x = owner.x
__y = owner.y
// the lighting object maintains a list of all light sources
SSlighting.lights += src
//Check a light to see if its effect needs reprocessing. If it does, remove any old effect and create a new one
/datum/light_source/proc/check()
if(!owner)
remove_effect()
return 1 //causes it to be removed from our list of lights. The garbage collector will then destroy it.
// check to see if we've moved since last update
if(owner.x != __x || owner.y != __y)
__x = owner.x
__y = owner.y
changed = 1
if(changed)
changed = 0
remove_effect()
return add_effect()
return 0
/datum/light_source/proc/remove_effect()
// before we apply the effect we remove the light's current effect.
for(var/turf/T in effect) // negate the effect of this light source
T.update_lumcount(-effect[T])
if(T.affecting_lights && T.affecting_lights.len)
T.affecting_lights -= src
else
T.affecting_lights = null
effect.Cut() // clear the effect list
/datum/light_source/proc/add_effect()
// only do this if the light is turned on and is on the map
if(owner.loc && owner.luminosity > 0)
effect = list()
var/turf/To = get_turf(owner)
var/range = owner.get_light_range()
for(var/turf/T in view(range, To))
var/delta_lumcount = T.lumen(src)
if(delta_lumcount > 0)
effect[T] = delta_lumcount
T.update_lumcount(delta_lumcount)
if(!T.affecting_lights)
T.affecting_lights = list()
T.affecting_lights += src
return 0
else
owner.light = null
return 1 //cause the light to be removed from the lights list and garbage collected once it's no
//longer referenced by the queue
/turf/proc/lumen(datum/light_source/L)
. = L.owner.luminosity
#ifdef USE_CIRCULAR_LIGHTING
. -= cheap_hypotenuse(x, y, L.__x, L.__y)
#else
. -= max(abs(x - L.__x), abs(y - L.__y))
#endif
return .
/turf/space/lumen()
return 0
/atom
var/datum/light_source/light
//Turfs with opacity when they are constructed will trigger nearby lights to update
//Turfs and atoms with luminosity when they are constructed will create a light_source automatically
/turf/New()
..()
if(luminosity)
if(light) WARNING("[type] - Don't set lights up manually during New(), We do it automatically.")
light = new(src)
//Movable atoms with opacity when they are constructed will trigger nearby lights to update
//Movable atoms with luminosity when they are constructed will create a light_source automatically
/atom/movable/New()
..()
if(opacity)
UpdateAffectingLights()
if(luminosity)
if(light) WARNING("[type] - Don't set lights up manually during New(), We do it automatically.")
light = new(src)
//Objects with opacity will trigger nearby lights to update at next lighting process.
/atom/movable/Destroy()
if(opacity)
UpdateAffectingLights()
return ..()
//Sets our luminosity.
//If we have no light it will create one.
//If we are setting luminosity to 0 the light will be cleaned up by the controller and garbage collected once all its
//queues are complete.
//if we have a light already it is merely updated, rather than making a new one.
/atom/proc/SetLuminosity(new_luminosity)
if(new_luminosity < 0)
new_luminosity = 0
if(light)
if(luminosity != new_luminosity) //non-luminous lights are removed from the lights list in add_effect()
light.changed = 1
else
if(new_luminosity)
light = new(src)
luminosity = new_luminosity
/atom/proc/AddLuminosity(delta_luminosity)
SetLuminosity(luminosity + delta_luminosity)
/area/SetLuminosity(new_luminosity) //we don't want dynamic lighting for areas
luminosity = !!new_luminosity
//change our opacity (defaults to toggle), and then update all lights that affect us.
/atom/proc/SetOpacity(new_opacity)
if(new_opacity == null)
new_opacity = !opacity //default = toggle opacity
else if(opacity == new_opacity)
return 0 //opacity hasn't changed! don't bother doing anything
opacity = new_opacity //update opacity, the below procs now call light updates.
UpdateAffectingLights()
/turf
var/lighting_lumcount = 0
var/lighting_changed = 0
var/list/affecting_lights //not initialised until used (even empty lists reserve a fair bit of memory)
/turf/space
lighting_lumcount = 4 //starlight
/turf/proc/update_lumcount(amount)
lighting_lumcount += amount
if(!lighting_changed)
SSlighting.changed_turfs += src
lighting_changed = 1
/area/proc/lighting_tag(level)
return tagbase + "sd_L[level]"
/area/proc/build_lighting_area(tag, level)
var/area/A = locate(tag) // find an appropriate area
if(A)
return A
A = new type() // create area if it wasn't found
// replicate vars
for(var/V in vars)
switch(V)
if("contents","last_light","overlays") continue
else
if(issaved(vars[V])) A.vars[V] = vars[V]
A.tag = tag
A.lighting_subarea = 1
A.lighting_space = 0 // in case it was copied from a space subarea
A.SetLightLevel(level)
related += A
return A
/turf/proc/shift_to_subarea()
lighting_changed = 0
var/area/Area = loc
if(!istype(Area) || !Area.lighting_use_dynamic) return
var/level = min(max(round(lighting_lumcount,1),0),SSlighting.lighting_images.len)
var/new_tag = Area.lighting_tag(level)
if(Area.tag!=new_tag) //skip if already in this area
var/area/A = Area.build_lighting_area(new_tag,level)
A.contents += src // move the turf into the area
/area
var/lighting_use_dynamic = 1 //Turn this flag off to prevent sd_DynamicAreaLighting from affecting this area
var/last_light //tracks the last light level set for this area (used for removing previously applied lighting overlays)
var/lighting_subarea = 0 //tracks whether we're a lighting sub-area
var/lighting_space = 0 // true for space-only lighting subareas
var/tagbase
/area/proc/SetLightLevel(light)
if(!src) return
if(light <= 1)
light = 1
luminosity = 0
else
if(light > SSlighting.lighting_images.len)
light = SSlighting.lighting_images.len
luminosity = 1
if(last_light != light)
if(last_light)
overlays -= SSlighting.lighting_images[last_light]
overlays += SSlighting.lighting_images[light]
last_light = light
/area/proc/SetDynamicLighting()
lighting_use_dynamic = 1
for(var/turf/T in contents)
T.update_lumcount(0)
/area/proc/InitializeLighting() //TODO: could probably improve this bit ~Carn
tagbase = "[type]"
if(!tag) tag = tagbase
if(!lighting_use_dynamic)
if(!lighting_subarea) // see if this is a lighting subarea already
//show the dark overlay so areas, not yet in a lighting subarea, won't be bright as day and look silly.
SetLightLevel(4)
#undef USE_CIRCULAR_LIGHTING
//set the changed status of all lights which could have possibly lit this atom.
//We don't need to worry about lights which lit us but moved away, since they will have change status set already
//This proc can cause lots of lights to be updated. :(
/atom/proc/UpdateAffectingLights()
/atom/movable/UpdateAffectingLights()
if(isturf(loc))
loc.UpdateAffectingLights()
/turf/UpdateAffectingLights()
if(affecting_lights)
for(var/thing in affecting_lights)
thing:changed = 1 //force it to update at next process()
#define LIGHTING_MAX_LUMINOSITY_STATIC 8 //Maximum luminosity to reduce lag.
#define LIGHTING_MAX_LUMINOSITY_MOBILE 5 //Moving objects have a lower max luminosity since these update more often. (lag reduction)
#define LIGHTING_MAX_LUMINOSITY_MOB 5
#define LIGHTING_MAX_LUMINOSITY_TURF 1 //turfs have a severely shortened range to protect from inevitable floor-lighttile spam.
//caps luminosity effects max-range based on what type the light's owner is.
/atom/proc/get_light_range()
return min(luminosity, LIGHTING_MAX_LUMINOSITY_STATIC)
/atom/movable/get_light_range()
return min(luminosity, LIGHTING_MAX_LUMINOSITY_MOBILE)
/mob/get_light_range()
return min(luminosity, LIGHTING_MAX_LUMINOSITY_MOB)
/obj/machinery/light/get_light_range()
return min(luminosity, LIGHTING_MAX_LUMINOSITY_STATIC)
/turf/get_light_range()
return min(luminosity, LIGHTING_MAX_LUMINOSITY_TURF)
#undef LIGHTING_MAX_LUMINOSITY_STATIC
#undef LIGHTING_MAX_LUMINOSITY_MOBILE
#undef LIGHTING_MAX_LUMINOSITY_MOB
#undef LIGHTING_MAX_LUMINOSITY_TURF
+17 -18
View File
@@ -92,23 +92,20 @@
var/traitor_scaling_coeff = 6 //how much does the amount of players get divided by to determine traitors
var/changeling_scaling_coeff = 6 //how much does the amount of players get divided by to determine changelings
var/security_scaling_coeff = 8 //how much does the amount of players get divided by to determine open security officer positions
var/abductor_scaling_coeff = 15 //how many players per abductor team
var/traitor_objectives_amount = 2
var/protect_roles_from_antagonist = 0 //If security and such can be traitor/cult/other
var/protect_assistant_from_antagonist = 0 //If assistants can be traitor/cult/other
var/enforce_human_authority = 0 //If non-human species are barred from joining as a head of staff
var/allow_latejoin_antagonists = 0 // If late-joining players can be traitor/changeling
var/continuous_round_rev = 0 // Gamemodes which end instantly will instead keep on going until the round ends by escape shuttle or nuke.
var/continuous_round_gang = 0
var/continuous_round_wiz = 0
var/continuous_round_malf = 0
var/continuous_round_blob = 0
var/list/continuous = list() // which roundtypes continue if all antagonists die
var/list/midround_antag = list() // which roundtypes use the midround antagonist system
var/midround_antag_time_check = 60 // How late (in minutes) you want the midround antag system to stay on, setting this to 0 will disable the system
var/midround_antag_life_check = 0.7 // A ratio of how many people need to be alive in order for the round not to immediately end in midround antagonist
var/shuttle_refuel_delay = 12000
var/show_game_type_odds = 0 //if set this allows players to see the odds of each roundtype on the get revision screen
var/mutant_races = 0 //players can choose their mutant race before joining the game
var/mutant_colors = 0
var/no_summon_guns //No
var/no_summon_magic //Fun
@@ -397,16 +394,18 @@
config.sec_start_brig = 1
if("gateway_delay")
config.gateway_delay = text2num(value)
if("continuous_round_rev")
config.continuous_round_rev = 1
if("continuous_round_gang")
config.continuous_round_gang = 1
if("continuous_round_wiz")
config.continuous_round_wiz = 1
if("continuous_round_malf")
config.continuous_round_malf = 1
if("continuous_round_blob")
config.continuous_round_blob = 1
if("continuous")
var/mode_name = lowertext(value)
if(mode_name in config.modes)
config.continuous[mode_name] = 1
else
diary << "Unknown continuous configuration definition: [mode_name]."
if("midround_antag")
var/mode_name = lowertext(value)
if(mode_name in config.modes)
config.midround_antag[mode_name] = 1
else
diary << "Unknown midround antagonist configuration definition: [mode_name]."
if("midround_antag_time_check")
config.midround_antag_time_check = text2num(value)
if("midround_antag_life_check")
@@ -423,6 +422,8 @@
config.changeling_scaling_coeff = text2num(value)
if("security_scaling_coeff")
config.security_scaling_coeff = text2num(value)
if("abductor_scaling_coeff")
config.abductor_scaling_coeff = text2num(value)
if("traitor_objectives_amount")
config.traitor_objectives_amount = text2num(value)
if("probability")
@@ -472,8 +473,6 @@
config.silicon_max_law_amount = text2num(value)
if("join_with_mutant_race")
config.mutant_races = 1
if("mutant_colors")
config.mutant_colors = 1
if("assistant_cap")
config.assistant_cap = text2num(value)
if("starlight")
+2 -1
View File
@@ -82,7 +82,8 @@ var/datum/subsystem/garbage_collector/SSgarbage
// Return true if the the GC controller should allow the object to continue existing. (Useful if pooling objects.)
/datum/proc/Destroy()
//del(src)
return
tag = null
return 0
/datum/var/gc_destroyed //Time when this object was destroyed.
+44 -54
View File
@@ -1,56 +1,50 @@
var/datum/subsystem/lighting/SSlighting
#define MC_AVERAGE(average, current) (0.8*(average) + 0.2*(current))
#define LIGHTING_ICON 'icons/effects/ss13_dark_alpha6.dmi'
#define LIGHTING_LAYER 10 //Drawing layer for lighting overlays
/datum/subsystem/lighting
name = "Lighting"
wait = 5
priority = 1
var/list/lighting_images = list() //replaces lighting_states (use lighting_images.len) ~carn
var/list/lights = list() //list of all datum/light_source
var/lights_workload = 0 //stats on the largest number of lights (max lights.len)
var/list/changed_turfs = list() //list of all turfs which need moving to a new lighting subarea
var/list/changed_lights = list() //list of all datum/light_source that need updating
var/changed_lights_workload = 0 //stats on the largest number of lights (max changed_lights.len)
var/list/changed_turfs = list() //list of all turfs which may have a different light level
var/changed_turfs_workload = 0 //stats on the largest number of turfs changed (max changed_turfs.len)
/datum/subsystem/lighting/New()
NEW_SS_GLOBAL(SSlighting)
//cache lighting images
if(!lighting_images.len)
for(var/icon_state in icon_states(LIGHTING_ICON))
lighting_images += image(LIGHTING_ICON, null, icon_state, LIGHTING_LAYER)
return ..()
/datum/subsystem/lighting/stat_entry()
stat(name, "[round(cost,0.001)]ds (CPU:[round(cpu,1)]%) L:[round(lights_workload,1)]/T:[round(changed_turfs_workload,1)]")
stat(name, "[round(cost,0.001)]ds (CPU:[round(cpu,1)]%) L:[round(changed_lights_workload,1)]/T:[round(changed_turfs_workload,1)]")
//Workhorse of lighting. It cycles through each light to see which ones need their effects updating. It updates their
//effects and then processes every turf in the queue, moving the turfs to the corresponing lighting sub-area.
//All queue lists prune themselves, which will cause lights with no luminosity to be garbage collected (cheaper and safer
//than deleting them).
//Workhorse of lighting. It cycles through each light that needs updating. It updates their
//effects and then processes every turf in the queue, updating their lighting object's appearance
//Any light that returns 1 in check() deletes itself
//By using queues we are ensuring we don't perform more updates than are necessary
/datum/subsystem/lighting/fire()
lights_workload = MC_AVERAGE(lights_workload, lights.len)
var/i=1
for(var/thing in lights)
if(thing && !thing:check()) //yes, cry that I'm using the : operator, it's much faster looping like this. And this gets called a lot. Dealwithit.
++i
continue
lights.Cut(i, i+1)
changed_lights_workload = MC_AVERAGE(changed_lights_workload, changed_lights.len)
// for(var/area/A in sortedAreas)
// A.luminosity = 1
for(var/datum/light_source/thing in changed_lights)
thing.check()
changed_lights.Cut()
changed_turfs_workload = MC_AVERAGE(changed_turfs_workload, changed_turfs.len)
for(var/thing in changed_turfs)
if(thing && thing:lighting_changed)
thing:shift_to_subarea()
for(var/turf/thing in changed_turfs)
if(thing && thing.lighting_changed)
thing.redraw_lighting()
changed_turfs.Cut()
// for(var/area/A in sortedAreas)
// A.luminosity = !A.lighting_use_dynamic
//same as above except it attempts to shift ALL turfs in the world regardless of lighting_changed status
//Does not loop. Should be run prior to process() being called for the first time.
@@ -58,12 +52,13 @@ var/datum/subsystem/lighting/SSlighting
//z-levels with the z_level argument
/datum/subsystem/lighting/Initialize(timeofday, z_level)
var/i=1
for(var/thing in lights)
if(thing && !thing:check())
++i
continue
lights.Cut(i, i+1)
// for(var/area/A in sortedAreas)
// A.luminosity = 1
for(var/datum/light_source/thing in changed_lights)
thing.add_effect()
thing.changed = 0
changed_lights.Cut()
var/z_start = 1
var/z_finish = world.maxz
@@ -72,28 +67,24 @@ var/datum/subsystem/lighting/SSlighting
z_start = z_level
z_finish = z_level
for(var/z=z_start, z<=z_finish, ++z)
for(var/x=1, x<=world.maxx, ++x)
for(var/y=1, y<=world.maxy, ++y)
var/turf/T = locate(x,y,z)
if(T)
T.shift_to_subarea()
var/list/turfs_to_init = block(locate(1, 1, z_start), locate(world.maxx, world.maxy, z_finish))
for(var/turf/T in turfs_to_init)
T.init_lighting()
if(z_level)
//we need to loop through to clear only shifted turfs from the list. or we will cause errors
i=1
for(var/thing in changed_turfs)
if(thing && thing:z < z_start && z_finish < thing:z)
var/i=1
for(var/turf/thing in changed_turfs)
if(thing && thing.z < z_start && z_finish < thing.z)
++i
continue
changed_turfs.Cut(i, i+1)
else
changed_turfs.Cut()
if(config.starlight)
set background = 1
for(var/turf/space/S in world)
S.update_starlight()
// for(var/area/A in sortedAreas)
// A.luminosity = !A.lighting_use_dynamic
..()
@@ -103,21 +94,20 @@ var/datum/subsystem/lighting/SSlighting
/datum/subsystem/lighting/Recover()
if(!istype(SSlighting.changed_turfs))
SSlighting.changed_turfs = list()
if(!istype(SSlighting.lights))
SSlighting.lights = list()
if(!istype(SSlighting.changed_lights))
SSlighting.changed_lights = list()
if(istype(SSlighting.lighting_images))
lighting_images = SSlighting.lighting_images
// for(var/area/A in sortedAreas)
// A.luminosity = 1
for(var/datum/light_source/L in SSlighting.lights)
for(var/datum/light_source/L in SSlighting.changed_lights)
spawn(-1) //so we don't crash the loop (inefficient)
L.check()
lights += L //If we didn't runtime then this will get transferred over
for(var/turf/T in changed_turfs)
if(T.lighting_changed)
spawn(-1)
T.shift_to_subarea()
T.redraw_lighting()
var/msg = "## DEBUG: [time2text(world.timeofday)] [name] subsystem restarted. Reports:\n"
for(var/varname in SSlighting.vars)
@@ -132,5 +122,5 @@ var/datum/subsystem/lighting/SSlighting
msg += "\t [varname] = [varval1] -> [varval2]\n"
world.log << msg
#undef LIGHTING_ICON
#undef LIGHTING_LAYER
// for(var/area/A in sortedAreas)
// A.luminosity = !A.lighting_use_dynamic
+1 -1
View File
@@ -110,7 +110,7 @@ var/datum/subsystem/npcpool/SSbp
if(needsHelp_non.len)
for(var/obj/machinery/bot/B in needsHelp_non)
if(canBeUsed_non.len)
var/obj/machinery/bot/candidate = pick(canBeUsed_non.len)
var/obj/machinery/bot/candidate = pick(canBeUsed_non)
candidate.call_bot(B,get_turf(B),FALSE)
canBeUsed_non -= B
needsHelp_non -= candidate
+3
View File
@@ -17,6 +17,7 @@ var/datum/subsystem/ticker/ticker
var/event = 0
var/login_music //music played in pregame lobby
var/round_end_sound //music/jingle played when the world reboots
var/list/datum/mind/minds = list() //The characters in the game. Used for objective tracking.
@@ -50,6 +51,8 @@ var/datum/subsystem/ticker/ticker
if(SSevent.holidays && SSevent.holidays[APRIL_FOOLS])
login_music = 'sound/ambience/clown.ogg'
round_end_sound = pick('sound/AI/newroundsexy.ogg','sound/misc/apcdestroyed.ogg','sound/misc/bangindonk.ogg','sound/misc/leavingtg.ogg')
/datum/subsystem/ticker/Initialize()
if(!syndicate_code_phrase) syndicate_code_phrase = generate_code_phrase()
if(!syndicate_code_response) syndicate_code_response = generate_code_phrase()
+1
View File
@@ -70,6 +70,7 @@
return {"<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<head>
[head_content]
</head>
+7
View File
@@ -38,6 +38,7 @@
DD.holder = src
if(DD.disease_flags & CAN_CARRY && prob(5))
DD.carrier = 1
DD.strain_data = D.strain_data.Copy()
DD.affected_mob.med_hud_set_status()
@@ -127,3 +128,9 @@
if(!CanContractDisease(D))
return 0
AddDisease(D)
/mob/living/carbon/human/CanContractDisease(var/datum/disease/D)
if(dna && VIRUSIMMUNE in dna.species.specflags)
return 0
return ..()
+3 -1
View File
@@ -179,7 +179,9 @@ var/list/diseases = typesof(/datum/disease) - /datum/disease
/datum/disease/proc/Copy()
return new type()
var/datum/disease/D = new type()
D.strain_data = strain_data.Copy()
return D
/datum/disease/proc/GetDiseaseID()
+1 -1
View File
@@ -13,7 +13,7 @@ var/list/archive_diseases = list()
var/list/advance_cures = list(
"nutriment", "sugar", "orangejuice",
"spaceacillin", "salglu_solution", "ethanol",
"leporazine", "synaptizine", "lipozine",
"leporazine", "synaptizine", "lipolicide",
"silver", "gold"
)
@@ -31,10 +31,10 @@ Bonus
var/mob/living/M = A.affected_mob
switch(A.stage)
if(3, 4)
M << "<span class='notice'>[pick("You hear a ringing in your ear.", "Your ears pop.")]</span>"
M << "<span class='italics'>[pick("You hear a ringing in your ear.", "Your ears pop.")]</span>"
if(5)
if(!(M.ear_deaf))
M << "<span class='danger'>Your ears pop and begin ringing loudly!</span>"
M << "<span class='userdanger'>Your ears pop and begin ringing loudly!</span>"
M.setEarDamage(-1,INFINITY) //Shall be enough
spawn(200)
if(M)
+1 -1
View File
@@ -16,7 +16,7 @@
switch(stage)
if(2) //also changes say, see say.dm
if(prob(5))
affected_mob << "<span class='notice'>Your feel anxious.</span>"
affected_mob << "<span class='notice'>You feel anxious.</span>"
if(3)
if(prob(10))
affected_mob << "<span class='notice'>Your stomach flutters.</span>"
+27 -19
View File
@@ -8,7 +8,7 @@
disease_flags = CAN_CARRY|CAN_RESIST
agent = "S4E1 retrovirus"
viable_mobtypes = list(/mob/living/carbon/human)
var/list/original_dna = list()
var/datum/dna/original_dna = null
var/transformed = 0
desc = "This disease transplants the genetic code of the intial vector into new hosts."
severity = MEDIUM
@@ -16,6 +16,17 @@
/datum/disease/dnaspread/stage_act()
..()
if(!affected_mob.dna)
cure()
if(!strain_data["dna"])
//Absorbs the target DNA.
strain_data["dna"] = new affected_mob.dna.type
affected_mob.dna.copy_dna(strain_data["dna"])
src.carrier = 1
src.stage = 4
return
switch(stage)
if(2 || 3) //Pretend to be a cold and give time to spread.
if(prob(8))
@@ -32,21 +43,18 @@
affected_mob.adjustToxLoss(2)
affected_mob.updatehealth()
if(4)
if(!src.transformed)
if ((!strain_data["name"]) || (!strain_data["UI"]) || (!strain_data["SE"]))
del(affected_mob.virus)
return
if(!src.transformed && !src.carrier)
//Save original dna for when the disease is cured.
src.original_dna["name"] = affected_mob.real_name
src.original_dna["UI"] = affected_mob.dna.uni_identity
src.original_dna["SE"] = affected_mob.dna.struc_enzymes
original_dna = new affected_mob.dna.type
affected_mob.dna.copy_dna(original_dna)
affected_mob << "<span class='danger'>You don't feel like yourself..</span>"
affected_mob.dna.uni_identity = strain_data["UI"]
var/datum/dna/transform_dna = strain_data["dna"]
transform_dna.transfer_identity(affected_mob)
affected_mob.real_name = affected_mob.dna.real_name
updateappearance(affected_mob)
affected_mob.dna.struc_enzymes = strain_data["SE"]
affected_mob.real_name = strain_data["name"]
domutcheck(affected_mob)
src.transformed = 1
@@ -55,12 +63,12 @@
return
/datum/disease/dnaspread/Del()
if ((original_dna["name"]) && (original_dna["UI"]) && (original_dna["SE"]))
if(affected_mob)
affected_mob.dna.uni_identity = original_dna["UI"]
updateappearance(affected_mob)
affected_mob.dna.struc_enzymes = original_dna["SE"]
affected_mob.real_name = original_dna["name"]
if (original_dna && transformed && affected_mob)
original_dna.transfer_identity(affected_mob)
affected_mob.real_name = affected_mob.dna.real_name
affected_mob << "<span class='notice'>You feel more like yourself.</span>"
updateappearance(affected_mob)
domutcheck(affected_mob)
affected_mob << "<span class='notice'>You feel more like yourself.</span>"
..()
+2 -1
View File
@@ -9,6 +9,7 @@
severity = HARMFUL
stage_prob = 10
visibility_flags = HIDDEN_SCANNER|HIDDEN_PANDEMIC
disease_flags = CURABLE
var/list/stage1 = list("You feel unremarkable.")
var/list/stage2 = list("You feel boring.")
var/list/stage3 = list("You feel utterly plain.")
@@ -202,7 +203,7 @@
var/mob/living/carbon/human/human = affected_mob
if(human.dna && human.dna.species.id != "slime")
human.dna.species = new /datum/species/slime()
human.update_icons()
human.regenerate_icons()
/datum/disease/transformation/corgi
name = "The Barkening"
@@ -0,0 +1,15 @@
/datum/icon_snapshot
var/name
var/icon
var/icon_state
var/list/overlays
/datum/icon_snapshot/proc/makeImg()
if(!icon || !icon_state)
return
var/obj/temp = new
temp.icon = icon
temp.icon_state = icon_state
temp.overlays = overlays.Copy()
var/icon/tempicon = getFlatIcon(temp) // TODO Actually write something less heavy-handed for this
return tempicon
+1
View File
@@ -12,6 +12,7 @@ var/datum/atom_hud/huds = list( \
ANTAG_HUD_GANG_A = new/datum/atom_hud/antag(), \
ANTAG_HUD_GANG_B = new/datum/atom_hud/antag(), \
ANTAG_HUD_WIZ = new/datum/atom_hud/antag(), \
ANTAG_HUD_SHADOW = new/datum/atom_hud/antag(), \
)
/datum/atom_hud
+324
View File
@@ -0,0 +1,324 @@
/datum/martial_art
var/name = "Martial Art"
var/streak = ""
var/max_streak_length = 6
var/current_target = null
var/temporary = 0
var/datum/martial_art/base = null // The permanent style
/datum/martial_art/proc/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
return 0
/datum/martial_art/proc/harm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
return 0
/datum/martial_art/proc/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
return 0
/datum/martial_art/proc/add_to_streak(var/element,var/mob/living/carbon/human/D)
if(D != current_target)
current_target = D
streak = ""
streak = streak+element
if(length(streak) > max_streak_length)
streak = copytext(streak,2)
return
/datum/martial_art/proc/basic_hit(var/mob/living/carbon/human/A,var/mob/living/carbon/human/D)
add_logs(A, D, "punched")
A.do_attack_animation(D)
var/damage = rand(0,9)
var/atk_verb = "punch"
if(D.lying)
atk_verb = "kick"
else if(A.dna)
atk_verb = A.dna.species.attack_verb
if(A.dna)
damage += A.dna.species.punchmod
if(!damage)
if(A.dna)
playsound(D.loc, A.dna.species.miss_sound, 25, 1, -1)
else
playsound(D.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
D.visible_message("<span class='warning'>[A] has attempted to [atk_verb] [D]!</span>")
return 0
var/obj/item/organ/limb/affecting = D.get_organ(ran_zone(A.zone_sel.selecting))
var/armor_block = D.run_armor_check(affecting, "melee")
if(A.dna)
playsound(D.loc, A.dna.species.attack_sound, 25, 1, -1)
else
playsound(D.loc, 'sound/weapons/punch1.ogg', 25, 1, -1)
D.visible_message("<span class='danger'>[A] has [atk_verb]ed [D]!</span>", \
"<span class='userdanger'>[A] has [atk_verb]ed [D]!</span>")
D.apply_damage(damage, BRUTE, affecting, armor_block)
if((D.stat != DEAD) && damage >= 9)
D.visible_message("<span class='danger'>[A] has weakened [D]!!</span>", \
"<span class='userdanger'>[A] has weakened [D]!</span>")
D.apply_effect(4, WEAKEN, armor_block)
D.forcesay(hit_appends)
else if(D.lying)
D.forcesay(hit_appends)
return 1
/datum/martial_art/proc/teach(var/mob/living/carbon/human/H,var/make_temporary=0)
if(make_temporary)
temporary = 1
if(H.martial_art && H.martial_art.temporary)
if(temporary)
base = H.martial_art.base
else
H.martial_art.base = src //temporary styles have priority
return
H.martial_art = src
/datum/martial_art/proc/remove(var/mob/living/carbon/human/H)
if(H.martial_art != src)
return
H.martial_art = base
/datum/martial_art/boxing
name = "Boxing"
/datum/martial_art/boxing/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
A << "<span class='warning'> Can't disarm while boxing!</span>"
return 1
/datum/martial_art/boxing/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
A << "<span class='warning'> Can't grab while boxing!</span>"
return 1
/datum/martial_art/boxing/harm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
add_logs(A, D, "punched")
A.do_attack_animation(D)
var/atk_verb = pick("left hook","right hook","straight punch")
var/damage = rand(5,8)
if(A.dna)
damage += A.dna.species.punchmod
if(!damage)
if(A.dna)
playsound(D.loc, A.dna.species.miss_sound, 25, 1, -1)
else
playsound(D.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
D.visible_message("<span class='warning'>[A] has attempted to hit [D] with a [atk_verb]!</span>")
return 0
var/obj/item/organ/limb/affecting = D.get_organ(ran_zone(A.zone_sel.selecting))
var/armor_block = D.run_armor_check(affecting, "melee")
playsound(D.loc, 'sound/weapons/punch1.ogg', 25, 1, -1)
D.visible_message("<span class='danger'>[A] has hit [D] with a [atk_verb]!</span>", \
"<span class='userdanger'>[A] has hit [D] with a [atk_verb]!</span>")
D.apply_damage(damage, STAMINA, affecting, armor_block)
if(D.getStaminaLoss() > 50)
var/knockout_prob = D.getStaminaLoss() + rand(-15,15)
if((D.stat != DEAD) && prob(knockout_prob))
D.visible_message("<span class='danger'>[A] has knocked [D] out with a haymaker!</span>", \
"<span class='userdanger'>[A] has knocked [D] out with a haymaker!</span>")
D.apply_effect(10,WEAKEN,armor_block)
D.SetSleeping(5)
D.forcesay(hit_appends)
else if(D.lying)
D.forcesay(hit_appends)
return 1
/datum/martial_art/wrestling
name = "Wrestling"
/datum/martial_art/wrestling/harm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
D.grabbedby(A,1)
var/obj/item/weapon/grab/G = A.get_active_hand()
if(G && prob(50))
G.state = GRAB_AGGRESSIVE
D.visible_message("<span class='danger'>[A] has [D] in a clinch!</span>", \
"<span class='userdanger'>[A] has [D] in a clinch!</span>")
else
D.visible_message("<span class='danger'>[A] fails to get [D] in a clinch!</span>", \
"<span class='userdanger'>[A] fails to get [D] in a clinch!</span>")
return 1
/datum/martial_art/wrestling/proc/Suplex(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
add_logs(A, D, "suplexed")
D.visible_message("<span class='danger'>[A] suplexes [D]!</span>", \
"<span class='userdanger'>[A] suplexes [D]!</span>")
D.forceMove(A.loc)
var/armor_block = D.run_armor_check(null, "melee")
D.apply_damage(30, BRUTE, null, armor_block)
D.apply_effect(6, WEAKEN, armor_block)
A.SpinAnimation(10,1)
D.SpinAnimation(10,1)
spawn(3)
armor_block = A.run_armor_check(null, "melee")
A.apply_effect(4, WEAKEN, armor_block)
return
/datum/martial_art/wrestling/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
if(istype(A.get_inactive_hand(),/obj/item/weapon/grab))
var/obj/item/weapon/grab/G = A.get_inactive_hand()
if(G.affecting == D)
Suplex(A,D)
return 1
harm_act(A,D)
return 1
/datum/martial_art/wrestling/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
D.grabbedby(A,1)
D.visible_message("<span class='danger'>[A] holds [D] down!</span>", \
"<span class='userdanger'>[A] holds [D] down!</span>")
var/obj/item/organ/limb/affecting = D.get_organ(ran_zone(A.zone_sel.selecting))
var/armor_block = D.run_armor_check(affecting, "melee")
D.apply_damage(10, STAMINA, affecting, armor_block)
return 1
#define TORNADO_COMBO "HHD"
#define THROWBACK_COMBO "DHD"
#define PLASMA_COMBO "HDDDH"
/datum/martial_art/plasma_fist
name = "Plasma Fist"
/datum/martial_art/plasma_fist/proc/check_streak(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
if(findtext(streak,TORNADO_COMBO))
streak = ""
Tornado(A,D)
return 1
if(findtext(streak,THROWBACK_COMBO))
streak = ""
Throwback(A,D)
return 1
if(findtext(streak,PLASMA_COMBO))
streak = ""
Plasma(A,D)
return 1
return 0
/datum/martial_art/plasma_fist/proc/Tornado(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
A.say("TORNADO SWEEP!")
spawn(0)
for(var/i in list(NORTH,SOUTH,EAST,WEST,EAST,SOUTH,NORTH,SOUTH,EAST,WEST,EAST,SOUTH))
A.dir = i
playsound(A.loc, 'sound/weapons/punch1.ogg', 15, 1, -1)
sleep(1)
var/obj/effect/proc_holder/spell/aoe_turf/repulse/R = new(null)
var/list/turfs = list()
for(var/turf/T in range(1,A))
turfs.Add(T)
R.cast(turfs)
return
/datum/martial_art/plasma_fist/proc/Throwback(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
D.visible_message("<span class='danger'>[A] has hit [D] with Plasma Punch!</span>", \
"<span class='userdanger'>[A] has hit [D] with Plasma Punch!</span>")
playsound(D.loc, 'sound/weapons/punch1.ogg', 50, 1, -1)
var/atom/throw_target = get_edge_target_turf(D, get_dir(D, get_step_away(D, A)))
D.throw_at(throw_target, 200, 4)
A.say("HYAH!")
return
/datum/martial_art/plasma_fist/proc/Plasma(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
A.do_attack_animation(D)
playsound(D.loc, 'sound/weapons/punch1.ogg', 50, 1, -1)
A.say("PLASMA FIST!")
D.visible_message("<span class='danger'>[A] has hit [D] with THE PLASMA FIST TECHNIQUE!</span>", \
"<span class='userdanger'>[A] has hit [D] with THE PLASMA FIST TECHNIQUE!</span>")
var/obj/item/organ/brain/B = D.getorgan(/obj/item/organ/brain)
if(B)
B.loc = get_turf(D)
B.transfer_identity(D)
D.internal_organs -= B
D.gib()
return
/datum/martial_art/plasma_fist/harm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
add_to_streak("H")
if(check_streak(A,D))
return 1
basic_hit(A,D)
return 1
/datum/martial_art/plasma_fist/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
add_to_streak("D")
if(check_streak(A,D))
return 1
basic_hit(A,D)
return 1
/datum/martial_art/plasma_fist/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
add_to_streak("G")
if(check_streak(A,D))
return 1
basic_hit(A,D)
return 1
//ITEMS
/obj/item/clothing/gloves/boxing
var/datum/martial_art/boxing/style = new
/obj/item/clothing/gloves/boxing/equipped(mob/user, slot)
if(!ishuman(user))
return
if(slot == slot_gloves)
var/mob/living/carbon/human/H = user
style.teach(H,1)
return
/obj/item/clothing/gloves/boxing/dropped(mob/user)
if(!ishuman(user))
return
var/mob/living/carbon/human/H = user
if(H.get_item_by_slot(slot_gloves) == src)
style.remove(H)
return
/obj/item/weapon/storage/belt/champion/wrestling
name = "Wrestling Belt"
var/datum/martial_art/wrestling/style = new
/obj/item/weapon/storage/belt/champion/wrestling/equipped(mob/user, slot)
if(!ishuman(user))
return
if(slot == slot_belt)
var/mob/living/carbon/human/H = user
style.teach(H,1)
return
/obj/item/weapon/storage/belt/champion/wrestling/dropped(mob/user)
if(!ishuman(user))
return
var/mob/living/carbon/human/H = user
if(H.get_item_by_slot(slot_belt) == src)
style.remove(H)
return
/obj/item/weapon/plasma_fist_scroll
name = "Plasma Fist Scroll"
desc = "Teaches the traditional wizard martial art."
icon = 'icons/obj/wizard.dmi'
icon_state ="scroll2"
var/used = 0
/obj/item/weapon/plasma_fist_scroll/attack_self(mob/user as mob)
if(!ishuman(user))
return
if(!used)
var/mob/living/carbon/human/H = user
var/datum/martial_art/plasma_fist/F = new/datum/martial_art/plasma_fist(null)
F.teach(H)
H << "<span class='notice'>You learn the PLASMA FIST style</span>"
used = 1
desc += "It looks like it's magic was used up."
+117 -47
View File
@@ -80,6 +80,7 @@
current = new_character //associate ourself with our new body
new_character.mind = src //and associate our new body with ourself
transfer_antag_huds(new_character) //inherit the antag HUDs from this mind (TODO: move this to a possible antag datum)
transfer_actions(new_character)
if(active)
new_character.key = key //now transfer the key to link the client to our new body
@@ -288,39 +289,26 @@
text += "<br>Equipment: <a href='?src=\ref[src];gang=equip'>give</a>"
var/list/L = current.get_contents()
var/obj/item/device/flash/flash = locate() in L
if (flash)
if(!flash.broken)
text += "|<a href='?src=\ref[src];gang=takeequip'>take</a>."
else
text += "|<a href='?src=\ref[src];gang=takeequip'>take</a>|<a href='?src=\ref[src];gang=repairflash'>repair flash</a>."
var/obj/item/device/gangtool/gangtool = locate() in L
if (gangtool)
text += "|<a href='?src=\ref[src];gang=takeequip'>take</a>."
else
text += "."
if (objectives.len==0)
text += "<br>Objectives are empty! <a href='?src=\ref[src];gang=autoobjective'>Set to kill all rival gang leaders</a>."
else if (src in ticker.mode.B_bosses)
text += "loyal|<a href='?src=\ref[src];gang=clear'>none</a>|(A) <a href='?src=\ref[src];gang=agang'>gangster</a> <a href='?src=\ref[src];gang=aboss'>boss</a>|<B>(B)</B> <a href='?src=\ref[src];gang=bgang'>gangster</a> <b>BOSS</b>"
text += "<br>Equipment: <a href='?src=\ref[src];gang=equip'>give</a>"
var/list/L = current.get_contents()
var/obj/item/device/flash/flash = locate() in L
if (flash)
if(!flash.broken)
text += "<br><a href='?src=\ref[src];gang=takeequip'>take</a>."
else
text += "<br><a href='?src=\ref[src];gang=takeequip'>take</a>|<a href='?src=\ref[src];gang=repairflash'>repair flash</a>."
var/obj/item/device/gangtool/gangtool = locate() in L
if (gangtool)
text += "|<a href='?src=\ref[src];gang=takeequip'>take</a>."
else
text += "."
if (objectives.len==0)
text += "<br>Objectives are empty! <a href='?src=\ref[src];gang=autoobjective'>Set to kill all rival gang leaders</a>."
else if (src in ticker.mode.A_gangsters)
else if (src in ticker.mode.A_gang)
text += "loyal|<a href='?src=\ref[src];gang=clear'>none</a>|<B>(A) GANGSTER</B> <a href='?src=\ref[src];gang=aboss'>boss</a>|(B) <a href='?src=\ref[src];gang=bgang'>gangster</a> <a href='?src=\ref[src];gang=bboss'>boss</a>"
else if (src in ticker.mode.B_gangsters)
else if (src in ticker.mode.B_gang)
text += "loyal|<a href='?src=\ref[src];gang=clear'>none</a>|(A) <a href='?src=\ref[src];gang=agang'>gangster</a> <a href='?src=\ref[src];gang=aboss'>boss</a>|<B>(B) GANGSTER</B> <a href='?src=\ref[src];gang=bboss'>boss</a>"
else if(isloyal(current))
text += "<B>LOYAL</B>|none|(A) <a href='?src=\ref[src];gang=agang'>gangster</a> <a href='?src=\ref[src];gang=aboss'>boss</a>|(B) <a href='?src=\ref[src];gang=bgang'>gangster</a> <a href='?src=\ref[src];gang=bboss'>boss</a>"
@@ -448,6 +436,25 @@
sections["traitor"] = text
/** SHADOWLING **/
text = "shadowling"
if(ticker.mode.config_tag == "shadowling")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if(src in ticker.mode.shadows)
text += "<b>SHADOWLING</b>|thrall|<a href='?src=\ref[src];shadowling=clear'>human</a>"
else if(src in ticker.mode.thralls)
text += "shadowling|<b>THRALL</b>|<a href='?src=\ref[src];shadowling=clear'>human</a>"
else
text += "<a href='?src=\ref[src];shadowling=shadowling'>shadowling</a>|<a href='?src=\ref[src];shadowling=thrall'>thrall</a>|<b>HUMAN</b>"
if(current && current.client && current.client.prefs.be_special & BE_SHADOWLING)
text += "|Enabled in Prefs"
else
text += "|Disabled in Prefs"
sections["shadowling"] = text
/** MONKEY ***/
if (istype(current, /mob/living/carbon))
text = "monkey"
@@ -804,7 +811,7 @@
log_admin("[key_name(usr)] has de-gang'ed [current].")
if("agang")
if(src in ticker.mode.A_gangsters)
if(src in ticker.mode.A_gang)
return
ticker.mode.remove_gangster(src, 0, 2)
ticker.mode.add_gangster(src,"A",0)
@@ -821,9 +828,11 @@
current << "<FONT size=3 color=red><B>You are a [gang_name("A")] Gang Boss!</B></FONT>"
message_admins("[key_name_admin(usr)] has added [current] to the [gang_name("A")] Gang (A) leadership.")
log_admin("[key_name(usr)] has added [current] to the [gang_name("A")] Gang (A) leadership.")
ticker.mode.forge_gang_objectives(src)
ticker.mode.greet_gang(src,0)
if("bgang")
if(src in ticker.mode.B_gangsters)
if(src in ticker.mode.B_gang)
return
ticker.mode.remove_gangster(src, 0, 2)
ticker.mode.add_gangster(src,"B",0)
@@ -840,39 +849,26 @@
current << "<FONT size=3 color=red><B>You are a [gang_name("B")] Gang Boss!</B></FONT>"
message_admins("[key_name_admin(usr)] has added [current] to the [gang_name("B")] Gang (B) leadership.")
log_admin("[key_name(usr)] has added [current] to the [gang_name("B")] Gang (B) leadership.")
if("autoobjective")
ticker.mode.forge_gang_objectives(src)
ticker.mode.greet_gang(src,0)
usr << "<span class='info>The objectives for gang war have been generated and shown to [key]</span>"
if("equip")
switch(ticker.mode.equip_gang(current))
if(2)
usr << "<span class='warning'>Unable to equip flash!</span>"
if(1)
usr << "<span class='warning'>Unable to equip recaller!</span>"
if(0)
usr << "<span class='warning'>Unable to equip both flash and recaller!</span>"
usr << "<span class='warning'>Unable to equip territory spraycan!</span>"
if(2)
usr << "<span class='warning'>Unable to equip recruitment pen and spraycan!</span>"
if(3)
usr << "<span class='warning'>Unable to equip gangtool, pen, and spraycan!</span>"
if("takeequip")
var/list/L = current.get_contents()
var/obj/item/device/flash/flash = locate() in L
if (!flash)
usr << "<span class='warning'>Deleting flash failed!</span>"
qdel(flash)
var/obj/item/device/recaller/recaller = locate() in L
if (!recaller)
usr << "<span class='warning'>Deleting recaller failed!</span>"
qdel(recaller)
if("repairflash")
var/list/L = current.get_contents()
var/obj/item/device/flash/flash = locate() in L
if (!flash)
usr << "<span class='warning'>Repairing flash failed!</span>"
else
flash.broken = 0
for(var/obj/item/weapon/pen/gang/pen in L)
qdel(pen)
for(var/obj/item/device/gangtool/gangtool in L)
qdel(gangtool)
for(var/obj/item/toy/crayon/spraycan/gang/SC in L)
qdel(SC)
else if (href_list["cult"])
switch(href_list["cult"])
@@ -1035,6 +1031,49 @@
ticker.mode.forge_traitor_objectives(src)
usr << "<span class='notice'>The objectives for traitor [key] have been generated. You can edit them and anounce manually.</span>"
else if(href_list["shadowling"])
switch(href_list["shadowling"])
if("clear")
ticker.mode.update_shadow_icons_removed(src)
src.spell_list = null
if(src in ticker.mode.shadows)
ticker.mode.shadows -= src
special_role = null
current << "<span class='userdanger'>Your powers have been quenched! You are no longer a shadowling!</span>"
src.spell_list = null
message_admins("[key_name_admin(usr)] has de-shadowling'ed [current].")
log_admin("[key_name(usr)] has de-shadowling'ed [current].")
current.verbs -= /mob/living/carbon/human/proc/shadowling_hatch
current.verbs -= /mob/living/carbon/human/proc/shadowling_ascendance
else if(src in ticker.mode.thralls)
ticker.mode.thralls -= src
special_role = null
current << "<span class='userdanger'>You have been brainwashed! You are no longer a thrall!</span>"
message_admins("[key_name_admin(usr)] has de-thrall'ed [current].")
log_admin("[key_name(usr)] has de-thrall'ed [current].")
if("shadowling")
if(!ishuman(current))
usr << "<span class='warning'>This only works on humans!</span>"
return
ticker.mode.shadows += src
special_role = "shadowling"
current << "<span class='deadsay'><b>You notice a brightening around you. No, it isn't that. The shadows grow, darken, swirl. The darkness has a new welcome for you, and you realize with a \
start that you can't be human. No, you are a shadowling, a harbringer of the shadows! Your alien abilities have been unlocked from within, and you may both commune with your allies and use \
a chrysalis to reveal your true form. You are to ascend at all costs.</b></span>"
ticker.mode.finalize_shadowling(src)
ticker.mode.update_shadow_icons_added(src)
if("thrall")
if(!ishuman(current))
usr << "<span class='warning'>This only works on humans!</span>"
return
ticker.mode.add_thrall(src)
special_role = "thrall"
current << "<span class='deadsay'>All at once it becomes clear to you. Where others see darkness, you see an ally. You realize that the shadows are not dead and dark as one would think, but \
living, and breathing, and <b>eating</b>. Their children, the Shadowlings, are to be obeyed and protected at all costs.</span>"
current << "<span class='danger'>You may use the Hivemind Commune ability to communicate with your fellow enlightened ones.</span>"
message_admins("[key_name_admin(usr)] has thrall'ed [current].")
log_admin("[key_name(usr)] has thrall'ed [current].")
else if (href_list["monkey"])
var/mob/living/L = current
if (L.notransform)
@@ -1310,6 +1349,37 @@
ticker.mode.greet_gang(src)
ticker.mode.equip_gang(current)
/datum/mind/proc/AddSpell(var/obj/effect/proc_holder/spell/spell)
spell_list += spell
if(!spell.action)
spell.action = new/datum/action/spell_action
spell.action.target = spell
spell.action.name = spell.name
spell.action.button_icon = spell.action_icon
spell.action.button_icon_state = spell.action_icon_state
spell.action.background_icon_state = spell.action_background_icon_state
spell.action.Grant(current)
return
/datum/mind/proc/transfer_actions(var/mob/living/new_character)
if(current && current.actions)
for(var/datum/action/A in current.actions)
A.Grant(new_character)
transfer_mindbound_actions(new_character)
/datum/mind/proc/transfer_mindbound_actions(var/mob/living/new_character)
for(var/obj/effect/proc_holder/spell/spell in spell_list)
if(!spell.action) // Unlikely but whatever
spell.action = new/datum/action/spell_action
spell.action.target = spell
spell.action.name = spell.name
spell.action.button_icon = spell.action_icon
spell.action.button_icon_state = spell.action_icon_state
spell.action.background_icon_state = spell.action_background_icon_state
spell.action.Grant(new_character)
return
/mob/proc/sync_mind()
mind_initialize() //updates the mind (or creates and initializes one if one doesn't exist)
mind.active = 1 //indicates that the mind is currently synced with a client
+46
View File
@@ -53,6 +53,11 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin
var/critfailchance = 0
var/centcom_cancast = 1 //Whether or not the spell should be allowed on z2
var/datum/action/spell_action/action = null
var/action_icon = 'icons/mob/actions.dmi'
var/action_icon_state = "spell_default"
var/action_background_icon_state = "bg_spell"
/obj/effect/proc_holder/spell/proc/cast_check(skipcharge = 0,mob/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell
if(((!user.mind) || !(src in user.mind.spell_list)) && !(src in user.mob_spell_list))
@@ -347,4 +352,45 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin
qdel(dummy)
return 0
qdel(dummy)
return 1
/obj/effect/proc_holder/spell/proc/can_cast(mob/user = usr)
if(((!user.mind) || !(src in user.mind.spell_list)) && !(src in user.mob_spell_list))
return 0
if(user.z == ZLEVEL_CENTCOM && !centcom_cancast) //Certain spells are not allowed on the centcom zlevel
return 0
if(user.z == ZLEVEL_CENTCOM && ticker.mode.name == "ragin' mages")
return 0
switch(charge_type)
if("recharge")
if(charge_counter < charge_max)
return 0
if("charges")
if(!charge_counter)
return 0
if(user.stat && !stat_allowed)
return 0
if(ishuman(user))
var/mob/living/carbon/human/H = user
if((invocation_type == "whisper" || invocation_type == "shout") && H.is_muzzled())
return 0
if(clothes_req) //clothes check
if(!istype(H.wear_suit, /obj/item/clothing/suit/wizrobe) && !istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/wizard))
return 0
if(!istype(H.shoes, /obj/item/clothing/shoes/sandal))
return 0
if(!istype(H.head, /obj/item/clothing/head/wizard) && !istype(H.head, /obj/item/clothing/head/helmet/space/hardsuit/wizard))
return 0
else
if(clothes_req || human_req)
return 0
if(nonabstract_req && (isbrain(user) || ispAI(user)))
return 0
return 1
+2
View File
@@ -14,6 +14,8 @@
selection_type = "range"
var/list/compatible_mobs = list(/mob/living/carbon/human,/mob/living/carbon/monkey)
action_icon_state = "barn"
/obj/effect/proc_holder/spell/targeted/barnyardcurse/cast(list/targets, mob/user = usr)
if(!targets.len)
user << "<span class='notice'>No target found in range.</span>"
+2
View File
@@ -5,6 +5,8 @@
var/emp_heavy = 2
var/emp_light = 3
action_icon_state = "emp"
/obj/effect/proc_holder/spell/targeted/emplosion/cast(list/targets)
for(var/mob/living/target in targets)
+1
View File
@@ -13,6 +13,7 @@
centcom_cancast = 0 //Prevent people from getting to centcom
nonabstract_req = 1
var/jaunt_duration = 50 //in deciseconds
action_icon_state = "jaunt"
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/cast(list/targets) //magnets, so mostly hardcoded
for(var/mob/living/target in targets)
+2
View File
@@ -10,6 +10,8 @@
range = 3
cooldown_min = 20 //20 deciseconds reduction per rank
action_icon_state = "knock"
/obj/effect/proc_holder/spell/aoe_turf/knock/cast(list/targets)
for(var/turf/T in targets)
for(var/obj/machinery/door/door in T.contents)
+2
View File
@@ -14,6 +14,8 @@
var/ready = 0
var/image/halo = null
action_icon_state = "lightning"
/obj/effect/proc_holder/spell/targeted/lightning/Click()
if(!ready)
if(cast_check())
+7 -2
View File
@@ -12,6 +12,8 @@
range = 0
cast_sound = null
action_icon_state = "mime"
action_background_icon_state = "bg_mime"
/obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall/Click()
if(usr && usr.mind)
@@ -35,6 +37,9 @@
range = -1
include_user = 1
action_icon_state = "mime"
action_background_icon_state = "bg_mime"
/obj/effect/proc_holder/spell/targeted/mime/speak/Click()
if(!usr)
return
@@ -42,9 +47,9 @@
return
var/mob/living/carbon/human/H = usr
if(H.mind.miming)
still_recharging_msg = "<span class='notice'>You can't break your vow of silence that fast!</span>"
still_recharging_msg = "<span class='warning'>You can't break your vow of silence that fast!</span>"
else
still_recharging_msg = "<span class='notice'>You'll have to wait before you can give your vow of silence again.</span>"
still_recharging_msg = "<span class='warning'>You'll have to wait before you can give your vow of silence again!</span>"
..()
/obj/effect/proc_holder/spell/targeted/mime/speak/cast(list/targets)
+8 -6
View File
@@ -13,6 +13,8 @@
var/paralysis_amount_caster = 20 //how much the caster is paralysed for after the spell
var/paralysis_amount_victim = 20 //how much the victim is paralysed for after the spell
action_icon_state = "mindswap"
/*
Urist: I don't feel like figuring out how you store object spells so I'm leaving this for you to do.
Make sure spells that are removed from spell_list are actually removed and deleted when mind transfering.
@@ -20,29 +22,29 @@ Also, you never added distance checking after target is selected. I've went ahea
*/
/obj/effect/proc_holder/spell/targeted/mind_transfer/cast(list/targets,mob/user = usr, distanceoverride)
if(!targets.len)
user << "No mind found."
user << "<span class='warning'>No mind found!</span>"
return
if(targets.len > 1)
user << "Too many minds! You're not a hive damnit!"//Whaa...aat?
user << "<span class='warning'>Too many minds! You're not a hive damnit!</span>"//Whaa...aat?
return
var/mob/living/target = targets[1]
if(!(target in oview(range)) && !distanceoverride)//If they are not in overview after selection. Do note that !() is necessary for in to work because ! takes precedence over it.
user << "They are too far away!"
user << "<span class='warning'>They are too far away!</span>"
return
if(target.stat == DEAD)
user << "You don't particularly want to be dead."
user << "<span class='warning'>You don't particularly want to be dead!</span>"
return
if(!target.key || !target.mind)
user << "They appear to be catatonic. Not even magic can affect their vacant mind."
user << "<span class='warning'>They appear to be catatonic! Not even magic can affect their vacant mind.</span>"
return
if(target.mind.special_role in protected_roles)
user << "Their mind is resisting your spell."
user << "<span class='warning'>Their mind is resisting your spell!</span>"
return
var/mob/living/victim = target//The target of the spell whos body will be transferred to.
+2
View File
@@ -13,6 +13,8 @@
var/obj/marked_item
action_icon_state = "summons"
/obj/effect/proc_holder/spell/targeted/summonitem/cast(list/targets)
for(var/mob/living/user in targets)
var/list/hand_items = list(user.get_active_hand(),user.get_inactive_hand())
+24 -2
View File
@@ -24,6 +24,8 @@
proj_trail_lifespan = 5
proj_trail_icon_state = "magicmd"
action_icon_state = "magicm"
/obj/effect/proc_holder/spell/targeted/inflict_handler/magic_missile
amt_weakened = 3
amt_dam_fire = 10
@@ -46,6 +48,8 @@
duration = 300
cooldown_min = 300 //25 deciseconds reduction per rank
action_icon_state = "mutate"
/obj/effect/proc_holder/spell/targeted/inflict_handler/disintegrate
name = "Disintegrate"
desc = "This spell instantly kills somebody adjacent to you with the vilest of magick."
@@ -63,6 +67,8 @@
sparks_spread = 1
sparks_amt = 4
action_icon_state = "gib"
/obj/effect/proc_holder/spell/targeted/smoke
name = "Smoke"
desc = "This spell spawns a cloud of choking smoke at your location and does not require wizard garb."
@@ -79,6 +85,8 @@
smoke_spread = 2
smoke_amt = 10
action_icon_state = "smoke"
/obj/effect/proc_holder/spell/targeted/emplosion/disable_tech
name = "Disable Tech"
desc = "This spell disables all weapons, cameras and most other technology in range."
@@ -115,6 +123,8 @@
centcom_cancast = 0 //prevent people from getting to centcom
action_icon_state = "blink"
/obj/effect/proc_holder/spell/targeted/area_teleport/teleport
name = "Teleport"
desc = "This spell teleports you to a type of area of your selection."
@@ -146,6 +156,8 @@
summon_type = list("/obj/effect/forcefield")
summon_lifespan = 300
action_icon_state = "shield"
/obj/effect/proc_holder/spell/aoe_turf/conjure/carp
name = "Summon Carp"
@@ -174,6 +186,8 @@
summon_type = list(/obj/structure/constructshell)
action_icon_state = "artificer"
/obj/effect/proc_holder/spell/aoe_turf/conjure/creature
name = "Summon Creature Swarm"
@@ -203,6 +217,8 @@
starting_spells = list("/obj/effect/proc_holder/spell/targeted/inflict_handler/blind","/obj/effect/proc_holder/spell/targeted/genetic/blind")
action_icon_state = "blind"
/obj/effect/proc_holder/spell/targeted/inflict_handler/blind
amt_eye_blind = 10
amt_eye_blurry = 20
@@ -226,6 +242,8 @@
summon_type = "/obj/structure/closet/statue"
action_icon_state = "statue"
/obj/effect/proc_holder/spell/dumbfire/fireball
name = "Fireball"
desc = "This spell fires a fireball at a target and does not require wizard garb."
@@ -245,6 +263,8 @@
proj_lifespan = 200
proj_step_delay = 1
action_icon_state = "fireball"
/obj/effect/proc_holder/spell/turf/fireball/cast(var/turf/T)
explosion(T, -1, 0, 2, 3, 0, flame_range = 2)
@@ -271,6 +291,8 @@
selection_type = "view"
var/maxthrow = 5
action_icon_state = "repulse"
/obj/effect/proc_holder/spell/aoe_turf/repulse/cast(list/targets)
var/mob/user = usr
var/list/thrownatoms = list()
@@ -279,10 +301,10 @@
for(var/turf/T in targets) //Done this way so things don't get thrown all around hilariously.
for(var/atom/movable/AM in T)
thrownatoms += AM
for(var/atom/movable/AM in thrownatoms)
if(AM == user || AM.anchored) continue
var/obj/effect/overlay/targeteffect = new /obj/effect/overlay{icon='icons/effects/effects.dmi'; icon_state="shieldsparkles"; mouse_opacity=0; density = 0}()
AM.overlays += targeteffect
throwtarget = get_edge_target_turf(user, get_dir(user, get_step_away(AM, user)))
+6 -5
View File
@@ -736,12 +736,13 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
/datum/supply_packs/organic/food
name = "Food Crate"
contains = list(/obj/item/weapon/reagent_containers/food/condiment/flour,
/obj/item/weapon/reagent_containers/food/condiment/rice,
/obj/item/weapon/reagent_containers/food/condiment/milk,
/obj/item/weapon/reagent_containers/food/condiment/soymilk,
/obj/item/weapon/storage/fancy/egg_box,
/obj/item/weapon/reagent_containers/food/condiment/enzyme,
/obj/item/weapon/reagent_containers/food/condiment/sugar,
/obj/item/weapon/reagent_containers/food/snacks/meat/monkey,
/obj/item/weapon/reagent_containers/food/snacks/meat/slab/monkey,
/obj/item/weapon/reagent_containers/food/snacks/grown/banana,
/obj/item/weapon/reagent_containers/food/snacks/grown/banana,
/obj/item/weapon/reagent_containers/food/snacks/grown/banana)
@@ -1254,19 +1255,19 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
/obj/item/weapon/gun/projectile/shotgun/toy,
/obj/item/weapon/gun/projectile/shotgun/toy,
/obj/item/weapon/gun/projectile/shotgun/toy,
/obj/item/weapon/gun/projectile/shotgun/toy,
/obj/item/weapon/gun/projectile/shotgun/toy,
/obj/item/weapon/gun/projectile/shotgun/toy,
/obj/item/weapon/gun/projectile/shotgun/toy,
/obj/item/weapon/gun/projectile/shotgun/toy,
/obj/item/weapon/gun/projectile/shotgun/toy)
cost = 10
containername = "foam force crate"
/datum/supply_packs/misc/foamforce/bonus
name = "Foam Force Pistols Crate"
name = "Foam Force Pistols Crate"
contains = list(/obj/item/weapon/gun/projectile/automatic/toy/pistol,
/obj/item/weapon/gun/projectile/automatic/toy/pistol,
/obj/item/ammo_box/magazine/toy/pistol,
/obj/item/ammo_box/magazine/toy/pistol)
cost = 40
containername = "foam force pistols crate"
containername = "foam force pistols crate"
contraband = 1
+36 -9
View File
@@ -120,6 +120,10 @@ var/list/uplink_items = list()
gamemodes = list(/datum/game_mode/nuclear)
surplus = 40
/datum/uplink_item/dangerous/smg/unrestricted
item = /obj/item/weapon/gun/projectile/automatic/c20r/unrestricted
gamemodes = list(/datum/game_mode/gang)
/datum/uplink_item/dangerous/carbine
name = "M-90gl Carbine"
desc = "A fully-loaded three-round burst carbine that uses 30-round 5.56mm magazines with a togglable underslung 40mm grenade launcher."
@@ -128,6 +132,10 @@ var/list/uplink_items = list()
gamemodes = list(/datum/game_mode/nuclear)
surplus = 50
/datum/uplink_item/dangerous/carbine/unrestricted
item = /obj/item/weapon/gun/projectile/automatic/m90/unrestricted
gamemodes = list(/datum/game_mode/gang)
/datum/uplink_item/dangerous/machinegun
name = "L6 Squad Automatic Weapon"
desc = "A fully-loaded Aussec Armoury belt-fed machine gun. This deadly weapon has a massive 50-round magazine of devastating 7.62x51mm ammunition."
@@ -142,7 +150,7 @@ var/list/uplink_items = list()
The bow generates bolts using an internal power source but must be manually charged between shots."
item = /obj/item/weapon/gun/energy/kinetic_accelerator/crossbow
cost = 12
excludefrom = list(/datum/game_mode/nuclear)
excludefrom = list(/datum/game_mode/nuclear,/datum/game_mode/gang)
surplus = 50
/datum/uplink_item/dangerous/flamethrower
@@ -150,7 +158,7 @@ var/list/uplink_items = list()
desc = "A flamethrower, fueled by a portion of highly flammable biotoxins stolen previously from Nanotrasen stations. Make a statement by roasting the filth in their own greed. Use with caution."
item = /obj/item/weapon/flamethrower/full/tank
cost = 11
gamemodes = list(/datum/game_mode/nuclear)
gamemodes = list(/datum/game_mode/nuclear,/datum/game_mode/gang)
surplus = 40
/datum/uplink_item/dangerous/sword
@@ -201,7 +209,7 @@ var/list/uplink_items = list()
Use with extreme caution, to prevent exposure to yourself and your fellow operatives."
item = /obj/item/weapon/reagent_containers/spray/chemsprayer/bioterror
cost = 20
gamemodes = list(/datum/game_mode/nuclear)
gamemodes = list(/datum/game_mode/nuclear,/datum/game_mode/gang)
surplus = 0
/datum/uplink_item/dangerous/gygax
@@ -258,7 +266,7 @@ var/list/uplink_items = list()
desc = "An additional 20-round .45 magazine for use in the C-20r submachine gun. These bullets pack a lot of punch that can knock most targets down, but do limited overall damage."
item = /obj/item/ammo_box/magazine/smgm45
cost = 2
gamemodes = list(/datum/game_mode/nuclear)
gamemodes = list(/datum/game_mode/nuclear,/datum/game_mode/gang)
/datum/uplink_item/ammo/bullbuck
name = "Drum Magazine - 12g Buckshot"
@@ -286,7 +294,7 @@ var/list/uplink_items = list()
desc = "An additional 30-round 5.56 magazine for use in the M-90gl carbine. These bullets don't have the punch to knock most targets down, but dish out higher overall damage."
item = /obj/item/ammo_box/magazine/m556
cost = 2
gamemodes = list(/datum/game_mode/nuclear)
gamemodes = list(/datum/game_mode/nuclear,/datum/game_mode/gang)
/datum/uplink_item/ammo/a40mm
name = "Ammo Box - 40mm grenades"
@@ -330,6 +338,7 @@ var/list/uplink_items = list()
item = /obj/item/weapon/gun/projectile/automatic/toy/pistol/riot
cost = 10
surplus = 10
excludefrom = list(/datum/game_mode/gang)
/datum/uplink_item/stealthy_weapons/sleepy_pen
name = "Sleepy Pen"
@@ -337,7 +346,7 @@ var/list/uplink_items = list()
The pen holds one dose of the mixture, and cannot be refilled."
item = /obj/item/weapon/pen/sleepy
cost = 4
excludefrom = list(/datum/game_mode/nuclear)
excludefrom = list(/datum/game_mode/nuclear,/datum/game_mode/gang)
/datum/uplink_item/stealthy_weapons/soap
name = "Syndicate Soap"
@@ -367,6 +376,19 @@ var/list/uplink_items = list()
cost = 3
surplus = 10
/datum/uplink_item/stealthy_weapons/pizza_bomb
name = "Pizza Bomb"
desc = "A pizza box with a bomb taped inside of it. The timer needs to be set by opening the box; afterwards, opening the box again will trigger the detonation."
item = /obj/item/device/pizza_bomb
cost = 4
surplus = 8
/datum/uplink_item/stealthy_weapons/dehy_carp
name = "Dehydrated Space Carp"
desc = "Just add water to make your very own hostile to everything space carp. It looks just like a plushie."
item = /obj/item/toy/carpplushie/dehy_carp
cost = 3
// STEALTHY TOOLS
/datum/uplink_item/stealthy_tools
@@ -409,6 +431,7 @@ var/list/uplink_items = list()
desc = "Projects an image across a user, disguising them as an object scanned with it, as long as they don't move the projector from their hand. The disguised user cannot run and rojectiles pass over them."
item = /obj/item/device/chameleon
cost = 7
excludefrom = list(/datum/game_mode/gang)
/datum/uplink_item/stealthy_tools/camera_bug
name = "Camera Bug"
@@ -441,6 +464,7 @@ var/list/uplink_items = list()
desc = "The emag is a small card that unlocks hidden functions in electronic devices, subverts intended functions and characteristically breaks security mechanisms."
item = /obj/item/weapon/card/emag
cost = 6
excludefrom = list(/datum/game_mode/gang)
/datum/uplink_item/device_tools/toolbox
name = "Full Syndicate Toolbox"
@@ -454,7 +478,7 @@ var/list/uplink_items = list()
and other medical supplies helpful for a medical field operative."
item = /obj/item/weapon/storage/firstaid/tactical
cost = 9
gamemodes = list(/datum/game_mode/nuclear)
gamemodes = list(/datum/game_mode/nuclear,/datum/game_mode/gang)
/datum/uplink_item/badass/syndiecigs
name = "Syndicate Smokes"
@@ -467,6 +491,7 @@ var/list/uplink_items = list()
desc = "The red and black syndicate space suit is less encumbering than Nanotrasen variants, fits inside bags, and has a weapon slot. Nanotrasen crewmembers are trained to report red space suit sightings."
item = /obj/item/weapon/storage/box/syndie_kit/space
cost = 5
excludefrom = list(/datum/game_mode/gang)
/datum/uplink_item/device_tools/hardsuit
name = "Blood-red Hardsuit"
@@ -476,6 +501,7 @@ var/list/uplink_items = list()
Nanotrasen crewmembers are trained to report red space suit sightings, these suits in particular are known to drive employees into a panic."
item = /obj/item/clothing/suit/space/hardsuit/syndi
cost = 8
excludefrom = list(/datum/game_mode/gang)
/datum/uplink_item/device_tools/thermal
name = "Thermal Imaging Glasses"
@@ -540,6 +566,7 @@ var/list/uplink_items = list()
leading to an emergency evacuation. Because of its size, it cannot be carried. Ordering this sends you a small beacon that will teleport the larger beacon to your location on activation."
item = /obj/item/device/sbeacondrop
cost = 14
excludefrom = list(/datum/game_mode/gang)
/datum/uplink_item/device_tools/syndicate_bomb
name = "Syndicate Bomb"
@@ -577,7 +604,7 @@ var/list/uplink_items = list()
desc = "An incredibly useful personal shield projector, capable of reflecting energy projectiles and defending against other attacks."
item = /obj/item/weapon/shield/energy
cost = 16
gamemodes = list(/datum/game_mode/nuclear)
gamemodes = list(/datum/game_mode/nuclear,/datum/game_mode/gang)
surplus = 20
@@ -623,7 +650,7 @@ var/list/uplink_items = list()
desc = "Syndicate Bundles are specialised groups of items that arrive in a plain box. These items are collectively worth more than 10 telecrystals, but you do not know which specialisation you will receive."
item = /obj/item/weapon/storage/box/syndicate
cost = 20
excludefrom = list(/datum/game_mode/nuclear)
excludefrom = list(/datum/game_mode/nuclear,/datum/game_mode/gang)
/datum/uplink_item/badass/syndiecards
name = "Syndicate Playing Cards"
+2 -2
View File
@@ -137,11 +137,11 @@ var/const/AIRLOCK_WIRE_LIGHT = 2048
//raises them if they are down (only if power's on)
if(!A.locked)
A.locked = 1
A.audible_message("You hear a click from the bottom of the door.", null, 1)
A.audible_message("<span class='italics'>You hear a click from the bottom of the door.</span>", null, 1)
else
if(A.hasPower()) //only can raise bolts if power's on
A.locked = 0
A.audible_message("You hear a click from the bottom of the door.", null, 1)
A.audible_message("<span class='italics'>You hear a click from the bottom of the door.</span>", null, 1)
A.update_icon()
if(AIRLOCK_WIRE_BACKUP_POWER1 || AIRLOCK_WIRE_BACKUP_POWER2)
+3 -3
View File
@@ -113,14 +113,14 @@ var/list/wireColours = list("red", "blue", "green", "black", "orange", "brown",
var/colour = href_list["cut"]
CutWireColour(colour)
else
L << "<span class='error'>You need wirecutters!</span>"
L << "<span class='warning'>You need wirecutters!</span>"
else if(href_list["pulse"])
if(istype(I, /obj/item/device/multitool))
var/colour = href_list["pulse"]
PulseColour(colour)
else
L << "<span class='error'>You need a multitool!</span>"
L << "<span class='warning'>You need a multitool!</span>"
else if(href_list["attach"])
var/colour = href_list["attach"]
@@ -138,7 +138,7 @@ var/list/wireColours = list("red", "blue", "green", "black", "orange", "brown",
L.drop_item()
Attach(colour, A)
else
L << "<span class='error'>You need a attachable assembly!</span>"
L << "<span class='warning'>You need a attachable assembly!</span>"
+1 -1
View File
@@ -134,7 +134,7 @@
name = "syntiflesh"
desc = "Meat that appears...strange..."
gender = PLURAL
icon = 'icons/obj/food.dmi'
icon = 'icons/obj/food/food.dmi'
icon_state = "meat"
flags = CONDUCT
w_class = 1.0
+13 -5
View File
@@ -28,6 +28,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
mouse_opacity = 0
invisibility = INVISIBILITY_LIGHTING
var/lightswitch = 1
var/valid_territory = 1 //If it's a valid territory for gangs to claim
var/eject = null
@@ -109,6 +110,7 @@ proc/process_ghost_teleport_locs()
power_light = 0
power_equip = 0
power_environ = 0
valid_territory = 0
ambientsounds = list('sound/ambience/ambispace.ogg','sound/ambience/title2.ogg',)
@@ -123,6 +125,7 @@ proc/process_ghost_teleport_locs()
luminosity = 1
lighting_use_dynamic = 1
has_gravity = 1
valid_territory = 0
/area/start
@@ -194,8 +197,7 @@ proc/process_ghost_teleport_locs()
/area/asteroid/artifactroom/New()
..()
lighting_use_dynamic = 1
InitializeLighting()
SetDynamicLighting()
/area/planet/clown
name = "\improper Clown Planet"
@@ -246,9 +248,12 @@ proc/process_ghost_teleport_locs()
requires_power = 0
has_gravity = 1
//Abductors
/area/abductor_ship
name = "\improper Abductor Ship"
icon_state = "yellow"
requires_power = 0
has_gravity = 1
//PRISON
@@ -344,6 +349,7 @@ proc/process_ghost_teleport_locs()
//Maintenance
/area/maintenance
ambientsounds = list('sound/ambience/ambimaint1.ogg', 'sound/ambience/ambimaint2.ogg', 'sound/ambience/ambimaint3.ogg', 'sound/ambience/ambimaint4.ogg', 'sound/ambience/ambimaint5.ogg')
valid_territory = 0
/area/maintenance/atmos_control
name = "Atmospherics Maintenance"
@@ -653,6 +659,7 @@ proc/process_ghost_teleport_locs()
requires_power = 0
luminosity = 1
lighting_use_dynamic = 0
valid_territory = 0
auxport
name = "\improper Fore Port Solar Array"
@@ -961,6 +968,7 @@ proc/process_ghost_teleport_locs()
icon_state = "toxmisc"
/area/toxins/test_area
valid_territory = 0
name = "\improper Toxins Test Area"
icon_state = "toxtest"
+8 -6
View File
@@ -43,7 +43,6 @@
..()
power_change() // all machines set to current power level, also updates lighting icon
InitializeLighting()
blend_mode = BLEND_MULTIPLY // Putting this in the constructure so that it stops the icons being screwed up in the map editor.
@@ -223,7 +222,7 @@
return
/area/proc/updateicon()
if ((fire || eject || party) && (!requires_power||power_environ) && !lighting_space)//If it doesn't require power, can still activate this proc.
if ((fire || eject || party) && (!requires_power||power_environ))//If it doesn't require power, can still activate this proc.
if(fire && !eject && !party)
icon_state = "blue"
/*else if(atmosalm && !fire && !eject && !party)
@@ -238,6 +237,8 @@
// new lighting behaviour with obj lights
icon_state = null
/area/space/updateicon()
icon_state = null
/*
#define EQUIP 1
@@ -251,8 +252,6 @@
return 1
if(master.always_unpowered)
return 0
if(src.lighting_space)
return 0 // Nope sorry
switch(chan)
if(EQUIP)
return master.power_equip
@@ -263,6 +262,9 @@
return 0
/area/space/powered(chan) //Nope.avi
return 0
// called when power status changes
/area/proc/power_change()
@@ -330,11 +332,11 @@
L.lastarea = newarea
// Ambience goes down here -- make sure to list each area seperately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch
if(!L.client.ambience_playing && L.client.prefs.toggles & SOUND_SHIP_AMBIENCE)
if(L.client && !L.client.ambience_playing && L.client.prefs.toggles & SOUND_SHIP_AMBIENCE)
L.client.ambience_playing = 1
L << sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = 2)
if(!(L && L.client && (L.client.prefs.toggles & SOUND_AMBIENCE))) return //General ambience check is below the ship ambience so one can play without the other
if(!(L.client && (L.client.prefs.toggles & SOUND_AMBIENCE))) return //General ambience check is below the ship ambience so one can play without the other
if(prob(35))
var/sound = pick(ambientsounds)
+1 -1
View File
@@ -20,7 +20,7 @@
//var/chem_is_open_container = 0
// replaced by OPENCONTAINER flags and atom/proc/is_open_container()
///Chemistry.
var/allow_spin = 1
/atom/proc/onCentcom()
var/turf/T = get_turf(src)
if(!T)
+18 -8
View File
@@ -15,6 +15,7 @@
var/pass_flags = 0
glide_size = 8
/atom/movable/Move(atom/newloc, direct = 0)
if(!loc || !newloc) return 0
var/atom/oldloc = loc
@@ -46,11 +47,13 @@
else if (step(src, WEST))
. = step(src, SOUTH)
if(!loc || (loc == oldloc && oldloc != newloc))
last_move = 0
return
if(.)
Moved(oldloc, direct)
last_move = direct
spawn(5) // Causes space drifting. /tg/station has no concept of speed, we just use 5
@@ -58,6 +61,10 @@
if(loc == newloc) //Remove this check and people can accelerate. Not opening that can of worms just yet.
newtonian_move(last_move)
//Called after a successful Move(). By this point, we've already moved
/atom/movable/proc/Moved(atom/OldLoc, Dir)
return 1
/atom/movable/Del()
if(isnull(gc_destroyed) && loc)
testing("GC: -- [type] was deleted via del() rather than qdel() --")
@@ -68,14 +75,13 @@
..()
/atom/movable/Destroy()
. = ..()
if(reagents)
qdel(reagents)
for(var/atom/movable/AM in contents)
qdel(AM)
tag = null
loc = null
invisibility = 101
// Do not call ..()
// Previously known as HasEntered()
// This is automatically called when something enters your square
@@ -96,12 +102,15 @@
/atom/movable/proc/forceMove(atom/destination)
if(destination)
if(loc)
loc.Exited(src)
var/atom/oldloc = loc
if(oldloc)
oldloc.Exited(src, destination)
loc = destination
loc.Entered(src)
for(var/atom/movable/AM in loc)
destination.Entered(src, oldloc)
for(var/atom/movable/AM in destination)
if(AM == src) continue
AM.Crossed(src)
Moved(oldloc, 0)
return 1
return 0
@@ -159,7 +168,8 @@
//use a modified version of Bresenham's algorithm to get from the atom's current position to that of the target
src.throwing = 1
SpinAnimation(5, 1)
if(target.allow_spin) // turns out 1000+ spinning objects being thrown at the singularity creates lag - Iamgoofball
SpinAnimation(5, 1)
var/dist_x = abs(target.x - src.x)
var/dist_y = abs(target.y - src.y)
var/dx = (target.x > src.x) ? EAST : WEST
+4 -9
View File
@@ -97,7 +97,7 @@ Radio:
1355 - Medical
1357 - Engineering
1359 - Security
1441 - death squad
1337 - death squad
1443 - Confession Intercom
1349 - Miners
1347 - Cargo techs
@@ -130,7 +130,7 @@ var/list/radiochannels = list(
"Medical" = 1355,
"Engineering" = 1357,
"Security" = 1359,
"Centcom" = 1441,
"Centcom" = 1337,
"Syndicate" = 1213,
"Supply" = 1347,
"Service" = 1349,
@@ -144,7 +144,7 @@ var/list/radiochannelsreverse = list(
"1355" = "Medical",
"1357" = "Engineering",
"1359" = "Security",
"1441" = "Centcom",
"1337" = "Centcom",
"1213" = "Syndicate",
"1347" = "Supply",
"1349" = "Service",
@@ -160,7 +160,7 @@ var/const/COMM_FREQ = 1353 //command, colored gold in chat window
var/const/MED_FREQ = 1355 //medical, coloured blue in chat window
var/const/ENG_FREQ = 1357 //engineering, coloured orange in chat window
var/const/SEC_FREQ = 1359 //security, coloured red in chat window
var/const/CENTCOM_FREQ = 1441 //centcom frequency, coloured grey in chat window
var/const/CENTCOM_FREQ = 1337 //centcom frequency, coloured grey in chat window
var/const/AIPRIV_FREQ = 1447 //AI private, colored magenta in chat window
#define TRANSMISSION_WIRE 0
@@ -173,12 +173,7 @@ var/const/RADIO_CHAT = "3" //deprecated
var/const/RADIO_ATMOSIA = "4"
var/const/RADIO_NAVBEACONS = "5"
var/const/RADIO_AIRLOCK = "6"
var/const/RADIO_SECBOT = "7"
var/const/RADIO_MULEBOT = "8"
var/const/RADIO_MAGNETS = "9"
var/const/RADIO_CLEANBOT = "10"
var/const/RADIO_FLOORBOT = "11"
var/const/RADIO_MEDBOT = "12"
/datum/radio_frequency
+14 -3
View File
@@ -36,9 +36,20 @@
destination.dna.uni_identity = uni_identity
destination.dna.blood_type = blood_type
destination.dna.species = species
destination.dna.mutant_color = mutant_color
destination.dna.real_name = real_name
destination.dna.mutations = mutations
/datum/dna/proc/copy_dna(var/datum/dna/new_dna)
new_dna.unique_enzymes = unique_enzymes
new_dna.struc_enzymes = struc_enzymes
new_dna.uni_identity = uni_identity
new_dna.blood_type = blood_type
new_dna.species = new species.type
new_dna.mutant_color = mutant_color
new_dna.real_name = real_name
new_dna.mutations = mutations
/datum/dna/proc/add_mutation(mutation_name)
var/datum/mutation/human/HM = mutations_list[mutation_name]
HM.on_acquiring(holder)
@@ -392,15 +403,15 @@
return
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
user << "<span class='notice'>You lean on the back of [src] and start pushing the door open. (this will take about [breakout_time] minutes.)</span>"
user.visible_message("<span class='warning'>You hear a metallic creaking from [src]!</span>")
user << "<span class='notice'>You lean on the back of [src] and start pushing the door open... (this will take about [breakout_time] minutes.)</span>"
user.visible_message("<span class='italics'>You hear a metallic creaking from [src]!</span>")
if(do_after(user,(breakout_time*60*10))) //minutes * 60seconds * 10deciseconds
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open || !locked)
return
locked = 0
visible_message("<span class='danger'>[user] successfully broke out of [src]!</span>")
visible_message("<span class='warning'>[user] successfully broke out of [src]!</span>")
user << "<span class='notice'>You successfully break out of [src]!</span>"
open_machine()
+371
View File
@@ -0,0 +1,371 @@
/datum/game_mode
var/list/datum/mind/abductors = list()
/datum/game_mode/abduction
name = "Abduction"
config_tag = "abduction"
antag_flag = BE_ABDUCTOR
pre_setup_before_jobs = 1
recommended_enemies = 2
required_players = 15
var/max_teams = 4
var/teams = 1
var/list/datum/mind/scientists = list()
var/list/datum/mind/agents = list()
var/list/datum/objective/team_objectives = list()
var/list/team_names = list()
/datum/game_mode/abduction/announce()
world << "<B>The current game mode is - Abduction!</B>"
/datum/game_mode/abduction/pre_setup()
teams = max(1, min(max_teams,round(num_players()/config.abductor_scaling_coeff)))
var/possible_teams = max(1,round(antag_candidates.len / 2))
teams = min(teams,possible_teams)
abductors.len = 2*teams
scientists.len = teams
agents.len = teams
team_objectives.len = teams
team_names.len = teams
for(var/i=1,i<=teams,i++)
if(!make_abductor_team(i))
return 0
return 1
/datum/game_mode/abduction/proc/make_abductor_team(var/team_number,var/preset_agent=null,var/preset_scientist=null)
//Team Name
team_names[team_number] = "Mothership [pick(possible_changeling_IDs)]" //TODO Ensure unique and actual alieny names
//Team Objective
var/datum/objective/experiment/team_objective = new
team_objective.team = team_number
team_objectives[team_number] = team_objective
//Team Members
if(!preset_agent || !preset_scientist)
if(antag_candidates.len <=2)
return 0
var/datum/mind/scientist
var/datum/mind/agent
if(!preset_scientist)
scientist = pick(antag_candidates)
antag_candidates -= scientist
else
scientist = preset_scientist
if(!preset_agent)
agent = pick(antag_candidates)
antag_candidates -= agent
else
agent = preset_agent
scientist.assigned_role = "MODE"
scientist.special_role = "Abductor"
log_game("[scientist.key] (ckey) has been selected as an abductor team [team_number] scientist.")
agent.assigned_role = "MODE"
agent.special_role = "Abductor"
log_game("[agent.key] (ckey) has been selected as an abductor team [team_number] agent.")
abductors |= agent
abductors |= scientist
scientists[team_number] = scientist
agents[team_number] = agent
return 1
/datum/game_mode/abduction/post_setup()
//Spawn Team
var/list/obj/effect/landmark/abductor/agent_landmarks = new
var/list/obj/effect/landmark/abductor/scientist_landmarks = new
agent_landmarks.len = max_teams
scientist_landmarks.len = max_teams
for(var/obj/effect/landmark/abductor/A in landmarks_list)
if(istype(A,/obj/effect/landmark/abductor/agent))
agent_landmarks[text2num(A.team)] = A
else if(istype(A,/obj/effect/landmark/abductor/scientist))
scientist_landmarks[text2num(A.team)] = A
var/datum/mind/agent
var/obj/effect/landmark/L
var/datum/mind/scientist
var/team_name
var/mob/living/carbon/human/H
var/datum/species/abductor/S
for(var/team_number=1,team_number<=teams,team_number++)
team_name = team_names[team_number]
agent = agents[team_number]
H = agent.current
L = agent_landmarks[team_number]
H.loc = L.loc
H.dna.species = new /datum/species/abductor()
S = H.dna.species
S.agent = 1
S.team = team_number
H.real_name = team_name + " Agent"
equip_common(H,team_number)
equip_agent(H,team_number)
greet_agent(agent,team_number)
H.regenerate_icons()
scientist = scientists[team_number]
H = scientist.current
L = scientist_landmarks[team_number]
H.loc = L.loc
H.dna.species = new /datum/species/abductor()
S = H.dna.species
S.scientist = 1
S.team = team_number
H.real_name = team_name + " Scientist"
equip_common(H,team_number)
equip_scientist(H,team_number)
greet_scientist(scientist,team_number)
H.regenerate_icons()
return ..()
//Used for create antag buttons
/datum/game_mode/abduction/proc/post_setup_team(var/team_number)
var/list/obj/effect/landmark/abductor/agent_landmarks = new
var/list/obj/effect/landmark/abductor/scientist_landmarks = new
agent_landmarks.len = max_teams
scientist_landmarks.len = max_teams
for(var/obj/effect/landmark/abductor/A in landmarks_list)
if(istype(A,/obj/effect/landmark/abductor/agent))
agent_landmarks[text2num(A.team)] = A
else if(istype(A,/obj/effect/landmark/abductor/scientist))
scientist_landmarks[text2num(A.team)] = A
var/datum/mind/agent
var/obj/effect/landmark/L
var/datum/mind/scientist
var/team_name
var/mob/living/carbon/human/H
var/datum/species/abductor/S
team_name = team_names[team_number]
agent = agents[team_number]
H = agent.current
L = agent_landmarks[team_number]
H.loc = L.loc
H.dna.species = new /datum/species/abductor()
S = H.dna.species
S.agent = 1
S.team = team_number
H.real_name = team_name + " Agent"
equip_common(H,team_number)
equip_agent(H,team_number)
greet_agent(agent,team_number)
H.regenerate_icons()
scientist = scientists[team_number]
H = scientist.current
L = scientist_landmarks[team_number]
H.loc = L.loc
H.dna.species = new /datum/species/abductor()
S = H.dna.species
S.scientist = 1
S.team = team_number
H.real_name = team_name + " Scientist"
equip_common(H,team_number)
equip_scientist(H,team_number)
greet_scientist(scientist,team_number)
H.regenerate_icons()
/datum/game_mode/abduction/proc/greet_agent(var/datum/mind/abductor,var/team_number)
abductor.objectives += team_objectives[team_number]
var/team_name = team_names[team_number]
abductor.current << "<span class='notice'>You are an Abductor Agent of [team_name]!</span>"
abductor.current << "<span class='notice'>With the help of your teammate kidnap and experiment on station members!</span>"
abductor.current << "<span class='notice'>Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve.</span>"
var/obj_count = 1
for(var/datum/objective/objective in abductor.objectives)
abductor.current << "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
obj_count++
return
/datum/game_mode/abduction/proc/greet_scientist(var/datum/mind/abductor,var/team_number)
abductor.objectives += team_objectives[team_number]
var/team_name = team_names[team_number]
abductor.current << "<span class='notice'>You are an Abductor Scientist of [team_name]!</span>"
abductor.current << "<span class='notice'>With the help of your teammate kidnap and experiment on station members!</span>"
abductor.current << "<span class='notice'>Use your tool and ship consoles to support the agent and retrieve human specimens.</span>"
var/obj_count = 1
for(var/datum/objective/objective in abductor.objectives)
abductor.current << "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
obj_count++
return
/datum/game_mode/abduction/proc/equip_common(var/mob/living/carbon/human/agent,var/team_number)
var/radio_freq = SYND_FREQ
var/obj/item/device/radio/R = new /obj/item/device/radio/headset/syndicate/alt(agent)
R.set_frequency(radio_freq)
agent.equip_to_slot_or_del(R, slot_ears)
agent.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(agent), slot_shoes)
agent.equip_to_slot_or_del(new /obj/item/clothing/under/color/grey(agent), slot_w_uniform) //they're greys gettit
agent.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(agent), slot_back)
/datum/game_mode/abduction/proc/get_team_console(var/team)
var/obj/machinery/abductor/console/console
for(var/obj/machinery/abductor/console/c in machines)
if(c.team == team)
console = c
break
return console
/datum/game_mode/abduction/proc/equip_agent(var/mob/living/carbon/human/agent,var/team_number)
var/obj/machinery/abductor/console/console = get_team_console(team_number)
var/obj/item/clothing/suit/armor/abductor/vest/V = new /obj/item/clothing/suit/armor/abductor/vest(agent)
if(console!=null)
console.vest = V
V.flags |= NODROP
agent.equip_to_slot_or_del(V, slot_wear_suit)
agent.equip_to_slot_or_del(new /obj/item/weapon/abductor_baton(agent), slot_in_backpack)
agent.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/decloner/alien(agent), slot_belt)
agent.equip_to_slot_or_del(new /obj/item/device/abductor/silencer(agent), slot_in_backpack)
agent.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/abductor(agent), slot_head)
/datum/game_mode/abduction/proc/equip_scientist(var/mob/living/carbon/human/scientist,var/team_number)
var/obj/machinery/abductor/console/console = get_team_console(team_number)
var/obj/item/device/abductor/gizmo/G = new /obj/item/device/abductor/gizmo(scientist)
if(console!=null)
console.gizmo = G
G.console = console
scientist.equip_to_slot_or_del(G, slot_in_backpack)
var/obj/item/weapon/implant/abductor/beamplant = new /obj/item/weapon/implant/abductor(scientist)
beamplant.imp_in = scientist
beamplant.implanted = 1
beamplant.implanted(scientist)
beamplant.home = console.pad
/datum/game_mode/abduction/check_finished()
var/all_dead = 1
for(var/team_number=1,team_number<=teams,team_number++)
var/datum/mind/smind = scientists[team_number]
if(smind.current)
var/mob/living/M = smind.current
if(M.stat != DEAD)
all_dead = 0
var/obj/machinery/abductor/console/con = get_team_console(team_number)
var/datum/objective/objective = team_objectives[team_number]
if (con.experiment.points > objective.target_amount)
return 1
if(all_dead)
return 1
return ..()
/datum/game_mode/abduction/declare_completion()
for(var/team_number=1,team_number<=teams,team_number++)
var/obj/machinery/abductor/console/console = get_team_console(team_number)
var/datum/objective/objective = team_objectives[team_number]
var/team_name = team_names[team_number]
var/datum/mind/amind = agents[team_number]
var/datum/mind/smind = scientists[team_number]
var/mob/living/carbon/human/agent = amind.current
var/mob/living/carbon/human/scientist = smind.current
if (console.experiment.points > objective.target_amount)
world << "<font size = 3 color='green'><b>[team_name] team fullfilled its mission! </b></font>"
world << "<b>Team Members : [agent.name]([agent.ckey]),[scientist.name]([scientist.ckey])</b>"
else
world << "<font size = 3 color='red'><b>[team_name] team failed its mission! </b></font>"
world << "<b>Team Members</b>: [agent.name]([agent.ckey])<br>[scientist.name]([scientist.ckey])"
world << "<b>Abductees:</b>"
display_abductees(console)
..()
return 1
/datum/game_mode/abduction/proc/display_abductees(var/obj/machinery/abductor/console/console)
var/list/mob/living/abductees = console.experiment.history
for(var/mob/living/abductee in abductees)
if(!abductee.mind)
continue
world << "[abductee.name]([abductee.ckey]))"
var/count = 1
for(var/datum/objective/objective in abductee.mind.objectives)
if(objective.check_completion())
world << "<br><b>Objective #[count]</b>: [objective.explanation_text] <font color='green'><b>Success!</b></font>"
else
world << "<br><b>Objective #[count]</b>: [objective.explanation_text] <span class='danger'>Fail.</span>"
count++
/datum/game_mode/proc/auto_declare_completion_abduction()
if(abductors.len)
world << "Abductors:"
for(var/datum/mind/M in abductors)
world << "<font size = 2><b>Abductor [M.current ? M.current.name : "Abductor"]([M.key])</b></font>"
return
//Landmarks
// TODO: Split into seperate landmarks for prettier ships
/obj/effect/landmark/abductor
var/team = 1
/obj/effect/landmark/abductor/console/New()
var/obj/machinery/abductor/console/c = new /obj/machinery/abductor/console(src.loc)
c.team = team
spawn(5) // I'd do this properly when i got some time, temporary hack for mappers
c.Initialize()
qdel(src)
/obj/effect/landmark/abductor/agent
/obj/effect/landmark/abductor/scientist
// OBJECTIVES
datum/objective/experiment
dangerrating = 10
target_amount = 6
var/team
datum/objective/experiment/New()
explanation_text = "Experiment on [target_amount] humans"
datum/objective/experiment/check_completion()
return 0
datum/objective/abductee
dangerrating = 5
completed = 1
datum/objective/abductee/steal
explanation_text = "Steal all"
datum/objective/abductee/steal/New()
var/target = pick(list("Pets","Lights","Monkeys","Fruits","Shoes","Soap Bars"))
explanation_text+=" [target]"
datum/objective/abductee/capture
explanation_text = "Capture"
datum/objective/abductee/capture/New()
var/list/jobs = SSjob.occupations
for(var/datum/job/J in jobs)
if(J.current_positions < 1)
jobs -= J
if(jobs.len > 0)
var/datum/job/target = pick(jobs)
explanation_text += " \a [target.title]."
else
explanation_text += " someone."
datum/objective/abductee/shuttle
explanation_text = "You must escape the station! Get the shuttle called!"
datum/objective/abductee/noclone
explanation_text = "Don't allow anyone to be cloned."
@@ -0,0 +1,536 @@
#define VEST_STEALTH 1
#define VEST_COMBAT 2
#define GIZMO_SCAN 1
#define GIZMO_MARK 2
//AGENT VEST
/obj/item/clothing/suit/armor/abductor/vest
name = "Agent Vest"
desc = "Vest outfitted with alien stealth technology."
icon = 'icons/obj/abductor.dmi'
icon_state = "vest_stealth"
item_state = "armor"
blood_overlay_type = "armor"
armor = list(melee = 15, bullet = 15, laser = 15, energy = 15, bomb = 15, bio = 15, rad = 15)
action_button_name = "Activate"
action_button_is_hands_free = 1
var/mode = VEST_STEALTH
var/stealth_active = 0
var/combat_cooldown = 10
var/datum/icon_snapshot/disguise
var/stealth_armor = list(melee = 15, bullet = 15, laser = 15, energy = 15, bomb = 15, bio = 15, rad = 15)
var/combat_armor = list(melee = 50, bullet = 50, laser = 50, energy = 50, bomb = 50, bio = 50, rad = 50)
var/obj/machinery/camera/portable/vest_cam = null
/obj/item/clothing/suit/armor/abductor/vest/New()
..()
vest_cam = new /obj/machinery/camera/portable(src)
vest_cam.c_tag = "Agent Vest Cam"
vest_cam.network = list("Abductor")
/obj/item/clothing/suit/armor/abductor/vest/proc/flip_mode()
switch(mode)
if(VEST_STEALTH)
mode = VEST_COMBAT
DeactivateStealth()
armor = combat_armor
icon_state = "vest_combat"
if(istype(loc, /mob/living/carbon/human))
var/mob/living/carbon/human/H = loc
H.update_inv_wear_suit()
return
if(VEST_COMBAT)// TO STEALTH
mode = VEST_STEALTH
armor = stealth_armor
icon_state = "vest_stealth"
if(istype(loc, /mob/living/carbon/human))
var/mob/living/carbon/human/H = loc
H.update_inv_wear_suit()
return
/obj/item/clothing/suit/armor/abductor/vest/proc/SetDisguise(var/datum/icon_snapshot/entry)
disguise = entry
/obj/item/clothing/suit/armor/abductor/vest/proc/ActivateStealth()
if(disguise == null)
return
stealth_active = 1
if(istype(src.loc, /mob/living/carbon/human))
var/mob/living/carbon/human/M = src.loc
spawn(0)
anim(M.loc,M,'icons/mob/mob.dmi',,"cloak",,M.dir)
M.name_override = disguise.name
M.icon = disguise.icon
M.icon_state = disguise.icon_state
M.overlays = disguise.overlays
M.update_inv_r_hand()
M.update_inv_l_hand()
return
/obj/item/clothing/suit/armor/abductor/vest/proc/DeactivateStealth()
if(!stealth_active)
return
stealth_active = 0
if(istype(src.loc, /mob/living/carbon/human))
var/mob/living/carbon/human/M = src.loc
spawn(0)
anim(M.loc,M,'icons/mob/mob.dmi',,"uncloak",,M.dir)
M.name_override = null
M.overlays.Cut()
M.regenerate_icons()
return
/obj/item/clothing/suit/armor/abductor/vest/IsShield()
DeactivateStealth()
return 0
/obj/item/clothing/suit/armor/abductor/vest/IsReflect()
DeactivateStealth()
return 0
/obj/item/clothing/suit/armor/abductor/vest/ui_action_click()
switch(mode)
if(VEST_COMBAT)
Adrenaline()
if(VEST_STEALTH)
if(stealth_active)
DeactivateStealth()
else
ActivateStealth()
/obj/item/clothing/suit/armor/abductor/vest/proc/Adrenaline()
if(istype(src.loc, /mob/living/carbon/human))
if(combat_cooldown != initial(combat_cooldown))
src.loc << "<span class='warning'>Combat injection is still recharging.</span>"
var/mob/living/carbon/human/M = src.loc
M.stat = 0
M.SetParalysis(0)
M.SetStunned(0)
M.SetWeakened(0)
M.lying = 0
M.update_canmove()
M.adjustStaminaLoss(-75)
combat_cooldown = 0
SSobj.processing |= src
/obj/item/clothing/suit/armor/abductor/vest/process()
combat_cooldown++
if(combat_cooldown==initial(combat_cooldown))
SSobj.processing.Remove(src)
/obj/item/device/abductor/proc/IsAbductor(var/user)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.dna.species.id != "abductor")
return 0
return 1
return 0
/obj/item/device/abductor/proc/AbductorCheck(var/user)
if(IsAbductor(user))
return 1
user << "<span class='warning'>You can't figure how this works!</span>"
return 0
/obj/item/device/abductor/proc/ScientistCheck(var/user)
var/mob/living/carbon/human/H = user
var/datum/species/abductor/S = H.dna.species
return S.scientist
/obj/item/device/abductor/gizmo
name = "Science Tool"
desc = "Alien science is 90% dissections 10% probings."
icon = 'icons/obj/abductor.dmi'
icon_state = "gizmo_scan"
item_state = "silencer"
var/mode = GIZMO_SCAN
var/mob/living/marked = null
var/obj/machinery/abductor/console/console
/obj/item/device/abductor/gizmo/attack_self(mob/user)
if(!AbductorCheck(user))
return
if(!ScientistCheck(user))
user << "<span class='warning'>You're not trained to use this!</span>"
return
if(mode == GIZMO_SCAN)
mode = GIZMO_MARK
icon_state = "gizmo_mark"
else
mode = GIZMO_SCAN
icon_state = "gizmo_scan"
user << "<span class='notice'>You switch the device to [mode==GIZMO_SCAN? "SCAN": "MARK"] MODE</span>"
/obj/item/device/abductor/gizmo/attack(mob/living/M, mob/user)
if(!AbductorCheck(user))
return
if(!ScientistCheck(user))
user << "<span class='notice'>You're not trained to use this</span>"
return
switch(mode)
if(GIZMO_SCAN)
scan(M, user)
if(GIZMO_MARK)
mark(M, user)
/obj/item/device/abductor/gizmo/afterattack(var/atom/target, var/mob/living/user, flag, params)
if(flag)
return
if(!AbductorCheck(user))
return
if(!ScientistCheck(user))
user << "<span class='notice'>You're not trained to use this</span>"
return
switch(mode)
if(GIZMO_SCAN)
scan(target, user)
if(GIZMO_MARK)
mark(target, user)
/obj/item/device/abductor/gizmo/proc/scan(var/atom/target, var/mob/living/user)
if(istype(target,/mob/living/carbon/human))
if(console!=null)
console.AddSnapshot(target)
user << "<span class='notice'>You scan and add the being to the database</span>"
/obj/item/device/abductor/gizmo/proc/mark(var/atom/target, var/mob/living/user)
if(marked == target)
user << "<span class='warning'>This specimen is already marked!</span>"
return
if(istype(target,/mob/living/carbon/human))
if(IsAbductor(target))
marked = target
user << "<span class='notice'>You mark the target for future retrieval.</span>"
else
prepare(target,user)
/obj/item/device/abductor/gizmo/proc/prepare(var/atom/target, var/mob/living/user)
if(get_dist(target,user)>1)
user << "<span class='warning'>You need to be next to the specimen to prepare it for transport!</span>"
return
user << "<span class='notice'>You start preparing the specimen for transport...</span>"
if(do_after(user, 100))
marked = target
user << "<span class='notice'>You finish preparing the specimen for transport.</span>"
/obj/item/device/abductor/silencer
name = "Abductor Silencer"
desc = "Device used to break communication equipment"
icon = 'icons/obj/abductor.dmi'
icon_state = "silencer"
item_state = "gizmo"
/obj/item/device/abductor/silencer/attack(mob/living/M, mob/user)
if(!AbductorCheck(user))
return
radio_off(M, user)
/obj/item/device/abductor/silencer/afterattack(var/atom/target, var/mob/living/user, flag, params)
if(flag)
return
if(!AbductorCheck(user))
return
radio_off(target, user)
/obj/item/device/abductor/silencer/proc/radio_off(var/atom/target, var/mob/living/user)
if( !(user in (viewers(7,target))) )
return
var/turf/targloc = get_turf(target)
var/mob/living/carbon/human/M
for(M in view(2,targloc))
user << "<span class='notice'>You silence [M.name] radio devices.</span>"
radio_off_mob(M)
/obj/item/device/abductor/silencer/proc/radio_off_mob(var/mob/living/carbon/human/M)
var/list/all_items = M.GetAllContents()
for(var/obj/I in all_items)
if(istype(I,/obj/item/device/radio/))
var/obj/item/device/radio/r = I
r.listening = 0
if(!istype(I,/obj/item/device/radio/headset))
r.broadcasting = 0 //goddamned headset hacks
/obj/item/weapon/implant/abductor
name = "Emergency Beam"
desc = "Gets you back on the ship."
icon = 'icons/obj/abductor.dmi'
icon_state = "implant"
activated = 1
var/obj/machinery/abductor/pad/home
var/cooldown = 30
/obj/item/weapon/implant/abductor/activate()
if(cooldown == initial(cooldown))
home.Retrieve(imp_in,1)
cooldown = 0
SSobj.processing |= src
else
imp_in << "<span class='warning'>The emergency beam is still recharging!</span>"
return
/obj/item/weapon/implant/abductor/process()
if(cooldown < initial(cooldown))
cooldown++
if(cooldown == initial(cooldown))
SSobj.processing.Remove(src)
/obj/item/device/firing_pin/alien
name = "alien-looking pin"
desc = "Only non-humans can use this pin"
fail_message = "<span class='alienwarning'>Human DNA detected! Authorization revoked!</span>"
/obj/item/device/firing_pin/alien/pin_auth(mob/living/user)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.dna.species.id == "human") //stealth lizard buff go
return 0
return 1
/obj/item/weapon/gun/energy/decloner/alien
ammo_type = list(/obj/item/ammo_casing/energy/declone)
pin = /obj/item/device/firing_pin/alien
icon_state = "alienpistol"
item_state = "alienpistol"
/obj/item/weapon/gun/energy/decloner/alien/update_icon() // No charge levels
return
/obj/item/weapon/paper/abductor
name = "Dissection Guide"
info = {"<b>Dissection for Dummies</b><br>
<br>
1.Acquire fresh specimen.<br>
2.Put the specimen on operating table<br>
3.Apply surgical drapes preparing for dissection<br>
4.Apply scalpel to specimen torso<br>
5.Stop the bleeders and retract skin<br>
6.Cut out organs you find with a scalpel<br>
7.Use your hands to remove the remaining organs<br>
8.Insert replacement gland (Retrieve one from gland storage)<br>
9.Consider dressing the specimen back to not disturb the habitat <br>
10.Put the specimen in the experiment machinery<br>
11.Choose one of the machine options and follow displayed instructions<br>
<br>
Congratulations! You are now trained for xenobiology research!"}
#define BATON_STUN 0
#define BATON_SLEEP 1
#define BATON_CUFF 2
#define BATON_MODES 3
/obj/item/weapon/abductor_baton
name = "Advanced Baton"
var/mode = BATON_STUN
icon = 'icons/obj/abductor.dmi'
icon_state = "wonderprod"
item_state = "wonderprod"
slot_flags = SLOT_BELT
force = 7
w_class = 3
action_button_name = "Toggle Mode"
/obj/item/weapon/abductor_baton/proc/toggle(mob/living/user=usr)
mode = (mode+1)%BATON_MODES
var/txt
switch(mode)
if(BATON_STUN)
txt = "stun"
if(BATON_SLEEP)
txt = "sleep inducment"
if(BATON_CUFF)
txt = "restraining"
usr << "<span class='notice'>You switch the baton to [txt] mode</span>"
update_icon()
/obj/item/weapon/abductor_baton/update_icon()
switch(mode)
if(BATON_STUN)
icon_state = "wonderprod"
if(BATON_SLEEP)
icon_state = "wonderprod"
if(BATON_CUFF)
icon_state = "wonderprod"
/obj/item/weapon/abductor_baton/proc/IsAbductor(var/mob/living/user)
if(!ishuman(user))
return 0
var/mob/living/carbon/human/H = user
if(!H.dna)
return 0
if(H.dna.species.id != "abductor")
return 0
return 1
/obj/item/weapon/abductor_baton/attack(mob/target as mob, mob/living/user as mob)
if(!IsAbductor(user))
return
if(isrobot(target))
..()
return
if(!isliving(target))
return
if(user.a_intent == "help")
target.visible_message("<span class='danger'>[user] probes [target] with [src]!</span>", \
"<span class='userdanger'>[user] probed [target]!</span>")
return
var/mob/living/L = target
user.do_attack_animation(L)
switch(mode)
if(BATON_STUN)
StunAttack(L,user)
if(BATON_SLEEP)
SleepAttack(L,user)
if(BATON_CUFF)
CuffAttack(L,user)
/obj/item/weapon/abductor_baton/attack_self(mob/living/user)
toggle(user)
/obj/item/weapon/abductor_baton/proc/StunAttack(mob/living/L,mob/living/user)
user.lastattacked = L
L.lastattacker = user
L.Stun(7)
L.Weaken(7)
L.apply_effect(STUTTER, 7)
L.visible_message("<span class='danger'>[user] has stunned [L] with [src]!</span>", \
"<span class='userdanger'>[user] has stunned you with [src]!</span>")
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
if(ishuman(L))
var/mob/living/carbon/human/H = L
H.forcesay(hit_appends)
add_logs(user, L, "stunned")
return
/obj/item/weapon/abductor_baton/proc/SleepAttack(mob/living/L,mob/living/user)
if(L.stunned)
L.SetSleeping(60)
L.visible_message("<span class='danger'>[user] has induced sleep in [L] with [src]!</span>", \
"<span class='userdanger'>You suddenly feel very drowsy!</span>")
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
add_logs(user, L, "put to sleep")
return
/obj/item/weapon/abductor_baton/proc/CuffAttack(mob/living/L,mob/living/user)
if(!iscarbon(L))
return
var/mob/living/carbon/C = L
if(!C.handcuffed)
playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
C.visible_message("<span class='danger'>[user] is trying to put energy cuffs on [C]!</span>", \
"<span class='userdanger'>[user] is trying to put energy cuffs on [C]!</span>")
if(do_mob(user, C, 30))
if(!C.handcuffed)
C.handcuffed = new /obj/item/weapon/restraints/handcuffs/energy/used(C)
C.update_inv_handcuffed(0)
user << "<span class='notice'>You handcuff [C].</span>"
add_logs(user, C, "handcuffed")
else
user << "<span class='warning'>You fail to handcuff [C].</span>"
return
/obj/item/weapon/restraints/handcuffs/energy
name = "energy cuffs"
desc = "Energy field restraining the hands."
icon_state = "cuff_white" // Needs sprite
breakouttime = 450
trashtype = /obj/item/weapon/restraints/handcuffs/energy/used
/obj/item/weapon/restraints/handcuffs/energy/used
desc = "Energy Discharge"
/obj/item/weapon/restraints/handcuffs/energy/used/dropped(mob/user)
user.visible_message("<span class='danger'>[user] cuffs break in a discharge of energy!</span>", \
"<span class='userdanger'>[user] cuffs break in a discharge of energy!</span>")
var/datum/effect/effect/system/spark_spread/S = new
S.set_up(4,0,user.loc)
S.start()
qdel(src)
/obj/item/weapon/abductor_baton/examine(mob/user)
..()
switch(mode)
if(BATON_STUN)
user <<"<span class='warning'>The baton is in stun mode.</span>"
if(BATON_SLEEP)
user <<"<span class='warning'>The baton is in sleep induction mode.</span>"
if(BATON_CUFF)
user <<"<span class='warning'>The baton is in restrain mode.</span>"
/obj/item/weapon/scalpel/alien
name = "alien scalpel"
icon = 'icons/obj/abductor.dmi'
/obj/item/weapon/hemostat/alien
name = "alien hemostat"
icon = 'icons/obj/abductor.dmi'
/obj/item/weapon/retractor/alien
name = "alien retractor"
icon = 'icons/obj/abductor.dmi'
/obj/item/weapon/circular_saw/alien
name = "alien saw"
icon = 'icons/obj/abductor.dmi'
/obj/item/weapon/surgicaldrill/alien
name = "alien drill"
icon = 'icons/obj/abductor.dmi'
/obj/item/weapon/cautery/alien
name = "alien cautery"
icon = 'icons/obj/abductor.dmi'
/obj/item/clothing/head/helmet/abductor
name = "Agent Headgear"
desc = "Abducting with style. Spiky style."
icon_state = "alienhelmet"
item_state = "alienhelmet"
blockTracking = 1
// Operating Table / Beds / Lockers
/obj/structure/optable/abductor
icon = 'icons/obj/abductor.dmi'
icon_state = "bed"
can_buckle = 1
buckle_lying = 1
/obj/structure/stool/bed/abductor
name = "resting contraption"
desc = "This looks similar to contraptions from earth. Could aliens be stealing our technology?"
icon = 'icons/obj/abductor.dmi'
icon_state = "bed"
/obj/structure/table/abductor
name = "alien table"
desc = "Advanced flat surface technology at work!"
icon_state = "alientable"
/obj/structure/closet/abductor
name = "alien locker"
desc = "Contains secrets of the universe"
icon_state = "abductor"
icon_door = "abductor"
@@ -0,0 +1,47 @@
/datum/surgery/organ_extraction
name = "experimental dissection"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin,/datum/surgery_step/incise, /datum/surgery_step/extract_organ ,/datum/surgery_step/gland_insert)
species = list(/mob/living/carbon/human)
location = "chest"
user_species_restricted = 1
user_species_ids = list("abductor")
ignore_clothes = 1
/datum/surgery_step/extract_organ
accept_hand = 1
time = 32
var/obj/item/IC = null
var/list/organ_types = list(/obj/item/organ/heart)
/datum/surgery_step/extract_organ/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
for(var/obj/item/I in target.internal_organs)
if(I.type in organ_types)
IC = I
break
user.visible_message("[user] starts to remove [target]'s organs.", "<span class='notice'>You start to remove [target]'s organs...</span>")
/datum/surgery_step/extract_organ/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(IC)
user.visible_message("[user] pulls [IC] out of [target]'s [target_zone]!", "<span class='notice'>You pull [IC] out of [target]'s [target_zone].</span>")
user.put_in_hands(IC)
target.internal_organs -= IC
return 1
else
user << "<span class='warning'>You don't find anything in [target]'s [target_zone]!</span>"
return 0
/datum/surgery_step/gland_insert
implements = list(/obj/item/gland = 100)
time = 32
/datum/surgery_step/gland_insert/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
user.visible_message("[user] starts to insert [tool] into [target].", "<span class ='notice'>You start to insert [tool] into [target]...</span>")
/datum/surgery_step/gland_insert/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
user.visible_message("[user] inserts [tool] into [target].", "<span class ='notice'>You insert [tool] into [target].</span>")
user.drop_item()
var/obj/item/gland/gland = tool
gland.Inject(target)
return 1
+255
View File
@@ -0,0 +1,255 @@
/obj/item/gland/
name = "Fleshy mass"
desc = "Eww"
icon = 'icons/obj/abductor.dmi'
icon_state = "gland"
var/cooldown_low = 300
var/cooldown_high = 300
var/next_activation = 0
var/uses // -1 For inifinite
var/active = 0
var/mob/living/carbon/human/host
/obj/item/gland/proc/HostCheck()
if(ishuman(host) && host == src.loc)
if(host.stat != DEAD)
return 1
return 0
/obj/item/gland/proc/Start()
active = 1
next_activation = world.time + rand(cooldown_low,cooldown_high)
SSobj.processing |= src
/obj/item/gland/proc/Inject(var/mob/living/carbon/human/target)
host = target
target.internal_organs += src
src.loc = target
/obj/item/gland/process()
if(!active)
SSobj.processing.Remove(src)
return
if(next_activation <= world.time)
//This gives a chance to transplant the gland active into someone else if you're fast
if(!HostCheck())
active = 0
return
activate()
uses--
next_activation = world.time + rand(cooldown_low,cooldown_high)
if(uses == 0)
active = 0
/obj/item/gland/proc/activate()
return
/obj/item/gland/heals
cooldown_low = 200
cooldown_high = 400
uses = -1
icon_state = "health"
obj/item/gland/heals/activate()
host << "<span class='notice'>You feel weird.</span>"
host.adjustBruteLoss(-20)
host.adjustOxyLoss(-20)
host.adjustFireLoss(-20)
/obj/item/gland/slime
cooldown_low = 600
cooldown_high = 1200
uses = -1
icon_state = "slime"
obj/item/gland/slime/activate()
host << "<span class='notice'>You feel weird.</span>"
host.visible_message("<span class='danger'>[host] vomits on the floor!</span>", \
"<span class='userdanger'>You throw up on the floor!</span>")
host.nutrition -= 20
host.adjustToxLoss(-3)
var/turf/pos = get_turf(host)
pos.add_vomit_floor(host)
playsound(pos, 'sound/effects/splat.ogg', 50, 1)
var/mob/living/simple_animal/slime/Slime = new/mob/living/simple_animal/slime(pos)
Slime.Friends = list(host)
Slime.Leader = host
/obj/item/gland/mindshock
cooldown_low = 300
cooldown_high = 300
uses = -1
icon_state = "mindshock"
/obj/item/gland/mindshock/activate()
host << "<span class='notice'>You feel weird.</span>"
var/turf/T = get_turf(host)
for(var/mob/living/carbon/human/H in orange(4,T))
if(H == host)
continue
H << "<span class='alien'> You hear a buzz in your head </span>"
H.confused += 20
/obj/item/gland/pop
cooldown_low = 900
cooldown_high = 1800
uses = 6
icon_state = "species"
/obj/item/gland/pop/activate()
host << "<span class='notice'>You feel weird.</span>"
var/species = pick(list(/datum/species/lizard,/datum/species/slime,/datum/species/plant/pod,/datum/species/fly))
host.dna.species = new species()
host.regenerate_icons()
return
/obj/item/gland/ventcrawling
cooldown_low = 1800
cooldown_high = 2400
uses = 1
icon_state = "vent"
/obj/item/gland/ventcrawling/activate()
host << "<span class='notice'>You feel weird.</span>"
host << "<span class='notice'>You feel very stretchy.</span>"
host.ventcrawler = 2
return
/obj/item/gland/viral
cooldown_low = 1800
cooldown_high = 2400
uses = 1
icon_state = "viral"
/obj/item/gland/viral/activate()
var/virus_type = pick(/datum/disease/beesease, /datum/disease/brainrot, /datum/disease/magnitis)
var/datum/disease/D = new virus_type()
D.carrier = 1
host.viruses += D
D.affected_mob = host
D.holder = host
host.med_hud_set_status()
/obj/item/gland/emp //TODO : Replace with something more interesting
cooldown_low = 900
cooldown_high = 1600
uses = 10
icon_state = "emp"
/obj/item/gland/emp/activate()
empulse(get_turf(host), 2, 5, 1)
/obj/item/gland/spiderman
cooldown_low = 450
cooldown_high = 900
uses = 10
icon_state = "spider"
/obj/item/gland/spiderman/activate()
if(uses == initial(uses))
host.faction += "spiders"
new /obj/effect/spider/spiderling(host.loc)
/obj/item/gland/egg
cooldown_low = 300
cooldown_high = 600
uses = -1
icon_state = "egg"
/obj/item/gland/egg/activate()
var/obj/item/weapon/reagent_containers/food/snacks/egg/egg = new(host.loc)
egg.reagents.add_reagent("sacid",20)
egg.desc += " It smells bad."
/obj/item/gland/bloody
cooldown_low = 200
cooldown_high = 400
uses = -1
/obj/item/gland/bloody/activate()
host.adjustBruteLoss(15)
host.visible_message("<span class='danger'>[host] skin erupts with blood!</span>",\
"<span class='userdanger'>Your skin erupts with blood! It hurts!</span>")
for(var/turf/T in oview(3,host)) //Make this respect walls and such
T.add_blood_floor(host)
for(var/mob/living/carbon/human/H in oview(3,host)) //Blood decals for simple animals would be neat. aka Carp with blood on it.
if(H.wear_suit)
H.wear_suit.add_blood(host)
H.update_inv_wear_suit(0)
else if(H.w_uniform)
H.w_uniform.add_blood(host)
H.update_inv_w_uniform(0)
/obj/item/gland/bodysnatch
cooldown_low = 600
cooldown_high = 600
uses = 1
/obj/item/gland/bodysnatch/activate()
//spawn cocoon with clone greytide snpc inside
var/obj/effect/cocoon/abductor/C = new (get_turf(host))
C.Copy(host)
C.Start()
host.gib()
return
/obj/effect/cocoon/abductor
name = "Slimy cocoon"
desc = "You can see something moving inside"
icon = 'icons/effects/effects.dmi'
icon_state = "cocoon_large3"
color = rgb(10,120,10)
density = 1
var/hatch_time = 0
/obj/effect/cocoon/abductor/proc/Copy(var/mob/living/carbon/human/H)
var/mob/living/carbon/human/interactive/greytide/clone = new(src)
hardset_dna(clone,H.dna.uni_identity,H.dna.struc_enzymes,H.real_name, H.dna.blood_type, H.dna.species.type, H.dna.mutant_color)
//There's no define for this / get all items ?
var/list/slots = list(slot_back,slot_w_uniform,slot_wear_suit,\
slot_wear_mask,slot_head,slot_shoes,slot_gloves,slot_ears,\
slot_glasses,slot_belt,slot_s_store,slot_l_store,slot_r_store,slot_wear_id)
for(var/slot in slots)
var/obj/item/I = H.get_item_by_slot(slot)
if(I)
clone.equip_to_slot_if_possible(I,slot)
/obj/effect/cocoon/abductor/proc/Start()
hatch_time = world.time + 600
SSobj.processing |= src
/obj/effect/cocoon/abductor/process()
if(world.time > hatch_time)
SSobj.processing.Remove(src)
for(var/mob/M in contents)
src.visible_message("<span class='warning'>[src] hatches!</span>")
M.loc = src.loc
qdel(src)
/obj/item/gland/plasma
cooldown_low = 1200
cooldown_high = 2400
uses = 1
/obj/item/gland/plasma/activate()
host << "<span class='warning'>You feel bloated.</span>"
sleep(150)
host << "<span class='userdanger'>Your stomach feels about to explode!</span>"
sleep(50)
host.visible_message("<span class='danger'>[host] explodes in a cloud of plasma!</span>")
var/turf/simulated/T = get_turf(host)
if(istype(T))
T.atmos_spawn_air(SPAWN_TOXINS|SPAWN_20C,300)
host.gib()
return
@@ -0,0 +1,142 @@
/obj/machinery/computer/camera_advanced/abductor
name = "Human Observation Console"
var/team = 0
networks = list("SS13","Abductor")
off_action = new/datum/action/camera_off/abductor //specific datum
var/datum/action/teleport_in/tele_in_action = new
var/datum/action/teleport_out/tele_out_action = new
var/datum/action/teleport_self/tele_self_action = new
var/datum/action/vest_mode_swap/vest_mode_action = new
var/datum/action/vest_disguise_swap/vest_disguise_action = new
var/obj/machinery/abductor/console/console
icon = 'icons/obj/abductor.dmi'
icon_state = "camera"
/obj/machinery/computer/camera_advanced/abductor/CreateEye()
..()
eyeobj.visible_icon = 1
eyeobj.icon = 'icons/obj/abductor.dmi'
eyeobj.icon_state = "camera_target"
/obj/machinery/computer/camera_advanced/abductor/GrantActions(var/mob/living/carbon/user)
off_action.target = user
off_action.Grant(user)
jump_action.target = user
jump_action.Grant(user)
//TODO : add null checks
tele_in_action.target = console.pad
tele_in_action.Grant(user)
tele_out_action.target = console
tele_out_action.Grant(user)
tele_self_action.target = console.pad
tele_self_action.Grant(user)
vest_mode_action.target = console
vest_mode_action.Grant(user)
vest_disguise_action.target = console
vest_disguise_action.Grant(user)
/obj/machinery/computer/camera_advanced/abductor/proc/IsAbductor(var/mob/living/carbon/human/H)
return H.dna.species.id == "abductor"
/obj/machinery/computer/camera_advanced/abductor/proc/IsScientist(var/mob/living/carbon/human/H)
var/datum/species/abductor/S = H.dna.species
return S.scientist
/obj/machinery/computer/camera_advanced/abductor/attack_hand(var/mob/user as mob)
if(!iscarbon(user) || !IsAbductor(user))
return
return ..()
/datum/action/camera_off/abductor/Activate()
if(!target || !iscarbon(target))
return
var/mob/living/carbon/C = target
var/mob/camera/aiEye/remote/remote_eye = C.remote_control
var/obj/machinery/computer/camera_advanced/abductor/origin = remote_eye.origin
C.remote_view = 0
origin.current_user = null
origin.jump_action.Remove(C)
origin.tele_in_action.Remove(C)
origin.tele_out_action.Remove(C)
origin.tele_self_action.Remove(C)
origin.vest_mode_action.Remove(C)
origin.vest_disguise_action.Remove(C)
if(C.client)
C.client.perspective = MOB_PERSPECTIVE
C.client.eye = src
C.client.images -= remote_eye.user_image
C.remote_control = null
C.unset_machine()
src.Remove(C)
/datum/action/teleport_in
name = "Send To"
action_type = AB_INNATE
button_icon_state = "beam_down"
/datum/action/teleport_in/Activate()
if(!target || !iscarbon(owner))
return
var/mob/living/carbon/human/C = owner
var/mob/camera/aiEye/remote/remote_eye = C.remote_control
var/obj/machinery/abductor/pad/P = target
if(cameranet.checkTurfVis(remote_eye.loc))
P.PadToLoc(remote_eye.loc)
/datum/action/teleport_out
name = "Retrieve"
action_type = AB_INNATE
button_icon_state = "beam_up"
/datum/action/teleport_out/Activate()
if(!target || !iscarbon(owner))
return
var/obj/machinery/abductor/console/console = target
console.TeleporterRetrieve()
/datum/action/teleport_self
name = "Send Self"
action_type = AB_INNATE
button_icon_state = "beam_down"
/datum/action/teleport_self/Activate()
if(!target || !iscarbon(owner))
return
var/mob/living/carbon/human/C = owner
var/mob/camera/aiEye/remote/remote_eye = C.remote_control
var/obj/machinery/abductor/pad/P = target
if(cameranet.checkTurfVis(remote_eye.loc))
P.MobToLoc(remote_eye.loc,C)
/datum/action/vest_mode_swap
name = "Switch Vest Mode"
action_type = AB_INNATE
button_icon_state = "vest_mode"
/datum/action/vest_mode_swap/Activate()
if(!target || !iscarbon(owner))
return
var/obj/machinery/abductor/console/console = target
console.FlipVest()
/datum/action/vest_disguise_swap
name = "Switch Vest Disguise"
action_type = AB_INNATE
button_icon_state = "vest_disguise"
/datum/action/vest_disguise_swap/Activate()
if(!target || !iscarbon(owner))
return
var/obj/machinery/abductor/console/console = target
console.SelectDisguise(remote=1)
@@ -0,0 +1,184 @@
//Common
/obj/machinery/abductor
var/team = 0
/obj/machinery/abductor/proc/IsAbductor(var/mob/living/carbon/human/H)
if(!H.dna)
return 0
return H.dna.species.id == "abductor"
/obj/machinery/abductor/proc/IsAgent(var/mob/living/carbon/human/H)
if(H.dna.species.id == "abductor")
var/datum/species/abductor/S = H.dna.species
return S.agent
return 0
/obj/machinery/abductor/proc/IsScientist(var/mob/living/carbon/human/H)
if(H.dna.species.id == "abductor")
var/datum/species/abductor/S = H.dna.species
return S.scientist
return 0
//Console
/obj/machinery/abductor/console
name = "Abductor console"
desc = "Ship command center."
icon = 'icons/obj/abductor.dmi'
icon_state = "console"
density = 1
anchored = 1.0
var/obj/item/device/abductor/gizmo/gizmo
var/obj/item/clothing/suit/armor/abductor/vest/vest
var/obj/machinery/abductor/experiment/experiment
var/obj/machinery/abductor/pad/pad
var/obj/machinery/computer/camera_advanced/abductor/camera
var/list/datum/icon_snapshot/disguises = list()
/obj/machinery/abductor/console/attack_hand(var/mob/user as mob)
if(..())
return
if(!IsAbductor(user))
user << "<span class='warning'>You start mashing alien buttons at random!</span>"
if(do_after(user,100))
TeleporterSend()
return
user.set_machine(src)
var/dat = ""
dat += "<H3> Abductsoft 3000 </H3>"
if(experiment != null)
var/points = experiment.points
dat += "Collected Samples : [points] <br>"
else
dat += "<span class='bad'>NO EXPERIMENT MACHINE DETECTED</span> <br>"
if(pad!=null)
dat += "<span class='bad'>Emergency Teleporter System.</span>"
dat += "<span class='bad'>Consider using primary observation console first.</span>"
dat += "<a href='?src=\ref[src];teleporter_send=1'>Activate Teleporter</A><br>"
dat += "<a href='?src=\ref[src];teleporter_set=1'>Set Teleporter</A><br>"
if(gizmo!=null && gizmo.marked!=null)
dat += "<a href='?src=\ref[src];teleporter_retrieve=1'>Retrieve Mark</A><br>"
else
dat += "<span class='linkOff'>Retrieve Mark</span><br>"
else
dat += "<span class='bad'>NO TELEPAD DETECTED</span></br>"
if(vest!=null)
dat += "<h4> Agent Vest Mode </h4><br>"
var/mode = vest.mode
if(mode == VEST_STEALTH)
dat += "<a href='?src=\ref[src];flip_vest=1'>Combat</A>"
dat += "<span class='linkOff'>Stealth</span>"
else
dat += "<span class='linkOff'>Combat</span>"
dat += "<a href='?src=\ref[src];flip_vest=1'>Stealth</A>"
dat+="<br>"
dat += "<a href='?src=\ref[src];select_disguise=1'>Select Agent Vest Disguise</a><br>"
else
dat += "<span class='bad'>NO AGENT VEST DETECTED</span>"
var/datum/browser/popup = new(user, "computer", "Abductor Console", 400, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
/obj/machinery/abductor/console/Topic(href, href_list)
if(..())
return
usr.set_machine(src)
if(href_list["teleporter_set"])
TeleporterSet()
else if(href_list["teleporter_send"])
TeleporterSend()
else if(href_list["teleporter_retrieve"])
TeleporterRetrieve()
else if(href_list["flip_vest"])
FlipVest()
else if(href_list["select_disguise"])
SelectDisguise()
src.updateUsrDialog()
/obj/machinery/abductor/console/proc/TeleporterSet()
var/A = null
A = input("Select area to teleport to", "Teleport", A) in teleportlocs
if(pad!=null && in_range(usr,src))
pad.teleport_target = teleportlocs[A]
return
/obj/machinery/abductor/console/proc/TeleporterRetrieve()
if(gizmo!=null && pad!=null && gizmo.marked)
pad.Retrieve(gizmo.marked)
return
/obj/machinery/abductor/console/proc/TeleporterSend()
if(pad!=null)
pad.Send()
return
/obj/machinery/abductor/console/proc/FlipVest()
if(vest!=null)
vest.flip_mode()
return
/obj/machinery/abductor/console/proc/SelectDisguise(var/remote=0)
var/list/entries = list()
var/tempname
var/datum/icon_snapshot/temp
for(var/i = 1; i <= disguises.len; i++)
temp = disguises[i]
tempname = temp.name
entries["[tempname]"] = disguises[i]
var/entry_name = input( "Choose Disguise", "Disguise") in entries
var/datum/icon_snapshot/chosen = entries[entry_name]
if(chosen && (remote || in_range(usr,src)))
vest.SetDisguise(chosen)
return
/obj/machinery/abductor/console/proc/Initialize()
for(var/obj/machinery/abductor/pad/p in machines)
if(p.team == team)
pad = p
break
for(var/obj/machinery/abductor/experiment/e in machines)
if(e.team == team)
experiment = e
e.console = src
for(var/obj/machinery/computer/camera_advanced/abductor/c in machines)
if(c.team == team)
camera = c
c.console = src
/obj/machinery/abductor/console/proc/AddSnapshot(var/mob/living/carbon/human/target)
var/datum/icon_snapshot/entry = new
entry.name = target.name
entry.icon = target.icon
entry.icon_state = target.icon_state
entry.overlays = target.get_overlays_copy(list(L_HAND_LAYER,R_HAND_LAYER))
for(var/i=1,i<=disguises.len,i++)
var/datum/icon_snapshot/temp = disguises[i]
if(temp.name == entry.name)
disguises[i] = entry
return
disguises.Add(entry)
return
/obj/machinery/abductor/console/attackby(O as obj, user as mob, params)
if(istype(O, /obj/item/device/abductor/gizmo))
var/obj/item/device/abductor/gizmo/G = O
user << "<span class='notice'>You link the tool to the console.</span>"
gizmo = G
G.console = src
else if(istype(O, /obj/item/clothing/suit/armor/abductor/vest))
var/obj/item/clothing/suit/armor/abductor/vest/V = O
user << "<span class='notice'>You link the vest to the console.</span>"
vest = V
else
..()
@@ -0,0 +1,82 @@
/obj/machinery/abductor/gland_dispenser
name = "Replacement Organ Storage"
desc = "A tank filled with replacement organs"
icon = 'icons/obj/abductor.dmi'
icon_state = "dispenser"
density = 1
anchored = 1
var/list/gland_types
var/list/gland_colors
var/list/amounts
/obj/machinery/abductor/gland_dispenser/proc/random_color()
//TODO : replace with presets or spectrum
return rgb(rand(0,255),rand(0,255),rand(0,255))
/obj/machinery/abductor/gland_dispenser/New()
gland_types = typesof(/obj/item/gland) - /obj/item/gland
gland_types = shuffle(gland_types)
gland_colors = new/list(gland_types.len)
amounts = new/list(gland_types.len)
for(var/i=1,i<=gland_types.len,i++)
gland_colors[i] = random_color()
amounts[i] = rand(1,5)
/obj/machinery/abductor/gland_dispenser/attack_hand(var/mob/user as mob)
if(..())
return
if(!IsAbductor(user))
return
user.set_machine(src)
var/box_css = {"
<style>
a.box.gland {
float: left;
width: 20px;
height: 20px;
margin: 5px;
border-width: 1px;
border-style: solid;
border-color: rgba(0,0,0,.2);
text-align: center;
}
</style>"}
var/dat = ""
var/item_count = 0
for(var/i=1,i<=gland_colors.len,i++)
item_count++
var/g_color = gland_colors[i]
var/amount = amounts[i]
dat += "<a class='box gland' style='background-color:[g_color]' href='?src=\ref[src];dispense=[i]'>[amount]</a>"
if(item_count == 3) // Three boxes per line
dat +="</br></br>"
item_count = 0
var/datum/browser/popup = new(user, "glands", "Gland Dispenser", 200, 200)
popup.add_head_content(box_css)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
/obj/machinery/abductor/gland_dispenser/attackby(obj/item/weapon/W, mob/user, params)
if(istype(W, /obj/item/gland))
user.drop_item()
W.loc = src
for(var/i=1,i<=gland_colors.len,i++)
if(gland_types[i] == W.type)
amounts[i]++
/obj/machinery/abductor/gland_dispenser/Topic(href, href_list)
if(..())
return
usr.set_machine(src)
if(href_list["dispense"])
Dispense(text2num(href_list["dispense"]))
src.updateUsrDialog()
/obj/machinery/abductor/gland_dispenser/proc/Dispense(var/count)
if(amounts[count]>0)
amounts[count]--
var/T = gland_types[count]
new T(get_turf(src))
@@ -0,0 +1,204 @@
/obj/machinery/abductor/experiment
name = "Experimental machinery"
desc = "A human-sized coffin sporting wide array of automatic surgery tools"
icon = 'icons/obj/abductor.dmi'
icon_state = "experiment-open"
density = 0
anchored = 1
state_open = 1
var/points = 0
var/list/history = new
var/flash = " - || - "
var/obj/machinery/abductor/console/console
/obj/machinery/abductor/experiment/MouseDrop_T(mob/target, mob/user)
if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user) || !ishuman(target))
return
if(IsAbductor(target))
return
close_machine(target)
/obj/machinery/abductor/experiment/allow_drop()
return 0
/obj/machinery/abductor/experiment/attack_hand(mob/user)
if(..())
return
experimentUI(user)
/obj/machinery/abductor/experiment/open_machine()
if(!state_open && !panel_open)
..()
/obj/machinery/abductor/experiment/close_machine(mob/target)
for(var/mob/living/carbon/C in loc)
if(IsAbductor(C))
return
if(state_open && !panel_open)
..(target)
/obj/machinery/abductor/experiment/proc/dissection_icon(var/mob/living/carbon/human/H)
var/icon/photo = null
var/g = (H.gender == FEMALE) ? "f" : "m"
if(!config.mutant_races || H.dna.species.use_skintones)
photo = icon("icon" = 'icons/mob/human.dmi', "icon_state" = "[H.skin_tone]_[g]_s")
else
photo = icon("icon" = 'icons/mob/human.dmi', "icon_state" = "[H.dna.species.id]_[g]_s")
photo.Blend("#[H.dna.mutant_color]", ICON_MULTIPLY)
var/icon/eyes_s
if(EYECOLOR in H.dna.species.specflags)
eyes_s = icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = "[H.dna.species.eyes]_s")
eyes_s.Blend("#[H.eye_color]", ICON_MULTIPLY)
var/datum/sprite_accessory/S
S = hair_styles_list[H.hair_style]
if(S && (HAIR in H.dna.species.specflags))
var/icon/hair_s = icon("icon" = S.icon, "icon_state" = "[S.icon_state]_s")
hair_s.Blend("#[H.hair_color]", ICON_MULTIPLY)
eyes_s.Blend(hair_s, ICON_OVERLAY)
S = facial_hair_styles_list[H.facial_hair_style]
if(S && (FACEHAIR in H.dna.species.specflags))
var/icon/facial_s = icon("icon" = S.icon, "icon_state" = "[S.icon_state]_s")
facial_s.Blend("#[H.facial_hair_color]", ICON_MULTIPLY)
eyes_s.Blend(facial_s, ICON_OVERLAY)
if(eyes_s)
photo.Blend(eyes_s, ICON_OVERLAY)
var/icon/splat = icon("icon" = 'icons/mob/dam_human.dmi',"icon_state" = "chest30")
photo.Blend(splat,ICON_OVERLAY)
return photo
/obj/machinery/abductor/experiment/proc/experimentUI(mob/user)
var/dat
dat += "<h3> Experiment </h3>"
if(occupant)
var/obj/item/weapon/photo/P = new
P.photocreate(null, icon(dissection_icon(occupant), dir = SOUTH))
user << browse_rsc(P.img, "dissection_img")
dat += "<table><tr><td>"
dat += "<img src=dissection_img height=80 width=80>" //Avert your eyes
dat += "</td><td>"
dat += "<a href='?src=\ref[src];experiment=1'>Probe</a><br>"
dat += "<a href='?src=\ref[src];experiment=2'>Dissect</a><br>"
dat += "<a href='?src=\ref[src];experiment=3'>Analyze</a><br>"
dat += "</td></tr></table>"
else
dat += "<span class='linkOff'> Experiment </span>"
if(!occupant)
dat += "<h3>Machine Unoccupied</h3>"
else
dat += "<h3>Subject Status : </h3>"
dat += "[occupant.name] => "
switch(occupant.stat)
if(0)
dat += "<span class='good'>Conscious</span>"
if(1)
dat += "<span class='average'>Unconscious</span>"
else
dat += "<span class='bad'>DEAD</span>"
dat += "<br>"
dat += "[flash]"
dat += "<br>"
dat += "<a href='?src=\ref[src];refresh=1'>Scan</a>"
dat += "<a href='?src=\ref[src];[state_open ? "close=1'>Close</a>" : "open=1'>Open</a>"]"
var/datum/browser/popup = new(user, "experiment", "Probing Console", 300, 300)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.set_content(dat)
popup.open()
/obj/machinery/abductor/experiment/Topic(href, href_list)
if(..() || usr == occupant)
return
usr.set_machine(src)
if(href_list["refresh"])
updateUsrDialog()
return
if(href_list["open"])
open_machine()
return
if(href_list["close"])
close_machine()
return
if(occupant && occupant.stat != DEAD)
if(href_list["experiment"])
flash = Experiment(occupant,href_list["experiment"])
updateUsrDialog()
add_fingerprint(usr)
/obj/machinery/abductor/experiment/proc/Experiment(var/mob/occupant,var/type)
var/mob/living/carbon/human/H = occupant
var/point_reward = 0
if(H in history)
return "<span class='bad'>Specimen already in the database</span>"
if(H.stat == DEAD)
say("Specimen deceased - please provide fresh sample.")
return "<span class='bad'>Specimen Deceased</span>"
var/obj/item/gland/GlandTest = locate() in H
if(!GlandTest)
say("Experimental dissection not detected!")
return "<span class='bad'>No glands detected!</span>"
if(H.mind != null || H.ckey != null)
history += H
say("Processing Specimen...")
sleep(5)
switch(text2num(type))
if(1)
H << "<span class='warning'>You feel violated.</span>"
if(2)
H << "<span class='warning'>You feel being sliced and put back together.</span>"
if(3)
H << "<span class='warning'>You feel under intense scrutiny.</span>"
sleep(5)
H << "<span class='warning'>Your mind snaps!</span>"
var/objtype = pick(typesof(/datum/objective/abductee/) - /datum/objective/abductee/)
var/datum/objective/abductee/O = new objtype()
H.mind.objectives += O
var/obj_count = 1
H << "<span class='notice'>Your current objectives:</span>"
for(var/datum/objective/objective in H.mind.objectives)
H << "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
obj_count++
for(var/obj/item/gland/G in H)
G.Start()
point_reward++
if(point_reward > 0)
open_machine()
SendBack(H)
playsound(src.loc, 'sound/machines/ding.ogg', 50, 1)
points += point_reward
return "<span class='good'>Experiment Successfull! [point_reward] new data-points collected.</span>"
else
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 1)
return "<span class='bad'>Experiment Failed! No replacement organ detected.</span>"
else
say("Brain Activity Nonexistant - Disposing Sample...")
open_machine()
SendBack(H)
return "<span class='bad'>Specimen Braindead - Disposed</span>"
return "<span class='bad'>ERROR</span>"
/obj/machinery/abductor/experiment/proc/SendBack(var/mob/living/carbon/human/H)
H.Sleeping(8)
var/area/A
if(console && console.pad && console.pad.teleport_target)
A = console.pad.teleport_target
else
A = teleportlocs[pick(teleportlocs)]
TeleportToArea(H,A)
/obj/machinery/abductor/experiment/update_icon()
if(state_open)
icon_state = "experiment-open"
else
icon_state = "experiment"
/obj/machinery/abductor/experiment/say_quote(text)
return "beeps, \"[text]\""
@@ -0,0 +1,86 @@
/obj/machinery/abductor/pad
name = "Alien Telepad"
desc = "Use this to transport to and from human habitat"
icon = 'icons/obj/abductor.dmi'
icon_state = "alien-pad-idle"
anchored = 1
var/area/teleport_target
/obj/machinery/abductor/proc/TeleportToArea(var/mob/living/target,var/area/thearea)
var/list/L = list()
for(var/turf/T in get_area_turfs(thearea.type))
if(!T.density)
var/clear = 1
for(var/obj/O in T)
if(O.density)
clear = 0
break
if(clear)
L+=T
if(!L.len)
return
if(target && target.buckled)
target.buckled.unbuckle_mob()
var/list/tempL = L
var/attempt = null
var/success = 0
while(tempL.len)
attempt = pick(tempL)
target.Move(attempt)
if(get_turf(target) == attempt)
success = 1
break
else
tempL.Remove(attempt)
if(!success)
target.loc = pick(L)
/obj/machinery/abductor/pad/proc/Warp(var/mob/living/target)
target.Move(src.loc)
/obj/machinery/abductor/pad/proc/Send()
if(teleport_target == null)
teleport_target = teleportlocs[pick(teleportlocs)]
flick("alien-pad", src)
for(var/mob/living/target in src.loc)
TeleportToArea(target,teleport_target)
spawn(0)
anim(target.loc,target,'icons/mob/mob.dmi',,"uncloak",,target.dir)
/obj/machinery/abductor/pad/proc/Retrieve(var/mob/living/carbon/human/target)
flick("alien-pad", src)
spawn(0)
anim(target.loc,target,'icons/mob/mob.dmi',,"uncloak",,target.dir)
Warp(target)
/obj/machinery/abductor/pad/proc/MobToLoc(var/place,var/mob/living/target)
var/obj/effect/teleport_abductor/F = new(place)
var/datum/effect/effect/system/spark_spread/S = new
S.set_up(10,0,place)
S.start()
sleep(80)
qdel(F)
flick("alien-pad", src)
target.forceMove(place)
anim(target.loc,target,'icons/mob/mob.dmi',,"uncloak",,target.dir)
/obj/machinery/abductor/pad/proc/PadToLoc(var/place)
var/obj/effect/teleport_abductor/F = new(place)
var/datum/effect/effect/system/spark_spread/S = new
S.set_up(10,0,place)
S.start()
sleep(80)
qdel(F)
flick("alien-pad", src)
for(var/mob/living/target in src.loc)
target.forceMove(place)
spawn(0)
anim(target.loc,target,'icons/mob/mob.dmi',,"uncloak",,target.dir)
/obj/effect/teleport_abductor
name = "Huh"
icon = 'icons/obj/abductor.dmi'
icon_state = "teleport"
+8 -8
View File
@@ -71,21 +71,21 @@
M << "<B>You are the [usr.real_name]'s apprentice! You are bound by magic contract to follow their orders and help them in accomplishing their goals."
switch(type)
if("destruction")
M.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile(null)
M.mind.spell_list += new /obj/effect/proc_holder/spell/dumbfire/fireball(null)
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile(null))
M.mind.AddSpell(new /obj/effect/proc_holder/spell/dumbfire/fireball(null))
M << "<B>Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned powerful, destructive spells. You are able to cast magic missile and fireball."
if("bluespace")
M.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null)
M.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(null)
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null))
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(null))
M << "<B>Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned reality bending mobility spells. You are able to cast teleport and ethereal jaunt."
if("healing")
M.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/charge(null)
M.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/conjure/forcewall(null)
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/charge(null))
M.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/forcewall(null))
M.equip_to_slot_or_del(new /obj/item/weapon/gun/magic/staff/healing(M), slot_r_hand)
M << "<B>Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned livesaving survival spells. You are able to cast charge and forcewall."
if("robeless")
M.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/knock(null)
M.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/mind_transfer(null)
M.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null))
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mind_transfer(null))
M << "<B>Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned stealthy, robeless spells. You are able to cast knock and mindswap."
equip_antag(M)
+10 -5
View File
@@ -1,4 +1,6 @@
/datum/game_mode/blob/check_finished()
if(replacementmode && round_converted == 2)
return replacementmode.check_finished()
if(round_converted)
return ..()
if(infected_crew.len > burst)//Some blobs have yet to burst
@@ -6,15 +8,18 @@
if(blobwincount <= blobs.len)//Blob took over
return 1
if(!blob_cores.len) // blob is dead
if(config.continuous_round_blob)
round_converted = convert_roundtype()
if(!round_converted)
return 1
if(config.continuous["blob"])
SSshuttle.emergencyNoEscape = 0
if(SSshuttle.emergency.mode == SHUTTLE_STRANDED)
SSshuttle.emergency.mode = SHUTTLE_DOCKED
SSshuttle.emergency.timer = world.time
priority_announce("Hostile enviroment resolved. You have 3 minutes to board the Emergency Shuttle.", null, 'sound/AI/shuttledock.ogg', "Priority")
return 0
if(config.midround_antag["blob"])
round_converted = convert_roundtype()
if(!round_converted)
return 1
return ..()
return 1
if(station_was_nuked)//Nuke went off
return 1
+22 -16
View File
@@ -54,12 +54,11 @@
var/door = 0
var/grille = 0
var/mach = 0
var/num_territories = 1//Number of total valid territories for gang mode
/datum/station_state/proc/count()
for(var/turf/T in world)
if(T.z != ZLEVEL_STATION)
continue
/datum/station_state/proc/count(var/count_territories)
for(var/turf/T in block(locate(1,1,1), locate(world.maxx,world.maxy,1)))
if(istype(T,/turf/simulated/floor))
if(!(T:burnt))
@@ -79,20 +78,27 @@
else
src.r_wall += 1
for(var/obj/O in world)
if(O.z != ZLEVEL_STATION)
continue
if(istype(O, /obj/structure/window))
src.window += 1
else if(istype(O, /obj/structure/grille) && (!O:destroyed))
src.grille += 1
else if(istype(O, /obj/machinery/door))
src.door += 1
else if(istype(O, /obj/machinery))
src.mach += 1
return
for(var/obj/O in T.contents)
if(istype(O, /obj/structure/window))
src.window += 1
else if(istype(O, /obj/structure/grille) && (!O:destroyed))
src.grille += 1
else if(istype(O, /obj/machinery/door))
src.door += 1
else if(istype(O, /obj/machinery))
src.mach += 1
if(count_territories)
var/list/valid_territories = list()
for(var/area/A in world) //First, collect all area types on the station zlevel
if(A.z == ZLEVEL_STATION)
if(!(A.type in valid_territories) && A.valid_territory)
valid_territories |= A.type
if(valid_territories.len)
num_territories = valid_territories.len //Add them all up to make the total number of area types
else
world << "ERROR: NO VALID TERRITORIES"
/datum/station_state/proc/score(var/datum/station_state/result)
if(!result) return 0
+6 -10
View File
@@ -35,6 +35,7 @@
melee_damage_upper = 4
attacktext = "hits"
attack_sound = 'sound/weapons/genhit1.ogg'
speak_emote = list("pulses")
var/obj/effect/blob/factory/factory = null
var/list/human_overlays = list()
var/is_zombie = 0
@@ -77,6 +78,7 @@
melee_damage_lower = 10
melee_damage_upper = 15
icon = H.icon
speak_emote = list("groans")
icon_state = "zombie_s"
H.hair_style = null
H.update_hair()
@@ -140,10 +142,11 @@
icon_dead = "blobbernaut_dead"
health = 240
maxHealth = 240
melee_damage_lower = 10
melee_damage_upper = 10
melee_damage_lower = 20
melee_damage_upper = 20
attacktext = "hits"
attack_sound = 'sound/effects/blobattack.ogg'
speak_emote = list("gurgles")
minbodytemp = 0
maxbodytemp = 360
force_threshold = 10
@@ -151,16 +154,9 @@
mob_size = MOB_SIZE_LARGE
/mob/living/simple_animal/hostile/blob/blobbernaut/AttackingTarget()
..()
if(isliving(target))
if(overmind)
overmind.blob_reagent_datum.reaction_mob(target, TOUCH)
/mob/living/simple_animal/hostile/blob/blobbernaut/blob_act()
return
/mob/living/simple_animal/hostile/blob/blobbernaut/death(gibbed)
..(gibbed)
flick("blobbernaut_death", src)
flick("blobbernaut_death", src)
+1 -1
View File
@@ -2,7 +2,7 @@
/mob/camera/blob/proc/can_buy(var/cost = 15)
if(blob_points < cost)
src << "<span class='warning'>You cannot afford this.</span>"
src << "<span class='warning'>You cannot afford this!</span>"
return 0
add_points(-cost)
return 1
+1 -1
View File
@@ -171,7 +171,7 @@
return
/obj/effect/blob/proc/take_damage(damage, damage_type)
if(!damage) // Avoid divide by zero errors
if(!damage || damage_type == STAMINA) // Avoid divide by zero errors
return
switch(damage_type)
if(BRUTE)
+1 -2
View File
@@ -88,9 +88,8 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon"
if(character.client.prefs.be_special & BE_CHANGELING)
if(!jobban_isbanned(character.client, "changeling") && !jobban_isbanned(character.client, "Syndicate"))
if(age_check(character.client))
if(!(character.job in ticker.mode.restricted_jobs))
if(!(character.job in restricted_jobs))
character.mind.make_Changling()
..()
/datum/game_mode/proc/forge_changeling_objectives(var/datum/mind/changeling)
//OBJECTIVES - random traitor objectives. Unique objectives "steal brain" and "identity theft".
@@ -17,10 +17,10 @@
var/obj/item/weapon/grab/G = user.get_active_hand()
if(!istype(G))
user << "<span class='warning'>We must be grabbing a creature in our active hand to absorb them.</span>"
user << "<span class='warning'>We must be grabbing a creature in our active hand to absorb them!</span>"
return
if(G.state <= GRAB_NECK)
user << "<span class='warning'>We must have a tighter grip to absorb this creature.</span>"
user << "<span class='warning'>We must have a tighter grip to absorb this creature!</span>"
return
var/mob/living/carbon/target = G.affecting
@@ -38,12 +38,10 @@
if(1)
user << "<span class='notice'>This creature is compatible. We must hold still...</span>"
if(2)
user << "<span class='notice'>We extend a proboscis.</span>"
user.visible_message("<span class='warning'>[user] extends a proboscis!</span>")
user.visible_message("<span class='warning'>[user] extends a proboscis!</span>", "<span class='notice'>We extend a proboscis.</span>")
if(3)
user << "<span class='notice'>We stab [target] with the proboscis.</span>"
user.visible_message("<span class='danger'>[user] stabs [target] with the proboscis!</span>")
target << "<span class='danger'>You feel a sharp stabbing pain!</span>"
user.visible_message("<span class='danger'>[user] stabs [target] with the proboscis!</span>", "<span class='notice'>We stab [target] with the proboscis.</span>")
target << "<span class='userdanger'>You feel a sharp stabbing pain!</span>"
target.take_overall_damage(40)
feedback_add_details("changeling_powers","A[stage]")
@@ -52,9 +50,8 @@
changeling.isabsorbing = 0
return
user << "<span class='notice'>We have absorbed [target]!</span>"
user.visible_message("<span class='danger'>[user] sucks the fluids from [target]!</span>")
target << "<span class='danger'>You have been absorbed by the changeling!</span>"
user.visible_message("<span class='danger'>[user] sucks the fluids from [target]!</span>", "<span class='notice'>We have absorbed [target].</span>")
target << "<span class='userdanger'>You are absorbed by the changeling!</span>"
if(!changeling.has_dna(target.dna))
changeling.absorb_dna(target, user)
@@ -1,6 +1,6 @@
/obj/effect/proc_holder/changeling/headcrab
name = "Last Resort"
desc = "We sacrifce our current body in a moment of need, stunning and damaging everyone nearby. If a dead body is nearby we infect it to raise again."
desc = "We sacrifice our current body in a moment of need, stunning and damaging everyone nearby. If a dead body is nearby we infect it to raise again."
chemical_cost = 20
dna_cost = 1
req_human = 1
@@ -11,6 +11,9 @@
spawn(5) // So it's not killed in explosion
var/mob/living/simple_animal/hostile/headcrab/crab = new(turf)
crab.origin = user.mind
if(user.mind)
user.mind.transfer_to(crab)
crab << "<span class='warning'>You burst out of the remains of your former body in a shower of gore!</span>"
user.gib()
feedback_add_details("changeling_powers","LR")
return 1
@@ -23,19 +23,19 @@
/obj/effect/proc_holder/changeling/weapon/try_to_sting(var/mob/user, var/mob/target)
if(istype(user.l_hand, weapon_type)) //Not the nicest way to do it, but eh
qdel(user.l_hand)
user.visible_message("<span class='warning'>With a sickening crunch, [user] reforms his [weapon_name_simple] into an arm!</span>", "<span class='notice'>We assimilate the [weapon_name_simple] back into our body.</span>", "<span class='warning>You hear organic matter ripping and tearing!</span>")
user.visible_message("<span class='warning'>With a sickening crunch, [user] reforms his [weapon_name_simple] into an arm!</span>", "<span class='notice'>We assimilate the [weapon_name_simple] back into our body.</span>", "<span class='italics>You hear organic matter ripping and tearing!</span>")
user.update_inv_l_hand()
return
if(istype(user.r_hand, weapon_type))
qdel(user.r_hand)
user.visible_message("<span class='warning'>With a sickening crunch, [user] reforms his [weapon_name_simple] into an arm!</span>", "<span class='notice'>We assimilate the [weapon_name_simple] back into our body.</span>", "<span class='warning>You hear organic matter ripping and tearing!</span>")
user.visible_message("<span class='warning'>With a sickening crunch, [user] reforms his [weapon_name_simple] into an arm!</span>", "<span class='notice'>We assimilate the [weapon_name_simple] back into our body.</span>", "<span class='italics>You hear organic matter ripping and tearing!</span>")
user.update_inv_r_hand()
return
..(user, target)
/obj/effect/proc_holder/changeling/weapon/sting_action(var/mob/user)
if(!user.drop_item())
user << "The [user.get_active_hand()] is stuck to your hand, you cannot grow a [weapon_name_simple] over it!"
user << "<span class='warning'>The [user.get_active_hand()] is stuck to your hand, you cannot grow a [weapon_name_simple] over it!</span>"
return
var/obj/item/W = new weapon_type(user)
user.put_in_hands(W)
@@ -64,7 +64,7 @@
var/mob/living/carbon/human/H = user
if(istype(H.wear_suit, suit_type) || istype(H.head, helmet_type))
H.visible_message("<span class='warning'>[H] casts off their [suit_name_simple]!</span>", "<span class='warning'>We cast off our [suit_name_simple][genetic_damage > 0 ? ", temporarily weakening our genomes." : "."]</span>", "<span class='warning'>You hear the organic matter ripping and tearing!</span>")
H.visible_message("<span class='warning'>[H] casts off their [suit_name_simple]!</span>", "<span class='warning'>We cast off our [suit_name_simple][genetic_damage > 0 ? ", temporarily weakening our genomes." : "."]</span>", "<span class='italics'>You hear the organic matter ripping and tearing!</span>")
qdel(H.wear_suit)
qdel(H.head)
H.update_inv_wear_suit()
@@ -133,10 +133,10 @@
/obj/item/weapon/melee/arm_blade/New()
..()
if(ismob(loc))
loc.visible_message("<span class='warning'>A grotesque blade forms around [loc.name]\'s arm!</span>", "<span class='warning'>Our arm twists and mutates, transforming it into a deadly blade.</span>", "<span class='warning'>You hear organic matter ripping and tearing!</span>")
loc.visible_message("<span class='warning'>A grotesque blade forms around [loc.name]\'s arm!</span>", "<span class='warning'>Our arm twists and mutates, transforming it into a deadly blade.</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
/obj/item/weapon/melee/arm_blade/dropped(mob/user)
user.visible_message("<span class='warning'>With a sickening crunch, [user] reforms his blade into an arm!</span>", "<span class='notice'>We assimilate the blade back into our body.</span>", "<span class='warning>You hear organic matter ripping and tearing!</span>")
user.visible_message("<span class='warning'>With a sickening crunch, [user] reforms his blade into an arm!</span>", "<span class='notice'>We assimilate the blade back into our body.</span>", "<span class='italics>You hear organic matter ripping and tearing!</span>")
qdel(src)
/obj/item/weapon/melee/arm_blade/afterattack(atom/target, mob/user, proximity)
@@ -157,16 +157,16 @@
return
if(A.hasPower())
user << "<span class='notice'>The airlock's motors resist our efforts to force it.</span>"
user << "<span class='warning'>The airlock's motors resist our efforts to force it!</span>"
return
else if(A.locked)
user << "<span class='notice'>The airlock's bolts prevent it from being forced.</span>"
user << "<span class='warning'>The airlock's bolts prevent it from being forced!</span>"
return
else
//user.say("Heeeeeeeeeerrre's Johnny!")
user.visible_message("<span class='warning'>[user] forces the door to open with \his [src]!</span>", "<span class='warning'>We force the door to open.</span>", "<span class='warning'>You hear a metal screeching sound.</span>")
user.visible_message("<span class='warning'>[user] forces the door to open with \his [src]!</span>", "<span class='warning'>We force the door to open.</span>", "<span class='italics'>You hear a metal screeching sound.</span>")
A.open(1)
@@ -207,7 +207,7 @@
/obj/item/weapon/melee/shield/New()
..()
if(ismob(loc))
loc.visible_message("<span class='warning'>The end of [loc.name]\'s hand inflates rapidly, forming a huge shield-like mass!</span>", "<span class='warning'>We inflate our hand into a strong shield.</span>", "<span class='warning'>You hear organic matter ripping and tearing!</span>")
loc.visible_message("<span class='warning'>The end of [loc.name]\'s hand inflates rapidly, forming a huge shield-like mass!</span>", "<span class='warning'>We inflate our hand into a strong shield.</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
/obj/item/clothing/head/helmet/space/changeling/dropped()
qdel(src)
@@ -216,7 +216,7 @@
if(remaining_uses < 1)
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
H.visible_message("<span class='warning'>With a sickening crunch, [H] reforms his shield into an arm!</span>", "<span class='notice'>We assimilate our shield into our body</span>", "<span class='warning>You hear organic matter ripping and tearing!</span>")
H.visible_message("<span class='warning'>With a sickening crunch, [H] reforms his shield into an arm!</span>", "<span class='notice'>We assimilate our shield into our body</span>", "<span class='italics>You hear organic matter ripping and tearing!</span>")
H.unEquip(src, 1)
qdel(src)
return 0
@@ -256,7 +256,7 @@
/obj/item/clothing/suit/space/changeling/New()
..()
if(ismob(loc))
loc.visible_message("<span class='warning'>[loc.name]\'s flesh rapidly inflates, forming a bloated mass around their body!</span>", "<span class='warning'>We inflate our flesh, creating a spaceproof suit!</span>", "<span class='warning'>You hear organic matter ripping and tearing!</span>")
loc.visible_message("<span class='warning'>[loc.name]\'s flesh rapidly inflates, forming a bloated mass around their body!</span>", "<span class='warning'>We inflate our flesh, creating a spaceproof suit!</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
SSobj.processing += src
/obj/item/clothing/suit/space/changeling/dropped()
@@ -312,7 +312,7 @@
/obj/item/clothing/suit/armor/changeling/New()
..()
if(ismob(loc))
loc.visible_message("<span class='warning'>[loc.name]\'s flesh turns black, quickly transforming into a hard, chitinous mass!</span>", "<span class='warning'>We harden our flesh, creating a suit of armor!</span>", "<span class='warning'>You hear organic matter ripping and tearing!</span>")
loc.visible_message("<span class='warning'>[loc.name]\'s flesh turns black, quickly transforming into a hard, chitinous mass!</span>", "<span class='warning'>We harden our flesh, creating a suit of armor!</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
/obj/item/clothing/suit/armor/changeling/dropped()
qdel(src)
@@ -73,6 +73,6 @@
if(character.client.prefs.be_special & BE_CHANGELING)
if(!jobban_isbanned(character.client, "changeling") && !jobban_isbanned(character.client, "Syndicate"))
if(age_check(character.client))
if(!(character.job in ticker.mode.restricted_jobs))
if(!(character.job in restricted_jobs))
character.mind.make_Changling()
..()
+2
View File
@@ -216,6 +216,7 @@
if (!istype(cult_mind))
return 0
if(!(cult_mind in cult) && is_convertable_to_cult(cult_mind))
cult_mind.current.Paralyse(5)
cult += cult_mind
cult_mind.current.cult_add_comm()
update_cult_icons_added(cult_mind)
@@ -233,6 +234,7 @@
if(cult_mind in cult)
cult -= cult_mind
cult_mind.current.verbs -= /mob/living/proc/cult_innate_comm
cult_mind.current.Paralyse(5)
cult_mind.current << "<span class='userdanger'>An unfamiliar white light flashes through your mind, cleansing the taint of the dark-one and the memories of your time as his servant with it.</span>"
cult_mind.memory = ""
cult_mind.cult_words = initial(cult_mind.cult_words)
+8 -8
View File
@@ -42,7 +42,7 @@ var/engwords = list("travel", "blood", "join", "hell", "destroy", "technology",
return
if(ishuman(usr) || ismonkey(usr)) //Damage only applies to humans and monkeys, to allow constructs to communicate
usr.visible_message("<span class='warning'>[usr.name] starts clawing at his arms like a mad man!")
usr.visible_message("<span class='warning'>[usr.name] starts clawing at his arms like a mad man!</span>", "<span class='warning'>You start clawing at his arms like a mad man!</span>")
apply_damage(25,BRUTE, "l_arm")
apply_damage(25,BRUTE, "r_arm")
sleep(50)
@@ -55,7 +55,7 @@ var/engwords = list("travel", "blood", "join", "hell", "destroy", "technology",
apply_damage(15,BRUTE, "r_arm")
if(usr.incapacitated())
return
usr.visible_message("<span class='warning'>[usr.name] paints strange symbols with their own blood")
usr.visible_message("<span class='warning'>[usr.name] paints strange symbols with their own blood.</span>", "<span class='warning'>You paint strange symbols with your own blood.</span>")
sleep(20)
usr.say("O bidai nabora se[pick("'","`")]sma!")
@@ -164,9 +164,9 @@ var/engwords = list("travel", "blood", "join", "hell", "destroy", "technology",
/obj/effect/rune/attack_hand(mob/living/user as mob) // OH GOD this is horrible
if(!iscultist(user))
user << "<span class='notice'>You can't mouth the arcane scratchings without fumbling over them.</span>"
user << "<span class='warning'>You can't mouth the arcane scratchings without fumbling over them!</span>"
return
var/message = "<span class='notice'>You are unable to speak the words of the rune.</span>"
var/message = "<span class='warning'>You are unable to speak the words of the rune!</span>"
if(!user.can_speak(message) && (user.mind && !user.mind.miming))
user << message
return
@@ -236,7 +236,7 @@ var/engwords = list("travel", "blood", "join", "hell", "destroy", "technology",
cultist.say(gibberish)
else
cultist.whisper(gibberish)
visible_message("<span class='danger'>The markings pulse with a small burst of light, then fall dark.</span>", 3, "<span class='danger'>You hear a faint fizzle.</span>", 2)
visible_message("<span class='danger'>The markings pulse with a small burst of light, then fall dark.</span>", 3, "<span class='italics'>You hear a faint fizzle.</span>", 2)
return
/obj/effect/rune/proc/check_icon()
@@ -637,8 +637,8 @@ var/engwords = list("travel", "blood", "join", "hell", "destroy", "technology",
return
for (var/mob/V in viewers(src))
V.show_message("<span class='danger'>[user] slices open a finger and begins to chant and paint symbols on the floor.</span>", 3, "<span class='danger'>You hear chanting.</span>", 2)
user << "<span class='danger'>You slice open one of your fingers and begin drawing a rune on the floor whilst chanting the ritual that binds your life essence with the dark arcane energies flowing through the surrounding world.</span>"
V.show_message("<span class='danger'>[user] slices open a finger and begins to chant and paint symbols on the floor.</span>", 3, "<span class='italics'>You hear chanting.</span>", 2)
user << "<span class='userdanger'>You slice open one of your fingers and begin drawing a rune on the floor whilst chanting the ritual that binds your life essence with the dark arcane energies flowing through the surrounding world.</span>"
user.take_overall_damage((rand(9)+1)/10) // 0.1 to 1.0 damage
if(do_after(user, 50))
if(usr.get_active_hand() != src)
@@ -670,7 +670,7 @@ var/engwords = list("travel", "blood", "join", "hell", "destroy", "technology",
// if(M == user)
for(var/entry in words)
words[entry] = T.words[entry]
user << "You copy the translation notes from your tome."
user << "<span class='notice'>You copy the translation notes from your tome.</span>"
/obj/item/weapon/tome/examine(mob/user)
+15 -15
View File
@@ -26,8 +26,8 @@ var/list/sacrificed = list()
else
user.whisper("Sas[pick("'","`")]so c'arta forbici!")
user.visible_message("<span class='danger'>[user] disappears in a flash of red light!</span>", \
"<span class='danger'>You feel as your body gets dragged through the dimension of Nar-Sie!</span>", \
"<span class='danger'>You hear a sickening crunch and sloshing of viscera.</span>")
"<span class='userdanger'>You feel as your body gets dragged through the dimension of Nar-Sie!</span>", \
"<span class='italics'>You hear a sickening crunch and sloshing of viscera.</span>")
user.loc = allrunesloc[rand(1,index)]
return
if(istype(src,/obj/effect/rune))
@@ -53,7 +53,7 @@ var/list/sacrificed = list()
IP = R
runecount++
if(runecount >= 2)
user << "<span class='danger'>You feel pain, as the rune disappears in reality shift caused by too much wear of space-time fabric</span>"
user << "<span class='userdanger'>You feel pain, as the rune disappears in reality shift caused by too much wear of space-time fabric</span>"
if (istype(user, /mob/living))
user.take_overall_damage(5, 0)
qdel(src)
@@ -85,7 +85,7 @@ var/list/sacrificed = list()
usr.whisper("N[pick("'","`")]ath reth sh'yro eth d'raggathnor!")
usr.visible_message("<span class='danger'>Rune disappears with a flash of red light, and in its place now a book lies.</span>", \
"<span class='danger'>You are blinded by the flash of red light! After you're able to see again, you see that now instead of the rune there's a book.</span>", \
"<span class='danger'>You hear a pop and smell ozone.</span>")
"<span class='italics'>You hear a pop and smell ozone.</span>")
if(istype(src,/obj/effect/rune))
new /obj/item/weapon/tome(src.loc)
else
@@ -110,8 +110,8 @@ var/list/sacrificed = list()
C.say("Mah[pick("'","`")]weyh pleggh at e'ntrath!")
if(cultsinrange.len >= 3)
M.visible_message("<span class='danger'>[M] writhes in pain as the markings below him glow a bloody red.</span>", \
"<span class='danger'>AAAAAAHHHH!</span>", \
"<span class='danger'>You hear an anguished scream.</span>")
"<span class='userdanger'>AAAAAAHHHH!</span>", \
"<span class='italics'>You hear an anguished scream.</span>")
if(is_convertable_to_cult(M.mind))
ticker.mode.add_cultist(M.mind)
M.mind.special_role = "Cultist"
@@ -221,14 +221,14 @@ var/list/sacrificed = list()
usr.say ("Yu[pick("'","`")]gular faras desdae. Havas mithum javara. Umathar uf'kal thenar!")
usr.visible_message("<span class='danger'>Blood flows from the rune into [usr]!</span>", \
"<span class='danger'>The blood starts flowing from the rune and into your frail mortal body. You feel... empowered.</span>", \
"<span class='danger'>You hear a liquid flowing.</span>")
"<span class='italics'>You hear a liquid flowing.</span>")
var/mob/living/user = usr
if(user.bhunger)
user.bhunger = max(user.bhunger-2*drain,0)
if(drain>=50)
user.visible_message("<span class='danger'>[user]'s eyes give off eerie red glow!</span>", \
"<span class='danger'>...but it wasn't nearly enough. You crave, crave for more. The hunger consumes you from within.</span>", \
"<span class='danger'>You hear a heartbeat.</span>")
"<span class='italics'>You hear a heartbeat.</span>")
user.bhunger += drain
src = user
spawn()
@@ -341,10 +341,10 @@ var/list/sacrificed = list()
usr.say("Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!")
corpse_to_raise.visible_message("<span class='danger'>[corpse_to_raise]'s eyes glow with a faint red as he stands up, slowly starting to breathe again.</span>", \
"<span class='danger'>Life... I'm alive again...</span>", \
"<span class='danger'>You hear a faint, slightly familiar whisper.</span>")
"<span class='italics'>You hear a faint, slightly familiar whisper.</span>")
body_to_sacrifice.visible_message("<span class='danger'>[body_to_sacrifice] is torn apart, a black smoke swiftly dissipating from his remains!</span>", \
"<span class='danger'>You feel as your blood boils, tearing you apart.</span>", \
"<span class='danger'>You hear a thousand voices, all crying in pain.</span>")
"<span class='italics'>You hear a thousand voices, all crying in pain.</span>")
body_to_sacrifice.gib()
// if(ticker.mode.name == "cult")
@@ -396,7 +396,7 @@ var/list/sacrificed = list()
usr.say("Fwe[pick("'","`")]sh mah erl nyag r'ya!")
usr.visible_message("<span class='danger'>[usr]'s eyes glow blue as \he freezes in place, absolutely motionless.</span>", \
"<span class='danger'>The shadow that is your spirit separates itself from your body. You are now in the realm beyond. While this is a great sight, being here strains your mind and body. Hurry...</span>", \
"<span class='danger'>You hear only complete silence for a moment.</span>")
"<span class='italics'>You hear only complete silence for a moment.</span>")
usr.ghostize(1)
L.ajourn = 1
while(L)
@@ -431,7 +431,7 @@ var/list/sacrificed = list()
var/mob/living/carbon/human/dummy/D = new(this_rune.loc)
usr.visible_message("<span class='danger'>A shape forms in the center of the rune. A shape of... a man.</span>", \
"<span class='danger'>A shape forms in the center of the rune. A shape of... a man.</span>", \
"<span class='danger'>You hear liquid flowing.</span>")
"<span class='italics'>You hear liquid flowing.</span>")
D.real_name = "[pick(first_names_male)] [pick(last_names)]"
D.status_flags = CANSTUN|CANWEAKEN|CANPARALYSE|CANPUSH
@@ -453,7 +453,7 @@ var/list/sacrificed = list()
if(D)
D.visible_message("<span class='danger'>[D] slowly dissipates into dust and bones.</span>", \
"<span class='danger'>You feel pain, as bonds formed between your soul and this homunculus break.</span>", \
"<span class='danger'>You hear faint rustle.</span>")
"<span class='italics'>You hear faint rustle.</span>")
D.dust()
return
@@ -552,7 +552,7 @@ var/list/sacrificed = list()
runedec+=10
user.visible_message("<span class='danger'>[user] keels over dead, his blood glowing blue as it escapes his body and dissipates into thin air.</span>", \
"<span class='danger'>In the last moment of your humble life, you feel an immense pain as fabric of reality mends... with your blood.</span>", \
"<span class='danger'>You hear faint rustle.</span>")
"<span class='italics'>You hear faint rustle.</span>")
for(,user.stat==2)
sleep(600)
if (!user)
@@ -877,7 +877,7 @@ var/list/sacrificed = list()
C.take_overall_damage(25, 0)
user.visible_message("<span class='danger'>Rune disappears with a flash of red light, and in its place now a body lies.</span>", \
"<span class='danger'>You are blinded by the flash of red light! After you're able to see again, you see that now instead of the rune there's a body.</span>", \
"<span class='danger'>You hear a pop and smell ozone.</span>")
"<span class='italics'>You hear a pop and smell ozone.</span>")
qdel(src)
return fizzle(user)
+47 -9
View File
@@ -84,7 +84,7 @@
spawn (rand(waittime_l, waittime_h))
send_intercept(0)
start_state = new /datum/station_state()
start_state.count()
start_state.count(1)
return 1
///make_antag_chance()
@@ -104,7 +104,7 @@
living_crew++
if(living_crew / joined_player_list.len <= config.midround_antag_life_check) //If a lot of the player base died, we start fresh
message_admins("Convert_roundtype failed due to too many dead people. Limit is [config.midround_antag_life_check * 100]% living crew")
return 0
return null
var/list/datum/game_mode/runnable_modes = config.get_runnable_midround_modes(living_crew)
var/list/datum/game_mode/usable_modes = list()
@@ -114,11 +114,9 @@
else
del(G)
SSshuttle.emergencyNoEscape = 0 //Time to get the fuck out of here
if(!usable_modes)
message_admins("Convert_roundtype failed due to no valid modes to convert to. Please report this error to the Coders.")
return 0
return null
replacementmode = pickweight(usable_modes)
@@ -131,7 +129,7 @@
if(world.time >= (config.midround_antag_time_check * 600))
message_admins("Convert_roundtype failed due to round length. Limit is [config.midround_antag_time_check] minutes.")
return 0
return null
var/list/antag_canadates = list()
@@ -141,7 +139,7 @@
if(!antag_canadates)
message_admins("Convert_roundtype failed due to no antag canadates.")
return 0
return null
antag_canadates = shuffle(antag_canadates)
@@ -150,9 +148,12 @@
if(config.protect_assistant_from_antagonist)
replacementmode.restricted_jobs += "Assistant"
message_admins("The roundtype will be converted. If you feel that the round should not continue, <A HREF='?_src_=holder;end_round=\ref[usr]'>end the round now</A>.")
message_admins("The roundtype will be converted. If you have other plans for the station or think the round should end <A HREF='?_src_=holder;toggle_midround_antag=\ref[usr]'>stop the creation of antags</A> or <A HREF='?_src_=holder;end_round=\ref[usr]'>end the round now</A>.")
spawn(rand(1800,4200)) //somewhere between 3 and 7 minutes from now
spawn(rand(1200,3000)) //somewhere between 2 and 5 minutes from now
if(!config.midround_antag[ticker.mode.config_tag])
round_converted = 0
return 1
for(var/mob/living/carbon/human/H in antag_canadates)
replacementmode.make_antag_chance(H)
round_converted = 2
@@ -172,6 +173,42 @@
/datum/game_mode/proc/declare_completion()
var/clients = 0
var/surviving_humans = 0
var/surviving_total = 0
var/ghosts = 0
var/escaped_humans = 0
var/escaped_total = 0
for(var/mob/M in player_list)
if(M.client)
clients++
if(ishuman(M))
if(!M.stat)
surviving_humans++
if(M.z == 2)
escaped_humans++
if(!M.stat)
surviving_total++
if(M.z == 2)
escaped_total++
if(isobserver(M))
ghosts++
if(clients > 0)
feedback_set("round_end_clients",clients)
if(ghosts > 0)
feedback_set("round_end_ghosts",ghosts)
if(surviving_humans > 0)
feedback_set("survived_human",surviving_humans)
if(surviving_total > 0)
feedback_set("survived_total",surviving_total)
if(escaped_humans > 0)
feedback_set("escaped_human",escaped_humans)
if(escaped_total > 0)
feedback_set("escaped_total",escaped_total)
send2irc("Server", "Round just ended.")
return 0
@@ -226,6 +263,7 @@
if(BE_GANG) roletext="gangster"
if(BE_CULTIST) roletext="cultist"
if(BE_MONKEY) roletext="monkey"
if(BE_ABDUCTOR) roletext="abductor"
// Ultimate randomizing code right here
+194 -147
View File
@@ -2,10 +2,19 @@
//Gang War Game Mode
/datum/game_mode
var/list/datum/mind/A_bosses = list() //gang A bosses
var/list/datum/mind/A_gangsters = list() //gang A Members
var/list/datum/mind/B_bosses = list() //gang B bosses
var/list/datum/mind/B_gangsters = list() //gang B Members
var/list/datum/mind/A_gang = list() //gang A Members
var/list/datum/mind/B_gang = list() //gang B Members
var/list/datum/mind/A_bosses = list() //gang A Bosses
var/list/datum/mind/B_bosses = list() //gang B Bosses
var/obj/item/device/gangtool/A_tools = list()
var/obj/item/device/gangtool/B_tools = list()
var/datum/gang_points/gang_points
var/list/A_territory = list()
var/list/B_territory = list()
var/list/A_territory_new = list()
var/list/A_territory_lost = list()
var/list/B_territory_new = list()
var/list/B_territory_lost = list()
/datum/game_mode/gang
name = "gang war"
@@ -16,15 +25,15 @@
required_enemies = 2
recommended_enemies = 2
enemy_minimum_age = 14
var/finished = 0
var/checkwin_counter = 0
var/goal_scalar = 0.6 //Goal = Total territories x goal_scalar
///////////////////////////
//Announces the game type//
///////////////////////////
/datum/game_mode/gang/announce()
world << "<B>The current game mode is - Gang War!</B>"
world << "<B>A violent turf war has erupted on the station!<BR>Gangsters - Take over the station by recruiting gangsters and killing the rival gang's boss! <BR>Crew - Identify and stop the mob bosses without killing either of them!</B>"
world << "<B>A violent turf war has erupted on the station!<BR>Gangsters - Take over the station by claiming more than [round(100*goal_scalar,1)]% of the station! <BR>Crew - The gangs will try to keep you on the station. Successfully evacuate the station to win!</B>"
///////////////////////////////////////////////////////////////////////////////
@@ -69,39 +78,30 @@
modePlayer += B_bosses
..()
/datum/game_mode/gang/process()
checkwin_counter++
if(checkwin_counter >= 5)
if(!finished)
ticker.mode.check_win()
checkwin_counter = 0
return 0
/datum/game_mode/gang/proc/assign_bosses()
var/datum/mind/boss = pick(antag_candidates)
A_bosses += boss
antag_candidates -= boss
boss.special_role = "[gang_name("A")] Gang (A) Boss"
log_game("[boss.key] has been selected as a boss for the [gang_name("A")] Gang (A)")
log_game("[boss.key] has been selected as the boss for the [gang_name("A")] Gang (A)")
boss = pick(antag_candidates)
B_bosses += boss
antag_candidates -= boss
boss.special_role = "[gang_name("B")] Gang (B) Boss"
log_game("[boss.key] has been selected as a boss for the [gang_name("B")] Gang (B)")
log_game("[boss.key] has been selected as the boss for the [gang_name("B")] Gang (B)")
/datum/game_mode/proc/forge_gang_objectives(var/datum/mind/boss_mind)
var/datum/objective/rival_obj = new
rival_obj.owner = boss_mind
rival_obj.explanation_text = "Assassinate or exile the [(boss_mind in A_bosses) ? gang_name("B") : gang_name("A")] Gang's bosses."
rival_obj.explanation_text = "Claim more than 60% the station before the [(boss_mind in A_bosses) ? gang_name("B") : gang_name("A")] Gang does."
boss_mind.objectives += rival_obj
/datum/game_mode/proc/greet_gang(var/datum/mind/boss_mind, var/you_are=1)
var/obj_count = 1
if (you_are)
boss_mind.current << "<FONT size=3 color=red><B>You are a [(boss_mind in A_bosses) ? gang_name("A") : gang_name("B")] Gang Boss!</B></FONT>"
boss_mind.current << "<FONT size=3 color=red><B>You are the founding member of the [(boss_mind in A_bosses) ? gang_name("A") : gang_name("B")] Gang!</B></FONT>"
for(var/datum/objective/objective in boss_mind.objectives)
boss_mind.current << "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
obj_count++
@@ -118,51 +118,9 @@
mob << "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself."
mob.dna.remove_mutation(CLOWNMUT)
// find a radio! toolbox(es), backpack, belt, headset
var/loc = ""
var/obj/item/R = locate(/obj/item/device/pda) in mob.contents //Hide the uplink in a PDA if available, otherwise radio
if(!R)
R = locate(/obj/item/device/radio) in mob.contents
if (!R)
mob << "Unfortunately, Your Syndicate benefactors wasn't able to get you an uplink."
. = 0
else
if (istype(R, /obj/item/device/radio))
// generate list of radio freqs
var/obj/item/device/radio/target_radio = R
var/freq = 1441
var/list/freqlist = list()
while (freq <= 1489)
if (freq < 1451 || freq > 1459)
freqlist += freq
freq += 2
if ((freq % 2) == 0)
freq += 1
freq = freqlist[rand(1, freqlist.len)]
var/obj/item/device/uplink/hidden/T = new(R)
target_radio.hidden_uplink = T
T.uplink_owner = "[mob.key]"
target_radio.traitor_frequency = freq
mob << "Your Syndicate benefactors have cunningly disguised a Syndicate Uplink as your [R.name] [loc]. Simply dial the frequency [format_frequency(freq)] to unlock its hidden features."
mob.mind.store_memory("<B>Radio Freq:</B> [format_frequency(freq)] ([R.name] [loc]).")
else if (istype(R, /obj/item/device/pda))
// generate a passcode if the uplink is hidden in a PDA
var/pda_pass = "[rand(100,999)] [pick("Alpha","Bravo","Delta","Omega")]"
var/obj/item/device/uplink/hidden/T = new(R)
R.hidden_uplink = T
T.uplink_owner = "[mob.key]"
var/obj/item/device/pda/P = R
P.lock_code = pda_pass
mob << "Your Syndicate benefactors have cunningly disguised a Syndicate Uplink as your [R.name] [loc]. Simply enter the code \"[pda_pass]\" into the ringtone select to unlock its hidden features."
mob.mind.store_memory("<B>Uplink Passcode:</B> [pda_pass] ([R.name] [loc]).")
var/obj/item/device/flash/T = new(mob)
var/obj/item/device/recaller/recaller = new(mob)
var/obj/item/toy/crayon/spraycan/SC = new(mob)
var/obj/item/weapon/pen/gang/T = new(mob)
var/obj/item/device/gangtool/gangtool = new(mob)
var/obj/item/toy/crayon/spraycan/gang/SC = new(mob)
var/list/slots = list (
"backpack" = slot_in_backpack,
@@ -174,28 +132,28 @@
. = 0
var/spray = mob.equip_in_one_of_slots(SC,slots)
if (!spray)
mob << "Your Syndicate benefactors were unfortunately unable to get you some spraypaint."
else
mob << "The Spraypaint in your [spray] will help you spread your message of unrest."
mob.update_icons()
var/where2 = mob.equip_in_one_of_slots(recaller, slots)
if (!where2)
mob << "Your Syndicate benefactors were unfortunately unable to get you a Recaller."
else
mob << "The <b>Recaller</b> in your [where2] will allow you to prevent the station from prematurely evacuating. Use it to recall the emergency shuttle from anywhere on the station."
. += 2
var/where = mob.equip_in_one_of_slots(T, slots)
var/where = mob.equip_in_one_of_slots(gangtool, slots)
if (!where)
mob << "Your Syndicate benefactors were unfortunately unable to get you a flash."
mob << "Your Syndicate benefactors were unfortunately unable to get you a Gangtool."
else
mob << "The <b>flash</b> in your [where] will help you to persuade the crew to work for you."
gangtool.register_device(mob)
mob << "The <b>Gangtool</b> in your [where] will allow you to use your influence to purchase items and prevent the station from evacuating before you can take over. Use it to recall the emergency shuttle from anywhere on the station."
mob << "You can also promote your gang members to lieutenant by giving them an unregistered gangtool. Lieutenants cannot be deconverted and are able to use recruitment pens and gangtools."
. += 1
var/where2 = mob.equip_in_one_of_slots(T, slots)
if (!where2)
mob << "Your Syndicate benefactors were unfortunately unable to get you a recruitment pen to start."
else
mob << "The <b>recruitment pen</b> in your [where2] will help you get your gang started. Use it on unsuspecting crew members to recruit them."
. += 1
var/where3 = mob.equip_in_one_of_slots(SC, slots)
if (!where3)
mob << "Your Syndicate benefactors were unfortunately unable to get you a territory spraycan to start."
else
mob << "The <b>territory spraycan</b> in your [where3] can be used to claim areas of the station for your gang. The more territory your gang controls, the more influence you get."
. += 1
mob.update_icons()
return .
@@ -204,23 +162,16 @@
//Checks if the either gang have won or not//
/////////////////////////////////////////////
/datum/game_mode/gang/check_win()
var/A_victory = check_gang_victory(B_bosses) //Check if B bosses are dead or exiled
var/B_victory = check_gang_victory(A_bosses) //Check if A bosses are dead or exiled
if(A_victory && B_victory)
finished = "Draw" //Both teams fail. Allow for draws in case they're all incapacitated at the same time.
else if(A_victory)
if(A_territory.len > (start_state.num_territories * goal_scalar))
finished = "A" //Gang A wins
else if(B_victory)
else if(B_territory.len > (start_state.num_territories * goal_scalar))
finished = "B" //Gang B wins
///////////////////////////////
//Checks if the round is over//
///////////////////////////////
/datum/game_mode/gang/check_finished()
if(finished && !config.continuous_round_gang) //Check for Gang Boss death
if(finished)
return 1
return ..() //Check for evacuation/nuke
@@ -230,23 +181,28 @@
/datum/game_mode/proc/add_gangster(datum/mind/gangster_mind, var/gang, var/check = 1)
if(check && isloyal(gangster_mind.current)) //Check to see if the potential gangster is implanted
return 0
if((gangster_mind in A_bosses) || (gangster_mind in A_gangsters) || (gangster_mind in B_bosses) || (gangster_mind in B_gangsters))
if(gangster_mind in (A_bosses | A_gang | B_bosses | B_gang))
return 0
if(gang == "A")
A_gangsters += gangster_mind
A_gang += gangster_mind
else
B_gangsters += gangster_mind
B_gang += gangster_mind
if(check)
gangster_mind.current.Paralyse(5)
if(iscarbon(gangster_mind.current))
var/mob/living/carbon/carbon_mob = gangster_mind.current
carbon_mob.silent = max(carbon_mob.silent, 5)
carbon_mob.flash_eyes(1, 1)
gangster_mind.current.Stun(5)
gangster_mind.current << "<FONT size=3 color=red><B>You are now a member of the [gang=="A" ? gang_name("A") : gang_name("B")] Gang!</B></FONT>"
gangster_mind.current << "<font color='red'>Help your Boss take over the station by defeating the rival gang. You can identify your Boss by their brown \"B\" icon.</font>"
gangster_mind.current << "<font color='red'>Help your bosses take over the station by claiming territory with the special spraycans they provide. Simply spray on any unclaimed area of the station.</font>"
gangster_mind.current << "<font color='red'>You can identify your bosses by their brown \"G\" icon.</font>"
gangster_mind.current.attack_log += "\[[time_stamp()]\] <font color='red'>Has been converted to the [gang=="A" ? "[gang_name("A")] Gang (A)" : "[gang_name("B")] Gang (B)"]!</font>"
gangster_mind.special_role = "[gang=="A" ? "[gang_name("A")] Gang (A)" : "[gang_name("B")] Gang (B)"]"
update_gang_icons_added(gangster_mind,gang)
return 1
//////////////////////////////////////////////////////////////
//Deals with players going straight (Not a gangster anymore)//
//////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
//Deals with players reverting to neutral (Not a gangster anymore)//
////////////////////////////////////////////////////////////////////
/datum/game_mode/proc/remove_gangster(datum/mind/gangster_mind, var/beingborged, var/silent, var/exclude_bosses=0)
var/gang
@@ -259,12 +215,12 @@
B_bosses -= gangster_mind
gang = "B"
if(gangster_mind in A_gangsters)
A_gangsters -= gangster_mind
if(gangster_mind in A_gang)
A_gang -= gangster_mind
gang = "A"
if(gangster_mind in B_gangsters)
B_gangsters -= gangster_mind
if(gangster_mind in B_gang)
B_gang -= gangster_mind
gang = "B"
if(!gang) //not a valid gangster
@@ -321,21 +277,6 @@
ganghud.leave_hud(defector_mind.current)
set_antag_hud(defector_mind.current, null)
///////////////////////////
//Checks for gang victory//
///////////////////////////
/datum/game_mode/gang/proc/check_gang_victory(var/list/boss_list)
if(!boss_list.len)
return 0
for(var/datum/mind/boss_mind in boss_list)
if(boss_mind.current)
if(boss_mind.current.stat == DEAD || !ishuman(boss_mind.current) || !boss_mind.current.ckey)
return 1
var/turf/T = get_turf(boss_mind.current)
if(T && (T.z != ZLEVEL_STATION)) //If they leave the station they count as dead for this
return 1
return 0
return 1
//////////////////////////////////////////////////////////////////////
//Announces the end of the game with all relavent information stated//
@@ -343,10 +284,8 @@
/datum/game_mode/gang/declare_completion()
if(!finished)
world << "<FONT size=3 color=red><B>The station was [station_was_nuked ? "destroyed!" : "evacuated before either gang could claim it!"]</B></FONT>"
else if(finished == "Draw")
world << "<FONT size=3 color=red><B>All gang bosses have been killed or exiled!</B></FONT>"
else
world << "<FONT size=3 color=red><B>The [finished=="A" ? gang_name("A") : gang_name("B")] Gang defeated their rivals!</B></FONT>"
world << "<FONT size=3 color=red><B>The [finished=="A" ? gang_name("A") : gang_name("B")] Gang has taken over the station!</B></FONT>"
..()
return 1
@@ -359,36 +298,22 @@
else
winner = "Draw"
var/num_ganga = 0
var/list/agang = A_gangsters + A_bosses
for(var/datum/mind/agangster in agang)
if(agangster.current)
if(agangster.current in living_mob_list)
num_ganga++
var/num_gangb = 0
var/list/bgang = B_gangsters + B_bosses
for(var/datum/mind/bgangster in bgang)
if(bgangster.current)
if(bgangster.current in living_mob_list)
num_gangb++
if(A_bosses.len || A_gangsters.len)
if(A_bosses.len || A_gang.len)
if(winner)
world << "<br><b>The [gang_name("A")] Gang was [winner=="A" ? "<font color=green>victorious</font>" : "<font color=red>defeated</font>"] with [num_ganga] members!</b>"
world << "<br><font size=2><b>The [gang_name("A")] Gang Boss was:</b></font>"
world << "<br><b>The [gang_name("A")] Gang was [winner=="A" ? "<font color=green>victorious</font>" : "<font color=red>defeated</font>"] with [round((ticker.mode.A_territory.len/start_state.num_territories)*100, 1)]% control of the station!</b>"
world << "<br>The [gang_name("A")] Gang Bosses were:"
gang_membership_report(A_bosses)
world << "<br><font size=2><b>The [gang_name("A")] Gangsters were:</b></font>"
gang_membership_report(A_gangsters)
world << "<br>The [gang_name("A")] Gangsters were:"
gang_membership_report(A_gang)
world << "<br>"
if(B_bosses.len || B_gangsters.len)
if(B_bosses.len || B_gang.len)
if(winner)
world << "<br><b>The [gang_name("B")] Gang was [winner=="B" ? "<font color=green>victorious</font>" : "<font color=red>defeated</font>"] with [num_gangb] members!</b>"
world << "<br><font size=2><b>The [gang_name("B")] Gang Boss was:</b></font>"
world << "<br><b>The [gang_name("B")] Gang was [winner=="B" ? "<font color=green>victorious</font>" : "<font color=red>defeated</font>"] with [round((ticker.mode.B_territory.len/start_state.num_territories)*100, 1)]% control of the station!</b></b>"
world << "<br>The [gang_name("B")] Gang Bosses were:"
gang_membership_report(B_bosses)
world << "<br><font size=2><b>The [gang_name("B")] Gangsters were:</b></font>"
gang_membership_report(B_gangsters)
world << "<br>The [gang_name("B")] Gangsters were:"
gang_membership_report(B_gang)
world << "<br>"
/datum/game_mode/proc/gang_membership_report(var/list/membership)
@@ -409,3 +334,125 @@
text += ")"
world << text
//////////////////////////////////////////////////////////
//Handles influence, territories, and the victory checks//
//////////////////////////////////////////////////////////
/datum/gang_points
var/A = 30
var/B = 30
var/next_point_time = 0
/datum/gang_points/proc/start()
next_point_time = world.time + 3000
spawn(3000)
income()
/datum/gang_points/proc/income()
var/A_added_names = ""
var/B_added_names = ""
var/A_lost_names = ""
var/B_lost_names = ""
//Process lost territories
for(var/area in ticker.mode.A_territory_lost)
if(A_lost_names == "")
A_lost_names += ":<br>"
else
A_lost_names += ", "
A_lost_names += "[ticker.mode.A_territory_lost[area]], "
ticker.mode.A_territory -= area
for(var/area in ticker.mode.B_territory_lost)
if(B_lost_names == "")
B_lost_names += ":<br>"
else
B_lost_names += ", "
B_lost_names += "[ticker.mode.B_territory_lost[area]], "
ticker.mode.B_territory -= area
//Calculate and report influence growth
ticker.mode.message_gangtools(ticker.mode.A_tools,"<b>[gang_name("A")] Gang Status Report:</b>")
var/A_new = min(100,A + 15 + min(ticker.mode.A_territory.len, 15) + round(max(ticker.mode.A_territory.len - 15, 0) * 0.5,1))
var/A_message = ""
if(A_new != A)
A_message += "Your gang has gained <b>[A_new - A] Influence</b> for holding on to [ticker.mode.A_territory.len] territories."
if(A_new == 100)
A_message += "Maximum influence reached."
A = A_new
ticker.mode.message_gangtools(ticker.mode.A_tools,A_message,0)
ticker.mode.message_gangtools(ticker.mode.B_tools,"<b>[gang_name("B")] Gang Status Report:</b>")
var/B_new = min(100,B + 15 + min(ticker.mode.B_territory.len, 15) + round(max(ticker.mode.B_territory.len - 15, 0) * 0.5,1))
var/B_message = ""
if(B_new != B)
B_message += "Your gang has gained <b>[B_new - B] Influence</b> for holding on to [ticker.mode.B_territory.len] territories."
if(B_new == 100)
B_message += "Maximum influence reached."
B = B_new
ticker.mode.message_gangtools(ticker.mode.B_tools,B_message,0)
//Remove territories they already own from the buffer, so if they got tagged over, they can still earn income if they tag it back before the next status report
ticker.mode.A_territory_new -= ticker.mode.A_territory
ticker.mode.B_territory_new -= ticker.mode.B_territory
//Process new territories
for(var/area in ticker.mode.A_territory_new)
if(A_added_names == "")
A_added_names += ":<br>"
else
A_added_names += ", "
A_added_names += "[ticker.mode.A_territory_new[area]]"
ticker.mode.A_territory += area
for(var/area in ticker.mode.B_territory_new)
if(B_added_names == "")
B_added_names += ":<br>"
else
B_added_names += ", "
B_added_names += "[ticker.mode.B_territory_new[area]]"
ticker.mode.B_territory += area
//Report territory changes
ticker.mode.message_gangtools(ticker.mode.A_tools,"<b>[ticker.mode.A_territory_new.len] new territories</b>[A_added_names]",0)
ticker.mode.message_gangtools(ticker.mode.B_tools,"<b>[ticker.mode.B_territory_new.len] new territories</b>[B_added_names]",0,)
ticker.mode.message_gangtools(ticker.mode.A_tools,"<b>[ticker.mode.A_territory_lost.len] territories lost</b>[A_lost_names]",0,1)
ticker.mode.message_gangtools(ticker.mode.B_tools,"<b>[ticker.mode.B_territory_lost.len] territories lost</b>[B_lost_names]",0,1)
//Clear the lists
ticker.mode.A_territory_new = list()
ticker.mode.B_territory_new = list()
ticker.mode.A_territory_lost = list()
ticker.mode.B_territory_lost = list()
var/A_control = round((ticker.mode.A_territory.len/start_state.num_territories)*100, 1)
var/B_control = round((ticker.mode.B_territory.len/start_state.num_territories)*100, 1)
ticker.mode.message_gangtools((ticker.mode.A_tools),"Your gang now has <b>[A_control]% control</b> of the station.",0)
ticker.mode.message_gangtools((ticker.mode.A_tools),"The [gang_name("B")] Gang has <b>[B_control]% control</b> of the station.",0,1)
ticker.mode.message_gangtools((ticker.mode.B_tools),"Your gang now has <b>[B_control]% control</b> of the station.",0)
ticker.mode.message_gangtools((ticker.mode.B_tools),"The [gang_name("A")] Gang has <b>[A_control]% control</b> of the station.",0,1)
//Victory check
ticker.mode.check_win()
//Restart the counter
start()
////////////////////////////////////////////////
//Sends a message to the boss via his gangtool//
////////////////////////////////////////////////
/datum/game_mode/proc/message_gangtools(var/list/gangtools,var/message,var/beep=1,var/warning)
if(!gangtools.len || !message)
return
for(var/obj/item/device/gangtool/tool in gangtools)
var/mob/living/mob = get(tool.loc,/mob/living)
if(mob && mob.mind)
if(((tool.gang == "A") && ((mob.mind in A_gang) || (mob.mind in A_bosses))) || ((tool.gang == "B") && ((mob.mind in B_gang) || (mob.mind in B_bosses))))
mob << "<span class='[warning ? "warning" : "notice"]'>\icon[tool] [message]</span>"
if(beep)
playsound(mob.loc, 'sound/machines/twobeep.ogg', 50, 1)
+3 -3
View File
@@ -228,9 +228,9 @@
*/
/datum/intercept_text/proc/build_gang(datum/mind/correct_person)
src.text += "<BR><BR>Syndicate forces may be supplying opposing criminal organizations within your sector in an attempt at destabilizing our operations."
src.text += "Ensure law and order is maintained on the station and be on the lookout for violent confrontations between station factions."
src.text += "Central Command retains an interest in any criminal leaders captured by station security. The execution or exile of these persons are ill-advised."
src.text += "<BR><BR>We have recieved reports of a sudden increase of criminal activity in close proximity to our operations within your sector."
src.text += "Ensure law and order is maintained on the station and be on the lookout for unusually territorial behavior from the crew."
src.text += "In the event of a full-scale takeover attempt, sensitive research items are to be secured and the station evacuated ASAP."
src.text += "<BR><HR>"
/datum/intercept_text/proc/build_wizard(datum/mind/correct_person)
@@ -47,6 +47,10 @@
/mob/living/silicon/ai/proc/upgrade_turrets()
set category = "Malfunction"
set name = "Upgrade Turrets"
if(!canUseTopic())
return
src.verbs -= /mob/living/silicon/ai/proc/upgrade_turrets
for(var/obj/machinery/porta_turret/turret in machines)
if(turret.ai) //Make sure only the AI's turrets are affected.
@@ -67,8 +71,7 @@
set category = "Malfunction"
set name = "Initiate Hostile Lockdown"
if(src.stat == 2)
src <<"You cannot begin a lockdown because you are dead!"
if(!canUseTopic())
return
if(malf_cooldown)
@@ -105,8 +108,7 @@
set category = "Malfunction"
set name = "Disable Lockdown"
if(src.stat == 2)
src <<"You cannot disable lockdown because you are dead!"
if(!canUseTopic())
return
if(malf_cooldown)
return
@@ -141,6 +143,10 @@
/mob/living/silicon/ai/proc/disable_rcd()
set category = "Malfunction"
set name = "Disable RCDs"
if(!canUseTopic())
return
for(var/datum/AI_Module/large/disable_rcd/rcdmod in current_modules)
if(rcdmod.uses > 0)
rcdmod.uses --
@@ -165,6 +171,9 @@
set name = "Override Thermal Sensors"
set category = "Malfunction"
if(!canUseTopic())
return
for(var/obj/machinery/firealarm/F in world)
if(F.z != ZLEVEL_STATION)
continue
@@ -186,6 +195,9 @@
set name = "Disable Air Alarm Safeties"
set category = "Malfunction"
if(!canUseTopic())
return
for(var/obj/machinery/alarm/A in world)
if(A.z != ZLEVEL_STATION)
continue
@@ -207,11 +219,15 @@
/mob/living/silicon/ai/proc/overload_machine(obj/machinery/M as obj in world)
set name = "Overload Machine"
set category = "Malfunction"
if(!canUseTopic())
return
if (istype(M, /obj/machinery))
for(var/datum/AI_Module/small/overload_machine/overload in current_modules)
if(overload.uses > 0)
overload.uses --
audible_message("<span class='notice'>You hear a loud electrical buzzing sound!</span>")
audible_message("<span class='italics'>You hear a loud electrical buzzing sound!</span>")
src << "<span class='warning'>Overloading machine circuitry...</span>"
spawn(50)
if(M)
@@ -233,11 +249,15 @@
/mob/living/silicon/ai/proc/override_machine(obj/machinery/M as obj in world)
set name = "Override Machine"
set category = "Malfunction"
if(!canUseTopic())
return
if (istype(M, /obj/machinery))
for(var/datum/AI_Module/small/override_machine/override in current_modules)
if(override.uses > 0)
override.uses --
audible_message("<span class='notice'>You hear a loud electrical buzzing sound!</span>")
audible_message("<span class='italics'>You hear a loud electrical buzzing sound!</span>")
src << "<span class='warning'>Reprogramming machine behaviour...</span>"
spawn(50)
if(M && !M.gc_destroyed)
@@ -271,6 +291,9 @@
src << "Out of uses."
return
if(!canUseTopic())
return
var/sure = alert(src, "Make sure the room it is in is big enough, there is camera vision and that there is a 1x3 area for the machine. Are you sure you want to place the machine here?", "Are you sure?", "Yes", "No")
if(sure != "Yes")
return
@@ -319,6 +342,10 @@
/mob/living/silicon/ai/proc/blackout()
set category = "Malfunction"
set name = "Blackout"
if(!canUseTopic())
return
for(var/datum/AI_Module/small/blackout/blackout in current_modules)
if(blackout.uses > 0)
blackout.uses --
@@ -341,6 +368,10 @@
/mob/living/silicon/ai/proc/reactivate_camera(obj/machinery/camera/C as obj in cameranet.cameras)
set name = "Reactivate Camera"
set category = "Malfunction"
if(!canUseTopic())
return
if (istype (C, /obj/machinery/camera))
for(var/datum/AI_Module/small/reactivate_camera/camera in current_modules)
if(camera.uses > 0)
@@ -365,6 +396,10 @@
/mob/living/silicon/ai/proc/upgrade_camera(obj/machinery/camera/C as obj in cameranet.cameras)
set name = "Upgrade Camera"
set category = "Malfunction"
if(!canUseTopic())
return
if(istype(C))
var/datum/AI_Module/small/upgrade_camera/UC = locate(/datum/AI_Module/small/upgrade_camera) in current_modules
if(UC)
@@ -391,11 +426,11 @@
if(upgraded)
UC.uses --
C.visible_message("<span class='notice'>\icon[C] *beep*</span>")
src << "<span class='notice'>Camera successully upgraded!</span>"
src << "<span class='notice'>You successully upgrade the camera.</span>"
else
src << "<span class='notice'>This camera is already upgraded!</span>"
src << "<span class='warning'>This camera is already upgraded!</span>"
else
src << "<span class='notice'>Out of uses.</span>"
src << "<span class='warning'>Out of uses!</span>"
/datum/module_picker
var/temp = null
@@ -439,6 +474,10 @@
return
var/mob/living/silicon/ai/A = usr
if(A.stat == DEAD)
A <<"You are already dead!" //Omae Wa Mou Shindeiru
return
for(var/datum/AI_Module/AM in possible_modules)
if (href_list[AM.mod_pick_name])
+11 -5
View File
@@ -5,7 +5,7 @@
name = "AI malfunction"
config_tag = "malfunction"
antag_flag = BE_MALF
required_players = 1
required_players = 25
required_enemies = 1
recommended_enemies = 1
pre_setup_before_jobs = 1
@@ -170,12 +170,14 @@
/datum/game_mode/malfunction/check_finished()
if(round_converted)
return ..()
if(replacementmode && round_converted == 2)
return replacementmode.check_finished()
if(round_converted == 1) //No reason to waste resources
return ..() //Check for evacuation/nuke
if (station_captured && !to_nuke_or_not_to_nuke)
return 1
if (is_malf_ai_dead() || !check_ai_loc())
if(config.continuous_round_malf)
if(config.continuous["malfunction"])
if(SSshuttle.emergency.mode == SHUTTLE_STRANDED)
SSshuttle.emergency.mode = SHUTTLE_DOCKED
SSshuttle.emergency.timer = world.time
@@ -184,7 +186,11 @@
malf_mode_declared = 0
if(get_security_level() == "delta")
set_security_level("red")
round_converted = convert_roundtype()
if(config.midround_antag["malfunction"])
round_converted = convert_roundtype()
if(!round_converted)
return 1
return ..()
else
return 1
return ..() //check for shuttle and nuke
+2 -2
View File
@@ -238,7 +238,7 @@
explosion(src.loc, 0, 0, 4, 3, 0)
new /obj/effect/decal/cleanable/greenglow(get_turf(src))
for(var/mob/living/L in view(5, src))
L.apply_effect(40, IRRADIATE)
L.irradiate(40)
//Meaty Ore
/obj/effect/meteor/meaty
@@ -267,7 +267,7 @@
//Meaty Ore Xeno edition
/obj/effect/meteor/meaty/xeno
color = "#5EFF00"
meteordrop = /obj/item/weapon/reagent_containers/food/snacks/meat/xeno
meteordrop = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/xeno
meteorgibs = /obj/effect/gibspawner/xeno
/obj/effect/meteor/meaty/xeno/ram_turf(var/turf/T)
+1
View File
@@ -164,6 +164,7 @@
var/obj/item/device/radio/R = new /obj/item/device/radio/headset/syndicate/alt(synd_mob)
R.set_frequency(radio_freq)
R.freqlock = 1
synd_mob.equip_to_slot_or_del(R, slot_ears)
synd_mob.equip_to_slot_or_del(new /obj/item/clothing/under/syndicate(synd_mob), slot_w_uniform)
+8 -7
View File
@@ -122,7 +122,7 @@
location = locate(locationx,locationy,Z.z)
usr << "You set the pinpointer to locate [locationx],[locationy]"
usr << "<span class='notice'>You set the pinpointer to locate [locationx],[locationy]</span>"
return attack_self()
@@ -140,9 +140,9 @@
return
target=locate(possible_items[targetitem])
if(!target)
usr << "Failed to locate [targetitem]!"
usr << "<span class='warning'>Failed to locate [targetitem]!</span>"
return
usr << "You set the pinpointer to locate [targetitem]"
usr << "<span class='notice'>You set the pinpointer to locate [targetitem].</span>"
if("DNA")
var/DNAstring = input("Input DNA string to search for." , "Please Enter String." , "")
if(!DNAstring)
@@ -170,12 +170,13 @@
/obj/item/weapon/pinpointer/nukeop/attack_self(mob/user as mob)
if(!active)
active = 1
var/mode_text = "Authentication Disk Locator mode"
if(!mode)
workdisk()
user << "<span class='notice'>Authentication Disk Locator active.</span>"
else
mode_text = "Shuttle Locator mode"
worklocation()
user << "<span class='notice'>Shuttle Locator active.</span>"
user << "<span class='notice'>You activate the pinpointer([mode_text]).</span>"
else
active = 0
icon_state = "pinoff"
@@ -191,7 +192,7 @@
mode = 1 //Ensures worklocation() continues to work
worklocation()
playsound(loc, 'sound/machines/twobeep.ogg', 50, 1) //Plays a beep
visible_message("Shuttle Locator active.") //Lets the mob holding it know that the mode has changed
visible_message("Shuttle Locator mode actived.") //Lets the mob holding it know that the mode has changed
return //Get outta here
scandisk()
if(!the_disk)
@@ -221,7 +222,7 @@
mode = 0
workdisk()
playsound(loc, 'sound/machines/twobeep.ogg', 50, 1)
visible_message("<span class='notice'>Authentication Disk Locator active.</span>")
visible_message("<span class='notice'>Authentication Disk Locator mode actived.</span>")
return
if(!home)
home = SSshuttle.getShuttle("syndicate")
+1 -1
View File
@@ -49,7 +49,7 @@ datum/objective_item/steal/magboots
datum/objective_item/steal/corgimeat
name = "a piece of corgi meat"
targetitem = /obj/item/weapon/reagent_containers/food/snacks/meat/corgi
targetitem = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/corgi
difficulty = 5
excludefromjob = list("Head of Personnel", "Quartermaster", "Cargo Technician") //>hurting your little buddy ever
+25 -17
View File
@@ -146,18 +146,15 @@
"left hand" = slot_l_hand,
"right hand" = slot_r_hand,
)
var/spray = mob.equip_in_one_of_slots(R,slots)
var/where = mob.equip_in_one_of_slots(T, slots)
if (!spray)
mob << "The Syndicate were unfortunately unable to get you some spraypaint."
else
mob << "The Spraypaint in your [spray] will help you spread your message of unrest and revolution."
mob.update_icons()
mob.equip_in_one_of_slots(R,slots)
mob.update_icons()
if (!where)
mob << "The Syndicate were unfortunately unable to get you a flash."
else
mob << "The flash in your [where] will help you to persuade the crew to join your cause."
mob.update_icons()
return 1
/////////////////////////////////
@@ -182,7 +179,7 @@
for(var/datum/mind/rev_mind in head_revolutionaries)
mark_for_death(rev_mind, head_mind)
if(max_headrevs < initial(max_headrevs) && max_headrevs < heads.len)
if(head_revolutionaries.len < max_headrevs && head_revolutionaries.len < heads.len)
latejoin_headrev()
///////////////////////////////
@@ -190,14 +187,19 @@
///////////////////////////////
/datum/game_mode/revolution/proc/latejoin_headrev()
if(revolutionaries) //Head Revs are not in this list
var/datum/mind/stalin = pick(revolutionaries)
revolutionaries -= stalin
head_revolutionaries += stalin
log_game("[stalin.key] (ckey) has been promoted to a head rev")
equip_revolutionary(stalin.current)
forge_revolutionary_objectives(stalin)
greet_revolutionary(stalin)
++max_headrevs
var/list/promotable_revs = list()
for(var/datum/mind/khrushchev in revolutionaries)
if(khrushchev.current && khrushchev.current.client && khrushchev.current.stat != DEAD)
if(khrushchev.current.client.prefs.be_special & BE_REV)
promotable_revs += khrushchev
if(promotable_revs)
var/datum/mind/stalin = pick(promotable_revs)
revolutionaries -= stalin
head_revolutionaries += stalin
log_game("[stalin.key] (ckey) has been promoted to a head rev")
equip_revolutionary(stalin.current)
forge_revolutionary_objectives(stalin)
greet_revolutionary(stalin)
//////////////////////////////////////
//Checks if the revs have won or not//
@@ -213,7 +215,7 @@
//Checks if the round is over//
///////////////////////////////
/datum/game_mode/revolution/check_finished()
if(config.continuous_round_rev)
if(config.continuous["revolution"])
if(finished != 0)
SSshuttle.emergencyNoEscape = 0
return ..()
@@ -234,6 +236,11 @@
if((rev_mind in revolutionaries) || (rev_mind in head_revolutionaries))
return 0
revolutionaries += rev_mind
if(iscarbon(rev_mind.current))
var/mob/living/carbon/carbon_mob = rev_mind.current
carbon_mob.silent = max(carbon_mob.silent, 5)
carbon_mob.flash_eyes(1, 1)
rev_mind.current.Stun(5)
rev_mind.current << "<span class='danger'><FONT size = 3> You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution!</FONT></span>"
rev_mind.current.attack_log += "\[[time_stamp()]\] <font color='red'>Has been converted to the revolution!</font>"
rev_mind.special_role = "Revolutionary"
@@ -253,6 +260,7 @@
message_admins("[key_name_admin(rev_mind.current)] <A HREF='?_src_=holder;adminmoreinfo=\ref[rev_mind.current]'>?</A> has been borged while being a member of the revolution.")
else
rev_mind.current.Paralyse(5)
rev_mind.current << "<span class='danger'><FONT size = 3>You have been brainwashed! You are no longer a revolutionary! Your memory is hazy from the time you were a rebel...the only thing you remember is the name of the one who brainwashed you...</FONT></span>"
update_rev_icons_removed(rev_mind)
@@ -0,0 +1,259 @@
#define LIGHT_DAM_THRESHOLD 4
#define LIGHT_HEAL_THRESHOLD 2
#define LIGHT_DAMAGE_TAKEN 10
/*
SHADOWLING: A gamemode based on previously-run events
Aliens called shadowlings are on the station.
These shadowlings can 'enthrall' crew members and enslave them.
They also burn in the light but heal rapidly whilst in the dark.
The game will end under two conditions:
1. The shadowlings die
2. The emergency shuttle docks at CentCom
Shadowling strengths:
- The dark
- Hard vacuum (They are not affected by it)
- Their thralls who are not harmed by the light
- Stealth
Shadowling weaknesses:
- The light
- Fire
- Enemy numbers
- Lasers (Lasers are concentrated light and do more damage)
- Flashbangs (High stun and high burn damage; if the light stuns humans, you bet your ass it'll hurt the shadowling very much!)
Shadowlings start off disguised as normal crew members, and they only have two abilities: Hatch and Enthrall.
They can still enthrall and perhaps complete their objectives in this form.
Hatch will, after a short time, cast off the human disguise and assume the shadowling's true identity.
They will then assume the normal shadowling form and gain their abilities.
The shadowling will seem OP, and that's because it kinda is. Being restricted to the dark while being alone most of the time is extremely difficult and as such the shadowling needs powerful abilities.
Made by Xhuis
*/
/*
GAMEMODE
*/
/datum/game_mode
var/list/datum/mind/shadows = list()
var/list/datum/mind/thralls = list()
var/list/shadow_objectives = list()
var/required_thralls = 15 //How many thralls are needed (hardcoded for now)
var/shadowling_ascended = 0 //If at least one shadowling has ascended
var/shadowling_dead = 0 //is shadowling kill
/proc/is_thrall(var/mob/living/M)
return istype(M) && M.mind && ticker && ticker.mode && (M.mind in ticker.mode.thralls)
/proc/is_shadow_or_thrall(var/mob/living/M)
return istype(M) && M.mind && ticker && ticker.mode && ((M.mind in ticker.mode.thralls) || (M.mind in ticker.mode.shadows))
/proc/is_shadow(var/mob/living/M)
return istype(M) && M.mind && ticker && ticker.mode && (M.mind in ticker.mode.shadows)
/datum/game_mode/shadowling
name = "shadowling"
config_tag = "shadowling"
antag_flag = BE_SHADOWLING
required_players = 30
required_enemies = 2
recommended_enemies = 2
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain")
/datum/game_mode/shadowling/announce()
world << "<b>The current game mode is - Shadowling!</b>"
world << "<b>There are alien <span class='deadsay'>shadowlings</span> on the station. Crew: Kill the shadowlings before they can eat or enthrall the crew. Shadowlings: Enthrall the crew while remaining in hiding.</b>"
/datum/game_mode/shadowling/pre_setup()
if(config.protect_roles_from_antagonist)
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
restricted_jobs += "Assistant"
for(var/datum/mind/player in antag_candidates)
for(var/job in restricted_jobs)
if(player.assigned_role == job)
antag_candidates -= player
var/shadowlings = 2 //How many shadowlings there are; hardcoded to 2
while(shadowlings)
var/datum/mind/shadow = pick(antag_candidates)
shadows += shadow
antag_candidates -= shadow
modePlayer += shadow
shadow.special_role = "Shadowling"
shadowlings--
return 1
/datum/game_mode/shadowling/post_setup()
for(var/datum/mind/shadow in shadows)
log_game("[shadow.key] (ckey) has been selected as a Shadowling.")
sleep(10)
shadow.current << "<br>"
shadow.current << "<span class='deadsay'><b><font size=3>You are a shadowling!</font></b></span>"
greet_shadow(shadow)
finalize_shadowling(shadow)
process_shadow_objectives(shadow)
//give_shadowling_abilities(shadow)
..()
return
/datum/game_mode/proc/greet_shadow(var/datum/mind/shadow)
shadow.current << "<b>Currently, you are disguised as an employee aboard [world.name].</b>"
shadow.current << "<b>In your limited state, you have three abilities: Enthrall, Hatch, and Hivemind Commune.</b>"
shadow.current << "<b>Any other shadowlings are you allies. You must assist them as they shall assist you.</b>"
shadow.current << "<b>If you are new to shadowling, or want to read about abilities, check the wiki page at https://tgstation13.org/wiki/Shadowling</b><br>"
/datum/game_mode/proc/process_shadow_objectives(var/datum/mind/shadow_mind)
var/objective = "enthrall" //may be devour later, but for now it seems murderbone-y
if(objective == "enthrall")
var/objective_explanation = "Ascend to your true form by use of the Ascendance ability. This may only be used with [required_thralls] collective thralls, while hatched, and is unlocked with the Collective Mind ability."
shadow_objectives += "enthrall"
shadow_mind.memory += "<b>Objective #1</b>: [objective_explanation]"
shadow_mind.current << "<b>Objective #1</b>: [objective_explanation]<br>"
/datum/game_mode/proc/finalize_shadowling(var/datum/mind/shadow_mind)
var/mob/living/carbon/human/S = shadow_mind.current
shadow_mind.current.verbs += /mob/living/carbon/human/proc/shadowling_hatch
shadow_mind.spell_list += new /obj/effect/proc_holder/spell/targeted/enthrall
spawn(0)
shadow_mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind
update_shadow_icons_added(shadow_mind)
if(shadow_mind.assigned_role == "Clown")
S << "<span class='notice'>Your alien nature has allowed you to overcome your clownishness.</span>"
S.dna.remove_mutation(CLOWNMUT)
/datum/game_mode/proc/add_thrall(datum/mind/new_thrall_mind)
if (!istype(new_thrall_mind))
return 0
if(!(new_thrall_mind in thralls))
update_shadow_icons_added(new_thrall_mind)
thralls += new_thrall_mind
new_thrall_mind.current.attack_log += "\[[time_stamp()]\] <span class='danger'>Became a thrall</span>"
new_thrall_mind.memory += "<b>The Shadowlings' Objectives:</b> Ascend to your true form by use of the Ascendance ability. \
This may only be used with [required_thralls] collective thralls, while hatched, and is unlocked with the Collective Mind ability."
new_thrall_mind.current << "<b>The objectives of your shadowlings:</b>: Ascend to your true form by use of the Ascendance ability. \
This may only be used with [required_thralls] collective thralls, while hatched, and is unlocked with the Collective Mind ability."
new_thrall_mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind
return 1
/*
GAME FINISH CHECKS
*/
/datum/game_mode/shadowling/check_finished()
var/shadows_alive = 0 //and then shadowling was kill
for(var/datum/mind/shadow in shadows) //but what if shadowling was not kill?
if(!istype(shadow.current,/mob/living/carbon/human) && !istype(shadow.current,/mob/living/simple_animal/ascendant_shadowling))
continue
if(shadow.current.stat == DEAD)
continue
shadows_alive++
if(shadows_alive)
return ..()
else
shadowling_dead = 1 //but shadowling was kill :(
return 1
/datum/game_mode/shadowling/proc/check_shadow_victory()
var/success = 0 //Did they win?
if(shadow_objectives.Find("enthrall"))
success = shadowling_ascended
return success
/datum/game_mode/shadowling/declare_completion()
if(check_shadow_victory() && SSshuttle.emergency.mode >= SHUTTLE_ESCAPE) //Doesn't end instantly - this is hacky and I don't know of a better way ~X
world << "<span class='greentext'><b>The shadowlings have ascended and taken over the station!</b></span>"
else if(shadowling_dead && !check_shadow_victory()) //If the shadowlings have ascended, they can not lose the round
world << "<span class='redtext'><b>The shadowlings have been killed by the crew!</b></span>"
else if(!check_shadow_victory() && SSshuttle.emergency.mode >= SHUTTLE_ESCAPE)
world << "<span class='redtext'><b>The crew has escaped the station before the shadowlings could ascend!</b></span>"
..()
return 1
/datum/game_mode/proc/auto_declare_completion_shadowling()
var/text = ""
if(shadows.len)
text += "<br><span class='big'><b>The shadowlings were:</b></span>"
for(var/datum/mind/shadow in shadows)
text += printplayer(shadow)
text += "<br>"
if(thralls.len)
text += "<br><span class='big'><b>The thralls were:</b></span>"
for(var/datum/mind/thrall in thralls)
text += printplayer(thrall)
text += "<br>"
world << text
/*
MISCELLANEOUS
*/
/datum/species/shadow/ling
//Normal shadowpeople but with enhanced effects
name = "Shadowling"
id = "shadowling"
say_mod = "chitters"
specflags = list(NOBREATH,NOBLOOD,RADIMMUNE,NOGUNS) //Can't use guns due to muzzle flash
burnmod = 2 //2x burn damage lel
heatmod = 2
/datum/species/shadow/ling/spec_life(mob/living/carbon/human/H)
//H.shadowling_status = 1 //If they are affected more strongly by flashes and stuff
var/light_amount = 0
H.nutrition = NUTRITION_LEVEL_WELL_FED //i aint never get hongry
if(isturf(H.loc)) //Copypasta
var/turf/T = H.loc
var/area/A = T.loc
if(A)
if(A.lighting_use_dynamic) light_amount = T.lighting_lumcount
else light_amount = 10
if(light_amount > LIGHT_DAM_THRESHOLD) //Not complete blackness - they can live in very small light levels plus starlight
H.take_overall_damage(0, LIGHT_DAMAGE_TAKEN)
H << "<span class='userdanger'>The light burns you!</span>"
H << 'sound/weapons/sear.ogg'
else if (light_amount < LIGHT_HEAL_THRESHOLD)
H.heal_overall_damage(5,5)
H.adjustToxLoss(-5)
H.adjustBrainLoss(-25) //gibbering shadowlings are hilarious but also bad to have
H.adjustCloneLoss(-1)
H.SetWeakened(0)
H.SetStunned(0)
/datum/game_mode/proc/update_shadow_icons_added(datum/mind/shadow_mind)
var/datum/atom_hud/antag/shadow_hud = huds[ANTAG_HUD_SHADOW]
shadow_hud.join_hud(shadow_mind.current)
set_antag_hud(shadow_mind.current, ((shadow_mind in shadows) ? "shadowling" : "thrall"))
/datum/game_mode/proc/update_shadow_icons_removed(datum/mind/shadow_mind) //This should never actually occur, but it's here anyway.
var/datum/atom_hud/antag/shadow_hud = huds[ANTAG_HUD_SHADOW]
shadow_hud.leave_hud(shadow_mind.current)
set_antag_hud(shadow_mind.current, null)
@@ -0,0 +1,663 @@
/obj/effect/proc_holder/spell/targeted/glare
name = "Glare"
desc = "Stuns and mutes a target for a decent duration."
panel = "Shadowling Abilities"
charge_max = 300
clothes_req = 0
/obj/effect/proc_holder/spell/targeted/glare/cast(list/targets)
for(var/mob/living/carbon/human/target in targets)
if(!ishuman(target))
charge_counter = charge_max
return
if(target.stat)
charge_counter = charge_max
return
if(is_shadow_or_thrall(target))
usr << "<span class='danger'>You don't see why you would want to paralyze an ally.</span>"
charge_counter = charge_max
return
usr.visible_message("<span class='warning'><b>[usr]'s eyes flash a blinding red!</b></span>")
target.visible_message("<span class='danger'>[target] freezes in place, their eyes glazing over...</span>")
if(in_range(target, usr))
target << "<span class='userdanger'>Your gaze is forcibly drawn into [usr]'s eyes, and you are mesmerized by the heavenly lights...</span>"
else //Only alludes to the shadowling if the target is close by
target << "<span class='userdanger'>Red lights suddenly dance in your vision, and you are mesmerized by the heavenly lights...</span>"
target.Stun(10)
if(target.reagents)
target.reagents.add_reagent("mutetoxin", 4) //This is really bad but it's the only way it works.
/obj/effect/proc_holder/spell/aoe_turf/veil
name = "Veil"
desc = "Extinguishes all electronic lights in a decent radius."
panel = "Shadowling Abilities"
charge_max = 250 //Short cooldown because people can just turn the lights back on
clothes_req = 0
range = 5
/obj/effect/proc_holder/spell/aoe_turf/veil/cast(list/targets)
usr << "<span class='deadsay'>You silently disable all nearby lights.</span>"
var/list/blacklisted_lights = list(/obj/item/device/flashlight/flare, /obj/item/device/flashlight/slime)
for(var/turf/T in targets)
for(var/obj/item/device/flashlight/F in T.contents)
if(is_type_in_list(F, blacklisted_lights))
F.visible_message("<span class='danger'>[F] goes slightly dim for a moment.</span>")
return
F.on = 0
F.visible_message("<span class='danger'>[F] gutters and falls dark.</span>")
F.update_brightness()
for(var/obj/machinery/light/L in T.contents)
L.on = 0
L.visible_message("<span class='danger'>[L] flickers and falls dark.</span>")
L.update(0)
for(var/obj/item/device/pda/P in T.contents)
P.fon = 0
P.SetLuminosity(0)
for(var/obj/effect/glowshroom/G in orange(2, usr)) //Very small radius
G.visible_message("<span class='warning'>\The [G] withers away!</span>")
qdel(G)
for(var/mob/living/carbon/human/H in T.contents)
for(var/obj/item/device/flashlight/F in H)
if(is_type_in_list(F, blacklisted_lights))
F.visible_message("<span class='danger'>[F] goes slightly dim for a moment.</span>")
return
F.on = 0
F.visible_message("<span class='danger'>[F] gutters and falls dark.</span>")
F.update_brightness()
for(var/obj/item/device/pda/P in H)
P.fon = 0
P.SetLuminosity(0) //failsafe
if(H != usr)
H << "<span class='boldannounce'>You feel a chill and are plunged into darkness.</span>"
H.SetLuminosity(0) //This is required with the object-based lighting
/obj/effect/proc_holder/spell/targeted/shadow_walk
name = "Shadow Walk"
desc = "Phases you into the space between worlds for a short time, allowing movement through walls and invisbility."
panel = "Shadowling Abilities"
charge_max = 600
clothes_req = 0
range = -1
include_user = 1
/obj/effect/proc_holder/spell/targeted/shadow_walk/cast(list/targets)
for(var/mob/living/user in targets)
playsound(user.loc, 'sound/effects/bamf.ogg', 50, 1)
user.visible_message("<span class='danger'>[user] vanishes into thin air!</span>", "<span class='deadsay'>You enter the space between worlds as a passageway.</span>")
user.SetStunned(0)
user.SetWeakened(0)
user.incorporeal_move = 1
user.alpha = 0
if(user.buckled)
user.buckled.unbuckle_mob()
sleep(40) //4 seconds
user.visible_message("<span class='danger'>[user] appears out of nowhere!</span>", "<span class='deadsay'>The pressure becomes too much and you vacate the interdimensional darkness.</span>")
user.incorporeal_move = 0
user.alpha = 255
/obj/effect/proc_holder/spell/aoe_turf/flashfreeze
name = "Flash Freeze"
desc = "Instantly freezes the blood of nearby people, stunning them and causing burn damage."
panel = "Shadowling Abilities"
range = 5
charge_max = 1200
clothes_req = 0
/obj/effect/proc_holder/spell/aoe_turf/flashfreeze/cast(list/targets)
usr << "<span class='deadsay'>You freeze the nearby air.</span>"
playsound(usr.loc, 'sound/effects/ghost2.ogg', 50, 1)
for(var/turf/T in targets)
for(var/mob/living/carbon/human/target in T.contents)
if(is_shadow_or_thrall(target))
if(target == usr) //No message for the user, of course
continue
else
target << "<span class='danger'>You feel a blast of paralyzingly cold air wrap around you and flow past, but you are unaffected!</span>"
continue
target << "<span class='userdanger'>You are hit by a blast of paralyzingly cold air and feel goosebumps break out across your body!</span>"
target.Stun(2)
if(target.bodytemperature)
target.bodytemperature -= 200 //Extreme amount of initial cold
if(target.reagents)
target.reagents.add_reagent("frostoil", 15) //Half of a cryosting
//Enthrall is the single most important spell
/obj/effect/proc_holder/spell/targeted/enthrall
name = "Enthrall"
desc = "Allows you to enslave a conscious, non-braindead, non-catatonic human to your will. This takes some time to cast."
panel = "Shadowling Abilities"
charge_max = 450
clothes_req = 0
range = 1 //Adjacent to user
var/enthralling = 0
/obj/effect/proc_holder/spell/targeted/enthrall/cast(list/targets)
for(var/mob/living/carbon/human/target in targets)
if(!in_range(usr, target))
usr << "<span class='warning'>You need to be closer to enthrall [target].</span>"
charge_counter = charge_max
return
if(!target.ckey)
usr << "<span class='warning'>The target has no mind.</span>"
charge_counter = charge_max
return
if(target.stat)
usr << "<span class='warning'>The target must be conscious.</span>"
charge_counter = charge_max
return
if(is_shadow_or_thrall(target))
usr << "<span class='warning'>You can not enthrall allies.</span>"
charge_counter = charge_max
return
if(!ishuman(target))
usr << "<span class='warning'>You can only enthrall humans.</span>"
charge_counter = charge_max
return
if(enthralling)
usr << "<span class='danger'>You are already enthralling!</span>"
charge_counter = charge_max
return
enthralling = 1
usr << "<span class='danger'>This target is valid. You begin the enthralling.</span>"
target << "<span class='userdanger'>[usr] focuses in concentration. Your head begins to ache.</span>"
for(var/progress = 0, progress <= 3, progress++)
switch(progress)
if(1)
usr << "<span class='notice'>You begin allocating energy for the enthralling.</span>"
usr.visible_message("<span class='danger'>[usr]'s eyes begin to throb a piercing red.</span>")
if(2)
usr << "<span class='notice'>You begin the enthralling of [target].</span>"
usr.visible_message("<span class='danger'>[usr] leans over [target], their eyes glowing a deep crimson, and stares into their face.</span>")
target << "<span class='danger'>Your gaze is forcibly drawn into a blinding red light. You fall to the floor as conscious thought is wiped away.</span>"
target.Weaken(12)
sleep(20)
if(isloyal(target))
usr << "<span class='notice'>They are enslaved by Nanotrasen. You begin to shut down the nanobot implant - this will take some time.</span>"
usr.visible_message("<span class='danger'>[usr] halts for a moment, then begins passing its hand over [target]'s body.</span>")
target << "<span class='danger'>You feel your loyalties begin to weaken!</span>"
sleep(150) //15 seconds - not spawn() so the enthralling takes longer
usr << "<span class='notice'>The nanobots composing the loyalty implant have been rendered inert. Now to continue.</span>"
usr.visible_message("<span class='danger'>[usr] halts thier hand and resumes staring into [target]'s face.</span>")
for(var/obj/item/weapon/implant/loyalty/L in target)
if(L && L.implanted)
qdel(L)
target << "<span class='danger'>Your unwavering loyalty to Nanotrasen falters, dims, dies.</span>"
if(3)
usr << "<span class='notice'>You begin rearranging [target]'s memories.</span>"
usr.visible_message("<span class='danger'>[usr]'s eyes flare brightly, and a horrible grin begins to spread across [target]'s face...</span>")
target << "<span class='danger'>Your head cries out. The veil of reality begins to crumple and something evil bleeds through.</span>" //Ow the edge
if(!do_mob(usr, target, 100)) //around 30 seconds total for enthralling, 45 for someone with a loyalty implant
usr << "<span class='danger'>The enthralling has been interrupted - your target's mind returns to its previous state.</span>"
target << "<span class='warning'>Your thoughts become coherent once more. Already you can barely remember what's happened to you.</span>"
enthralling = 0
return
enthralling = 0
usr << "<span class='notice'>You have enthralled <b>[target]</b>!</span>"
target << "<span class='deadsay'><b>You see the Truth. Reality has been torn away and you realize what a fool you've been.</b></span>"
target << "<span class='deadsay'><b>The shadowlings are your masters.</b> Serve them above all else and ensure they complete their goals.</span>"
target << "<span class='deadsay'>You may not harm other thralls or the shadowlings. However, you do not need to obey other thralls.</span>"
target << "<span class='deadsay'>You can communicate with the other enlightened ones by using the Hivemind Commune ability.</span>"
target.adjustOxyLoss(-200) //In case the shadowling was choking them out
ticker.mode.add_thrall(target.mind)
target.mind.special_role = "Thrall"
/obj/effect/proc_holder/spell/targeted/shadowling_hivemind
name = "Hivemind Commune"
desc = "Allows you to silently communicate with all other shadowlings and thralls."
panel = "Shadowling Abilities"
charge_max = 25
clothes_req = 0
range = -1
include_user = 1
/obj/effect/proc_holder/spell/targeted/shadowling_hivemind/cast(list/targets)
for(var/mob/living/user in targets)
var/text = stripped_input(user, "What do you want to say to fellow thralls and shadowlings?.", "Hive Chat", "")
if(!text)
return
for(var/mob/M in mob_list)
if(is_shadow_or_thrall(M) || (M in dead_mob_list))
M << "<span class='shadowling'><b>\[Hive Chat\]</b><i> [usr.real_name]</i>: [text]</span>"
/obj/effect/proc_holder/spell/targeted/shadowling_regenarmor
name = "Regenerate Chitin"
desc = "Re-forms protective chitin that may be lost during cloning or similar processes."
panel = "Shadowling Abilities"
charge_max = 600
clothes_req = 0
range = -1
include_user = 1
/obj/effect/proc_holder/spell/targeted/shadowling_regenarmor/cast(list/targets)
for(var/mob/living/user in targets)
user.visible_message("<span class='warning'>[user]'s skin suddenly bubbles and begins to shift around their body!</span>", \
"<span class='shadowling'>You regenerate your protective armor and cleanse your form of defects.</span>")
user.equip_to_slot_or_del(new /obj/item/clothing/under/shadowling(usr), slot_w_uniform)
user.equip_to_slot_or_del(new /obj/item/clothing/shoes/shadowling(usr), slot_shoes)
user.equip_to_slot_or_del(new /obj/item/clothing/suit/space/shadowling(usr), slot_wear_suit)
user.equip_to_slot_or_del(new /obj/item/clothing/head/shadowling(usr), slot_head)
user.equip_to_slot_or_del(new /obj/item/clothing/gloves/shadowling(usr), slot_gloves)
user.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/shadowling(usr), slot_wear_mask)
user.equip_to_slot_or_del(new /obj/item/clothing/glasses/night/shadowling(usr), slot_glasses)
hardset_dna(user, null, null, null, null, /datum/species/shadow/ling) //can't be a shadowling without being a shadowling
/obj/effect/proc_holder/spell/targeted/collective_mind
name = "Collective Hivemind"
desc = "Gathers the power of all of your thralls and compares it to what is needed for ascendance. Also gains you new abilities."
panel = "Shadowling Abilities"
charge_max = 300 //30 second cooldown to prevent spam
clothes_req = 0
range = -1
include_user = 1
var/blind_smoke_acquired
var/screech_acquired
var/drain_thrall_acquired
var/thrall_swap_acquired
/obj/effect/proc_holder/spell/targeted/collective_mind/cast(list/targets)
for(var/mob/living/user in targets)
var/thralls = 0
var/victory_threshold = 15
var/mob/M
user << "<span class='shadowling'><b>You focus your telepathic energies abound, harnessing and drawing together the strength of your thralls.</b></span>"
for(M in living_mob_list)
if(is_thrall(M))
thralls++
M << "<span class='deadsay'>You feel hooks sink into your mind and pull.</span>"
if(!do_after(user, 30))
user << "<span class='warning'>Your concentration has been broken. The mental hooks you have sent out now retract into your mind.</span>"
return
if(thralls >= 3 && !blind_smoke_acquired)
blind_smoke_acquired = 1
user << "<span class='shadowling'><i>The power of your thralls has granted you the <b>Blinding Smoke</b> ability. It will create a choking cloud that will blind any non-thralls who enter. \
</i></span>"
user.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/blindness_smoke
if(thralls >= 5 && !drain_thrall_acquired)
drain_thrall_acquired = 1
user << "<span class='shadowling'><i>The power of your thralls has granted you the <b>Drain Thrall</b> ability. You can now drain nearby thralls to heal yourself.</i></span>"
user.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/drain_thralls
if(thralls >= 7 && !screech_acquired)
screech_acquired = 1
user << "<span class='shadowling'><i>The power of your thralls has granted you the <b>Sonic Screech</b> ability. This ability will shatter nearby windows and deafen enemies.</span>"
user.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/unearthly_screech
if(thralls >= 9 && !thrall_swap_acquired)
thrall_swap_acquired = 1
user << "<span class='shadowling'><i>The power of your thralls has granted you the <b>Spatial Relocation</b> ability. This will, allow you to instantly swap places with one of your thralls in \
addition to shattering nearby lights.</i></span>"
user.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/spatial_relocation
if(thralls < victory_threshold)
user << "<span class='shadowling'>You do not have the power to ascend. You require [victory_threshold] thralls, but only [thralls] living thralls are present.</span>"
else if(thralls >= victory_threshold)
usr << "<span class='shadowling'><b>You are now powerful enough to ascend. Use the Ascendance ability when you are ready. <i>This will kill all of your thralls.</i></span>"
usr << "<span class='shadowling'><b>You may find Ascendance in the Shadowling Evolution tab.</b></span>"
for(M in living_mob_list)
if(is_shadow(M))
M.mind.spell_list -= /obj/effect/proc_holder/spell/targeted/collective_mind
M.mind.current.verbs -= /mob/living/carbon/human/proc/shadowling_hatch //In case a shadowling hasn't hatched
M.mind.current.verbs += /mob/living/carbon/human/proc/shadowling_ascendance
if(M == usr)
return
M << "<span class='shadowling'><b>[user.real_name] has coalesced the strength of the thralls. You can draw upon it at any time to ascend.</span>" //Tells all the other shadowlings
/obj/effect/proc_holder/spell/targeted/blindness_smoke
name = "Blindness Smoke"
desc = "Spews a cloud of smoke which will blind enemies."
panel = "Shadowling Abilities"
charge_max = 600
clothes_req = 0
range = -1
include_user = 1
/obj/effect/proc_holder/spell/targeted/blindness_smoke/cast(list/targets) //Extremely hacky
for(var/mob/living/user in targets)
user.visible_message("<span class='warning'>[user] suddenly bends over and coughs out a cloud of black smoke, which begins to spread rapidly!</span>")
user << "<span class='deadsay'>You regurgitate a vast cloud of blinding smoke.</span>"
playsound(user, 'sound/effects/bamf.ogg', 50, 1)
var/obj/item/weapon/reagent_containers/glass/beaker/large/B = new /obj/item/weapon/reagent_containers/glass/beaker/large(user.loc)
B.reagents.clear_reagents() //Just in case!
B.icon_state = null //Invisible
B.reagents.add_reagent("blindness_smoke", 10)
var/datum/effect/effect/system/chem_smoke_spread/S = new /datum/effect/effect/system/chem_smoke_spread
S.attach(B)
if(S)
S.set_up(B.reagents, 10, 0, B.loc)
S.start()
sleep(10)
S.start()
qdel(B)
datum/reagent/shadowling_blindness_smoke //Blinds non-shadowlings, heals shadowlings/thralls
name = "!(%@ ERROR )!@$"
id = "blindness_smoke"
description = "<::ERROR::> CANNOT ANALYZE REAGENT <::ERROR::>"
color = "#000000" //Complete black (RGB: 0, 0, 0)
metabolization_rate = 100 //lel
datum/reagent/shadowling_blindness_smoke/on_mob_life(var/mob/living/M as mob)
if(!M) M = holder.my_atom
if(!is_shadow_or_thrall(M))
M << "<span class='warning'><b>You breathe in the black smoke, and your eyes burn horribly!</b></span>"
M.eye_blind = 5
if(prob(25))
M.visible_message("<b>[M]</b> screams and claws at their eyes!")
M.Stun(2)
else
M << "<span class='notice'><b>You breathe in the black smoke, and you feel revitalized!</b></span>"
M.heal_organ_damage(2,2)
M.adjustOxyLoss(-2)
M.adjustToxLoss(-2)
..()
return
/obj/effect/proc_holder/spell/aoe_turf/unearthly_screech
name = "Sonic Screech"
desc = "Deafens, stuns, and confuses nearby people. Also shatters windows."
panel = "Shadowling Abilities"
range = 7
charge_max = 300
clothes_req = 0
/obj/effect/proc_holder/spell/aoe_turf/unearthly_screech/cast(list/targets)
usr.audible_message("<span class='warning'><b>[usr] lets out a horrible scream!</b></span>")
playsound(usr.loc, 'sound/effects/screech.ogg', 100, 1)
for(var/turf/T in targets)
for(var/mob/target in T.contents)
if(is_shadow_or_thrall(target))
if(target == usr) //No message for the user, of course
continue
else
continue
if(iscarbon(target))
var/mob/living/carbon/M = target
M << "<span class='danger'><b>A spike of pain drives into your head and scrambles your thoughts!</b></span>"
M.confused += 10
M.setEarDamage(M.ear_damage + 3)
else if(issilicon(target))
var/mob/living/silicon/S = target
S << "<span class='warning'><b>ERROR $!(@ ERROR )#^! SENSOR INTERFERENCE DETECTED</b></span>"
S << 'sound/misc/interference.ogg'
playsound(S, 'sound/machines/warning-buzzer.ogg', 50, 1)
var/datum/effect/effect/system/spark_spread/sp = new /datum/effect/effect/system/spark_spread
sp.set_up(5, 1, S)
sp.start()
S.Weaken(6)
for(var/obj/structure/window/W in T.contents)
W.hit(rand(50,100))
/obj/effect/proc_holder/spell/aoe_turf/drain_thralls
name = "Drain Thralls"
desc = "Damages nearby thralls, draining their life and healing yourself."
panel = "Shadowling Abilities"
range = 3
charge_max = 100
clothes_req = 0
var/thralls_drained = 0
var/list/nearby_thralls = list()
/obj/effect/proc_holder/spell/aoe_turf/drain_thralls/cast(list/targets)
thralls_drained = 0
nearby_thralls = list()
for(var/turf/T in targets)
for(var/mob/living/carbon/M in T.contents)
if(is_thrall(M))
thralls_drained++
nearby_thralls.Add(M)
M << "<span class='warning'>You feel a curious draining sensation and a wave of exhaustion washes over you.</span>"
for(var/mob/living/carbon/M in nearby_thralls)
nearby_thralls.Remove(M) //To prevent someone dying like a zillion times
M.take_organ_damage(25/thralls_drained,25/thralls_drained) //For every nearby thrall, the damage to each is reduced - 1 thrall = 50 for him, 2 thralls = 25 for each, etc.
usr << "<span class='deadsay'>You draw the life from [M] to heal your wounds.</span>"
if(thralls_drained)
var/mob/living/carbon/U = usr
U.heal_organ_damage(25, 25)
else
charge_counter = charge_max
usr << "<span class='warning'>There were no nearby thralls for you to drain.</span>"
/obj/effect/proc_holder/spell/targeted/spatial_relocation
name = "Spatial Relocation"
desc = "Swaps places with a thrall and breaks nearby lights."
panel = "Shadowling Abilities"
range = -1
charge_max = 3000
clothes_req = 0
include_user = 1
var/list/thralls_in_world = list()
/obj/effect/proc_holder/spell/targeted/spatial_relocation/cast(list/targets, distanceoverride)
for(var/mob/living/carbon/human/M in world)
if(is_thrall(M))
thralls_in_world += M
if(!thralls_in_world)
charge_counter = charge_max
return
var/mob/living/carbon/thrall_to_swap = input("Who do you wish to swap places with?", "Available Thralls") as null|anything in (thralls_in_world)
var/turf/shadowturf = get_turf(usr)
var/turf/thrallturf = get_turf(thrall_to_swap)
thrall_to_swap.visible_message("<span class='danger'>[thrall_to_swap] suddenly vanishes in a puff of black smoke!</span>")
thrall_to_swap << "<span class='warning'><b>You feel a brief sense of nausea before finding yourself in an entirely new place!</b></span>"
usr.visible_message("<span class='danger'>[usr] suddenly goes transparent and vanishes!</span>")
usr << "<span class='deadsay'>You experience vertigo as you swap your location with [thrall_to_swap]'s.</span>"
thrall_to_swap.loc = shadowturf
usr.loc = thrallturf
thrall_to_swap.Weaken(4)
usr.Weaken(4)
usr.regenerate_icons()
thrall_to_swap.regenerate_icons()
// ASCENDANT ABILITIES BEYOND THIS POINT //
/obj/effect/proc_holder/spell/targeted/annihilate
name = "Annihilate"
desc = "Gibs a human after a short time."
panel = "Ascendant"
range = 7
charge_max = 300
clothes_req = 0
/obj/effect/proc_holder/spell/targeted/annihilate/cast(list/targets)
var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
if(SHA.phasing)
usr << "<span class='warning'>You are not in the same plane of existence. Unphase first.</span>"
charge_counter = charge_max
return
for(var/mob/living/carbon/human/boom in targets)
if(is_shadow_or_thrall(boom))
usr << "<span class='warning'>Making an ally explode seems unwise.<span>"
charge_counter = charge_max
return
usr.visible_message("<span class='danger'>[usr]'s eyes flare as they gesture at [boom]!</span>", \
"<span class='shadowling'>You direct a lance of telekinetic energy at [boom].</span>")
boom << "<span class='userdanger'><font size=3>You feel an immense pressure building all across your body!</span></font>"
boom.Stun(10)
boom.audible_message("<b>[boom]</b> screams!")
sleep(20)
playsound(boom, 'sound/effects/splat.ogg', 100, 1)
boom.visible_message("<span class='userdanger'>[boom] explodes!</span>")
boom.gib()
/obj/effect/proc_holder/spell/targeted/hypnosis
name = "Hypnosis"
desc = "Instantly enthralls a human."
panel = "Ascendant"
range = 7
charge_max = 450
clothes_req = 0
/obj/effect/proc_holder/spell/targeted/hypnosis/cast(list/targets)
var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
if(SHA.phasing)
charge_counter = charge_max
usr << "<span class='warning'>You are not in the same plane of existence. Unphase first.</span>"
return
for(var/mob/living/carbon/human/target in targets)
if(is_shadow_or_thrall(target))
usr << "<span class='warning'>You cannot enthrall an ally.<span>"
charge_counter = charge_max
return
if(!target.ckey)
usr << "<span class='warning'>The target has no mind.</span>"
charge_counter = charge_max
return
if(target.stat)
usr << "<span class='warning'>The target must be conscious.</span>"
charge_counter = charge_max
return
if(!ishuman(target))
usr << "<span class='warning'>You can only enthrall humans.</span>"
charge_counter = charge_max
return
usr << "<span class='shadowling'>You instantly rearrange <b>[target]</b>'s memories, hyptonitizing them into a thrall.</span>"
target << "<span class='userdanger'><font size=3>An agonizing spike of pain drives into your mind, and--</font></span>"
target << "<span class='deadsay'><b>And you see the Truth. Reality has been torn away and you realize what a fool you've been.</b></span>"
target << "<span class='deadsay'><b>The shadowlings are your masters.</b> Serve them above all else and ensure they complete their goals.</span>"
target << "<span class='deadsay'>You may not harm other thralls or the shadowlings. However, you do not need to obey other thralls.</span>"
target << "<span class='deadsay'>You can communicate with the other enlightened ones by using the Hivemind Commune ability.</span>"
ticker.mode.add_thrall(target.mind)
target.mind.special_role = "Thrall"
var/datum/mind/thrall_mind = target.mind
thrall_mind.spell_list += new /obj/effect/proc_holder/spell/targeted/shadowling_hivemind
/obj/effect/proc_holder/spell/targeted/shadowling_phase_shift
name = "Phase Shift"
desc = "Phases you into the space between worlds at will, allowing you to move through walls and become invisible."
panel = "Ascendant"
range = -1
include_user = 1
charge_max = 15
clothes_req = 0
/obj/effect/proc_holder/spell/targeted/shadowling_phase_shift/cast(list/targets)
var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
for(SHA in targets)
SHA.phasing = !SHA.phasing
if(SHA.phasing)
SHA.visible_message("<span class='danger'>[SHA] suddenly vanishes!</span>", \
"<span class='shadowling'>You begin phasing through planes of existence. Use the ability again to return.</span>")
SHA.incorporeal_move = 1
SHA.alpha = 0
else
SHA.visible_message("<span class='danger'>[SHA] suddenly appears from nowhere!</span>", \
"<span class='shadowling'>You return from the space between worlds.</span>")
SHA.incorporeal_move = 0
SHA.alpha = 255
/obj/effect/proc_holder/spell/aoe_turf/glacial_blast
name = "Glacial Blast"
desc = "Extremely empowered version of Flash Freeze."
panel = "Ascendant"
range = 5
charge_max = 600
clothes_req = 0
/obj/effect/proc_holder/spell/aoe_turf/glacial_blast/cast(list/targets)
var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
if(SHA.phasing)
usr << "<span class='warning'>You are not in the same plane of existence. Unphase first.</span>"
return
usr << "<span class='deadsay'>You freeze the nearby air.</span>"
playsound(usr.loc, 'sound/effects/ghost2.ogg', 100, 1)
for(var/turf/T in targets)
for(var/mob/living/carbon/human/target in T.contents)
if(is_shadow_or_thrall(target))
if(target == usr) //No message for the user, of course
continue
else
target << "<span class='danger'>You feel a blast of paralyzingly cold air wrap around you and flow past, but you are unaffected!</span>"
continue
target << "<span class='userdanger'>You are hit by a blast of cold unlike anything you have ever felt. Your limbs instantly lock in place and you feel ice burns across your body!</span>"
target.Weaken(15)
if(target.bodytemperature)
target.bodytemperature -= INFINITY //:^)
target.take_organ_damage(0,80)
/obj/effect/proc_holder/spell/targeted/vortex
name = "Vortex"
desc = "Tears open a hole in reality. Anyone, INCLUDING YOU, walking through it will be trapped there for eternity."
panel = "Ascendant"
range = -1
include_user = 1
charge_max = 1200
clothes_req = 0
/obj/effect/proc_holder/spell/targeted/vortex/cast(list/targets)
var/mob/living/simple_animal/ascendant_shadowling/SHA = usr
if(SHA.phasing)
usr << "<span class='warning'>You are not in the same plane of existence. Unphase first.</span>"
return
for(SHA in targets)
SHA.visible_message("<span class='userdanger'>[SHA] raises their arms upward as the markings on their body flare a blinding red!</span>", \
"<span class='shadowling'>You tear open a rift to the black space between worlds. <b><font size=3>It would be wise to avoid it.</font></b></span>")
new /obj/structure/shadow_vortex(SHA.loc)
/obj/effect/proc_holder/spell/targeted/shadowling_hivemind_ascendant
name = "Ascendant Commune"
desc = "Allows you to silently communicate with all other shadowlings and thralls."
panel = "Ascendant"
charge_max = 20
clothes_req = 0
range = -1
include_user = 1
/obj/effect/proc_holder/spell/targeted/shadowling_hivemind_ascendant/cast(list/targets)
for(var/mob/living/user in targets)
var/text = stripped_input(user, "What do you want to say to fellow thralls and shadowlings?.", "Hive Chat", "")
if(!text)
return
text = "<font size=3>[text]</font>"
for(var/mob/M in mob_list)
if(is_shadow_or_thrall(M) || (M in dead_mob_list))
M << "<span class='shadowling'><b>\[Hive Chat\]<i> [usr.real_name] (ASCENDANT)</i>: [text]</b></span>" //Bigger text for ascendants.

Some files were not shown because too many files have changed in this diff Show More