mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-31 00:58:26 +01:00
Merge branch 'master' of https://github.com/tgstation/-tg-station into ClownNamePreferences
Conflicts: code/modules/mob/transform_procs.dm
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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++
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>")
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
@@ -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")
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 ..()
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>"
|
||||
|
||||
@@ -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>"
|
||||
..()
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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>"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,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)))
|
||||
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>"
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
..()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
@@ -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])
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user