Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into upstream-merge-27219

This commit is contained in:
LetterJay
2017-05-18 02:27:50 -05:00
256 changed files with 20577 additions and 14654 deletions
+4
View File
@@ -13,6 +13,10 @@
#define MC_AVERAGE_FAST(average, current) (0.7 * (average) + 0.3 * (current))
#define MC_AVERAGE(average, current) (0.8 * (average) + 0.2 * (current))
#define MC_AVERAGE_SLOW(average, current) (0.9 * (average) + 0.1 * (current))
#define MC_AVG_FAST_UP_SLOW_DOWN(average, current) (average > current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current))
#define MC_AVG_SLOW_UP_FAST_DOWN(average, current) (average < current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current))
#define NEW_SS_GLOBAL(varname) if(varname != src){if(istype(varname)){Recover();qdel(varname);}varname = src;}
#define START_PROCESSING(Processor, Datum) if (!Datum.isprocessing) {Datum.isprocessing = 1;Processor.processing += Datum}
+4 -3
View File
@@ -1,3 +1,4 @@
#define ANTAG_DATUM_CULT /datum/antagonist/cult
#define ANTAG_DATUM_CLOCKCULT /datum/antagonist/clockcult
#define ANTAG_DATUM_CLOCKCULT_SILENT /datum/antagonist/clockcult/silent
#define ANTAG_DATUM_CULT /datum/antagonist/cult
#define ANTAG_DATUM_CULT_MASTER /datum/antagonist/cult/master
#define ANTAG_DATUM_CLOCKCULT /datum/antagonist/clockcult
#define ANTAG_DATUM_CLOCKCULT_SILENT /datum/antagonist/clockcult/silent
+1 -1
View File
@@ -32,7 +32,7 @@
#define BOTANIST (1<<2)
#define COOK (1<<3)
#define JANITOR (1<<4)
#define CURATOR (1<<5)
#define CURATOR (1<<5)
#define QUARTERMASTER (1<<6)
#define CARGOTECH (1<<7)
#define MINER (1<<8)
+3
View File
@@ -2,3 +2,6 @@
#define TONGUELESS_SPEECH 2
#define LANGUAGE_HIDE_ICON_IF_UNDERSTOOD 4
#define LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD 8
#define LANGUAGE_KNOWN "language_known"
#define LANGUAGE_SHADOWED "language_shadowed"
-10
View File
@@ -1,10 +0,0 @@
diff a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm (rejected hunks)
@@ -33,4 +33,8 @@
#define STATUS_EFFECT_SIGILMARK /datum/status_effect/sigil_mark
#define STATUS_EFFECT_BELLIGERENT /datum/status_effect/belligerent //forces the affected to walk, doing damage if they try to run
+#define STATUS_EFFECT_MANIAMOTOR /datum/status_effect/maniamotor //disrupts, damages, and confuses the affected as long as they're in range of the motor
+#define MAX_MANIA_SEVERITY 100 //how high the mania severity can go
+#define MANIA_DAMAGE_TO_CONVERT 90 //how much damage is required before it'll convert affected targets
+
#define STATUS_EFFECT_HISWRATH /datum/status_effect/his_wrath //His Wrath.
+1
View File
@@ -46,6 +46,7 @@
#define INIT_ORDER_TICKER 13
#define INIT_ORDER_MAPPING 12
#define INIT_ORDER_ATOMS 11
#define INIT_ORDER_LANGUAGE 10
#define INIT_ORDER_MACHINES 9
#define INIT_ORDER_SHUTTLE 3
#define INIT_ORDER_TIMER 1
+1 -1
View File
@@ -457,7 +457,7 @@
#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= L.len ? L[I] : null) : L[I]) : null)
#define LAZYLEN(L) length(L)
#define LAZYCLEARLIST(L) if(L) L.Cut()
#define SANITIZE_LIST(L) ( islist(L) ? L : list() )
#define SANITIZE_LIST(L) ( islist(L) ? L : list() )
/* Definining a counter as a series of key -> numeric value entries
+600 -535
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -24,7 +24,6 @@
//doesn't have an object argument because this is "Stacking" with the animate call above
//3 billion% intentional
//Dumps the matrix data in format a-f
/matrix/proc/tolist()
. = list()
+9
View File
@@ -3,3 +3,12 @@ GLOBAL_VAR_INIT(secret_force_mode, "secret") // if this is anything but "secret"
GLOBAL_VAR_INIT(wavesecret, 0) // meteor mode, delays wave progression, terrible name
GLOBAL_DATUM(start_state, /datum/station_state) // Used in round-end report
// Cult, needs to be global so admin cultists are functional
GLOBAL_VAR_INIT(blood_target, null) // Cult Master's target or Construct's Master
GLOBAL_DATUM(blood_target_image, /image)
GLOBAL_DATUM(sac_mind, /datum/mind)
GLOBAL_VAR_INIT(sac_image, null)
GLOBAL_VAR_INIT(cult_mastered, FALSE)
GLOBAL_VAR_INIT(reckoning_complete, FALSE)
GLOBAL_VAR_INIT(sac_complete, FALSE)
+4 -2
View File
@@ -19,5 +19,7 @@ GLOBAL_LIST_EMPTY(silicon_mobs) //all silicon mobs
GLOBAL_LIST_EMPTY(ai_list)
GLOBAL_LIST_EMPTY(pai_list)
GLOBAL_LIST_EMPTY(available_ai_shells)
GLOBAL_LIST_EMPTY(language_datums)
GLOBAL_LIST_EMPTY(simple_animals)
GLOBAL_LIST_EMPTY(simple_animals)
GLOBAL_LIST_EMPTY(language_datum_instances)
GLOBAL_LIST_EMPTY(all_languages)
+33 -33
View File
@@ -1,34 +1,34 @@
GLOBAL_VAR(log_directory)
GLOBAL_PROTECT(log_directory)
GLOBAL_VAR(world_game_log)
GLOBAL_PROTECT(world_game_log)
GLOBAL_VAR(world_runtime_log)
GLOBAL_PROTECT(world_runtime_log)
GLOBAL_VAR(world_attack_log)
GLOBAL_PROTECT(world_attack_log)
GLOBAL_VAR(world_href_log)
GLOBAL_PROTECT(world_href_log)
GLOBAL_VAR(round_id)
GLOBAL_PROTECT(round_id)
GLOBAL_VAR(config_error_log)
GLOBAL_PROTECT(config_error_log)
GLOBAL_LIST_EMPTY(bombers)
GLOBAL_PROTECT(bombers)
GLOBAL_LIST_EMPTY(admin_log)
GLOBAL_PROTECT(admin_log)
GLOBAL_LIST_EMPTY(lastsignalers) //keeps last 100 signals here in format: "[src] used \ref[src] @ location [src.loc]: [freq]/[code]"
GLOBAL_PROTECT(lastsignalers)
GLOBAL_LIST_EMPTY(lawchanges) //Stores who uploaded laws to which silicon-based lifeform, and what the law was
GLOBAL_PROTECT(lawchanges)
GLOBAL_LIST_EMPTY(combatlog)
GLOBAL_PROTECT(combatlog)
GLOBAL_LIST_EMPTY(IClog)
GLOBAL_PROTECT(IClog)
GLOBAL_LIST_EMPTY(OOClog)
GLOBAL_PROTECT(OOClog)
GLOBAL_LIST_EMPTY(adminlog)
GLOBAL_PROTECT(adminlog)
GLOBAL_VAR(log_directory)
GLOBAL_PROTECT(log_directory)
GLOBAL_VAR(world_game_log)
GLOBAL_PROTECT(world_game_log)
GLOBAL_VAR(world_runtime_log)
GLOBAL_PROTECT(world_runtime_log)
GLOBAL_VAR(world_attack_log)
GLOBAL_PROTECT(world_attack_log)
GLOBAL_VAR(world_href_log)
GLOBAL_PROTECT(world_href_log)
GLOBAL_VAR(round_id)
GLOBAL_PROTECT(round_id)
GLOBAL_VAR(config_error_log)
GLOBAL_PROTECT(config_error_log)
GLOBAL_LIST_EMPTY(bombers)
GLOBAL_PROTECT(bombers)
GLOBAL_LIST_EMPTY(admin_log)
GLOBAL_PROTECT(admin_log)
GLOBAL_LIST_EMPTY(lastsignalers) //keeps last 100 signals here in format: "[src] used \ref[src] @ location [src.loc]: [freq]/[code]"
GLOBAL_PROTECT(lastsignalers)
GLOBAL_LIST_EMPTY(lawchanges) //Stores who uploaded laws to which silicon-based lifeform, and what the law was
GLOBAL_PROTECT(lawchanges)
GLOBAL_LIST_EMPTY(combatlog)
GLOBAL_PROTECT(combatlog)
GLOBAL_LIST_EMPTY(IClog)
GLOBAL_PROTECT(IClog)
GLOBAL_LIST_EMPTY(OOClog)
GLOBAL_PROTECT(OOClog)
GLOBAL_LIST_EMPTY(adminlog)
GLOBAL_PROTECT(adminlog)
GLOBAL_LIST_EMPTY(active_turfs_startlist)
+80 -80
View File
@@ -111,108 +111,108 @@
W.attack_self(src)
update_inv_hands()
return
//These are always reachable.
//User itself, current loc, and user inventory
if(DirectAccess(A))
//These are always reachable.
//User itself, current loc, and user inventory
if(DirectAccess(A))
if(W)
melee_item_attack_chain(src,W,A,params)
melee_item_attack_chain(src,W,A,params)
else
if(ismob(A))
changeNext_move(CLICK_CD_MELEE)
UnarmedAttack(A)
return
//Can't reach anything else in lockers or other weirdness
if(!loc.AllowClick())
//Can't reach anything else in lockers or other weirdness
if(!loc.AllowClick())
return
//Standard reach turf to turf or reaching inside storage
if(CanReach(A,W))
if(W)
melee_item_attack_chain(src,W,A,params)
else
if(ismob(A))
changeNext_move(CLICK_CD_MELEE)
UnarmedAttack(A,1)
else
if(W)
W.afterattack(A,src,0,params)
else
RangedAttack(A,params)
/atom/movable/proc/CanReach(atom/target,obj/item/tool,view_only = FALSE)
if(isturf(target) || isturf(target.loc) || DirectAccess(target)) //Directly accessible atoms
if(Adjacent(target) || (tool && CheckToolReach(src, target, tool.reach))) //Adjacent or reaching attacks
return TRUE
else
//Things inside storage insde another storage
//Eg Contents of a box in a backpack
var/atom/outer_storage = get_atom_on_turf(target)
if(outer_storage == target) //whatever that is we don't want infinite loop.
return FALSE
if(outer_storage && CanReach(outer_storage,tool) && outer_storage.CanReachStorage(target,src,view_only ? STORAGE_VIEW_DEPTH : INVENTORY_DEPTH))
return TRUE
return FALSE
//Can [target] in this container be reached by [user], can't be more than [depth] levels deep
/atom/proc/CanReachStorage(atom/target,user,depth)
return FALSE
/obj/item/weapon/storage/CanReachStorage(atom/target,user,depth)
while(target && depth > 0)
target = target.loc
depth--
if(target == src)
return TRUE
return FALSE
/atom/movable/proc/DirectAccess(atom/target)
if(target == src)
return TRUE
if(target == loc)
return TRUE
/mob/DirectAccess(atom/target)
if(..())
return TRUE
if(target in contents) //This could probably use moving down and restricting to inventory only
return TRUE
return FALSE
/mob/living/DirectAccess(atom/target)
if(..()) //Lightweight checks first
return TRUE
if(target in GetAllContents())
return TRUE
/atom/proc/AllowClick()
return FALSE
/turf/AllowClick()
return TRUE
//Standard reach turf to turf or reaching inside storage
if(CanReach(A,W))
if(W)
melee_item_attack_chain(src,W,A,params)
else
if(ismob(A))
changeNext_move(CLICK_CD_MELEE)
UnarmedAttack(A,1)
else
if(W)
W.afterattack(A,src,0,params)
else
RangedAttack(A,params)
/proc/CheckToolReach(atom/movable/here, atom/movable/there, reach)
/atom/movable/proc/CanReach(atom/target,obj/item/tool,view_only = FALSE)
if(isturf(target) || isturf(target.loc) || DirectAccess(target)) //Directly accessible atoms
if(Adjacent(target) || (tool && CheckToolReach(src, target, tool.reach))) //Adjacent or reaching attacks
return TRUE
else
//Things inside storage insde another storage
//Eg Contents of a box in a backpack
var/atom/outer_storage = get_atom_on_turf(target)
if(outer_storage == target) //whatever that is we don't want infinite loop.
return FALSE
if(outer_storage && CanReach(outer_storage,tool) && outer_storage.CanReachStorage(target,src,view_only ? STORAGE_VIEW_DEPTH : INVENTORY_DEPTH))
return TRUE
return FALSE
//Can [target] in this container be reached by [user], can't be more than [depth] levels deep
/atom/proc/CanReachStorage(atom/target,user,depth)
return FALSE
/obj/item/weapon/storage/CanReachStorage(atom/target,user,depth)
while(target && depth > 0)
target = target.loc
depth--
if(target == src)
return TRUE
return FALSE
/atom/movable/proc/DirectAccess(atom/target)
if(target == src)
return TRUE
if(target == loc)
return TRUE
/mob/DirectAccess(atom/target)
if(..())
return TRUE
if(target in contents) //This could probably use moving down and restricting to inventory only
return TRUE
return FALSE
/mob/living/DirectAccess(atom/target)
if(..()) //Lightweight checks first
return TRUE
if(target in GetAllContents())
return TRUE
/atom/proc/AllowClick()
return FALSE
/turf/AllowClick()
return TRUE
/proc/CheckToolReach(atom/movable/here, atom/movable/there, reach)
if(!here || !there)
return
switch(reach)
if(0)
return FALSE
return FALSE
if(1)
return FALSE //here.Adjacent(there)
return FALSE //here.Adjacent(there)
if(2 to INFINITY)
var/obj/dummy = new(get_turf(here))
var/obj/dummy = new(get_turf(here))
dummy.pass_flags |= PASSTABLE
dummy.invisibility = INVISIBILITY_ABSTRACT
dummy.invisibility = INVISIBILITY_ABSTRACT
for(var/i in 1 to reach) //Limit it to that many tries
var/turf/T = get_step(dummy, get_dir(dummy, there))
if(dummy.CanReach(there))
if(dummy.CanReach(there))
qdel(dummy)
return TRUE
return TRUE
if(!dummy.Move(T)) //we're blocked!
qdel(dummy)
return
qdel(dummy)
qdel(dummy)
// Default behavior: ignore double clicks (the second click that makes the doubleclick call already calls for a normal click)
/mob/proc/DblClickOn(atom/A, params)
+162 -162
View File
@@ -1,162 +1,162 @@
/*
These defines specificy screen locations. For more information, see the byond documentation on the screen_loc var.
The short version:
Everything is encoded as strings because apparently that's how Byond rolls.
"1,1" is the bottom left square of the user's screen. This aligns perfectly with the turf grid.
"1:2,3:4" is the square (1,3) with pixel offsets (+2, +4); slightly right and slightly above the turf grid.
Pixel offsets are used so you don't perfectly hide the turf under them, that would be crappy.
In addition, the keywords NORTH, SOUTH, EAST, WEST and CENTER can be used to represent their respective
screen borders. NORTH-1, for example, is the row just below the upper edge. Useful if you want your
UI to scale with screen size.
The size of the user's screen is defined by client.view (indirectly by world.view), in our case "15x15".
Therefore, the top right corner (except during admin shenanigans) is at "15,15"
*/
//Lower left, persistent menu
#define ui_inventory "WEST:6,SOUTH:5"
//Middle left indicators
#define ui_lingchemdisplay "WEST,CENTER-1:15"
#define ui_lingstingdisplay "WEST:6,CENTER-3:11"
#define ui_crafting "12:-10,1:5"
#define ui_building "12:-10,1:21"
#define ui_language_menu "11:6,2:-11"
#define ui_devilsouldisplay "WEST:6,CENTER-1:15"
//Lower center, persistent menu
#define ui_sstore1 "CENTER-5:10,SOUTH:5"
#define ui_id "CENTER-4:12,SOUTH:5"
#define ui_belt "CENTER-3:14,SOUTH:5"
#define ui_back "CENTER-2:14,SOUTH:5"
/proc/ui_hand_position(i) //values based on old hand ui positions (CENTER:-/+16,SOUTH:5)
var/x_off = -(!(i % 2))
var/y_off = round((i-1) / 2)
return"CENTER+[x_off]:16,SOUTH+[y_off]:5"
/proc/ui_equip_position(mob/M)
var/y_off = round((M.held_items.len-1) / 2) //values based on old equip ui position (CENTER: +/-16,SOUTH+1:5)
return "CENTER:-16,SOUTH+[y_off+1]:5"
/proc/ui_swaphand_position(mob/M, which = 1) //values based on old swaphand ui positions (CENTER: +/-16,SOUTH+1:5)
var/x_off = which == 1 ? -1 : 0
var/y_off = round((M.held_items.len-1) / 2)
return "CENTER+[x_off]:16,SOUTH+[y_off+1]:5"
#define ui_storage1 "CENTER+1:18,SOUTH:5"
#define ui_storage2 "CENTER+2:20,SOUTH:5"
#define ui_borg_sensor "CENTER-3:16, SOUTH:5" //borgs
#define ui_borg_lamp "CENTER-4:16, SOUTH:5" //borgs
#define ui_borg_thrusters "CENTER-5:16, SOUTH:5" //borgs
#define ui_inv1 "CENTER-2:16,SOUTH:5" //borgs
#define ui_inv2 "CENTER-1 :16,SOUTH:5" //borgs
#define ui_inv3 "CENTER :16,SOUTH:5" //borgs
#define ui_borg_module "CENTER+1:16,SOUTH:5" //borgs
#define ui_borg_store "CENTER+2:16,SOUTH:5" //borgs
#define ui_borg_camera "CENTER+3:21,SOUTH:5" //borgs
#define ui_borg_album "CENTER+4:21,SOUTH:5" //borgs
#define ui_borg_language_menu "CENTER+4:21,SOUTH+1:5" //borgs
#define ui_monkey_head "CENTER-5:13,SOUTH:5" //monkey
#define ui_monkey_mask "CENTER-4:14,SOUTH:5" //monkey
#define ui_monkey_neck "CENTER-3:15,SOUTH:5" //monkey
#define ui_monkey_back "CENTER-2:16,SOUTH:5" //monkey
#define ui_alien_storage_l "CENTER-2:14,SOUTH:5"//alien
#define ui_alien_storage_r "CENTER+1:18,SOUTH:5"//alien
#define ui_alien_language_menu "EAST-3:26,SOUTH:5" //alien
#define ui_drone_drop "CENTER+1:18,SOUTH:5" //maintenance drones
#define ui_drone_pull "CENTER+2:2,SOUTH:5" //maintenance drones
#define ui_drone_storage "CENTER-2:14,SOUTH:5" //maintenance drones
#define ui_drone_head "CENTER-3:14,SOUTH:5" //maintenance drones
//Lower right, persistent menu
#define ui_drop_throw "EAST-1:28,SOUTH+1:7"
#define ui_pull_resist "EAST-2:26,SOUTH+1:7"
#define ui_movi "EAST-2:26,SOUTH:5"
#define ui_acti "EAST-3:24,SOUTH:5"
#define ui_zonesel "EAST-1:28,SOUTH:5"
#define ui_acti_alt "EAST-1:28,SOUTH:5" //alternative intent switcher for when the interface is hidden (F12)
#define ui_borg_pull "EAST-2:26,SOUTH+1:7"
#define ui_borg_radio "EAST-1:28,SOUTH+1:7"
#define ui_borg_intents "EAST-2:26,SOUTH:5"
//Upper-middle right (alerts)
#define ui_alert1 "EAST-1:28,CENTER+5:27"
#define ui_alert2 "EAST-1:28,CENTER+4:25"
#define ui_alert3 "EAST-1:28,CENTER+3:23"
#define ui_alert4 "EAST-1:28,CENTER+2:21"
#define ui_alert5 "EAST-1:28,CENTER+1:19"
//Middle right (status indicators)
#define ui_healthdoll "EAST-1:28,CENTER-2:13"
#define ui_health "EAST-1:28,CENTER-1:15"
#define ui_internal "EAST-1:28,CENTER:17"
//borgs
#define ui_borg_health "EAST-1:28,CENTER-1:15" //borgs have the health display where humans have the pressure damage indicator.
//aliens
#define ui_alien_health "EAST,CENTER-1:15" //aliens have the health display where humans have the pressure damage indicator.
#define ui_alienplasmadisplay "EAST,CENTER-2:15"
#define ui_alien_queen_finder "EAST,CENTER-3:15"
//constructs
#define ui_construct_pull "EAST,CENTER-2:15"
#define ui_construct_health "EAST,CENTER:15" //same as borgs and humans
// AI
#define ui_ai_core "SOUTH:6,WEST"
#define ui_ai_camera_list "SOUTH:6,WEST+1"
#define ui_ai_track_with_camera "SOUTH:6,WEST+2"
#define ui_ai_camera_light "SOUTH:6,WEST+3"
#define ui_ai_crew_monitor "SOUTH:6,WEST+4"
#define ui_ai_crew_manifest "SOUTH:6,WEST+5"
#define ui_ai_alerts "SOUTH:6,WEST+6"
#define ui_ai_announcement "SOUTH:6,WEST+7"
#define ui_ai_shuttle "SOUTH:6,WEST+8"
#define ui_ai_state_laws "SOUTH:6,WEST+9"
#define ui_ai_pda_send "SOUTH:6,WEST+10"
#define ui_ai_pda_log "SOUTH:6,WEST+11"
#define ui_ai_take_picture "SOUTH:6,WEST+12"
#define ui_ai_view_images "SOUTH:6,WEST+13"
#define ui_ai_sensor "SOUTH:6,WEST+14"
//Pop-up inventory
#define ui_shoes "WEST+1:8,SOUTH:5"
#define ui_iclothing "WEST:6,SOUTH+1:7"
#define ui_oclothing "WEST+1:8,SOUTH+1:7"
#define ui_gloves "WEST+2:10,SOUTH+1:7"
#define ui_glasses "WEST:6,SOUTH+3:11"
#define ui_mask "WEST+1:8,SOUTH+2:9"
#define ui_ears "WEST+2:10,SOUTH+2:9"
#define ui_neck "WEST:6,SOUTH+2:9"
#define ui_head "WEST+1:8,SOUTH+3:11"
//Ghosts
#define ui_ghost_jumptomob "SOUTH:6,CENTER-2:24"
#define ui_ghost_orbit "SOUTH:6,CENTER-1:24"
#define ui_ghost_reenter_corpse "SOUTH:6,CENTER:24"
#define ui_ghost_teleport "SOUTH:6,CENTER+1:24"
#define ui_ghost_pai "SOUTH: 6, CENTER+2:24"
//Hand of God, god
#define ui_deityhealth "EAST-1:28,CENTER-2:13"
#define ui_deitypower "EAST-1:28,CENTER-1:15"
#define ui_deityfollowers "EAST-1:28,CENTER:17"
/*
These defines specificy screen locations. For more information, see the byond documentation on the screen_loc var.
The short version:
Everything is encoded as strings because apparently that's how Byond rolls.
"1,1" is the bottom left square of the user's screen. This aligns perfectly with the turf grid.
"1:2,3:4" is the square (1,3) with pixel offsets (+2, +4); slightly right and slightly above the turf grid.
Pixel offsets are used so you don't perfectly hide the turf under them, that would be crappy.
In addition, the keywords NORTH, SOUTH, EAST, WEST and CENTER can be used to represent their respective
screen borders. NORTH-1, for example, is the row just below the upper edge. Useful if you want your
UI to scale with screen size.
The size of the user's screen is defined by client.view (indirectly by world.view), in our case "15x15".
Therefore, the top right corner (except during admin shenanigans) is at "15,15"
*/
//Lower left, persistent menu
#define ui_inventory "WEST:6,SOUTH:5"
//Middle left indicators
#define ui_lingchemdisplay "WEST,CENTER-1:15"
#define ui_lingstingdisplay "WEST:6,CENTER-3:11"
#define ui_crafting "12:-10,1:5"
#define ui_building "12:-10,1:21"
#define ui_language_menu "11:6,2:-11"
#define ui_devilsouldisplay "WEST:6,CENTER-1:15"
//Lower center, persistent menu
#define ui_sstore1 "CENTER-5:10,SOUTH:5"
#define ui_id "CENTER-4:12,SOUTH:5"
#define ui_belt "CENTER-3:14,SOUTH:5"
#define ui_back "CENTER-2:14,SOUTH:5"
/proc/ui_hand_position(i) //values based on old hand ui positions (CENTER:-/+16,SOUTH:5)
var/x_off = -(!(i % 2))
var/y_off = round((i-1) / 2)
return"CENTER+[x_off]:16,SOUTH+[y_off]:5"
/proc/ui_equip_position(mob/M)
var/y_off = round((M.held_items.len-1) / 2) //values based on old equip ui position (CENTER: +/-16,SOUTH+1:5)
return "CENTER:-16,SOUTH+[y_off+1]:5"
/proc/ui_swaphand_position(mob/M, which = 1) //values based on old swaphand ui positions (CENTER: +/-16,SOUTH+1:5)
var/x_off = which == 1 ? -1 : 0
var/y_off = round((M.held_items.len-1) / 2)
return "CENTER+[x_off]:16,SOUTH+[y_off+1]:5"
#define ui_storage1 "CENTER+1:18,SOUTH:5"
#define ui_storage2 "CENTER+2:20,SOUTH:5"
#define ui_borg_sensor "CENTER-3:16, SOUTH:5" //borgs
#define ui_borg_lamp "CENTER-4:16, SOUTH:5" //borgs
#define ui_borg_thrusters "CENTER-5:16, SOUTH:5" //borgs
#define ui_inv1 "CENTER-2:16,SOUTH:5" //borgs
#define ui_inv2 "CENTER-1 :16,SOUTH:5" //borgs
#define ui_inv3 "CENTER :16,SOUTH:5" //borgs
#define ui_borg_module "CENTER+1:16,SOUTH:5" //borgs
#define ui_borg_store "CENTER+2:16,SOUTH:5" //borgs
#define ui_borg_camera "CENTER+3:21,SOUTH:5" //borgs
#define ui_borg_album "CENTER+4:21,SOUTH:5" //borgs
#define ui_borg_language_menu "CENTER+4:21,SOUTH+1:5" //borgs
#define ui_monkey_head "CENTER-5:13,SOUTH:5" //monkey
#define ui_monkey_mask "CENTER-4:14,SOUTH:5" //monkey
#define ui_monkey_neck "CENTER-3:15,SOUTH:5" //monkey
#define ui_monkey_back "CENTER-2:16,SOUTH:5" //monkey
#define ui_alien_storage_l "CENTER-2:14,SOUTH:5"//alien
#define ui_alien_storage_r "CENTER+1:18,SOUTH:5"//alien
#define ui_alien_language_menu "EAST-3:26,SOUTH:5" //alien
#define ui_drone_drop "CENTER+1:18,SOUTH:5" //maintenance drones
#define ui_drone_pull "CENTER+2:2,SOUTH:5" //maintenance drones
#define ui_drone_storage "CENTER-2:14,SOUTH:5" //maintenance drones
#define ui_drone_head "CENTER-3:14,SOUTH:5" //maintenance drones
//Lower right, persistent menu
#define ui_drop_throw "EAST-1:28,SOUTH+1:7"
#define ui_pull_resist "EAST-2:26,SOUTH+1:7"
#define ui_movi "EAST-2:26,SOUTH:5"
#define ui_acti "EAST-3:24,SOUTH:5"
#define ui_zonesel "EAST-1:28,SOUTH:5"
#define ui_acti_alt "EAST-1:28,SOUTH:5" //alternative intent switcher for when the interface is hidden (F12)
#define ui_borg_pull "EAST-2:26,SOUTH+1:7"
#define ui_borg_radio "EAST-1:28,SOUTH+1:7"
#define ui_borg_intents "EAST-2:26,SOUTH:5"
//Upper-middle right (alerts)
#define ui_alert1 "EAST-1:28,CENTER+5:27"
#define ui_alert2 "EAST-1:28,CENTER+4:25"
#define ui_alert3 "EAST-1:28,CENTER+3:23"
#define ui_alert4 "EAST-1:28,CENTER+2:21"
#define ui_alert5 "EAST-1:28,CENTER+1:19"
//Middle right (status indicators)
#define ui_healthdoll "EAST-1:28,CENTER-2:13"
#define ui_health "EAST-1:28,CENTER-1:15"
#define ui_internal "EAST-1:28,CENTER:17"
//borgs
#define ui_borg_health "EAST-1:28,CENTER-1:15" //borgs have the health display where humans have the pressure damage indicator.
//aliens
#define ui_alien_health "EAST,CENTER-1:15" //aliens have the health display where humans have the pressure damage indicator.
#define ui_alienplasmadisplay "EAST,CENTER-2:15"
#define ui_alien_queen_finder "EAST,CENTER-3:15"
//constructs
#define ui_construct_pull "EAST,CENTER-2:15"
#define ui_construct_health "EAST,CENTER:15" //same as borgs and humans
// AI
#define ui_ai_core "SOUTH:6,WEST"
#define ui_ai_camera_list "SOUTH:6,WEST+1"
#define ui_ai_track_with_camera "SOUTH:6,WEST+2"
#define ui_ai_camera_light "SOUTH:6,WEST+3"
#define ui_ai_crew_monitor "SOUTH:6,WEST+4"
#define ui_ai_crew_manifest "SOUTH:6,WEST+5"
#define ui_ai_alerts "SOUTH:6,WEST+6"
#define ui_ai_announcement "SOUTH:6,WEST+7"
#define ui_ai_shuttle "SOUTH:6,WEST+8"
#define ui_ai_state_laws "SOUTH:6,WEST+9"
#define ui_ai_pda_send "SOUTH:6,WEST+10"
#define ui_ai_pda_log "SOUTH:6,WEST+11"
#define ui_ai_take_picture "SOUTH:6,WEST+12"
#define ui_ai_view_images "SOUTH:6,WEST+13"
#define ui_ai_sensor "SOUTH:6,WEST+14"
//Pop-up inventory
#define ui_shoes "WEST+1:8,SOUTH:5"
#define ui_iclothing "WEST:6,SOUTH+1:7"
#define ui_oclothing "WEST+1:8,SOUTH+1:7"
#define ui_gloves "WEST+2:10,SOUTH+1:7"
#define ui_glasses "WEST:6,SOUTH+3:11"
#define ui_mask "WEST+1:8,SOUTH+2:9"
#define ui_ears "WEST+2:10,SOUTH+2:9"
#define ui_neck "WEST:6,SOUTH+2:9"
#define ui_head "WEST+1:8,SOUTH+3:11"
//Ghosts
#define ui_ghost_jumptomob "SOUTH:6,CENTER-2:24"
#define ui_ghost_orbit "SOUTH:6,CENTER-1:24"
#define ui_ghost_reenter_corpse "SOUTH:6,CENTER:24"
#define ui_ghost_teleport "SOUTH:6,CENTER+1:24"
#define ui_ghost_pai "SOUTH: 6, CENTER+2:24"
//Hand of God, god
#define ui_deityhealth "EAST-1:28,CENTER-2:13"
#define ui_deitypower "EAST-1:28,CENTER-1:15"
#define ui_deityfollowers "EAST-1:28,CENTER:17"
+98
View File
@@ -42,6 +42,7 @@
thealert.override_alerts = override
if(override)
thealert.timeout = null
thealert.mob_viewer = src
if(new_master)
var/old_layer = new_master.layer
@@ -96,6 +97,7 @@
var/severity = 0
var/alerttooltipstyle = ""
var/override_alerts = FALSE //If it is overriding other alerts of the same type
var/mob/mob_viewer //the mob viewing this alert
/obj/screen/alert/MouseEntered(location,control,params)
@@ -256,6 +258,102 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
icon_state = "blobbernaut_nofactory"
alerttooltipstyle = "blob"
// BLOODCULT
/obj/screen/alert/bloodsense
name = "Blood Sense"
desc = "Allows you to sense blood that is manipulated by dark magicks."
icon_state = "cult_sense"
alerttooltipstyle = "cult"
var/static/image/narnar
var/angle = 0
var/mob/living/simple_animal/hostile/construct/Cviewer = null
/obj/screen/alert/bloodsense/Initialize()
. = ..()
if(!narnar)
narnar = new('icons/mob/screen_alert.dmi', "mini_nar")
START_PROCESSING(SSprocessing, src)
/obj/screen/alert/bloodsense/Destroy()
Cviewer = null
STOP_PROCESSING(SSprocessing, src)
return ..()
/obj/screen/alert/bloodsense/process()
var/atom/blood_target
if(GLOB.blood_target)
if(!get_turf(GLOB.blood_target))
GLOB.blood_target = null
else
blood_target = GLOB.blood_target
if(Cviewer)
if(Cviewer.seeking && Cviewer.master)
blood_target = Cviewer.master
if(!blood_target && !GLOB.sac_complete)
if(icon_state == "runed_sense0")
return
animate(src, transform = null, time = 1, loop = 0)
angle = 0
cut_overlays()
icon_state = "runed_sense0"
desc = "Nar-Sie demands that [GLOB.sac_mind] be sacrificed before the summoning ritual can begin."
add_overlay(GLOB.sac_image)
return
if(!blood_target && GLOB.sac_complete)
if(icon_state == "runed_sense1")
return
animate(src, transform = null, time = 1, loop = 0)
angle = 0
cut_overlays()
icon_state = "runed_sense1"
desc = "The sacrifice is complete, prepare to summon Nar-Sie!"
add_overlay(narnar)
return
if(!blood_target)
return
var/turf/P = get_turf(blood_target)
var/turf/Q = get_turf(mob_viewer)
var/area/A = get_area(P)
if(P.z != Q.z) //The target is on a different Z level, we cannot sense that far.
return
desc = "You are currently tracking [blood_target] in [A.name]."
var/target_angle = Get_Angle(Q, P)
var/target_dist = get_dist(P, Q)
cut_overlays()
switch(target_dist)
if(0 to 1)
icon_state = "runed_sense2"
if(2 to 8)
icon_state = "arrow8"
if(9 to 15)
icon_state = "arrow7"
if(16 to 22)
icon_state = "arrow6"
if(23 to 29)
icon_state = "arrow5"
if(30 to 36)
icon_state = "arrow4"
if(37 to 43)
icon_state = "arrow3"
if(44 to 50)
icon_state = "arrow2"
if(51 to 57)
icon_state = "arrow1"
if(58 to 64)
icon_state = "arrow0"
if(65 to 400)
icon_state = "arrow"
var/difference = target_angle - angle
angle = target_angle
if(!difference)
return
var/matrix/final = matrix(transform)
final.Turn(difference)
animate(src, transform = final, time = 5, loop = 0)
// CLOCKCULT
/obj/screen/alert/clockwork
alerttooltipstyle = "clockcult"
+4
View File
@@ -68,6 +68,10 @@
using.screen_loc = ui_ghost_pai
static_inventory += using
using = new /obj/screen/language_menu
using.icon = ui_style
static_inventory += using
/datum/hud/ghost/show_hud(version = 0, mob/viewmob)
..()
if(!mymob.client.prefs.ghost_hud)
+2 -2
View File
@@ -265,6 +265,6 @@
E.screen_loc = ui_equip_position(mymob)
if(mymob.hud_used)
show_hud(HUD_STYLE_STANDARD,mymob)
/datum/hud/proc/update_locked_slots()
/datum/hud/proc/update_locked_slots()
return
+12 -12
View File
@@ -313,18 +313,18 @@
inv_slots[inv.slot_id] = inv
inv.update_icon()
/datum/hud/human/update_locked_slots()
if(!mymob)
return
var/mob/living/carbon/human/H = mymob
var/datum/species/S = H.dna.species
for(var/obj/screen/inventory/inv in (static_inventory + toggleable_inventory))
if(inv.slot_id)
if(inv.slot_id in S.no_equip)
inv.alpha = 128
else
inv.alpha = initial(inv.alpha)
/datum/hud/human/update_locked_slots()
if(!mymob)
return
var/mob/living/carbon/human/H = mymob
var/datum/species/S = H.dna.species
for(var/obj/screen/inventory/inv in (static_inventory + toggleable_inventory))
if(inv.slot_id)
if(inv.slot_id in S.no_equip)
inv.alpha = 128
else
inv.alpha = initial(inv.alpha)
/datum/hud/human/hidden_inventory_update(mob/viewer)
if(!mymob)
return
+3 -4
View File
@@ -91,10 +91,9 @@
screen_loc = ui_language_menu
/obj/screen/language_menu/Click()
var/mob/living/L = usr
if(!istype(L))
return
L.open_language_menu(usr)
var/mob/M = usr
var/datum/language_holder/H = M.get_language_holder()
H.open_language_menu(usr)
/obj/screen/inventory
var/slot_id // The indentifier for the slot. It has nothing to do with ID cards.
+12 -7
View File
@@ -421,26 +421,31 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
else
tick_precentage = tick_remaining
GLOB.CURRENT_TICKLIMIT = world.tick_usage + tick_precentage
tick_precentage = max(tick_precentage*0.5, tick_precentage-queue_node.tick_overrun)
GLOB.CURRENT_TICKLIMIT = round(world.tick_usage + tick_precentage)
if (!(queue_node_flags & SS_TICKER))
ran_non_ticker = TRUE
ran = TRUE
tick_usage = world.tick_usage
queue_node_paused = (queue_node.state == SS_PAUSED || queue_node.state == SS_PAUSING)
last_type_processed = queue_node
queue_node.state = SS_RUNNING
tick_usage = world.tick_usage
var/state = queue_node.ignite(queue_node_paused)
tick_usage = world.tick_usage - tick_usage
if (state == SS_RUNNING)
state = SS_IDLE
current_tick_budget -= queue_node_priority
tick_usage = world.tick_usage - tick_usage
if (tick_usage < 0)
tick_usage = 0
queue_node.tick_overrun = max(0, MC_AVG_FAST_UP_SLOW_DOWN(queue_node.tick_overrun, tick_usage-tick_precentage))
queue_node.state = state
if (state == SS_PAUSED)
@@ -467,13 +472,13 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
queue_node.times_fired++
if (queue_node_flags & SS_TICKER)
queue_node.next_fire = world.time + (world.tick_lag * queue_node.wait)
queue_node.next_fire = world.time + (world.tick_lag * (queue_node.wait + (queue_node.tick_overrun/100)))
else if (queue_node_flags & SS_POST_FIRE_TIMING)
queue_node.next_fire = world.time + queue_node.wait
queue_node.next_fire = world.time + queue_node.wait + (world.tick_lag * (queue_node.tick_overrun/100))
else if (queue_node_flags & SS_KEEP_TIMING)
queue_node.next_fire += queue_node.wait
else
queue_node.next_fire = queue_node.queued_time + queue_node.wait
queue_node.next_fire = queue_node.queued_time + queue_node.wait + (world.tick_lag * (queue_node.tick_overrun/100))
queue_node.queued_time = 0
+2 -1
View File
@@ -17,6 +17,7 @@
var/next_fire = 0 //scheduled world.time for next fire()
var/cost = 0 //average time to execute
var/tick_usage = 0 //average tick usage
var/tick_overrun = 0 //average tick overrun
var/state = SS_IDLE //tracks the current state of the ss, running, paused, etc.
var/paused_ticks = 0 //ticks this ss is taking to run right now.
var/paused_tick_usage //total tick_usage of all of our runs while pausing this run
@@ -168,7 +169,7 @@
if(can_fire && !(SS_NO_FIRE in flags))
msg = "[round(cost,1)]ms|[round(tick_usage,1)]%|[round(ticks,0.1)]\t[msg]"
msg = "[round(cost,1)]ms|[round(tick_usage,1)]%([round(tick_overrun,1)]%)|[round(ticks,0.1)]\t[msg]"
else
msg = "OFFLINE\t[msg]"
+4 -14
View File
@@ -287,8 +287,6 @@ SUBSYSTEM_DEF(job)
if(PopcapReached())
RejectPlayer(player)
var/datum/job/validjob
// Loop through all jobs
for(var/datum/job/job in shuffledoccupations) // SHUFFLE ME BABY
if(!job)
@@ -315,19 +313,11 @@ SUBSYSTEM_DEF(job)
// If the job isn't filled
if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1)
Debug("DO pass, Player: [player], Level:[level], Job:[job.title]")
AssignRole(player, job.title)
unassigned -= player
break
validjob = job
//Is the Job empty? Stop Looking Then!
if (!job.current_positions)
break
//Assign us the last job we found
if (validjob)
Debug("DO pass, Player: [player], Level:[level], Job:[validjob.title]")
AssignRole(player, validjob.title)
unassigned -= player
break
// Hand out random jobs to the people who didn't get any in the last check
// Also makes sure that they got their preference correct
+18
View File
@@ -0,0 +1,18 @@
SUBSYSTEM_DEF(language)
name = "Language"
init_order = INIT_ORDER_LANGUAGE
flags = SS_NO_FIRE
/datum/controller/subsystem/language/Initialize(timeofday)
for(var/L in subtypesof(/datum/language))
var/datum/language/language = L
if(!initial(language.key))
continue
GLOB.all_languages += language
var/datum/language/instance = new language
GLOB.language_datum_instances[language] = instance
return ..()
+4 -3
View File
@@ -482,6 +482,7 @@
/datum/action/language_menu/Trigger()
if(!..())
return FALSE
if(isliving(owner))
var/mob/living/L = owner
L.open_language_menu(usr)
if(ismob(owner))
var/mob/M = owner
var/datum/language_holder/H = M.get_language_holder()
H.open_language_menu(usr)
+111 -11
View File
@@ -2,9 +2,55 @@
var/datum/action/innate/cultcomm/communion = new
/datum/antagonist/cult/Destroy()
qdel(communion)
QDEL_NULL(communion)
return ..()
/datum/antagonist/cult/proc/add_objectives()
var/list/target_candidates = list()
for(var/mob/living/carbon/human/player in GLOB.player_list)
if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && !is_convertable_to_cult(player) && (player != owner) && player.stat != DEAD)
target_candidates += player.mind
if(target_candidates.len == 0)
message_admins("Cult Sacrifice: Could not find unconvertable target, checking for convertable target.")
for(var/mob/living/carbon/human/player in GLOB.player_list)
if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && (player != owner) && player.stat != DEAD)
target_candidates += player.mind
listclearnulls(target_candidates)
if(LAZYLEN(target_candidates))
GLOB.sac_mind = pick(target_candidates)
if(!GLOB.sac_mind)
message_admins("Cult Sacrifice: ERROR - Null target chosen!")
else
var/datum/job/sacjob = SSjob.GetJob(GLOB.sac_mind.assigned_role)
var/datum/preferences/sacface = GLOB.sac_mind.current.client.prefs
var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
reshape.Shift(SOUTH, 4)
reshape.Shift(EAST, 1)
reshape.Crop(7,4,26,31)
reshape.Crop(-5,-3,26,30)
GLOB.sac_image = reshape
else
message_admins("Cult Sacrifice: Could not find unconvertable or convertable target. WELP!")
GLOB.sac_complete = TRUE
SSticker.mode.cult_objectives += "sacrifice"
SSticker.mode.cult_objectives += "eldergod"
/datum/antagonist/cult/proc/cult_memorization(datum/mind/cult_mind)
var/mob/living/current = cult_mind.current
for(var/obj_count = 1,obj_count <= SSticker.mode.cult_objectives.len,obj_count++)
var/explanation
switch(SSticker.mode.cult_objectives[obj_count])
if("sacrifice")
if(GLOB.sac_mind)
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role] via invoking a Sacrifice rune with them on it and three acolytes around it."
else
explanation = "The veil has already been weakened here, proceed to the final objective."
if("eldergod")
explanation = "Summon Nar-Sie by invoking the rune 'Summon Nar-Sie' with nine acolytes on it. You must do this after sacrificing your target."
if(!silent)
to_chat(current, "<B>Objective #[obj_count]</B>: [explanation]")
cult_mind.memory += "<B>Objective #[obj_count]</B>: [explanation]<BR>"
/datum/antagonist/cult/can_be_owned(datum/mind/new_owner)
. = ..()
if(.)
@@ -12,14 +58,17 @@
/datum/antagonist/cult/on_gain()
. = ..()
SSticker.mode.cult += owner
var/mob/living/current = owner.current
if(!LAZYLEN(SSticker.mode.cult_objectives))
add_objectives()
SSticker.mode.cult += owner // Only add after they've been given objectives
cult_memorization(owner)
if(jobban_isbanned(current, ROLE_CULTIST))
addtimer(CALLBACK(SSticker.mode, /datum/game_mode.proc/replace_jobbaned_player, current, ROLE_CULTIST, ROLE_CULTIST), 0)
SSticker.mode.update_cult_icons_added(owner)
if(istype(SSticker.mode, /datum/game_mode/cult))
var/datum/game_mode/cult/C = SSticker.mode
C.memorize_cult_objectives(owner)
if(jobban_isbanned(owner.current, ROLE_CULTIST))
addtimer(CALLBACK(SSticker.mode, /datum/game_mode.proc/replace_jobbaned_player, owner.current, ROLE_CULTIST, ROLE_CULTIST), 0)
owner.current.log_message("<font color=#960000>Has been converted to the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
current.log_message("<font color=#960000>Has been converted to the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
if(GLOB.blood_target && GLOB.blood_target_image && current.client)
current.client.images += GLOB.blood_target_image
/datum/antagonist/cult/apply_innate_effects(mob/living/mob_override)
. = ..()
@@ -27,8 +76,12 @@
if(mob_override)
current = mob_override
current.faction |= "cult"
current.grant_language(/datum/language/narsie)
current.verbs += /mob/living/proc/cult_help
if(!GLOB.cult_mastered)
current.verbs += /mob/living/proc/cult_master
communion.Grant(current)
current.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
/datum/antagonist/cult/remove_innate_effects(mob/living/mob_override)
. = ..()
@@ -36,15 +89,62 @@
if(mob_override)
current = mob_override
current.faction -= "cult"
current.remove_language(/datum/language/narsie)
current.verbs -= /mob/living/proc/cult_help
communion.Remove(current)
owner.current.verbs -= /mob/living/proc/cult_master
for(var/datum/action/innate/cultmast/H in owner.current.actions)
qdel(H)
current.clear_alert("bloodsense")
/datum/antagonist/cult/on_removal()
owner.wipe_memory()
SSticker.mode.cult -= owner
SSticker.mode.update_cult_icons_removed(owner)
to_chat(owner, "<span class='userdanger'>An unfamiliar white light flashes through your mind, cleansing the taint of the Dark One and all your memories as its servant.</span>")
owner.current.log_message("<font color=#960000>Has renounced the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
if(!silent)
owner.current.visible_message("<span class='big'>[owner] looks like [owner.current.p_they()] just reverted to their old faith!</span>")
to_chat(owner.current, "<span class='userdanger'>An unfamiliar white light flashes through your mind, cleansing the taint of the Geometer and all your memories as her servant.</span>")
owner.current.log_message("<font color=#960000>Has renounced the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
owner.current.visible_message("<span class='big'>[owner.current] looks like [owner.current.p_they()] just reverted to their old faith!</span>")
if(GLOB.blood_target && GLOB.blood_target_image && owner.current.client)
owner.current.client.images -= GLOB.blood_target_image
. = ..()
/datum/antagonist/cult/master
var/datum/action/innate/cultmast/finalreck/reckoning = new
var/datum/action/innate/cultmast/cultmark/bloodmark = new
/datum/antagonist/cult/master/Destroy()
QDEL_NULL(reckoning)
QDEL_NULL(bloodmark)
return ..()
/datum/antagonist/cult/master/on_gain()
. = ..()
var/mob/living/current = owner.current
SSticker.mode.set_antag_hud(current, "cultmaster")
/datum/antagonist/cult/master/greet()
to_chat(owner.current, "<span class='cultlarge'>You are the cult's Master</span>. As the cult's Master, you have a unique title and loud voice when communicating, are capable of marking \
targets, such as a location or a noncultist, to direct the cult to them, and, finally, you are capable of summoning the entire living cult to your location <b><i>once</i></b>.")
to_chat(owner.current, "Use these abilities to direct the cult to victory at any cost.")
/datum/antagonist/cult/master/apply_innate_effects(mob/living/mob_override)
. = ..()
var/mob/living/current = owner.current
if(mob_override)
current = mob_override
if(!GLOB.reckoning_complete)
reckoning.Grant(current)
bloodmark.Grant(current)
current.update_action_buttons_icon()
current.apply_status_effect(/datum/status_effect/cult_master)
/datum/antagonist/cult/master/remove_innate_effects(mob/living/mob_override)
. = ..()
var/mob/living/current = owner.current
if(mob_override)
current = mob_override
reckoning.Remove(current)
bloodmark.Remove(current)
current.update_action_buttons_icon()
current.remove_status_effect(/datum/status_effect/cult_master)
+1
View File
@@ -1,3 +1,4 @@
#define HOLOPAD_MAX_DIAL_TIME 200
/mob/camera/aiEye/remote/holo/setLoc()
+1583 -1577
View File
File diff suppressed because it is too large Load Diff
+29
View File
@@ -228,3 +228,32 @@
name = "Wish Granter's Immortality"
desc = "You are being resurrected!"
icon_state = "wish_granter"
/datum/status_effect/cult_master
id = "The Cult Master"
duration = -1
tick_interval = 100
alert_type = null
var/alive = TRUE
/datum/status_effect/cult_master/proc/deathrattle()
var/area/A = get_area(owner)
for(var/datum/mind/B in SSticker.mode.cult)
if(isliving(B.current))
var/mob/living/M = B.current
M << 'sound/hallucinations/veryfar_noise.ogg'
to_chat(M, "<span class='cultlarge'>The Cult's Master, [owner], has fallen in the [A]!")
/datum/status_effect/cult_master/tick()
if(owner.stat != DEAD && !alive)
alive = TRUE
return
if(owner.stat == DEAD && alive)
alive = FALSE
deathrattle()
/datum/status_effect/cult_master/on_remove()
deathrattle()
. = ..()
-75
View File
@@ -1,75 +0,0 @@
diff a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm (rejected hunks)
@@ -108,20 +108,6 @@
to_chat(owner, "<span class='sevtug[span_part]'>You feel a frustrated voice quietly fade from your mind...</span>")
qdel(src)
return
- if(!(owner in viewers(7, motor))) //not being in range makes it fall off much faster
- if(!is_servant && !warned_outofsight)
- to_chat(owner, "<span class='sevtug[span_part]'>\"[text2ratvar(pick(flee_messages))]\"</span>")
- warned_outofsight = TRUE
- if(severity)
- severity--
- if(!severity)
- qdel(src)
- return
- else
- qdel(src)
- return
- else if(prob(severity * 2))
- warned_outofsight = FALSE
if(!motor.active) //it being off makes it fall off much faster
if(!is_servant && !warned_turnoff)
if(motor.total_accessable_power() > motor.mania_cost)
@@ -129,20 +115,24 @@
else
to_chat(owner, "<span class='sevtug[span_part]'>[text2ratvar(pick(powerloss_messages))]</span>")
warned_turnoff = TRUE
- if(severity)
- severity--
+ severity = max(severity - 2, 0)
+ if(!severity)
+ qdel(src)
+ return
+ else
+ if(prob(severity * 2))
+ warned_turnoff = FALSE
+ if(!(owner in viewers(7, motor))) //not being in range makes it fall off slightly faster
+ if(!is_servant && !warned_outofsight)
+ to_chat(owner, "<span class='sevtug[span_part]'>\"[text2ratvar(pick(flee_messages))]\"</span>")
+ warned_outofsight = TRUE
+ severity = max(severity - 1, 0)
if(!severity)
qdel(src)
return
- else
- qdel(src)
- return
- else if(prob(severity * 2))
- warned_turnoff = FALSE
+ else if(prob(severity * 2))
+ warned_outofsight = FALSE
if(is_servant) //heals servants of braindamage, hallucination, druggy, dizziness, and confusion
- var/brainloss = owner.getBrainLoss()
- if(brainloss)
- owner.adjustBrainLoss(-brainloss)
if(owner.hallucination)
owner.hallucination = 0
if(owner.druggy)
@@ -163,14 +153,12 @@
if(prob(severity * 0.15))
to_chat(owner, "<span class='sevtug[span_part]'>\"[text2ratvar(pick(mania_messages))]\"</span>")
owner.playsound_local(get_turf(motor), hum, severity, 1)
- if(owner.getBrainLoss() <= 50)
- owner.adjustBrainLoss(severity * 0.025) //2.5% of severity per second
owner.adjust_drugginess(Clamp(max(severity * 0.075, 1), 0, max(0, 50 - owner.druggy))) //7.5% of severity per second, minimum 1
if(owner.hallucination < 50)
owner.hallucination = min(owner.hallucination + max(severity * 0.075, 1), 50) //7.5% of severity per second, minimum 1
- if(owner.dizziness < 25)
- owner.dizziness = min(owner.dizziness + Floor(severity * 0.025), 25) //2.5% of severity per second above 20 severity
+ if(owner.dizziness < 50)
+ owner.dizziness = min(owner.dizziness + round(severity * 0.05, 1), 50) //5% of severity per second above 10 severity
if(owner.confused < 25)
- owner.confused = min(owner.confused + Floor(severity * 0.025), 25) //2.5% of severity per second above 20 severity
+ owner.confused = min(owner.confused + round(severity * 0.025, 1), 25) //2.5% of severity per second above 20 severity
owner.adjustToxLoss(severity * 0.02, TRUE, TRUE) //2% of severity per second
severity--
+3 -3
View File
@@ -13,16 +13,16 @@
/datum/wires/explosive/c4
holder_type = /obj/item/weapon/c4
holder_type = /obj/item/weapon/grenade/plastic/c4
randomize = TRUE //Same behaviour since no wire actually disarms it
/datum/wires/explosive/c4/interactable(mob/user)
var/obj/item/weapon/c4/P = holder
var/obj/item/weapon/grenade/plastic/c4/P = holder
if(P.open_panel)
return TRUE
/datum/wires/explosive/c4/explode()
var/obj/item/weapon/c4/P = holder
var/obj/item/weapon/grenade/plastic/c4/P = holder
P.explode()
+1 -1
View File
@@ -43,7 +43,7 @@
if(SSatoms.InitAtom(src, args))
//we were deleted
return
var/list/created = SSatoms.created_atoms
if(created)
created += src
+51 -26
View File
@@ -13,9 +13,9 @@
var/throw_speed = 2 //How many tiles to move per ds when being thrown. Float values are fully supported
var/throw_range = 7
var/mob/pulledby = null
var/list/languages
var/list/initial_languages = list(/datum/language/common)
var/only_speaks_language = null
var/initial_language_holder = /datum/language_holder
var/datum/language_holder/language_holder
var/datum/language_menu/language_menu = null
var/verb_say = "says"
var/verb_ask = "asks"
var/verb_exclaim = "exclaims"
@@ -44,10 +44,6 @@
return FALSE
return ..()
/atom/movable/Initialize(mapload)
. = ..()
for(var/L in initial_languages)
grant_language(L)
/atom/movable/Move(atom/newloc, direct = 0)
if(!loc || !newloc) return 0
@@ -177,6 +173,7 @@
STOP_PROCESSING(SSinbounds, src)
QDEL_NULL(proximity_monitor)
QDEL_NULL(language_holder)
. = ..()
if(loc)
@@ -576,44 +573,70 @@
/* Language procs */
/atom/movable/proc/get_language_holder(shadow=TRUE)
if(language_holder)
return language_holder
else
language_holder = new initial_language_holder(src)
return language_holder
/atom/movable/proc/grant_language(datum/language/dt)
LAZYINITLIST(languages)
languages[dt] = TRUE
var/datum/language_holder/H = get_language_holder()
H.grant_language(dt)
/atom/movable/proc/grant_all_languages(omnitongue=FALSE)
for(var/la in subtypesof(/datum/language))
grant_language(la)
if(omnitongue)
SET_SECONDARY_FLAG(src, OMNITONGUE)
var/datum/language_holder/H = get_language_holder()
H.grant_all_languages(omnitongue)
/atom/movable/proc/get_random_understood_language()
var/list/possible = list()
for(var/dt in languages)
possible += dt
. = safepick(possible)
var/datum/language_holder/H = get_language_holder()
. = H.get_random_understood_language()
/atom/movable/proc/remove_language(datum/language/dt)
LAZYREMOVE(languages, dt)
var/datum/language_holder/H = get_language_holder()
H.remove_language(dt)
/atom/movable/proc/remove_all_languages()
LAZYCLEARLIST(languages)
var/datum/language_holder/H = get_language_holder()
H.remove_all_languages()
/atom/movable/proc/has_language(datum/language/dt)
. = is_type_in_typecache(dt, languages)
var/datum/language_holder/H = get_language_holder()
. = H.has_language(dt)
// Whether an AM can speak in a language or not, independent of whether
// it KNOWS the language
/atom/movable/proc/could_speak_in_language(datum/language/dt)
. = TRUE
/atom/movable/proc/can_speak_in_language(datum/language/dt)
. = has_language(dt)
if(only_speaks_language && !HAS_SECONDARY_FLAG(src, OMNITONGUE))
. = . && ispath(only_speaks_language, dt)
var/datum/language_holder/H = get_language_holder()
if(!H.has_language(dt))
return FALSE
else if(H.omnitongue || could_speak_in_language(dt))
return TRUE
else
return FALSE
/atom/movable/proc/get_default_language()
// if no language is specified, and we want to say() something, which
// language do we use?
var/datum/language_holder/H = get_language_holder()
if(H.selected_default_language)
if(H.has_language(H.selected_default_language))
return H.selected_default_language
else
H.selected_default_language = null
var/datum/language/chosen_langtype
var/highest_priority
for(var/lt in languages)
for(var/lt in H.languages)
var/datum/language/langtype = lt
if(!can_speak_in_language(langtype))
continue
@@ -622,8 +645,10 @@
if(!highest_priority || (pri > highest_priority))
chosen_langtype = langtype
highest_priority = pri
H.selected_default_language = .
. = chosen_langtype
/* End language procs */
/atom/movable/proc/ConveyorMove(movedir)
set waitfor = FALSE
if(!anchored && has_gravity())
+2 -2
View File
@@ -155,8 +155,8 @@
if(!(check_usability(user)))
return
to_chat(user, "<span class='notice'>You activate [src] and wait for confirmation.</span>")
var/list/nuke_candidates = pollCandidatesForMob("Do you want to play as a syndicate [borg_to_spawn ? "[lowertext(borg_to_spawn)] cyborg":"operative"]?", ROLE_OPERATIVE, null, ROLE_OPERATIVE, 150, POLL_IGNORE_SYNDICATE, src)
to_chat(user, "<span class='notice'>You activate [src] and wait for confirmation.</span>")
var/list/nuke_candidates = pollCandidatesForMob("Do you want to play as a syndicate [borg_to_spawn ? "[lowertext(borg_to_spawn)] cyborg":"operative"]?", ROLE_OPERATIVE, null, ROLE_OPERATIVE, 150, POLL_IGNORE_SYNDICATE, src)
if(nuke_candidates.len)
if(!(check_usability(user)))
return
+1 -2
View File
@@ -14,8 +14,7 @@
verb_ask = "requests"
verb_exclaim = "proclaims"
verb_yell = "harangues"
initial_languages = list(/datum/language/common, /datum/language/ratvar)
only_speaks_language = /datum/language/ratvar
initial_language_holder = /datum/language_holder/clockmob
bubble_icon = "clock"
light_color = "#E42742"
death_sound = 'sound/magic/clockwork/anima_fragment_death.ogg'
@@ -135,7 +135,7 @@
if(!check_special_requirements())
return FALSE
to_chat(invoker, "<span class='warning'>The tendril shivers slightly as it selects a marauder...</span>")
var/list/marauder_candidates = pollCandidates("Do you want to play as the clockwork marauder of [invoker.real_name]?", ROLE_SERVANT_OF_RATVAR, null, FALSE, 50, POLL_IGNORE_CLOCKWORK_MARAUDER)
var/list/marauder_candidates = pollGhostCandidates("Do you want to play as the clockwork marauder of [invoker.real_name]?", ROLE_SERVANT_OF_RATVAR, null, FALSE, 50, POLL_IGNORE_CLOCKWORK_MARAUDER)
if(!check_special_requirements())
return FALSE
if(!marauder_candidates.len)
+72 -54
View File
@@ -1,34 +1,31 @@
/datum/game_mode
var/list/datum/mind/cult = list()
var/list/cult_objectives = list()
var/eldergod = 1 //for the summon god objective
/proc/iscultist(mob/living/M)
return istype(M) && M.mind && M.mind.has_antag_datum(ANTAG_DATUM_CULT)
/proc/is_sacrifice_target(datum/mind/mind)
if(SSticker.mode.name == "cult")
var/datum/game_mode/cult/cult_mode = SSticker.mode
if(mind == cult_mode.sacrifice_target)
return 1
return 0
if(mind == GLOB.sac_mind)
return TRUE
return FALSE
/proc/is_convertable_to_cult(mob/living/M)
if(!istype(M))
return 0
return FALSE
if(M.mind)
if(ishuman(M) && (M.mind.assigned_role in list("Captain", "Chaplain")))
return 0
return FALSE
if(is_sacrifice_target(M.mind))
return 0
return FALSE
if(M.mind.enslaved_to && !iscultist(M.mind.enslaved_to))
return 0
return FALSE
else
return 0
return FALSE
if(M.isloyal() || issilicon(M) || isbot(M) || isdrone(M) || is_servant_of_ratvar(M))
return 0 //can't convert machines, shielded, or ratvar's dogs
return 1
return FALSE //can't convert machines, shielded, or ratvar's dogs
return TRUE
/datum/game_mode/cult
name = "cult"
@@ -47,14 +44,13 @@
<span class='notice'>Crew</span>: Prevent the cult from expanding and drive it out."
var/finished = 0
var/eldergod = 1 //for the summon god objective
var/acolytes_needed = 10 //for the survive objective
var/acolytes_survived = 0
var/datum/mind/sacrifice_target = null//The target to be sacrificed
var/list/cultists_to_cult = list() //the cultists we'll convert
/datum/game_mode/cult/pre_setup()
cult_objectives += "sacrifice"
cult_objectives += "eldergod"
@@ -82,22 +78,6 @@
return (cultists_to_cult.len>=required_enemies)
/datum/game_mode/cult/proc/memorize_cult_objectives(datum/mind/cult_mind)
for(var/obj_count = 1,obj_count <= cult_objectives.len,obj_count++)
var/explanation
switch(cult_objectives[obj_count])
if("survive")
explanation = "Our knowledge must live on. Make sure at least [acolytes_needed] acolytes escape on the shuttle to spread their work on an another station."
if("sacrifice")
if(sacrifice_target)
explanation = "Sacrifice [sacrifice_target.name], the [sacrifice_target.assigned_role] via invoking a Sacrifice rune with them on it and three acolytes around it."
else
explanation = "Free objective."
if("eldergod")
explanation = "Summon Nar-Sie by invoking the rune 'Summon Nar-Sie' with nine acolytes on it. You must do this after sacrificing your target."
to_chat(cult_mind.current, "<B>Objective #[obj_count]</B>: [explanation]")
cult_mind.memory += "<B>Objective #[obj_count]</B>: [explanation]<BR>"
/datum/game_mode/cult/post_setup()
modePlayer += cultists_to_cult
if("sacrifice" in cult_objectives)
@@ -108,9 +88,18 @@
if(player.mind && !(player.mind in cultists_to_cult))
possible_targets += player.mind
if(possible_targets.len > 0)
sacrifice_target = pick(possible_targets)
if(!sacrifice_target)
GLOB.sac_mind = pick(possible_targets)
if(!GLOB.sac_mind)
message_admins("Cult Sacrifice: ERROR - Null target chosen!")
else
var/datum/job/sacjob = SSjob.GetJob(GLOB.sac_mind.assigned_role)
var/datum/preferences/sacface = GLOB.sac_mind.current.client.prefs
var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
reshape.Shift(SOUTH, 4)
reshape.Shift(EAST, 1)
reshape.Crop(7,4,26,31)
reshape.Crop(-5,-3,26,30)
GLOB.sac_image = reshape
else
message_admins("Cult Sacrifice: Could not find unconvertable or convertable target. WELP!")
for(var/datum/mind/cult_mind in cultists_to_cult)
@@ -198,7 +187,7 @@
if(cult_objectives.Find("eldergod"))
cult_fail += eldergod //1 by default, 0 if the elder god has been summoned at least once
if(cult_objectives.Find("sacrifice"))
if(sacrifice_target && !GLOB.sacrificed.Find(sacrifice_target)) //if the target has been GLOB.sacrificed, ignore this step. otherwise, add 1 to cult_fail
if(GLOB.sac_mind && GLOB.sac_complete) //if the target has been GLOB.sacrificed, ignore this step. otherwise, add 1 to cult_fail
cult_fail++
return cult_fail //if any objectives aren't met, failure
@@ -243,16 +232,12 @@
SSblackbox.add_details("cult_objective","cult_survive|FAIL|[acolytes_needed]")
SSticker.news_report = CULT_FAILURE
if("sacrifice")
if(sacrifice_target)
if(sacrifice_target in GLOB.sacrificed)
explanation = "Sacrifice [sacrifice_target.name], the [sacrifice_target.assigned_role]. <span class='greenannounce'>Success!</span>"
SSblackbox.add_details("cult_objective","cult_sacrifice|SUCCESS")
else if(sacrifice_target && sacrifice_target.current)
explanation = "Sacrifice [sacrifice_target.name], the [sacrifice_target.assigned_role]. <span class='boldannounce'>Fail.</span>"
SSblackbox.add_details("cult_objective","cult_sacrifice|FAIL")
else
explanation = "Sacrifice [sacrifice_target.name], the [sacrifice_target.assigned_role]. <span class='boldannounce'>Fail (Gibbed).</span>"
SSblackbox.add_details("cult_objective","cult_sacrifice|FAIL|GIBBED")
if(GLOB.sac_complete)
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. <span class='greenannounce'>Success!</span>"
SSblackbox.add_details("cult_objective","cult_sacrifice|SUCCESS")
else
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. <span class='boldannounce'>Fail.</span>"
SSblackbox.add_details("cult_objective","cult_sacrifice|FAIL")
if("eldergod")
if(!eldergod)
explanation = "Summon Nar-Sie. <span class='greenannounce'>Success!</span>"
@@ -269,12 +254,45 @@
return 1
/datum/game_mode/proc/auto_declare_completion_cult()
if( cult.len || (SSticker && istype(SSticker.mode,/datum/game_mode/cult)) )
var/text = "<br><font size=3><b>The cultists were:</b></font>"
for(var/datum/mind/cultist in cult)
text += printplayer(cultist)
text += "<br>"
to_chat(world, text)
/datum/game_mode/proc/datum_cult_completion()
var/text = ""
var/acolytes_survived = 0
for(var/datum/mind/cult_mind in cult)
if (cult_mind.current && cult_mind.current.stat != DEAD)
if(cult_mind.current.onCentcom() || cult_mind.current.onSyndieBase())
acolytes_survived++
var/cult_fail = 0
cult_fail += eldergod
if(!GLOB.sac_complete)
cult_fail++
if(!cult_fail)
SSblackbox.set_details("round_end_result","win - cult win")
SSblackbox.set_val("round_end_result",acolytes_survived)
to_chat(world, "<span class='greentext'>The cult has succeeded! Nar-sie has snuffed out another torch in the void!</span>")
else
SSblackbox.set_details("round_end_result","loss - staff stopped the cult")
SSblackbox.set_val("round_end_result",acolytes_survived)
to_chat(world, "<span class='redtext'>The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!</span>")
if(cult_objectives.len)
text += "<br><b>The cultists' objectives were:</b>"
for(var/obj_count in 1 to 2)
var/explanation
switch(cult_objectives[obj_count])
if("sacrifice")
if(GLOB.sac_complete)
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. <span class='greenannounce'>Success!</span>"
SSblackbox.add_details("cult_objective","cult_sacrifice|SUCCESS")
else
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. <span class='boldannounce'>Fail.</span>"
SSblackbox.add_details("cult_objective","cult_sacrifice|FAIL")
if("eldergod")
if(!eldergod)
explanation = "Summon Nar-Sie. <span class='greenannounce'>Success!</span>"
SSblackbox.add_details("cult_objective","cult_narsie|SUCCESS")
SSticker.news_report = CULT_SUMMON
else
explanation = "Summon Nar-Sie. <span class='boldannounce'>Fail.</span>"
SSblackbox.add_details("cult_objective","cult_narsie|FAIL")
SSticker.news_report = CULT_FAILURE
text += "<br><B>Objective #[obj_count]</B>: [explanation]"
to_chat(world, text)
+171 -2
View File
@@ -1,3 +1,5 @@
// Contains cult communion, guide, and cult master abilities
#define MARK_COOLDOWN
/datum/action/innate/cultcomm
name = "Communion"
@@ -19,11 +21,22 @@
cultist_commune(usr, input)
/proc/cultist_commune(mob/living/user, message)
var/my_message
if(!message)
return
user.whisper("O bidai nabora se[pick("'","`")]sma!")
user.whisper("O bidai nabora se[pick("'","`")]sma!", language = /datum/language/common)
user.whisper(html_decode(message))
var/my_message = "<span class='cultitalic'><b>[(ishuman(user) ? "Acolyte" : "Construct")] [findtextEx(user.name, user.real_name) ? user.name : "[user.real_name] (as [user.name])"]:</b> [message]</span>"
var/title = "Acolyte"
var/span = "cultitalic"
if(user.mind && user.mind.has_antag_datum(ANTAG_DATUM_CULT_MASTER))
span = "cultlarge"
if(ishuman(user))
title = "Master"
else
title = "Lord"
else if(!ishuman(user))
title = "Construct"
my_message = "<span class='[span]'><b>[title] [findtextEx(user.name, user.real_name) ? user.name : "[user.real_name] (as [user.name])"]:</b> [message]</span>"
for(var/mob/M in GLOB.mob_list)
if(iscultist(M))
to_chat(M, my_message)
@@ -65,3 +78,159 @@
popup.set_content(text)
popup.open()
return 1
/mob/living/proc/cult_master()
set category = "Cultist"
set name = "Assert Leadership"
pollCultists(src) // This proc handles the distribution of cult master actions
/datum/action/innate/cultmast
background_icon_state = "bg_demon"
buttontooltipstyle = "cult"
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_CONSCIOUS
/datum/action/innate/cultmast/IsAvailable()
if(!owner.mind || !owner.mind.has_antag_datum(ANTAG_DATUM_CULT_MASTER))
return 0
return ..()
/datum/action/innate/cultmast/finalreck
name = "Final Reckoning"
desc = "A single-use spell that brings the entire cult to the master's location."
button_icon_state = "sintouch"
/datum/action/innate/cultmast/finalreck/Activate()
for(var/i in 1 to 4)
chant(i)
var/list/destinations = list()
for(var/turf/T in orange(1, owner))
if(!is_blocked_turf(T, TRUE))
destinations += T
if(!LAZYLEN(destinations))
to_chat(owner, "<span class='warning'>You need more space to summon the cult!</span>")
return
if(do_after(owner, 30, target = owner))
for(var/datum/mind/B in SSticker.mode.cult)
if(B.current && B.current.stat != DEAD)
var/turf/mobloc = get_turf(B.current)
switch(i)
if(1)
new /obj/effect/overlay/temp/cult/sparks(mobloc, B.current.dir)
playsound(mobloc, "sparks", 50, 1)
if(2)
new /obj/effect/overlay/temp/dir_setting/cult/phase/out(mobloc, B.current.dir)
playsound(mobloc, "sparks", 75, 1)
if(3)
new /obj/effect/overlay/temp/dir_setting/cult/phase(mobloc, B.current.dir)
playsound(mobloc, "sparks", 100, 1)
if(4)
playsound(mobloc, 'sound/magic/exit_blood.ogg', 100, 1)
if(B.current != owner)
B.current.setDir(SOUTH)
var/turf/final = pick(destinations)
new /obj/effect/overlay/temp/cult/blood(final)
addtimer(CALLBACK(B.current, /mob/.proc/reckon, final), 10)
else
return
GLOB.reckoning_complete = TRUE
Remove(owner)
/mob/proc/reckon(turf/final)
new /obj/effect/overlay/temp/cult/blood/out(get_turf(src))
forceMove(final)
/datum/action/innate/cultmast/finalreck/proc/chant(chant_number)
switch(chant_number)
if(1)
owner.say("C'arta forbici!", language = /datum/language/common)
if(2)
owner.say("Pleggh e'ntrath!", language = /datum/language/common)
playsound(get_turf(owner),'sound/magic/clockwork/narsie_attack.ogg', 50, 1)
if(3)
owner.say("Barhah hra zar'garis!", language = /datum/language/common)
playsound(get_turf(owner),'sound/magic/clockwork/narsie_attack.ogg', 75, 1)
if(4)
owner.say("N'ath reth sh'yro eth d'rekkathnor!!!", language = /datum/language/common)
playsound(get_turf(owner),'sound/magic/clockwork/narsie_attack.ogg', 100, 1)
/datum/action/innate/cultmast/cultmark
name = "Mark Target"
desc = "Marks a target for the cult."
button_icon_state = "cult_mark"
var/obj/effect/proc_holder/cultmark/CM
var/cooldown = 0
var/base_cooldown = 1200
/datum/action/innate/cultmast/cultmark/New()
CM = new()
CM.attached_action = src
..()
/datum/action/innate/cultmast/cultmark/IsAvailable()
if(!owner.mind || !owner.mind.has_antag_datum(ANTAG_DATUM_CULT_MASTER))
return 0
if(cooldown > world.time)
if(!CM.active)
owner << "<span class='cultlarge'><b>You need to wait [round((cooldown - world.time) * 0.1)] seconds before you can mark another target!</b></span>"
return 0
return ..()
/datum/action/innate/cultmast/cultmark/Destroy()
QDEL_NULL(CM)
return ..()
/datum/action/innate/cultmast/cultmark/Activate()
CM.toggle(owner) //the important bit
return TRUE
/obj/effect/proc_holder/cultmark
active = FALSE
ranged_mousepointer = 'icons/effects/cult_target.dmi'
var/datum/action/innate/cultmast/cultmark/attached_action
/obj/effect/proc_holder/cultmark/Destroy()
attached_action = null
return ..()
/obj/effect/proc_holder/cultmark/proc/toggle(mob/user)
if(active)
remove_ranged_ability("<span class='cult'>You cease the marking ritual.</span>")
else
add_ranged_ability(user, "<span class='cult'>You prepare to mark a target for your cult...</span>")
/obj/effect/proc_holder/cultmark/InterceptClickOn(mob/living/caller, params, atom/target)
if(..())
return
if(ranged_ability_user.incapacitated())
remove_ranged_ability()
return
var/turf/T = get_turf(ranged_ability_user)
if(!isturf(T))
return FALSE
if(target in view(7, get_turf(ranged_ability_user)))
GLOB.blood_target = target
var/area/A = get_area(target)
attached_action.cooldown = world.time + attached_action.base_cooldown
addtimer(CALLBACK(attached_action.owner, /mob.proc/update_action_buttons_icon), attached_action.base_cooldown)
GLOB.blood_target_image = image('icons/effects/cult_target.dmi', target, "glow", ABOVE_MOB_LAYER)
GLOB.blood_target_image.appearance_flags = RESET_COLOR
GLOB.blood_target_image.pixel_x = -target.pixel_x
GLOB.blood_target_image.pixel_y = -target.pixel_y
for(var/datum/mind/B in SSticker.mode.cult)
if(B.current && B.current.stat != DEAD && B.current.client)
to_chat(B.current, "<span class='cultlarge'><b>Master [ranged_ability_user] has marked [GLOB.blood_target] in the [A.name] as the cult's top priority, get there immediately!</b></span>")
B.current << pick(sound('sound/hallucinations/over_here2.ogg',0,1,75), sound('sound/hallucinations/over_here3.ogg',0,1,75))
B.current.client.images += GLOB.blood_target_image
attached_action.owner.update_action_buttons_icon()
remove_ranged_ability("<span class='cult'>The marking rite is complete! It will last for 90 seconds.</span>")
addtimer(CALLBACK(GLOBAL_PROC, .proc/reset_blood_target), 900, TIMER_OVERRIDE)
return TRUE
return FALSE
/proc/reset_blood_target()
for(var/datum/mind/B in SSticker.mode.cult)
if(B.current && B.current.stat != DEAD && B.current.client)
if(GLOB.blood_target)
to_chat(B.current,"<span class='cultlarge'><b>The blood mark has expired!</b></span>")
B.current.client.images -= GLOB.blood_target_image
QDEL_NULL(GLOB.blood_target)
+1 -1
View File
@@ -213,7 +213,7 @@
flags_inv = HIDEJUMPSUIT
allowed = list(/obj/item/weapon/tome,/obj/item/weapon/melee/cultblade)
body_parts_covered = CHEST|GROIN|LEGS|ARMS
armor = list(melee = -50, bullet = -50, laser = -100,energy = -50, bomb = -50, bio = -50, rad = -50, fire = 0, acid = 0)
armor = list(melee = -50, bullet = -50, laser = -50,energy = -50, bomb = -50, bio = -50, rad = -50, fire = 0, acid = 0)
slowdown = -1
hoodtype = /obj/item/clothing/head/hooded/berserkerhood
+22 -27
View File
@@ -197,35 +197,30 @@ This file contains the arcane tome files.
if(!src || QDELETED(src) || !Adjacent(user) || user.incapacitated() || !check_rune_turf(Turf, user))
return
if(ispath(rune_to_scribe, /obj/effect/rune/narsie))
if(SSticker.mode.name == "cult")
var/datum/game_mode/cult/cult_mode = SSticker.mode
if(!("eldergod" in cult_mode.cult_objectives))
to_chat(user, "<span class='warning'>Nar-Sie does not wish to be summoned!</span>")
return
if(cult_mode.sacrifice_target && !(cult_mode.sacrifice_target in GLOB.sacrificed))
to_chat(user, "<span class='warning'>The sacrifice is not complete. The portal would lack the power to open if you tried!</span>")
return
if(!cult_mode.eldergod)
to_chat(user, "<span class='cultlarge'>\"I am already here. There is no need to try to summon me now.\"</span>")
return
if((loc.z && loc.z != ZLEVEL_STATION) || !A.blob_allowed)
to_chat(user, "<span class='warning'>The Geometer is not interested in lesser locations; the station is the prize!</span>")
return
var/confirm_final = alert(user, "This is the FINAL step to summon Nar-Sie, it is a long, painful ritual and the crew will be alerted to your presence", "Are you prepared for the final battle?", "My life for Nar-Sie!", "No")
if(confirm_final == "No")
to_chat(user, "<span class='cult'>You decide to prepare further before scribing the rune.</span>")
return
Turf = get_turf(user)
A = get_area(src)
if(!check_rune_turf(Turf, user) || (loc.z && loc.z != ZLEVEL_STATION)|| !A.blob_allowed)
return
priority_announce("Figments from an eldritch god are being summoned by [user] into [A.map_name] from an unknown dimension. Disrupt the ritual at all costs!","Central Command Higher Dimensionsal Affairs", 'sound/AI/spanomalies.ogg')
for(var/B in spiral_range_turfs(1, user, 1))
var/obj/structure/emergency_shield/sanguine/N = new(B)
shields += N
else
if(!("eldergod" in SSticker.mode.cult_objectives))
to_chat(user, "<span class='warning'>Nar-Sie does not wish to be summoned!</span>")
return
if(!GLOB.sac_complete)
to_chat(user, "<span class='warning'>The sacrifice is not complete. The portal would lack the power to open if you tried!</span>")
return
if(!SSticker.mode.eldergod)
to_chat(user, "<span class='cultlarge'>\"I am already here. There is no need to try to summon me now.\"</span>")
return
if((loc.z && loc.z != ZLEVEL_STATION) || !A.blob_allowed)
to_chat(user, "<span class='warning'>The Geometer is not interested in lesser locations; the station is the prize!</span>")
return
var/confirm_final = alert(user, "This is the FINAL step to summon Nar-Sie; it is a long, painful ritual and the crew will be alerted to your presence", "Are you prepared for the final battle?", "My life for Nar-Sie!", "No")
if(confirm_final == "No")
to_chat(user, "<span class='cult'>You decide to prepare further before scribing the rune.</span>")
return
Turf = get_turf(user)
A = get_area(src)
if(!check_rune_turf(Turf, user) || (loc.z && loc.z != ZLEVEL_STATION)|| !A.blob_allowed)
return
priority_announce("Figments from an eldritch god are being summoned by [user] into [A.map_name] from an unknown dimension. Disrupt the ritual at all costs!","Central Command Higher Dimensional Affairs", 'sound/AI/spanomalies.ogg')
for(var/B in spiral_range_turfs(1, user, 1))
var/obj/structure/emergency_shield/sanguine/N = new(B)
shields += N
user.visible_message("<span class='warning'>[user] [user.blood_volume ? "cuts open their arm and begins writing in their own blood":"begins sketching out a strange design"]!</span>", \
"<span class='cult'>You [user.blood_volume ? "slice open your arm and ":""]begin drawing a sigil of the Geometer.</span>")
if(user.blood_volume)
+10 -10
View File
@@ -136,7 +136,7 @@ structure_check() searches for nearby cultist structures required for the invoca
if(invocation)
for(var/M in invokers)
var/mob/living/L = M
L.say(invocation)
L.say(invocation, language = /datum/language/common)
do_invoke_glow()
/obj/effect/rune/proc/do_invoke_glow()
@@ -398,23 +398,23 @@ structure_check() searches for nearby cultist structures required for the invoca
return 1
/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers)
var/big_sac = FALSE
if((((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || is_sacrifice_target(sacrificial.mind)) && invokers.len < 3)
for(var/M in invokers)
to_chat(M, "<span class='cultitalic'>[sacrificial] is too greatly linked to the world! You need three acolytes!</span>")
log_game("Offer rune failed - not enough acolytes and target is living or sac target")
return FALSE
var/sacrifice_fulfilled = FALSE
if(sacrificial.mind)
GLOB.sacrificed += sacrificial.mind
if(is_sacrifice_target(sacrificial.mind))
sacrifice_fulfilled = TRUE
GLOB.sac_complete = TRUE
big_sac = TRUE
else
GLOB.sacrificed += sacrificial
new /obj/effect/overlay/temp/cult/sac(get_turf(src))
for(var/M in invokers)
if(sacrifice_fulfilled)
if(big_sac)
to_chat(M, "<span class='cultlarge'>\"Yes! This is the one I desire! You have done well.\"</span>")
else
if(ishuman(sacrificial) || iscyborg(sacrificial))
@@ -451,7 +451,7 @@ structure_check() searches for nearby cultist structures required for the invoca
scribe_delay = 450 //how long the rune takes to create
scribe_damage = 40.1 //how much damage you take doing it
var/used
var/ignore_gamemode = FALSE
var/ignore_gamemode = TRUE
/obj/effect/rune/narsie/Initialize(mapload, set_keyword)
. = ..()
@@ -490,7 +490,7 @@ structure_check() searches for nearby cultist structures required for the invoca
//BEGIN THE SUMMONING
used = 1
..()
send_to_playing_players('sound/effects/dimensional_rend.ogg') //There used to be a message for this but every time it was changed it got edgier so I removed it
send_to_playing_players('sound/effects/dimensional_rend.ogg')
var/turf/T = get_turf(src)
sleep(40)
if(src)
@@ -516,7 +516,7 @@ structure_check() searches for nearby cultist structures required for the invoca
/obj/effect/rune/raise_dead
cultist_name = "Raise Dead"
cultist_desc = "requires the corpse of a cultist placed upon the rune. Provided there have been sufficient sacrifices, they will be revived."
invocation = null //Depends on the name of the user - see below
invocation = "Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!" //Depends on the name of the user - see below
icon_state = "1"
color = "#C80000"
var/static/revives_used = 0
@@ -556,9 +556,9 @@ structure_check() searches for nearby cultist structures required for the invoca
return
rune_in_use = 1
if(user.name == "Herbert West")
user.say("To life, to life, I bring them!")
invocation = "To life, to life, I bring them!"
else
user.say("Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!")
invocation = initial(invocation)
..()
revives_used++
mob_to_revive.revive(1, 1) //This does remove disabilities and such, but the rune might actually see some use because of it!
+124
View File
@@ -0,0 +1,124 @@
//Supply Talisman: Has a few unique effects. Granted only to starter cultists.
/obj/item/weapon/paper/talisman/supply
cultist_name = "Supply Talisman"
cultist_desc = "A multi-use talisman that can create various objects. Intended to increase the cult's strength early on."
invocation = null
uses = 3
var/list/possible_summons = list(
/datum/cult_supply/tome,
/datum/cult_supply/metal,
/datum/cult_supply/talisman/teleport,
/datum/cult_supply/talisman/emp,
/datum/cult_supply/talisman/stun,
/datum/cult_supply/talisman/veil,
/datum/cult_supply/soulstone,
/datum/cult_supply/construct_shell
)
/obj/item/weapon/paper/talisman/supply/invoke(mob/living/user, successfuluse = 1)
var/list/dat = list()
dat += "<B>There are [uses] bloody runes on the parchment.</B><BR>"
dat += "Please choose the chant to be imbued into the fabric of reality.<BR>"
dat += "<HR>"
for(var/s in possible_summons)
var/datum/cult_supply/S = s
dat += "<a href='?src=\ref[src];id=[initial(S.id)]'>[initial(S.invocation)]</a> - [initial(S.desc)]<br>"
var/datum/browser/popup = new(user, "talisman", "", 400, 400)
popup.set_content(dat.Join(""))
popup.open()
return 0
/obj/item/weapon/paper/talisman/supply/Topic(href, href_list)
world.log << "[usr], [href], [href_list]"
if(QDELETED(src) || usr.incapacitated() || !in_range(src, usr))
return
var/id = href_list["id"]
var/datum/cult_supply/match
for(var/s in possible_summons)
var/datum/cult_supply/S = s
if(initial(S.id) == id)
match = S
break
if(!match)
to_chat(usr, "<span class='userdanger'>The fabric of reality quivers in agony.</span>")
return
var/turf/T = get_turf(src)
var/summon_type = initial(match.summon_type)
var/atom/movable/AM = new summon_type(T)
if(istype(AM, /obj/item))
usr.put_in_hands(AM)
uses--
if(uses <= 0)
to_chat(usr, "<span class='warning'>[src] crumbles to dust.</span>")
burn()
/obj/item/weapon/paper/talisman/supply/weak
cultist_name = "Lesser Supply Talisman"
uses = 2
/obj/item/weapon/paper/talisman/supply/weak/Initialize(mapload)
. = ..()
// no runed metal from lesser talismans.
possible_summons -= /datum/cult_supply/metal
/datum/cult_supply
var/id = "used_popcorn"
var/invocation = "Pla'ceho'lder."
var/desc = "Summons a generic supply item, to aid the cult."
var/summon_type = /obj/item/trash/popcorn // wait this isn't useful
/datum/cult_supply/tome
id = "arcane_tome"
invocation = "N'ath reth sh'yro eth d'raggathnor!"
desc = "Summons an arcane tome, used to scribe runes."
summon_type = /obj/item/weapon/tome
/datum/cult_supply/metal
id = "runed_metal"
invocation = "Bar'tea eas!"
desc = "Provides 5 runed metal, which can build a variety of cult structures."
summon_type = /obj/item/stack/sheet/runed_metal/five
/datum/cult_supply/talisman/teleport
id = "teleport_talisman"
invocation = "Sas'so c'arta forbici!"
desc = "Allows you to move to a selected teleportation rune."
summon_type = /obj/item/weapon/paper/talisman/teleport
/datum/cult_supply/talisman/emp
id = "emp_talisman"
invocation = "Ta'gh fara'qha fel d'amar det!"
desc = "Allows you to destroy technology in a short range."
summon_type = /obj/item/weapon/paper/talisman/emp
/datum/cult_supply/talisman/stun
id = "stun_talisman"
invocation = "Fuu ma'jin!"
desc = "Allows you to stun a person by attacking them with the talisman. Does not work on people holding a holy weapon!"
summon_type = /obj/item/weapon/paper/talisman/stun
/datum/cult_supply/talisman/veil
id = "veil_talisman"
invocation = "Kla'atu barada nikt'o!"
desc = "Two use talisman, first use makes all nearby runes invisible, secnd use reveals nearby hidden runes."
summon_type = /obj/item/weapon/paper/talisman/true_sight
/datum/cult_supply/soulstone
id = "soulstone"
invocation = "Kal'om neth!"
desc = "Summons a soul stone, used to capture the spirits of dead or dying humans."
summon_type = /obj/item/device/soulstone
/datum/cult_supply/construct_shell
id = "construct_shell"
invocation = "Daa'ig osk!"
desc = "Summons a construct shell for use with soulstone-captured souls. It is too large to carry on your person."
summon_type = /obj/structure/constructshell
+1 -69
View File
@@ -28,7 +28,7 @@
. = successfuluse
if(successfuluse) //if the calling whatever says we succeed, do the fancy stuff
if(invocation)
user.whisper(invocation)
user.whisper(invocation, language = /datum/language/common)
if(health_cost && iscarbon(user))
var/mob/living/carbon/C = user
C.apply_damage(health_cost, BRUTE, pick("l_arm", "r_arm"))
@@ -45,74 +45,6 @@
var/mob/living/carbon/C = user
C.apply_damage(10, BRUTE, "head")
//Supply Talisman: Has a few unique effects. Granted only to starter cultists.
/obj/item/weapon/paper/talisman/supply
cultist_name = "Supply Talisman"
cultist_desc = "A multi-use talisman that can create various objects. Intended to increase the cult's strength early on."
invocation = null
uses = 3
/obj/item/weapon/paper/talisman/supply/invoke(mob/living/user, successfuluse = 1)
var/dat = "<B>There are [uses] bloody runes on the parchment.</B><BR>"
dat += "Please choose the chant to be imbued into the fabric of reality.<BR>"
dat += "<HR>"
dat += "<A href='?src=\ref[src];rune=newtome'>N'ath reth sh'yro eth d'raggathnor!</A> - Summons an arcane tome, used to scribe runes and communicate with other cultists.<BR>"
dat += "<A href='?src=\ref[src];rune=metal'>Bar'tea eas!</A> - Provides 5 runed metal.<BR>"
dat += "<A href='?src=\ref[src];rune=teleport'>Sas'so c'arta forbici!</A> - Allows you to move to a selected teleportation rune.<BR>"
dat += "<A href='?src=\ref[src];rune=emp'>Ta'gh fara'qha fel d'amar det!</A> - Allows you to destroy technology in a short range.<BR>"
dat += "<A href='?src=\ref[src];rune=runestun'>Fuu ma'jin!</A> - Allows you to stun a person by attacking them with the talisman.<BR>"
dat += "<A href='?src=\ref[src];rune=veiling'>Kla'atu barada nikt'o!</A> - Two use talisman, first use makes all nearby runes invisible, second use reveals nearby hidden runes.<BR>"
dat += "<A href='?src=\ref[src];rune=soulstone'>Kal'om neth!</A> - Summons a soul stone, used to capure the spirits of dead or dying humans.<BR>"
dat += "<A href='?src=\ref[src];rune=construct'>Daa'ig osk!</A> - Summons a construct shell for use with soulstone-captured souls. It is too large to carry on your person.<BR>"
var/datum/browser/popup = new(user, "talisman", "", 400, 400)
popup.set_content(dat)
popup.open()
return 0
/obj/item/weapon/paper/talisman/supply/Topic(href, href_list)
if(src)
if(usr.stat || usr.restrained() || !in_range(src, usr))
return
if(href_list["rune"])
switch(href_list["rune"])
if("newtome")
var/obj/item/weapon/tome/T = new(usr)
usr.put_in_hands(T)
if("metal")
if(istype(src, /obj/item/weapon/paper/talisman/supply/weak))
usr.visible_message("<span class='cultitalic'>Lesser supply talismans lack the strength to materialize runed metal!</span>")
return
var/obj/item/stack/sheet/runed_metal/R = new(usr,5)
usr.put_in_hands(R)
if("teleport")
var/obj/item/weapon/paper/talisman/teleport/T = new(usr)
usr.put_in_hands(T)
if("emp")
var/obj/item/weapon/paper/talisman/emp/T = new(usr)
usr.put_in_hands(T)
if("runestun")
var/obj/item/weapon/paper/talisman/stun/T = new(usr)
usr.put_in_hands(T)
if("soulstone")
var/obj/item/device/soulstone/T = new(usr)
usr.put_in_hands(T)
if("construct")
new /obj/structure/constructshell(get_turf(usr))
if("veiling")
var/obj/item/weapon/paper/talisman/true_sight/T = new(usr)
usr.put_in_hands(T)
src.uses--
if(src.uses <= 0)
if(iscarbon(usr))
var/mob/living/carbon/C = usr
C.drop_item()
visible_message("<span class='warning'>[src] crumbles to dust.</span>")
qdel(src)
/obj/item/weapon/paper/talisman/supply/weak
cultist_name = "Lesser Supply Talisman"
uses = 2
//Rite of Translocation: Same as rune
/obj/item/weapon/paper/talisman/teleport
cultist_name = "Talisman of Teleportation"
+2
View File
@@ -257,6 +257,8 @@
if(escaped_total > 0)
SSblackbox.set_val("escaped_total",escaped_total)
send2irc("Server", "Round just ended.")
if(cult.len && !istype(SSticker.mode,/datum/game_mode/cult))
datum_cult_completion()
return 0
@@ -62,7 +62,7 @@
icon = 'icons/mob/swarmer.dmi'
desc = "A robot of unknown design, they seek only to consume materials and replicate themselves indefinitely."
speak_emote = list("tones")
initial_languages = list(/datum/language/swarmer)
initial_language_holder = /datum/language_holder/swarmer
bubble_icon = "swarmer"
health = 40
maxHealth = 40
@@ -14,7 +14,7 @@
var/icon_reveal = "revenant_revealed"
var/icon_stun = "revenant_stun"
var/icon_drain = "revenant_draining"
var/stasis = 0
var/stasis = FALSE
incorporeal_move = 3
invisibility = INVISIBILITY_REVENANT
health = INFINITY //Revenants don't use health, they use essence instead
@@ -205,6 +205,7 @@
/mob/living/simple_animal/revenant/death()
if(!revealed || stasis) //Revenants cannot die if they aren't revealed //or are already dead
return 0
stasis = TRUE
to_chat(src, "<span class='revendanger'>NO! No... it's too late, you can feel your essence [pick("breaking apart", "drifting away")]...</span>")
notransform = TRUE
revealed = TRUE
@@ -222,8 +223,7 @@
R.client_to_revive = client //If the essence reforms, the old revenant is put back in the body
R.revenant = src
invisibility = INVISIBILITY_ABSTRACT
revealed = 0
stasis = 1
revealed = FALSE
ghostize(0)//Don't re-enter invisible corpse
return
@@ -317,7 +317,7 @@
incorporeal_move = 3
invisibility = INVISIBILITY_REVENANT
alpha=255
stasis = 0
stasis = FALSE
//reforming
+6 -6
View File
@@ -17,7 +17,7 @@
var/atom/movable/constant_target = null //The thing we're always focused on, if we're in the right mode
var/target_x = 0 //The target coordinates if we're tracking those
var/target_y = 0
var/minimum_range = 0 //at what range the pinpointer declares you to be at your destination
var/minimum_range = 0 //at what range the pinpointer declares you to be at your destination
var/nuke_warning = FALSE // If we've set off a miniature alarm about an armed nuke
var/mode = TRACK_NUKE_DISK //What are we looking for?
@@ -112,7 +112,7 @@
var/mob/living/closest_operative = get_closest_atom(/mob/living/carbon/human, possible_targets, here)
if(closest_operative)
target = closest_operative
if(TRACK_ATOM)
if(TRACK_ATOM)
if(constant_target)
target = constant_target
if(TRACK_COORDINATES)
@@ -130,7 +130,7 @@
if(here.z != there.z)
icon_state = "pinon[nuke_warning ? "alert" : ""]null"
return
if(get_dist_euclidian(here,there)<=minimum_range)
if(get_dist_euclidian(here,there)<=minimum_range)
icon_state = "pinon[nuke_warning ? "alert" : ""]direct"
else
setDir(get_dir(here, there))
@@ -172,6 +172,6 @@
desc = "An integrated tracking device, jury-rigged to search for living Syndicate operatives."
mode = TRACK_OPERATIVES
flags = NODROP
+14 -5
View File
@@ -54,7 +54,7 @@
if(!ishuman(M))//If target is not a human.
return ..()
if(iscultist(M))
to_chat(user, "<span class='cultlarge'>\"Come now, do not capture your fellow's soul.\"</span>")
to_chat(user, "<span class='cultlarge'>\"Come now, do not capture your bretheren's soul.\"</span>")
return
add_logs(user, M, "captured [M.name]'s soul", src)
@@ -132,11 +132,11 @@
if("VICTIM")
var/mob/living/carbon/human/T = target
if(SSticker.mode.name == "cult" && T.mind == SSticker.mode:sacrifice_target)
if(is_sacrifice_target(T.mind))
if(iscultist(user))
to_chat(user, "<span class='cult'><b>\"This soul is mine.</b></span> <span class='cultlarge'>SACRIFICE THEM!\"</span>")
else
to_chat(user, "<span class='danger'>The soulstone doesn't work for no apparent reason.</span>")
to_chat(user, "<span class='danger'>The soulstone seems to reject this soul.</span>")
return 0
if(contents.len)
to_chat(user, "<span class='userdanger'>Capture failed!</span>: The soulstone is full! Free an existing soul to make room.")
@@ -188,7 +188,10 @@
else
makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder/noncult, A, user, 0, T.loc)
for(var/datum/mind/B in SSticker.mode.cult)
if(B == A.mind)
SSticker.mode.cult -= A.mind
SSticker.mode.update_cult_icons_removed(A.mind)
qdel(T)
user.drop_item()
qdel(src)
@@ -200,6 +203,9 @@
var/mob/living/simple_animal/hostile/construct/newstruct = new ctype((loc_override) ? (loc_override) : (get_turf(target)))
if(stoner)
newstruct.faction |= "\ref[stoner]"
newstruct.master = stoner
var/datum/action/innate/seek_master/SM = new()
SM.Grant(newstruct)
newstruct.key = target.key
if(newstruct.mind && ((stoner && iscultist(stoner)) || cultoverride) && SSticker && SSticker.mode)
SSticker.mode.add_cultist(newstruct.mind, 0)
@@ -207,6 +213,9 @@
to_chat(newstruct, "<b>You are still bound to serve the cult[stoner ? " and [stoner]":""], follow their orders and help them complete their goals at all costs.</b>")
else if(stoner)
to_chat(newstruct, "<b>You are still bound to serve your creator, [stoner], follow their orders and help them complete their goals at all costs.</b>")
newstruct.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
var/obj/screen/alert/bloodsense/BS = newstruct.alerts["bloodsense"]
BS.Cviewer = newstruct
newstruct.cancel_camera()
@@ -244,7 +253,7 @@
break
if(!chosen_ghost) //Failing that, we grab a ghost
var/list/consenting_candidates = pollCandidates("Would you like to play as a Shade?", "Cultist", null, ROLE_CULTIST, poll_time = 50)
var/list/consenting_candidates = pollGhostCandidates("Would you like to play as a Shade?", "Cultist", null, ROLE_CULTIST, poll_time = 50)
if(consenting_candidates.len)
chosen_ghost = pick(consenting_candidates)
if(!T)
File diff suppressed because it is too large Load Diff
+499 -499
View File
@@ -1,499 +1,499 @@
//Cloning revival method.
//The pod handles the actual cloning while the computer manages the clone profiles
//Potential replacement for genetics revives or something I dunno (?)
#define CLONE_INITIAL_DAMAGE 190 //Clones in clonepods start with 190 cloneloss damage and 190 brainloss damage, thats just logical
#define MINIMUM_HEAL_LEVEL 40
#define SPEAK(message) radio.talk_into(src, message, radio_channel, get_spans(), get_default_language())
/obj/machinery/clonepod
anchored = 1
name = "cloning pod"
desc = "An electronically-lockable pod for growing organic tissue."
density = 1
icon = 'icons/obj/cloning.dmi'
icon_state = "pod_0"
req_access = list(GLOB.access_cloning) //For premature unlocking.
verb_say = "states"
var/heal_level //The clone is released once its health reaches this level.
var/obj/machinery/computer/cloning/connected = null //So we remember the connected clone machine.
var/mess = FALSE //Need to clean out it if it's full of exploded clone.
var/attempting = FALSE //One clone attempt at a time thanks
var/speed_coeff
var/efficiency
var/datum/mind/clonemind
var/grab_ghost_when = CLONER_MATURE_CLONE
var/obj/item/device/radio/radio
var/radio_key = /obj/item/device/encryptionkey/headset_med
var/radio_channel = "Medical"
var/obj/effect/countdown/clonepod/countdown
var/list/unattached_flesh
var/flesh_number = 0
// The "brine" is the reagents that are automatically added in small
// amounts to the occupant.
var/static/list/brine_types = list(
"salbutamol", // anti-oxyloss
"bicaridine", // NOBREATHE species take brute in crit
"corazone", // prevents cardiac arrest damage
"mimesbane") // stops them gasping from lack of air.
/obj/machinery/clonepod/New()
..()
var/obj/item/weapon/circuitboard/machine/B = new /obj/item/weapon/circuitboard/machine/clonepod(null)
B.apply_default_parts(src)
countdown = new(src)
radio = new(src)
radio.keyslot = new radio_key
radio.subspace_transmission = 1
radio.canhear_range = 0
radio.recalculateChannels()
/obj/machinery/clonepod/Destroy()
go_out()
qdel(radio)
radio = null
qdel(countdown)
countdown = null
if(connected)
connected.DetachCloner(src)
for(var/i in unattached_flesh)
qdel(i)
LAZYCLEARLIST(unattached_flesh)
unattached_flesh = null
. = ..()
/obj/machinery/clonepod/RefreshParts()
speed_coeff = 0
efficiency = 0
for(var/obj/item/weapon/stock_parts/scanning_module/S in component_parts)
efficiency += S.rating
for(var/obj/item/weapon/stock_parts/manipulator/P in component_parts)
speed_coeff += P.rating
heal_level = (efficiency * 15) + 10
if(heal_level < MINIMUM_HEAL_LEVEL)
heal_level = MINIMUM_HEAL_LEVEL
if(heal_level > 100)
heal_level = 100
/obj/item/weapon/circuitboard/machine/clonepod
name = "Clone Pod (Machine Board)"
build_path = /obj/machinery/clonepod
origin_tech = "programming=2;biotech=2"
req_components = list(
/obj/item/stack/cable_coil = 2,
/obj/item/weapon/stock_parts/scanning_module = 2,
/obj/item/weapon/stock_parts/manipulator = 2,
/obj/item/stack/sheet/glass = 1)
//The return of data disks?? Just for transferring between genetics machine/cloning machine.
//TO-DO: Make the genetics machine accept them.
/obj/item/weapon/disk/data
name = "cloning data disk"
icon_state = "datadisk0" //Gosh I hope syndies don't mistake them for the nuke disk.
var/list/fields = list()
var/read_only = 0 //Well,it's still a floppy disk
//Disk stuff.
/obj/item/weapon/disk/data/New()
..()
icon_state = "datadisk[rand(0,6)]"
add_overlay("datadisk_gene")
/obj/item/weapon/disk/data/attack_self(mob/user)
read_only = !read_only
to_chat(user, "<span class='notice'>You flip the write-protect tab to [read_only ? "protected" : "unprotected"].</span>")
/obj/item/weapon/disk/data/examine(mob/user)
..()
to_chat(user, "The write-protect tab is set to [read_only ? "protected" : "unprotected"].")
//Clonepod
/obj/machinery/clonepod/examine(mob/user)
..()
var/mob/living/mob_occupant = occupant
if(mess)
to_chat(user, "It's filled with blood and viscera. You swear you can see it moving...")
if(is_operational() && mob_occupant)
if(mob_occupant.stat != DEAD)
to_chat(user, "Current clone cycle is [round(get_completion())]% complete.")
/obj/machinery/clonepod/return_air()
// We want to simulate the clone not being in contact with
// the atmosphere, so we'll put them in a constant pressure
// nitrogen. They'll breathe through the chemicals we pump into them.
var/static/datum/gas_mixture/immutable/cloner/GM //global so that there's only one instance made for all cloning pods
if(!GM)
GM = new
return GM
/obj/machinery/clonepod/proc/get_completion()
. = FALSE
var/mob/living/mob_occupant = occupant
if(mob_occupant)
. = (100 * ((mob_occupant.health + 100) / (heal_level + 100)))
/obj/machinery/clonepod/attack_ai(mob/user)
return examine(user)
//Start growing a human clone in the pod!
/obj/machinery/clonepod/proc/growclone(ckey, clonename, ui, se, mindref, datum/species/mrace, list/features, factions)
if(panel_open)
return FALSE
if(mess || attempting)
return FALSE
clonemind = locate(mindref)
if(!istype(clonemind)) //not a mind
return FALSE
if( clonemind.current && clonemind.current.stat != DEAD ) //mind is associated with a non-dead body
return FALSE
if(clonemind.active) //somebody is using that mind
if( ckey(clonemind.key)!=ckey )
return FALSE
else
// get_ghost() will fail if they're unable to reenter their body
var/mob/dead/observer/G = clonemind.get_ghost()
if(!G)
return FALSE
if(clonemind.damnation_type) //Can't clone the damned.
INVOKE_ASYNC(src, .proc/horrifyingsound)
mess = TRUE
icon_state = "pod_g"
update_icon()
return FALSE
attempting = TRUE //One at a time!!
countdown.start()
var/mob/living/carbon/human/H = new /mob/living/carbon/human(src)
if(clonemind.changeling)
var/obj/item/organ/brain/B = H.getorganslot("brain")
B.vital = FALSE
B.decoy_override = TRUE
H.hardset_dna(ui, se, H.real_name, null, mrace, features)
if(efficiency > 2)
var/list/unclean_mutations = (GLOB.not_good_mutations|GLOB.bad_mutations)
H.dna.remove_mutation_group(unclean_mutations)
if(efficiency > 5 && prob(20))
H.randmutvg()
if(efficiency < 3 && prob(50))
var/mob/M = H.randmutb()
if(ismob(M))
H = M
H.silent = 20 //Prevents an extreme edge case where clones could speak if they said something at exactly the right moment.
occupant = H
if(!clonename) //to prevent null names
clonename = "clone ([rand(0,999)])"
H.real_name = clonename
icon_state = "pod_1"
//Get the clone body ready
maim_clone(H)
check_brine() // put in chemicals NOW to stop death via cardiac arrest
H.Paralyse(4)
clonemind.transfer_to(H)
if(grab_ghost_when == CLONER_FRESH_CLONE)
H.grab_ghost()
to_chat(H, "<span class='notice'><b>Consciousness slowly creeps over you as your body regenerates.</b><br><i>So this is what cloning feels like?</i></span>")
if(grab_ghost_when == CLONER_MATURE_CLONE)
H.ghostize(TRUE) //Only does anything if they were still in their old body and not already a ghost
to_chat(H.get_ghost(TRUE), "<span class='notice'>Your body is beginning to regenerate in a cloning pod. You will become conscious when it is complete.</span>")
if(H)
H.faction |= factions
H.set_cloned_appearance()
H.suiciding = FALSE
attempting = FALSE
return TRUE
//Grow clones to maturity then kick them out. FREELOADERS
/obj/machinery/clonepod/process()
var/mob/living/mob_occupant = occupant
if(!is_operational()) //Autoeject if power is lost
if(mob_occupant)
go_out()
connected_message("Clone Ejected: Loss of power.")
else if(mob_occupant && (mob_occupant.loc == src))
if((mob_occupant.stat == DEAD) || (mob_occupant.suiciding) || mob_occupant.hellbound) //Autoeject corpses and suiciding dudes.
connected_message("Clone Rejected: Deceased.")
SPEAK("The cloning of [mob_occupant.real_name] has been \
aborted due to unrecoverable tissue failure.")
go_out()
else if(mob_occupant.cloneloss > (100 - heal_level))
mob_occupant.Paralyse(4)
//Slowly get that clone healed and finished.
mob_occupant.adjustCloneLoss(-((speed_coeff/2) * config.damage_multiplier))
var/progress = CLONE_INITIAL_DAMAGE - mob_occupant.getCloneLoss()
// To avoid the default cloner making incomplete clones
progress += (100 - MINIMUM_HEAL_LEVEL)
var/milestone = CLONE_INITIAL_DAMAGE / flesh_number
var/installed = flesh_number - unattached_flesh.len
if((progress / milestone) >= installed)
// attach some flesh
var/obj/item/I = pick_n_take(unattached_flesh)
if(isorgan(I))
var/obj/item/organ/O = I
O.Insert(mob_occupant)
else if(isbodypart(I))
var/obj/item/bodypart/BP = I
BP.attach_limb(mob_occupant)
//Premature clones may have brain damage.
mob_occupant.adjustBrainLoss(-((speed_coeff/2) * config.damage_multiplier))
check_brine()
use_power(7500) //This might need tweaking.
else if((mob_occupant.cloneloss <= (100 - heal_level)))
connected_message("Cloning Process Complete.")
SPEAK("The cloning cycle of [mob_occupant.real_name] is complete.")
go_out()
else if (!mob_occupant || mob_occupant.loc != src)
occupant = null
if (!mess && !panel_open)
icon_state = "pod_0"
use_power(200)
//Let's unlock this early I guess. Might be too early, needs tweaking.
/obj/machinery/clonepod/attackby(obj/item/weapon/W, mob/user, params)
if(!(occupant || mess))
if(default_deconstruction_screwdriver(user, "[icon_state]_maintenance", "[initial(icon_state)]",W))
return
if(exchange_parts(user, W))
return
if(default_deconstruction_crowbar(W))
return
if(istype(W,/obj/item/device/multitool))
var/obj/item/device/multitool/P = W
if(istype(P.buffer, /obj/machinery/computer/cloning))
if(get_area(P.buffer) != get_area(src))
to_chat(user, "<font color = #666633>-% Cannot link machines across power zones. Buffer cleared %-</font color>")
P.buffer = null
return
to_chat(user, "<font color = #666633>-% Successfully linked [P.buffer] with [src] %-</font color>")
var/obj/machinery/computer/cloning/comp = P.buffer
if(connected)
connected.DetachCloner(src)
comp.AttachCloner(src)
else
P.buffer = src
to_chat(user, "<font color = #666633>-% Successfully stored \ref[P.buffer] [P.buffer.name] in buffer %-</font color>")
return
var/mob/living/mob_occupant = occupant
if(W.GetID())
if(!check_access(W))
to_chat(user, "<span class='danger'>Access Denied.</span>")
return
if(!(mob_occupant || mess))
to_chat(user, "<span class='danger'>Error: Pod has no occupant.</span>")
return
else
connected_message("Authorized Ejection")
SPEAK("An authorized ejection of [clonemind.name] has occurred.")
to_chat(user, "<span class='notice'>You force an emergency ejection. </span>")
go_out()
else
return ..()
/obj/machinery/clonepod/emag_act(mob/user)
if(!occupant)
return
to_chat(user, "<span class='warning'>You corrupt the genetic compiler.</span>")
malfunction()
//Put messages in the connected computer's temp var for display.
/obj/machinery/clonepod/proc/connected_message(message)
if ((isnull(connected)) || (!istype(connected, /obj/machinery/computer/cloning)))
return FALSE
if (!message)
return FALSE
connected.temp = message
connected.updateUsrDialog()
return TRUE
/obj/machinery/clonepod/proc/go_out()
countdown.stop()
var/mob/living/mob_occupant = occupant
if(mess) //Clean that mess and dump those gibs!
mess = FALSE
new /obj/effect/gibspawner/generic(loc)
audible_message("<span class='italics'>You hear a splat.</span>")
icon_state = "pod_0"
return
if(!mob_occupant)
return
if(grab_ghost_when == CLONER_MATURE_CLONE)
mob_occupant.grab_ghost()
to_chat(occupant, "<span class='notice'><b>There is a bright flash!</b><br><i>You feel like a new being.</i></span>")
mob_occupant.flash_act()
var/turf/T = get_turf(src)
occupant.forceMove(T)
icon_state = "pod_0"
mob_occupant.domutcheck(1) //Waiting until they're out before possible monkeyizing. The 1 argument forces powers to manifest.
occupant = null
/obj/machinery/clonepod/proc/malfunction()
var/mob/living/mob_occupant = occupant
if(mob_occupant)
connected_message("Critical Error!")
SPEAK("Critical error! Please contact a Thinktronic Systems \
technician, as your warranty may be affected.")
mess = TRUE
for(var/obj/item/O in unattached_flesh)
qdel(O)
icon_state = "pod_g"
if(mob_occupant.mind != clonemind)
clonemind.transfer_to(mob_occupant)
mob_occupant.grab_ghost() // We really just want to make you suffer.
flash_color(mob_occupant, flash_color="#960000", flash_time=100)
to_chat(mob_occupant, "<span class='warning'><b>Agony blazes across your consciousness as your body is torn apart.</b><br><i>Is this what dying is like? Yes it is.</i></span>")
playsound(src.loc, 'sound/machines/warning-buzzer.ogg', 50, 0)
mob_occupant << sound('sound/hallucinations/veryfar_noise.ogg',0,1,50)
QDEL_IN(mob_occupant, 40)
/obj/machinery/clonepod/relaymove(mob/user)
if(user.stat == CONSCIOUS)
go_out()
/obj/machinery/clonepod/emp_act(severity)
var/mob/living/mob_occupant = occupant
if(mob_occupant && prob(100/(severity*efficiency)))
connected_message(Gibberish("EMP-caused Accidental Ejection", 0))
SPEAK(Gibberish("Exposure to electromagnetic fields has caused the ejection of [mob_occupant.real_name] prematurely." ,0))
go_out()
..()
/obj/machinery/clonepod/ex_act(severity, target)
..()
if(!QDELETED(src))
go_out()
/obj/machinery/clonepod/handle_atom_del(atom/A)
if(A == occupant)
occupant = null
countdown.stop()
/obj/machinery/clonepod/proc/horrifyingsound()
for(var/i in 1 to 5)
playsound(loc,pick('sound/hallucinations/growl1.ogg','sound/hallucinations/growl2.ogg','sound/hallucinations/growl3.ogg'), 100, rand(0.95,1.05))
sleep(1)
sleep(10)
playsound(loc,'sound/hallucinations/wail.ogg',100,1)
/obj/machinery/clonepod/deconstruct(disassembled = TRUE)
if(occupant)
go_out()
..()
/obj/machinery/clonepod/proc/maim_clone(mob/living/carbon/human/H)
if(!unattached_flesh)
unattached_flesh = list()
else
for(var/fl in unattached_flesh)
qdel(fl)
unattached_flesh.Cut()
H.setCloneLoss(CLONE_INITIAL_DAMAGE) //Yeah, clones start with very low health, not with random, because why would they start with random health
H.setBrainLoss(CLONE_INITIAL_DAMAGE)
// In addition to being cellularly damaged and having barely any
// brain function, they also have no limbs or internal organs.
var/static/list/zones = list("r_arm", "l_arm", "r_leg", "l_leg")
for(var/zone in zones)
var/obj/item/bodypart/BP = H.get_bodypart(zone)
BP.drop_limb()
BP.forceMove(src)
unattached_flesh += BP
for(var/o in H.internal_organs)
var/obj/item/organ/organ = o
if(!istype(organ) || organ.vital)
continue
organ.Remove(H, special=TRUE)
organ.forceMove(src)
unattached_flesh += organ
flesh_number = unattached_flesh.len
/obj/machinery/clonepod/proc/check_brine()
// Clones are in a pickled bath of mild chemicals, keeping
// them alive, despite their lack of internal organs
for(var/bt in brine_types)
if(occupant.reagents.get_reagent_amount(bt) < 1)
occupant.reagents.add_reagent(bt, 1)
/*
* Manual -- A big ol' manual.
*/
/obj/item/weapon/paper/Cloning
name = "paper - 'H-87 Cloning Apparatus Manual"
info = {"<h4>Getting Started</h4>
Congratulations, your station has purchased the H-87 industrial cloning device!<br>
Using the H-87 is almost as simple as brain surgery! Simply insert the target humanoid into the scanning chamber and select the scan option to create a new profile!<br>
<b>That's all there is to it!</b><br>
<i>Notice, cloning system cannot scan inorganic life or small primates. Scan may fail if subject has suffered extreme brain damage.</i><br>
<p>Clone profiles may be viewed through the profiles menu. Scanning implants a complementary HEALTH MONITOR IMPLANT into the subject, which may be viewed from each profile.
Profile Deletion has been restricted to \[Station Head\] level access.</p>
<h4>Cloning from a profile</h4>
Cloning is as simple as pressing the CLONE option at the bottom of the desired profile.<br>
Per your company's EMPLOYEE PRIVACY RIGHTS agreement, the H-87 has been blocked from cloning crewmembers while they are still alive.<br>
<br>
<p>The provided CLONEPOD SYSTEM will produce the desired clone. Standard clone maturation times (With SPEEDCLONE technology) are roughly 90 seconds.
The cloning pod may be unlocked early with any \[Medical Researcher\] ID after initial maturation is complete.</p><br>
<i>Please note that resulting clones may have a small DEVELOPMENTAL DEFECT as a result of genetic drift.</i><br>
<h4>Profile Management</h4>
<p>The H-87 (as well as your station's standard genetics machine) can accept STANDARD DATA DISKETTES.
These diskettes are used to transfer genetic information between machines and profiles.
A load/save dialog will become available in each profile if a disk is inserted.</p><br>
<i>A good diskette is a great way to counter aforementioned genetic drift!</i><br>
<br>
<font size=1>This technology produced under license from Thinktronic Systems, LTD.</font>"}
#undef CLONE_INITIAL_DAMAGE
#undef SPEAK
#undef MINIMUM_HEAL_LEVEL
//Cloning revival method.
//The pod handles the actual cloning while the computer manages the clone profiles
//Potential replacement for genetics revives or something I dunno (?)
#define CLONE_INITIAL_DAMAGE 190 //Clones in clonepods start with 190 cloneloss damage and 190 brainloss damage, thats just logical
#define MINIMUM_HEAL_LEVEL 40
#define SPEAK(message) radio.talk_into(src, message, radio_channel, get_spans(), get_default_language())
/obj/machinery/clonepod
anchored = 1
name = "cloning pod"
desc = "An electronically-lockable pod for growing organic tissue."
density = 1
icon = 'icons/obj/cloning.dmi'
icon_state = "pod_0"
req_access = list(GLOB.access_cloning) //For premature unlocking.
verb_say = "states"
var/heal_level //The clone is released once its health reaches this level.
var/obj/machinery/computer/cloning/connected = null //So we remember the connected clone machine.
var/mess = FALSE //Need to clean out it if it's full of exploded clone.
var/attempting = FALSE //One clone attempt at a time thanks
var/speed_coeff
var/efficiency
var/datum/mind/clonemind
var/grab_ghost_when = CLONER_MATURE_CLONE
var/obj/item/device/radio/radio
var/radio_key = /obj/item/device/encryptionkey/headset_med
var/radio_channel = "Medical"
var/obj/effect/countdown/clonepod/countdown
var/list/unattached_flesh
var/flesh_number = 0
// The "brine" is the reagents that are automatically added in small
// amounts to the occupant.
var/static/list/brine_types = list(
"salbutamol", // anti-oxyloss
"bicaridine", // NOBREATHE species take brute in crit
"corazone", // prevents cardiac arrest damage
"mimesbane") // stops them gasping from lack of air.
/obj/machinery/clonepod/New()
..()
var/obj/item/weapon/circuitboard/machine/B = new /obj/item/weapon/circuitboard/machine/clonepod(null)
B.apply_default_parts(src)
countdown = new(src)
radio = new(src)
radio.keyslot = new radio_key
radio.subspace_transmission = 1
radio.canhear_range = 0
radio.recalculateChannels()
/obj/machinery/clonepod/Destroy()
go_out()
qdel(radio)
radio = null
qdel(countdown)
countdown = null
if(connected)
connected.DetachCloner(src)
for(var/i in unattached_flesh)
qdel(i)
LAZYCLEARLIST(unattached_flesh)
unattached_flesh = null
. = ..()
/obj/machinery/clonepod/RefreshParts()
speed_coeff = 0
efficiency = 0
for(var/obj/item/weapon/stock_parts/scanning_module/S in component_parts)
efficiency += S.rating
for(var/obj/item/weapon/stock_parts/manipulator/P in component_parts)
speed_coeff += P.rating
heal_level = (efficiency * 15) + 10
if(heal_level < MINIMUM_HEAL_LEVEL)
heal_level = MINIMUM_HEAL_LEVEL
if(heal_level > 100)
heal_level = 100
/obj/item/weapon/circuitboard/machine/clonepod
name = "Clone Pod (Machine Board)"
build_path = /obj/machinery/clonepod
origin_tech = "programming=2;biotech=2"
req_components = list(
/obj/item/stack/cable_coil = 2,
/obj/item/weapon/stock_parts/scanning_module = 2,
/obj/item/weapon/stock_parts/manipulator = 2,
/obj/item/stack/sheet/glass = 1)
//The return of data disks?? Just for transferring between genetics machine/cloning machine.
//TO-DO: Make the genetics machine accept them.
/obj/item/weapon/disk/data
name = "cloning data disk"
icon_state = "datadisk0" //Gosh I hope syndies don't mistake them for the nuke disk.
var/list/fields = list()
var/read_only = 0 //Well,it's still a floppy disk
//Disk stuff.
/obj/item/weapon/disk/data/New()
..()
icon_state = "datadisk[rand(0,6)]"
add_overlay("datadisk_gene")
/obj/item/weapon/disk/data/attack_self(mob/user)
read_only = !read_only
to_chat(user, "<span class='notice'>You flip the write-protect tab to [read_only ? "protected" : "unprotected"].</span>")
/obj/item/weapon/disk/data/examine(mob/user)
..()
to_chat(user, "The write-protect tab is set to [read_only ? "protected" : "unprotected"].")
//Clonepod
/obj/machinery/clonepod/examine(mob/user)
..()
var/mob/living/mob_occupant = occupant
if(mess)
to_chat(user, "It's filled with blood and viscera. You swear you can see it moving...")
if(is_operational() && mob_occupant)
if(mob_occupant.stat != DEAD)
to_chat(user, "Current clone cycle is [round(get_completion())]% complete.")
/obj/machinery/clonepod/return_air()
// We want to simulate the clone not being in contact with
// the atmosphere, so we'll put them in a constant pressure
// nitrogen. They'll breathe through the chemicals we pump into them.
var/static/datum/gas_mixture/immutable/cloner/GM //global so that there's only one instance made for all cloning pods
if(!GM)
GM = new
return GM
/obj/machinery/clonepod/proc/get_completion()
. = FALSE
var/mob/living/mob_occupant = occupant
if(mob_occupant)
. = (100 * ((mob_occupant.health + 100) / (heal_level + 100)))
/obj/machinery/clonepod/attack_ai(mob/user)
return examine(user)
//Start growing a human clone in the pod!
/obj/machinery/clonepod/proc/growclone(ckey, clonename, ui, se, mindref, datum/species/mrace, list/features, factions)
if(panel_open)
return FALSE
if(mess || attempting)
return FALSE
clonemind = locate(mindref)
if(!istype(clonemind)) //not a mind
return FALSE
if( clonemind.current && clonemind.current.stat != DEAD ) //mind is associated with a non-dead body
return FALSE
if(clonemind.active) //somebody is using that mind
if( ckey(clonemind.key)!=ckey )
return FALSE
else
// get_ghost() will fail if they're unable to reenter their body
var/mob/dead/observer/G = clonemind.get_ghost()
if(!G)
return FALSE
if(clonemind.damnation_type) //Can't clone the damned.
INVOKE_ASYNC(src, .proc/horrifyingsound)
mess = TRUE
icon_state = "pod_g"
update_icon()
return FALSE
attempting = TRUE //One at a time!!
countdown.start()
var/mob/living/carbon/human/H = new /mob/living/carbon/human(src)
if(clonemind.changeling)
var/obj/item/organ/brain/B = H.getorganslot("brain")
B.vital = FALSE
B.decoy_override = TRUE
H.hardset_dna(ui, se, H.real_name, null, mrace, features)
if(efficiency > 2)
var/list/unclean_mutations = (GLOB.not_good_mutations|GLOB.bad_mutations)
H.dna.remove_mutation_group(unclean_mutations)
if(efficiency > 5 && prob(20))
H.randmutvg()
if(efficiency < 3 && prob(50))
var/mob/M = H.randmutb()
if(ismob(M))
H = M
H.silent = 20 //Prevents an extreme edge case where clones could speak if they said something at exactly the right moment.
occupant = H
if(!clonename) //to prevent null names
clonename = "clone ([rand(0,999)])"
H.real_name = clonename
icon_state = "pod_1"
//Get the clone body ready
maim_clone(H)
check_brine() // put in chemicals NOW to stop death via cardiac arrest
H.Paralyse(4)
clonemind.transfer_to(H)
if(grab_ghost_when == CLONER_FRESH_CLONE)
H.grab_ghost()
to_chat(H, "<span class='notice'><b>Consciousness slowly creeps over you as your body regenerates.</b><br><i>So this is what cloning feels like?</i></span>")
if(grab_ghost_when == CLONER_MATURE_CLONE)
H.ghostize(TRUE) //Only does anything if they were still in their old body and not already a ghost
to_chat(H.get_ghost(TRUE), "<span class='notice'>Your body is beginning to regenerate in a cloning pod. You will become conscious when it is complete.</span>")
if(H)
H.faction |= factions
H.set_cloned_appearance()
H.suiciding = FALSE
attempting = FALSE
return TRUE
//Grow clones to maturity then kick them out. FREELOADERS
/obj/machinery/clonepod/process()
var/mob/living/mob_occupant = occupant
if(!is_operational()) //Autoeject if power is lost
if(mob_occupant)
go_out()
connected_message("Clone Ejected: Loss of power.")
else if(mob_occupant && (mob_occupant.loc == src))
if((mob_occupant.stat == DEAD) || (mob_occupant.suiciding) || mob_occupant.hellbound) //Autoeject corpses and suiciding dudes.
connected_message("Clone Rejected: Deceased.")
SPEAK("The cloning of [mob_occupant.real_name] has been \
aborted due to unrecoverable tissue failure.")
go_out()
else if(mob_occupant.cloneloss > (100 - heal_level))
mob_occupant.Paralyse(4)
//Slowly get that clone healed and finished.
mob_occupant.adjustCloneLoss(-((speed_coeff/2) * config.damage_multiplier))
var/progress = CLONE_INITIAL_DAMAGE - mob_occupant.getCloneLoss()
// To avoid the default cloner making incomplete clones
progress += (100 - MINIMUM_HEAL_LEVEL)
var/milestone = CLONE_INITIAL_DAMAGE / flesh_number
var/installed = flesh_number - unattached_flesh.len
if((progress / milestone) >= installed)
// attach some flesh
var/obj/item/I = pick_n_take(unattached_flesh)
if(isorgan(I))
var/obj/item/organ/O = I
O.Insert(mob_occupant)
else if(isbodypart(I))
var/obj/item/bodypart/BP = I
BP.attach_limb(mob_occupant)
//Premature clones may have brain damage.
mob_occupant.adjustBrainLoss(-((speed_coeff/2) * config.damage_multiplier))
check_brine()
use_power(7500) //This might need tweaking.
else if((mob_occupant.cloneloss <= (100 - heal_level)))
connected_message("Cloning Process Complete.")
SPEAK("The cloning cycle of [mob_occupant.real_name] is complete.")
go_out()
else if (!mob_occupant || mob_occupant.loc != src)
occupant = null
if (!mess && !panel_open)
icon_state = "pod_0"
use_power(200)
//Let's unlock this early I guess. Might be too early, needs tweaking.
/obj/machinery/clonepod/attackby(obj/item/weapon/W, mob/user, params)
if(!(occupant || mess))
if(default_deconstruction_screwdriver(user, "[icon_state]_maintenance", "[initial(icon_state)]",W))
return
if(exchange_parts(user, W))
return
if(default_deconstruction_crowbar(W))
return
if(istype(W,/obj/item/device/multitool))
var/obj/item/device/multitool/P = W
if(istype(P.buffer, /obj/machinery/computer/cloning))
if(get_area(P.buffer) != get_area(src))
to_chat(user, "<font color = #666633>-% Cannot link machines across power zones. Buffer cleared %-</font color>")
P.buffer = null
return
to_chat(user, "<font color = #666633>-% Successfully linked [P.buffer] with [src] %-</font color>")
var/obj/machinery/computer/cloning/comp = P.buffer
if(connected)
connected.DetachCloner(src)
comp.AttachCloner(src)
else
P.buffer = src
to_chat(user, "<font color = #666633>-% Successfully stored \ref[P.buffer] [P.buffer.name] in buffer %-</font color>")
return
var/mob/living/mob_occupant = occupant
if(W.GetID())
if(!check_access(W))
to_chat(user, "<span class='danger'>Access Denied.</span>")
return
if(!(mob_occupant || mess))
to_chat(user, "<span class='danger'>Error: Pod has no occupant.</span>")
return
else
connected_message("Authorized Ejection")
SPEAK("An authorized ejection of [clonemind.name] has occurred.")
to_chat(user, "<span class='notice'>You force an emergency ejection. </span>")
go_out()
else
return ..()
/obj/machinery/clonepod/emag_act(mob/user)
if(!occupant)
return
to_chat(user, "<span class='warning'>You corrupt the genetic compiler.</span>")
malfunction()
//Put messages in the connected computer's temp var for display.
/obj/machinery/clonepod/proc/connected_message(message)
if ((isnull(connected)) || (!istype(connected, /obj/machinery/computer/cloning)))
return FALSE
if (!message)
return FALSE
connected.temp = message
connected.updateUsrDialog()
return TRUE
/obj/machinery/clonepod/proc/go_out()
countdown.stop()
var/mob/living/mob_occupant = occupant
if(mess) //Clean that mess and dump those gibs!
mess = FALSE
new /obj/effect/gibspawner/generic(loc)
audible_message("<span class='italics'>You hear a splat.</span>")
icon_state = "pod_0"
return
if(!mob_occupant)
return
if(grab_ghost_when == CLONER_MATURE_CLONE)
mob_occupant.grab_ghost()
to_chat(occupant, "<span class='notice'><b>There is a bright flash!</b><br><i>You feel like a new being.</i></span>")
mob_occupant.flash_act()
var/turf/T = get_turf(src)
occupant.forceMove(T)
icon_state = "pod_0"
mob_occupant.domutcheck(1) //Waiting until they're out before possible monkeyizing. The 1 argument forces powers to manifest.
occupant = null
/obj/machinery/clonepod/proc/malfunction()
var/mob/living/mob_occupant = occupant
if(mob_occupant)
connected_message("Critical Error!")
SPEAK("Critical error! Please contact a Thinktronic Systems \
technician, as your warranty may be affected.")
mess = TRUE
for(var/obj/item/O in unattached_flesh)
qdel(O)
icon_state = "pod_g"
if(mob_occupant.mind != clonemind)
clonemind.transfer_to(mob_occupant)
mob_occupant.grab_ghost() // We really just want to make you suffer.
flash_color(mob_occupant, flash_color="#960000", flash_time=100)
to_chat(mob_occupant, "<span class='warning'><b>Agony blazes across your consciousness as your body is torn apart.</b><br><i>Is this what dying is like? Yes it is.</i></span>")
playsound(src.loc, 'sound/machines/warning-buzzer.ogg', 50, 0)
mob_occupant << sound('sound/hallucinations/veryfar_noise.ogg',0,1,50)
QDEL_IN(mob_occupant, 40)
/obj/machinery/clonepod/relaymove(mob/user)
if(user.stat == CONSCIOUS)
go_out()
/obj/machinery/clonepod/emp_act(severity)
var/mob/living/mob_occupant = occupant
if(mob_occupant && prob(100/(severity*efficiency)))
connected_message(Gibberish("EMP-caused Accidental Ejection", 0))
SPEAK(Gibberish("Exposure to electromagnetic fields has caused the ejection of [mob_occupant.real_name] prematurely." ,0))
go_out()
..()
/obj/machinery/clonepod/ex_act(severity, target)
..()
if(!QDELETED(src))
go_out()
/obj/machinery/clonepod/handle_atom_del(atom/A)
if(A == occupant)
occupant = null
countdown.stop()
/obj/machinery/clonepod/proc/horrifyingsound()
for(var/i in 1 to 5)
playsound(loc,pick('sound/hallucinations/growl1.ogg','sound/hallucinations/growl2.ogg','sound/hallucinations/growl3.ogg'), 100, rand(0.95,1.05))
sleep(1)
sleep(10)
playsound(loc,'sound/hallucinations/wail.ogg',100,1)
/obj/machinery/clonepod/deconstruct(disassembled = TRUE)
if(occupant)
go_out()
..()
/obj/machinery/clonepod/proc/maim_clone(mob/living/carbon/human/H)
if(!unattached_flesh)
unattached_flesh = list()
else
for(var/fl in unattached_flesh)
qdel(fl)
unattached_flesh.Cut()
H.setCloneLoss(CLONE_INITIAL_DAMAGE) //Yeah, clones start with very low health, not with random, because why would they start with random health
H.setBrainLoss(CLONE_INITIAL_DAMAGE)
// In addition to being cellularly damaged and having barely any
// brain function, they also have no limbs or internal organs.
var/static/list/zones = list("r_arm", "l_arm", "r_leg", "l_leg")
for(var/zone in zones)
var/obj/item/bodypart/BP = H.get_bodypart(zone)
BP.drop_limb()
BP.forceMove(src)
unattached_flesh += BP
for(var/o in H.internal_organs)
var/obj/item/organ/organ = o
if(!istype(organ) || organ.vital)
continue
organ.Remove(H, special=TRUE)
organ.forceMove(src)
unattached_flesh += organ
flesh_number = unattached_flesh.len
/obj/machinery/clonepod/proc/check_brine()
// Clones are in a pickled bath of mild chemicals, keeping
// them alive, despite their lack of internal organs
for(var/bt in brine_types)
if(occupant.reagents.get_reagent_amount(bt) < 1)
occupant.reagents.add_reagent(bt, 1)
/*
* Manual -- A big ol' manual.
*/
/obj/item/weapon/paper/Cloning
name = "paper - 'H-87 Cloning Apparatus Manual"
info = {"<h4>Getting Started</h4>
Congratulations, your station has purchased the H-87 industrial cloning device!<br>
Using the H-87 is almost as simple as brain surgery! Simply insert the target humanoid into the scanning chamber and select the scan option to create a new profile!<br>
<b>That's all there is to it!</b><br>
<i>Notice, cloning system cannot scan inorganic life or small primates. Scan may fail if subject has suffered extreme brain damage.</i><br>
<p>Clone profiles may be viewed through the profiles menu. Scanning implants a complementary HEALTH MONITOR IMPLANT into the subject, which may be viewed from each profile.
Profile Deletion has been restricted to \[Station Head\] level access.</p>
<h4>Cloning from a profile</h4>
Cloning is as simple as pressing the CLONE option at the bottom of the desired profile.<br>
Per your company's EMPLOYEE PRIVACY RIGHTS agreement, the H-87 has been blocked from cloning crewmembers while they are still alive.<br>
<br>
<p>The provided CLONEPOD SYSTEM will produce the desired clone. Standard clone maturation times (With SPEEDCLONE technology) are roughly 90 seconds.
The cloning pod may be unlocked early with any \[Medical Researcher\] ID after initial maturation is complete.</p><br>
<i>Please note that resulting clones may have a small DEVELOPMENTAL DEFECT as a result of genetic drift.</i><br>
<h4>Profile Management</h4>
<p>The H-87 (as well as your station's standard genetics machine) can accept STANDARD DATA DISKETTES.
These diskettes are used to transfer genetic information between machines and profiles.
A load/save dialog will become available in each profile if a disk is inserted.</p><br>
<i>A good diskette is a great way to counter aforementioned genetic drift!</i><br>
<br>
<font size=1>This technology produced under license from Thinktronic Systems, LTD.</font>"}
#undef CLONE_INITIAL_DAMAGE
#undef SPEAK
#undef MINIMUM_HEAL_LEVEL
-38
View File
@@ -1,38 +0,0 @@
diff a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm (rejected hunks)
@@ -311,15 +311,15 @@
to_chat(user, "<font color = #666633>-% Successfully stored \ref[P.buffer] [P.buffer.name] in buffer %-</font color>")
return
+ var/mob/living/mob_occupant = occupant
if(W.GetID())
if(!check_access(W))
to_chat(user, "<span class='danger'>Access Denied.</span>")
return
- if(!(occupant || mess))
+ if(!(mob_occupant || mess))
to_chat(user, "<span class='danger'>Error: Pod has no occupant.</span>")
return
else
- var/mob/living/mob_occupant
connected_message("Authorized Ejection")
SPEAK("An authorized ejection of [clonemind.name] has occurred.")
to_chat(user, "<span class='notice'>You force an emergency ejection. </span>")
@@ -395,16 +395,10 @@
go_out()
/obj/machinery/clonepod/emp_act(severity)
-<<<<<<< HEAD
- if((occupant || mess) && prob(100/(severity*efficiency)))
- connected_message(Gibberish("EMP-caused Accidental Ejection", 0))
- SPEAK(Gibberish("Exposure to electromagnetic fields has caused the ejection of [clonemind.name] prematurely." ,0))
-=======
- if(isliving(occupant) && prob(100/(severity*efficiency)))
- var/mob/living/mob_occupant = occupant
+ var/mob/living/mob_occupant = occupant
+ if(mob_occupant && prob(100/(severity*efficiency)))
connected_message(Gibberish("EMP-caused Accidental Ejection", 0))
SPEAK(Gibberish("Exposure to electromagnetic fields has caused the ejection of [mob_occupant.real_name] prematurely." ,0))
->>>>>>> Changes /obj/machinery to have atom/movable occupants
go_out()
..()
+8 -8
View File
@@ -186,23 +186,23 @@
// Scanner
if (!isnull(src.scanner))
var/mob/living/scanner_occupant = scanner.occupant
var/mob/living/scanner_occupant = scanner.occupant
dat += "<h3>Scanner Functions</h3>"
dat += "<div class='statusDisplay'>"
if(!scanner_occupant)
if(!scanner_occupant)
dat += "Scanner Unoccupied"
else if(loading)
dat += "[scanner_occupant] => Scanning..."
dat += "[scanner_occupant] => Scanning..."
else
if(scanner_occupant.ckey != scantemp_ckey)
if(scanner_occupant.ckey != scantemp_ckey)
scantemp = "Ready to Scan"
scantemp_ckey = scanner_occupant.ckey
dat += "[scanner_occupant] => [scantemp]"
scantemp_ckey = scanner_occupant.ckey
dat += "[scanner_occupant] => [scantemp]"
dat += "</div>"
if(scanner_occupant)
if(scanner_occupant)
dat += "<a href='byond://?src=\ref[src];scan=1'>Start Scan</a>"
dat += "<br><a href='byond://?src=\ref[src];lock=1'>[src.scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>"
else
+3 -3
View File
@@ -113,8 +113,8 @@
to_chat(R.connected_ai, "<br><br><span class='alert'>ALERT - Cyborg detonation detected: [R.name]</span><br>")
R.ResetSecurityCodes()
else
var/turf/T = get_turf(R)
message_admins("<span class='notice'>[ADMIN_LOOKUPFLW(usr)] detonated [key_name(R, R.client)][ADMIN_JMP(T)]!</span>")
var/turf/T = get_turf(R)
message_admins("<span class='notice'>[ADMIN_LOOKUPFLW(usr)] detonated [key_name(R, R.client)][ADMIN_JMP(T)]!</span>")
log_game("\<span class='notice'>[key_name(usr)] detonated [key_name(R)]!</span>")
if(R.connected_ai)
to_chat(R.connected_ai, "<br><br><span class='alert'>ALERT - Cyborg detonation detected: [R.name]</span><br>")
@@ -128,7 +128,7 @@
if(can_control(usr, R))
var/choice = input("Are you certain you wish to [R.canmove ? "lock down" : "release"] [R.name]?") in list("Confirm", "Abort")
if(choice == "Confirm" && can_control(usr, R) && !..())
message_admins("<span class='notice'>[ADMIN_LOOKUPFLW(usr)] [R.canmove ? "locked down" : "released"] [key_name(R, R.client)][ADMIN_LOOKUPFLW(R)]!</span>")
message_admins("<span class='notice'>[ADMIN_LOOKUPFLW(usr)] [R.canmove ? "locked down" : "released"] [key_name(R, R.client)][ADMIN_LOOKUPFLW(R)]!</span>")
log_game("[key_name(usr)] [R.canmove ? "locked down" : "released"] [key_name(R)]!")
R.SetLockdown(!R.lockcharge)
to_chat(R, "[!R.lockcharge ? "<span class='notice'>Your lockdown has been lifted!" : "<span class='alert'>You have been locked down!"]</span>")
@@ -58,12 +58,12 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
/obj/machinery/computer/telecrystals/uplinker/proc/donateTC(amt, addLog = 1)
if(uplinkholder && linkedboss)
if(amt < 0)
linkedboss.storedcrystals += uplinkholder.hidden_uplink.telecrystals
if(addLog)
linkedboss.logTransfer("[src] donated [uplinkholder.hidden_uplink.telecrystals] telecrystals to [linkedboss].")
uplinkholder.hidden_uplink.telecrystals = 0
else if(amt <= uplinkholder.hidden_uplink.telecrystals)
if(amt < 0)
linkedboss.storedcrystals += uplinkholder.hidden_uplink.telecrystals
if(addLog)
linkedboss.logTransfer("[src] donated [uplinkholder.hidden_uplink.telecrystals] telecrystals to [linkedboss].")
uplinkholder.hidden_uplink.telecrystals = 0
else if(amt <= uplinkholder.hidden_uplink.telecrystals)
uplinkholder.hidden_uplink.telecrystals -= amt
linkedboss.storedcrystals += amt
if(addLog)
@@ -71,12 +71,12 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
/obj/machinery/computer/telecrystals/uplinker/proc/giveTC(amt, addLog = 1)
if(uplinkholder && linkedboss)
if(amt < 0)
uplinkholder.hidden_uplink.telecrystals += linkedboss.storedcrystals
if(addLog)
linkedboss.logTransfer("[src] received [linkedboss.storedcrystals] telecrystals from [linkedboss].")
linkedboss.storedcrystals = 0
else if(amt <= linkedboss.storedcrystals)
if(amt < 0)
uplinkholder.hidden_uplink.telecrystals += linkedboss.storedcrystals
if(addLog)
linkedboss.logTransfer("[src] received [linkedboss.storedcrystals] telecrystals from [linkedboss].")
linkedboss.storedcrystals = 0
else if(amt <= linkedboss.storedcrystals)
uplinkholder.hidden_uplink.telecrystals += amt
linkedboss.storedcrystals -= amt
if(addLog)
@@ -99,7 +99,7 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
if(uplinkholder)
dat += "[uplinkholder.hidden_uplink.telecrystals] telecrystals remain in this uplink.<BR>"
if(linkedboss)
dat += "Donate TC: <a href='byond://?src=\ref[src];donate=1'>1</a> | <a href='byond://?src=\ref[src];donate=5'>5</a> | <a href='byond://?src=\ref[src];donate=-1'>All</a>"
dat += "Donate TC: <a href='byond://?src=\ref[src];donate=1'>1</a> | <a href='byond://?src=\ref[src];donate=5'>5</a> | <a href='byond://?src=\ref[src];donate=-1'>All</a>"
dat += "<br><a href='byond://?src=\ref[src];eject=1'>Eject Uplink</a>"
@@ -113,9 +113,9 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
if(..())
return
if(href_list["donate"])
var/tcamt = text2num(href_list["donate"])
donateTC(tcamt)
if(href_list["donate"])
var/tcamt = text2num(href_list["donate"])
donateTC(tcamt)
if(href_list["eject"])
ejectuplink()
@@ -170,7 +170,7 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
var/dat = ""
dat += "<a href='byond://?src=\ref[src];scan=1'>Scan for TC stations.</a><BR>"
dat += "[storedcrystals] telecrystals are available for distribution. <BR>"
dat += "[storedcrystals] telecrystals are available for distribution. <BR>"
dat += "<BR><BR>"
@@ -179,10 +179,10 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
if(A.uplinkholder)
dat += "[A.uplinkholder.hidden_uplink.telecrystals] telecrystals."
if(storedcrystals)
dat+= "<BR>Add TC: <a href ='?src=\ref[src];target=\ref[A];give=1'>1</a> | <a href ='?src=\ref[src];target=\ref[A];give=5'>5</a> | <a href ='?src=\ref[src];target=\ref[A];give=10'>10</a> | <a href ='?src=\ref[src];target=\ref[A];give=-1'>All</a>"
dat+= "<BR>Add TC: <a href ='?src=\ref[src];target=\ref[A];give=1'>1</a> | <a href ='?src=\ref[src];target=\ref[A];give=5'>5</a> | <a href ='?src=\ref[src];target=\ref[A];give=10'>10</a> | <a href ='?src=\ref[src];target=\ref[A];give=-1'>All</a>"
dat += "<BR>"
if(TCstations.len && storedcrystals)
if(TCstations.len && storedcrystals)
dat += "<BR><BR><a href='byond://?src=\ref[src];distrib=1'>Evenly distribute remaining TC.</a><BR><BR>"
@@ -203,11 +203,11 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
if(href_list["scan"])
scanUplinkers()
if(href_list["give"])
var/tcamt = text2num(href_list["give"])
if(TCstations.len) // sanity
var/obj/machinery/computer/telecrystals/uplinker/A = locate(href_list["target"]) in TCstations
A.giveTC(tcamt)
if(href_list["give"])
var/tcamt = text2num(href_list["give"])
if(TCstations.len) // sanity
var/obj/machinery/computer/telecrystals/uplinker/A = locate(href_list["target"]) in TCstations
A.giveTC(tcamt)
if(href_list["distrib"])
var/sanity = 0
+1 -1
View File
@@ -85,7 +85,7 @@
return
if(!allowed(user))
to_chat(user,"<span class='warning'>Error: Access Denied - Message: Only the engineering department can be trusted with this kind of power.</span>")
playsound_local(src,'sound/misc/compiler-failure.ogg', 25, 1)
user.playsound_local(src,'sound/misc/compiler-failure.ogg', 25, 1)
return
if(!Adjacent(user) && !isAI(user))
return
+3 -2
View File
@@ -61,7 +61,6 @@ GLOBAL_LIST_EMPTY(holopads)
/obj/machinery/holopad/Destroy()
if(outgoing_call)
LAZYADD(holo_calls, outgoing_call)
outgoing_call = null
for(var/I in holo_calls)
var/datum/holocall/HC = I
@@ -295,7 +294,9 @@ GLOBAL_LIST_EMPTY(holopads)
Hologram.add_atom_colour("#77abff", FIXED_COLOUR_PRIORITY)
Hologram.Impersonation = user
Hologram.languages = user.languages
Hologram.language_holder = user.get_language_holder()
Hologram.mouse_opacity = 0//So you can't click on it.
Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them.
Hologram.anchored = 1//So space wind cannot drag it.
+1 -1
View File
@@ -121,7 +121,7 @@
var/atom/movable/AM = i
var/obj/item/bodypart/head/as_head = AM
var/obj/item/device/mmi/as_mmi = AM
var/brain_holder = istype(AM, /obj/item/organ/brain) || (istype(as_head) && as_head.brain) || (istype(as_mmi) && as_mmi.brain) || istype(AM, /mob/living/brain)
var/brain_holder = istype(AM, /obj/item/organ/brain) || (istype(as_head) && as_head.brain) || (istype(as_mmi) && as_mmi.brain) || istype(AM, /mob/living/brain)
if(isliving(AM) || brain_holder)
if(emagged)
if(!brain_holder)
+9 -9
View File
@@ -211,13 +211,13 @@
uv = TRUE
locked = TRUE
update_icon()
if(occupant)
var/mob/living/mob_occupant = occupant
if(occupant)
var/mob/living/mob_occupant = occupant
if(uv_super)
mob_occupant.adjustFireLoss(rand(20, 36))
mob_occupant.adjustFireLoss(rand(20, 36))
else
mob_occupant.adjustFireLoss(rand(10, 16))
mob_occupant.emote("scream")
mob_occupant.adjustFireLoss(rand(10, 16))
mob_occupant.emote("scream")
addtimer(CALLBACK(src, .proc/cook), 50)
else
uv_cycles = initial(uv_cycles)
@@ -368,15 +368,15 @@
else if(!helmet && !mask && !suit && !storage && !occupant)
return
else
if(occupant)
var/mob/living/mob_occupant = occupant
to_chat(mob_occupant, "<span class='userdanger'>[src]'s confines grow warm, then hot, then scorching. You're being burned [!mob_occupant.stat ? "alive" : "away"]!</span>")
if(occupant)
var/mob/living/mob_occupant = occupant
to_chat(mob_occupant, "<span class='userdanger'>[src]'s confines grow warm, then hot, then scorching. You're being burned [!mob_occupant.stat ? "alive" : "away"]!</span>")
cook()
. = TRUE
if("dispense")
if(!state_open)
return
var/static/list/valid_items = list("helmet", "suit", "mask", "storage")
var/item_name = params["item"]
if(item_name in valid_items)
+2 -1
View File
@@ -947,7 +947,8 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
/obj/item/seeds/tea = 3,/obj/item/seeds/tobacco = 3,/obj/item/seeds/tomato = 3,
/obj/item/seeds/tower = 3,/obj/item/seeds/watermelon = 3,/obj/item/seeds/wheat = 3,/obj/item/seeds/whitebeet = 3)
contraband = list(/obj/item/seeds/amanita = 2,/obj/item/seeds/glowshroom = 2,/obj/item/seeds/liberty = 2,/obj/item/seeds/nettle = 2,
/obj/item/seeds/plump = 2,/obj/item/seeds/reishi = 2,/obj/item/seeds/cannabis = 3, /obj/item/seeds/random = 2)
/obj/item/seeds/plump = 2,/obj/item/seeds/reishi = 2,/obj/item/seeds/cannabis = 3,/obj/item/seeds/starthistle = 2,
/obj/item/seeds/random = 2)
premium = list(/obj/item/weapon/reagent_containers/spray/waterflower = 1)
armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50)
resistance_flags = FIRE_PROOF
+3 -3
View File
@@ -107,7 +107,7 @@
icon_state = "mecha_ion"
origin_tech = "materials=4;engineering=4;combat=6;magnets=6"
energy_drain = 500
projectile = /obj/item/projectile/energy/tesla/cannon
projectile = /obj/item/projectile/energy/tesla/cannon
fire_sound = 'sound/magic/lightningbolt.ogg'
@@ -337,8 +337,8 @@
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/proj_init(var/obj/item/weapon/grenade/flashbang/F)
var/turf/T = get_turf(src)
message_admins("[ADMIN_LOOKUPFLW(chassis.occupant)] fired a [src] in [ADMIN_COORDJMP(T)]",0,1)
log_game("[key_name(chassis.occupant)] fired a [src] [COORD(T)]")
message_admins("[ADMIN_LOOKUPFLW(chassis.occupant)] fired a [src] in [ADMIN_COORDJMP(T)]",0,1)
log_game("[key_name(chassis.occupant)] fired a [src] [COORD(T)]")
addtimer(CALLBACK(F, /obj/item/weapon/grenade/flashbang.proc/prime), det_time)
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/clusterbang //Because I am a heartless bastard -Sieve //Heartless? for making the poor man's honkblast? - Kaze
+1 -1
View File
@@ -94,7 +94,7 @@
name = "Head of Personnel"
/obj/effect/landmark/start/librarian
name = "Curator"
name = "Curator"
/obj/effect/landmark/start/lawyer
name = "Lawyer"
+9 -1
View File
@@ -230,7 +230,15 @@
name = "blood sparks"
icon_state = "bloodsparkles"
/obj/effect/overlay/temp/dir_setting/cult/phase
/obj/effect/overlay/temp/cult/blood // The traditional teleport
name = "blood jaunt"
duration = 12
icon_state = "bloodin"
/obj/effect/overlay/temp/cult/blood/out
icon_state = "bloodout"
/obj/effect/overlay/temp/dir_setting/cult/phase // The veil shifter teleport
name = "phase glow"
duration = 7
icon_state = "cultin"
+1 -1
View File
@@ -63,7 +63,7 @@
return
if (istype(M, /atom/movable))
if(ismegafauna(M))
message_admins("[M] [ADMIN_FLW(M)] has teleported through [src].")
message_admins("[M] [ADMIN_FLW(M)] has teleported through [src].")
do_teleport(M, target, precision) ///You will appear adjacent to the beacon
+3 -2
View File
@@ -183,8 +183,9 @@
if(!T)
return
if(triggerer_only)
A.playsound_local(T, sound, volume, freq_vary)
if(triggerer_only && ismob(A))
var/mob/B = A
B.playsound_local(T, sound, volume, freq_vary)
else
playsound(T, sound, volume, freq_vary, extra_range)
+27 -3
View File
@@ -7,6 +7,7 @@
desc = "An official document entrusting the governance of the station \
and surrounding space to the Captain. "
var/used = FALSE
var/name_type = "station"
var/unlimited_uses = FALSE
var/ignores_timeout = FALSE
@@ -33,10 +34,10 @@
/obj/item/station_charter/attack_self(mob/living/user)
if(used)
to_chat(user, "This charter has already been used to name the station.")
to_chat(user, "The [name_type] has already been named.")
return
if(!ignores_timeout && (world.time-SSticker.round_start_time > STATION_RENAME_TIME_LIMIT)) //5 minutes
to_chat(user, "The crew has already settled into the shift. It probably wouldn't be good to rename the station right now.")
to_chat(user, "The crew has already settled into the shift. It probably wouldn't be good to rename the [name_type] right now.")
return
if(response_timer_id)
to_chat(user, "You're still waiting for approval from your employers about your proposed name change, it'd be best to wait for now.")
@@ -60,7 +61,7 @@
to_chat(user, "Your name has been sent to your employers for approval.")
// Autoapproves after a certain time
response_timer_id = addtimer(CALLBACK(src, .proc/rename_station, new_name, user.name, user.real_name, key_name(user)), approval_time, TIMER_STOPPABLE)
to_chat(GLOB.admins, "<span class='adminnotice'><b><font color=orange>CUSTOM STATION RENAME:</font></b>[ADMIN_LOOKUPFLW(user)] proposes to rename the station to [new_name] (will autoapprove in [approval_time / 10] seconds). [ADMIN_SMITE(user)] (<A HREF='?_src_=holder;reject_custom_name=\ref[src]'>REJECT</A>) [ADMIN_CENTCOM_REPLY(user)]</span>")
to_chat(GLOB.admins, "<span class='adminnotice'><b><font color=orange>CUSTOM STATION RENAME:</font></b>[ADMIN_LOOKUPFLW(user)] proposes to rename the [name_type] to [new_name] (will autoapprove in [approval_time / 10] seconds). [ADMIN_SMITE(user)] (<A HREF='?_src_=holder;reject_custom_name=\ref[src]'>REJECT</A>) [ADMIN_CENTCOM_REPLY(user)]</span>")
/obj/item/station_charter/proc/reject_proposed(user)
if(!user)
@@ -94,4 +95,27 @@
unlimited_uses = TRUE
ignores_timeout = TRUE
/obj/item/weapon/station_charter/flag
name = "nanotrasen banner"
icon = 'icons/obj/items.dmi'
var/name_type = "planet"
icon_state = "banner"
item_state = "banner"
desc = "A cunning device used to claim ownership of planets."
w_class = 5
force = 15
/obj/item/station_charter/flag/rename_station(designation, uname, ureal_name, ukey)
set_station_name(designation)
minor_announce("[ureal_name] has designated the planet as [station_name()]", "Captain's Banner", 0)
log_game("[ukey] has renamed the planet as [station_name()].")
name = "banner of [station_name()]"
desc = "The banner bears the official coat of arms of Nanotrasen, signifying that [station_name()] has been claimed by Captain [uname] in the name of the company."
SSblackbox.set_details("station_renames","[station_name()]")
if(!unlimited_uses)
used = TRUE
#undef STATION_RENAME_TIME_LIMIT
+1 -1
View File
@@ -108,7 +108,7 @@
access_mime = 1
var/mime_charges = 5
/obj/item/weapon/cartridge/curator
/obj/item/weapon/cartridge/curator
name = "\improper Lib-Tweet cartridge"
icon_state = "cart-s"
access_newscaster = 1
+80 -80
View File
@@ -12,9 +12,9 @@ GLOBAL_LIST_EMPTY(GPS_list)
var/emped = FALSE
var/turf/locked_location
var/tracking = TRUE
var/updating = TRUE //Automatic updating of GPS list. Can be set to manual by user.
var/global_mode = TRUE //If disabled, only GPS signals of the same Z level are shown
var/updating = TRUE //Automatic updating of GPS list. Can be set to manual by user.
var/global_mode = TRUE //If disabled, only GPS signals of the same Z level are shown
/obj/item/device/gps/Initialize()
..()
@@ -31,7 +31,7 @@ GLOBAL_LIST_EMPTY(GPS_list)
cut_overlay("working")
add_overlay("emp")
addtimer(CALLBACK(src, .proc/reboot), 300, TIMER_OVERRIDE) //if a new EMP happens, remove the old timer so it doesn't reactivate early
SStgui.close_uis(src) //Close the UI control if it is open.
SStgui.close_uis(src) //Close the UI control if it is open.
/obj/item/device/gps/proc/reboot()
emped = FALSE
@@ -39,9 +39,9 @@ GLOBAL_LIST_EMPTY(GPS_list)
add_overlay("working")
/obj/item/device/gps/AltClick(mob/user)
toggletracking(user)
/obj/item/device/gps/proc/toggletracking(mob/user)
toggletracking(user)
/obj/item/device/gps/proc/toggletracking(mob/user)
if(!user.canUseTopic(src, be_close=TRUE))
return //user not valid to use gps
if(emped)
@@ -57,80 +57,80 @@ GLOBAL_LIST_EMPTY(GPS_list)
tracking = TRUE
/obj/item/device/gps/ui_interact(mob/user, ui_key = "gps", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state.
/obj/item/device/gps/ui_interact(mob/user, ui_key = "gps", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state.
if(emped)
to_chat(user, "[src] fizzles weakly.")
return
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
var/gps_window_height = 300 + GLOB.GPS_list.len * 20 // Variable window height, depending on how many GPS units there are to show
ui = new(user, src, ui_key, "gps", "Global Positioning System", 600, gps_window_height, master_ui, state) //width, height
ui.open()
ui.set_autoupdate(state = updating)
/obj/item/device/gps/ui_data(mob/user)
var/list/data = list()
data["power"] = tracking
data["tag"] = gpstag
data["updating"] = updating
data["globalmode"] = global_mode
if(!tracking || emped) //Do not bother scanning if the GPS is off or EMPed
return data
var/turf/curr = get_turf(src)
data["current"] = "[get_area_name(curr)] ([curr.x], [curr.y], [curr.z])"
var/list/signals = list()
data["signals"] = list()
for(var/gps in GLOB.GPS_list)
var/obj/item/device/gps/G = gps
if(G.emped || !G.tracking || G == src)
continue
var/turf/pos = get_turf(G)
if(!global_mode && pos.z != curr.z)
continue
var/area/gps_area = get_area_name(G)
var/list/signal = list()
signal["entrytag"] = G.gpstag //Name or 'tag' of the GPS
signal["area"] = format_text(gps_area)
signal["coord"] = "[pos.x], [pos.y], [pos.z]"
if(pos.z == curr.z) //Distance/Direction calculations for same z-level only
signal["dist"] = max(get_dist(curr, pos), 0) //Distance between the src and remote GPS turfs
signal["degrees"] = round(Get_Angle(curr, pos)) //0-360 degree directional bearing, for more precision.
var/direction = uppertext(dir2text(get_dir(curr, pos))) //Direction text (East, etc). Not as precise, but still helpful.
if(!direction)
direction = "CENTER"
signal["degrees"] = "N/A"
signal["direction"] = direction
signals += list(signal) //Add this signal to the list of signals
data["signals"] = signals
return data
/obj/item/device/gps/ui_act(action, params)
if(..())
return
switch(action)
if("rename")
var/a = input("Please enter desired tag.", name, gpstag) as text
a = uppertext(copytext(sanitize(a), 1, 5))
gpstag = a
name = "global positioning system ([gpstag])"
. = TRUE
if("power")
toggletracking(usr)
. = TRUE
if("updating")
updating = !updating
. = TRUE
if("globalmode")
global_mode = !global_mode
. = TRUE
to_chat(user, "[src] fizzles weakly.")
return
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
var/gps_window_height = 300 + GLOB.GPS_list.len * 20 // Variable window height, depending on how many GPS units there are to show
ui = new(user, src, ui_key, "gps", "Global Positioning System", 600, gps_window_height, master_ui, state) //width, height
ui.open()
ui.set_autoupdate(state = updating)
/obj/item/device/gps/ui_data(mob/user)
var/list/data = list()
data["power"] = tracking
data["tag"] = gpstag
data["updating"] = updating
data["globalmode"] = global_mode
if(!tracking || emped) //Do not bother scanning if the GPS is off or EMPed
return data
var/turf/curr = get_turf(src)
data["current"] = "[get_area_name(curr)] ([curr.x], [curr.y], [curr.z])"
var/list/signals = list()
data["signals"] = list()
for(var/gps in GLOB.GPS_list)
var/obj/item/device/gps/G = gps
if(G.emped || !G.tracking || G == src)
continue
var/turf/pos = get_turf(G)
if(!global_mode && pos.z != curr.z)
continue
var/area/gps_area = get_area_name(G)
var/list/signal = list()
signal["entrytag"] = G.gpstag //Name or 'tag' of the GPS
signal["area"] = format_text(gps_area)
signal["coord"] = "[pos.x], [pos.y], [pos.z]"
if(pos.z == curr.z) //Distance/Direction calculations for same z-level only
signal["dist"] = max(get_dist(curr, pos), 0) //Distance between the src and remote GPS turfs
signal["degrees"] = round(Get_Angle(curr, pos)) //0-360 degree directional bearing, for more precision.
var/direction = uppertext(dir2text(get_dir(curr, pos))) //Direction text (East, etc). Not as precise, but still helpful.
if(!direction)
direction = "CENTER"
signal["degrees"] = "N/A"
signal["direction"] = direction
signals += list(signal) //Add this signal to the list of signals
data["signals"] = signals
return data
/obj/item/device/gps/ui_act(action, params)
if(..())
return
switch(action)
if("rename")
var/a = input("Please enter desired tag.", name, gpstag) as text
a = uppertext(copytext(sanitize(a), 1, 5))
gpstag = a
name = "global positioning system ([gpstag])"
. = TRUE
if("power")
toggletracking(usr)
. = TRUE
if("updating")
updating = !updating
. = TRUE
if("globalmode")
global_mode = !global_mode
. = TRUE
/obj/item/device/gps/Topic(href, href_list)
..()
+2 -2
View File
@@ -95,8 +95,8 @@
"[user] activates \the [src]!", \
"<span class='notice'>You activate \the [src].</span>",
"<span class='italics'>You hear a click.</span>")
message_admins("Power sink activated by [ADMIN_LOOKUPFLW(user)] at [ADMIN_COORDJMP(src)]")
log_game("Power sink activated by [key_name(user)] at [COORD(src)]")
message_admins("Power sink activated by [ADMIN_LOOKUPFLW(user)] at [ADMIN_COORDJMP(src)]")
log_game("Power sink activated by [key_name(user)] at [COORD(src)]")
set_mode(OPERATING)
if(OPERATING)
@@ -296,7 +296,6 @@
// --- Cold, emotionless machines. ---
else if(isobj(M))
jobname = "Machine"
voice = capitalize(voice)
// --- Unidentifiable mob ---
else
@@ -178,21 +178,21 @@
var/log_attacher = ""
if(attacher)
log_attacher = "[ADMIN_QUE(attacher)] [ADMIN_FLW(attacher)]"
log_attacher = "[ADMIN_QUE(attacher)] [ADMIN_FLW(attacher)]"
var/mob/mob = get_mob_by_key(src.fingerprintslast)
var/last_touch_info = ""
if(mob)
last_touch_info = "[ADMIN_QUE(mob)] [ADMIN_FLW(mob)]"
last_touch_info = "[ADMIN_QUE(mob)] [ADMIN_FLW(mob)]"
var/log_str3 = " Last touched by: [key_name_admin(mob)]"
var/bomb_message = "[log_str1] [A.name][ADMIN_JMP(bombturf)] [log_str2][log_attacher] [log_str3][last_touch_info]"
var/bomb_message = "[log_str1] [A.name][ADMIN_JMP(bombturf)] [log_str2][log_attacher] [log_str3][last_touch_info]"
GLOB.bombers += bomb_message
message_admins(bomb_message, 0, 1)
log_game("[log_str1] [A.name][COORD(bombturf)] [log_str2] [log_str3]")
log_game("[log_str1] [A.name][COORD(bombturf)] [log_str2] [log_str3]")
merge_gases()
spawn(20) // In case one tank bursts
for (var/i=0,i<5,i++)
@@ -237,7 +237,7 @@
/obj/item/borg/upgrade/selfrepair/proc/check_dropped()
if(loc != cyborg)
toggle_action.Remove(cyborg)
QDEL_NULL(toggle_action)
QDEL_NULL(toggle_action)
cyborg = null
deactivate()
@@ -400,4 +400,4 @@
return
R.make_shell(src)
return TRUE
return TRUE
@@ -118,6 +118,9 @@ GLOBAL_LIST_INIT(xeno_recipes, list ( \
var/wetness = 30 //Reduced when exposed to high temperautres
var/drying_threshold_temperature = 500 //Kelvin to start drying
/*
* Leather SHeet
*/
/obj/item/stack/sheet/leather
name = "leather"
desc = "The by-product of mob grinding."
@@ -125,6 +128,24 @@ GLOBAL_LIST_INIT(xeno_recipes, list ( \
icon_state = "sheet-leather"
origin_tech = "materials=2"
GLOBAL_LIST_INIT(leather_recipes, list ( \
new/datum/stack_recipe("wallet", /obj/item/weapon/storage/wallet, 1), \
new/datum/stack_recipe("muzzle", /obj/item/clothing/mask/muzzle, 2), \
new/datum/stack_recipe("botany gloves", /obj/item/clothing/gloves/botanic_leather, 3), \
new/datum/stack_recipe("toolbelt", /obj/item/weapon/storage/belt/utility, 4), \
new/datum/stack_recipe("leather satchel", /obj/item/weapon/storage/backpack/satchel, 5), \
new/datum/stack_recipe("bandolier", /obj/item/weapon/storage/belt/bandolier, 5), \
new/datum/stack_recipe("leather jacket", /obj/item/clothing/suit/jacket/leather, 7), \
new/datum/stack_recipe("leather overcoat", /obj/item/clothing/suit/jacket/leather/overcoat, 10), \
))
/obj/item/stack/sheet/leather/Initialize(mapload, new_amount, merge = TRUE)
recipes = GLOB.leather_recipes
return ..()
/*
* Sinew
*/
/obj/item/stack/sheet/sinew
name = "watcher sinew"
icon = 'icons/obj/mining.dmi'
@@ -136,11 +157,12 @@ GLOBAL_LIST_INIT(xeno_recipes, list ( \
GLOBAL_LIST_INIT(sinew_recipes, list ( \
new/datum/stack_recipe("sinew restraints", /obj/item/weapon/restraints/handcuffs/sinew, 1, on_floor = 1), \
))
))
/obj/item/stack/sheet/sinew/Initialize(mapload, new_amount, merge = TRUE)
recipes = GLOB.sinew_recipes
return ..()
/*
* Plates
*/
@@ -207,4 +229,4 @@ GLOBAL_LIST_INIT(sinew_recipes, list ( \
var/obj/item/stack/sheet/leather/HS = new(src.loc)
HS.amount = 1
wetness = initial(wetness)
src.use(1)
src.use(1)
@@ -286,13 +286,16 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list ( \
return
..()
/obj/item/stack/sheet/runed_metal/fifty
amount = 50
/obj/item/stack/sheet/runed_metal/Initialize(mapload, new_amount, merge = TRUE)
recipes = GLOB.runed_metal_recipes
return ..()
/obj/item/stack/sheet/runed_metal/fifty
amount = 50
/obj/item/stack/sheet/runed_metal/five
amount = 5
/*
* Brass
*/
+46
View File
@@ -0,0 +1,46 @@
/obj/item/weapon/pie_cannon
name = "pie cannon"
desc = "Load cream pie for optimal results"
force = 10
icon_state = "piecannon"
item_state = "powerfist"
var/obj/item/weapon/reagent_containers/food/snacks/pie/loaded = null
/obj/item/weapon/pie_cannon/attackby(obj/item/I, mob/living/L)
if(istype(I, /obj/item/weapon/reagent_containers/food/snacks/pie))
if(!loaded)
L.transferItemToLoc(I, src)
loaded = I
to_chat(L, "<span class='notice'>You load the [I] into the [src]!</span>")
return
return ..()
/obj/item/weapon/pie_cannon/afterattack(atom/target, mob/living/user, flag, params)
if(!loaded)
return ..()
var/obj/item/projectile/pie/launched = new /obj/item/projectile/pie(src)
launched.P = loaded
loaded.forceMove(launched)
launched.appearance = loaded.appearance
loaded = null
launched.preparePixelProjectile(target, get_turf(target), user, params, 0)
launched.forceMove(get_turf(src))
launched.fire()
user.visible_message("<span class='danger'>[user] fires the [src] at [target]!</span>")
/obj/item/projectile/pie
name = "pie"
desc = "Think fast!"
var/obj/item/weapon/reagent_containers/food/snacks/pie/P = null
/obj/item/projectile/pie/on_hit(atom/A)
. = ..()
if(P)
A.visible_message("<span class='danger'>[P] smashes into [A] at high velocity!</span>")
P.forceMove(get_turf(A))
P.throw_impact(A)
if(ismovableatom(A))
var/atom/movable/AM = A
if(!AM.anchored)
AM.throw_at(get_edge_target_turf(get_dir(src, AM), 3, 2))
@@ -1,115 +0,0 @@
//In this file: C4
/obj/item/weapon/c4
name = "C-4"
desc = "Used to put holes in specific areas without too much extra hole."
gender = PLURAL
icon = 'icons/obj/grenade.dmi'
icon_state = "plastic-explosive0"
item_state = "plasticx"
flags = NOBLUDGEON
w_class = WEIGHT_CLASS_SMALL
origin_tech = "syndicate=1"
var/timer = 10
var/open_panel = 0
parent_type = /obj/item/weapon/grenade/plastic/c4
/obj/item/weapon/c4/New()
wires = new /datum/wires/explosive/c4(src)
plastic_overlay = mutable_appearance(icon, "plastic-explosive2")
..()
/obj/item/weapon/c4/Destroy()
qdel(wires)
wires = null
target = null
return ..()
/obj/item/weapon/c4/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] activates the [src.name] and holds it above [user.p_their()] head! It looks like [user.p_theyre()] going out with a bang!</span>")
var/message_say = "FOR NO RAISIN!"
if(user.mind)
if(user.mind.special_role)
var/role = lowertext(user.mind.special_role)
if(role == "traitor" || role == "syndicate")
message_say = "FOR THE SYNDICATE!"
else if(role == "changeling")
message_say = "FOR THE HIVE!"
else if(role == "cultist")
message_say = "FOR NAR-SIE!"
else if(role == "revolutionary" || role == "head revolutionary")
message_say = "VIVA LA REVOLUTION!"
else if(user.mind.gang_datum)
message_say = "[uppertext(user.mind.gang_datum.name)] RULES!"
user.say(message_say)
target = user
message_admins("[ADMIN_LOOKUPFLW(user)] suicided with [name] at [ADMIN_COORDJMP(src)]",0,1)
message_admins("[key_name(user)] suicided with [name] at ([x],[y],[z])")
sleep(10)
explode(get_turf(user))
user.gib(1, 1)
/obj/item/weapon/c4/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/weapon/screwdriver))
open_panel = !open_panel
to_chat(user, "<span class='notice'>You [open_panel ? "open" : "close"] the wire panel.</span>")
else if(is_wire_tool(I))
wires.interact(user)
else
return ..()
/obj/item/weapon/c4/attack_self(mob/user)
var/newtime = input(usr, "Please set the timer.", "Timer", 10) as num
if(user.get_active_held_item() == src)
newtime = Clamp(newtime, 10, 60000)
timer = newtime
to_chat(user, "Timer set for [timer] seconds.")
/obj/item/weapon/c4/afterattack(atom/movable/AM, mob/user, flag)
if (!flag)
return
if (ismob(AM))
return
if(loc == AM)
return
if((istype(AM, /obj/item/weapon/storage/)) && !((istype(AM, /obj/item/weapon/storage/secure)) || (istype(AM, /obj/item/weapon/storage/lockbox)))) //If its storage but not secure storage OR a lockbox, then place it inside.
return
if((istype(AM,/obj/item/weapon/storage/secure)) || (istype(AM, /obj/item/weapon/storage/lockbox)))
var/obj/item/weapon/storage/secure/S = AM
if(!S.locked) //Literal hacks, this works for lockboxes despite incorrect type casting, because they both share the locked var. But if its unlocked, place it inside, otherwise PLANTING C4!
return
to_chat(user, "<span class='notice'>You start planting the bomb...</span>")
if(do_after(user, 50, target = AM))
if(!user.temporarilyRemoveItemFromInventory(src))
return
src.target = AM
forceMove(null)
var/message = "[ADMIN_LOOKUPFLW(user)] planted [name] on [target.name] at [ADMIN_COORDJMP(target)] with [timer] second fuse"
GLOB.bombers += message
message_admins(message,0,1)
log_game("[key_name(user)] planted [name] on [target.name] at [COORD(target)] with [timer] second fuse")
target.add_overlay(plastic_overlay, 1)
to_chat(user, "<span class='notice'>You plant the bomb. Timer counting down from [timer].</span>")
addtimer(CALLBACK(src, .proc/explode), timer * 10)
/obj/item/weapon/c4/proc/explode()
if(QDELETED(src))
return
var/turf/location
if(target)
if(!QDELETED(target))
location = get_turf(target)
target.cut_overlay(plastic_overlay, TRUE)
else
location = get_turf(src)
if(location)
location.ex_act(2, target)
explosion(location,0,0,3)
qdel(src)
/obj/item/weapon/c4/attack(mob/M, mob/user, def_zone)
return
@@ -154,6 +154,115 @@
/obj/item/weapon/grenade/plastic/c4
name = "C4"
desc = "Used to put holes in specific areas without too much extra hole. A saboteur's favorite."
gender = PLURAL
icon = 'icons/obj/grenade.dmi'
icon_state = "plastic-explosive0"
item_state = "plasticx"
flags = NOBLUDGEON
w_class = WEIGHT_CLASS_SMALL
origin_tech = "syndicate=1"
var/timer = 10
var/open_panel = 0
/obj/item/weapon/grenade/plastic/c4/New()
wires = new /datum/wires/explosive/c4(src)
plastic_overlay = mutable_appearance(icon, "plastic-explosive2")
..()
/obj/item/weapon/grenade/plastic/c4/Destroy()
qdel(wires)
wires = null
target = null
return ..()
/obj/item/weapon/grenade/plastic/c4/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] activates the [src.name] and holds it above [user.p_their()] head! It looks like [user.p_theyre()] going out with a bang!</span>")
var/message_say = "FOR NO RAISIN!"
if(user.mind)
if(user.mind.special_role)
var/role = lowertext(user.mind.special_role)
if(role == "traitor" || role == "syndicate")
message_say = "FOR THE SYNDICATE!"
else if(role == "changeling")
message_say = "FOR THE HIVE!"
else if(role == "cultist")
message_say = "FOR NAR-SIE!"
else if(role == "revolutionary" || role == "head revolutionary")
message_say = "VIVA LA REVOLUTION!"
else if(user.mind.gang_datum)
message_say = "[uppertext(user.mind.gang_datum.name)] RULES!"
user.say(message_say)
target = user
message_admins("[ADMIN_LOOKUPFLW(user)] suicided with [name] at [ADMIN_COORDJMP(src)]",0,1)
message_admins("[key_name(user)] suicided with [name] at ([x],[y],[z])")
sleep(10)
explode(get_turf(user))
user.gib(1, 1)
/obj/item/weapon/grenade/plastic/c4/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/weapon/screwdriver))
open_panel = !open_panel
to_chat(user, "<span class='notice'>You [open_panel ? "open" : "close"] the wire panel.</span>")
else if(is_wire_tool(I))
wires.interact(user)
else
return ..()
/obj/item/weapon/grenade/plastic/c4/attack_self(mob/user)
var/newtime = input(usr, "Please set the timer.", "Timer", 10) as num
if(user.get_active_held_item() == src)
newtime = Clamp(newtime, 10, 60000)
timer = newtime
to_chat(user, "Timer set for [timer] seconds.")
/obj/item/weapon/grenade/plastic/c4/afterattack(atom/movable/AM, mob/user, flag)
if (!flag)
return
if (ismob(AM))
return
if(loc == AM)
return
if((istype(AM, /obj/item/weapon/storage/)) && !((istype(AM, /obj/item/weapon/storage/secure)) || (istype(AM, /obj/item/weapon/storage/lockbox)))) //If its storage but not secure storage OR a lockbox, then place it inside.
return
if((istype(AM,/obj/item/weapon/storage/secure)) || (istype(AM, /obj/item/weapon/storage/lockbox)))
var/obj/item/weapon/storage/secure/S = AM
if(!S.locked) //Literal hacks, this works for lockboxes despite incorrect type casting, because they both share the locked var. But if its unlocked, place it inside, otherwise PLANTING C4!
return
to_chat(user, "<span class='notice'>You start planting the bomb...</span>")
if(do_after(user, 50, target = AM))
if(!user.temporarilyRemoveItemFromInventory(src))
return
src.target = AM
forceMove(null)
var/message = "[ADMIN_LOOKUPFLW(user)] planted [name] on [target.name] at [ADMIN_COORDJMP(target)] with [timer] second fuse"
GLOB.bombers += message
message_admins(message,0,1)
log_game("[key_name(user)] planted [name] on [target.name] at [COORD(target)] with [timer] second fuse")
target.add_overlay(plastic_overlay, 1)
to_chat(user, "<span class='notice'>You plant the bomb. Timer counting down from [timer].</span>")
addtimer(CALLBACK(src, .proc/explode), timer * 10)
/obj/item/weapon/grenade/plastic/c4/proc/explode()
if(QDELETED(src))
return
var/turf/location
if(target)
if(!QDELETED(target))
location = get_turf(target)
target.cut_overlay(plastic_overlay, TRUE)
else
location = get_turf(src)
if(location)
location.ex_act(2, target)
explosion(location,0,0,3)
qdel(src)
/obj/item/weapon/grenade/plastic/c4/attack(mob/M, mob/user, def_zone)
return
// X4 is an upgraded directional variant of c4 which is relatively safe to be standing next to. And much less safe to be standing on the other side of.
// C4 is intended to be used for infiltration, and destroying tech. X4 is intended to be used for heavy breaching and tight spaces.
@@ -1,5 +1,5 @@
/obj/item/weapon/grenade/spawnergrenade
desc = "It will unleash an unspecified anomaly into the vicinity."
desc = "It will unleash an unspecified anomaly into the vicinity."
name = "delivery grenade"
icon = 'icons/obj/grenade.dmi'
icon_state = "delivery"
@@ -214,7 +214,7 @@
possessed = TRUE
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as the spirit of [user.real_name]'s blade?", ROLE_PAI, null, FALSE, 100, POLL_IGNORE_POSSESSED_BLADE)
var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the spirit of [user.real_name]'s blade?", ROLE_PAI, null, FALSE, 100, POLL_IGNORE_POSSESSED_BLADE)
var/mob/dead/observer/theghost = null
if(LAZYLEN(candidates))
@@ -41,10 +41,10 @@
data["open"] = state_open
data["occupant"] = list()
if(occupant)
var/mob/living/mob_occupant = occupant
data["occupant"]["name"] = mob_occupant.name
data["occupant"]["stat"] = mob_occupant.stat
if(occupant)
var/mob/living/mob_occupant = occupant
data["occupant"]["name"] = mob_occupant.name
data["occupant"]["stat"] = mob_occupant.stat
data["special_name"] = special ? special_name : null
data["ready_implants"] = ready_implants
@@ -16,7 +16,7 @@
var/brightness_on = 3
/obj/item/weapon/melee/energy/Initialize()
. = ..()
. = ..()
if(LAZYLEN(possible_colors))
item_color = pick(possible_colors)
switch(item_color)//Only run this check if the color was picked randomly, so that colors can be manually set for non-random colored energy weapons.
@@ -183,8 +183,8 @@
light_color = "#40ceff"
possible_colors = null
/obj/item/weapon/melee/energy/sword/cyborg/saw/Initialize()
. = ..()
/obj/item/weapon/melee/energy/sword/cyborg/saw/Initialize()
. = ..()
icon_state = "esaw_0"
item_color = null
@@ -207,9 +207,9 @@
/obj/item/weapon/melee/energy/sword/saber/attackby(obj/item/weapon/W, mob/living/user, params)
if(istype(W, /obj/item/device/multitool))
if(!hacked)
hacked = TRUE
if(istype(W, /obj/item/device/multitool))
if(!hacked)
hacked = TRUE
item_color = "rainbow"
to_chat(user, "<span class='warning'>RNBW_ENGAGE</span>")
@@ -243,8 +243,8 @@
sharpness = IS_SHARP
//Most of the other special functions are handled in their own files. aka special snowflake code so kewl
/obj/item/weapon/melee/energy/blade/Initialize()
. = ..()
/obj/item/weapon/melee/energy/blade/Initialize()
. = ..()
spark_system = new /datum/effect_system/spark_spread()
spark_system.set_up(5, 0, src)
spark_system.attach(src)
@@ -1,3 +1,7 @@
#define PCANNON_FIREALL 1
#define PCANNON_FILO 2
#define PCANNON_FIFO 3
/obj/item/weapon/pneumatic_cannon
name = "pneumatic cannon"
desc = "A gas-powered cannon that can fire any object loaded into it."
@@ -16,7 +20,15 @@
var/gasPerThrow = 3 //How much gas is drawn from a tank's pressure to fire
var/list/loadedItems = list() //The items loaded into the cannon that will be fired out
var/pressureSetting = 1 //How powerful the cannon is - higher pressure = more gas but more powerful throws
var/checktank = TRUE
var/range_multiplier = 1
var/throw_amount = 20 //How many items to throw per fire
var/fire_mode = PCANNON_FIREALL
var/automatic = FALSE
var/clumsyCheck = TRUE
/obj/item/weapon/pneumatic_cannon/CanItemAutoclick()
return automatic
/obj/item/weapon/pneumatic_cannon/examine(mob/user)
..()
@@ -30,6 +42,8 @@
/obj/item/weapon/pneumatic_cannon/attackby(obj/item/weapon/W, mob/user, params)
if(user.a_intent == INTENT_HARM)
return ..()
if(istype(W, /obj/item/weapon/tank/internals))
if(!tank)
var/obj/item/weapon/tank/internals/IT = W
@@ -55,19 +69,31 @@
to_chat(user, "<span class='warning'>\The [src] can't hold any more items!</span>")
else if(istype(W, /obj/item))
var/obj/item/IW = W
if((loadedWeightClass + IW.w_class) > maxWeightClass)
to_chat(user, "<span class='warning'>\The [IW] won't fit into \the [src]!</span>")
return
if(IW.w_class > src.w_class)
to_chat(user, "<span class='warning'>\The [IW] is too large to fit into \the [src]!</span>")
return
if(!user.transferItemToLoc(W, src))
return
to_chat(user, "<span class='notice'>You load \the [IW] into \the [src].</span>")
loadedItems.Add(IW)
loadedWeightClass += IW.w_class
load_item(IW, user)
/obj/item/weapon/pneumatic_cannon/proc/can_load_item(obj/item/I, mob/user)
if((loadedWeightClass + I.w_class) > maxWeightClass) //Only make messages if there's a user
if(user)
to_chat(user, "<span class='warning'>\The [I] won't fit into \the [src]!</span>")
return FALSE
if(I.w_class > w_class)
if(user)
to_chat(user, "<span class='warning'>\The [I] is too large to fit into \the [src]!</span>")
return FALSE
return TRUE
/obj/item/weapon/pneumatic_cannon/proc/load_item(obj/item/I, mob/user)
if(!can_load_item(I, user))
return FALSE
if(user) //Only use transfer proc if there's a user, otherwise just set loc.
if(!user.transferItemToLoc(I, src))
return FALSE
to_chat(user, "<span class='notice'>You load \the [I] into \the [src].</span>")
else
I.forceMove(src)
loadedItems += I
loadedWeightClass += I.w_class
return TRUE
/obj/item/weapon/pneumatic_cannon/afterattack(atom/target, mob/living/carbon/human/user, flag, params)
if(flag && user.a_intent == INTENT_HARM) //melee attack
@@ -76,7 +102,6 @@
return
Fire(user, target)
/obj/item/weapon/pneumatic_cannon/proc/Fire(mob/living/carbon/human/user, var/atom/target)
if(!istype(user) && !target)
return
@@ -90,13 +115,13 @@
if(!loadedItems || !loadedWeightClass)
to_chat(user, "<span class='warning'>\The [src] has nothing loaded.</span>")
return
if(!tank)
if(!tank && checktank)
to_chat(user, "<span class='warning'>\The [src] can't fire without a source of gas.</span>")
return
if(tank && !tank.air_contents.remove(gasPerThrow * pressureSetting))
to_chat(user, "<span class='warning'>\The [src] lets out a weak hiss and doesn't react!</span>")
return
if(user.disabilities & CLUMSY && prob(75))
if(user.disabilities & CLUMSY && prob(75) && clumsyCheck)
user.visible_message("<span class='warning'>[user] loses their grip on [src], causing it to go off!</span>", "<span class='userdanger'>[src] slips out of your hands and goes off!</span>")
user.drop_item()
if(prob(10))
@@ -109,17 +134,48 @@
user.visible_message("<span class='danger'>[user] fires \the [src]!</span>", \
"<span class='danger'>You fire \the [src]!</span>")
add_logs(user, target, "fired at", src)
var/turf/T = get_target(target, get_turf(src))
playsound(src.loc, 'sound/weapons/sonic_jackhammer.ogg', 50, 1)
for(var/obj/item/ITD in loadedItems) //Item To Discharge
loadedItems.Remove(ITD)
loadedWeightClass -= ITD.w_class
ITD.throw_speed = pressureSetting * 2
ITD.loc = get_turf(src)
ITD.throw_at(target, pressureSetting * 5, pressureSetting * 2,user)
fire_items(T, user)
if(pressureSetting >= 3 && user)
user.visible_message("<span class='warning'>[user] is thrown down by the force of the cannon!</span>", "<span class='userdanger'>[src] slams into your shoulder, knocking you down!")
user.Weaken(3)
/obj/item/weapon/pneumatic_cannon/proc/fire_items(turf/target, mob/user)
if(fire_mode == PCANNON_FIREALL)
for(var/obj/item/ITD in loadedItems) //Item To Discharge
if(!throw_item(target, ITD, user))
break
else
for(var/i in 1 to throw_amount)
if(!loadedItems.len)
break
var/obj/item/I
if(fire_mode == PCANNON_FILO)
I = loadedItems[loadedItems.len]
else
I = loadedItems[1]
if(!throw_item(target, I, user))
break
/obj/item/weapon/pneumatic_cannon/proc/throw_item(turf/target, obj/item/I, mob/user)
if(!istype(I))
return FALSE
loadedItems -= I
loadedWeightClass -= I.w_class
I.forceMove(get_turf(src))
I.throw_at(target, pressureSetting * 10 * range_multiplier, pressureSetting * 2, user)
return TRUE
/obj/item/weapon/pneumatic_cannon/proc/get_target(turf/target, turf/starting)
if(range_multiplier == 1)
return target
var/x_o = (target.x - starting.x)
var/y_o = (target.y - starting.y)
var/new_x = Clamp((starting.x + (x_o * range_multiplier)), 0, world.maxx)
var/new_y = Clamp((starting.y + (y_o * range_multiplier)), 0, world.maxy)
var/turf/newtarget = locate(new_x, new_y, starting.z)
return newtarget
/obj/item/weapon/pneumatic_cannon/ghetto //Obtainable by improvised methods; more gas per use, less capacity, but smaller
name = "improvised pneumatic cannon"
@@ -164,3 +220,35 @@
return
add_overlay(tank.icon_state)
src.update_icon()
/obj/item/weapon/pneumatic_cannon/proc/fill_with_type(type, amount)
if(!ispath(type, /obj/item))
return FALSE
var/loaded = 0
for(var/i in 1 to amount)
var/obj/item/I = new type
if(!load_item(I, null))
qdel(I)
return loaded
loaded++
CHECK_TICK
return loaded
/obj/item/weapon/pneumatic_cannon/pie
name = "pie cannon"
desc = "Load cream pie for optimal results"
force = 10
icon_state = "piecannon"
gasPerThrow = 0
checktank = FALSE
range_multiplier = 3
fire_mode = PCANNON_FIFO
throw_amount = 1
maxWeightClass = 100 //50 pies. :^)
clumsyCheck = FALSE
/obj/item/weapon/pneumatic_cannon/pie/can_load_item(obj/item/I, mob/user)
if(istype(I, /obj/item/weapon/reagent_containers/food/snacks/pie))
return ..()
to_chat(user, "<span class='warning'>[src] only accepts pies!</span>")
return FALSE
@@ -296,7 +296,7 @@
/obj/item/weapon/lighter,
/obj/item/device/multitool,
/obj/item/weapon/reagent_containers/food/drinks/bottle/molotov,
/obj/item/weapon/c4,
/obj/item/weapon/grenade/plastic/c4,
)
/obj/item/weapon/storage/belt/grenade/full/PopulateContents()
new /obj/item/weapon/grenade/flashbang(src)
@@ -92,7 +92,7 @@
new /obj/item/pizzabox/bomb
if("darklord") //20 tc + tk + summon item close enough for now
new /obj/item/weapon/twohanded/dualsaber(src)
new /obj/item/weapon/twohanded/dualsaber(src)
new /obj/item/weapon/dnainjector/telemut/darkbundle(src)
new /obj/item/clothing/suit/hooded/chaplain_hoodie(src)
new /obj/item/weapon/card/id/syndicate(src)
@@ -218,8 +218,8 @@
new /obj/item/weapon/reagent_containers/glass/bottle/polonium(src)
new /obj/item/weapon/reagent_containers/glass/bottle/venom(src)
new /obj/item/weapon/reagent_containers/glass/bottle/neurotoxin2(src)
new /obj/item/weapon/reagent_containers/glass/bottle/formaldehyde(src)
new /obj/item/weapon/reagent_containers/glass/bottle/spewium(src)
new /obj/item/weapon/reagent_containers/glass/bottle/formaldehyde(src)
new /obj/item/weapon/reagent_containers/glass/bottle/spewium(src)
new /obj/item/weapon/reagent_containers/glass/bottle/cyanide(src)
new /obj/item/weapon/reagent_containers/glass/bottle/histamine(src)
new /obj/item/weapon/reagent_containers/glass/bottle/initropidril(src)
@@ -296,3 +296,10 @@
/obj/item/weapon/storage/box/syndie_kit/mimery/PopulateContents()
new /obj/item/weapon/spellbook/oneuse/mimery_blockade(src)
new /obj/item/weapon/spellbook/oneuse/mimery_guns(src)
/obj/item/weapon/storage/box/syndie_kit/holoparasite
name = "box"
/obj/item/weapon/storage/box/syndie_kit/holoparasite/PopulateContents()
new /obj/item/weapon/guardiancreator/tech/choose/traitor(src)
new /obj/item/weapon/paper/guardian(src)
@@ -71,9 +71,9 @@
icon_state = "refill_clothes"
charges = list(31, 4, 4)// of 101 standard, 12 contraband, 10 premium(?)
init_charges = list(31, 4, 4)
/obj/item/weapon/vending_refill/medical
machine_name = "NanoMed"
icon_state = "refill_medical"
charges = list(26, 5, 3)// of 76 standard, 13 contraband, 8 premium
/obj/item/weapon/vending_refill/medical
machine_name = "NanoMed"
icon_state = "refill_medical"
charges = list(26, 5, 3)// of 76 standard, 13 contraband, 8 premium
init_charges = list(26, 5, 3)
+11 -11
View File
@@ -390,7 +390,7 @@
desc = "A chainsaw that has replaced your arm."
icon_state = "chainsaw_on"
item_state = "mounted_chainsaw"
flags = NODROP | ABSTRACT | DROPDEL
flags = NODROP | ABSTRACT | DROPDEL
w_class = WEIGHT_CLASS_HUGE
force = 21
throwforce = 0
@@ -400,17 +400,17 @@
attack_verb = list("sawed", "torn", "cut", "chopped", "diced")
hitsound = 'sound/weapons/chainsawhit.ogg'
/obj/item/weapon/mounted_chainsaw/Destroy()
var/obj/item/bodypart/part
/obj/item/weapon/mounted_chainsaw/Destroy()
var/obj/item/bodypart/part
new /obj/item/weapon/twohanded/required/chainsaw(get_turf(src))
if(iscarbon(loc))
var/mob/living/carbon/holder = loc
var/index = holder.get_held_index_of_item(src)
if(index)
part = holder.hand_bodyparts[index]
. = ..()
if(part)
part.drop_limb()
if(iscarbon(loc))
var/mob/living/carbon/holder = loc
var/index = holder.get_held_index_of_item(src)
if(index)
part = holder.hand_bodyparts[index]
. = ..()
if(part)
part.drop_limb()
/obj/item/weapon/statuebust
name = "bust"
+1 -1
View File
@@ -23,7 +23,7 @@
var/persistence_replacement //have something WAY too amazing to live to the next round? Set a new path here. Overuse of this var will make me upset.
var/unique_rename = FALSE // can you customize the description/name of the thing?
var/dangerous_possession = FALSE //Admin possession yes/no
/obj/vv_edit_var(vname, vval)
+5 -5
View File
@@ -106,11 +106,11 @@ LINEN BINS
icon_state = "sheetrd"
item_color = "director"
// for Free Golems.
/obj/item/weapon/bedsheet/rd/royal_cape
name = "Royal Cape of the Liberator"
desc = "Majestic."
// for Free Golems.
/obj/item/weapon/bedsheet/rd/royal_cape
name = "Royal Cape of the Liberator"
desc = "Majestic."
/obj/item/weapon/bedsheet/medical
name = "medical blanket"
desc = "It's a sterilized* blanket commonly used in the Medbay. *Sterilization is voided if a virologist is present onboard the station."
@@ -11,7 +11,7 @@
else
new /obj/item/weapon/storage/backpack/satchel/cap(src)
new /obj/item/clothing/neck/cloak/cap(src)
new /obj/item/weapon/storage/daki(src)
new /obj/item/weapon/storage/daki(src)
new /obj/item/weapon/storage/backpack/dufflebag/captain(src)
new /obj/item/clothing/head/crown/fancy(src)
new /obj/item/clothing/suit/captunic(src)
+361 -361
View File
@@ -1,361 +1,361 @@
/obj/structure/displaycase
name = "display case"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "glassbox0"
desc = "A display case for prized possessions."
density = 1
anchored = 1
resistance_flags = ACID_PROOF
armor = list(melee = 30, bullet = 0, laser = 0, energy = 0, bomb = 10, bio = 0, rad = 0, fire = 70, acid = 100)
obj_integrity = 200
max_integrity = 200
integrity_failure = 50
var/obj/item/showpiece = null
var/alert = TRUE
var/open = FALSE
var/openable = TRUE
var/obj/item/weapon/electronics/airlock/electronics
var/start_showpiece_type = null //add type for items on display
/obj/structure/displaycase/Initialize()
. = ..()
if(start_showpiece_type)
showpiece = new start_showpiece_type (src)
update_icon()
/obj/structure/displaycase/Destroy()
if(electronics)
QDEL_NULL(electronics)
if(showpiece)
QDEL_NULL(showpiece)
return ..()
/obj/structure/displaycase/examine(mob/user)
..()
if(alert)
to_chat(user, "<span class='notice'>Hooked up with an anti-theft system.</span>")
if(showpiece)
to_chat(user, "<span class='notice'>There's [showpiece] inside.</span>")
/obj/structure/displaycase/proc/dump()
if (showpiece)
showpiece.forceMove(loc)
showpiece = null
/obj/structure/displaycase/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
switch(damage_type)
if(BRUTE)
playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
if(BURN)
playsound(src.loc, 'sound/items/Welder.ogg', 100, 1)
/obj/structure/displaycase/deconstruct(disassembled = TRUE)
if(!(flags & NODECONSTRUCT))
dump()
if(!disassembled)
new /obj/item/weapon/shard( src.loc )
trigger_alarm()
qdel(src)
/obj/structure/displaycase/obj_break(damage_flag)
if(!broken && !(flags & NODECONSTRUCT))
density = 0
broken = 1
new /obj/item/weapon/shard( src.loc )
playsound(src, "shatter", 70, 1)
update_icon()
trigger_alarm()
/obj/structure/displaycase/proc/trigger_alarm()
//Activate Anti-theft
if(alert)
var/area/alarmed = get_area(src)
alarmed.burglaralert(src)
playsound(src, 'sound/effects/alert.ogg', 50, 1)
/*
*/
/obj/structure/displaycase/proc/is_directional(atom/A)
try
getFlatIcon(A,defdir=4)
catch
return FALSE
return TRUE
/obj/structure/displaycase/proc/get_flat_icon_directional(atom/A)
//Get flatIcon even if dir is mismatched for directionless icons
//SLOW
var/icon/I
if(is_directional(A))
I = getFlatIcon(A)
else
var/old_dir = A.dir
A.setDir(2)
I = getFlatIcon(A)
A.setDir(old_dir)
return I
/obj/structure/displaycase/update_icon()
var/icon/I
if(open)
I = icon('icons/obj/stationobjs.dmi',"glassbox_open")
else
I = icon('icons/obj/stationobjs.dmi',"glassbox0")
if(broken)
I = icon('icons/obj/stationobjs.dmi',"glassboxb0")
if(showpiece)
var/icon/S = get_flat_icon_directional(showpiece)
S.Scale(17,17)
I.Blend(S,ICON_UNDERLAY,8,8)
src.icon = I
return
/obj/structure/displaycase/attackby(obj/item/weapon/W, mob/user, params)
if(W.GetID() && !broken && openable)
if(allowed(user))
to_chat(user, "<span class='notice'>You [open ? "close":"open"] the [src]</span>")
toggle_lock(user)
else
to_chat(user, "<span class='warning'>Access denied.</span>")
else if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent == INTENT_HELP && !broken)
var/obj/item/weapon/weldingtool/WT = W
if(obj_integrity < max_integrity && WT.remove_fuel(5, user))
to_chat(user, "<span class='notice'>You begin repairing [src].</span>")
playsound(loc, WT.usesound, 40, 1)
if(do_after(user, 40*W.toolspeed, target = src))
obj_integrity = max_integrity
playsound(loc, 'sound/items/Welder2.ogg', 50, 1)
update_icon()
to_chat(user, "<span class='notice'>You repair [src].</span>")
else
to_chat(user, "<span class='warning'>[src] is already in good condition!</span>")
return
else if(!alert && istype(W,/obj/item/weapon/crowbar) && openable) //Only applies to the lab cage and player made display cases
if(broken)
if(showpiece)
to_chat(user, "<span class='notice'>Remove the displayed object first.</span>")
else
to_chat(user, "<span class='notice'>You remove the destroyed case</span>")
qdel(src)
else
to_chat(user, "<span class='notice'>You start to [open ? "close":"open"] the [src]</span>")
if(do_after(user, 20*W.toolspeed, target = src))
to_chat(user, "<span class='notice'>You [open ? "close":"open"] the [src]</span>")
toggle_lock(user)
else if(open && !showpiece)
if(user.transferItemToLoc(W, src))
showpiece = W
to_chat(user, "<span class='notice'>You put [W] on display</span>")
update_icon()
else if(istype(W, /obj/item/stack/sheet/glass) && broken)
var/obj/item/stack/sheet/glass/G = W
if(G.get_amount() < 2)
to_chat(user, "<span class='warning'>You need two glass sheets to fix the case!</span>")
return
to_chat(user, "<span class='notice'>You start fixing [src]...</span>")
if(do_after(user, 20, target = src))
G.use(2)
broken = 0
obj_integrity = max_integrity
update_icon()
else
return ..()
/obj/structure/displaycase/proc/toggle_lock(mob/user)
open = !open
update_icon()
/obj/structure/displaycase/attack_paw(mob/user)
return src.attack_hand(user)
/obj/structure/displaycase/attack_hand(mob/user)
user.changeNext_move(CLICK_CD_MELEE)
if (showpiece && (broken || open))
to_chat(user, "<span class='notice'>You deactivate the hover field built into the case.</span>")
dump()
src.add_fingerprint(user)
update_icon()
return
else
//prevents remote "kicks" with TK
if (!Adjacent(user))
return
user.visible_message("<span class='danger'>[user] kicks the display case.</span>", null, null, COMBAT_MESSAGE_RANGE)
user.do_attack_animation(src, ATTACK_EFFECT_KICK)
take_damage(2)
/obj/structure/displaycase_chassis
anchored = 1
density = 0
name = "display case chassis"
desc = "wooden base of display case"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "glassbox_chassis"
var/obj/item/weapon/electronics/airlock/electronics
/obj/structure/displaycase_chassis/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/weapon/wrench)) //The player can only deconstruct the wooden frame
to_chat(user, "<span class='notice'>You start disassembling [src]...</span>")
playsound(src.loc, I.usesound, 50, 1)
if(do_after(user, 30*I.toolspeed, target = src))
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
new /obj/item/stack/sheet/mineral/wood(get_turf(src), 5)
qdel(src)
else if(istype(I, /obj/item/weapon/electronics/airlock))
to_chat(user, "<span class='notice'>You start installing the electronics into [src]...</span>")
playsound(src.loc, I.usesound, 50, 1)
if(do_after(user, 30, target = src) && user.transferItemToLoc(I,src))
electronics = I
to_chat(user, "<span class='notice'>You install the airlock electronics.</span>")
else if(istype(I, /obj/item/stack/sheet/glass))
var/obj/item/stack/sheet/glass/G = I
if(G.get_amount() < 10)
to_chat(user, "<span class='warning'>You need ten glass sheets to do this!</span>")
return
to_chat(user, "<span class='notice'>You start adding [G] to [src]...</span>")
if(do_after(user, 20, target = src))
G.use(10)
var/obj/structure/displaycase/display = new(src.loc)
if(electronics)
electronics.loc = display
display.electronics = electronics
if(electronics.one_access)
display.req_one_access = electronics.accesses
else
display.req_access = electronics.accesses
qdel(src)
else
return ..()
//The captains display case requiring specops ID access is intentional.
//The lab cage and captains display case do not spawn with electronics, which is why req_access is needed.
/obj/structure/displaycase/captain
alert = 1
start_showpiece_type = /obj/item/weapon/gun/energy/laser/captain
req_access = list(GLOB.access_cent_specops)
/obj/structure/displaycase/labcage
name = "lab cage"
desc = "A glass lab container for storing interesting creatures."
start_showpiece_type = /obj/item/clothing/mask/facehugger/lamarr
req_access = list(GLOB.access_rd)
/obj/structure/displaycase/trophy
name = "trophy display case"
desc = "Store your trophies of accomplishment in here, and they will stay forever."
var/trophy_message = ""
var/placer_key = ""
var/added_roundstart = TRUE
var/is_locked = TRUE
alert = TRUE
integrity_failure = 0
openable = FALSE
/obj/structure/displaycase/trophy/Initialize()
. = ..()
GLOB.trophy_cases += src
/obj/structure/displaycase/trophy/Destroy()
GLOB.trophy_cases -= src
return ..()
/obj/structure/displaycase/trophy/examine(mob/user)
..()
if(trophy_message)
to_chat(user, "The plaque reads:")
to_chat(user, trophy_message)
/obj/structure/displaycase/trophy/attackby(obj/item/weapon/W, mob/user, params)
if(!user.Adjacent(src)) //no TK museology
return
if(user.a_intent == INTENT_HARM)
return ..()
if(user.is_holding_item_of_type(/obj/item/key/displaycase))
if(added_roundstart)
is_locked = !is_locked
to_chat(user, "You [!is_locked ? "un" : ""]lock the case.")
else
to_chat(user, "<span class='danger'>The lock is stuck shut!</span>")
return
if(is_locked)
to_chat(user, "<span class='danger'>The case is shut tight with an old fashioned physical lock. Maybe you should ask the curator for the key?</span>")
return
if(!added_roundstart)
to_chat(user, "You've already put something new in this case.")
return
if(is_type_in_typecache(W, GLOB.blacklisted_cargo_types))
to_chat(user, "<span class='danger'>The case rejects the [W].</span>")
return
for(var/a in W.GetAllContents())
if(is_type_in_typecache(a, GLOB.blacklisted_cargo_types))
to_chat(user, "<span class='danger'>The case rejects the [W].</span>")
return
if(user.transferItemToLoc(W, src))
if(showpiece)
to_chat(user, "You press a button, and [showpiece] descends into the floor of the case.")
QDEL_NULL(showpiece)
to_chat(user, "You insert [W] into the case.")
showpiece = W
added_roundstart = FALSE
update_icon()
placer_key = user.ckey
trophy_message = W.desc //default value
var/chosen_plaque = stripped_input(user, "What would you like the plaque to say? Default value is item's description.", "Trophy Plaque")
if(chosen_plaque)
if(user.Adjacent(src))
trophy_message = chosen_plaque
to_chat(user, "You set the plaque's text.")
else
to_chat(user, "You are too far to set the plaque's text.")
SSpersistence.SaveTrophy(src)
return TRUE
else
to_chat(user, "<span class='warning'>\The [W] is stuck to your hand, you can't put it in the [src.name]!</span>")
return
/obj/structure/displaycase/trophy/dump()
if (showpiece)
if(added_roundstart)
visible_message("<span class='danger'>The [showpiece] crumbles to dust!</span>")
new /obj/effect/decal/cleanable/ash(loc)
QDEL_NULL(showpiece)
else
..()
/obj/item/key/displaycase
name = "display case key"
desc = "The key to the curator's display cases."
/obj/item/showpiece_dummy
name = "Cheap replica"
/obj/item/showpiece_dummy/Initialize(mapload, path)
. = ..()
var/obj/item/I = path
name = initial(I.name)
icon = initial(I.icon)
icon_state = initial(I.icon_state)
/obj/structure/displaycase
name = "display case"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "glassbox0"
desc = "A display case for prized possessions."
density = 1
anchored = 1
resistance_flags = ACID_PROOF
armor = list(melee = 30, bullet = 0, laser = 0, energy = 0, bomb = 10, bio = 0, rad = 0, fire = 70, acid = 100)
obj_integrity = 200
max_integrity = 200
integrity_failure = 50
var/obj/item/showpiece = null
var/alert = TRUE
var/open = FALSE
var/openable = TRUE
var/obj/item/weapon/electronics/airlock/electronics
var/start_showpiece_type = null //add type for items on display
/obj/structure/displaycase/Initialize()
. = ..()
if(start_showpiece_type)
showpiece = new start_showpiece_type (src)
update_icon()
/obj/structure/displaycase/Destroy()
if(electronics)
QDEL_NULL(electronics)
if(showpiece)
QDEL_NULL(showpiece)
return ..()
/obj/structure/displaycase/examine(mob/user)
..()
if(alert)
to_chat(user, "<span class='notice'>Hooked up with an anti-theft system.</span>")
if(showpiece)
to_chat(user, "<span class='notice'>There's [showpiece] inside.</span>")
/obj/structure/displaycase/proc/dump()
if (showpiece)
showpiece.forceMove(loc)
showpiece = null
/obj/structure/displaycase/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
switch(damage_type)
if(BRUTE)
playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
if(BURN)
playsound(src.loc, 'sound/items/Welder.ogg', 100, 1)
/obj/structure/displaycase/deconstruct(disassembled = TRUE)
if(!(flags & NODECONSTRUCT))
dump()
if(!disassembled)
new /obj/item/weapon/shard( src.loc )
trigger_alarm()
qdel(src)
/obj/structure/displaycase/obj_break(damage_flag)
if(!broken && !(flags & NODECONSTRUCT))
density = 0
broken = 1
new /obj/item/weapon/shard( src.loc )
playsound(src, "shatter", 70, 1)
update_icon()
trigger_alarm()
/obj/structure/displaycase/proc/trigger_alarm()
//Activate Anti-theft
if(alert)
var/area/alarmed = get_area(src)
alarmed.burglaralert(src)
playsound(src, 'sound/effects/alert.ogg', 50, 1)
/*
*/
/obj/structure/displaycase/proc/is_directional(atom/A)
try
getFlatIcon(A,defdir=4)
catch
return FALSE
return TRUE
/obj/structure/displaycase/proc/get_flat_icon_directional(atom/A)
//Get flatIcon even if dir is mismatched for directionless icons
//SLOW
var/icon/I
if(is_directional(A))
I = getFlatIcon(A)
else
var/old_dir = A.dir
A.setDir(2)
I = getFlatIcon(A)
A.setDir(old_dir)
return I
/obj/structure/displaycase/update_icon()
var/icon/I
if(open)
I = icon('icons/obj/stationobjs.dmi',"glassbox_open")
else
I = icon('icons/obj/stationobjs.dmi',"glassbox0")
if(broken)
I = icon('icons/obj/stationobjs.dmi',"glassboxb0")
if(showpiece)
var/icon/S = get_flat_icon_directional(showpiece)
S.Scale(17,17)
I.Blend(S,ICON_UNDERLAY,8,8)
src.icon = I
return
/obj/structure/displaycase/attackby(obj/item/weapon/W, mob/user, params)
if(W.GetID() && !broken && openable)
if(allowed(user))
to_chat(user, "<span class='notice'>You [open ? "close":"open"] the [src]</span>")
toggle_lock(user)
else
to_chat(user, "<span class='warning'>Access denied.</span>")
else if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent == INTENT_HELP && !broken)
var/obj/item/weapon/weldingtool/WT = W
if(obj_integrity < max_integrity && WT.remove_fuel(5, user))
to_chat(user, "<span class='notice'>You begin repairing [src].</span>")
playsound(loc, WT.usesound, 40, 1)
if(do_after(user, 40*W.toolspeed, target = src))
obj_integrity = max_integrity
playsound(loc, 'sound/items/Welder2.ogg', 50, 1)
update_icon()
to_chat(user, "<span class='notice'>You repair [src].</span>")
else
to_chat(user, "<span class='warning'>[src] is already in good condition!</span>")
return
else if(!alert && istype(W,/obj/item/weapon/crowbar) && openable) //Only applies to the lab cage and player made display cases
if(broken)
if(showpiece)
to_chat(user, "<span class='notice'>Remove the displayed object first.</span>")
else
to_chat(user, "<span class='notice'>You remove the destroyed case</span>")
qdel(src)
else
to_chat(user, "<span class='notice'>You start to [open ? "close":"open"] the [src]</span>")
if(do_after(user, 20*W.toolspeed, target = src))
to_chat(user, "<span class='notice'>You [open ? "close":"open"] the [src]</span>")
toggle_lock(user)
else if(open && !showpiece)
if(user.transferItemToLoc(W, src))
showpiece = W
to_chat(user, "<span class='notice'>You put [W] on display</span>")
update_icon()
else if(istype(W, /obj/item/stack/sheet/glass) && broken)
var/obj/item/stack/sheet/glass/G = W
if(G.get_amount() < 2)
to_chat(user, "<span class='warning'>You need two glass sheets to fix the case!</span>")
return
to_chat(user, "<span class='notice'>You start fixing [src]...</span>")
if(do_after(user, 20, target = src))
G.use(2)
broken = 0
obj_integrity = max_integrity
update_icon()
else
return ..()
/obj/structure/displaycase/proc/toggle_lock(mob/user)
open = !open
update_icon()
/obj/structure/displaycase/attack_paw(mob/user)
return src.attack_hand(user)
/obj/structure/displaycase/attack_hand(mob/user)
user.changeNext_move(CLICK_CD_MELEE)
if (showpiece && (broken || open))
to_chat(user, "<span class='notice'>You deactivate the hover field built into the case.</span>")
dump()
src.add_fingerprint(user)
update_icon()
return
else
//prevents remote "kicks" with TK
if (!Adjacent(user))
return
user.visible_message("<span class='danger'>[user] kicks the display case.</span>", null, null, COMBAT_MESSAGE_RANGE)
user.do_attack_animation(src, ATTACK_EFFECT_KICK)
take_damage(2)
/obj/structure/displaycase_chassis
anchored = 1
density = 0
name = "display case chassis"
desc = "wooden base of display case"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "glassbox_chassis"
var/obj/item/weapon/electronics/airlock/electronics
/obj/structure/displaycase_chassis/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/weapon/wrench)) //The player can only deconstruct the wooden frame
to_chat(user, "<span class='notice'>You start disassembling [src]...</span>")
playsound(src.loc, I.usesound, 50, 1)
if(do_after(user, 30*I.toolspeed, target = src))
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
new /obj/item/stack/sheet/mineral/wood(get_turf(src), 5)
qdel(src)
else if(istype(I, /obj/item/weapon/electronics/airlock))
to_chat(user, "<span class='notice'>You start installing the electronics into [src]...</span>")
playsound(src.loc, I.usesound, 50, 1)
if(do_after(user, 30, target = src) && user.transferItemToLoc(I,src))
electronics = I
to_chat(user, "<span class='notice'>You install the airlock electronics.</span>")
else if(istype(I, /obj/item/stack/sheet/glass))
var/obj/item/stack/sheet/glass/G = I
if(G.get_amount() < 10)
to_chat(user, "<span class='warning'>You need ten glass sheets to do this!</span>")
return
to_chat(user, "<span class='notice'>You start adding [G] to [src]...</span>")
if(do_after(user, 20, target = src))
G.use(10)
var/obj/structure/displaycase/display = new(src.loc)
if(electronics)
electronics.loc = display
display.electronics = electronics
if(electronics.one_access)
display.req_one_access = electronics.accesses
else
display.req_access = electronics.accesses
qdel(src)
else
return ..()
//The captains display case requiring specops ID access is intentional.
//The lab cage and captains display case do not spawn with electronics, which is why req_access is needed.
/obj/structure/displaycase/captain
alert = 1
start_showpiece_type = /obj/item/weapon/gun/energy/laser/captain
req_access = list(GLOB.access_cent_specops)
/obj/structure/displaycase/labcage
name = "lab cage"
desc = "A glass lab container for storing interesting creatures."
start_showpiece_type = /obj/item/clothing/mask/facehugger/lamarr
req_access = list(GLOB.access_rd)
/obj/structure/displaycase/trophy
name = "trophy display case"
desc = "Store your trophies of accomplishment in here, and they will stay forever."
var/trophy_message = ""
var/placer_key = ""
var/added_roundstart = TRUE
var/is_locked = TRUE
alert = TRUE
integrity_failure = 0
openable = FALSE
/obj/structure/displaycase/trophy/Initialize()
. = ..()
GLOB.trophy_cases += src
/obj/structure/displaycase/trophy/Destroy()
GLOB.trophy_cases -= src
return ..()
/obj/structure/displaycase/trophy/examine(mob/user)
..()
if(trophy_message)
to_chat(user, "The plaque reads:")
to_chat(user, trophy_message)
/obj/structure/displaycase/trophy/attackby(obj/item/weapon/W, mob/user, params)
if(!user.Adjacent(src)) //no TK museology
return
if(user.a_intent == INTENT_HARM)
return ..()
if(user.is_holding_item_of_type(/obj/item/key/displaycase))
if(added_roundstart)
is_locked = !is_locked
to_chat(user, "You [!is_locked ? "un" : ""]lock the case.")
else
to_chat(user, "<span class='danger'>The lock is stuck shut!</span>")
return
if(is_locked)
to_chat(user, "<span class='danger'>The case is shut tight with an old fashioned physical lock. Maybe you should ask the curator for the key?</span>")
return
if(!added_roundstart)
to_chat(user, "You've already put something new in this case.")
return
if(is_type_in_typecache(W, GLOB.blacklisted_cargo_types))
to_chat(user, "<span class='danger'>The case rejects the [W].</span>")
return
for(var/a in W.GetAllContents())
if(is_type_in_typecache(a, GLOB.blacklisted_cargo_types))
to_chat(user, "<span class='danger'>The case rejects the [W].</span>")
return
if(user.transferItemToLoc(W, src))
if(showpiece)
to_chat(user, "You press a button, and [showpiece] descends into the floor of the case.")
QDEL_NULL(showpiece)
to_chat(user, "You insert [W] into the case.")
showpiece = W
added_roundstart = FALSE
update_icon()
placer_key = user.ckey
trophy_message = W.desc //default value
var/chosen_plaque = stripped_input(user, "What would you like the plaque to say? Default value is item's description.", "Trophy Plaque")
if(chosen_plaque)
if(user.Adjacent(src))
trophy_message = chosen_plaque
to_chat(user, "You set the plaque's text.")
else
to_chat(user, "You are too far to set the plaque's text.")
SSpersistence.SaveTrophy(src)
return TRUE
else
to_chat(user, "<span class='warning'>\The [W] is stuck to your hand, you can't put it in the [src.name]!</span>")
return
/obj/structure/displaycase/trophy/dump()
if (showpiece)
if(added_roundstart)
visible_message("<span class='danger'>The [showpiece] crumbles to dust!</span>")
new /obj/effect/decal/cleanable/ash(loc)
QDEL_NULL(showpiece)
else
..()
/obj/item/key/displaycase
name = "display case key"
desc = "The key to the curator's display cases."
/obj/item/showpiece_dummy
name = "Cheap replica"
/obj/item/showpiece_dummy/Initialize(mapload, path)
. = ..()
var/obj/item/I = path
name = initial(I.name)
icon = initial(I.icon)
icon_state = initial(I.icon_state)
@@ -48,6 +48,11 @@
/obj/effect/mob_spawn/human/ash_walker/special(mob/living/new_spawn)
new_spawn.real_name = random_unique_lizard_name(gender)
to_chat(new_spawn, "<b>Drag the corpses of men and beasts to your nest. It will absorb them to create more of your kind. Glory to the Necropolis!</b>")
new_spawn.grant_language(/datum/language/draconic)
var/datum/language_holder/holder = new_spawn.get_language_holder()
holder.selected_default_language = /datum/language/draconic
if(ishuman(new_spawn))
var/mob/living/carbon/human/H = new_spawn
H.underwear = "Nude"
@@ -188,9 +188,9 @@
/obj/structure/mineral_door/transparent/plasma/attackby(obj/item/weapon/W, mob/user, params)
if(W.is_hot())
var/turf/T = get_turf(src)
message_admins("Plasma mineral door ignited by [ADMIN_LOOKUPFLW(user)] in [ADMIN_COORDJMP(T)]",0,1)
log_game("Plasma mineral door ignited by [key_name(user)] in [COORD(T)]")
var/turf/T = get_turf(src)
message_admins("Plasma mineral door ignited by [ADMIN_LOOKUPFLW(user)] in [ADMIN_COORDJMP(T)]",0,1)
log_game("Plasma mineral door ignited by [key_name(user)] in [COORD(T)]")
TemperatureAct()
else
return ..()
+3 -3
View File
@@ -61,7 +61,7 @@ GLOBAL_LIST_INIT(freqtospan, list(
var/messagepart = " <span class='message'>[lang_treat(speaker, message_language, raw_message, spans)]</span></span>"
var/languageicon = ""
var/datum/language/D = get_language_instance(message_language)
var/datum/language/D = GLOB.language_datum_instances[message_language]
if(D.display_icon(src))
languageicon = "[D.get_icon()] "
@@ -103,7 +103,7 @@ GLOBAL_LIST_INIT(freqtospan, list(
return speaker.say_quote(raw_message, spans, message_mode)
else if(language)
var/atom/movable/AM = speaker.GetSource()
var/datum/language/D = get_language_instance(language)
var/datum/language/D = GLOB.language_datum_instances[language]
raw_message = D.scramble(raw_message)
if(AM)
return AM.say_quote(raw_message, spans, message_mode)
@@ -143,7 +143,7 @@ GLOBAL_LIST_INIT(freqtospan, list(
return "0"
/atom/movable/proc/GetVoice()
return name
return "[src]" //Returns the atom's name, prepended with 'The' if it's not a proper noun
/atom/movable/proc/IsVocal()
return 1
+4 -9
View File
@@ -23,10 +23,10 @@
if(T && T.z == turf_source.z)
M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, surround, channel, pressure_affected)
/atom/proc/playsound_direct(soundin, vol as num, vary, frequency, falloff, surround = TRUE, channel = 0, pressure_affected = FALSE)
playsound_local(get_turf(src), soundin, vol, vary, frequency, falloff, surround, channel)
/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff, surround = 1, channel = 0, pressure_affected = TRUE)
if(!client || !can_hear())
return
/atom/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff, surround = 1, channel = 0, pressure_affected = TRUE)
soundin = get_sfx(soundin)
var/sound/S = sound(soundin)
@@ -76,15 +76,10 @@
// The y value is for above your head, but there is no ceiling in 2d spessmens.
S.y = 1
S.falloff = (falloff ? falloff : FALLOFF_SOUNDS)
S.falloff = falloff || FALLOFF_SOUNDS
src << S
/mob/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff, surround = 1, channel = 0, pressure_affected = TRUE)
if(!client || !can_hear())
return
..()
/proc/open_sound_channel()
var/static/next_channel = 1 //loop through the available 1024 - (the ones we reserve) channels and pray that its not still being used
. = ++next_channel
+5 -5
View File
@@ -71,13 +71,13 @@
computerid = bancid
ip = banip
var/datum/DBQuery/query_add_ban_get_ckey = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ckey = '[ckey]'")
if(!query_add_ban_get_ckey.warn_execute())
var/datum/DBQuery/query_add_ban_get_ckey = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("player")] WHERE ckey = '[ckey]'")
if(!query_add_ban_get_ckey.warn_execute())
return
if(!query_add_ban_get_ckey.NextRow())
if(!query_add_ban_get_ckey.NextRow())
if(!banned_mob || (banned_mob && !IsGuestKey(banned_mob.key)))
if(alert(usr, "[ckey] has not been seen before, are you sure you want to create a ban for them?", "Unknown ckey", "Yes", "No", "Cancel") != "Yes")
return
if(alert(usr, "[ckey] has not been seen before, are you sure you want to create a ban for them?", "Unknown ckey", "Yes", "No", "Cancel") != "Yes")
return
var/a_ckey
var/a_computerid
File diff suppressed because it is too large Load Diff
+20 -20
View File
@@ -1,21 +1,21 @@
atom/proc/investigate_log(message, subject)
if(!message || !subject)
return
var/F = file("[GLOB.log_directory]/[subject].html")
F << "<small>[time_stamp()] \ref[src] ([x],[y],[z])</small> || [src] [message]<br>"
/client/proc/investigate_show( subject in list("hrefs","notes, memos, watchlist","singulo","wires","telesci", "gravity", "records", "cargo", "supermatter", "atmos", "experimentor", "botany") )
set name = "Investigate"
set category = "Admin"
if(!holder)
return
switch(subject)
if("notes, memos, watchlist")
browse_messages()
else
var/F = file("[GLOB.log_directory]/[subject].html")
if(!fexists(F))
to_chat(src, "<span class='danger'>No [subject] logfile was found.</span>")
return
atom/proc/investigate_log(message, subject)
if(!message || !subject)
return
var/F = file("[GLOB.log_directory]/[subject].html")
F << "<small>[time_stamp()] \ref[src] ([x],[y],[z])</small> || [src] [message]<br>"
/client/proc/investigate_show( subject in list("hrefs","notes, memos, watchlist","singulo","wires","telesci", "gravity", "records", "cargo", "supermatter", "atmos", "experimentor", "botany") )
set name = "Investigate"
set category = "Admin"
if(!holder)
return
switch(subject)
if("notes, memos, watchlist")
browse_messages()
else
var/F = file("[GLOB.log_directory]/[subject].html")
if(!fexists(F))
to_chat(src, "<span class='danger'>No [subject] logfile was found.</span>")
return
src << browse(F,"window=investigate[subject];size=800x300")
+5 -5
View File
@@ -1799,12 +1799,12 @@
if(!check_rights(R_ADMIN))
return
var/mob/living/L = locate(href_list["languagemenu"]) in GLOB.mob_list
if(!isliving(L))
to_chat(usr, "This can only be used on instances of type /mob/living.")
var/mob/M = locate(href_list["languagemenu"]) in GLOB.mob_list
if(!ismob(M))
to_chat(usr, "This can only be used on instances of type /mob.")
return
L.open_language_menu(usr)
var/datum/language_holder/H = M.get_language_holder()
H.open_language_menu(usr)
else if(href_list["traitor"])
if(!check_rights(R_ADMIN))
-55
View File
@@ -1,55 +0,0 @@
diff a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm (rejected hunks)
@@ -67,7 +67,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
for(var/I in l2b)
var/datum/admin_help/AH = I
dat += "<span class='adminnotice'><span class='adminhelp'>Ticket #[AH.id]</span>: <A HREF='?_src_=holder;ahelp=\ref[AH];ahelp_action=ticket'>[AH.initiator_key_name]: [AH.name]</A></span><br>"
-
+
usr << browse(dat.Join(), "window=ahelp_list[state];size=600x480")
//Tickets statpanel
@@ -253,7 +253,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
if(state == AHELP_ACTIVE)
to_chat(usr, "<span class='warning'>This ticket is already open.</span>")
return
-
+
if(GLOB.ahelp_tickets.CKey2ActiveTicket(initiator_ckey))
to_chat(usr, "<span class='warning'>This user already has an active ticket, cannot reopen this one.</span>")
return
@@ -310,7 +310,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
RemoveActive()
state = AHELP_RESOLVED
GLOB.ahelp_tickets.ListInsert(src)
-
+
if(initiator)
initiator.giveadminhelpverb()
@@ -325,7 +325,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
/datum/admin_help/proc/Reject(key_name = key_name_admin(usr))
if(state != AHELP_ACTIVE)
return
-
+
if(initiator)
initiator.giveadminhelpverb()
@@ -494,7 +494,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
if(!check_rights(R_ADMIN, TRUE))
return
-
+
var/browse_to
switch(input("Display which ticket list?") as null|anything in list("Active Tickets", "Closed Tickets", "Resolved Tickets"))
@@ -506,7 +506,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
browse_to = AHELP_RESOLVED
else
return
-
+
GLOB.ahelp_tickets.BrowseTickets(browse_to)
//
+5 -5
View File
@@ -132,7 +132,7 @@
/datum/admins/proc/makeWizard()
var/list/mob/dead/observer/candidates = pollCandidates("Do you wish to be considered for the position of a Wizard Foundation 'diplomat'?", "wizard", null)
var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for the position of a Wizard Foundation 'diplomat'?", "wizard", null)
var/mob/dead/observer/selected = pick_n_take(candidates)
@@ -215,7 +215,7 @@
/datum/admins/proc/makeNukeTeam()
var/datum/game_mode/nuclear/temp = new
var/list/mob/dead/observer/candidates = pollCandidates("Do you wish to be considered for a nuke team being sent in?", "operative", temp)
var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for a nuke team being sent in?", "operative", temp)
var/list/mob/dead/observer/chosen = list()
var/mob/dead/observer/theghost = null
@@ -288,7 +288,7 @@
// DEATH SQUADS
/datum/admins/proc/makeDeathsquad()
var/mission = input("Assign a mission to the deathsquad", "Assign Mission", "Leave no witnesses.")
var/list/mob/dead/observer/candidates = pollCandidates("Do you wish to be considered for an elite Nanotrasen Strike Team?", "deathsquad", null)
var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for an elite Nanotrasen Strike Team?", "deathsquad", null)
var/squadSpawned = 0
if(candidates.len >= 2) //Minimum 2 to be considered a squad
@@ -396,7 +396,7 @@
/datum/admins/proc/makeOfficial()
var/mission = input("Assign a task for the official", "Assign Task", "Conduct a routine preformance review of [station_name()] and its Captain.")
var/list/mob/dead/observer/candidates = pollCandidates("Do you wish to be considered to be a Centcom Official?", "deathsquad")
var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered to be a Centcom Official?", "deathsquad")
if(candidates.len)
var/mob/dead/observer/chosen_candidate = pick(candidates)
@@ -457,7 +457,7 @@
var/mission = input("Assign a mission to the Emergency Response Team", "Assign Mission", "Assist the station.") as null|text
if(!mission)
return
var/list/mob/dead/observer/candidates = pollCandidates("Do you wish to be considered for a Code [alert] Nanotrasen Emergency Response Team?", "deathsquad", null)
var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for a Code [alert] Nanotrasen Emergency Response Team?", "deathsquad", null)
var/teamSpawned = 0
if(candidates.len > 0)
+1 -1
View File
@@ -587,7 +587,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
empulse(O, heavy, light)
log_admin("[key_name(usr)] created an EM Pulse ([heavy],[light]) at ([O.x],[O.y],[O.z])")
message_admins("[key_name_admin(usr)] created an EM PUlse ([heavy],[light]) at ([O.x],[O.y],[O.z])")
message_admins("[key_name_admin(usr)] created an EM Pulse ([heavy],[light]) at ([O.x],[O.y],[O.z])")
SSblackbox.add_details("admin_verb","EM Pulse") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
return
@@ -1,12 +0,0 @@
diff a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm (rejected hunks)
@@ -108,8 +108,8 @@
for(var/mob/M in view(range,A))
to_chat(M, msg)
- log_admin("LocalNarrate: [key_name(usr)] at ([get_area(A)]): [msg]")
- message_admins("<span class='adminnotice'><b> LocalNarrate: [key_name_admin(usr)] at (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[A.x];Y=[A.y];Z=[A.z]'>[get_area(A)]</a>):</b> [msg]<BR></span>")
+ log_admin("LocalNarrate: [key_name(usr)] at [get_area(A)][COORD(A)]: [msg]")
+ message_admins("<span class='adminnotice'><b> LocalNarrate: [key_name_admin(usr)] at [get_area(A)][ADMIN_JMP(A)]:</b> [msg]<BR></span>")
SSblackbox.add_details("admin_verb","Local Narrate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/cmd_admin_godmode(mob/M in GLOB.mob_list)

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