Merge branch 'master' of https://github.com/PolarisSS13/Polaris into 3/30/2016_dumb_gun_balance

# Conflicts resolved:
#	code/modules/projectiles/projectile/beams.dm
This commit is contained in:
Neerti
2016-04-20 05:41:36 -04:00
222 changed files with 4002 additions and 3123 deletions

View File

@@ -36,4 +36,9 @@ script:
- (num=`grep -E '\\\\(red|blue|green|black|b|i[^mc])' **/*.dm | wc -l`; echo "$num escapes (expecting ${MACRO_COUNT} or less)"; [ $num -le ${MACRO_COUNT} ])
- source $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}/byond/bin/byondsetup
- python tools/TagMatcher/tag-matcher.py ../..
- echo "#define UNIT_TEST 1" > code/_unit_tests.dm
- cp config/example/* config/
- DreamMaker polaris.dme
- DreamDaemon polaris.dmb -invisible -trusted -core 2>&1 | tee log.txt
- grep "All Unit Tests Passed" log.txt

View File

@@ -0,0 +1,3 @@
// Consider these images/atoms as part of the UI/HUD
#define APPEARANCE_UI_IGNORE_ALPHA RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA
#define APPEARANCE_UI RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR

View File

@@ -0,0 +1,4 @@
#define ASCII_ESC ascii2text(27)
#define ASCII_RED "[ASCII_ESC]\[31m"
#define ASCII_GREEN "[ASCII_ESC]\[32m"
#define ASCII_RESET "[ASCII_ESC]\[0m"

View File

@@ -78,7 +78,13 @@ var/global/list/socks_t = list(
"Black knee" = "black_knee", "Black thigh" = "black_thigh", "Thin knee" = "thin_knee",
"Thin thigh" = "thin_thigh", "Pantyhose" = "pantyhose", "Striped thigh" = "striped_thigh",
"Striped knee" = "striped_knee", "Rainbow knee" = "rainbow_knee", "Rainbow thigh" = "rainbow_thigh",
"Fishnets" = "fishnet", "Thin white thigh" = "thinwhite_thigh", "Thin white knee" = "thinwhite_knee", "None")
"Fishnets" = "fishnet", "Thin white thigh" = "thinwhite_thigh", "Thin white knee" = "thinwhite_knee",
"Green striped thigh" = "gstriped_thigh", "Green striped knee" = "gstriped_knee",
"Purple striped thigh" = "pstriped_thigh", "Purple striped knee" = "pstriped_knee",
"Blue striped thigh" = "bstriped_thigh", "Blue striped knee" = "bstriped_knee",
"Yellow striped thigh" = "ystriped_thigh", "Yellow striped knee" = "ystriped_knee",
"Red striped thigh" = "rstriped_thigh", "Red striped knee" = "rstriped_knee",
"Orange striped thigh" = "ostriped_thigh", "Orange striped knee" = "ostriped_knee", "None")
//Backpacks
var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Alt")

View File

@@ -30,13 +30,6 @@
return "[output][and_text][input[index]]"
/proc/ConvertReqString2List(var/list/source_list)
var/list/temp_list = params2list(source_list)
for(var/O in temp_list)
temp_list[O] = text2num(temp_list[O])
return temp_list
//Returns list element or null. Should prevent "index out of bounds" error.
proc/listgetindex(var/list/list,index)
if(istype(list) && list.len)

View File

@@ -31,7 +31,7 @@
diary << "\[[time_stamp()]]DEBUG: [text][log_end]"
for(var/client/C in admins)
if(C.is_preference_enabled(/datum/client_preference/admin/show_debug_logs))
if(C.is_preference_enabled(/datum/client_preference/debug/show_debug_logs))
C << "DEBUG: [text]"
@@ -82,6 +82,9 @@
/proc/log_misc(text)
diary << "\[[time_stamp()]]MISC: [text][log_end]"
/proc/log_unit_test(text)
world.log << "## UNIT_TEST: [text]"
//pretty print a direction bitflag, can be useful for debugging.
/proc/print_dir(var/dir)
var/list/comps = list()

View File

@@ -30,13 +30,10 @@ proc/random_hair_style(gender, species = "Human")
var/list/valid_hairstyles = list()
for(var/hairstyle in hair_styles_list)
var/datum/sprite_accessory/S = hair_styles_list[hairstyle]
if(gender != NEUTER && gender != PLURAL)
if(gender == MALE && S.gender == FEMALE)
continue
if(gender == FEMALE && S.gender == MALE)
continue
if(gender == MALE && S.gender == FEMALE)
continue
if(gender == FEMALE && S.gender == MALE)
continue
if( !(species in S.species_allowed))
continue
valid_hairstyles[hairstyle] = hair_styles_list[hairstyle]
@@ -52,13 +49,10 @@ proc/random_facial_hair_style(gender, species = "Human")
var/list/valid_facialhairstyles = list()
for(var/facialhairstyle in facial_hair_styles_list)
var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle]
if(gender != NEUTER && gender != PLURAL)
if(gender == MALE && S.gender == FEMALE)
continue
if(gender == FEMALE && S.gender == MALE)
continue
if(gender == MALE && S.gender == FEMALE)
continue
if(gender == FEMALE && S.gender == MALE)
continue
if( !(species in S.species_allowed))
continue
@@ -171,3 +165,88 @@ Proc for attack log creation, because really why not
return 0
var/mob/living/silicon/robot/R = thing.loc
return (thing in R.module.modules)
/proc/get_exposed_defense_zone(var/atom/movable/target)
var/obj/item/weapon/grab/G = locate() in target
if(G && G.state >= GRAB_NECK) //works because mobs are currently not allowed to upgrade to NECK if they are grabbing two people.
return pick("head", "l_hand", "r_hand", "l_foot", "r_foot", "l_arm", "r_arm", "l_leg", "r_leg")
else
return pick("chest", "groin")
/proc/do_mob(mob/user , mob/target, time = 30, uninterruptible = 0, progress = 1)
if(!user || !target)
return 0
var/user_loc = user.loc
var/target_loc = target.loc
var/holding = user.get_active_hand()
var/datum/progressbar/progbar
if (progress)
progbar = new(user, time, target)
var/endtime = world.time+time
var/starttime = world.time
. = 1
while (world.time < endtime)
sleep(1)
if (progress)
progbar.update(world.time - starttime)
if(!user || !target)
. = 0
break
if(uninterruptible)
continue
if(!user || user.incapacitated() || user.loc != user_loc)
. = 0
break
if(target.loc != target_loc)
. = 0
break
if(user.get_active_hand() != holding)
. = 0
break
if (progbar)
qdel(progbar)
/proc/do_after(mob/user, delay, atom/target = null, needhand = 1, progress = 1, var/incapacitation_flags = INCAPACITATION_DEFAULT)
if(!user)
return 0
var/atom/target_loc = null
if(target)
target_loc = target.loc
var/atom/original_loc = user.loc
var/holding = user.get_active_hand()
var/datum/progressbar/progbar
if (progress)
progbar = new(user, delay, target)
var/endtime = world.time + delay
var/starttime = world.time
. = 1
while (world.time < endtime)
sleep(1)
if (progress)
progbar.update(world.time - starttime)
if(!user || user.incapacitated(incapacitation_flags) || user.loc != original_loc)
. = 0
break
if(target_loc && (!target || target_loc != target.loc))
. = 0
break
if(needhand)
if(user.get_active_hand() != holding)
. = 0
break
if (progbar)
qdel(progbar)

View File

@@ -149,6 +149,26 @@
if (rights & R_MENTOR) . += "[seperator]+MENTOR"
return .
// Converts a hexadecimal color (e.g. #FF0050) to a list of numbers for red, green, and blue (e.g. list(255,0,80) ).
/proc/hex2rgb(hex)
// Strips the starting #, in case this is ever supplied without one, so everything doesn't break.
if(findtext(hex,"#",1,2))
hex = copytext(hex, 2)
return list(hex2rgb_r(hex), hex2rgb_g(hex), hex2rgb_b(hex))
// The three procs below require that the '#' part of the hex be stripped, which hex2rgb() does automatically.
/proc/hex2rgb_r(hex)
var/hex_to_work_on = copytext(hex,1,3)
return hex2num(hex_to_work_on)
/proc/hex2rgb_g(hex)
var/hex_to_work_on = copytext(hex,3,5)
return hex2num(hex_to_work_on)
/proc/hex2rgb_b(hex)
var/hex_to_work_on = copytext(hex,5,7)
return hex2num(hex_to_work_on)
// heat2color functions. Adapted from: http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
/proc/heat2color(temp)
return rgb(heat2color_r(temp), heat2color_g(temp), heat2color_b(temp))

View File

@@ -646,47 +646,6 @@ proc/GaussRandRound(var/sigma,var/roundto)
else return get_step(ref, base_dir)
/proc/do_mob(var/mob/user, var/mob/target, var/delay = 30, var/numticks = 5, var/needhand = 1) //This is quite an ugly solution but i refuse to use the old request system.
if(!user || !target) return 0
if(numticks == 0) return 0
var/delayfraction = round(delay/numticks)
var/original_user_loc = user.loc
var/original_target_loc = target.loc
var/holding = user.get_active_hand()
for(var/i = 0, i<numticks, i++)
sleep(delayfraction)
if(!user || user.stat || user.weakened || user.stunned || user.loc != original_user_loc)
return 0
if(!target || target.loc != original_target_loc)
return 0
if(needhand && !(user.get_active_hand() == holding)) //Sometimes you don't want the user to have to keep their active hand
return 0
return 1
/proc/do_after(var/mob/user as mob, delay as num, var/numticks = 5, var/needhand = 1)
if(!user || isnull(user))
return 0
if(numticks == 0)
return 0
var/delayfraction = round(delay/numticks)
var/original_loc = user.loc
var/holding = user.get_active_hand()
for(var/i = 0, i<numticks, i++)
sleep(delayfraction)
if(!user || user.stat || user.weakened || user.stunned || user.loc != original_loc)
return 0
if(needhand && !(user.get_active_hand() == holding)) //Sometimes you don't want the user to have to keep their active hand
return 0
return 1
//Takes: Anything that could possibly have variables and a varname to check.
//Returns: 1 if found, 0 if not.
/proc/hasvar(var/datum/A, var/varname)
@@ -1351,3 +1310,15 @@ var/mob/dview/dview_mob = new
// call to generate a stack trace and print to runtime logs
/proc/crash_with(msg)
CRASH(msg)
/proc/screen_loc2turf(scr_loc, turf/origin)
var/tX = splittext(scr_loc, ",")
var/tY = splittext(tX[2], ":")
var/tZ = origin.z
tY = tY[1]
tX = splittext(tX[1], ":")
tX = tX[1]
tX = max(1, min(world.maxx, origin.x + (text2num(tX) - (world.view + 1))))
tY = max(1, min(world.maxy, origin.y + (text2num(tY) - (world.view + 1))))
return locate(tX, tY, tZ)

View File

@@ -87,6 +87,7 @@
if(in_throw_mode)
if(isturf(A) || isturf(A.loc))
throw_item(A)
trigger_aiming(TARGET_CAN_CLICK)
return 1
throw_mode_off()
@@ -94,6 +95,7 @@
if(W == A) // Handle attack_self
W.attack_self(src)
trigger_aiming(TARGET_CAN_CLICK)
update_inv_active_hand(0)
return 1
@@ -113,6 +115,8 @@
if(ismob(A)) // No instant mob attacking
setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
UnarmedAttack(A, 1)
trigger_aiming(TARGET_CAN_CLICK)
return 1
if(!isturf(loc)) // This is going to stop you from telekinesing from inside a closet, but I don't shed many tears for that
@@ -134,12 +138,15 @@
if(ismob(A)) // No instant mob attacking
setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
UnarmedAttack(A, 1)
trigger_aiming(TARGET_CAN_CLICK)
return
else // non-adjacent click
if(W)
W.afterattack(A, src, 0, params) // 0: not Adjacent
else
RangedAttack(A, params)
trigger_aiming(TARGET_CAN_CLICK)
return 1
/mob/proc/setClickCooldown(var/timeout)
@@ -325,3 +332,20 @@
else direction = WEST
if(direction != dir)
facedir(direction)
/obj/screen/click_catcher
icon = 'icons/mob/screen1_full.dmi'
icon_state = "passage0"
layer = 0
mouse_opacity = 2
screen_loc = "1,1"
/obj/screen/click_catcher/Click(location, control, params)
var/list/modifiers = params2list(params)
if(modifiers["middle"] && istype(usr, /mob/living/carbon))
var/mob/living/carbon/C = usr
C.swap_hand()
else
var/turf/T = screen_loc2turf(modifiers["screen-loc"], get_turf(usr))
T.Click(location, control, params)
return 1

View File

@@ -130,6 +130,8 @@
using.layer = SCREEN_LAYER
adding += using
mymob.client.screen = list()
mymob.client.screen += adding + other
mymob.client.screen += mymob.client.void
return

View File

@@ -41,6 +41,7 @@
mymob.fire.name = "fire"
mymob.fire.screen_loc = ui_fire
mymob.client.screen = null
mymob.client.screen = list()
mymob.client.screen += list( mymob.healths, mymob.blind, mymob.flash, mymob.fire) //, mymob.rest, mymob.sleep, mymob.mach )
mymob.client.screen += src.adding + src.other
mymob.client.screen += src.adding + src.other
mymob.client.screen += mymob.client.void

View File

@@ -361,10 +361,11 @@
mymob.radio_use_icon.color = ui_color
mymob.radio_use_icon.alpha = ui_alpha
mymob.client.screen = null
mymob.client.screen = list()
mymob.client.screen += hud_elements
mymob.client.screen += src.adding + src.hotkeybuttons
mymob.client.screen += mymob.client.void
inventory_shown = 0;
return

View File

@@ -27,9 +27,10 @@
blobhealthdisplay.screen_loc = ui_internal
blobhealthdisplay.layer = 20
mymob.client.screen = null
mymob.client.screen = list()
mymob.client.screen += list(blobpwrdisplay, blobhealthdisplay)
mymob.client.screen += mymob.client.void
/datum/hud/proc/slime_hud(ui_style = 'icons/mob/screen1_Midnight.dmi')
@@ -94,8 +95,9 @@
src.adding += using
hurt_intent = using
mymob.client.screen = null
mymob.client.screen = list()
mymob.client.screen += src.adding
mymob.client.screen += mymob.client.void
return
@@ -151,6 +153,7 @@
mymob.purged.name = "purged"
mymob.purged.screen_loc = ui_construct_purge
mymob.client.screen = null
mymob.client.screen = list()
mymob.client.screen += list(mymob.fire, mymob.healths, mymob.pullin, mymob.zone_sel, mymob.purged, mymob.flash)
mymob.client.screen += mymob.client.void

View File

@@ -157,10 +157,11 @@ var/obj/screen/robot_inventory
mymob.gun_move_icon = new /obj/screen/gun/move(null)
mymob.radio_use_icon = new /obj/screen/gun/radio(null)
mymob.client.screen = null
mymob.client.screen = list()
mymob.client.screen += list( mymob.throw_icon, mymob.zone_sel, mymob.oxygen, mymob.fire, mymob.hands, mymob.healths, mymob:cells, mymob.pullin, mymob.blind, mymob.flash, robot_inventory, mymob.gun_setting_icon)
mymob.client.screen += src.adding + src.other
mymob.client.screen += mymob.client.void
return

View File

@@ -17,12 +17,9 @@
if(can_reenter_corpse && mind && mind.current)
if(A == mind.current || (mind.current in A)) // double click your corpse or whatever holds it
reenter_corpse() // (cloning scanner, body bag, closet, mech, etc)
return // seems legit.
// Things you might plausibly want to follow
if((ismob(A) && A != src) || istype(A,/obj/singularity))
else if(istype(A,/atom/movable))
ManualFollow(A)
// Otherwise jump
else
following = null

View File

@@ -55,6 +55,7 @@
if(!..())
return 0
setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
A.attack_generic(src,rand(5,6),"bitten")
/*
@@ -76,6 +77,9 @@
Feedstop()
return
//should have already been set if we are attacking a mob, but it doesn't hurt and will cover attacking non-mobs too
setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
var/mob/living/M = A
if (istype(M))
@@ -144,6 +148,7 @@
custom_emote(1,"[friendly] [A]!")
return
setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
var/damage = rand(melee_damage_lower, melee_damage_upper)
if(A.attack_generic(src,damage,attacktext,environment_smash) && loc && attack_sound)
playsound(loc, attack_sound, 50, 1, 1)

10
code/_unit_tests.dm Normal file
View File

@@ -0,0 +1,10 @@
/*
*
* This file is used by Travis to indicate that Unit Tests are to be ran.
* Do not add anything but the UNIT_TEST definition here as it will be overwritten by Travis when running tests.
*
*
* Should you wish to edit set UNIT_TEST to 1 like so:
* #define UNIT_TEST 1
*/
#define UNIT_TEST 0

View File

@@ -317,9 +317,9 @@ var/global/datum/shuttle_controller/shuttle_controller
"Arrivals dock" = "nuke_shuttle_dock_airlock",
)
MS.announcer = "NDV Icarus"
MS.arrival_message = "Attention, [station_short], you have a large signature approaching the station - looks unarmed to surface scans. We're too far out to intercept - brace for visitors."
MS.departure_message = "Your visitors are on their way out of the system, [station_short], burning delta-v like it's nothing. Good riddance."
MS.announcer = "Automated Traffic Control"
MS.arrival_message = "Attention. A vessel is approaching the colony."
MS.departure_message = "Attention. A vessel is now leaving from the colony."
MS.interim = locate(/area/syndicate_station/transit)
MS.warmup_time = 0

View File

@@ -25,7 +25,7 @@
usr.client.debug_variables(antag)
message_admins("Admin [key_name_admin(usr)] is debugging the [antag.role_text] template.")
/client/proc/debug_controller(controller in list("Master","Ticker","Ticker Process","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants","Alarm","Nano","Chemistry"))
/client/proc/debug_controller(controller in list("Master","Ticker","Ticker Process","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants","Alarm","Nano","Chemistry","Vote"))
set category = "Debug"
set name = "Debug Controller"
set desc = "Debug the various periodic loop controllers for the game (be careful!)"
@@ -92,5 +92,8 @@
if("Chemistry")
debug_variables(chemistryProcess)
feedback_add_details("admin_verb", "DChem")
if("Vote")
debug_variables(vote)
feedback_add_details("admin_verb", "DVote")
message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.")
return

View File

@@ -1,9 +1,15 @@
var/datum/controller/vote/vote = new()
var/global/list/round_voters = list() //Keeps track of the individuals voting for a given round, for use in forcedrafting.
var/global/list/round_voters = list() // Keeps track of the individuals voting for a given round, for use in forcedrafting.
datum/controller/vote
var/initiator = null
#define VOTE_RESTART "restart"
#define VOTE_GAMEMODE "gamemode"
#define VOTE_CREW_TRANSFER "crew_transfer"
#define VOTE_ADD_ANTAGONIST "add_antagonist"
#define VOTE_CUSTOM "custom"
/datum/controller/vote
var/initiator = null // Key of the one who started the vote or "the server"
var/started_time = null
var/time_remaining = 0
var/mode = null
@@ -11,385 +17,366 @@ datum/controller/vote
var/list/choices = list()
var/list/gamemode_names = list()
var/list/voted = list()
var/list/voting = list()
var/list/current_votes = list()
var/list/additional_text = list()
var/auto_muted = 0
New()
if(vote != src)
if(istype(vote))
del(vote)
vote = src
/datum/controller/vote/New()
if(vote != src)
if(istype(vote))
del(vote)
vote = src
proc/process() //called by master_controller
if(mode)
// No more change mode votes after the game has started.
// 3 is GAME_STATE_PLAYING, but that #define is undefined for some reason
if(mode == "gamemode" && ticker.current_state >= 2)
world << "<b>Voting aborted due to game start.</b>"
src.reset()
return
/datum/controller/vote/proc/process() //called by master_controller
if(mode)
// No more change mode votes after the game has started.
if(mode == VOTE_GAMEMODE && ticker.current_state >= GAME_STATE_SETTING_UP)
world << "<b>Voting aborted due to game start.</b>"
src.reset()
return
// Calculate how much time is remaining by comparing current time, to time of vote start,
// plus vote duration
time_remaining = round((started_time + config.vote_period - world.time)/10)
if(time_remaining < 0)
result()
for(var/client/C in voting)
if(C)
C << browse(null,"window=vote")
reset()
else
for(var/client/C in voting)
if(C)
C << browse(vote.interface(C),"window=vote")
voting.Cut()
proc/autotransfer()
initiate_vote("crew_transfer","the server", 1)
log_debug("The server has called a crew transfer vote")
proc/autogamemode()
initiate_vote("gamemode","the server", 1)
log_debug("The server has called a gamemode vote")
proc/reset()
initiator = null
time_remaining = 0
mode = null
question = null
choices.Cut()
voted.Cut()
voting.Cut()
current_votes.Cut()
additional_text.Cut()
proc/get_result()
//get the highest number of votes
var/greatest_votes = 0
var/total_votes = 0
for(var/option in choices)
var/votes = choices[option]
total_votes += votes
if(votes > greatest_votes)
greatest_votes = votes
//default-vote for everyone who didn't vote
if(!config.vote_no_default && choices.len)
var/non_voters = (clients.len - total_votes)
if(non_voters > 0)
if(mode == "restart")
choices["Continue Playing"] += non_voters
if(choices["Continue Playing"] >= greatest_votes)
greatest_votes = choices["Continue Playing"]
else if(mode == "gamemode")
if(master_mode in choices)
choices[master_mode] += non_voters
if(choices[master_mode] >= greatest_votes)
greatest_votes = choices[master_mode]
else if(mode == "crew_transfer")
var/factor = 0.5
switch(world.time / (10 * 60)) // minutes
if(0 to 60)
factor = 0.5
if(61 to 120)
factor = 0.8
if(121 to 240)
factor = 1
if(241 to 300)
factor = 1.2
else
factor = 1.4
choices["Initiate Crew Transfer"] = round(choices["Initiate Crew Transfer"] * factor)
world << "<font color='purple'>Crew Transfer Factor: [factor]</font>"
greatest_votes = max(choices["Initiate Crew Transfer"], choices["Continue The Round"])
//get all options with that many votes and return them in a list
. = list()
if(greatest_votes)
for(var/option in choices)
if(choices[option] == greatest_votes)
. += option
return .
proc/announce_result()
var/list/winners = get_result()
var/text
if(winners.len > 0)
if(winners.len > 1)
if(mode != "gamemode" || ticker.hide_mode == 0) // Here we are making sure we don't announce potential game modes
text = "<b>Vote Tied Between:</b>\n"
for(var/option in winners)
text += "\t[option]\n"
. = pick(winners)
for(var/key in current_votes)
if(choices[current_votes[key]] == .)
round_voters += key // Keep track of who voted for the winning round.
if((mode == "gamemode" && . == "Extended") || ticker.hide_mode == 0) // Announce Extended gamemode, but not other gamemodes
text += "<b>Vote Result: [.]</b>"
else
if(mode != "gamemode")
text += "<b>Vote Result: [.]</b>"
else
text += "<b>The vote has ended.</b>" // What will be shown if it is a gamemode vote that isn't extended
else
text += "<b>Vote Result: Inconclusive - No Votes!</b>"
if(mode == "add_antagonist")
antag_add_failed = 1
log_vote(text)
world << "<font color='purple'>[text]</font>"
return .
proc/result()
. = announce_result()
var/restart = 0
if(.)
switch(mode)
if("restart")
if(. == "Restart Round")
restart = 1
if("gamemode")
if(master_mode != .)
world.save_mode(.)
if(ticker && ticker.mode)
restart = 1
else
master_mode = .
if("crew_transfer")
if(. == "Initiate Crew Transfer")
init_shift_change(null, 1)
if("add_antagonist")
if(isnull(.) || . == "None")
antag_add_failed = 1
else
additional_antag_types |= antag_names_to_ids[.]
if(mode == "gamemode") //fire this even if the vote fails.
if(!round_progressing)
round_progressing = 1
world << "<font color='red'><b>The round will start soon.</b></font>"
if(restart)
world << "World restarting due to vote..."
feedback_set_details("end_error","restart vote")
if(blackbox) blackbox.save_all_data_to_sql()
sleep(50)
log_game("Rebooting due to restart vote")
world.Reboot()
return .
proc/submit_vote(var/ckey, var/vote)
if(mode)
if(config.vote_no_dead && usr.stat == DEAD && !usr.client.holder)
return 0
if(vote && vote >= 1 && vote <= choices.len)
if(current_votes[ckey])
choices[choices[current_votes[ckey]]]--
voted += usr.ckey
choices[choices[vote]]++ //check this
current_votes[ckey] = vote
return vote
return 0
proc/initiate_vote(var/vote_type, var/initiator_key, var/automatic = 0)
if(!mode)
if(started_time != null && !(check_rights(R_ADMIN) || automatic))
var/next_allowed_time = (started_time + config.vote_delay)
if(next_allowed_time > world.time)
return 0
// Calculate how much time is remaining by comparing current time, to time of vote start,
// plus vote duration
time_remaining = round((started_time + config.vote_period - world.time)/10)
if(time_remaining < 0)
result()
reset()
switch(vote_type)
if("restart")
choices.Add("Restart Round","Continue Playing")
if("gamemode")
if(ticker.current_state >= 2)
return 0
choices.Add(config.votable_modes)
for (var/F in choices)
var/datum/game_mode/M = gamemode_cache[F]
if(!M)
continue
gamemode_names[M.config_tag] = capitalize(M.name) //It's ugly to put this here but it works
additional_text.Add("<td align = 'center'>[M.required_players]</td>")
gamemode_names["secret"] = "Secret"
if("crew_transfer")
if(check_rights(R_ADMIN|R_MOD, 0))
question = "End the shift?"
choices.Add("Initiate Crew Transfer", "Continue The Round")
/datum/controller/vote/proc/autotransfer()
initiate_vote(VOTE_CREW_TRANSFER, "the server", 1)
log_debug("The server has called a crew transfer vote")
/datum/controller/vote/proc/autogamemode()
initiate_vote(VOTE_GAMEMODE, "the server", 1)
log_debug("The server has called a gamemode vote")
/datum/controller/vote/proc/reset()
initiator = null
time_remaining = 0
mode = null
question = null
choices.Cut()
voted.Cut()
current_votes.Cut()
additional_text.Cut()
/datum/controller/vote/proc/get_result() // Get the highest number of votes
var/greatest_votes = 0
var/total_votes = 0
for(var/option in choices)
var/votes = choices[option]
total_votes += votes
if(votes > greatest_votes)
greatest_votes = votes
if(!config.vote_no_default && choices.len) // Default-vote for everyone who didn't vote
var/non_voters = (clients.len - total_votes)
if(non_voters > 0)
if(mode == VOTE_RESTART)
choices["Continue Playing"] += non_voters
if(choices["Continue Playing"] >= greatest_votes)
greatest_votes = choices["Continue Playing"]
else if(mode == VOTE_GAMEMODE)
if(master_mode in choices)
choices[master_mode] += non_voters
if(choices[master_mode] >= greatest_votes)
greatest_votes = choices[master_mode]
else if(mode == VOTE_CREW_TRANSFER)
var/factor = 0.5
switch(world.time / (10 * 60)) // minutes
if(0 to 60)
factor = 0.5
if(61 to 120)
factor = 0.8
if(121 to 240)
factor = 1
if(241 to 300)
factor = 1.2
else
if (get_security_level() == "red" || get_security_level() == "delta")
initiator_key << "The current alert status is too high to call for a crew transfer!"
return 0
if(ticker.current_state <= 2)
return 0
initiator_key << "The crew transfer button has been disabled!"
question = "End the shift?"
choices.Add("Initiate Crew Transfer", "Continue The Round")
if("add_antagonist")
if(!config.allow_extra_antags || ticker.current_state >= 2)
return 0
for(var/antag_type in all_antag_types)
var/datum/antagonist/antag = all_antag_types[antag_type]
if(!(antag.id in additional_antag_types) && antag.is_votable())
choices.Add(antag.role_text)
choices.Add("None")
if("custom")
question = sanitizeSafe(input(usr,"What is the vote for?") as text|null)
if(!question) return 0
for(var/i=1,i<=10,i++)
var/option = capitalize(sanitize(input(usr,"Please enter an option or hit cancel to finish") as text|null))
if(!option || mode || !usr.client) break
choices.Add(option)
else
return 0
mode = vote_type
initiator = initiator_key
started_time = world.time
var/text = "[capitalize(mode)] vote started by [initiator]."
if(mode == "custom")
text += "\n[question]"
factor = 1.4
choices["Initiate Crew Transfer"] = round(choices["Initiate Crew Transfer"] * factor)
world << "<font color='purple'>Crew Transfer Factor: [factor]</font>"
greatest_votes = max(choices["Initiate Crew Transfer"], choices["Continue The Round"])
log_vote(text)
world << "<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=\ref[src]'>here</a> to place your votes.\nYou have [config.vote_period/10] seconds to vote.</font>"
switch(vote_type)
if("crew_transfer")
world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3)
if("gamemode")
world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3)
if("custom")
world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3)
if(mode == "gamemode" && round_progressing)
round_progressing = 0
world << "<font color='red'><b>Round start has been delayed.</b></font>"
. = list() // Get all options with that many votes and return them in a list
if(greatest_votes)
for(var/option in choices)
if(choices[option] == greatest_votes)
. += option
time_remaining = round(config.vote_period/10)
return 1
return 0
/datum/controller/vote/proc/announce_result()
var/list/winners = get_result()
var/text
if(winners.len > 0)
if(winners.len > 1)
if(mode != VOTE_GAMEMODE || ticker.hide_mode == 0) // Here we are making sure we don't announce potential game modes
text = "<b>Vote Tied Between:</b>\n"
for(var/option in winners)
text += "\t[option]\n"
. = pick(winners)
proc/interface(var/client/C)
if(!C) return
var/admin = 0
var/trialmin = 0
if(C.holder)
if(C.holder.rights & R_ADMIN)
admin = 1
trialmin = 1 // don't know why we use both of these it's really weird, but I'm 2 lasy to refactor this all to use just admin.
voting |= C
. = "<html><head><title>Voting Panel</title></head><body>"
if(mode)
if(question) . += "<h2>Vote: '[question]'</h2>"
else . += "<h2>Vote: [capitalize(mode)]</h2>"
. += "Time Left: [time_remaining] s<hr>"
. += "<table width = '100%'><tr><td align = 'center'><b>Choices</b></td><td align = 'center'><b>Votes</b></td>"
if(capitalize(mode) == "Gamemode") .+= "<td align = 'center'><b>Minimum Players</b></td></tr>"
for(var/i = 1, i <= choices.len, i++)
var/votes = choices[choices[i]]
if(!votes) votes = 0
. += "<tr>"
if(mode == "gamemode")
if(current_votes[C.ckey] == i)
. += "<td><b><a href='?src=\ref[src];vote=[i]'>[gamemode_names[choices[i]]]</a></b></td><td align = 'center'>[votes]</td>"
else
. += "<td><a href='?src=\ref[src];vote=[i]'>[gamemode_names[choices[i]]]</a></td><td align = 'center'>[votes]</td>"
else
if(current_votes[C.ckey] == i)
. += "<td><b><a href='?src=\ref[src];vote=[i]'>[choices[i]]</a></b></td><td align = 'center'>[votes]</td>"
else
. += "<td><a href='?src=\ref[src];vote=[i]'>[choices[i]]</a></td><td align = 'center'>[votes]</td>"
if (additional_text.len >= i)
. += additional_text[i]
. += "</tr>"
. += "</table><hr>"
if(admin)
. += "(<a href='?src=\ref[src];vote=cancel'>Cancel Vote</a>) "
for(var/key in current_votes)
if(choices[current_votes[key]] == .)
round_voters += key // Keep track of who voted for the winning round.
if(mode != VOTE_GAMEMODE || . == "Extended" || ticker.hide_mode == 0) // Announce Extended gamemode, but not other gamemodes
text += "<b>Vote Result: [.]</b>"
else
. += "<h2>Start a vote:</h2><hr><ul><li>"
//restart
if(trialmin || config.allow_vote_restart)
. += "<a href='?src=\ref[src];vote=restart'>Restart</a>"
else
. += "<font color='grey'>Restart (Disallowed)</font>"
. += "</li><li>"
if(trialmin || config.allow_vote_restart)
. += "<a href='?src=\ref[src];vote=crew_transfer'>Crew Transfer</a>"
else
. += "<font color='grey'>Crew Transfer (Disallowed)</font>"
if(trialmin)
. += "\t(<a href='?src=\ref[src];vote=toggle_restart'>[config.allow_vote_restart?"Allowed":"Disallowed"]</a>)"
. += "</li><li>"
//gamemode
if(trialmin || config.allow_vote_mode)
. += "<a href='?src=\ref[src];vote=gamemode'>GameMode</a>"
else
. += "<font color='grey'>GameMode (Disallowed)</font>"
if(trialmin)
. += "\t(<a href='?src=\ref[src];vote=toggle_gamemode'>[config.allow_vote_mode?"Allowed":"Disallowed"]</a>)"
. += "</li><li>"
//extra antagonists
if(!antag_add_failed && config.allow_extra_antags)
. += "<a href='?src=\ref[src];vote=add_antagonist'>Add Antagonist Type</a>"
else
. += "<font color='grey'>Restart (Disallowed)</font>"
. += "</li>"
//custom
if(trialmin)
. += "<li><a href='?src=\ref[src];vote=custom'>Custom</a></li>"
. += "</ul><hr>"
. += "<a href='?src=\ref[src];vote=close' style='position:absolute;right:50px'>Close</a></body></html>"
return .
text += "<b>The vote has ended.</b>"
else
text += "<b>Vote Result: Inconclusive - No Votes!</b>"
if(mode == VOTE_ADD_ANTAGONIST)
antag_add_failed = 1
log_vote(text)
world << "<font color='purple'>[text]</font>"
Topic(href,href_list[],hsrc)
if(!usr || !usr.client) return //not necessary but meh...just in-case somebody does something stupid
switch(href_list["vote"])
if("close")
voting -= usr.client
usr << browse(null, "window=vote")
return
if("cancel")
if(usr.client.holder)
reset()
if("toggle_restart")
if(usr.client.holder)
config.allow_vote_restart = !config.allow_vote_restart
if("toggle_gamemode")
if(usr.client.holder)
config.allow_vote_mode = !config.allow_vote_mode
if("restart")
if(config.allow_vote_restart || usr.client.holder)
initiate_vote("restart",usr.key)
if("gamemode")
if(config.allow_vote_mode || usr.client.holder)
initiate_vote("gamemode",usr.key)
if("crew_transfer")
if(config.allow_vote_restart || usr.client.holder)
initiate_vote("crew_transfer",usr.key)
if("add_antagonist")
if(config.allow_extra_antags)
initiate_vote("add_antagonist",usr.key)
if("custom")
if(usr.client.holder)
initiate_vote("custom",usr.key)
/datum/controller/vote/proc/result()
. = announce_result()
var/restart = 0
if(.)
switch(mode)
if(VOTE_RESTART)
if(. == "Restart Round")
restart = 1
if(VOTE_GAMEMODE)
if(master_mode != .)
world.save_mode(.)
if(ticker && ticker.mode)
restart = 1
else
master_mode = .
if(VOTE_CREW_TRANSFER)
if(. == "Initiate Crew Transfer")
init_shift_change(null, 1)
if(VOTE_ADD_ANTAGONIST)
if(isnull(.) || . == "None")
antag_add_failed = 1
else
additional_antag_types |= antag_names_to_ids[.]
if(mode == VOTE_GAMEMODE) //fire this even if the vote fails.
if(!round_progressing)
round_progressing = 1
world << "<font color='red'><b>The round will start soon.</b></font>"
if(restart)
world << "World restarting due to vote..."
feedback_set_details("end_error", "restart vote")
if(blackbox)
blackbox.save_all_data_to_sql()
sleep(50)
log_game("Rebooting due to restart vote")
world.Reboot()
/datum/controller/vote/proc/submit_vote(var/ckey, var/newVote)
if(mode)
if(config.vote_no_dead && usr.stat == DEAD && !usr.client.holder)
return
if(current_votes[ckey])
choices[choices[current_votes[ckey]]]--
if(newVote && newVote >= 1 && newVote <= choices.len)
choices[choices[newVote]]++
current_votes[ckey] = newVote
else
current_votes[ckey] = null
/datum/controller/vote/proc/initiate_vote(var/vote_type, var/initiator_key, var/automatic = 0)
if(!mode)
if(started_time != null && !(check_rights(R_ADMIN) || automatic))
var/next_allowed_time = (started_time + config.vote_delay)
if(next_allowed_time > world.time)
return 0
reset()
switch(vote_type)
if(VOTE_RESTART)
choices.Add("Restart Round", "Continue Playing")
if(VOTE_GAMEMODE)
if(ticker.current_state >= GAME_STATE_SETTING_UP)
return 0
choices.Add(config.votable_modes)
for(var/F in choices)
var/datum/game_mode/M = gamemode_cache[F]
if(!M)
continue
gamemode_names[M.config_tag] = capitalize(M.name) //It's ugly to put this here but it works
additional_text.Add("<td align = 'center'>[M.required_players]</td>")
gamemode_names["secret"] = "Secret"
if(VOTE_CREW_TRANSFER)
if(!check_rights(R_ADMIN|R_MOD, 0)) // The gods care not for the affairs of the mortals
if(get_security_level() == "red" || get_security_level() == "delta")
initiator_key << "The current alert status is too high to call for a crew transfer!"
return 0
if(ticker.current_state <= GAME_STATE_SETTING_UP)
initiator_key << "The crew transfer button has been disabled!"
return 0
question = "End the shift?"
choices.Add("Initiate Crew Transfer", "Continue The Round")
if(VOTE_ADD_ANTAGONIST)
if(!config.allow_extra_antags || ticker.current_state >= GAME_STATE_SETTING_UP)
return 0
for(var/antag_type in all_antag_types)
var/datum/antagonist/antag = all_antag_types[antag_type]
if(!(antag.id in additional_antag_types) && antag.is_votable())
choices.Add(antag.role_text)
choices.Add("None")
if(VOTE_CUSTOM)
question = sanitizeSafe(input(usr, "What is the vote for?") as text|null)
if(!question)
return 0
for(var/i = 1 to 10)
var/option = capitalize(sanitize(input(usr, "Please enter an option or hit cancel to finish") as text|null))
if(!option || mode || !usr.client)
break
choices.Add(option)
else
var/t = round(text2num(href_list["vote"]))
if(t) // It starts from 1, so there's no problem
submit_vote(usr.ckey, t)
usr.vote()
return 0
mode = vote_type
initiator = initiator_key
started_time = world.time
var/text = "[capitalize(mode)] vote started by [initiator]."
if(mode == VOTE_CUSTOM)
text += "\n[question]"
/mob/verb/vote()
log_vote(text)
world << "<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=\ref[src]'>here</a> to place your votes.\nYou have [config.vote_period / 10] seconds to vote.</font>"
if(vote_type == VOTE_CREW_TRANSFER || vote_type == VOTE_GAMEMODE || vote_type == VOTE_CUSTOM)
world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3)
if(mode == VOTE_GAMEMODE && round_progressing)
round_progressing = 0
world << "<font color='red'><b>Round start has been delayed.</b></font>"
time_remaining = round(config.vote_period / 10)
return 1
return 0
/datum/controller/vote/proc/interface(var/client/C)
if(!istype(C))
return
var/admin = 0
if(C.holder)
if(C.holder.rights & R_ADMIN)
admin = 1
. = "<html><head><title>Voting Panel</title></head><body>"
if(mode)
if(question)
. += "<h2>Vote: '[question]'</h2>"
else
. += "<h2>Vote: [capitalize(mode)]</h2>"
. += "Time Left: [time_remaining] s<hr>"
. += "<table width = '100%'><tr><td align = 'center'><b>Choices</b></td><td align = 'center'><b>Votes</b></td>"
if(mode == VOTE_GAMEMODE)
.+= "<td align = 'center'><b>Minimum Players</b></td></tr>"
for(var/i = 1 to choices.len)
var/votes = choices[choices[i]]
if(!votes)
votes = 0
. += "<tr>"
var/thisVote = (current_votes[C.ckey] == i)
if(mode == VOTE_GAMEMODE)
. += "<td>[thisVote ? "<b>" : ""]<a href='?src=\ref[src];vote=[i]'>[gamemode_names[choices[i]]]</a>[thisVote ? "</b>" : ""]</td><td align = 'center'>[votes]</td>"
else
. += "<td>[thisVote ? "<b>" : ""]<a href='?src=\ref[src];vote=[i]'>[choices[i]]</a>[thisVote ? "</b>" : ""]</td><td align = 'center'>[votes]</td>"
if (additional_text.len >= i)
. += additional_text[i]
. += "</tr>"
. += "<tr><td><a href='?src=\ref[src];vote=unvote'>Unvote</a></td></tr>"
. += "</table><hr>"
if(admin)
. += "(<a href='?src=\ref[src];vote=cancel'>Cancel Vote</a>) "
else
. += "<h2>Start a vote:</h2><hr><ul><li>"
if(admin || config.allow_vote_restart)
. += "<a href='?src=\ref[src];vote=restart'>Restart</a>"
else
. += "<font color='grey'>Restart (Disallowed)</font>"
. += "</li><li>"
if(admin || config.allow_vote_restart)
. += "<a href='?src=\ref[src];vote=crew_transfer'>Crew Transfer</a>"
else
. += "<font color='grey'>Crew Transfer (Disallowed)</font>"
if(admin)
. += "\t(<a href='?src=\ref[src];vote=toggle_restart'>[config.allow_vote_restart ? "Allowed" : "Disallowed"]</a>)"
. += "</li><li>"
if(admin || config.allow_vote_mode)
. += "<a href='?src=\ref[src];vote=gamemode'>GameMode</a>"
else
. += "<font color='grey'>GameMode (Disallowed)</font>"
if(admin)
. += "\t(<a href='?src=\ref[src];vote=toggle_gamemode'>[config.allow_vote_mode ? "Allowed" : "Disallowed"]</a>)"
. += "</li><li>"
if(!antag_add_failed && config.allow_extra_antags)
. += "<a href='?src=\ref[src];vote=add_antagonist'>Add Antagonist Type</a>"
else
. += "<font color='grey'>Add Antagonist (Disallowed)</font>"
. += "</li>"
if(admin)
. += "<li><a href='?src=\ref[src];vote=custom'>Custom</a></li>"
. += "</ul><hr>"
. += "<a href='?src=\ref[src];vote=close' style='position:absolute;right:50px'>Close</a></body></html>"
/datum/controller/vote/Topic(href, href_list[])
if(!usr || !usr.client)
return
switch(href_list["vote"])
if("close")
usr << browse(null, "window=vote")
return
if("cancel")
if(usr.client.holder)
reset()
if("toggle_restart")
if(usr.client.holder)
config.allow_vote_restart = !config.allow_vote_restart
if("toggle_gamemode")
if(usr.client.holder)
config.allow_vote_mode = !config.allow_vote_mode
if(VOTE_RESTART)
if(config.allow_vote_restart || usr.client.holder)
initiate_vote(VOTE_RESTART, usr.key)
if(VOTE_GAMEMODE)
if(config.allow_vote_mode || usr.client.holder)
initiate_vote(VOTE_GAMEMODE, usr.key)
if(VOTE_CREW_TRANSFER)
if(config.allow_vote_restart || usr.client.holder)
initiate_vote(VOTE_CREW_TRANSFER, usr.key)
if(VOTE_ADD_ANTAGONIST)
if(config.allow_extra_antags || usr.client.holder)
initiate_vote(VOTE_ADD_ANTAGONIST, usr.key)
if(VOTE_CUSTOM)
if(usr.client.holder)
initiate_vote(VOTE_CUSTOM, usr.key)
if("unvote")
submit_vote(usr.ckey, null)
else
var/t = round(text2num(href_list["vote"]))
if(t) // It starts from 1, so there's no problem
submit_vote(usr.ckey, t)
usr.client.vote()
/client/verb/vote()
set category = "OOC"
set name = "Vote"
if(vote)
src << browse(vote.interface(client),"window=vote")
src << browse(vote.interface(src), "window=vote;size=500x[300 + vote.choices.len * 25]")

View File

@@ -74,11 +74,21 @@
if(real_rank in civilian_positions)
civ[name] = rank
department = 1
if(real_rank in nonhuman_positions)
bot[name] = rank
department = 1
if(!department && !(name in heads))
misc[name] = rank
// Synthetics don't have actual records, so we will pull them from here.
for(var/mob/living/silicon/ai/ai in mob_list)
bot[ai.name] = "Artificial Intelligence"
for(var/mob/living/silicon/robot/robot in mob_list)
// No combat/syndicate cyborgs, no drones.
if(robot.module && robot.module.hide_on_manifest)
continue
bot[robot.name] = "[robot.modtype] [robot.braintype]"
if(heads.len > 0)
dat += "<tr><th colspan=3>Heads</th></tr>"
for(name in heads)

View File

@@ -109,6 +109,8 @@
output += "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
obj_count++
if(ambitions)
output += "<HR><B>Ambitions:</B> [ambitions]<br>"
recipient << browse(output,"window=memory")
/datum/mind/proc/edit_memory()
@@ -142,7 +144,8 @@
else
out += "None."
out += "<br><a href='?src=\ref[src];obj_add=1'>\[add\]</a>"
out += "<br><a href='?src=\ref[src];obj_add=1'>\[add\]</a><br><br>"
out += "<b>Ambitions:</b> [ambitions ? ambitions : "None"] <a href='?src=\ref[src];amb_edit=\ref[src]'>\[edit\]</a></br>"
usr << browse(out, "window=edit_memory[src]")
/datum/mind/Topic(href, href_list)
@@ -182,6 +185,18 @@
if (isnull(new_memo)) return
memory = new_memo
else if (href_list["amb_edit"])
var/datum/mind/mind = locate(href_list["amb_edit"])
if(!mind)
return
var/new_ambition = input("Enter a new ambition", "Memory", mind.ambitions) as null|message
if(isnull(new_ambition))
return
if(mind)
mind.ambitions = sanitize(new_ambition)
mind.current << "<span class='warning'>Your ambitions have been changed by higher powers, they are now: [mind.ambitions]</span>"
log_and_message_admins("made [key_name(mind.current)]'s ambitions be '[mind.ambitions]'.")
else if (href_list["obj_edit"] || href_list["obj_add"])
var/datum/objective/objective
var/objective_pos

View File

@@ -0,0 +1,43 @@
/datum/progressbar
var/goal = 1
var/image/bar
var/shown = 0
var/mob/user
var/client/client
/datum/progressbar/New(mob/user, goal_number, atom/target)
. = ..()
if(!target) target = user
if (!istype(target))
EXCEPTION("Invalid target given")
if (goal_number)
goal = goal_number
bar = image('icons/effects/progessbar.dmi', target, "prog_bar_0")
bar.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
bar.pixel_y = 32
src.user = user
if(user)
client = user.client
/datum/progressbar/Destroy()
if (client)
client.images -= bar
qdel(bar)
. = ..()
/datum/progressbar/proc/update(progress)
//world << "Update [progress] - [goal] - [(progress / goal)] - [((progress / goal) * 100)] - [round(((progress / goal) * 100), 5)]"
if (!user || !user.client)
shown = 0
return
if (user.client != client)
if (client)
client.images -= bar
shown = 0
client = user.client
progress = Clamp(progress, 0, goal)
bar.icon_state = "prog_bar_[round(((progress / goal) * 100), 5)]"
if (!shown && user.is_preference_enabled(/datum/client_preference/show_progress_bar))
user.client.images += bar
shown = 1

View File

@@ -69,23 +69,38 @@
break
return .
/datum/recipe/proc/check_items(var/obj/machinery/microwave/container as obj)
/datum/recipe/proc/check_items(var/obj/container as obj)
. = 1
if (items && items.len)
var/list/checklist = list()
checklist = items.Copy() // You should really trust Copy
for(var/obj/O in container.ingredient_list)
if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/grown))
continue // Fruit is handled in check_fruit().
var/found = 0
for(var/i = 1; i < checklist.len+1; i++)
var/item_type = checklist[i]
if (istype(O,item_type))
checklist.Cut(i, i+1)
found = 1
break
if (!found)
. = 0
if(istype(container, /obj/machinery))
var/obj/machinery/machine = container
for(var/obj/O in (machine.contents - machine.component_parts))
if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/grown))
continue // Fruit is handled in check_fruit().
var/found = 0
for(var/i = 1; i < checklist.len+1; i++)
var/item_type = checklist[i]
if (istype(O,item_type))
checklist.Cut(i, i+1)
found = 1
break
if (!found)
. = 0
else
for(var/obj/O in container.contents)
if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/grown))
continue // Fruit is handled in check_fruit().
var/found = 0
for(var/i = 1; i < checklist.len+1; i++)
var/item_type = checklist[i]
if (istype(O,item_type))
checklist.Cut(i, i+1)
found = 1
break
if (!found)
. = 0
if (checklist.len)
. = -1
return .
@@ -93,25 +108,39 @@
//general version
/datum/recipe/proc/make(var/obj/container as obj)
var/obj/result_obj = new result(container)
for (var/obj/O in (container.contents-result_obj))
O.reagents.trans_to_obj(result_obj, O.reagents.total_volume)
qdel(O)
if(istype(container, /obj/machinery))
var/obj/machinery/machine = container
for (var/obj/O in ((machine.contents-result_obj)-machine.component_parts))
O.reagents.trans_to_obj(result_obj, O.reagents.total_volume)
qdel(O)
else
for (var/obj/O in (container.contents-result_obj))
O.reagents.trans_to_obj(result_obj, O.reagents.total_volume)
qdel(O)
container.reagents.clear_reagents()
return result_obj
// food-related
/datum/recipe/proc/make_food(var/obj/machinery/microwave/container as obj)
/datum/recipe/proc/make_food(var/obj/container as obj)
if(!result)
world << "<span class='danger'>Recipe [type] is defined without a result, please bug this.</span>"
return
var/obj/result_obj = new result(container)
for (var/obj/O in (container.ingredient_list)) //We no longer need to take result_obj out of the list, since it doesn't exist in the list.
if (O.reagents)
O.reagents.del_reagent("nutriment")
O.reagents.update_total()
O.reagents.trans_to_obj(result_obj, O.reagents.total_volume)
qdel(O)
container.ingredient_list.Cut() //Trust in Cut().
if(istype(container, /obj/machinery))
var/obj/machinery/machine = container
for (var/obj/O in ((machine.contents-result_obj)-machine.component_parts))
if (O.reagents)
O.reagents.del_reagent("nutriment")
O.reagents.update_total()
O.reagents.trans_to_obj(result_obj, O.reagents.total_volume)
qdel(O)
else
for (var/obj/O in (container.contents-result_obj))
if (O.reagents)
O.reagents.del_reagent("nutriment")
O.reagents.update_total()
O.reagents.trans_to_obj(result_obj, O.reagents.total_volume)
qdel(O)
container.reagents.clear_reagents()
return result_obj

View File

@@ -221,6 +221,12 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
name = "Janitorial supplies"
contains = list(/obj/item/weapon/reagent_containers/glass/bucket,
/obj/item/weapon/mop,
/obj/item/clothing/under/rank/janitor,
/obj/item/weapon/cartridge/janitor,
/obj/item/clothing/gloves/black,
/obj/item/clothing/head/soft/purple,
/obj/item/weapon/storage/belt/janitor,
/obj/item/clothing/shoes/galoshes,
/obj/item/weapon/caution,
/obj/item/weapon/caution,
/obj/item/weapon/caution,
@@ -1635,6 +1641,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
num_contained = 4
contains = list(/obj/item/clothing/accessory/storage/black_vest,
/obj/item/clothing/accessory/storage/brown_vest,
/obj/item/clothing/accessory/storage/white_vest,
/obj/item/clothing/accessory/storage/webbing)
cost = 15
containertype = "/obj/structure/closet/crate"
@@ -2074,7 +2081,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
/obj/item/weapon/cartridge/medical,
/obj/item/device/flashlight/pen,
/obj/item/weapon/reagent_containers/syringe,
/obj/item/clothing/accessory/storage/brown_vest)
/obj/item/clothing/accessory/storage/white_vest)
cost = 20
containertype = "/obj/structure/closet/crate/secure"
containername = "Paramedic equipment"

View File

@@ -129,6 +129,13 @@
icon_state = "nullrod"
item_state = "foldcane"
/obj/item/weapon/cane/whitecane
name = "white cane"
desc = "A cane used by the blind."
icon = 'icons/obj/weapons.dmi'
icon_state = "whitecane"
item_state = "whitecane"
/obj/item/weapon/disk
name = "disk"
icon = 'icons/obj/items.dmi'

View File

@@ -30,6 +30,12 @@
if(faction_verb && player.current)
player.current.verbs |= faction_verb
spawn(1 SECOND) //Added a delay so that this should pop up at the bottom and not the top of the text flood the new antag gets.
player.current << "<span class='notice'>Once you decide on a goal to pursue, you can optionally display it to \
everyone at the end of the shift with the <b>Set Ambition</b> verb, located in the IC tab. You can change this at any time, \
and it otherwise has no bearing on your round.</span>"
player.current.verbs |= /mob/living/proc/write_ambition
// Handle only adding a mind and not bothering with gear etc.
if(nonstandard_role_type)
faction_members |= player
@@ -50,5 +56,8 @@
player.special_role = null
update_icons_removed(player)
BITSET(player.current.hud_updateflag, SPECIALROLE_HUD)
if(!is_special_character(player))
player.current.verbs -= /mob/living/proc/write_ambition
player.ambitions = ""
return 1
return 0

View File

@@ -104,17 +104,6 @@
create_nuke()
show_objectives(player)
player.current << "<span class='notice'>Once you decide on a goal to pursue, you can optionally display it to \
everyone at the end of the shift with the <b>Set Ambition</b> verb, located in the IC tab. You can change this at any time, \
and it otherwise has no bearing on your round.</span>"
player.current.verbs |= /mob/living/proc/write_ambition
// Clown clumsiness check, I guess downstream might use it.
if (player.current.mind)
if (player.current.mind.assigned_role == "Clown")
player.current << "You have evolved beyond your clownish nature, allowing you to wield weapons without harming yourself."
player.current.mutations.Remove(CLUMSY)
return 1
/datum/antagonist/proc/set_antag_name(var/mob/living/player)

View File

@@ -37,14 +37,19 @@
if(!mind)
return
if(!src.mind.special_role)
if(!is_special_character(mind))
src << "<span class='warning'>While you may perhaps have goals, this verb's meant to only be visible \
to antagonists. Please make a bug report!</span>"
return
var/new_ambitions = input(src, "Write a short sentence of what your character hopes to accomplish \
today as an antagonist. Remember that this is purely optional. It will be shown at the end of the \
round for everybody else.", "Ambitions", mind.ambitions) as null|message
if(isnull(new_ambitions))
return
mind.ambitions = new_ambitions
new_ambitions = sanitize(new_ambitions)
if(new_ambitions)
mind.ambitions = new_ambitions
src << "<span class='notice'>You've set your goal to be '[new_ambitions]'.</span>"
else
src << "<span class='notice'>You leave your ambitions behind.</span>"
log_and_message_admins("has set their ambitions to now be: [new_ambitions].")

View File

@@ -9,7 +9,7 @@
text += get_special_objective_text(P)
if(P.ambitions)
text += "<br>Their goals for today were..."
text += "<br><b>[P.ambitions]</b>"
text += "<br><span class='notice'>[P.ambitions]</span>"
if(!global_objectives.len && P.objectives && P.objectives.len)
var/failed
var/num = 1

View File

@@ -27,7 +27,7 @@ var/datum/antagonist/raider/raiders
/obj/item/clothing/under/serviceoveralls,
/obj/item/clothing/under/captain_fly,
/obj/item/clothing/under/det,
/obj/item/clothing/under/brown,
/obj/item/clothing/under/color/brown,
)
var/list/raider_shoes = list(

View File

@@ -76,7 +76,7 @@ var/datum/antagonist/wizard/wizards
return 0
wizard_mob.equip_to_slot_or_del(new /obj/item/device/radio/headset(wizard_mob), slot_l_ear)
wizard_mob.equip_to_slot_or_del(new /obj/item/clothing/under/lightpurple(wizard_mob), slot_w_uniform)
wizard_mob.equip_to_slot_or_del(new /obj/item/clothing/under/color/lightpurple(wizard_mob), slot_w_uniform)
wizard_mob.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(wizard_mob), slot_shoes)
wizard_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe(wizard_mob), slot_wear_suit)
wizard_mob.equip_to_slot_or_del(new /obj/item/clothing/head/wizard(wizard_mob), slot_head)

View File

@@ -838,6 +838,10 @@ area/space/atmosalert()
/area/maintenance/engineering
name = "Engineering Maintenance"
icon_state = "maint_engineering"
/area/maintenance/engineering/pumpstation
name = "Engineering Pump Station"
icon_state = "maint_pumpstation"
/area/maintenance/evahallway
name = "\improper EVA Maintenance"

View File

@@ -0,0 +1,12 @@
/datum/absorbed_dna
var/name
var/datum/dna/dna
var/speciesName
var/list/languages
/datum/absorbed_dna/New(var/newName, var/newDNA, var/newSpecies, var/newLanguages)
..()
name = newName
dna = newDNA
speciesName = newSpecies
languages = newLanguages

View File

@@ -1,5 +1,5 @@
/datum/game_mode/changeling
name = "changeling"
name = "Changeling"
round_description = "There are alien changelings on the station. Do not let the changelings succeed!"
extended_round_description = "Life always finds a way. However, life can sometimes take a more disturbing route. \
Humanity's extensive knowledge of xeno-biological specimens has made them confident and arrogant. Yet \

View File

@@ -1,9 +1,8 @@
var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon","Zeta","Eta","Theta","Iota","Kappa","Lambda","Mu","Nu","Xi","Omicron","Pi","Rho","Sigma","Tau","Upsilon","Phi","Chi","Psi","Omega")
/datum/changeling //stores changeling powers, changeling recharge thingie, changeling absorbed DNA and changeling ID (for changeling hivemind)
var/list/absorbed_dna = list()
var/list/absorbed_species = list()
var/list/absorbed_languages = list()
var/list/datum/absorbed_dna/absorbed_dna = list()
var/list/absorbed_languages = list() // Necessary because of set_species stuff
var/absorbedcount = 0
var/chem_charges = 20
var/chem_recharge_rate = 0.5
@@ -23,25 +22,36 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
/datum/changeling/New(var/gender=FEMALE)
..()
var/honorific = (gender == FEMALE) ? "Ms." : "Mr."
if(possible_changeling_IDs.len)
changelingID = pick(possible_changeling_IDs)
possible_changeling_IDs -= changelingID
changelingID = "[honorific] [changelingID]"
changelingID = "[changelingID]"
else
changelingID = "[honorific] [rand(1,999)]"
changelingID = "[rand(1,999)]"
/datum/changeling/proc/regenerate()
chem_charges = min(max(0, chem_charges+chem_recharge_rate), chem_storage)
geneticdamage = max(0, geneticdamage-1)
/datum/changeling/proc/GetDNA(var/dna_owner)
var/datum/dna/chosen_dna
for(var/datum/dna/DNA in absorbed_dna)
if(dna_owner == DNA.real_name)
chosen_dna = DNA
break
return chosen_dna
for(var/datum/absorbed_dna/DNA in absorbed_dna)
if(dna_owner == DNA.name)
return DNA
/mob/proc/absorbDNA(var/datum/absorbed_dna/newDNA)
var/datum/changeling/changeling = null
if(src.mind && src.mind.changeling)
changeling = src.mind.changeling
if(!changeling)
return
for(var/language in newDNA.languages)
changeling.absorbed_languages |= language
changeling_update_languages(changeling.absorbed_languages)
if(!changeling.GetDNA(newDNA.name)) // Don't duplicate - I wonder if it's possible for it to still be a different DNA? DNA code could use a rewrite
changeling.absorbed_dna += newDNA
//Restores our verbs. It will only restore verbs allowed during lesser (monkey) form if we are not human
/mob/proc/make_changeling()
@@ -70,14 +80,13 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
if(!(P in src.verbs))
src.verbs += P.verbpath
mind.changeling.absorbed_dna |= dna
for(var/language in languages)
mind.changeling.absorbed_languages |= language
var/mob/living/carbon/human/H = src
if(istype(H))
mind.changeling.absorbed_species += H.species.name
for(var/language in languages)
mind.changeling.absorbed_languages |= language
var/datum/absorbed_dna/newDNA = new(H.real_name, H.dna, H.species.name, H.languages)
absorbDNA(newDNA)
return 1
@@ -118,10 +127,8 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
return changeling
//Used to dump the languages from the changeling datum into the actual mob.
/mob/proc/changeling_update_languages(var/updated_languages)
languages = list()
for(var/language in updated_languages)
languages += language
@@ -129,8 +136,6 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
//This isn't strictly necessary but just to be safe...
add_language("Changeling")
return
//////////
//STINGS// //They get a pretty header because there's just so fucking many of them ;_;
//////////
@@ -171,9 +176,3 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
if(!T.mind || !T.mind.changeling) return T //T will be affected by the sting
T << "<span class='warning'>You feel a tiny prick.</span>"
return

View File

@@ -65,33 +65,21 @@
src << "<span class='notice'>We have absorbed [T]!</span>"
src.visible_message("<span class='danger'>[src] sucks the fluids from [T]!</span>")
T << "<span class='danger'>You have been absorbed by the changeling!</span>"
T.dna.real_name = T.real_name //Set this again, just to be sure that it's properly set.
changeling.absorbed_dna |= T.dna
if(src.nutrition < 400)
src.nutrition = min((src.nutrition + T.nutrition), 400)
changeling.chem_charges += 10
// changeling.geneticpoints += 2
src.verbs += /mob/proc/changeling_respec
src << "<span class='notice'>We can now re-adapt, reverting our evolution so that we may start anew, if needed.</span>"
//Steal all of their languages!
for(var/language in T.languages)
if(!(language in changeling.absorbed_languages))
changeling.absorbed_languages += language
changeling_update_languages(changeling.absorbed_languages)
//Steal their species!
if(T.species && !(T.species.name in changeling.absorbed_species))
changeling.absorbed_species += T.species.name
var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.name, T.languages)
absorbDNA(newDNA)
if(T.mind && T.mind.changeling)
if(T.mind.changeling.absorbed_dna)
for(var/dna_data in T.mind.changeling.absorbed_dna) //steal all their loot
for(var/datum/absorbed_dna/dna_data in T.mind.changeling.absorbed_dna) //steal all their loot
if(dna_data in changeling.absorbed_dna)
continue
changeling.absorbed_dna += dna_data
absorbDNA(dna_data)
changeling.absorbedcount++
T.mind.changeling.absorbed_dna.len = 1

View File

@@ -19,6 +19,9 @@
var/mob/living/carbon/human/T = changeling_sting(40, /mob/proc/changeling_extract_dna_sting)
if(!T)
return
if(!istype(T) || T.isSynthetic())
src << "<span class='warning'>\The [T] is not compatible with our biology.</span>"
return 0
@@ -31,10 +34,8 @@
src << "<span class='warning'>This creature's DNA is ruined beyond useability!</span>"
return 0
T.dna.real_name = T.real_name
changeling.absorbed_dna |= T.dna
if(T.species && !(T.species.name in changeling.absorbed_species))
changeling.absorbed_species += T.species.name
var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.name, T.languages)
absorbDNA(newDNA)
feedback_add_details("changeling_powers","ED")
return 1

View File

@@ -27,9 +27,9 @@ var/list/datum/dna/hivemind_bank = list()
if(!changeling) return
var/list/names = list()
for(var/datum/dna/DNA in changeling.absorbed_dna)
for(var/datum/absorbed_dna/DNA in changeling.absorbed_dna)
if(!(DNA in hivemind_bank))
names += DNA.real_name
names += DNA.name
if(names.len <= 0)
src << "<span class='notice'>The airwaves already have all of our DNA.</span>"
@@ -38,7 +38,7 @@ var/list/datum/dna/hivemind_bank = list()
var/S = input("Select a DNA to channel: ", "Channel DNA", null) as null|anything in names
if(!S) return
var/datum/dna/chosen_dna = changeling.GetDNA(S)
var/datum/absorbed_dna/chosen_dna = changeling.GetDNA(S)
if(!chosen_dna)
return
@@ -57,9 +57,9 @@ var/list/datum/dna/hivemind_bank = list()
if(!changeling) return
var/list/names = list()
for(var/datum/dna/DNA in hivemind_bank)
for(var/datum/absorbed_dna/DNA in hivemind_bank)
if(!(DNA in changeling.absorbed_dna))
names[DNA.real_name] = DNA
names[DNA.name] = DNA
if(names.len <= 0)
src << "<span class='notice'>There's no new DNA to absorb from the air.</span>"
@@ -67,12 +67,12 @@ var/list/datum/dna/hivemind_bank = list()
var/S = input("Select a DNA absorb from the air: ", "Absorb DNA", null) as null|anything in names
if(!S) return
var/datum/dna/chosen_dna = names[S]
var/datum/absorbed_dna/chosen_dna = names[S]
if(!chosen_dna)
return
changeling.chem_charges -= 20
changeling.absorbed_dna += chosen_dna
absorbDNA(chosen_dna)
src << "<span class='notice'>We absorb the DNA of [S] from the air.</span>"
feedback_add_details("changeling_powers","HD")
return 1

View File

@@ -1,8 +1,8 @@
/datum/power/changeling/self_respiration
name = "Self Respiration"
desc = "We evolve our body to no longer require drawing oxygen from the atmosphere.."
desc = "We evolve our body to no longer require drawing oxygen from the atmosphere."
helptext = "We will no longer require internals, and we cannot inhale any gas, including harmful ones."
genomecost = 1
genomecost = 0
isVerb = 0
verbpath = /mob/proc/changeling_self_respiration

View File

@@ -4,12 +4,6 @@
genomecost = 0
verbpath = /mob/proc/changeling_transform
/datum/power/changeling/change_species
name = "Change Species"
desc = "We take on the apperance of a species that we have absorbed."
genomecost = 0
verbpath = /mob/proc/changeling_change_species
//Change our DNA to that of somebody we've absorbed.
/mob/proc/changeling_transform()
set category = "Changeling"
@@ -19,73 +13,42 @@
if(!changeling) return
var/list/names = list()
for(var/datum/dna/DNA in changeling.absorbed_dna)
names += "[DNA.real_name]"
for(var/datum/absorbed_dna/DNA in changeling.absorbed_dna)
names += "[DNA.name]"
var/S = input("Select the target DNA: ", "Target DNA", null) as null|anything in names
if(!S) return
var/datum/dna/chosen_dna = changeling.GetDNA(S)
var/datum/absorbed_dna/chosen_dna = changeling.GetDNA(S)
if(!chosen_dna)
return
changeling.chem_charges -= 5
src.visible_message("<span class='warning'>[src] transforms!</span>")
changeling.geneticdamage = 5
src.dna = chosen_dna.Clone()
if(ishuman(src))
var/mob/living/carbon/human/H = src
var/newSpecies = chosen_dna.speciesName
H.set_species(newSpecies,1)
src.dna = chosen_dna.dna.Clone()
src.dna.b_type = "AB+" //This is needed to avoid blood rejection bugs. The fact that the blood type might not match up w/ records could be a *FEATURE* too.
if(ishuman(src))
var/mob/living/carbon/human/H = src
H.b_type = "AB+" //For some reason we have two blood types on the mob.
for(var/flavor in H.flavor_texts) //Nulls out flavor text, so we don't keep our previous mob's flavor.
flavor = null
src.real_name = chosen_dna.real_name
src.real_name = chosen_dna.name
src.flavor_text = ""
src.UpdateAppearance()
domutcheck(src, null)
changeling_update_languages(changeling.absorbed_languages)
src.verbs -= /mob/proc/changeling_transform
spawn(10) src.verbs += /mob/proc/changeling_transform
spawn(10)
src.verbs += /mob/proc/changeling_transform
src.regenerate_icons()
feedback_add_details("changeling_powers","TR")
return 1
//Used to switch species based on the changeling datum.
/mob/proc/changeling_change_species()
set category = "Changeling"
set name = "Change Species (5)"
var/mob/living/carbon/human/H = src
if(!istype(H))
src << "<span class='warning'>We may only use this power while in humanoid form.</span>"
return
var/datum/changeling/changeling = changeling_power(5,1,0)
if(!changeling) return
if(changeling.absorbed_species.len < 2)
src << "<span class='warning'>We do not know of any other species genomes to use.</span>"
return
var/S = input("Select the target species: ", "Target Species", null) as null|anything in changeling.absorbed_species
if(!S) return
domutcheck(src, null)
changeling.chem_charges -= 5
changeling.geneticdamage = 5
src.visible_message("<span class='warning'>[src] transforms!</span>")
src.verbs -= /mob/proc/changeling_change_species
H.set_species(S,1) //Until someone moves body colour into DNA, they're going to have to use the default.
spawn(10)
src.verbs += /mob/proc/changeling_change_species
src.regenerate_icons()
changeling_update_languages(changeling.absorbed_languages)
feedback_add_details("changeling_powers","TR")
return 1

View File

@@ -185,7 +185,6 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","
throw_range = 5
w_class = 2.0
unique = 1
var/notedat = ""
var/tomedat = ""
var/list/words = list("ire" = "ire", "ego" = "ego", "nahlizet" = "nahlizet", "certum" = "certum", "veri" = "veri", "jatkaa" = "jatkaa", "balaq" = "balaq", "mgar" = "mgar", "karazet" = "karazet", "geeri" = "geeri")
@@ -285,57 +284,12 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","
</html>
"}
Topic(href,href_list[])
if (src.loc == usr)
var/number = text2num(href_list["number"])
if (usr.stat|| usr.restrained())
return
switch(href_list["action"])
if("clear")
words[words[number]] = words[number]
if("change")
words[words[number]] = input("Enter the translation for [words[number]]", "Word notes") in engwords
for (var/w in words)
if ((words[w] == words[words[number]]) && (w != words[number]))
words[w] = w
notedat = {"
<br><b>Word translation notes</b> <br>
[words[1]] is <a href='byond://?src=\ref[src];number=1;action=change'>[words[words[1]]]</A> <A href='byond://?src=\ref[src];number=1;action=clear'>Clear</A><BR>
[words[2]] is <A href='byond://?src=\ref[src];number=2;action=change'>[words[words[2]]]</A> <A href='byond://?src=\ref[src];number=2;action=clear'>Clear</A><BR>
[words[3]] is <a href='byond://?src=\ref[src];number=3;action=change'>[words[words[3]]]</A> <A href='byond://?src=\ref[src];number=3;action=clear'>Clear</A><BR>
[words[4]] is <a href='byond://?src=\ref[src];number=4;action=change'>[words[words[4]]]</A> <A href='byond://?src=\ref[src];number=4;action=clear'>Clear</A><BR>
[words[5]] is <a href='byond://?src=\ref[src];number=5;action=change'>[words[words[5]]]</A> <A href='byond://?src=\ref[src];number=5;action=clear'>Clear</A><BR>
[words[6]] is <a href='byond://?src=\ref[src];number=6;action=change'>[words[words[6]]]</A> <A href='byond://?src=\ref[src];number=6;action=clear'>Clear</A><BR>
[words[7]] is <a href='byond://?src=\ref[src];number=7;action=change'>[words[words[7]]]</A> <A href='byond://?src=\ref[src];number=7;action=clear'>Clear</A><BR>
[words[8]] is <a href='byond://?src=\ref[src];number=8;action=change'>[words[words[8]]]</A> <A href='byond://?src=\ref[src];number=8;action=clear'>Clear</A><BR>
[words[9]] is <a href='byond://?src=\ref[src];number=9;action=change'>[words[words[9]]]</A> <A href='byond://?src=\ref[src];number=9;action=clear'>Clear</A><BR>
[words[10]] is <a href='byond://?src=\ref[src];number=10;action=change'>[words[words[10]]]</A> <A href='byond://?src=\ref[src];number=10;action=clear'>Clear</A><BR>
"}
usr << browse("[notedat]", "window=notes")
// call(/obj/item/weapon/book/tome/proc/edit_notes)()
else
usr << browse(null, "window=notes")
return
// proc/edit_notes() FUCK IT. Cant get it to work properly. - K0000
// world << "its been called! [usr]"
// notedat = {"
// <br><b>Word translation notes</b> <br>
// [words[1]] is <a href='byond://?src=\ref[src];number=1;action=change'>[words[words[1]]]</A> <A href='byond://?src=\ref[src];number=1;action=clear'>Clear</A><BR>
// [words[2]] is <A href='byond://?src=\ref[src];number=2;action=change'>[words[words[2]]]</A> <A href='byond://?src=\ref[src];number=2;action=clear'>Clear</A><BR>
// [words[3]] is <a href='byond://?src=\ref[src];number=3;action=change'>[words[words[3]]]</A> <A href='byond://?src=\ref[src];number=3;action=clear'>Clear</A><BR>
// [words[4]] is <a href='byond://?src=\ref[src];number=4;action=change'>[words[words[4]]]</A> <A href='byond://?src=\ref[src];number=4;action=clear'>Clear</A><BR>
// [words[5]] is <a href='byond://?src=\ref[src];number=5;action=change'>[words[words[5]]]</A> <A href='byond://?src=\ref[src];number=5;action=clear'>Clear</A><BR>
// [words[6]] is <a href='byond://?src=\ref[src];number=6;action=change'>[words[words[6]]]</A> <A href='byond://?src=\ref[src];number=6;action=clear'>Clear</A><BR>
// [words[7]] is <a href='byond://?src=\ref[src];number=7;action=change'>[words[words[7]]]</A> <A href='byond://?src=\ref[src];number=7;action=clear'>Clear</A><BR>
// [words[8]] is <a href='byond://?src=\ref[src];number=8;action=change'>[words[words[8]]]</A> <A href='byond://?src=\ref[src];number=8;action=clear'>Clear</A><BR>
// [words[9]] is <a href='byond://?src=\ref[src];number=9;action=change'>[words[words[9]]]</A> <A href='byond://?src=\ref[src];number=9;action=clear'>Clear</A><BR>
// [words[10]] is <a href='byond://?src=\ref[src];number=10;action=change'>[words[words[10]]]</A> <A href='byond://?src=\ref[src];number=10;action=clear'>Clear</A><BR>
// "}
// usr << "whatev"
// usr << browse(null, "window=tank")
New()
..()
if(!cultwords["travel"])
runerandom()
for(var/V in cultwords)
words[cultwords[V]] = V
attack(mob/living/M as mob, mob/living/user as mob)
@@ -378,7 +332,7 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","
alert("The cloth of reality can't take that much of a strain. Remove some runes first!")
return
else
switch(alert("You open the tome",,"Read it","Scribe a rune", "Notes")) //Fuck the "Cancel" option. Rewrite the whole tome interface yourself if you want it to work better. And input() is just ugly. - K0000
switch(alert("You open the tome",,"Read it","Scribe a rune", "Cancel"))
if("Cancel")
return
if("Read it")
@@ -386,25 +340,6 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","
return
user << browse("[tomedat]", "window=Arcane Tome")
return
if("Notes")
if(usr.get_active_hand() != src)
return
notedat = {"
<br><b>Word translation notes</b> <br>
[words[1]] is <a href='byond://?src=\ref[src];number=1;action=change'>[words[words[1]]]</A> <A href='byond://?src=\ref[src];number=1;action=clear'>Clear</A><BR>
[words[2]] is <A href='byond://?src=\ref[src];number=2;action=change'>[words[words[2]]]</A> <A href='byond://?src=\ref[src];number=2;action=clear'>Clear</A><BR>
[words[3]] is <a href='byond://?src=\ref[src];number=3;action=change'>[words[words[3]]]</A> <A href='byond://?src=\ref[src];number=3;action=clear'>Clear</A><BR>
[words[4]] is <a href='byond://?src=\ref[src];number=4;action=change'>[words[words[4]]]</A> <A href='byond://?src=\ref[src];number=4;action=clear'>Clear</A><BR>
[words[5]] is <a href='byond://?src=\ref[src];number=5;action=change'>[words[words[5]]]</A> <A href='byond://?src=\ref[src];number=5;action=clear'>Clear</A><BR>
[words[6]] is <a href='byond://?src=\ref[src];number=6;action=change'>[words[words[6]]]</A> <A href='byond://?src=\ref[src];number=6;action=clear'>Clear</A><BR>
[words[7]] is <a href='byond://?src=\ref[src];number=7;action=change'>[words[words[7]]]</A> <A href='byond://?src=\ref[src];number=7;action=clear'>Clear</A><BR>
[words[8]] is <a href='byond://?src=\ref[src];number=8;action=change'>[words[words[8]]]</A> <A href='byond://?src=\ref[src];number=8;action=clear'>Clear</A><BR>
[words[9]] is <a href='byond://?src=\ref[src];number=9;action=change'>[words[words[9]]]</A> <A href='byond://?src=\ref[src];number=9;action=clear'>Clear</A><BR>
[words[10]] is <a href='byond://?src=\ref[src];number=10;action=change'>[words[words[10]]]</A> <A href='byond://?src=\ref[src];number=10;action=clear'>Clear</A><BR>
"}
// call(/obj/item/weapon/book/tome/proc/edit_notes)()
user << browse("[notedat]", "window=notes")
return
if(usr.get_active_hand() != src)
return
@@ -489,21 +424,6 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","
user << "The book seems full of illegible scribbles. Is this a joke?"
return
attackby(obj/item/weapon/book/tome/T as obj, mob/living/user as mob)
if(istype(T, /obj/item/weapon/book/tome)) // sanity check to prevent a runtime error
switch(alert("Copy the runes from your tome?",,"Copy", "Cancel"))
if("cancel")
return
// var/list/nearby = viewers(1,src) //- Fuck this as well. No clue why this doesnt work. -K0000
// if (T.loc != user)
// return
// for(var/mob/M in nearby)
// if(M == user)
for(var/entry in words)
words[entry] = T.words[entry]
user << "You copy the translation notes from your tome."
examine(mob/user)
if(!iscultist(user))
user << "An old, dusty tome with frayed edges and a sinister looking cover."

View File

@@ -423,7 +423,7 @@ var/list/sacrificed = list()
L.ajourn=0
return
else
L.take_organ_damage(10, 0)
L.take_organ_damage(3, 0)
sleep(100)
return fizzle()

View File

@@ -1,5 +1,5 @@
/datum/game_mode/epidemic
name = "epidemic"
name = "Epidemic"
config_tag = "epidemic"
required_players = 1
required_players_secret = 15

View File

@@ -39,10 +39,6 @@ var/global/list/additional_antag_types = list()
/datum/game_mode/New()
..()
// Enforce some formatting.
// This will probably break something.
name = capitalize(lowertext(name))
config_tag = lowertext(config_tag)
/datum/game_mode/Topic(href, href_list[])
if(..())

View File

@@ -112,7 +112,7 @@ var/global/datum/controller/gameticker/ticker
tmpmodes+=M.name
tmpmodes = sortList(tmpmodes)
if(tmpmodes.len)
world << "<B>Possibilities:</B> [english_list(tmpmodes)]"
world << "<B>Possibilities:</B> [english_list(tmpmodes, and_text= "; ", comma_text = "; ")]"
else
src.mode.announce()

View File

@@ -5,7 +5,7 @@ VOX HEIST ROUNDTYPE
var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind' objective. Clumsy, rewrite sometime.
/datum/game_mode/heist
name = "heist"
name = "Heist"
config_tag = "heist"
required_players = 15
required_players_secret = 15

View File

@@ -1,5 +1,5 @@
/datum/game_mode/malfunction
name = "AI malfunction"
name = "AI Malfunction"
round_description = "The AI is behaving abnormally and must be stopped."
extended_round_description = "The AI will attempt to hack the APCs around the station in order to gain as much control as possible."
config_tag = "malfunction"

View File

@@ -1,5 +1,5 @@
/datum/game_mode/conflux
name = "conflux"
name = "Wizard & Cult"
round_description = "A space wizard and a cult have invaded the station!"
extended_round_description = "Cultists and wizards spawn during this round."
config_tag = "conflux"

View File

@@ -1,5 +1,5 @@
/datum/game_mode/infestation
name = "infestation"
name = "Borers & Changelings"
round_description = "There's something in the walls!"
extended_round_description = "Two alien antagonists (Cortical Borers or Changelings) spawn during this round."
config_tag = "infestation"

View File

@@ -1,11 +1,11 @@
/datum/game_mode/intrigue
name = "Intrigue"
name = "Traitors & Ninja"
round_description = "Crewmembers are contacted by external elements while another infiltrates the colony."
extended_round_description = "Traitors and a ninja spawn during this round."
config_tag = "intrigue"
required_players = 15
required_players_secret = 15
required_enemies = 4
required_players = 6
required_players_secret = 8
required_enemies = 3
end_on_antag_death = 0
antag_tags = list(MODE_NINJA, MODE_AUTOTRAITOR)
round_autoantag = 1

View File

@@ -1,11 +1,11 @@
/datum/game_mode/lizard
name = "lizard"
name = "Wizard & Changelings"
round_description = "A space wizard and changelings have invaded the station!"
extended_round_description = "Changelings and a wizard spawn during this round."
config_tag = "lizard"
required_players = 15
required_players_secret = 15
required_enemies = 4
required_players = 2
required_players_secret = 8
required_enemies = 3
end_on_antag_death = 0
antag_tags = list(MODE_WIZARD, MODE_CHANGELING)
require_all_templates = 1

View File

@@ -1,5 +1,5 @@
/datum/game_mode/paranoia
name = "paranoia"
name = "Malf AI, Renegades & Changelings"
round_description = "The AI has malfunctioned, and subversive elements infest the crew..."
extended_round_description = "Rampant AIs, renegades and changelings spawn in this mode."
config_tag = "paranoia"

View File

@@ -1,5 +1,5 @@
/datum/game_mode/traitorling
name = "traitorling"
name = "Traitors & Changelings"
round_description = "There are traitors and alien changelings on the station. Do not let the changelings succeed!"
extended_round_description = "Traitors and changelings both spawn during this mode."
config_tag = "traitorling"

View File

@@ -1,5 +1,5 @@
/datum/game_mode/uprising
name = "uprising"
name = "Revolution & Cult"
config_tag = "uprising"
round_description = "Some crewmembers are attempting to start a revolution while a cult plots in the shadows!"
extended_round_description = "Cultists and revolutionaries spawn in this round."

View File

@@ -1,10 +1,10 @@
/datum/game_mode/visitors
name = "Visitors"
name = "Wizard & Ninja"
round_description = "A space wizard and a ninja have invaded the station!"
extended_round_description = "A ninja and wizard spawn during this round."
config_tag = "visitors"
required_players = 10
required_players_secret = 10
required_players = 6
required_players_secret = 6
required_enemies = 2
end_on_antag_death = 0
antag_tags = list(MODE_WIZARD, MODE_NINJA)

View File

@@ -1,5 +1,5 @@
/datum/game_mode/ninja
name = "ninja"
name = "Ninja"
round_description = "An agent of the Spider Clan is onboard the station!"
extended_round_description = "What was that?! Was that a person or did your eyes just play tricks on you? \
You have no idea. That slim-suited, cryptic individual is an enigma to you and all of your knowledge. \

View File

@@ -1,5 +1,5 @@
/datum/game_mode/sandbox
name = "sandbox"
name = "Sandbox"
config_tag = "sandbox"
required_players = 0
votable = 0

View File

@@ -19,6 +19,7 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1)
minimal_player_age = 14
economic_modifier = 20
minimum_character_age = 25
ideal_character_age = 70 // Old geezer captains ftw
@@ -67,6 +68,8 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1)
req_admin_notify = 1
minimal_player_age = 10
economic_modifier = 10
minimum_character_age = 25
ideal_character_age = 50
access = list(access_security, access_sec_doors, access_brig, access_forensics_lockers,

View File

@@ -188,12 +188,13 @@
department = "Civilian"
department_flag = CIVILIAN
faction = "Station"
total_positions = 1
spawn_positions = 1
total_positions = 2
spawn_positions = 2
supervisors = "the head of personnel"
selection_color = "#dddddd"
access = list(access_janitor, access_maint_tunnels)
minimal_access = list(access_janitor, access_maint_tunnels)
alt_titles = list("Custodian")
equip(var/mob/living/carbon/human/H)

View File

@@ -13,6 +13,7 @@
req_admin_notify = 1
economic_modifier = 10
minimum_character_age = 25
ideal_character_age = 50

View File

@@ -19,6 +19,7 @@
access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce,
access_keycard_auth, access_sec_doors, access_psychiatrist, access_eva, access_external_airlocks, access_maint_tunnels)
minimum_character_age = 25
minimal_player_age = 10
ideal_character_age = 50

View File

@@ -21,6 +21,7 @@
access_research, access_robotics, access_xenobiology, access_ai_upload, access_tech_storage,
access_RC_announce, access_keycard_auth, access_tcomsat, access_gateway, access_xenoarch)
minimum_character_age = 25
minimal_player_age = 14
ideal_character_age = 50

View File

@@ -20,6 +20,7 @@
access_forensics_lockers, access_morgue, access_maint_tunnels, access_all_personal_lockers,
access_research, access_engine, access_mining, access_medical, access_construction, access_mailsorting,
access_heads, access_hos, access_RC_announce, access_keycard_auth, access_gateway, access_external_airlocks)
minimum_character_age = 25
minimal_player_age = 14
equip(var/mob/living/carbon/human/H)
@@ -92,7 +93,7 @@
spawn_positions = 2
supervisors = "the head of security"
selection_color = "#ffeeee"
alt_titles = list("Forensic Technician")
alt_titles = list("Forensic Technician","Investigator")
access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_eva, access_external_airlocks)
minimal_access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_eva, access_external_airlocks)
economic_modifier = 5
@@ -119,6 +120,7 @@
else
H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/det_trench(H), slot_wear_suit)
H.equip_to_slot_or_del(new /obj/item/clothing/head/det(H), slot_head)
H.equip_to_slot_or_del(new /obj/item/weapon/storage/briefcase/crimekit(H), slot_r_hand)
return 1

View File

@@ -111,7 +111,7 @@ var/global/datum/controller/occupations/job_master
if(istype(job, GetJob("Assistant"))) // We don't want to give him assistant, that's boring!
continue
if(job in command_positions) //If you want a command position, select it!
if(job.title in command_positions) //If you want a command position, select it!
continue
if(jobban_isbanned(player, job.title))
@@ -331,7 +331,6 @@ var/global/datum/controller/occupations/job_master
var/list/custom_equip_slots = list() //If more than one item takes the same slot, all after the first one spawn in storage.
var/list/custom_equip_leftovers = list()
if(H.client.prefs.gear && H.client.prefs.gear.len && job.title != "Cyborg" && job.title != "AI")
for(var/thing in H.client.prefs.gear)
var/datum/gear/G = gear_datums[thing]
if(G)
@@ -353,10 +352,11 @@ var/global/datum/controller/occupations/job_master
if(G.slot && !(G.slot in custom_equip_slots))
// This is a miserable way to fix the loadout overwrite bug, but the alternative requires
// adding an arg to a bunch of different procs. Will look into it after this merge. ~ Z
var/metadata = H.client.prefs.gear[G.display_name]
if(G.slot == slot_wear_mask || G.slot == slot_wear_suit || G.slot == slot_head)
custom_equip_leftovers += thing
else if(H.equip_to_slot_or_del(new G.path(H), G.slot))
H << "<span class='notice'>Equipping you with [thing]!</span>"
else if(H.equip_to_slot_or_del(G.spawn_item(H, metadata), G.slot))
H << "<span class='notice'>Equipping you with \the [thing]!</span>"
custom_equip_slots.Add(G.slot)
else
custom_equip_leftovers.Add(thing)
@@ -375,8 +375,9 @@ var/global/datum/controller/occupations/job_master
if(G.slot in custom_equip_slots)
spawn_in_storage += thing
else
if(H.equip_to_slot_or_del(new G.path(H), G.slot))
H << "<span class='notice'>Equipping you with [thing]!</span>"
var/metadata = H.client.prefs.gear[G.display_name]
if(H.equip_to_slot_or_del(G.spawn_item(H, metadata), G.slot))
H << "<span class='notice'>Equipping you with \the [thing]!</span>"
custom_equip_slots.Add(G.slot)
else
spawn_in_storage += thing
@@ -439,9 +440,10 @@ var/global/datum/controller/occupations/job_master
if(!isnull(B))
for(var/thing in spawn_in_storage)
H << "<span class='notice'>Placing [thing] in your [B]!</span>"
H << "<span class='notice'>Placing \the [thing] in your [B.name]!</span>"
var/datum/gear/G = gear_datums[thing]
new G.path(B)
var/metadata = H.client.prefs.gear[G.display_name]
G.spawn_item(B, metadata)
else
H << "<span class='danger'>Failed to locate a storage object on your mob, either you spawned with no arms and no backpack or this is a bug.</span>"

View File

@@ -155,8 +155,12 @@
var/A = text2num(href_list["access"])
if (A in accesses)
accesses.Remove(A)
else
accesses.Add(A)
else
if(A in giver.access) //Let's make sure the ID card actually has the access.
accesses.Add(A)
else
usr << "<span class='warning'>Invalid selection, please consult technical support if there are any issues.</span>"
log_debug("[key_name_admin(usr)] tried selecting an invalid guest pass terminal option.")
if (href_list["action"])
switch(href_list["action"])
if ("id")

View File

@@ -91,7 +91,7 @@
if(!target || !istype(target))
return
var/istraitor = traitors.is_antagonist(target.mind)
var/istraitor = target.mind.special_role
if (istraitor)
target.lockcharge = !target.lockcharge
if (target.lockcharge)
@@ -187,7 +187,7 @@
robot["name"] = R.name
if(R.stat)
robot["status"] = "Not Responding"
else if (!R.canmove)
else if (R.lockcharge)
robot["status"] = "Lockdown"
else
robot["status"] = "Operational"

View File

@@ -63,10 +63,9 @@
return 1
/obj/machinery/atmospherics/unary/cryo_cell/relaymove(mob/user as mob)
if(user.stat)
return
go_out()
return
// note that relaymove will also be called for mobs outside the cell with UI open
if(src.occupant == user && !user.stat)
go_out()
/obj/machinery/atmospherics/unary/cryo_cell/attack_hand(mob/user)
ui_interact(user)

View File

@@ -219,7 +219,7 @@
var/disallow_occupant_types = list()
var/mob/occupant = null // Person waiting to be despawned.
var/time_till_despawn = 18000 // 30 minutes-ish safe period before being despawned.
var/time_till_despawn = 9000 // Down to 15 minutes //30 minutes-ish is too long
var/time_entered = 0 // Used to keep track of the safe period.
var/obj/item/device/radio/intercom/announce //
@@ -487,32 +487,33 @@
if(istype(G, /obj/item/weapon/grab))
var/obj/item/weapon/grab/grab = G
if(occupant)
user << "<span class='notice'>\The [src] is in use.</span>"
return
if(!ismob(G:affecting))
if(!ismob(grab.affecting))
return
if(!check_occupant_allowed(G:affecting))
if(!check_occupant_allowed(grab.affecting))
return
var/willing = null //We don't want to allow people to be forced into despawning.
var/mob/M = G:affecting
var/mob/M = grab.affecting
if(M.client)
if(alert(M,"Would you like to enter long-term storage?",,"Yes","No") == "Yes")
if(!M || !G || !G:affecting) return
if(!M || !grab || !grab:affecting) return
willing = 1
else
willing = 1
if(willing)
visible_message("[user] starts putting [G:affecting:name] into \the [src].", 3)
visible_message("\The [user] starts putting [grab:affecting:name] into \the [src].", 3)
if(do_after(user, 20))
if(!M || !G || !G:affecting) return
if(!M || !grab || !grab:affecting) return
M.forceMove(src)

View File

@@ -808,23 +808,23 @@ About the new airlock wires panel:
else
spawn(0) close(1)
else if(istype(C, /obj/item/weapon/material/twohanded/fireaxe) && !arePowerSystemsOn())
// Check if we're using a crowbar or armblade, and if the airlock's unpowered for whatever reason (off, broken, etc).
else if( (istype(C, /obj/item/weapon/material/twohanded/fireaxe) || istype(C, /obj/item/weapon/melee/arm_blade) ) && !arePowerSystemsOn())
if(locked)
user << "<span class='notice'>The airlock's bolts prevent it from being forced.</span>"
else if( !welded && !operating )
if(istype(C, /obj/item/weapon/material/twohanded/fireaxe)) // If this is a fireaxe, make sure it's held in two hands.
var/obj/item/weapon/material/twohanded/fireaxe/F = C
if(!F.wielded)
user << "<span class='warning'>You need to be wielding \the [F] to do that.</span>"
return
// At this point, it's an armblade or a fireaxe that passed the wielded test, let's try to open it.
if(density)
var/obj/item/weapon/material/twohanded/fireaxe/F = C
if(F.wielded)
spawn(0) open(1)
else
user << "<span class='warning'>You need to be wielding \the [C] to do that.</span>"
spawn(0)
open(1)
else
var/obj/item/weapon/material/twohanded/fireaxe/F = C
if(F.wielded)
spawn(0) close(1)
else
user << "<span class='warning'>You need to be wielding \the [C] to do that.</span>"
spawn(0)
close(1)
else
..()
return

View File

@@ -86,11 +86,17 @@
// Proc: attackby()
// Parameters: 2 (C - Item this object was clicked with, user - Mob which clicked this object)
// Description: If we are clicked with crowbar or wielded fire axe, try to manually open the door.
// Description: If we are clicked with crowbar, wielded fire axe, or armblade, try to manually open the door.
// This only works on broken doors or doors without power. Also allows repair with Plasteel.
/obj/machinery/door/blast/attackby(obj/item/weapon/C as obj, mob/user as mob)
src.add_fingerprint(user)
if(istype(C, /obj/item/weapon/crowbar) || (istype(C, /obj/item/weapon/material/twohanded/fireaxe) && C:wielded == 1))
if(istype(C, /obj/item/weapon/crowbar) || istype(C, /obj/item/weapon/material/twohanded/fireaxe) || istype(C, /obj/item/weapon/melee/arm_blade))
if(istype(C,/obj/item/weapon/material/twohanded/fireaxe))
var/obj/item/weapon/material/twohanded/fireaxe/F = C
if(!F.wielded)
user << "<span class='warning'>You need to be wielding \the [F] to do that.</span>"
return
if(((stat & NOPOWER) || (stat & BROKEN)) && !( src.operating ))
force_toggle()
else
@@ -144,7 +150,7 @@
if(stat & BROKEN)
stat &= ~BROKEN
/obj/machinery/door/blast/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
if(air_group) return 1
return ..()

View File

@@ -235,7 +235,7 @@
user << "<span class='danger'>\The [src] is welded shut!</span>"
return
if(istype(C, /obj/item/weapon/crowbar) || istype(C,/obj/item/weapon/material/twohanded/fireaxe))
if(istype(C, /obj/item/weapon/crowbar) || istype(C,/obj/item/weapon/material/twohanded/fireaxe) || istype(C, /obj/item/weapon/melee/arm_blade))
if(operating)
return

View File

@@ -18,8 +18,6 @@
var/global/list/acceptable_items // List of the items you can put in
var/global/list/acceptable_reagents // List of the reagents you can put in
var/global/max_n_of_items = 0
var/list/ingredient_list = list() //MUST BE INTIALIZED OR YOU GET RUNTIME ERRORS
// see code/modules/food/recipes_microwave.dm for recipes
@@ -116,13 +114,12 @@
user << "<span class='warning'>It's dirty!</span>"
return 1
else if(is_type_in_list(O,acceptable_items))
if (ingredient_list.len>=max_n_of_items)
if (contents.len>=(max_n_of_items + component_parts.len)) //Adds component_parts to the maximum number of items.
user << "<span class='warning'>This [src] is full of ingredients, you cannot put more.</span>"
return 1
if(istype(O, /obj/item/stack) && O:get_amount() > 1) // This is bad, but I can't think of how to change it
var/obj/item/stack/S = O
var/obj/item/stack/K = new O.type (src) //Needed for change into ingredient lists, rather than just contents.
ingredient_list += K
new O.type (src)
S.use(1)
user.visible_message( \
"<span class='notice'>\The [user] has added one of [O] to \the [src].</span>", \
@@ -132,7 +129,6 @@
// user.remove_from_mob(O) //This just causes problems so far as I can tell. -Pete
user.drop_item()
O.loc = src
ingredient_list += O
user.visible_message( \
"<span class='notice'>\The [user] has added \the [O] to \the [src].</span>", \
"<span class='notice'>You add \the [O] to \the [src].</span>")
@@ -181,7 +177,7 @@
var/list/items_counts = new
var/list/items_measures = new
var/list/items_measures_p = new
for (var/obj/O in ingredient_list)
for (var/obj/O in (contents-component_parts))
var/display_name = O.name
if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/egg))
items_measures[display_name] = "egg"
@@ -241,7 +237,7 @@
if(stat & (NOPOWER|BROKEN))
return
start()
if (reagents.total_volume==0 && !(locate(/obj) in ingredient_list)) //dry run
if (reagents.total_volume==0 && !(locate(/obj) in (contents-component_parts))) //dry run
if (!wzhzhzh(10))
abort()
return
@@ -303,7 +299,7 @@
return 1
/obj/machinery/microwave/proc/has_extra_item()
for (var/obj/O in ingredient_list)
for (var/obj/O in (contents-component_parts))
if ( \
!istype(O,/obj/item/weapon/reagent_containers/food) && \
!istype(O, /obj/item/weapon/grown) \
@@ -329,9 +325,8 @@
src.updateUsrDialog()
/obj/machinery/microwave/proc/dispose()
for (var/obj/O in ingredient_list)
for (var/obj/O in (contents-component_parts))
O.loc = src.loc
ingredient_list -= O
if (src.reagents.total_volume)
src.dirty++
src.reagents.clear_reagents()
@@ -365,7 +360,7 @@
/obj/machinery/microwave/proc/fail()
var/obj/item/weapon/reagent_containers/food/snacks/badrecipe/ffuu = new(src)
var/amount = 0
for (var/obj/O in ingredient_list-ffuu)
for (var/obj/O in (contents-ffuu)-component_parts)
amount++
if (O.reagents)
var/id = O.reagents.get_master_reagent_id()

View File

@@ -21,6 +21,8 @@
return
/obj/effect/spider/attackby(var/obj/item/weapon/W, var/mob/user)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(W.attack_verb.len)
visible_message("<span class='warning'>\The [src] have been [pick(W.attack_verb)] with \the [W][(user ? " by [user]." : ".")]</span>")
else

View File

@@ -10,6 +10,7 @@
var/burn_point = null
var/burning = null
var/hitsound = null
var/storage_cost = null
var/slot_flags = 0 //This is used to determine on which slots an item can fit.
var/no_attack_log = 0 //If it's an item we don't want to log attack_logs with, set this to 1
pass_flags = PASSTABLE
@@ -358,7 +359,7 @@ var/list/global/slot_flags_enumeration = list(
var/allow = 0
if(H.back && istype(H.back, /obj/item/weapon/storage/backpack))
var/obj/item/weapon/storage/backpack/B = H.back
if(B.contents.len < B.storage_slots && w_class <= B.max_w_class)
if(B.can_be_inserted(src,1))
allow = 1
if(!allow)
return 0

View File

@@ -354,12 +354,12 @@
var/muleData[0]
muleData["name"] = M.suffix
muleData["location"] = get_area(M)
muleData["mode"] = M.mode
muleData["paused"] = M.paused
muleData["home"] = M.homeName
muleData["target"] = M.targetName
muleData["ref"] = "\ref[M]"
muleData["load"] = M.load ? M.load.name : "Nothing"
mulebotsData[++mulebotsData.len] = muleData.Copy()
values["mulebotcount"] = count

View File

@@ -43,13 +43,30 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
node = get_exonet_node()
processing_objects |= src
//This is a pretty terrible way of doing this.
spawn(50) //Wait for our mob to finish spawning.
spawn(5 SECONDS) //Wait for our mob to finish spawning.
if(ismob(loc))
register_device(loc)
initialize_exonet(loc)
else if(istype(loc, /obj/item/weapon/storage))
var/obj/item/weapon/storage/S = loc
if(ismob(S.loc))
register_device(S.loc)
initialize_exonet(S.loc)
// Proc: initialize_exonet()
// Parameters: 1 (user - the person the communicator belongs to)
// Description: Sets up the exonet datum, gives the device an address, and then gets a node reference. Afterwards, populates the device
// list.
/obj/item/device/communicator/proc/initialize_exonet(mob/user)
if(!user || !istype(user, /mob/living))
return
if(!exonet)
exonet = new(src)
if(!exonet.address)
exonet.make_address("communicator-[user.client]-[user.name]")
if(!node)
node = get_exonet_node()
populate_known_devices()
// Proc: examine()
// Parameters: 1 (user - the person examining the device)
@@ -139,13 +156,7 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
// Description: Makes an exonet datum if one does not exist, allocates an address for it, maintains the lists of all devies, clears the alert icon, and
// finally makes NanoUI appear.
/obj/item/device/communicator/attack_self(mob/user)
if(!exonet)
exonet = new(src)
if(!exonet.address)
exonet.make_address("communicator-[user.client]-[user.name]")
if(!node)
node = get_exonet_node()
populate_known_devices()
initialize_exonet(user)
alert_called = 0
update_icon()
ui_interact(user)
@@ -292,7 +303,7 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
return
var/their_address = href_list["dial"]
exonet.send_message(their_address, "voice")
if(href_list["disconnect"])
var/name_to_disconnect = href_list["disconnect"]
for(var/mob/living/voice/V in contents)
@@ -304,13 +315,13 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
if(href_list["copy"])
target_address = href_list["copy"]
if(href_list["hang_up"])
for(var/mob/living/voice/V in contents)
close_connection(usr, V, "[usr] hung up.")
for(var/obj/item/device/communicator/comm in communicating)
close_connection(usr, comm, "[usr] hung up.")
if(href_list["switch_tab"])
selected_tab = href_list["switch_tab"]

View File

@@ -68,6 +68,12 @@
/obj/item/weapon/material/twohanded/update_icon()
icon_state = "[base_icon][wielded]"
item_state = icon_state
/obj/item/weapon/material/twohanded/dropped()
..()
if(wielded)
spawn(0)
update_held_icon()
/*
* Fireaxe

View File

@@ -22,7 +22,7 @@
)
w_class = 4
slot_flags = SLOT_BACK
max_w_class = 3
max_w_class = 4
max_storage_space = 28
/obj/item/weapon/storage/backpack/attackby(obj/item/weapon/W as obj, mob/user as mob)
@@ -53,6 +53,7 @@
icon_state = "holdingpack"
max_w_class = 4
max_storage_space = 56
storage_cost = 29
New()
..()
@@ -77,7 +78,6 @@
icon_state = "giftbag0"
item_state = "giftbag"
w_class = 4.0
storage_slots = 20
max_w_class = 3
max_storage_space = 400 // can store a ton of shit!
item_state_slots = null
@@ -142,57 +142,84 @@
desc = "It's an orange backpack which was designed to hold beakers, pill bottles and bottles."
icon_state = "chempack"
/*
* Duffle Types
*/
/obj/item/weapon/storage/backpack/dufflebag
name = "dufflebag"
desc = "A large dufflebag for holding extra things."
icon_state = "duffle"
item_state = "duffle"
item_state_slots = list(
slot_l_hand_str = "duffle",
slot_r_hand_str = "duffle",
)
slowdown = 1
max_storage_space = 38
storage_slots = 12
max_storage_space = 36
/obj/item/weapon/storage/backpack/dufflebag/syndie
name = "black dufflebag"
desc = "A large dufflebag for holding extra tactical supplies."
icon_state = "duffle_syndie"
item_state = "duffle_syndiemed"
item_state_slots = list(
slot_l_hand_str = "duffle_syndiemed",
slot_r_hand_str = "duffle_syndiemed",
)
slowdown = 0
/obj/item/weapon/storage/backpack/dufflebag/syndie/med
name = "medical dufflebag"
desc = "A large dufflebag for holding extra tactical medical supplies."
icon_state = "duffle_syndiemed"
item_state = "duffle_syndiemed"
item_state_slots = list(
slot_l_hand_str = "duffle_syndiemed",
slot_r_hand_str = "duffle_syndiemed",
)
/obj/item/weapon/storage/backpack/dufflebag/syndie/ammo
name = "ammunition dufflebag"
desc = "A large dufflebag for holding extra weapons ammunition and supplies."
icon_state = "duffle_syndieammo"
item_state = "duffle_syndieammo"
item_state_slots = list(
slot_l_hand_str = "duffle_syndieammo",
slot_r_hand_str = "duffle_syndieammo",
)
/obj/item/weapon/storage/backpack/dufflebag/captain
name = "captain's dufflebag"
desc = "A large dufflebag for holding extra captainly goods."
icon_state = "duffle_captain"
item_state = "duffle_captain"
item_state_slots = list(
slot_l_hand_str = "duffle_captain",
slot_r_hand_str = "duffle_captain",
)
/obj/item/weapon/storage/backpack/dufflebag/med
name = "medical dufflebag"
desc = "A large dufflebag for holding extra medical supplies."
icon_state = "duffle_med"
item_state = "duffle_med"
item_state_slots = list(
slot_l_hand_str = "duffle_med",
slot_r_hand_str = "duffle_med",
)
/obj/item/weapon/storage/backpack/dufflebag/sec
name = "security dufflebag"
desc = "A large dufflebag for holding extra security supplies and ammunition."
icon_state = "duffle_sec"
item_state = "duffle_sec"
item_state_slots = list(
slot_l_hand_str = "duffle_sec",
slot_r_hand_str = "duffle_sec",
)
/obj/item/weapon/storage/backpack/dufflebag/eng
name = "industrial dufflebag"
desc = "A large dufflebag for holding extra tools and supplies."
icon_state = "duffle_eng"
item_state = "duffle_eng"
item_state_slots = list(
slot_l_hand_str = "duffle_eng",
slot_r_hand_str = "duffle_eng",
)
/*
* Satchel Types

View File

@@ -34,7 +34,6 @@
w_class = 4
max_w_class = 2
storage_slots = 21
can_hold = list() // any
cant_hold = list(/obj/item/weapon/disk/nuclear)
@@ -61,7 +60,6 @@
w_class = 4
max_w_class = 2
storage_slots = 21
can_hold = list() // any
cant_hold = list(/obj/item/weapon/disk/nuclear)
@@ -76,8 +74,7 @@
icon_state = "satchel"
slot_flags = SLOT_BELT | SLOT_POCKET
w_class = 3
storage_slots = 50
max_storage_space = 200 //Doesn't matter what this is, so long as it's more or equal to storage_slots * ore.w_class
max_storage_space = 100
max_w_class = 3
can_hold = list(/obj/item/weapon/ore)
@@ -90,8 +87,7 @@
name = "plant bag"
icon = 'icons/obj/hydroponics_machines.dmi'
icon_state = "plantbag"
storage_slots = 50; //the number of plant pieces it can carry.
max_storage_space = 200 //Doesn't matter what this is, so long as it's more or equal to storage_slots * plants.w_class
max_storage_space = 100
max_w_class = 3
w_class = 2
can_hold = list(/obj/item/weapon/reagent_containers/food/snacks/grown,/obj/item/seeds,/obj/item/weapon/grown)
@@ -111,6 +107,7 @@
var/capacity = 300; //the number of sheets it can carry.
w_class = 3
storage_slots = 7
allow_quick_empty = 1 // this function is superceded
New()
@@ -193,7 +190,7 @@
var/col_count = min(7,storage_slots) -1
if (adjusted_contents > 7)
row_num = round((adjusted_contents-1) / 7) // 7 is the maximum allowed width.
src.standard_orient_objs(row_num, col_count, numbered_contents)
src.slot_orient_objs(row_num, col_count, numbered_contents)
return
@@ -248,8 +245,7 @@
icon = 'icons/obj/storage.dmi'
icon_state = "cashbag"
desc = "A bag for carrying lots of cash. It's got a big dollar sign printed on the front."
storage_slots = 50; //the number of cash pieces it can carry.
max_storage_space = 200 //Doesn't matter what this is, so long as it's more or equal to storage_slots * cash.w_class
max_storage_space = 100
max_w_class = 3
w_class = 2
can_hold = list(/obj/item/weapon/coin,/obj/item/weapon/spacecash)

View File

@@ -4,6 +4,9 @@
icon = 'icons/obj/clothing/belts.dmi'
icon_state = "utilitybelt"
item_state = "utility"
storage_slots = 7
max_storage_space = 28 //This should ensure belts always have enough room to store whatever.
max_w_class = 3
slot_flags = SLOT_BELT
attack_verb = list("whipped", "lashed", "disciplined")
sprite_sheets = list("Teshari" = 'icons/mob/species/seromi/belt.dmi')
@@ -121,9 +124,7 @@
desc = "Can hold security gear like handcuffs and flashes."
icon_state = "securitybelt"
item_state = "security"
storage_slots = 7
max_w_class = 3
max_storage_space = 28
can_hold = list(
/obj/item/weapon/grenade,
/obj/item/weapon/reagent_containers/spray/pepper,
@@ -180,7 +181,13 @@
/obj/item/device/megaphone,
/obj/item/device/radio/headset,
/obj/item/clothing/gloves,
/obj/item/taperoll/police
/obj/item/taperoll/police,
/obj/item/weapon/reagent_containers/spray/pepper,
/obj/item/weapon/handcuffs,
/obj/item/device/flash,
/obj/item/weapon/flame/lighter,
/obj/item/weapon/reagent_containers/food/snacks/donut/,
/obj/item/ammo_magazine
)
/obj/item/weapon/storage/belt/soulstone
@@ -227,3 +234,27 @@
desc = "Can hold security gear like handcuffs and flashes, with more pouches for more storage."
icon_state = "bandolier"
item_state = "bandolier"
/obj/item/weapon/storage/belt/janitor
name = "janitorial belt"
desc = "A belt used to hold most janitorial supplies."
icon_state = "janibelt"
item_state = "janibelt"
storage_slots = 7
max_w_class = 3
can_hold = list(
/obj/item/clothing/glasses,
/obj/item/device/flashlight,
/obj/item/weapon/grenade,
/obj/item/device/pda,
/obj/item/device/radio/headset,
/obj/item/clothing/gloves,
/obj/item/clothing/mask/surgical, //sterile mask,
/obj/item/device/assembly/mousetrap,
/obj/item/weapon/light/bulb,
/obj/item/weapon/light/tube,
/obj/item/weapon/flame/lighter,
/obj/item/device/megaphone,
/obj/item/weapon/reagent_containers/spray,
/obj/item/weapon/soap
)

View File

@@ -25,6 +25,7 @@
icon_state = "box"
item_state = "syringe_kit"
var/foldable = /obj/item/stack/material/cardboard // BubbleWrap - if set, can be folded (when empty) into a sheet of cardboard
max_w_class = 2
// BubbleWrap - A box can be folded up to make card
/obj/item/weapon/storage/box/attack_self(mob/user as mob)
@@ -498,12 +499,11 @@
desc = "Drymate brand monkey cubes. Just add water!"
icon = 'icons/obj/food.dmi'
icon_state = "monkeycubebox"
storage_slots = 7
can_hold = list(/obj/item/weapon/reagent_containers/food/snacks/monkeycube)
New()
..()
if(src.type == /obj/item/weapon/storage/box/monkeycubes)
for(var/i = 1; i <= 5; i++)
for(var/i = 1 to 5)
new /obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped(src)
/obj/item/weapon/storage/box/monkeycubes/farwacubes
@@ -511,7 +511,7 @@
desc = "Drymate brand farwa cubes, shipped from Ahdomai. Just add water!"
New()
..()
for(var/i = 1; i <= 5; i++)
for(var/i = 1 to 5)
new /obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped/farwacube(src)
/obj/item/weapon/storage/box/monkeycubes/stokcubes
@@ -519,7 +519,7 @@
desc = "Drymate brand stok cubes, shipped from Moghes. Just add water!"
New()
..()
for(var/i = 1; i <= 5; i++)
for(var/i = 1 to 5)
new /obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped/stokcube(src)
/obj/item/weapon/storage/box/monkeycubes/neaeracubes
@@ -527,7 +527,7 @@
desc = "Drymate brand neaera cubes, shipped from Jargon 4. Just add water!"
New()
..()
for(var/i = 1; i <= 5; i++)
for(var/i = 1 to 5)
new /obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped/neaeracube(src)
/obj/item/weapon/storage/box/ids
@@ -612,11 +612,10 @@
desc = "Eight wrappers of fun! Ages 8 and up. Not suitable for children."
icon = 'icons/obj/toy.dmi'
icon_state = "spbox"
storage_slots = 8
can_hold = list(/obj/item/toy/snappop)
New()
..()
for(var/i=1; i <= storage_slots; i++)
for(var/i = 1 to 8)
new /obj/item/toy/snappop(src)
/obj/item/weapon/storage/box/matches
@@ -625,14 +624,13 @@
icon = 'icons/obj/cigarettes.dmi'
icon_state = "matchbox"
item_state = "zippo"
storage_slots = 10
w_class = 1
slot_flags = SLOT_BELT
can_hold = list(/obj/item/weapon/flame/match)
New()
..()
for(var/i=1; i <= storage_slots; i++)
for(var/i=1 to 10)
new /obj/item/weapon/flame/match(src)
attackby(obj/item/weapon/flame/match/W as obj, mob/user as mob)
@@ -650,7 +648,7 @@
icon_state = "syringe"
New()
..()
for (var/i; i < storage_slots; i++)
for (var/i = 1 to 7)
new /obj/item/weapon/reagent_containers/hypospray/autoinjector(src)
/obj/item/weapon/storage/box/lights
@@ -696,7 +694,6 @@
icon_state = "portafreezer"
item_state = "medicalpack"
foldable = null
storage_slots=7
max_w_class = 3
can_hold = list(/obj/item/organ, /obj/item/weapon/reagent_containers/food, /obj/item/weapon/reagent_containers/glass)
max_storage_space = 21

View File

@@ -53,7 +53,7 @@
/obj/item/weapon/storage/fancy/egg_box/New()
..()
for(var/i=1; i <= storage_slots; i++)
for(var/i=1 to storage_slots)
new /obj/item/weapon/reagent_containers/food/snacks/egg(src)
return
@@ -68,14 +68,13 @@
icon_state = "candlebox5"
icon_type = "candle"
item_state = "candlebox5"
storage_slots = 5
throwforce = 2
slot_flags = SLOT_BELT
/obj/item/weapon/storage/fancy/candle_box/New()
..()
for(var/i=1; i <= storage_slots; i++)
for(var/i=1 to 5)
new /obj/item/weapon/flame/candle(src)
return
@@ -89,7 +88,6 @@
icon = 'icons/obj/crayons.dmi'
icon_state = "crayonbox"
w_class = 2.0
storage_slots = 6
icon_type = "crayon"
can_hold = list(
/obj/item/weapon/pen/crayon
@@ -144,27 +142,42 @@
for(var/i = 1 to storage_slots)
new /obj/item/clothing/mask/smokable/cigarette(src)
create_reagents(15 * storage_slots)//so people can inject cigarettes without opening a packet, now with being able to inject the whole one
flags |= OPENCONTAINER
/obj/item/weapon/storage/fancy/cigarettes/update_icon()
icon_state = "[initial(icon_state)][contents.len]"
return
/obj/item/weapon/storage/fancy/cigarettes/remove_from_storage(obj/item/W as obj, atom/new_location)
// Don't try to transfer reagents to lighters
if(istype(W, /obj/item/clothing/mask/smokable/cigarette))
var/obj/item/clothing/mask/smokable/cigarette/C = W
if(!istype(C)) return // what
reagents.trans_to_obj(C, (reagents.total_volume/contents.len))
..()
..()
/obj/item/weapon/storage/fancy/cigarettes/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
if(!istype(M, /mob))
return
if(M == user && user.zone_sel.selecting == O_MOUTH && contents.len > 0 && !user.wear_mask)
var/obj/item/clothing/mask/smokable/cigarette/W = new /obj/item/clothing/mask/smokable/cigarette(user)
reagents.trans_to_obj(W, (reagents.total_volume/contents.len))
user.equip_to_slot_if_possible(W, slot_wear_mask)
if(M == user && user.zone_sel.selecting == O_MOUTH)
// Find ourselves a cig. Note that we could be full of lighters.
var/obj/item/clothing/mask/smokable/cigarette/cig = locate() in src
if(cig == null)
user << "<span class='notice'>Looks like the packet is out of cigarettes.</span>"
return
// Instead of running equip_to_slot_if_possible() we check here first,
// to avoid dousing cig with reagents if we're not going to equip it
if(!cig.mob_can_equip(user, slot_wear_mask))
return
// We call remove_from_storage first to manage the reagent transfer and
// UI updates.
remove_from_storage(cig, null)
user.equip_to_slot(cig, slot_wear_mask)
reagents.maximum_volume = 15 * contents.len
contents.len--
user << "<span class='notice'>You take a cigarette out of the pack.</span>"
update_icon()
else
@@ -248,21 +261,6 @@
reagents.trans_to_obj(C, (reagents.total_volume/contents.len))
..()
/obj/item/weapon/storage/fancy/cigar/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
if(!istype(M, /mob))
return
if(M == user && user.zone_sel.selecting == O_MOUTH && contents.len > 0 && !user.wear_mask)
var/obj/item/clothing/mask/smokable/cigarette/cigar/W = new /obj/item/clothing/mask/smokable/cigarette/cigar(user)
reagents.trans_to_obj(W, (reagents.total_volume/contents.len))
user.equip_to_slot_if_possible(W, slot_wear_mask)
reagents.maximum_volume = 15 * contents.len
contents.len--
user << "<span class='notice'>You take a cigar out of the case.</span>"
update_icon()
else
..()
/*
* Vial Box
*/
@@ -278,7 +276,7 @@
/obj/item/weapon/storage/fancy/vials/New()
..()
for(var/i=1; i <= storage_slots; i++)
for(var/i=1 to 6)
new /obj/item/weapon/reagent_containers/glass/beaker/vial(src)
return

View File

@@ -162,7 +162,6 @@
can_hold = list(/obj/item/weapon/reagent_containers/pill,/obj/item/weapon/dice,/obj/item/weapon/paper)
allow_quick_gather = 1
use_to_pickup = 1
storage_slots = 14
use_sound = null
/obj/item/weapon/storage/pill_bottle/antitox

View File

@@ -8,7 +8,6 @@
w_class = 4
max_w_class = 3
max_storage_space = 14 //The sum of the w_classes of all the items in this storage item.
storage_slots = 4
req_access = list(access_armory)
var/locked = 1
var/broken = 0

View File

@@ -15,14 +15,13 @@
icon = 'icons/obj/food.dmi'
icon_state = "donutbox"
name = "donut box"
storage_slots = 6
var/startswith = 6
can_hold = list(/obj/item/weapon/reagent_containers/food/snacks/donut)
foldable = /obj/item/stack/material/cardboard
/obj/item/weapon/storage/box/donut/New()
..()
for(var/i=1; i <= startswith; i++)
for(var/i=1 to startswith)
new /obj/item/weapon/reagent_containers/food/snacks/donut/normal(src)
update_icon()
return

View File

@@ -15,9 +15,15 @@
var/list/cant_hold = new/list() //List of objects which this item can't store (in effect only if can_hold isn't set)
var/list/is_seeing = new/list() //List of mobs which are currently seeing the contents of this item's storage
var/max_w_class = 2 //Max size of objects that this object can store (in effect only if can_hold isn't set)
var/max_storage_space = 14 //The sum of the storage costs of all the items in this storage item.
var/storage_slots = 7 //The number of storage slots in this container.
var/max_storage_space = 8 //The sum of the storage costs of all the items in this storage item.
var/storage_slots = null //The number of storage slots in this container. If null, it uses the volume-based storage instead.
var/obj/screen/storage/boxes = null
var/obj/screen/storage/storage_start = null //storage UI
var/obj/screen/storage/storage_continue = null
var/obj/screen/storage/storage_end = null
var/obj/screen/storage/stored_start = null
var/obj/screen/storage/stored_continue = null
var/obj/screen/storage/stored_end = null
var/obj/screen/close/closer = null
var/use_to_pickup //Set this to make it possible to use this item in an inverse way, so you can have the item in your hand and click items on the floor to pick them up.
var/display_contents_with_number //Set this to make the storage item group contents of the same type and display them as a number.
@@ -29,6 +35,12 @@
/obj/item/weapon/storage/Destroy()
close_all()
qdel(boxes)
qdel(src.storage_start)
qdel(src.storage_continue)
qdel(src.storage_end)
qdel(src.stored_start)
qdel(src.stored_continue)
qdel(src.stored_end)
qdel(closer)
..()
@@ -92,11 +104,19 @@
if(user.s_active)
user.s_active.hide_from(user)
user.client.screen -= src.boxes
user.client.screen -= src.storage_start
user.client.screen -= src.storage_continue
user.client.screen -= src.storage_end
user.client.screen -= src.closer
user.client.screen -= src.contents
user.client.screen += src.boxes
user.client.screen += src.closer
user.client.screen += src.contents
if(storage_slots)
user.client.screen += src.boxes
else
user.client.screen += src.storage_start
user.client.screen += src.storage_continue
user.client.screen += src.storage_end
user.s_active = src
is_seeing |= user
return
@@ -106,6 +126,9 @@
if(!user.client)
return
user.client.screen -= src.boxes
user.client.screen -= src.storage_start
user.client.screen -= src.storage_continue
user.client.screen -= src.storage_end
user.client.screen -= src.closer
user.client.screen -= src.contents
if(user.s_active == src)
@@ -157,7 +180,7 @@
return
//This proc draws out the inventory and places the items on it. It uses the standard position.
/obj/item/weapon/storage/proc/standard_orient_objs(var/rows, var/cols, var/list/obj/item/display_contents)
/obj/item/weapon/storage/proc/slot_orient_objs(var/rows, var/cols, var/list/obj/item/display_contents)
var/cx = 4
var/cy = 2+rows
src.boxes.screen_loc = "4:16,2:16 to [4+cols]:16,[2+rows]:16"
@@ -183,6 +206,52 @@
src.closer.screen_loc = "[4+cols+1]:16,2:16"
return
/obj/item/weapon/storage/proc/space_orient_objs(var/list/obj/item/display_contents)
var/baseline_max_storage_space = 16 //should be equal to default backpack capacity
var/storage_cap_width = 2 //length of sprite for start and end of the box representing total storage space
var/stored_cap_width = 4 //length of sprite for start and end of the box representing the stored item
var/storage_width = min( round( 224 * max_storage_space/baseline_max_storage_space ,1) ,274) //length of sprite for the box representing total storage space
storage_start.overlays.Cut()
var/matrix/M = matrix()
M.Scale((storage_width-storage_cap_width*2+3)/32,1)
src.storage_continue.transform = M
src.storage_start.screen_loc = "4:16,2:16"
src.storage_continue.screen_loc = "4:[storage_cap_width+(storage_width-storage_cap_width*2)/2+2],2:16"
src.storage_end.screen_loc = "4:[19+storage_width-storage_cap_width],2:16"
var/startpoint = 0
var/endpoint = 1
for(var/obj/item/O in contents)
startpoint = endpoint + 1
endpoint += storage_width * O.get_storage_cost()/max_storage_space
var/matrix/M_start = matrix()
var/matrix/M_continue = matrix()
var/matrix/M_end = matrix()
M_start.Translate(startpoint,0)
M_continue.Scale((endpoint-startpoint-stored_cap_width*2)/32,1)
M_continue.Translate(startpoint+stored_cap_width+(endpoint-startpoint-stored_cap_width*2)/2 - 16,0)
M_end.Translate(endpoint-stored_cap_width,0)
src.stored_start.transform = M_start
src.stored_continue.transform = M_continue
src.stored_end.transform = M_end
storage_start.overlays += src.stored_start
storage_start.overlays += src.stored_continue
storage_start.overlays += src.stored_end
O.screen_loc = "4:[round((startpoint+endpoint)/2)+2],2:16"
O.maptext = ""
O.layer = 20
src.closer.screen_loc = "4:[storage_width+19],2:16"
return
/datum/numbered_display
var/obj/item/sample_object
var/number
@@ -214,12 +283,14 @@
adjusted_contents++
numbered_contents.Add( new/datum/numbered_display(I) )
//var/mob/living/carbon/human/H = user
var/row_num = 0
var/col_count = min(7,storage_slots) -1
if (adjusted_contents > 7)
row_num = round((adjusted_contents-1) / 7) // 7 is the maximum allowed width.
src.standard_orient_objs(row_num, col_count, numbered_contents)
if(storage_slots == null)
src.space_orient_objs(numbered_contents)
else
var/row_num = 0
var/col_count = min(7,storage_slots) -1
if (adjusted_contents > 7)
row_num = round((adjusted_contents-1) / 7) // 7 is the maximum allowed width.
src.slot_orient_objs(row_num, col_count, numbered_contents)
return
//This proc return 1 if the item can be picked up and 0 if it can't.
@@ -227,12 +298,12 @@
/obj/item/weapon/storage/proc/can_be_inserted(obj/item/W as obj, stop_messages = 0)
if(!istype(W)) return //Not an item
if(usr.isEquipped(W) && !usr.canUnEquip(W))
if(usr && usr.isEquipped(W) && !usr.canUnEquip(W))
return 0
if(src.loc == W)
return 0 //Means the item is already in the storage item
if(contents.len >= storage_slots)
if(storage_slots != null && contents.len >= storage_slots)
if(!stop_messages)
usr << "<span class='notice'>[src] is full, make some space.</span>"
return 0 //Storage item is full
@@ -249,9 +320,9 @@
usr << "<span class='notice'>[src] cannot hold [W].</span>"
return 0
if (W.w_class > max_w_class)
if (max_w_class != null && W.w_class > max_w_class)
if(!stop_messages)
usr << "<span class='notice'>[W] is too big for this [src].</span>"
usr << "<span class='notice'>[W] is too long for \the [src].</span>"
return 0
var/total_storage_space = W.get_storage_cost()
@@ -260,7 +331,7 @@
if(total_storage_space > max_storage_space)
if(!stop_messages)
usr << "<span class='notice'>[src] is full, make some space.</span>"
usr << "<span class='notice'>[src] is too full, make some space.</span>"
return 0
if(W.w_class >= src.w_class && (istype(W, /obj/item/weapon/storage)))
@@ -437,15 +508,51 @@
else
verbs -= /obj/item/weapon/storage/verb/toggle_gathering_mode
spawn(5)
var/total_storage_space = 0
for(var/obj/item/I in contents)
total_storage_space += I.get_storage_cost()
max_storage_space = max(total_storage_space,max_storage_space) //prevents spawned containers from being too small for their contents
src.boxes = new /obj/screen/storage( )
src.boxes.name = "storage"
src.boxes.master = src
src.boxes.icon_state = "block"
src.boxes.screen_loc = "7,7 to 10,8"
src.boxes.layer = 19
src.storage_start = new /obj/screen/storage( )
src.storage_start.name = "storage"
src.storage_start.master = src
src.storage_start.icon_state = "storage_start"
src.storage_start.screen_loc = "7,7 to 10,8"
src.storage_start.layer = 19
src.storage_continue = new /obj/screen/storage( )
src.storage_continue.name = "storage"
src.storage_continue.master = src
src.storage_continue.icon_state = "storage_continue"
src.storage_continue.screen_loc = "7,7 to 10,8"
src.storage_continue.layer = 19
src.storage_end = new /obj/screen/storage( )
src.storage_end.name = "storage"
src.storage_end.master = src
src.storage_end.icon_state = "storage_end"
src.storage_end.screen_loc = "7,7 to 10,8"
src.storage_end.layer = 19
src.stored_start = new /obj //we just need these to hold the icon
src.stored_start.icon_state = "stored_start"
src.stored_start.layer = 19
src.stored_continue = new /obj
src.stored_continue.icon_state = "stored_continue"
src.stored_continue.layer = 19
src.stored_end = new /obj
src.stored_end.icon_state = "stored_end"
src.stored_end.layer = 19
src.closer = new /obj/screen/close( )
src.closer.master = src
src.closer.icon_state = "x"
src.closer.icon_state = "storage_close"
src.closer.layer = 20
orient2hud()
return
@@ -500,4 +607,19 @@
return depth
/obj/item/proc/get_storage_cost()
return 2**(w_class-1) //1,2,4,8,16,...
if (storage_cost)
return storage_cost
else
switch(w_class)
if(1)
return 1
if(2)
return 2
if(3)
return 4
if(4)
return 8
if(5)
return 16
else
return 1000

View File

@@ -11,7 +11,7 @@
throw_range = 7
w_class = 4
max_w_class = 3
max_storage_space = 14 //can hold 7 w_class-2 items or up to 3 w_class-3 items (with 1 w_class-2 item as change).
max_storage_space = 14 //enough to hold all starting contents
origin_tech = list(TECH_COMBAT = 1)
attack_verb = list("robusted")
@@ -20,48 +20,47 @@
icon_state = "red"
item_state = "toolbox_red"
New()
..()
new /obj/item/weapon/crowbar/red(src)
new /obj/item/weapon/extinguisher/mini(src)
if(prob(50))
new /obj/item/device/flashlight(src)
else
new /obj/item/device/flashlight/flare(src)
new /obj/item/device/radio(src)
/obj/item/weapon/storage/toolbox/emergency/New()
..()
new /obj/item/weapon/crowbar/red(src)
new /obj/item/weapon/extinguisher/mini(src)
if(prob(50))
new /obj/item/device/flashlight(src)
else
new /obj/item/device/flashlight/flare(src)
new /obj/item/device/radio(src)
/obj/item/weapon/storage/toolbox/mechanical
name = "mechanical toolbox"
icon_state = "blue"
item_state = "toolbox_blue"
New()
..()
new /obj/item/weapon/screwdriver(src)
new /obj/item/weapon/wrench(src)
new /obj/item/weapon/weldingtool(src)
new /obj/item/weapon/crowbar(src)
new /obj/item/device/analyzer(src)
new /obj/item/weapon/wirecutters(src)
/obj/item/weapon/storage/toolbox/mechanical/New()
..()
new /obj/item/weapon/screwdriver(src)
new /obj/item/weapon/wrench(src)
new /obj/item/weapon/weldingtool(src)
new /obj/item/weapon/crowbar(src)
new /obj/item/device/analyzer(src)
new /obj/item/weapon/wirecutters(src)
/obj/item/weapon/storage/toolbox/electrical
name = "electrical toolbox"
icon_state = "yellow"
item_state = "toolbox_yellow"
New()
..()
var/color = pick("red","yellow","green","blue","pink","orange","cyan","white")
new /obj/item/weapon/screwdriver(src)
new /obj/item/weapon/wirecutters(src)
new /obj/item/device/t_scanner(src)
new /obj/item/weapon/crowbar(src)
new /obj/item/stack/cable_coil(src,30,color)
new /obj/item/stack/cable_coil(src,30,color)
if(prob(5))
new /obj/item/clothing/gloves/yellow(src)
else
new /obj/item/stack/cable_coil(src,30,color)
/obj/item/weapon/storage/toolbox/electrical/New()
..()
new /obj/item/weapon/screwdriver(src)
new /obj/item/weapon/wirecutters(src)
new /obj/item/device/t_scanner(src)
new /obj/item/weapon/crowbar(src)
new /obj/item/stack/cable_coil/random(src,30)
new /obj/item/stack/cable_coil/random(src,30)
if(prob(5))
new /obj/item/clothing/gloves/yellow(src)
else
new /obj/item/stack/cable_coil/random(src,30)
/obj/item/weapon/storage/toolbox/syndicate
name = "black and red toolbox"
@@ -70,13 +69,104 @@
origin_tech = list(TECH_COMBAT = 1, TECH_ILLEGAL = 1)
force = 7.0
New()
..()
var/color = pick("red","yellow","green","blue","pink","orange","cyan","white")
new /obj/item/weapon/screwdriver(src)
new /obj/item/weapon/wrench(src)
new /obj/item/weapon/weldingtool(src)
new /obj/item/weapon/crowbar(src)
new /obj/item/stack/cable_coil(src,30,color)
new /obj/item/weapon/wirecutters(src)
new /obj/item/device/multitool(src)
/obj/item/weapon/storage/toolbox/syndicate/New()
..()
new /obj/item/clothing/gloves/yellow(src)
new /obj/item/weapon/screwdriver(src)
new /obj/item/weapon/wrench(src)
new /obj/item/weapon/weldingtool(src)
new /obj/item/weapon/crowbar(src)
new /obj/item/weapon/wirecutters(src)
new /obj/item/device/multitool(src)
/obj/item/weapon/storage/toolbox/lunchbox
max_storage_space = 8 //slightly smaller than a toolbox
name = "rainbow lunchbox"
icon_state = "lunchbox_rainbow"
item_state = "toolbox_pink"
desc = "A little lunchbox. This one is the colors of the rainbow!"
w_class = 3
max_w_class = 2
var/filled = FALSE
attack_verb = list("lunched")
/obj/item/weapon/storage/toolbox/lunchbox/New()
..()
if(filled)
var/list/lunches = lunchables_lunches()
var/lunch = lunches[pick(lunches)]
new lunch(src)
var/list/snacks = lunchables_snacks()
var/snack = snacks[pick(snacks)]
new snack(src)
var/list/drinks = lunchables_drinks()
var/drink = drinks[pick(drinks)]
new drink(src)
/obj/item/weapon/storage/toolbox/lunchbox/filled
filled = TRUE
/obj/item/weapon/storage/toolbox/lunchbox/heart
name = "heart lunchbox"
icon_state = "lunchbox_lovelyhearts"
item_state = "toolbox_pink"
desc = "A little lunchbox. This one has cute little hearts on it!"
/obj/item/weapon/storage/toolbox/lunchbox/heart/filled
filled = TRUE
/obj/item/weapon/storage/toolbox/lunchbox/cat
name = "cat lunchbox"
icon_state = "lunchbox_sciencecatshow"
item_state = "toolbox_green"
desc = "A little lunchbox. This one has a cute little science cat from a popular show on it!"
/obj/item/weapon/storage/toolbox/lunchbox/cat/filled
filled = TRUE
/obj/item/weapon/storage/toolbox/lunchbox/nt
name = "Nanotrasen brand lunchbox"
icon_state = "lunchbox_nanotrasen"
item_state = "toolbox_blue"
desc = "A little lunchbox. This one is branded with the Nanotrasen logo!"
/obj/item/weapon/storage/toolbox/lunchbox/nt/filled
filled = TRUE
/obj/item/weapon/storage/toolbox/lunchbox/mars
name = "\improper Mars university lunchbox"
icon_state = "lunchbox_marsuniversity"
item_state = "toolbox_red"
desc = "A little lunchbox. This one is branded with the Mars university logo!"
/obj/item/weapon/storage/toolbox/lunchbox/mars/filled
filled = TRUE
/obj/item/weapon/storage/toolbox/lunchbox/cti
name = "\improper CTI lunchbox"
icon_state = "lunchbox_cti"
item_state = "toolbox_blue"
desc = "A little lunchbox. This one is branded with the CTI logo!"
/obj/item/weapon/storage/toolbox/lunchbox/cti/filled
filled = TRUE
/obj/item/weapon/storage/toolbox/lunchbox/nymph
name = "\improper Diona nymph lunchbox"
icon_state = "lunchbox_dionanymph"
item_state = "toolbox_yellow"
desc = "A little lunchbox. This one is an adorable Diona nymph on the side!"
/obj/item/weapon/storage/toolbox/lunchbox/nymph/filled
filled = TRUE
/obj/item/weapon/storage/toolbox/lunchbox/syndicate
name = "black and red lunchbox"
icon_state = "lunchbox_syndie"
item_state = "toolbox_syndi"
desc = "A little lunchbox. This one is a sleek black and red, made of a durable steel!"
/obj/item/weapon/storage/toolbox/lunchbox/syndicate/filled
filled = TRUE

View File

@@ -127,7 +127,6 @@
/obj/item/weapon/storage/box/syndie_kit/chameleon
name = "chameleon kit"
desc = "Comes with all the clothes you need to impersonate most people. Acting lessons sold seperately."
storage_slots = 10
/obj/item/weapon/storage/box/syndie_kit/chameleon/New()
..()

View File

@@ -102,7 +102,7 @@
usr.visible_message("<span class='warning'>[user] starts climbing onto \the [src]!</span>")
climbers |= user
if(!do_after(user,(issmall(user) ? 30 : 50)))
if(!do_after(user,(issmall(user) ? 20 : 34)))
climbers -= user
return

View File

@@ -79,6 +79,7 @@
new /obj/item/weapon/caution(src)
new /obj/item/device/lightreplacer(src)
new /obj/item/weapon/storage/bag/trash(src)
new /obj/item/weapon/storage/belt/janitor(src)
new /obj/item/clothing/shoes/galoshes(src)
/*

View File

@@ -48,7 +48,13 @@
/obj/structure/closet/l3closet/janitor/New()
..()
new /obj/item/clothing/suit/bio_suit/janitor(src)
new /obj/item/clothing/suit/bio_suit/janitor(src)
new /obj/item/clothing/head/bio_hood/janitor(src)
new /obj/item/clothing/head/bio_hood/janitor(src)
new /obj/item/clothing/mask/gas(src)
new /obj/item/clothing/mask/gas(src)
new /obj/item/weapon/tank/emergency_oxygen/engi(src)
new /obj/item/weapon/tank/emergency_oxygen/engi(src)
/obj/structure/closet/l3closet/scientist

View File

@@ -17,10 +17,7 @@
new /obj/item/weapon/storage/backpack/satchel_eng(src)
if(prob(50))
new /obj/item/weapon/storage/backpack/dufflebag/eng(src)
if (prob(70))
new /obj/item/clothing/accessory/storage/brown_vest(src)
else
new /obj/item/clothing/accessory/storage/webbing(src)
new /obj/item/clothing/accessory/storage/brown_vest(src)
new /obj/item/blueprints(src)
new /obj/item/clothing/under/rank/chief_engineer(src)
new /obj/item/clothing/under/rank/chief_engineer/skirt(src)
@@ -38,6 +35,7 @@
new /obj/item/device/flash(src)
new /obj/item/taperoll/engineering(src)
new /obj/item/clothing/suit/storage/hooded/wintercoat/engineering(src)
new /obj/item/weapon/tank/emergency_oxygen/engi(src)
return
@@ -118,10 +116,7 @@
new /obj/item/weapon/storage/backpack/satchel_eng(src)
if(prob(50))
new /obj/item/weapon/storage/backpack/dufflebag/eng(src)
if (prob(70))
new /obj/item/clothing/accessory/storage/brown_vest(src)
else
new /obj/item/clothing/accessory/storage/webbing(src)
new /obj/item/clothing/accessory/storage/brown_vest(src)
new /obj/item/weapon/storage/toolbox/mechanical(src)
new /obj/item/device/radio/headset/headset_eng(src)
new /obj/item/device/radio/headset/headset_eng/alt(src)
@@ -131,7 +126,11 @@
new /obj/item/weapon/cartridge/engineering(src)
new /obj/item/taperoll/engineering(src)
new /obj/item/clothing/suit/storage/hooded/wintercoat/engineering(src)
new /obj/item/weapon/tank/emergency_oxygen/engi(src)
return
/obj/structure/closet/secure_closet/atmos_personal
name = "technician's locker"
req_access = list(access_atmospherics)
@@ -151,10 +150,7 @@
new /obj/item/weapon/storage/backpack/satchel_eng(src)
if(prob(50))
new /obj/item/weapon/storage/backpack/dufflebag/eng(src)
if (prob(70))
new /obj/item/clothing/accessory/storage/brown_vest(src)
else
new /obj/item/clothing/accessory/storage/webbing(src)
new /obj/item/clothing/accessory/storage/brown_vest(src)
new /obj/item/clothing/suit/fire/firefighter(src)
new /obj/item/device/flashlight(src)
new /obj/item/weapon/extinguisher(src)
@@ -165,4 +161,5 @@
new /obj/item/weapon/cartridge/atmos(src)
new /obj/item/taperoll/atmos(src)
new /obj/item/clothing/suit/storage/hooded/wintercoat/engineering/atmos(src)
new /obj/item/weapon/tank/emergency_oxygen/engi(src)
return

View File

@@ -70,7 +70,7 @@
new /obj/item/weapon/storage/backpack/dufflebag/med(src)
new /obj/item/clothing/under/rank/nursesuit (src)
new /obj/item/clothing/head/nursehat (src)
switch(pick("blue", "green", "purple", "black"))
switch(pick("blue", "green", "purple", "black", "navyblue"))
if ("blue")
new /obj/item/clothing/under/rank/medical/blue(src)
new /obj/item/clothing/head/surgery/blue(src)
@@ -83,7 +83,10 @@
if ("black")
new /obj/item/clothing/under/rank/medical/black(src)
new /obj/item/clothing/head/surgery/black(src)
switch(pick("blue", "green", "purple", "black"))
if ("navyblue")
new /obj/item/clothing/under/rank/medical/navyblue(src)
new /obj/item/clothing/head/surgery/navyblue(src)
switch(pick("blue", "green", "purple", "black", "navyblue"))
if ("blue")
new /obj/item/clothing/under/rank/medical/blue(src)
new /obj/item/clothing/head/surgery/blue(src)
@@ -96,6 +99,9 @@
if ("black")
new /obj/item/clothing/under/rank/medical/black(src)
new /obj/item/clothing/head/surgery/black(src)
if ("navyblue")
new /obj/item/clothing/under/rank/medical/navyblue(src)
new /obj/item/clothing/head/surgery/navyblue(src)
new /obj/item/clothing/under/rank/medical(src)
new /obj/item/clothing/under/rank/nurse(src)
new /obj/item/clothing/under/rank/orderly(src)
@@ -144,7 +150,7 @@
new /obj/item/weapon/crowbar(src)
new /obj/item/weapon/extinguisher/mini(src)
new /obj/item/weapon/storage/box/freezer(src)
new /obj/item/clothing/accessory/storage/brown_vest(src)
new /obj/item/clothing/accessory/storage/white_vest(src)
return
/obj/structure/closet/secure_closet/CMO
@@ -168,7 +174,7 @@
new /obj/item/clothing/suit/bio_suit/cmo(src)
new /obj/item/clothing/head/bio_hood/cmo(src)
new /obj/item/clothing/shoes/white(src)
switch(pick("blue", "green", "purple", "black"))
switch(pick("blue", "green", "purple", "black", "navyblue"))
if ("blue")
new /obj/item/clothing/under/rank/medical/blue(src)
new /obj/item/clothing/head/surgery/blue(src)
@@ -181,6 +187,9 @@
if ("black")
new /obj/item/clothing/under/rank/medical/black(src)
new /obj/item/clothing/head/surgery/black(src)
if ("navyblue")
new /obj/item/clothing/under/rank/medical/navyblue(src)
new /obj/item/clothing/head/surgery/navyblue(src)
new /obj/item/clothing/under/rank/chief_medical_officer(src)
new /obj/item/clothing/under/rank/chief_medical_officer/skirt(src)
new /obj/item/clothing/suit/storage/toggle/labcoat/cmo(src)

View File

@@ -10,31 +10,16 @@
New()
..()
if(prob(50))
new /obj/item/weapon/storage/backpack/captain(src)
else
new /obj/item/weapon/storage/backpack/satchel_cap(src)
if(prob(50))
new /obj/item/weapon/storage/backpack/dufflebag/captain(src)
new /obj/item/clothing/suit/captunic(src)
new /obj/item/clothing/suit/captunic/capjacket(src)
new /obj/item/clothing/head/caphat/cap(src)
new /obj/item/clothing/under/rank/captain(src)
new /obj/item/weapon/storage/backpack/dufflebag/captain(src)
new /obj/item/clothing/suit/storage/vest(src)
new /obj/item/weapon/cartridge/captain(src)
new /obj/item/clothing/head/helmet/swat(src)
new /obj/item/weapon/storage/lockbox/medal(src)
new /obj/item/clothing/shoes/brown(src)
new /obj/item/device/radio/headset/heads/captain(src)
new /obj/item/device/radio/headset/heads/captain/alt(src)
new /obj/item/clothing/gloves/captain(src)
new /obj/item/weapon/gun/energy/gun(src)
new /obj/item/clothing/suit/armor/captain(src)
new /obj/item/weapon/melee/telebaton(src)
new /obj/item/clothing/under/dress/dress_cap(src)
new /obj/item/clothing/head/caphat/formal(src)
new /obj/item/clothing/under/captainformal(src)
new /obj/item/clothing/suit/storage/hooded/wintercoat/captain(src)
return
@@ -51,7 +36,6 @@
New()
..()
new /obj/item/clothing/glasses/sunglasses(src)
new /obj/item/clothing/suit/storage/vest(src)
new /obj/item/clothing/head/helmet(src)
new /obj/item/weapon/cartridge/hop(src)
@@ -89,6 +73,8 @@
new /obj/item/clothing/shoes/white(src)
new /obj/item/clothing/under/rank/head_of_personnel_whimsy(src)
new /obj/item/clothing/head/caphat/hop(src)
new /obj/item/clothing/under/gimmick/rank/head_of_personnel/suit(src)
new /obj/item/clothing/glasses/sunglasses(src)
return
@@ -273,20 +259,8 @@
New()
..()
new /obj/item/clothing/under/det(src)
new /obj/item/clothing/under/det/grey(src)
new /obj/item/clothing/under/det/black(src)
new /obj/item/clothing/under/det/waistcoat(src)
new /obj/item/clothing/under/det/grey/waistcoat(src)
new /obj/item/clothing/suit/storage/det_trench(src)
new /obj/item/clothing/suit/storage/det_trench/grey(src)
new /obj/item/clothing/suit/storage/forensics/blue(src)
new /obj/item/clothing/suit/storage/forensics/red(src)
new /obj/item/clothing/accessory/badge/holo/detective(src)
new /obj/item/clothing/gloves/black(src)
new /obj/item/clothing/head/det(src)
new /obj/item/clothing/head/det/grey(src)
new /obj/item/clothing/shoes/laceup(src)
new /obj/item/weapon/storage/belt/detective(src)
new /obj/item/weapon/storage/box/evidence(src)
new /obj/item/device/radio/headset/headset_sec(src)
@@ -299,6 +273,7 @@
new /obj/item/clothing/accessory/holster/armpit(src)
new /obj/item/device/flashlight/maglight(src)
new /obj/item/weapon/reagent_containers/food/drinks/flask/detflask(src)
new /obj/item/weapon/storage/briefcase/crimekit(src)
return
/obj/structure/closet/secure_closet/detective/update_icon()

View File

@@ -66,18 +66,32 @@
..()
new /obj/item/clothing/head/det(src)
new /obj/item/clothing/head/det(src)
new /obj/item/clothing/shoes/brown(src)
new /obj/item/clothing/shoes/brown(src)
new /obj/item/clothing/under/det(src)
new /obj/item/clothing/under/det(src)
new /obj/item/clothing/head/det/grey(src)
new /obj/item/clothing/head/det/grey(src)
new /obj/item/clothing/shoes/brown(src)
new /obj/item/clothing/shoes/brown(src)
new /obj/item/clothing/shoes/laceup(src)
new /obj/item/clothing/shoes/laceup(src)
new /obj/item/clothing/under/det(src)
new /obj/item/clothing/under/det(src)
new /obj/item/clothing/under/det/waistcoat(src)
new /obj/item/clothing/under/det/waistcoat(src)
new /obj/item/clothing/under/det/grey(src)
new /obj/item/clothing/under/det/grey(src)
new /obj/item/clothing/under/det/grey/waistcoat(src)
new /obj/item/clothing/under/det/grey/waistcoat(src)
new /obj/item/clothing/under/det/black(src)
new /obj/item/clothing/under/det/black(src)
new /obj/item/clothing/under/det/corporate(src)
new /obj/item/clothing/under/det/corporate(src)
new /obj/item/clothing/suit/storage/det_trench(src)
new /obj/item/clothing/suit/storage/det_trench(src)
new /obj/item/clothing/suit/storage/det_trench/grey(src)
new /obj/item/clothing/suit/storage/det_trench/grey(src)
new /obj/item/clothing/suit/storage/forensics/blue(src)
new /obj/item/clothing/suit/storage/forensics/blue(src)
new /obj/item/clothing/suit/storage/forensics/red(src)
new /obj/item/clothing/suit/storage/forensics/red(src)
return
/obj/structure/closet/wardrobe/pink
@@ -280,6 +294,9 @@
new /obj/item/clothing/suit/storage/hooded/wintercoat/engineering(src)
new /obj/item/clothing/suit/storage/hooded/wintercoat/engineering(src)
new /obj/item/clothing/suit/storage/hooded/wintercoat/engineering(src)
new /obj/item/clothing/shoes/workboots(src)
new /obj/item/clothing/shoes/workboots(src)
new /obj/item/clothing/shoes/workboots(src)
return
@@ -453,6 +470,8 @@
new /obj/item/clothing/under/rank/medical/green(src)
new /obj/item/clothing/under/rank/medical/purple(src)
new /obj/item/clothing/under/rank/medical/black(src)
new /obj/item/clothing/under/rank/medical/navyblue(src)
new /obj/item/clothing/head/surgery/navyblue(src)
new /obj/item/clothing/head/surgery/purple(src)
new /obj/item/clothing/head/surgery/blue(src)
new /obj/item/clothing/head/surgery/green(src)
@@ -516,7 +535,7 @@
new /obj/item/clothing/under/pants/black(src)
new /obj/item/clothing/under/pants/tan(src)
new /obj/item/clothing/under/pants/track(src)
new /obj/item/clothing/under/pants/jeans(src)
new /obj/item/clothing/under/pants(src)
new /obj/item/clothing/under/pants/khaki(src)
new /obj/item/clothing/mask/bandana/blue(src)
new /obj/item/clothing/mask/bandana/blue(src)
@@ -589,3 +608,29 @@
new /obj/item/clothing/under/scratch(src)
new /obj/item/weapon/storage/backpack/satchel(src)
new /obj/item/weapon/storage/backpack/satchel(src)
return
/obj/structure/closet/wardrobe/captain
name = "captain's wardrobe"
icon_state = "cabinet_closed"
icon_closed = "cabinet_closed"
icon_opened = "cabinet_open"
/obj/structure/closet/wardrobe/captain/New()
..()
new /obj/item/weapon/storage/backpack/captain(src)
new /obj/item/clothing/suit/captunic(src)
new /obj/item/clothing/suit/captunic/capjacket(src)
new /obj/item/clothing/head/caphat/cap(src)
new /obj/item/clothing/under/rank/captain(src)
new /obj/item/clothing/shoes/brown(src)
new /obj/item/clothing/gloves/captain(src)
new /obj/item/clothing/under/dress/dress_cap(src)
new /obj/item/weapon/storage/backpack/satchel_cap(src)
new /obj/item/clothing/head/caphat/formal(src)
new /obj/item/clothing/under/captainformal(src)
new /obj/item/clothing/suit/storage/hooded/wintercoat/captain(src)
new /obj/item/clothing/head/beret/centcom/captain(src)
new /obj/item/clothing/under/gimmick/rank/captain/suit(src)
new /obj/item/clothing/glasses/sunglasses(src)
return

View File

@@ -40,7 +40,7 @@
/obj/structure/inflatable/bullet_act(var/obj/item/projectile/Proj)
var/proj_damage = Proj.get_structure_damage()
if(!proj_damage) return
health -= proj_damage
..()
if(health <= 0)
@@ -248,6 +248,7 @@
desc = "Contains inflatable walls and doors."
icon_state = "inf_box"
item_state = "syringe_kit"
w_class = 3
max_storage_space = 28
can_hold = list(/obj/item/inflatable)

View File

@@ -306,8 +306,8 @@
if(istype(W, /obj/item/weapon/crowbar))
user << "<span class='notice'>You struggle to pry off the outer sheath.</span>"
playsound(src, 'sound/items/Crowbar.ogg', 100, 1)
sleep(100)
if(!istype(src, /turf/simulated/wall) || !user || !W || !T ) return
if(!do_after(user,100) || !istype(src, /turf/simulated/wall) || !user || !W || !T )
return
if(user.loc == T && user.get_active_hand() == W )
user << "<span class='notice'>You pry off the outer sheath.</span>"
dismantle_wall()

View File

@@ -16,7 +16,7 @@ var/global/floorIsLava = 0
var/rendered = "<span class=\"log_message\"><span class=\"prefix\">ATTACK:</span> <span class=\"message\">[text]</span></span>"
for(var/client/C in admins)
if((R_ADMIN|R_MOD) & C.holder.rights)
if(C.is_preference_enabled(/datum/client_preference/admin/show_attack_logs))
if(C.is_preference_enabled(/datum/client_preference/mod/show_attack_logs))
var/msg = rendered
C << msg
@@ -895,22 +895,26 @@ proc/admin_notice(var/message, var/rights)
////////////////////////////////////////////////////////////////////////////////////////////////ADMIN HELPER PROCS
/proc/is_special_character(mob/M as mob) // returns 1 for specail characters and 2 for heroes of gamemode
/proc/is_special_character(var/character) // returns 1 for special characters and 2 for heroes of gamemode
if(!ticker || !ticker.mode)
return 0
if (!istype(M))
return 0
var/datum/mind/M
if (ismob(character))
var/mob/C = character
M = C.mind
else if(istype(character, /datum/mind))
M = character
if(M.mind)
if(M)
if(ticker.mode.antag_templates && ticker.mode.antag_templates.len)
for(var/datum/antagonist/antag in ticker.mode.antag_templates)
if(antag.is_antagonist(M.mind))
if(antag.is_antagonist(M))
return 2
else if(M.mind.special_role)
else if(M.special_role)
return 1
if(isrobot(M))
var/mob/living/silicon/robot/R = M
if(isrobot(character))
var/mob/living/silicon/robot/R = character
if(R.emagged)
return 1

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