Merge branch 'master' into protean-rework

This commit is contained in:
BlackMajor
2022-09-12 23:40:01 +12:00
committed by GitHub
358 changed files with 167589 additions and 233144 deletions

3
.gitignore vendored
View File

@@ -22,9 +22,6 @@ cfg/
!/.vscode/settings.json
!/.vscode/tasks.json
code/game/gamemodes/technomancer/spells/projectile/overload.dm
code/game/gamemodes/technomancer/spells/projectile/overload.dm
code/modules/client/preference_setup/loadout/loadout_xeno.dm
temp.dmi
node_modules/

5
.prettierignore Normal file
View File

@@ -0,0 +1,5 @@
# We don't want prettier to run on anything outside of the TGUI folder, so we have to do this.
/*
# We want it to run into the TGUI folder, however.
!/tgui

View File

@@ -11,6 +11,7 @@
#define WEATHER_BLOOD_MOON "blood moon" // For admin fun or cult later on.
#define WEATHER_EMBERFALL "emberfall" // More adminbuse, from TG. Harmless.
#define WEATHER_ASH_STORM "ash storm" // Ripped from TG, like the above. Less harmless.
#define WEATHER_ASH_STORM_SAFE "light ash storm" //Safe version of the ash storm. Dimmer.
#define WEATHER_FALLOUT "fallout" // Modified emberfall, actually harmful. Admin only.
#define MOON_PHASE_NEW_MOON "new moon"

View File

@@ -14,5 +14,7 @@
#define LANGUAGE_ECHOSONG "Echo Song"
#define LANGUAGE_ANIMAL "Animal"
#define LANGUAGE_TEPPI "Teppi"
#define LANGUAGE_MOUSE "Mouse"
#define LANGUAGE_SHADEKIN "Shadekin Empathy"

View File

@@ -1,5 +1,7 @@
GLOBAL_LIST_EMPTY(admins) //all clients whom are admins
GLOBAL_PROTECT(admins)
GLOBAL_LIST_EMPTY(mentors)
GLOBAL_PROTECT(mentors)
GLOBAL_LIST_EMPTY(deadmins) //all ckeys who have used the de-admin verb.
GLOBAL_LIST_EMPTY(stealthminID)
GLOBAL_LIST_EMPTY(directory) //all ckeys with associated client

View File

@@ -37,7 +37,7 @@
/proc/log_debug(text)
if (config.log_debug)
WRITE_LOG(debug_log, "DEBUG: [text]")
WRITE_LOG(debug_log, "DEBUG: [sanitize(text)]")
for(var/client/C in GLOB.admins)
if(C.is_preference_enabled(/datum/client_preference/debug/show_debug_logs))

View File

@@ -156,6 +156,7 @@
for(var/obj/O in T)
if(O.simulated)
O.loc = X
if(O.light_system == STATIC_LIGHT)
O.update_light()
if(z_level_change) // The objects still need to know if their z-level changed.
O.onTransitZ(T.z, X.z)

View File

@@ -79,6 +79,7 @@ var/list/gamemode_cache = list()
var/static/kick_inactive = 0 //force disconnect for inactive players after this many minutes, if non-0
var/static/show_mods = 0
var/static/show_devs = 0
var/static/show_mentors = 0
var/static/show_event_managers = 0
var/static/mods_can_tempban = 0
var/static/mods_can_job_tempban = 0
@@ -660,6 +661,9 @@ var/list/gamemode_cache = list()
if("show_devs")
config.show_devs = 1
if("show_mentors")
config.show_mentors = 1
if("show_event_managers")
config.show_event_managers = 1

View File

@@ -36,7 +36,7 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
if(!statclick)
statclick = new/obj/effect/statclick/debug(null, "Initializing...", src)
stat("GLOB:", statclick.update("Edit"))
stat("GLOB:", "Button Removed Due To Crashing") //VOREStation Edit
/datum/controller/global_vars/vv_edit_var(var_name, var_value)
if(gvars_datum_protected_varlist[var_name])

View File

@@ -52,7 +52,7 @@ SUBSYSTEM_DEF(chat)
for(var/I in target)
var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible
if(!C)
if(!C || !C.chatOutput)
continue // No client? No care.
else if(C.chatOutput.broken)
DIRECT_OUTPUT(C, original_message)
@@ -65,7 +65,7 @@ SUBSYSTEM_DEF(chat)
else
var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible
if(!C)
if(!C || !C.chatOutput)
return // No client? No care.
else if(C.chatOutput.broken)
DIRECT_OUTPUT(C, original_message)

View File

@@ -1,8 +1,8 @@
#define XENOARCH_SPAWN_CHANCE 0.5
#define DIGSITESIZE_LOWER 4
#define DIGSITESIZE_UPPER 12
#define ARTIFACTSPAWNNUM_LOWER 6
#define ARTIFACTSPAWNNUM_UPPER 12
#define ARTIFACTSPAWNNUM_LOWER 12
#define ARTIFACTSPAWNNUM_UPPER 24
//
// Xenoarch subsystem handles initialization of Xenoarcheaology artifacts and digsites.

View File

@@ -1,3 +1,10 @@
var/bluespace_item_types = newlist(/obj/item/weapon/storage/backpack/holding,
/obj/item/weapon/storage/bag/trash/holding,
/obj/item/weapon/storage/pouch/holding,
/obj/item/weapon/storage/belt/utility/holding,
/obj/item/weapon/storage/belt/medical/holding
)
//wrapper
/proc/do_teleport(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, local=TRUE, bohsafe=FALSE) //CHOMPStation Edit
new /datum/teleport/instant/science(arglist(args))
@@ -157,21 +164,27 @@
/datum/teleport/instant/science/setPrecision(aprecision)
..()
if(bohsafe)
return 1
if(istype(teleatom, /obj/item/weapon/storage/backpack/holding))
precision = rand(1,100)
if(bohsafe) //CHOMPedit
return 1 //CHOMPedit
var/list/bluespace_things = newlist()
for (var/item in bluespace_item_types)
if (istype(teleatom, item))
precision = rand(1, 100)
bluespace_things |= teleatom.search_contents_for(item)
var/list/bagholding = teleatom.search_contents_for(/obj/item/weapon/storage/backpack/holding)
//VOREStation Addition Start: Prevent taurriding abuse
if(istype(teleatom, /mob/living))
var/mob/living/L = teleatom
if(LAZYLEN(L.buckled_mobs))
for(var/mob/rider in L.buckled_mobs)
bagholding += rider.search_contents_for(/obj/item/weapon/storage/backpack/holding)
for (var/item in bluespace_item_types)
bluespace_things |= rider.search_contents_for(item)
//VOREStation Addition End: Prevent taurriding abuse
if(bagholding.len)
precision = max(rand(1,100)*bagholding.len,100)
if(bluespace_things.len)
precision = max(rand(1,100)*bluespace_things.len,100)
if(istype(teleatom, /mob/living))
var/mob/living/MM = teleatom
to_chat(MM, "<span class='danger'>The Bluespace interface on your [teleatom] interferes with the teleport!</span>")

View File

@@ -1,8 +1,14 @@
//wrapper
//This teleport effect means that bluespace items will cause a teleport location variation of 1 to 100 tiles.
/proc/do_noeffect_teleport(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, local=FALSE)
new /datum/teleport/instant/science/noeffect(arglist(args))
return
//This teleport effect does not interact with bluespace items.
/proc/do_safe_teleport(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, local=FALSE)
new /datum/teleport/instant(arglist(args))
return
/datum/teleport/instant/science/noeffect/setEffects(datum/effect/effect/system/aeffectin,datum/effect/effect/system/aeffectout)
return 1

View File

@@ -7,7 +7,7 @@
backpack = /obj/item/weapon/storage/backpack/captain
satchel_one = /obj/item/weapon/storage/backpack/satchel/cap
messenger_bag = /obj/item/weapon/storage/backpack/messenger/com
id_type = /obj/item/weapon/card/id/gold
id_type = /obj/item/weapon/card/id/gold/captain // CHOMPFix, captain gets their two gold stripe drip back.
pda_type = /obj/item/device/pda/captain
/decl/hierarchy/outfit/job/captain/post_equip(var/mob/living/carbon/human/H)

View File

@@ -29,7 +29,7 @@
containertype = /obj/structure/largecrate/animal/weretiger
containername = "Weretiger crate"
access = access_xenobiology
/*
/datum/supply_pack/sci/otie
name = "VARMAcorp adoptable reject (Dangerous!)"
cost = 100
@@ -43,4 +43,3 @@
containertype = /obj/structure/largecrate/animal/otie/phoron
containername = "VARMAcorp adaptive beta subject (Experimental)"
access = access_xenobiology
*/ //VORESTATION AI TEMPORARY REMOVAL. Oties commented out cuz broke.

View File

@@ -1,4 +1,4 @@
/*/datum/supply_pack/security/guardbeast //VORESTATION AI TEMPORARY REMOVAL
/datum/supply_pack/security/guardbeast
name = "VARMAcorp autoNOMous security solution"
cost = 150
containertype = /obj/structure/largecrate/animal/guardbeast
@@ -17,7 +17,6 @@
access_security,
access_xenobiology)
one_access = TRUE
*/
/datum/supply_pack/randomised/security/armor
access = access_armory

View File

@@ -48,6 +48,11 @@
name = "Ration Station Vendor Refill Cartridge"
cost = 10
/datum/supply_pack/vending_refills/altevian
contains = list(/obj/item/weapon/refill_cartridge/autoname/food/altevian)
name = "Altevian Vendor Refill Cartridge"
cost = 10
/datum/supply_pack/vending_refills/coffee
contains = list(/obj/item/weapon/refill_cartridge/autoname/drink/coffee)
name = "Hot Drinks Vendor Refill Cartridge"

View File

@@ -259,4 +259,11 @@
cost = 80
containertype = /obj/structure/closet/crate/oculum
containername = "Vox Civilian Hardsuit"
/datum/supply_pack/voidsuits/voxeng
name = "Vox Engineering Hardsuit"
contains = list (/obj/item/weapon/rig/vox/engineering)
cost = 150
containertype = /obj/structure/closet/crate/oculum
containername = "Vox Engineering Hardsuit"
//ChompEdit End

View File

@@ -6,22 +6,22 @@
/datum/uplink_item/item/tools/binoculars
name = "Binoculars"
item_cost = 5
item_cost = 3
path = /obj/item/device/binoculars
/datum/uplink_item/item/tools/toolbox // Leaving the basic as an option since powertools are loud.
name = "Fully Loaded Toolbox"
item_cost = 5
item_cost = 3
path = /obj/item/weapon/storage/toolbox/syndicate
/datum/uplink_item/item/tools/powertoolbox
name = "Fully Loaded Powertool Box"
item_cost = 10
item_cost = 5
path = /obj/item/weapon/storage/toolbox/syndicate/powertools
/datum/uplink_item/item/tools/clerical
name = "Morphic Clerical Kit"
item_cost = 10
item_cost = 5
path = /obj/item/weapon/storage/box/syndie_kit/clerical
/datum/uplink_item/item/tools/encryptionkey_radio
@@ -42,7 +42,7 @@
/datum/uplink_item/item/tools/duffle
name = "Black Duffle Bag"
item_cost = 10
item_cost = 5
path = /obj/item/weapon/storage/backpack/dufflebag/syndie
/datum/uplink_item/item/tools/duffle/med
@@ -61,7 +61,7 @@
/datum/uplink_item/item/tools/space_suit
name = "Space Suit"
item_cost = 15
item_cost = 10
path = /obj/item/weapon/storage/box/syndie_kit/space
/datum/uplink_item/item/tools/encryptionkey_binary
@@ -71,7 +71,7 @@
/datum/uplink_item/item/tools/hacking_tool
name = "Door Hacking Tool"
item_cost = 20
item_cost = 15
path = /obj/item/device/multitool/hacktool
desc = "Appears and functions as a standard multitool until the mode is toggled by applying a screwdriver appropriately. \
When in hacking mode this device will grant full access to any standard airlock within 20 to 40 seconds. \
@@ -79,7 +79,7 @@
/datum/uplink_item/item/tools/ai_detector
name = "Anti-Surveillance Tool"
item_cost = 20
item_cost = 15
path = /obj/item/device/multitool/ai_detector
desc = "This functions like a normal multitool, but includes an integrated camera network sensor that will warn the holder if they are being \
watched, by changing color and beeping. It is able to detect both AI visual surveillance and security camera utilization from terminals, and \
@@ -87,20 +87,20 @@
/datum/uplink_item/item/tools/radio_jammer
name = "Subspace Jammer"
item_cost = 25
item_cost = 20
path = /obj/item/device/radio_jammer
desc = "A device which is capable of disrupting subspace communications, preventing the use of headsets, PDAs, and communicators within \
a radius of seven meters. It runs off weapon cells, which can be replaced as needed. One cell will last for approximately ten minutes."
/datum/uplink_item/item/tools/wall_elecrtifier
name = "Wall Electrifier"
item_cost = 10
item_cost = 5
path = /obj/item/weapon/cell/spike
desc = "A modified powercell which will electrify walls and reinforced floors in a 3x3 tile range around it. Always active."
/datum/uplink_item/item/tools/emag
name = "Cryptographic Sequencer"
item_cost = 30
item_cost = 20
path = /obj/item/weapon/card/emag
/datum/uplink_item/item/tools/graviton
@@ -111,7 +111,7 @@
/datum/uplink_item/item/tools/thermal
name = "Thermal Imaging Glasses"
item_cost = 30
item_cost = 25
path = /obj/item/clothing/glasses/thermal/syndi
/datum/uplink_item/item/tools/packagebomb

View File

@@ -22,7 +22,7 @@
// Give Random Bad Mutation to M
/proc/randmutb(var/mob/living/M)
if(!M) return
if(!M || !(M.dna)) return
M.dna.check_integrity()
//var/block = pick(GLASSESBLOCK,COUGHBLOCK,FAKEBLOCK,NERVOUSBLOCK,CLUMSYBLOCK,TWITCHBLOCK,HEADACHEBLOCK,BLINDBLOCK,DEAFBLOCK,HALLUCINATIONBLOCK) // Most of these are disabled anyway.
var/block = pick(FAKEBLOCK,CLUMSYBLOCK,BLINDBLOCK,DEAFBLOCK)
@@ -30,7 +30,7 @@
// Give Random Good Mutation to M
/proc/randmutg(var/mob/living/M)
if(!M) return
if(!M || !(M.dna)) return
M.dna.check_integrity()
//var/block = pick(HULKBLOCK,XRAYBLOCK,FIREBLOCK,TELEBLOCK,NOBREATHBLOCK,REMOTEVIEWBLOCK,REGENERATEBLOCK,INCREASERUNBLOCK,REMOTETALKBLOCK,MORPHBLOCK,BLENDBLOCK,NOPRINTSBLOCK,SHOCKIMMUNITYBLOCK,SMALLSIZEBLOCK) // Much like above, most of these blocks are disabled in code.
var/block = pick(HULKBLOCK,XRAYBLOCK,FIREBLOCK,TELEBLOCK,REGENERATEBLOCK,REMOTETALKBLOCK)
@@ -38,13 +38,13 @@
// Random Appearance Mutation
/proc/randmuti(var/mob/living/M)
if(!M) return
if(!M || !(M.dna)) return
M.dna.check_integrity()
M.dna.SetUIValue(rand(1,DNA_UI_LENGTH),rand(1,4095))
// Scramble UI or SE.
/proc/scramble(var/UI, var/mob/M, var/prob)
if(!M) return
if(!M || !(M.dna)) return
M.dna.check_integrity()
if(UI)
for(var/i = 1, i <= DNA_UI_LENGTH-1, i++)

View File

@@ -14,6 +14,9 @@
/datum/alt_title/captain
title = "Captain"
/datum/job/captain/get_request_reasons()
return list("Training crew")
/datum/job/hop
disallow_jobhop = TRUE
pto_type = PTO_CIVILIAN
@@ -29,13 +32,13 @@
access_all_personal_lockers, access_maint_tunnels, access_bar, access_janitor, access_construction, access_morgue,
access_crematorium, access_kitchen, access_cargo, access_cargo_bot, access_mailsorting, access_qm, access_hydroponics, access_lawyer,
access_chapel_office, access_library, access_research, access_mining, access_heads_vault, access_mining_station,
access_hop, access_RC_announce, access_clown, access_tomfoolery, access_mime, access_keycard_auth, access_gateway)
access_hop, access_RC_announce, access_clown, access_tomfoolery, access_mime, access_keycard_auth, access_gateway, access_entertainment)
minimal_access = list(access_security, access_sec_doors, access_brig, access_forensics_lockers,
access_medical, access_engine, access_change_ids, access_ai_upload, access_eva, access_heads,
access_all_personal_lockers, access_maint_tunnels, access_bar, access_janitor, access_construction, access_morgue,
access_crematorium, access_kitchen, access_cargo, access_cargo_bot, access_mailsorting, access_qm, access_hydroponics, access_lawyer,
access_chapel_office, access_library, access_research, access_mining, access_heads_vault, access_mining_station,
access_hop, access_RC_announce, access_clown, access_tomfoolery, access_mime, access_keycard_auth, access_gateway)
access_hop, access_RC_announce, access_clown, access_tomfoolery, access_mime, access_keycard_auth, access_gateway, access_entertainment)
/datum/alt_title/deputy_director
title = "Deputy Director"
@@ -46,6 +49,9 @@
/datum/alt_title/facility_steward
title = "Facility Steward"
/datum/job/hop/get_request_reasons()
return list("ID modification", "Training crew")
/datum/job/secretary
disallow_jobhop = TRUE

View File

@@ -57,6 +57,9 @@
/datum/alt_title/cargo_supervisor
title = "Cargo Supervisor"
/datum/job/qm/get_request_reasons()
return list("Training crew")
/datum/job/cargo_tech
total_positions = 3

View File

@@ -24,7 +24,7 @@
title = "Maintenance Manager"
/datum/job/chief_engineer/get_request_reasons()
return list("Engine setup", "Construction project", "Repairs necessary")
return list("Engine setup", "Construction project", "Repairs necessary", "Training crew")
/datum/job/engineer

View File

@@ -55,6 +55,9 @@
/datum/alt_title/exploration_manager
title = "Exploration Manager"
/datum/job/pathfinder/get_request_reasons()
return list("Training crew")
/datum/job/pilot
title = "Pilot"

View File

@@ -22,7 +22,7 @@
title = "Healthcare Manager"
/datum/job/cmo/get_request_reasons()
return list("Surgery pending", "Viral outbreak")
return list("Surgery pending", "Viral outbreak", "Training crew")
/datum/job/doctor

View File

@@ -25,6 +25,9 @@
/datum/alt_title/head_scientist
title = "Head Scientist"
/datum/job/rd/get_request_reasons()
return list("Repairs needed", "Training crew")
/datum/job/scientist
spawn_positions = 5
pto_type = PTO_SCIENCE
@@ -87,6 +90,9 @@
/datum/alt_title/assembly_tech
title = "Assembly Technician"
/datum/job/roboticist/get_request_reasons()
return list("Repairs needed")
//////////////////////////////////
// Xenobotanist
//////////////////////////////////

View File

@@ -17,7 +17,7 @@
title = "Security Manager"
/datum/job/hos/get_request_reasons()
return list("Wildlife management", "Forensic investigation")
return list("Wildlife management", "Forensic investigation", "Training crew")
/datum/job/warden

View File

@@ -423,6 +423,8 @@
/obj/machinery/sleeper/relaymove(var/mob/user)
..()
if(user.incapacitated())
return
go_out()
/obj/machinery/sleeper/emp_act(var/severity)

View File

@@ -72,7 +72,7 @@
/obj/structure/barricade/cutout/attackby(var/obj/I, var/mob/user)
if(is_type_in_list(I, painters))
var/choice = tgui_input_list(user, "What would you like to paint the cutout as?", "Cutout Painting", cutout_types)
if(!choice || !Adjacent(user, src) || I != user.get_active_hand())
if(!choice || !Adjacent(user) || I != user.get_active_hand())
return TRUE
if(do_after(user, 10 SECONDS, src))
var/picked_type = cutout_types[choice]

View File

@@ -92,8 +92,8 @@
return
/obj/machinery/teleport/station/attack_ai()
attack_hand()
/obj/machinery/teleport/station/attack_ai(mob/user)
attack_hand(user)
/obj/machinery/computer/teleporter/attack_ai(mob/user)
teleport_control.tgui_interact(user)

View File

@@ -2,9 +2,9 @@
name = "virtual reality sleeper"
desc = "A fancy bed with built-in sensory I/O ports and connectors to interface users' minds with their bodies in virtual reality."
icon = 'icons/obj/Cryogenic2.dmi'
icon_state = "syndipod_0"
icon_state = "body_scanner_0"
var/base_state = "syndipod_"
var/base_state = "body_scanner_"
density = TRUE
anchored = TRUE
@@ -88,9 +88,9 @@
/obj/machinery/sleeper/relaymove(var/mob/user)
/obj/machinery/vr_sleeper/relaymove(var/mob/user)
..()
if(usr.incapacitated())
if(user.incapacitated())
return
go_out()
@@ -245,9 +245,14 @@
if(occupant.species.name != "Promethean" && occupant.species.name != "Human" && mirror_first_occupant)
avatar.shapeshifter_change_shape(occupant.species.name)
avatar.forceMove(get_turf(S)) // Put the mob on the landmark, instead of inside it
avatar.Sleeping(1)
occupant.enter_vr(avatar)
//Yes, I am using a aheal just so your markings transfer over, I could not get .prefs.copy_to working. This is very stupid, and I can't be assed to rewrite this. Too bad!
avatar.revive()
avatar.revive()
avatar.verbs += /mob/living/carbon/human/proc/exit_vr //ahealing removes the prommie verbs and the VR verbs, giving it back
avatar.Sleeping(1)
// Prompt for username after they've enterred the body.
var/newname = sanitize(tgui_input_text(avatar, "You are entering virtual reality. Your username is currently [src.name]. Would you like to change it to something else?", "Name change", null, MAX_NAME_LEN), MAX_NAME_LEN)

View File

@@ -94,10 +94,6 @@
if(power <= 0)
return
if(src in explosion_turfs)
return
explosion_turfs |= src
if(explosion_turfs[src] >= power)
return //The turf already sustained and spread a power greated than what we are dealing with. No point spreading again.
explosion_turfs[src] = power
@@ -112,7 +108,7 @@
T = get_step(src, turn(direction,90))
T.explosion_spread(spread_power, turn(direction,90), explosion_turfs)
T = get_step(src, turn(direction,-90))
T.explosion_spread(spread_power, turn(direction,90), explosion_turfs)
T.explosion_spread(spread_power, turn(direction,-90), explosion_turfs)
/turf/unsimulated/explosion_spread(power)
return //So it doesn't get to the parent proc, which simulates explosions

View File

@@ -382,7 +382,7 @@
im_list += list(list("address" = exonet.address, "to_address" = their_address, "im" = text))
log_pda("(COMM: [src]) sent \"[text]\" to [exonet.get_atom_from_address(their_address)]", usr)
var/obj/item/device/communicator/comm = exonet.get_atom_from_address(their_address)
to_chat(usr, "<span class='notice'>\icon[src][bicon(src)] Sent message to [comm.owner], <b>\"[text]\"</b> (<a href='?src=\ref[src];action=Reply;target=\ref[exonet.get_atom_from_address(comm.exonet.address)]'>Reply</a>)</span>")
to_chat(usr, "<span class='notice'>\icon[src][bicon(src)] Sent message to [istype(comm, /obj/item/device/communicator) ? comm.owner : comm.name], <b>\"[text]\"</b> (<a href='?src=\ref[src];action=Reply;target=\ref[exonet.get_atom_from_address(comm.exonet.address)]'>Reply</a>)</span>")
for(var/mob/M in player_list)
if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears))
if(istype(M, /mob/new_player) || M.forbid_seeing_deadchat)

View File

@@ -108,7 +108,7 @@
exonet.send_message(comm.exonet.address, "text", message)
im_list += list(list("address" = exonet.address, "to_address" = comm.exonet.address, "im" = message))
log_pda("(COMM: [src]) sent \"[message]\" to [exonet.get_atom_from_address(comm.exonet.address)]", usr)
to_chat(usr, "<span class='notice'>\icon[src][bicon(src)] Sent message to [comm.owner], <b>\"[message]\"</b> (<a href='?src=\ref[src];action=Reply;target=\ref[exonet.get_atom_from_address(comm.exonet.address)]'>Reply</a>)</span>")
to_chat(usr, "<span class='notice'>\icon[src][bicon(src)] Sent message to [istype(comm, /obj/item/device/communicator) ? comm.owner : comm.name], <b>\"[message]\"</b> (<a href='?src=\ref[src];action=Reply;target=\ref[exonet.get_atom_from_address(comm.exonet.address)]'>Reply</a>)</span>")
// Verb: text_communicator()
// Parameters: None

View File

@@ -308,8 +308,8 @@
return bad_vital_organ
//this needs to be last since if any of the 'other conditions are met their messages take precedence
if(!H.client && !H.teleop)
return "buzzes, \"Resuscitation failed - Mental interface error. Further attempts may be successful.\""
//if(!H.client && !H.teleop)
// return "buzzes, \"Resuscitation failed - Mental interface error. Further attempts may be successful.\""// CHOMPEdit, removing this check to allow revival through bad internet connections.
return null

View File

@@ -126,7 +126,11 @@
if(H.species.vision_organ)
vision = H.internal_organs_by_name[H.species.vision_organ]
if(!vision)
user.visible_message("<b>\The [user]</b> directs [src] at [M]'s face.", \
"<span class='notice'>You direct [src] at [M]'s face.</span>")
to_chat(user, "<span class='warning'>You can't find any [H.species.vision_organ ? H.species.vision_organ : "eyes"] on [H]!</span>")
user.setClickCooldown(user.get_attack_speed(src))
return
user.visible_message("<b>\The [user]</b> directs [src] to [M]'s eyes.", \
"<span class='notice'>You direct [src] to [M]'s eyes.</span>")

View File

@@ -53,6 +53,7 @@
var/emagged = 0
var/failmsg = ""
var/charge = 0
var/selected_color = LIGHT_COLOR_INCANDESCENT_TUBE //Default color!
// Eating used bulbs gives us bulb shards
var/bulb_shards = 0
@@ -141,6 +142,10 @@
return
*/
to_chat(usr, "It has [uses] lights remaining.")
var/new_color = input(usr, "Choose a color to set the light to! (Default is [LIGHT_COLOR_INCANDESCENT_TUBE])", "", selected_color) as color|null
if(new_color)
selected_color = new_color
to_chat(usr, "The light color has been changed.")
/obj/item/device/lightreplacer/update_icon()
icon_state = "lightreplacer[emagged]"
@@ -184,19 +189,13 @@
to_chat(U, "<span class='notice'>\The [src] has fabricated a new bulb from the broken bulbs it has stored. It now has [uses] uses.</span>")
playsound(src, 'sound/machines/ding.ogg', 50, 1)
target.status = LIGHT_EMPTY
target.installed_light = null //Remove the light!
target.update()
var/obj/item/weapon/light/L2 = new target.light_type()
target.status = L2.status
target.switchcount = L2.switchcount
target.rigged = emagged
target.brightness_range = L2.brightness_range
target.brightness_power = L2.brightness_power
target.brightness_color = L2.brightness_color
target.on = target.has_power()
L2.brightness_color = selected_color
target.insert_bulb(L2) //Call the insertion proc.
target.update()
qdel(L2)
if(target.on && target.rigged)
target.explode()

View File

@@ -20,7 +20,7 @@
to_chat(user, "<span class='warning'>\The [src] cannot be applied to [M]!</span>")
return 1
if (!M.IsAdvancedToolUser())
if (!user.IsAdvancedToolUser())
to_chat(user, "<span class='warning'>You don't have the dexterity to do this!</span>")
return 1

View File

@@ -333,7 +333,10 @@
if (prob(transfer/orig_amount * 100))
transfer_fingerprints_to(S)
if(blood_DNA)
if(S.blood_DNA)
S.blood_DNA |= blood_DNA
else
S.blood_DNA = blood_DNA.Copy()
return transfer
return 0

View File

@@ -30,3 +30,18 @@
name = "dirty fancy plate"
icon = 'icons/obj/trash_vr.dmi'
icon_state = "fancyplate"
/obj/item/trash/ratcheese
name = "\improper Flavor Unit package"
icon = 'icons/obj/trash_vr.dmi'
icon_state = "altevian_cheese_block-trash"
/obj/item/trash/ratveg
name = "\improper Premium Ration packet"
icon = 'icons/obj/trash_vr.dmi'
icon_state = "altevian_veggies-trash"
/obj/item/trash/ratjuice
name = "\improper Space-Safe Meal package"
icon = 'icons/obj/trash_vr.dmi'
icon_state = "altevian_juice-trash"

View File

@@ -119,7 +119,8 @@
recharging = TRUE
if(istype(A, /obj/item/weapon/gun/energy) && !charge_guns)
to_chat(user, "<span class='alert'>Error unable to interface with device.</span>")
to_chat(user, "<span class='alert'>Error: Device is unable to interface with weapons.</span>")
recharging = FALSE
return FALSE
//The cell we hopefully eventually find

View File

@@ -43,7 +43,7 @@
. = ..()
. += "There [uses == 1 ? "is" : "are"] [uses] [material] [uses == 1 ? src.material.sheet_singular_name : src.material.sheet_plural_name] left for use."
/obj/item/weapon/material/sharpeningkit/Initialize()
/obj/item/weapon/material/sharpeningkit/New()
. = ..()
setrepair()

View File

@@ -400,7 +400,7 @@
max_storage_space = ITEMSIZE_COST_NORMAL * 25
max_w_class = ITEMSIZE_NORMAL
w_class = ITEMSIZE_SMALL
can_hold = list(/obj/item/weapon/coin,/obj/item/weapon/spacecash)
can_hold = list(/obj/item/weapon/coin,/obj/item/weapon/spacecash,/obj/item/weapon/spacecasinocash)
// -----------------------------
// Chemistry Bag

View File

@@ -36,3 +36,6 @@
/obj/item/weapon/storage/box/brainzsnax/red
starts_with = list(/obj/item/weapon/reagent_containers/food/snacks/canned/brainzsnax/red = 6)
/obj/item/weapon/storage/box/freezer
can_hold = list(/obj/item/organ, /obj/item/weapon/reagent_containers/blood, /obj/item/weapon/reagent_containers/glass, /obj/item/weapon/reagent_containers/food)

View File

@@ -36,7 +36,8 @@
/obj/item/weapon/stamp,
/obj/item/clothing/accessory/permit,
/obj/item/clothing/accessory/badge,
/obj/item/weapon/makeover
/obj/item/weapon/makeover,
/obj/item/pizzavoucher //VOREStation edit
)
cant_hold = list(/obj/item/weapon/tool/screwdriver/power)
slot_flags = SLOT_ID

View File

@@ -100,7 +100,7 @@
/obj/item/weapon/melee/baton/examine(mob/user)
. = ..()
if(Adjacent(user, src))
if(Adjacent(user))
if(bcell)
. += "<span class='notice'>The baton is [round(bcell.percent())]% charged.</span>"
if(!bcell)

View File

@@ -0,0 +1,436 @@
/obj/structure/micro_tunnel
name = "mouse hole"
desc = "A tiny little hole... where does it go?"
icon = 'icons/obj/structures/micro_structures.dmi'
icon_state = "mouse_hole"
anchored = TRUE
density = FALSE
var/magic = FALSE //For events and stuff, if true, this tunnel will show up in the list regardless of whether it's in valid range, of if you're in a tunnel with this var, all tunnels of the same faction will show up redardless of range
micro_target = TRUE
var/static/non_micro_types = list(
/mob/living/simple_mob/vore/alienanimals/catslug,
/mob/living/simple_mob/vore/hostile/morph,
/mob/living/simple_mob/protean_blob,
/mob/living/simple_mob/slime
)
/obj/structure/micro_tunnel/Initialize()
. = ..()
if(name == initial(name))
var/area/our_area = get_area(src)
name = "[our_area.name] [name]"
if(pixel_x || pixel_y)
return
offset_tunnel()
/obj/structure/micro_tunnel/Destroy()
visible_message("<span class = 'warning'>\The [src] collapses!</span>")
for(var/mob/thing in src.contents)
visible_message("<span class = 'warning'>\The [thing] tumbles out!</span>")
thing.forceMove(get_turf(src.loc))
thing.cancel_camera()
return ..()
/obj/structure/micro_tunnel/set_dir(new_dir)
. = ..()
offset_tunnel()
/obj/structure/micro_tunnel/proc/offset_tunnel()
pixel_x = 0
pixel_y = 0
switch(dir)
if(1)
pixel_y = 32
if(2)
pixel_y = -32
if(4)
pixel_x = 32
if(8)
pixel_x = -32
/obj/structure/micro_tunnel/attack_hand(mob/living/user)
if(!isliving(user))
return ..()
if(user.loc == src)
var/list/our_options = list("Exit", "Move")
if(is_type_in_list(user, non_micro_types))
if(src.contents.len > 1)
our_options |= "Eat"
our_options |= "Cancel"
var/choice = tgui_alert(user,"It's dark and gloomy in here. What would you like to do?","Tunnel",our_options)
switch(choice)
if("Exit")
if(user.loc != src)
to_chat(user, "<span class = 'warning'>You can't do that unless you're in \the [src].</span>")
return
user.forceMove(get_turf(src.loc))
user.cancel_camera()
user.visible_message("<span class = 'notice'>\The [user] climbs out of \the [src]!</span>")
return
if("Move")
if(user.loc != src)
to_chat(user, "<span class = 'warning'>You can't do that unless you're in \the [src].</span>")
return
var/list/destinations = list()
var/turf/myturf = get_turf(src.loc)
var/datum/planet/planet
for(var/datum/planet/P in SSplanets.planets)
if(myturf.z in P.expected_z_levels)
planet = P
else
for(var/obj/structure/micro_tunnel/t in world)
if(t == src)
continue
if(magic || t.magic)
destinations |= t
continue
if(t.z == z)
destinations |= t
continue
var/turf/targetturf = get_turf(t.loc)
if(planet)
if(targetturf.z in planet.expected_z_levels)
destinations |= t
continue
else
var/above = GetAbove(myturf)
if(above && t.z == z + 1)
destinations |= t
continue
var/below = GetBelow(myturf)
if(below && t.z == z - 1)
destinations |= t
if(!destinations.len)
to_chat(user, "<span class = 'warning'>There are no other tunnels connected to this one!</span>")
return
else if(destinations.len == 1)
choice = pick(destinations)
else
choice = tgui_input_list(user, "Where would you like to go?", "Pick a tunnel", destinations)
if(!choice)
return
to_chat(user,"<span class = 'notice'>You begin moving...</span>")
if(!do_after(user, 10 SECONDS, exclusive = TRUE))
return
user.forceMove(choice)
user.cancel_camera()
var/obj/structure/micro_tunnel/da_oddawun = choice
da_oddawun.tunnel_notify(user)
return
if("Eat")
var/list/our_targets = list()
for(var/mob/living/L in src.contents)
if(L == user)
continue
our_targets |= L
if(!our_targets.len)
to_chat(user, "<span class = 'warning'>There is no one in here except for you!</span>")
return
var/mob/our_choice
if(our_targets.len == 1)
our_choice = pick(our_targets)
else
our_choice = tgui_input_list(user, "Who would you like to eat?", "Pick a target to eat", our_targets)
if(user.loc != src)
to_chat(user, "<span class = 'warning'>You are no longer inside \the [src], and so cannot eat \the [our_choice].</span>")
return
if(our_choice.loc != src)
to_chat(user, "<span class = 'warning'>\The [our_choice] is no longer inside \the [src], and so cannot be eaten.</span>")
return
user.feed_grabbed_to_self(user,our_choice)
return
if("Cancel")
return
if(!can_enter(user))
user.visible_message("<span class = 'warning'>\The [user] reaches into \the [src]. . .</span>","<span class = 'warning'>You reach into \the [src]. . .</span>")
if(!do_after(user, 3 SECONDS, exclusive = TRUE))
user.visible_message("<span class = 'notice'>\The [user] pulls their hand out of \the [src].</span>","<span class = 'warning'>You pull your hand out of \the [src]</span>")
return
if(!src.contents.len)
to_chat(user, "<span class = 'warning'>There was nothing inside.</span>")
user.visible_message("<span class = 'notice'>\The [user] pulls their hand out of \the [src].</span>","<span class = 'warning'>You pull your hand out of \the [src]</span>")
return
var/grabbed = pick(src.contents)
if(!grabbed)
to_chat(user, "<span class = 'warning'>There was nothing inside.</span>")
user.visible_message("<span class = 'notice'>\The [user] pulls their hand out of \the [src].</span>","<span class = 'warning'>You pull your hand out of \the [src]</span>")
return
if(ishuman(user))
var/mob/living/carbon/human/h = user
var/mob/living/l = grabbed
if(isliving(grabbed))
if(!l.attempt_to_scoop(h))
l.forceMove(get_turf(src.loc))
else
var/atom/movable/whatever = grabbed
whatever.forceMove(get_turf(src.loc))
user.visible_message("<span class = 'warning'>\The [user] pulls \the [grabbed] out of \the [src]! ! !</span>")
return
else if(isanimal(user))
var/mob/living/simple_mob/a = user
var/mob/living/l = grabbed
if(!a.has_hands || isliving(grabbed))
if(!l.attempt_to_scoop(a))
l.forceMove(get_turf(src.loc))
else
var/atom/movable/whatever = grabbed
whatever.forceMove(get_turf(src.loc))
user.visible_message("<span class = 'warning'>\The [user] pulls \the [grabbed] out of \the [src]! ! !</span>")
return
user.visible_message("<span class = 'notice'>\The [user] begins climbing into \the [src]!</span>")
if(!do_after(user, 10 SECONDS, exclusive = TRUE))
to_chat(user, "<span class = 'warning'>You didn't go into \the [src]!</span>")
return
enter_tunnel(user)
/obj/structure/micro_tunnel/proc/can_enter(var/mob/living/user)
if(user.mob_size <= MOB_TINY || user.get_effective_size(TRUE) <= micro_accepted_scale)
return TRUE
if(is_type_in_list(user, non_micro_types))
if(tgui_alert(user, "Would you like to enter the tunnel, or reach inside it?", "Enter or reach", list("Enter","Reach")) == "Enter")
return TRUE
return FALSE
/obj/structure/micro_tunnel/attack_generic(mob/user, damage, attack_verb)
attack_hand(user)
return ..()
/obj/structure/micro_tunnel/MouseDrop_T(mob/living/M, mob/living/user)
. = ..()
if(M != user)
return
if(!can_enter(user))
return
var/mob/living/k = M
k.visible_message("<span class = 'notice'>\The [k] begins climbing into \the [src]!</span>")
if(!do_after(k, 3 SECONDS, exclusive = TRUE))
to_chat(k, "<span class = 'warning'>You didn't go into \the [src]!</span>")
return
enter_tunnel(k)
/obj/structure/micro_tunnel/proc/enter_tunnel(mob/living/k)
k.visible_message("<span class = 'notice'>\The [k] climbs into \the [src]!</span>")
k.forceMove(src)
k.cancel_camera()
to_chat(k,"<span class = 'notice'>You are inside of \the [src]. It's dark and gloomy inside of here. You can click upon the tunnel to exit, or travel to another tunnel if there are other tunnels linked to it.</span>")
tunnel_notify(k)
/obj/structure/micro_tunnel/proc/tunnel_notify(var/mob/living/user)
to_chat(user, "<span class = 'notice'>You arrive inside \the [src].</span>")
var/our_message = "You can see "
var/found_stuff = FALSE
for(var/thing in src.contents)
if(thing == user)
continue
found_stuff = TRUE
our_message = "[our_message] [thing], "
if(isliving(thing))
var/mob/living/t = thing
to_chat(t, "<span class = 'notice'>\The [user] enters \the [src]!</span>")
if(found_stuff)
to_chat(user, "<span class = 'notice'>[our_message]inside of \the [src]!</span>")
if(prob(25))
visible_message("<span class = 'warning'>Something moves inside of \the [src]. . .</span>")
/obj/structure/micro_tunnel/magic
magic = TRUE
/obj
var/micro_accepted_scale = 0.5
var/micro_target = FALSE
/obj/Initialize(mapload)
. = ..()
if(micro_target)
verbs += /obj/proc/micro_interact
/obj/proc/micro_interact()
set name = "Micro Interact"
set desc = "Micros can enter, or move between objects with this! Non-micros can reach into objects to search for micros!"
set category = "Object"
set src in oview(1)
if(!isliving(usr))
return
var/list/contained_mobs = list()
for(var/mob/living/issamob in src.contents)
if(isliving(issamob))
contained_mobs |= issamob
if(usr.loc == src)
var/choice = tgui_alert(usr,"What would you like to do?","[src]",list("Exit", "Move", "Cancel"))
switch(choice)
if("Exit")
if(usr.loc != src)
to_chat(usr, "<span class = 'warning'>You can't do that unless you're in \the [src].</span>")
return
usr.forceMove(get_turf(src.loc))
usr.cancel_camera()
usr.visible_message("<span class = 'notice'>\The [usr] climbs out of \the [src]!</span>")
return
if("Move")
if(usr.loc != src)
to_chat(usr, "<span class = 'warning'>You can't do that unless you're in \the [src].</span>")
return
var/list/destinations = list()
var/turf/myturf = get_turf(src.loc)
for(var/obj/o in range(1,myturf))
if(!istype(o,/obj))
continue
if(o == src)
continue
if(o.micro_target)
destinations |= o
if(!destinations.len)
to_chat(usr, "<span class = 'warning'>There is nowhere to move to!</span>")
return
else if(destinations.len == 1)
choice = pick(destinations)
else
choice = tgui_input_list(usr, "Where would you like to go?", "Pick a destination", destinations)
if(!choice)
return
to_chat(usr,"<span class = 'notice'>You begin moving...</span>")
if(!do_after(usr, 10 SECONDS, exclusive = TRUE))
return
var/obj/our_choice = choice
var/list/new_contained_mobs = list()
for(var/mob/living/issamob in src.contents)
if(isliving(issamob))
contained_mobs |= issamob
usr.forceMove(our_choice)
usr.cancel_camera()
to_chat(usr,"<span class = 'notice'>You are inside of \the [our_choice]. You can click upon the thing you are in to exit, or travel to a nearby thing if there are other tunnels linked to it.</span>")
var/our_message = "You can see "
var/found_stuff = FALSE
for(var/thing in new_contained_mobs)
if(thing == usr)
continue
found_stuff = TRUE
our_message = "[our_message] [thing], "
if(isliving(thing))
var/mob/living/t = thing
to_chat(t, "<span class = 'notice'>\The [usr] enters \the [src]!</span>")
if(found_stuff)
to_chat(usr, "<span class = 'notice'>[our_message]inside of \the [src]!</span>")
if(prob(25))
our_choice.visible_message("<span class = 'warning'>Something moves inside of \the [our_choice]. . .</span>")
return
if("Cancel")
return
if(!(usr.mob_size <= MOB_TINY || usr.get_effective_size(TRUE) <= micro_accepted_scale))
usr.visible_message("<span class = 'warning'>\The [usr] reaches into \the [src]. . .</span>","<span class = 'warning'>You reach into \the [src]. . .</span>")
if(!do_after(usr, 3 SECONDS, exclusive = TRUE))
usr.visible_message("<span class = 'notice'>\The [usr] pulls their hand out of \the [src].</span>","<span class = 'warning'>You pull your hand out of \the [src]</span>")
return
if(!contained_mobs.len)
to_chat(usr, "<span class = 'warning'>There was nothing inside.</span>")
usr.visible_message("<span class = 'notice'>\The [usr] pulls their hand out of \the [src].</span>","<span class = 'warning'>You pull your hand out of \the [src]</span>")
return
var/grabbed = pick(contained_mobs)
if(!grabbed)
to_chat(usr, "<span class = 'warning'>There was nothing inside.</span>")
usr.visible_message("<span class = 'notice'>\The [usr] pulls their hand out of \the [src].</span>","<span class = 'warning'>You pull your hand out of \the [src]</span>")
return
if(ishuman(usr))
var/mob/living/carbon/human/h = usr
var/mob/living/l = grabbed
if(isliving(grabbed))
l.attempt_to_scoop(h)
if(!l.attempt_to_scoop(h))
l.forceMove(get_turf(src.loc))
else
var/atom/movable/whatever = grabbed
whatever.forceMove(get_turf(src.loc))
usr.visible_message("<span class = 'warning'>\The [usr] pulls \the [grabbed] out of \the [src]! ! !</span>")
return
else if(isanimal(usr))
var/mob/living/simple_mob/a = usr
var/mob/living/l = grabbed
if(!a.has_hands || isliving(grabbed))
if(!l.attempt_to_scoop(a))
l.forceMove(get_turf(src.loc))
else
var/atom/movable/whatever = grabbed
whatever.forceMove(get_turf(src.loc))
usr.visible_message("<span class = 'warning'>\The [usr] pulls \the [grabbed] out of \the [src]! ! !</span>")
return
usr.visible_message("<span class = 'notice'>\The [usr] begins climbing into \the [src]!</span>")
if(!do_after(usr, 10 SECONDS, exclusive = TRUE))
to_chat(usr, "<span class = 'warning'>You didn't go into \the [src]!</span>")
return
usr.visible_message("<span class = 'notice'>\The [usr] climbs into \the [src]!</span>")
usr.forceMove(src)
usr.cancel_camera()
to_chat(usr,"<span class = 'notice'>You are inside of \the [src]. You can click upon the tunnel to exit, or travel to another tunnel if there are other tunnels linked to it.</span>")
var/our_message = "You can see "
var/found_stuff = FALSE
for(var/thing in contained_mobs)
if(thing == usr)
continue
found_stuff = TRUE
our_message = "[our_message] [thing], "
if(isliving(thing))
var/mob/living/t = thing
to_chat(t, "<span class = 'notice'>\The [usr] enters \the [src]!</span>")
if(found_stuff)
to_chat(usr, "<span class = 'notice'>[our_message]inside of \the [src]!</span>")
if(prob(25))
visible_message("<span class = 'warning'>Something moves inside of \the [src]. . .</span>")
/obj/effect/mouse_hole_spawner
name = "mouse hole spawner"
icon = 'icons/obj/landmark_vr.dmi'
icon_state = "blue-x"
invisibility = 101
var/chance_to_spawn = 25
/obj/effect/mouse_hole_spawner/Initialize()
. = ..()
if(prob(chance_to_spawn))
var/obj/structure/micro_tunnel/tunnel = new (get_turf(src.loc))
tunnel.set_dir(dir)
qdel(src)

View File

@@ -23,6 +23,20 @@
/obj/Destroy()
STOP_PROCESSING(SSobj, src)
//VOREStation Add Start - I really am an idiot why did I make it this way
if(micro_target)
for(var/thing in src.contents)
if(!ismob(thing))
continue
var/mob/m = thing
if(isbelly(src.loc))
m.forceMove(src.loc)
else
m.forceMove(get_turf(src.loc))
m.visible_message("<span class = 'notice'>\The [m] tumbles out of \the [src]!</span>")
//VOREStation Add End
return ..()
/obj/Topic(href, href_list, var/datum/tgui_state/state = GLOB.tgui_default_state)

View File

@@ -97,7 +97,8 @@
/obj/machinery/vending/weeb,
/obj/machinery/vending/sol,
/obj/machinery/vending/snix,
/obj/machinery/vending/snlvend)
/obj/machinery/vending/snlvend,
/obj/machinery/vending/altevian)
/obj/random/vendordrink //Random drink vendors for station use
name = "random drink vending machine"

View File

@@ -323,7 +323,7 @@
name = "random drink"
desc = "This is a random drink."
icon = 'icons/obj/drinks.dmi'
icon_state = "whiskeybottle"
icon_state = "whiskeybottle1"
/obj/random/drinkbottle/item_to_spawn()
return pick(/obj/item/weapon/reagent_containers/food/drinks/bottle/whiskey,

View File

@@ -106,7 +106,7 @@
if(choice == "No")
return
var/basecolor = input(user, "Select a base color for the canvas:", "Base Color", canvas_color) as null|color
if(basecolor && Adjacent(user, src) && Adjacent(user, I))
if(basecolor && Adjacent(user) && user.get_active_hand() == I)
canvas_color = basecolor
reset_grid()
user.visible_message("[user] smears paint on [src], covering the entire thing in paint.", "You smear paint on [src], changing the color of the entire thing.", runemessage = "smears paint")

View File

@@ -56,7 +56,7 @@
/mob/living/simple_mob/otie/zorgoia, //CHOMPstation edit
/mob/living/simple_mob/vore/rabbit,
/mob/living/simple_mob/vore/weretiger;0.5,
// /mob/living/simple_mob/otie;0.5
/mob/living/simple_mob/otie;0.5
))
return ..()
@@ -72,11 +72,12 @@
/mob/living/simple_mob/animal/space/alien/drone,
/mob/living/simple_mob/animal/space/alien/sentinel,
/mob/living/simple_mob/animal/space/alien/queen,
// /mob/living/simple_mob/otie/feral,
// /mob/living/simple_mob/otie/red,
/mob/living/simple_mob/otie/feral,
/mob/living/simple_mob/otie/feral/chubby,
/mob/living/simple_mob/otie/red,
/mob/living/simple_mob/vore/aggressive/corrupthound))
return ..()
/*
/obj/structure/largecrate/animal/guardbeast
name = "VARMAcorp autoNOMous security solution"
desc = "The VARMAcorp bioengineering division flagship product on trained optimal snowflake guard dogs."
@@ -84,6 +85,11 @@
icon_state = "sotiecrate"
starts_with = list(/mob/living/simple_mob/otie/security)
/obj/structure/largecrate/animal/otie/guardbeast/Initialize()
starts_with = list(pick(/mob/living/simple_mob/otie/security,
/mob/living/simple_mob/otie/security/chubby))
return ..()
/obj/structure/largecrate/animal/guardmutant
name = "VARMAcorp autoNOMous security solution for hostile environments."
desc = "The VARMAcorp bioengineering division flagship product on trained optimal snowflake guard dogs. This one can survive hostile atmosphere."
@@ -91,6 +97,12 @@
icon_state = "sotiecrate"
starts_with = list(/mob/living/simple_mob/otie/security/phoron)
/obj/structure/largecrate/animal/otie/guardmutant/Initialize()
starts_with = list(pick(/mob/living/simple_mob/otie/security/phoron;2,
/mob/living/simple_mob/otie/security/phoron/red;0.5,
/mob/living/simple_mob/otie/security/phoron/red/chubby;0.5))
return ..()
/obj/structure/largecrate/animal/otie
name = "VARMAcorp adoptable reject (Dangerous!)"
desc = "A warning on the side says the creature inside was returned to the supplier after injuring or devouring several unlucky members of the previous adoption family. It was given a second chance with the next customer. Godspeed and good luck with your new pet!"
@@ -99,6 +111,11 @@
starts_with = list(/mob/living/simple_mob/otie/cotie)
var/taped = 1
/obj/structure/largecrate/animal/otie/Initialize()
starts_with = list(pick(/mob/living/simple_mob/otie/cotie,
/mob/living/simple_mob/otie/cotie/chubby))
return ..()
/obj/structure/largecrate/animal/otie/phoron
name = "VARMAcorp adaptive beta subject (Experimental)"
desc = "VARMAcorp experimental hostile environment adaptive breeding development kit. WARNING, DO NOT RELEASE IN WILD!"
@@ -106,7 +123,8 @@
/obj/structure/largecrate/animal/otie/phoron/Initialize()
starts_with = list(pick(/mob/living/simple_mob/otie/cotie/phoron;2,
/mob/living/simple_mob/otie/red/friendly;0.5))
/mob/living/simple_mob/otie/red/friendly;0.5,
/mob/living/simple_mob/otie/red/chubby;0.5))
return ..()
/obj/structure/largecrate/animal/otie/attack_hand(mob/living/carbon/human/M as mob)//I just couldn't decide between the icons lmao
@@ -115,7 +133,6 @@
icon_state = "otiecrate"
taped = 0
..()
*/ //VORESTATION AI REMOVAL, Oties are still fucking broken.
/obj/structure/largecrate/animal/catgirl
name = "Catgirl Crate"

View File

@@ -13,9 +13,11 @@
// Looping through the player list has the added bonus of working for mobs inside containers
var/sound/S = sound(get_sfx(soundin))
var/maxdistance = (world.view + extrarange) * 2 //VOREStation Edit - 3 to 2
var/list/listeners = player_list
var/list/listeners = player_list.Copy()
if(!ignore_walls) //these sounds don't carry through walls
listeners = listeners & hearers(maxdistance,turf_source)
for(var/mob/listen in listeners)
if(!(get_turf(listen) in hear(maxdistance,source)))
listeners -= listen
for(var/mob/M as anything in listeners)
if(!M || !M.client)
continue

View File

@@ -80,8 +80,8 @@ var/world_topic_spam_protect_ip = "0.0.0.0"
var/world_topic_spam_protect_time = world.timeofday
/world/Topic(T, addr, master, key)
TGS_TOPIC
VGS_TOPIC // VOREStation Edit - VGS
VGS_TOPIC // VOREStation Edit - VGS //CHOMP Edit swapped lines around
TGS_TOPIC //CHOMP Edit swapped lines around
log_topic("\"[T]\", from:[addr], master:[master], key:[key]")
if (T == "ping")
@@ -509,12 +509,9 @@ var/world_topic_spam_protect_time = world.timeofday
if (copytext(line, 1, 2) == ";")
continue
var/title = "Mentor"
var/rights = admin_ranks[title]
var/ckey = copytext(line, 1, length(line)+1)
var/datum/admins/D = new /datum/admins(title, rights, ckey)
D.associate(GLOB.directory[ckey])
var/datum/mentor/M = new /datum/mentor(ckey)
M.associate(GLOB.directory[ckey])
/world/proc/update_status()
var/s = ""

View File

@@ -7,6 +7,8 @@ var/list/admin_verbs_default = list(
/client/proc/cmd_admin_say, //VOREStation Add,
/client/proc/cmd_mod_say, //VOREStation Add,
/client/proc/cmd_event_say, //VOREStation Add,
/client/proc/cmd_mentor_ticket_panel,
/client/proc/cmd_mentor_say
// /client/proc/hide_verbs, //hides all our adminverbs, //VOREStation Remove,
// /client/proc/hide_most_verbs, //hides all our hideable adminverbs, //VOREStation Remove,
// /client/proc/debug_variables, //allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify, //VOREStation Remove,
@@ -122,7 +124,9 @@ var/list/admin_verbs_admin = list(
/datum/admins/proc/set_uplink, //VOREStation Add,
/datum/admins/proc/sendFax,
/client/proc/despawn_player,
/datum/admins/proc/view_feedback
/datum/admins/proc/view_feedback,
/client/proc/make_mentor,
/client/proc/unmake_mentor
)
var/list/admin_verbs_ban = list(

View File

@@ -24,6 +24,8 @@
else if(href_list["ahelp_tickets"])
GLOB.ahelp_tickets.BrowseTickets(text2num(href_list["ahelp_tickets"]))
mentor_commands(href, href_list, src)
if(href_list["dbsearchckey"] || href_list["dbsearchadmin"])
var/adminckey = href_list["dbsearchadmin"]

View File

@@ -627,6 +627,9 @@
/obj/effect/bmode/buildmode/proc/get_path_from_partial_text(default_path)
var/desired_path = tgui_input_text(usr, "Enter full or partial typepath.","Typepath","[default_path]")
if(!desired_path) //VOREStation Add - If you don't give it anything it builds a list of every possible thing in the game and crashes your client.
return //VOREStation Add - And the main way for it to do that is to push the cancel button, which should just do nothing. :U
var/list/types = typesof(/atom)
var/list/matches = list()

View File

@@ -16,7 +16,7 @@
to_chat(usr, "<font color='red'> You cannot pray (muted).</font>")
return
var/image/cross = image('icons/obj/storage.dmi',"bible")
var/icon/cross = icon('icons/obj/storage.dmi',"bible")
msg = "<font color='blue'>\icon[cross][bicon(cross)] <b><font color=purple>PRAY: </font>[key_name(src, 1)] (<A HREF='?_src_=holder;adminmoreinfo=\ref[src]'>?</A>) (<A HREF='?_src_=holder;adminplayeropts=\ref[src]'>PP</A>) (<A HREF='?_src_=vars;Vars=\ref[src]'>VV</A>) (<A HREF='?_src_=holder;subtlemessage=\ref[src]'>SM</A>) ([admin_jump_link(src, src)]) (<A HREF='?_src_=holder;secretsadmin=check_antagonist'>CA</A>) (<A HREF='?_src_=holder;adminspawncookie=\ref[src]'>SC</a>) (<A HREF='?_src_=holder;adminsmite=\ref[src]'>SMITE</a>):</b> [msg]</font>"
for(var/client/C in GLOB.admins)

View File

@@ -123,6 +123,12 @@
/datum/ai_holder/simple_mob/xenobio_slime/handle_special_tactic()
evolve_and_reproduce()
/datum/ai_holder/simple_mob/xenobio_slime/handle_stance_tactical()
if(!istype(holder) || QDELETED(holder))
qdel(src)
return
..()
// Hit the correct verbs to keep the slime species going.
/datum/ai_holder/simple_mob/xenobio_slime/proc/evolve_and_reproduce()
var/mob/living/simple_mob/slime/xenobio/my_slime = holder

View File

@@ -534,27 +534,27 @@
return
//
//Slave Terminal
//Sentient Prize Terminal
//
/obj/machinery/casinoslave_handler
/obj/machinery/casinosentientprize_handler
name = "Sentient Prize Automated Sales Machinery"
desc = "The Sentient Prize Automated Sales Machinery, also known as SPASM! Here one can see who is on sale as sentinet prizes, as well as selling self and also buying prizes."
icon = 'icons/obj/casino.dmi'
icon_state = "casinoslave_hub_off"
density = 1
density = 0
anchored = 1
req_access = list(300)
req_access = list(101)
var/casinoslave_sale = "disabled"
var/casinoslave_price = 100
var/casinosentientprize_sale = "disabled"
var/casinosentientprize_price = 500
var/collar_list = list()
var/slaves_ckeys_list = list() //Same trick as lottery, to keep life simple
var/obj/item/clothing/accessory/collar/casinoslave/selected_collar = null
var/sentientprizes_ckeys_list = list() //Same trick as lottery, to keep life simple
var/obj/item/clothing/accessory/collar/casinosentientprize/selected_collar = null
/obj/machinery/casinoslave_handler/attack_hand(mob/living/user as mob)
/obj/machinery/casinosentientprize_handler/attack_hand(mob/living/user as mob)
if(usr.incapacitated())
return
if(casinoslave_sale == "disabled")
if(casinosentientprize_sale == "disabled")
to_chat(user,"<span class='notice'>The SPASM is disabled.</span> ")
return
@@ -565,14 +565,14 @@
if("Show selected Prize")
if(QDELETED(selected_collar))
collar_list -= selected_collar
slaves_ckeys_list -= selected_collar.slaveckey
sentientprizes_ckeys_list -= selected_collar.sentientprizeckey
to_chat(user, "<span class='warning'>No collar is currently selected or the currently selected one has been destroyed or disabled.</span>")
selected_collar = null
return
to_chat(user, "<span class='warning'>Sentient Prize information</span>")
to_chat(user, "<span class='notice'>Name: [selected_collar.slavename]</span>")
to_chat(user, "<span class='notice'>Description: [selected_collar.slaveflavor]</span>")
to_chat(user, "<span class='notice'>OOC: [selected_collar.slaveooc]</span>")
to_chat(user, "<span class='notice'>Name: [selected_collar.sentientprizename]</span>")
to_chat(user, "<span class='notice'>Description: [selected_collar.sentientprizeflavor]</span>")
to_chat(user, "<span class='notice'>OOC: [selected_collar.sentientprizeooc]</span>")
if(selected_collar.ownername != null)
to_chat(user, "<span class='warning'>This prize is already owned by [selected_collar.ownername]</span>")
@@ -580,47 +580,50 @@
selected_collar = tgui_input_list(user, "Select a prize", "Chose a collar", collar_list)
if(QDELETED(selected_collar))
collar_list -= selected_collar
slaves_ckeys_list -= selected_collar.slaveckey
sentientprizes_ckeys_list -= selected_collar.sentientprizeckey
to_chat(user, "<span class='warning'>No collars to chose, or selected collar has been destroyed or deactived, selection has been removed from list.</span>")
selected_collar = null
return
if("Become Prize (Please examine yourself first)") //Its awkward, but no easy way to obtain flavor_text due to server not loading text of mob until its been examined at least once.
var/safety_ckey = user.client.ckey
if(safety_ckey in slaves_ckeys_list)
if(safety_ckey in sentientprizes_ckeys_list)
to_chat(user, "<span class='warning'>The SPASM beeps in an upset manner, you already have a collar!</span>")
return
var/confirm = tgui_alert(usr, "Are you sure you want to become a sentient prize?", "Confirm Sentient Prize", list("Yes", "No"))
if(confirm == "Yes")
to_chat(user, "<span class='warning'>You are now a prize!</span>")
if(safety_ckey in slaves_ckeys_list)
if(safety_ckey in sentientprizes_ckeys_list)
to_chat(user, "<span class='warning'>The SPASM beeps in an upset manner, you already have a collar!</span>")
return
slaves_ckeys_list += user.ckey
var/obj/item/clothing/accessory/collar/casinoslave/C = new(src.loc)
C.slavename = "[user.name]"
C.slaveckey = "[user.ckey]"
C.slaveflavor = user.flavor_text
C.slaveooc = user.ooc_notes
sentientprizes_ckeys_list += user.ckey
var/obj/item/clothing/accessory/collar/casinosentientprize/C = new(src.loc)
C.sentientprizename = "[user.name]"
C.sentientprizeckey = "[user.ckey]"
C.sentientprizeflavor = user.flavor_text
C.sentientprizeooc = user.ooc_notes
C.name = "Sentient Prize Collar: Available! [user.name] purchaseable at the SPASM!"
C.desc = "SPASM collar. The tags shows in flashy colorful text the wearer is [user.name] and is currently available to buy at the Sentient Prize Automated Sales Machinery!"
C.icon_state = "casinoslave_available"
C.update_icon()
collar_list += C
spawn_casinochips(casinoslave_price, src.loc)
spawn_casinochips(casinosentientprize_price, src.loc)
/obj/machinery/casinoslave_handler/attackby(obj/item/weapon/W as obj, mob/user as mob)
/obj/machinery/casinosentientprize_handler/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(usr.incapacitated())
return
if(istype(W, /obj/item/weapon/spacecasinocash))
if(casinoslave_sale == "disabled")
if(casinosentientprize_sale == "disabled")
to_chat(user, "<span class='warning'>Sentient Prize sales are currently disabled.</span>")
return
if(!selected_collar)
to_chat(user, "<span class='warning'>Select a prize first.</span>")
return
if(!selected_collar.ownername)
var/obj/item/weapon/spacecasinocash/C = W
if(user.client.ckey == selected_collar.slaveckey)
if(user.client.ckey == selected_collar.sentientprizeckey)
insert_chip(C, user, "selfbuy")
return
else
@@ -630,12 +633,12 @@
to_chat(user, "<span class='warning'>This Sentient Prize is already owned! If you are the owner you can release the prize by swiping the collar on the SPASM!</span>")
return
if(istype(W, /obj/item/clothing/accessory/collar/casinoslave))
var/obj/item/clothing/accessory/collar/casinoslave/C = W
if(user.name != C.slavename && user.name != C.ownername)
if(istype(W, /obj/item/clothing/accessory/collar/casinosentientprize))
var/obj/item/clothing/accessory/collar/casinosentientprize/C = W
if(user.name != C.sentientprizename && user.name != C.ownername)
to_chat(user, "<span class='warning'>This Sentient Prize collar isn't yours, please give it to the one it tagged for, belongs to, or a casino staff member!</span>")
return
if(user.name == C.slavename)
if(user.name == C.sentientprizename)
if(!C.ownername)
to_chat(user,"<span class='notice'>If collar isn't disabled and entry removed, please select your entry and insert chips. Or contact staff if you need assistance.</span> ")
return
@@ -643,15 +646,15 @@
to_chat(user,"<span class='notice'>If collar isn't disabled and entry removed, please ask your owner to free you with collar swipe on the SPASM, or contact staff if you need assistance.</span> ")
return
if(user.name == C.ownername)
var/confirm = tgui_alert(usr, "Are you sure you want to wipe [C.slavename] entry?", "Confirm Sentient Prize Release", list("Yes", "No"))
var/confirm = tgui_alert(usr, "Are you sure you want to wipe [C.sentientprizename] entry?", "Confirm Sentient Prize Release", list("Yes", "No"))
if(confirm == "Yes")
to_chat(user, "<span class='warning'>[C.slavename] collar has been deleted from registry!</span>")
to_chat(user, "<span class='warning'>[C.sentientprizename] collar has been deleted from registry!</span>")
C.icon_state = "casinoslave"
C.update_icon()
C.name = "a disabled Sentient Prize Collar: [C.slavename]"
C.desc = "A collar worn by sentient prizes registered to a SPASM. The tag says its registered to [C.slavename], but harsh red text informs you its been disabled."
slaves_ckeys_list -= C.slaveckey
C.slaveckey = null
C.name = "disabled Sentient Prize Collar: [C.sentientprizename]"
C.desc = "A collar worn by sentient prizes registered to a SPASM. The tag says its registered to [C.sentientprizename], but harsh red text informs you its been disabled."
sentientprizes_ckeys_list -= C.sentientprizeckey
C.sentientprizeckey = null
collar_list -= C
if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
@@ -666,13 +669,13 @@
return
if("Toggle Sentient Prize Sales")
if(casinoslave_sale == "disabled")
casinoslave_sale = "enabled"
if(casinosentientprize_sale == "disabled")
casinosentientprize_sale = "enabled"
icon_state = "casinoslave_hub_on"
update_icon()
to_chat(user,"<span class='notice'>Prize sale has been enabled.</span> ")
else
casinoslave_sale = "disabled"
casinosentientprize_sale = "disabled"
icon_state = "casinoslave_hub_off"
update_icon()
to_chat(user,"<span class='notice'>Prize sale has been disabled.</span> ")
@@ -683,21 +686,21 @@
return
if(QDELETED(selected_collar))
collar_list -= selected_collar
slaves_ckeys_list -= selected_collar.slaveckey
sentientprizes_ckeys_list -= selected_collar.sentientprizeckey
to_chat(user, "<span class='warning'>Collar has been destroyed!</span>")
selected_collar = null
return
var/safety_ckey = selected_collar.slaveckey
var/confirm = tgui_alert(usr, "Are you sure you want to wipe [selected_collar.slavename] entry?", "Confirm Sentient Prize", list("Yes", "No"))
var/safety_ckey = selected_collar.sentientprizeckey
var/confirm = tgui_alert(usr, "Are you sure you want to wipe [selected_collar.sentientprizename] entry?", "Confirm Sentient Prize", list("Yes", "No"))
if(confirm == "Yes")
if(safety_ckey == selected_collar.slaveckey)
to_chat(user, "<span class='warning'>[selected_collar.slavename] collar has been deleted from registry!</span>")
if(safety_ckey == selected_collar.sentientprizeckey)
to_chat(user, "<span class='warning'>[selected_collar.sentientprizename] collar has been deleted from registry!</span>")
selected_collar.icon_state = "casinoslave"
selected_collar.update_icon()
selected_collar.name = "a disabled Sentient Prize Collar: [selected_collar.slavename]"
selected_collar.desc = "A collar worn by sentient prizes registered to a SPASM. The tag says its registered to [selected_collar.slavename], but harsh red text informs you its been disabled."
slaves_ckeys_list -= selected_collar.slaveckey
selected_collar.slaveckey = null
selected_collar.name = "disabled Sentient Prize Collar: [selected_collar.sentientprizename]"
selected_collar.desc = "A collar worn by sentient prizes registered to a SPASM. The tag says its registered to [selected_collar.sentientprizename], but harsh red text informs you its been disabled."
sentientprizes_ckeys_list -= selected_collar.sentientprizeckey
selected_collar.sentientprizeckey = null
collar_list -= selected_collar
selected_collar = null
else
@@ -707,12 +710,12 @@
if("Change Prize Value")
setprice(user)
/obj/machinery/casinoslave_handler/proc/insert_chip(var/obj/item/weapon/spacecasinocash/cashmoney, mob/user, var/buystate)
if(cashmoney.worth < casinoslave_price)
/obj/machinery/casinosentientprize_handler/proc/insert_chip(var/obj/item/weapon/spacecasinocash/cashmoney, mob/user, var/buystate)
if(cashmoney.worth < casinosentientprize_price)
to_chat(user,"<span class='notice'>You dont have enough chips to pay for the sentient prize!</span> ")
return
cashmoney.worth -= casinoslave_price
cashmoney.worth -= casinosentientprize_price
cashmoney.update_icon()
if(cashmoney.worth <= 0)
@@ -721,31 +724,31 @@
cashmoney.update_icon()
if(buystate == "selfbuy")
to_chat(user,"<span class='notice'>You put [casinoslave_price] credits worth of chips into the SPASM and nullify your collar!</span> ")
to_chat(user,"<span class='notice'>You put [casinosentientprize_price] credits worth of chips into the SPASM and nullify your collar!</span> ")
selected_collar.icon_state = "casinoslave"
selected_collar.update_icon()
selected_collar.name = "a disabled Sentient Prize Collar: [selected_collar.slavename]"
selected_collar.desc = "A collar worn by sentient prizes registered to a SPASM. The tag says its registered to [selected_collar.slavename], but harsh red text informs you its been disabled."
slaves_ckeys_list -= selected_collar.slaveckey
selected_collar.slaveckey = null
selected_collar.name = "disabled Sentient Prize Collar: [selected_collar.sentientprizename]"
selected_collar.desc = "A collar worn by sentient prizes registered to a SPASM. The tag says its registered to [selected_collar.sentientprizename], but harsh red text informs you its been disabled."
sentientprizes_ckeys_list -= selected_collar.sentientprizeckey
selected_collar.sentientprizeckey = null
collar_list -= selected_collar
selected_collar = null
if(buystate == "buy")
to_chat(user,"<span class='notice'>You put [casinoslave_price] credits worth of chips into the SPASM and it pings to inform you bought [selected_collar.slavename]!</span> ")
to_chat(user,"<span class='notice'>You put [casinosentientprize_price] credits worth of chips into the SPASM and it pings to inform you bought [selected_collar.sentientprizename]!</span> ")
selected_collar.icon_state = "casinoslave_owned"
selected_collar.update_icon()
selected_collar.ownername = user.name
selected_collar.name = "Sentient Prize Collar: [selected_collar.slavename] owned by [selected_collar.ownername]!"
selected_collar.desc = "A collar worn by sentient prizes registered to a SPASM. The tag says its registered to [selected_collar.slavename] and they are owned by [selected_collar.ownername]."
selected_collar.name = "Sentient Prize Collar: [selected_collar.sentientprizename] owned by [selected_collar.ownername]!"
selected_collar.desc = "A collar worn by sentient prizes registered to a SPASM. The tag says its registered to [selected_collar.sentientprizename] and they are owned by [selected_collar.ownername]."
selected_collar = null
/obj/machinery/casinoslave_handler/proc/setprice(mob/living/user as mob)
/obj/machinery/casinosentientprize_handler/proc/setprice(mob/living/user as mob)
if(usr.incapacitated())
return
if(ishuman(usr) || istype(usr, /mob/living/silicon/robot))
casinoslave_price = tgui_input_number(usr, "Select the desired price (1-1000)", "Set Price", null, null, 1000, 1)
if(casinoslave_price>1000 || casinoslave_price<1)
casinosentientprize_price = tgui_input_number(usr, "Select the desired price (1-1000)", "Set Price", null, null, 1000, 1)
if(casinosentientprize_price>1000 || casinosentientprize_price<1)
to_chat(user,"<span class='notice'>Invalid price.</span> ")
return
to_chat(user,"<span class='notice'>You set the price to [casinoslave_price]</span> ")
to_chat(user,"<span class='notice'>You set the price to [casinosentientprize_price]</span> ")

View File

@@ -120,141 +120,12 @@
EXCHANGE RATE <br>
FROM = TO <br>
5 Thalers = 1 casino chip <br>
1 casino chip = 5 Thalers <br> <br>
1 Thaler = 1 casino chip <br>
1 casino chip = 1 Thaler <br> <br>
The special sentient prize is 100 chips! More about it in section below! <br> <br>
The special sentient prize is 200 chips! More about it in section below! <br> <br>
Melee weapons
<ul>
<li>scepter 500</li>
<li>chain of command 250</li>
</ul>
Guns and 'guns' ((disclaimer, giving out guns will mean you get a weapons license as well with the shifts you have it, abusing these weapons will quickly get them removed!))
<ul>
<li>sizegun 100</li>
<li>advanced anti particle rifle 500</li>
<li>temperature gun 250</li>
<li>alien pistol 1000</li>
<li>floral somatoray 250</li>
<li>net gun 500</li>
</ul>
Gear
<ul>
<li>experimental welder 500</li>
<li>alien belt 750</li>
<li>alien enhancement vest 750</li>
<li>The monocoole 1000</li>
<li>chameleon black tie 250</li>
<li>cryostasis beaker 200</li>
<li>bluespace beaker 200</li>
<li>chem sprayer 250</li>
</ul>
Masks and hats - EVERYTHING IS 50 except chameleon!
<ul>
<li>assistant hat</li>
<li>Shark mask</li>
<li>Pig mask</li>
<li>Luchador mask</li>
<li>Horse mask</li>
<li>Goblin mask</li>
<li>Fake moustache</li>
<li>Dolphin mask</li>
<li>Demon mask</li>
<li>Chameleon gas mask 250</li>
</ul>
Costumes - All costumes are 100 except the hoodies which are 50!
<ul>
<li>Black bunny girl outfit (black suit and rabbit ears)</li>
<li>White bunny girl outfit (white suit and rabbit ears)</li>
<li>Corgi hoodie</li>
<li>Sexy clown</li>
<li>nyan girl</li>
<li>Wizard</li>
<li>Chicken</li>
<li>Carp hoodie</li>
<li>Sexy mime</li>
<li>Pirate</li>
<li>Commie</li>
<li>Plague doctor</li>
<li>Imperium monk</li>
<li>Cute witch</li>
<li>Gladiator</li>
</ul>
Toys and misc - ALL THESE ARE 50
<ul>
<li>Toy sword</li>
<li>Water flower</li>
<li>Stick horse</li>
<li>Replica katana</li>
<li>Magic conch</li>
<li>Magic 8-ball</li>
<li>Foam sword</li>
<li>Foam crossbow (with 5 bolts)</li>
<li>Bosun's whistle</li>
<li>Golden cup</li>
<li>Havana cigar case</li>
<li>Casino wallet (to keep after shift)</li>
<li>Casino card deck (to keep after shift)</li>
</ul>
Booze - ALL BOOZE IS 50
<ul>
<li>Redeemer brew</li>
<li>Warlock velvet</li>
<li>Wrapp artiste patron</li>
<li>Flask of holy water</li>
<li>College girl goldschlager</li>
<li>Gilthari luxury champagne</li>
<li>Bottle of nothing</li>
<li>Special blend whiskey</li>
<li>Akvavit</li>
</ul>
Pets
<ul>
<li>Armadillo 150</li>
<li>Cat 150</li>
<li>Goat 150</li>
<li>Fox 150</li>
<li>Lizard 150</li>
<li>Penguin 150</li>
<li>Goose 200</li>
<li>Chicken 200</li>
<li>Cow 200</li>
<li>Corgi 200</li>
<li>Snake 200</li>
<li>Yithian 200</li>
<li>Tindalos 200</li>
<li>Fennec 300</li>
<li>Red Panda 300</li>
<li>Horse 300</li>
<li>Otie 500</li>
<li>Chonker Otie 500</li>
<li>Zorgoia 500</li>
</ul>
Mechs
<ul>
<li>Mining Ripley 1000</li>
<li>Firefighter Ripley 750</li>
<li>Serenity 1500</li>
<li>Odysseus 1250</li>
<li>Phazon Scuttlebug 2000</li>
<li>Phazon Janus 3500</li>
<li>Scarab 500</li>
<li>Shuttlepod 250</li>
<li><3E>Shuttlecraft 500</li>
</ul>
Implants
<ul>
<li>Implanter 100 (A basic empty implanter, you are going to need this to implant yourself with cyberntic augments)</li>
<li>Implant: Tazer 1000 (A cybernetic implant that allows one to spawn a personal defense taser)</li>
<li>Implant: Medkit 500 (A cybernetic implant that allows you to spawn all the tools needed for surgery)</li>
<li>Implant: Shades 750 (A cybernetic implant that will spawn protective thermoshades upon your eyes, AR included!)</li>
<li>Implant: Sprinter 1500 (A cybernetic implant that will give you that extra kick of energy to run faster!)</li>
<li>Implant: Toolkit 500 (A cybernetic implant that allows you to spawn all the tools needed for engineering)</li>
<li>Implant: Language 1000 (A cybernetic implant that allows you to understand almost all languages)</li>
<li>Implant: Analyzer 500 (A cybernetic implant that allows one to spawn a Portable Resonant Analyzer for any science needs)</li>
<li>Implant: Size Control 500 (A cybernetic implant that allows one to change the size of others via specific voice commands)</li>
</ul>
This section was outdated, someone better write it.
Thats it for prizes! <br><br>

View File

@@ -0,0 +1,462 @@
//Original Casino Code created by Shadowfire117#1269 - Ported from CHOMPstation
//Modified by GhostActual#2055 for use with VOREstation
/*
* Slot Machine
*/
/obj/machinery/slot_machine
name = "slot machine"
desc = "A gambling machine designed to give you false hope and rob you of your wealth, hence why it's often called a one armed bandit."
icon = 'icons/obj/casino.dmi'
icon_state = "slotmachine"
anchored = 1
density = 1
power_channel = EQUIP
use_power = USE_POWER_IDLE
idle_power_usage = 10
active_power_usage = 100
light_power = 0.9
light_range = 2
light_color = "#B1FBBFF"
var/isbroken = 0 //1 if someone banged it with something heavy
var/ispowered = 1 //starts powered, changes with power_change()
var/busy = 0
var/symbol1 = null
var/symbol2 = null
var/symbol3 = null
var/datum/effect/effect/system/confetti_spread
var/confetti_strength = 8
/obj/machinery/slot_machine/update_icon()
cut_overlays()
if(!ispowered || isbroken)
icon_state = "slotmachine_off"
if(isbroken) //If the thing is smashed, add crack overlay on top of the unpowered sprite.
add_overlay("slotmachine_broken")
set_light(0)
set_light_on(FALSE)
return
icon_state = "slotmachine"
set_light(2)
set_light_on(TRUE)
return
/obj/machinery/slot_machine/power_change()
if(isbroken) //Broken shit can't be powered.
return
..()
if(!(stat & NOPOWER))
ispowered = 1
update_icon()
else
spawn(rand(0, 15))
ispowered = 0
update_icon()
/obj/machinery/slot_machine/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(busy)
to_chat(user,"<span class='notice'>The slot machine is currently running.</span> ")
return
if(W.is_wrench())
playsound(src, W.usesound, 100, 1)
if(anchored)
user.visible_message("[user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.")
else
user.visible_message("[user] begins securing \the [src] to the floor.", "You start securing \the [src] to the floor.")
if(do_after(user, 20 * W.toolspeed))
if(!src) return
to_chat(user, "<span class='notice'>You [anchored? "un" : ""]secured \the [src]!</span>")
anchored = !anchored
return
if(!anchored)
to_chat(user,"<span class='notice'> The slot machine isn't secured.</span>")
return
var/handled = 0
var/paid = 0
if(istype(W, /obj/item/weapon/spacecasinocash))
var/obj/item/weapon/spacecasinocash/C = W
paid = insert_chip(C, user)
handled = 1
if(paid)
return
if(handled)
SStgui.update_uis(src)
return // don't smack that machine with your 2 chips
else if(!(stat & NOPOWER))
return
else if(isbroken)
return
/obj/machinery/slot_machine/proc/insert_chip(var/obj/item/weapon/spacecasinocash/cashmoney, mob/user)
if (ispowered == 0)
return
if (isbroken)
return
if (busy)
to_chat(user,"<span class='notice'>The slot machine is currently rolling.</span> ")
return
if(cashmoney.worth < 5)
to_chat(user,"<span class='notice'>You dont have enough chips to gamble!</span> ")
return
to_chat(user,"<span class='notice'>You puts 5 credits in the slot machine and presses start.</span>")
cashmoney.worth -= 5
cashmoney.update_icon()
if(cashmoney.worth <= 0)
usr.drop_from_inventory(cashmoney)
qdel(cashmoney)
cashmoney.update_icon()
busy = 1
icon_state = "slotmachine_rolling"
playsound(src.loc, 'sound/machines/slotmachine_pull.ogg', 15, 1)
var/slot1 = rand(0,9)
switch(slot1)
if(0 to 3) symbol1 = "cherry"
if(4 to 4) symbol1 = "lemon"
if(5 to 5) symbol1 = "bell"
if(6 to 6) symbol1 = "four leaf clover"
if(7 to 7) symbol1 = "seven"
if(8 to 8) symbol1 = "diamond"
if(9 to 9) symbol1 = "platinum coin"
var/slot2 = rand(0,16)
switch(slot2)
if(0 to 5) symbol2 = "cherry"
if(6 to 7) symbol2 = "lemon"
if(8 to 9) symbol2 = "bell"
if(10 to 11) symbol2 = "four leaf clover"
if(12 to 13) symbol2 = "seven"
if(14 to 15) symbol2 = "diamond"
if(16) symbol2 = "platinum coin"
var/slot3 = rand(0,9)
switch(slot3)
if(0 to 3) symbol3 = "cherry"
if(4 to 4) symbol3 = "lemon"
if(5 to 5) symbol3 = "bell"
if(6 to 6) symbol3 = "four leaf clover"
if(7 to 7) symbol3 = "seven"
if(8 to 8) symbol3 = "diamond"
if(9 to 9) symbol3 = "platinum coin"
var/output //Output variable to send out in chat after the large if statement.
var/winnings = 0 //How much money will be given if any.
var/platinumwin = 0 // If you win the platinum chip or not
var/celebrate = 0
var/delaytime = 5 SECONDS
spawn(delaytime)
to_chat(user,"<span class='notice'>The slot machine flashes with bright colours as the slots lights up with a [symbol1], a [symbol2] and a [symbol3]!</span>")
if (symbol1 == "cherry" && symbol2 == "cherry" && symbol3 == "cherry")
output = "<span class='notice'>Three cherries! The slot machine deposits chips worth 25 credits!</span>"
winnings = 25
if ((symbol1 != "cherry" && symbol2 == "cherry" && symbol3 == "cherry") || (symbol1 == "cherry" && symbol2 != "cherry" && symbol3 == "cherry") ||(symbol1 == "cherry" && symbol2 == "cherry" && symbol3 != "cherry"))
output = "<span class='notice'>Two cherries! The slot machine deposits a 10 credit chip!</span>"
winnings = 10
if (symbol1 == "lemon" && symbol2 == "lemon" && symbol3 == "lemon")
output = "<span class='notice'>Three lemons! The slot machine deposits a 50 credit chip!</span>"
winnings = 50
if (symbol1 == "watermelon" && symbol2 == "watermelon" && symbol3 == "watermelon")
output = "<span class='notice'>Three watermelons! The slot machine deposits chips worth 75 credits!</span>"
winnings = 75
if (symbol1 == "bell" && symbol2 == "bell" && symbol3 == "bell")
output = "<span class='notice'>Three bells! The slot machine deposits chips a 100 credit chip!</span>"
winnings = 100
if (symbol1 == "four leaf clover" && symbol2 == "four leaf clover" && symbol3 == "four leaf clover")
output = "<span class='notice'>Three four leaf clovers! The slot machine deposits a 200 credit chip!</span>"
winnings = 200
if (symbol1 == "seven" && symbol2 == "seven" && symbol3 == "seven")
output = "<span class='notice'>Three sevens! The slot machine deposits a 500 credit chip!</span>"
winnings = 500
celebrate = 1
if (symbol1 == "diamond" && symbol2 == "diamond" && symbol3 == "diamond")
output = "<span class='notice'>Three diamonds! The slot machine deposits a 1000 credit chip!</span>"
winnings = 1000
celebrate = 1
if (symbol1 == "platinum coin" && symbol2 == "platinum coin" && symbol3 == "platinum coin")
output = "<span class='notice'>Three platinum coins! The slot machine deposits a platinum chip!</span>"
platinumwin = TRUE
celebrate = 1
icon_state = initial(icon_state) // Set it back to the original iconstate.
if(!output) // Is there anything to output? If not, consider it a loss.
to_chat(user,"Better luck next time!")
busy = FALSE
return
to_chat(user,output) //Output message
if(platinumwin) // Did they win the platinum chip?
new /obj/item/weapon/casino_platinum_chip(src.loc)
playsound(src.loc, 'sound/machines/slotmachine.ogg', 25, 1)
if(winnings) //Did the person win?
icon_state = "slotmachine_winning"
playsound(src.loc, 'sound/machines/slotmachine.ogg', 25, 1)
spawn(delaytime)
spawn_casinochips(winnings, src.loc)
icon_state = "slotmachine"
if(celebrate) // Happy celebrations!
src.confetti_spread = new /datum/effect/effect/system/confetti_spread()
src.confetti_spread.attach(src) //If somehow people start dragging slot machine
spawn(0)
for(var/i = 1 to confetti_strength)
src.confetti_spread.start()
sleep(10)
busy = FALSE
/*
* Station Slot Machine (takes space cash instead of chips)
*/
/obj/machinery/station_slot_machine
name = "station slot machine"
desc = "A gambling machine owned by NanoTrasen, designed to take Thalers as opposed to casino chips."
icon = 'icons/obj/casino.dmi'
icon_state = "ntslotmachine"
anchored = 1
density = 1
power_channel = EQUIP
use_power = USE_POWER_IDLE
idle_power_usage = 10
active_power_usage = 100
light_power = 0.9
light_range = 2
light_color = "#B1FBBFF"
var/isbroken = 0 //1 if someone banged it with something heavy
var/ispowered = 1 //starts powered, changes with power_change()
var/busy = 0
var/symbol1 = null
var/symbol2 = null
var/symbol3 = null
var/datum/effect/effect/system/confetti_spread
var/confetti_strength = 8
/obj/machinery/station_slot_machine/update_icon()
cut_overlays()
if(!ispowered || isbroken)
icon_state = "ntslotmachine_off"
if(isbroken) //If the thing is smashed, add crack overlay on top of the unpowered sprite.
add_overlay("ntslotmachine_broken")
set_light(0)
set_light_on(FALSE)
return
icon_state = "ntslotmachine"
set_light(2)
set_light_on(TRUE)
return
/obj/machinery/station_slot_machine/power_change()
if(isbroken) //Broken shit can't be powered.
return
..()
if(!(stat & NOPOWER))
ispowered = 1
update_icon()
else
spawn(rand(0, 15))
ispowered = 0
update_icon()
/obj/machinery/station_slot_machine/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(busy)
to_chat(user,"<span class='notice'>The slot machine is currently running.</span> ")
return
if(W.is_wrench())
playsound(src, W.usesound, 100, 1)
if(anchored)
user.visible_message("[user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.")
else
user.visible_message("[user] begins securing \the [src] to the floor.", "You start securing \the [src] to the floor.")
if(do_after(user, 20 * W.toolspeed))
if(!src) return
to_chat(user, "<span class='notice'>You [anchored? "un" : ""]secured \the [src]!</span>")
anchored = !anchored
return
if(!anchored)
to_chat(user,"<span class='notice'> The slot machine isn't secured.</span>")
return
var/handled = 0
var/paid = 0
if(istype(W, /obj/item/weapon/spacecash))
var/obj/item/weapon/spacecash/C = W
paid = insert_cash(C, user)
handled = 1
if(paid)
return
if(handled)
SStgui.update_uis(src)
return // don't smack that machine with your 2 chips
else if(!(stat & NOPOWER))
return
else if(isbroken)
return
/obj/machinery/station_slot_machine/proc/insert_cash(var/obj/item/weapon/spacecash/cashmoney, mob/user)
if (ispowered == 0)
return
if (isbroken)
return
if (busy)
to_chat(user,"<span class='notice'>The slot machine is currently rolling.</span> ")
return
if(cashmoney.worth < 5)
to_chat(user,"<span class='notice'>You dont have enough Thalers to gamble!</span> ")
return
to_chat(user,"<span class='notice'>You puts 5 Thalers in the slot machine and presses start.</span>")
cashmoney.worth -= 5
cashmoney.update_icon()
if(cashmoney.worth <= 0)
usr.drop_from_inventory(cashmoney)
qdel(cashmoney)
cashmoney.update_icon()
busy = 1
icon_state = "ntslotmachine_rolling"
playsound(src.loc, 'sound/machines/slotmachine_pull.ogg', 15, 1)
var/slot1 = rand(0,9)
switch(slot1)
if(0 to 3) symbol1 = "cherry"
if(4 to 4) symbol1 = "lemon"
if(5 to 5) symbol1 = "bell"
if(6 to 6) symbol1 = "four leaf clover"
if(7 to 7) symbol1 = "seven"
if(8 to 8) symbol1 = "diamond"
if(9 to 9) symbol1 = "platinum coin"
var/slot2 = rand(0,16)
switch(slot2)
if(0 to 5) symbol2 = "cherry"
if(6 to 7) symbol2 = "lemon"
if(8 to 9) symbol2 = "bell"
if(10 to 11) symbol2 = "four leaf clover"
if(12 to 13) symbol2 = "seven"
if(14 to 15) symbol2 = "diamond"
if(16) symbol2 = "platinum coin"
var/slot3 = rand(0,9)
switch(slot3)
if(0 to 3) symbol3 = "cherry"
if(4 to 4) symbol3 = "lemon"
if(5 to 5) symbol3 = "bell"
if(6 to 6) symbol3 = "four leaf clover"
if(7 to 7) symbol3 = "seven"
if(8 to 8) symbol3 = "diamond"
if(9 to 9) symbol3 = "platinum coin"
var/output //Output variable to send out in chat after the large if statement.
var/winnings = 0 //How much money will be given if any.
var/platinumwin = 0 // If you win the platinum chip or not
var/celebrate = 0
var/delaytime = 5 SECONDS
spawn(delaytime)
to_chat(user,"<span class='notice'>The slot machine flashes with bright colours as the slots lights up with a [symbol1], a [symbol2] and a [symbol3]!</span>")
if (symbol1 == "cherry" && symbol2 == "cherry" && symbol3 == "cherry")
output = "<span class='notice'>Three cherries! The slot machine deposits 25 Thalers!</span>"
winnings = 25
if ((symbol1 != "cherry" && symbol2 == "cherry" && symbol3 == "cherry") || (symbol1 == "cherry" && symbol2 != "cherry" && symbol3 == "cherry") ||(symbol1 == "cherry" && symbol2 == "cherry" && symbol3 != "cherry"))
output = "<span class='notice'>Two cherries! The slot machine deposits 10 Thalers!</span>"
winnings = 10
if (symbol1 == "lemon" && symbol2 == "lemon" && symbol3 == "lemon")
output = "<span class='notice'>Three lemons! The slot machine deposits 50 Thalers!</span>"
winnings = 50
if (symbol1 == "watermelon" && symbol2 == "watermelon" && symbol3 == "watermelon")
output = "<span class='notice'>Three watermelons! The slot machine deposits 75 Thalers!</span>"
winnings = 75
if (symbol1 == "bell" && symbol2 == "bell" && symbol3 == "bell")
output = "<span class='notice'>Three bells! The slot machine deposits 100 Thalers!</span>"
winnings = 100
if (symbol1 == "four leaf clover" && symbol2 == "four leaf clover" && symbol3 == "four leaf clover")
output = "<span class='notice'>Three four leaf clovers! The slot machine deposits 200 Thalers!</span>"
winnings = 200
if (symbol1 == "seven" && symbol2 == "seven" && symbol3 == "seven")
output = "<span class='notice'>Three sevens! The slot machine deposits 500 Thalers!</span>"
winnings = 500
celebrate = 1
if (symbol1 == "diamond" && symbol2 == "diamond" && symbol3 == "diamond")
output = "<span class='notice'>Three diamonds! The slot machine deposits 1000 Thalers!</span>"
winnings = 1000
celebrate = 1
if (symbol1 == "platinum coin" && symbol2 == "platinum coin" && symbol3 == "platinum coin")
output = "<span class='notice'>Three platinum coins! The slot machine deposits a platinum chip!</span>"
platinumwin = TRUE;
celebrate = 1
icon_state = initial(icon_state) // Set it back to the original iconstate.
if(!output) // Is there anything to output? If not, consider it a loss.
to_chat(user,"Better luck next time!")
busy = FALSE
return
to_chat(user,output) //Output message
if(platinumwin) // Did they win the platinum chip?
new /obj/item/weapon/casino_platinum_chip(src.loc)
playsound(src.loc, 'sound/machines/slotmachine.ogg', 25, 1)
if(winnings) //Did the person win?
icon_state = "ntslotmachine_winning"
playsound(src.loc, 'sound/machines/slotmachine.ogg', 25, 1)
spawn(delaytime)
spawn_money(winnings, src.loc)
icon_state = "ntslotmachine"
if(celebrate) // Happy celebrations!
src.confetti_spread = new /datum/effect/effect/system/confetti_spread()
src.confetti_spread.attach(src) //If somehow people start dragging slot machine
spawn(0)
for(var/i = 1 to confetti_strength)
src.confetti_spread.start()
sleep(10)
busy = FALSE

View File

@@ -2,7 +2,7 @@
name = "Casino Creature Container (Cat)"
desc = "It is set to detonate in 5 seconds. It will release a cat won from the casino prize vendor!"
icon = 'icons/obj/casino.dmi'
icon_state = "casino"
icon_state = "casino_delivery"
item_state = "flashbang"
origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 2)
spawner_type = /mob/living/simple_mob/animal/passive/cat
@@ -75,6 +75,11 @@
name = "Casino Creature Container (Otie)"
spawner_type = /mob/living/simple_mob/otie/friendly
/obj/item/weapon/grenade/spawnergrenade/casino/goldcrest
desc = "It is set to detonate in 5 seconds. It will release a bird won from the casino prize vendor!"
name = "Casino Creature Container (Bird)"
spawner_type = /mob/living/simple_mob/animal/passive/bird/goldcrest
//
// Mecha
//

View File

@@ -60,6 +60,14 @@
cmd_admin_pm(C,null)
return
if(href_list["mentorhelp_msg"])
var/client/C = locate(href_list["mentorhelp_msg"])
if(ismob(C))
var/mob/M = C
C = M.client
cmd_mentor_pm(C, null)
return
if(href_list["irc_msg"])
if(!holder && received_irc_pm < world.time - 6000) //Worse they can do is spam IRC for 10 minutes
to_chat(usr, "<span class='warning'>You are no longer able to use this, it's been more then 10 minutes since an admin on IRC has responded to you</span>")
@@ -123,6 +131,7 @@
switch(href_list["_src_"])
if("holder") hsrc = holder
if("mentorholder") hsrc = (check_rights(R_ADMIN, 0) ? holder : mentorholder)
if("usr") hsrc = mob
if("prefs") return prefs.process_link(usr,href_list)
if("vars") return view_var_Topic(href,href_list,hsrc)
@@ -178,6 +187,7 @@
GLOB.directory[ckey] = src
GLOB.ahelp_tickets.ClientLogin(src)
GLOB.mhelp_tickets.ClientLogin(src)
//Admin Authorisation
holder = admin_datums[ckey]
@@ -185,6 +195,10 @@
GLOB.admins += src
holder.owner = src
mentorholder = mentor_datums[ckey]
if (mentorholder)
mentorholder.associate(GLOB.directory[ckey])
//preferences datum - also holds some persistant data for the client (because we may as well keep these datums to a minimum)
prefs = preferences_datums[ckey]
if(!prefs)
@@ -262,7 +276,11 @@
if(holder)
holder.owner = null
GLOB.admins -= src
if (mentorholder)
mentorholder.owner = null
GLOB.mentors -= src
GLOB.ahelp_tickets.ClientLogout(src)
GLOB.mhelp_tickets.ClientLogout(src)
GLOB.directory -= ckey
GLOB.clients -= src
return ..()

View File

@@ -14,12 +14,14 @@
//CHOMPEdit Begin
S["species"] >> pref.species
//CHOMPEdit End
S["language_custom_keys"] >> pref.language_custom_keys
/datum/category_item/player_setup_item/general/language/save_character(var/savefile/S)
S["language"] << pref.alternate_languages
S["extra_languages"] << pref.extra_languages
testing("LANGSANI: Saved to [pref.client]'s character [pref.real_name || "-name not yet loaded-"] savefile: [english_list(pref.alternate_languages || list())]")
S["language_prefixes"] << pref.language_prefixes
S["language_custom_keys"] << pref.language_custom_keys
/datum/category_item/player_setup_item/general/language/sanitize_character()
if(!islist(pref.alternate_languages)) pref.alternate_languages = list()
@@ -43,6 +45,14 @@
for(var/prefix in pref.language_prefixes)
if(prefix in forbidden_prefixes)
pref.language_prefixes -= prefix
if(isnull(pref.language_custom_keys))
pref.language_custom_keys = list()
var/datum/species/S = GLOB.all_species[pref.species]
for(var/key in pref.language_custom_keys)
if(!pref.language_custom_keys[key])
pref.language_custom_keys.Remove(key)
if(!((pref.language_custom_keys[key] == S.language) || (pref.language_custom_keys[key] == S.default_language && S.default_language != S.language) || (pref.language_custom_keys[key] in pref.alternate_languages)))
pref.language_custom_keys.Remove(key)
/datum/category_item/player_setup_item/general/language/content()
. += "<b>Languages</b><br>"
@@ -51,14 +61,15 @@
testing("LANGSANI: Truncated [pref.client]'s character [pref.real_name || "-name not yet loaded-"] language list because it was too long (len: [pref.alternate_languages.len], allowed: [S.num_alternate_languages])")
pref.alternate_languages.len = (S.num_alternate_languages + pref.extra_languages) // Truncate to allowed length
if(S.language)
. += "- [S.language]<br>"
. += "- [S.language] - <a href='?src=\ref[src];set_custom_key=[S.language]'>Set Custom Key</a><br>"
if(S.default_language && S.default_language != S.language)
. += "- [S.default_language]<br>"
. += "- [S.default_language] - <a href='?src=\ref[src];set_custom_key=[S.default_language]'>Set Custom Key</a><br>"
if(S.num_alternate_languages + pref.extra_languages)
if(pref.alternate_languages.len)
for(var/i = 1 to pref.alternate_languages.len)
var/lang = pref.alternate_languages[i]
. += "- [lang] - <a href='?src=\ref[src];remove_language=[i]'>remove</a><br>"
. += "- [lang] - <a href='?src=\ref[src];remove_language=[i]'>remove</a> - <a href='?src=\ref[src];set_custom_key=[lang]'>Set Custom Key</a><br>"
if(pref.alternate_languages.len < (S.num_alternate_languages + pref.extra_languages))
. += "- <a href='?src=\ref[src];add_language=1'>add</a> ([(S.num_alternate_languages + pref.extra_languages) - pref.alternate_languages.len] remaining)<br>"
else
@@ -125,4 +136,32 @@
pref.language_prefixes = config.language_prefixes.Copy()
return TOPIC_REFRESH
else if(href_list["set_custom_key"])
var/lang = href_list["set_custom_key"]
if(!(lang in GLOB.all_languages))
return TOPIC_REFRESH
var/oldkey = ""
for(var/key in pref.language_custom_keys)
if(pref.language_custom_keys[key] == lang)
oldkey = key
break
var/char = tgui_input_text(user, "Input a language key for [lang]. Input a single space to reset.", "Language Custom Key", oldkey)
if(length(char) != 1)
return TOPIC_REFRESH
else if(char == " ")
for(var/key in pref.language_custom_keys)
if(pref.language_custom_keys[key] == lang)
pref.language_custom_keys -= key
break
else if(contains_az09(char))
if(!(char in pref.language_custom_keys))
pref.language_custom_keys += char
pref.language_custom_keys[char] = lang
else
tgui_alert_async(user, "Improper language key. Rejected.", "Error")
return TOPIC_REFRESH
return ..()

View File

@@ -364,6 +364,12 @@ var/list/_client_preferences_by_type
enabled_description = "Popup New On Login"
disabled_description = "Do Nothing"
/datum/client_preference/play_mentorhelp_ping
description = "Mentorhelps"
key = "SOUND_MENTORHELP"
enabled_description = "Hear"
disabled_description = "Silent"
/********************
* Staff Preferences *
********************/

View File

@@ -282,6 +282,13 @@
ckeywhitelist = list("coolcrow420")
character_name = list("Jade Davis")
/datum/gear/fluff/m4il_hdd
path = /obj/item/weapon/implant/language/fluff/m41l
display_name = "dusty hard drive"
slot = "implant"
ckeywhitelist = list("coolcrow420")
character_name = list("M41L")
// D CKEYS
/datum/gear/fluff/dhaeleena_medal
path = /obj/item/clothing/accessory/medal/silver/security/fluff/dhael

View File

@@ -49,6 +49,14 @@
display_name = "pink tiger pelt"
path = /obj/item/clothing/head/pelt/tigerpeltpink
/datum/gear/head/magic_hat
display_name = "wizard hat, colorable"
path = /obj/item/clothing/head/wizard/fake/realistic/colorable
/datum/gear/head/magic_hat/New()
..()
gear_tweaks += gear_tweak_free_color_choice
/*
Talon hats
*/

View File

@@ -292,36 +292,13 @@ Talon jumpsuit
path = /obj/item/clothing/under/undersuit/command
//Altevian Uniforms
/datum/gear/uniform/job_altevian/cmd
display_name = "altevian uniform, cmd"
path = /obj/item/clothing/under/pants/altevian/command
allowed_roles = list("Head of Security","Site Manager","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer")
/datum/gear/uniform/altevian
description = "An extremely comfortable set of clothing that's made to help people handle their day to day work around the fleets with little to no discomfort."
display_name = "altevian uniform selection"
/datum/gear/uniform/job_altevian/sec
display_name = "altevian uniform, sec"
path = /obj/item/clothing/under/pants/altevian/security
allowed_roles = list("Head of Security", "Warden", "Detective", "Security Officer")
/datum/gear/uniform/job_altevian/med
display_name = "altevian uniform, med"
path = /obj/item/clothing/under/pants/altevian/medical
allowed_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Paramedic","Geneticist","Field Medic","Psychiatrist")
/datum/gear/uniform/job_altevian/eng
display_name = "altevian uniform, eng"
path = /obj/item/clothing/under/pants/altevian/engineering
allowed_roles = list("Chief Engineer","Atmospheric Technician","Engineer")
/datum/gear/uniform/job_altevian/sci
display_name = "altevian uniform, sci"
path = /obj/item/clothing/under/pants/altevian/science
allowed_roles = list("Research Director", "Scientist", "Roboticist", "Xenobiologist", "Xenobotanist")
/datum/gear/uniform/job_altevian/crg
display_name = "altevian uniform, cargo"
path = /obj/item/clothing/under/pants/altevian/cargo
allowed_roles = list("Quartermaster", "Cargo Technician", "Shaft Miner")
/datum/gear/uniform/job_altevian/civ
display_name = "altevian uniform, civ"
path = /obj/item/clothing/under/pants/altevian
/datum/gear/uniform/altevian/New()
..()
var/list/pants = list()
for(var/obj/item/clothing/under/pants/altevian/pants_type as anything in typesof(/obj/item/clothing/under/pants/altevian))
pants[initial(pants_type.name)] = pants_type
gear_tweaks += new/datum/gear_tweak/path(sortAssoc(pants))

View File

@@ -167,9 +167,9 @@
sort_category = "Xenowear"
/datum/gear/uniform/dept/undercoat/cap
display_name = "facility director undercoat (Teshari)"
display_name = "site manager undercoat (Teshari)"
path = /obj/item/clothing/under/teshari/undercoat/jobs/cap
allowed_roles = list("Facility Director")
allowed_roles = list("Site Manager")
/datum/gear/uniform/dept/undercoat/hop
display_name = "head of personnel undercoat (Teshari)"
@@ -276,9 +276,9 @@
sort_category = "Xenowear"
/datum/gear/suit/dept/cloak/cap
display_name = "facility director cloak (Teshari)"
display_name = "site manager cloak (Teshari)"
path = /obj/item/clothing/suit/storage/teshari/cloak/jobs
allowed_roles = list("Facility Director")
allowed_roles = list("Site Manager")
/datum/gear/suit/dept/cloak/hop
display_name = "head of personnel cloak (Teshari)"

View File

@@ -94,5 +94,14 @@
/datum/gear/suit/taur/white_dress
display_name = "white wedding dress (Wolf/Horse-taur)"
path = /obj/item/clothing/suit/taur_dress/white
path = /obj/item/clothing/suit/taur/dress
sort_category = "Xenowear"
/datum/gear/uniform/taur/colorable_skirt
display_name = "colorable skirt (Wolf/Horse-taur)"
path = /obj/item/clothing/under/taur/skirt
sort_category = "Xenowear"
/datum/gear/uniform/taur/colorable_skirt/New()
..()
gear_tweaks += gear_tweak_free_color_choice

View File

@@ -63,7 +63,8 @@ var/list/preferences_datums = list()
var/species = SPECIES_HUMAN //Species datum to use.
var/species_preview //Used for the species selection window.
var/list/alternate_languages = list() //Secondary language(s)
var/list/language_prefixes = list() //Kanguage prefix keys
var/list/language_prefixes = list() //Language prefix keys
var/list/language_custom_keys = list() //Language custom call keys
var/list/gear //Left in for Legacy reasons, will no longer save.
var/list/gear_list = list() //Custom/fluff item loadouts.
var/gear_slot = 1 //The current gear save slot

View File

@@ -105,3 +105,18 @@
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb","TCaptureCrystal") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggle_mentorhelp_ping()
set name = "Toggle Mentorhelp Ping"
set category = "Preferences"
set desc = "Toggles the mentorhelp ping"
var/pref_path = /datum/client_preference/play_mentorhelp_ping
toggle_preference(pref_path)
to_chat(src, "Mentorhelp pings are now [ is_preference_enabled(pref_path) ? "enabled" : "disabled"]")
SScharacter_setup.queue_preferences_save(prefs)
feedback_add_details("admin_verb", "TSoundMentorhelps")

View File

@@ -224,8 +224,6 @@
persist_storable = FALSE
/obj/item/weapon/gun/energy/sizegun/admin
persist_storable = FALSE
/obj/item/weapon/gun/energy/sizegun/abductor
persist_storable = FALSE
/obj/item/stack
persist_storable = FALSE
/obj/item/weapon/book
@@ -252,3 +250,7 @@
persist_storable = FALSE
/obj/item/weapon/rcd
persist_storable = FALSE
/obj/item/weapon/spacecash
persist_storable = FALSE
/obj/item/weapon/spacecasinocash
persist_storable = FALSE

View File

@@ -121,6 +121,28 @@
if(config.show_event_managers)
msg += "\n<b> Current Miscellaneous ([num_event_managers_online]):</b>\n" + eventMmsg
var/num_mentors_online = 0
var/mmsg = ""
for(var/client/C in GLOB.mentors)
num_mentors_online++
mmsg += "\t[C] is a Mentor"
if(holder)
if(isobserver(C.mob))
mmsg += " - Observing"
else if(istype(C.mob,/mob/new_player))
mmsg += " - Lobby"
else
mmsg += " - Playing"
if(C.is_afk())
var/seconds = C.last_activity_seconds()
mmsg += " (AFK - [round(seconds / 60)] minutes, [seconds % 60] seconds)"
mmsg += "\n"
if(config.show_mentors)
msg += "\n<b> Current Mentors ([num_mentors_online]):</b>\n" + mmsg
msg += "\n<span class='info'>Adminhelps are also sent to Discord. If no admins are available in game try anyway and an admin on Discord may see it and respond.</span>"
to_chat(src, msg)

View File

@@ -786,7 +786,7 @@
var/image/standing = ..()
if(taurized) //Special snowflake var on suits
standing.pixel_x = -16
standing.layer = BODY_LAYER + 16 // 16 is above tail layer, so will not be covered by taurbody.
standing.layer = BODY_LAYER + 17 // 17 is above tail layer, so will not be covered by taurbody. TAIL_UPPER_LAYER +1
return standing
/obj/item/clothing/suit/apply_accessories(var/image/standing)

View File

@@ -120,6 +120,7 @@
species_restricted = list("Vox")
drop_sound = 'sound/items/drop/metalboots.ogg'
pickup_sound = 'sound/items/pickup/toolbox.ogg'
armor = list (melee = 20, bullet = 15, laser = 10, energy = 10, bomb =5, bio = 30, rad = 30) //gently bumped up Heavy engineering gloves value for protection //ChompEdit
cold_protection = HANDS
min_cold_protection_temperature = GLOVES_MIN_COLD_PROTECTION_TEMPERATURE

View File

@@ -90,6 +90,7 @@
icon_state = "boots-vox"
flags = PHORONGUARD
species_restricted = list(SPECIES_VOX)
armor = list (melee = 40, bullet = 10, laser = 10, energy = 20, bomb = 20, bio = 10, rad = 20) //values of workboots and heavy duty engineering gloves, it's the only option that will ever be taken so may as well give the turkeys some protection //ChompEdit
action_button_name = "Toggle the magclaws"

View File

@@ -143,7 +143,7 @@
suit_type = "sinister alien"
icon_state = "voxstealth_rig"
desc = "A light alien rig for repairs and maintenance to the outside of habitats and vessels."
armor = list(melee = 30, bullet = 10, laser = 20,energy = 25, bomb = 20, bio = 100, rad = 100) //Standard Engineering Suit Values
armor = list(melee = 30, bullet = 10, laser = 20, energy = 25, bomb = 20, bio = 100, rad = 100) //Standard Engineering Suit Values
req_access = list()
req_one_access = list()
@@ -152,3 +152,40 @@
initial_modules = list(
)
//ChompEdit Begins
/obj/item/weapon/rig/vox/engineering
name = "fluid alien control module"
suit_type = "sinister alien"
icon_state = "voxstealth_rig"
desc = "A lightweight, alien rig dedicated for construction and engineering tasks. Not reccomended for hostile engagement."
armor = list (melee = 25, bullet = 5, laser = 40, energy = 45, bomb = 50, bio = 100, rad = 100) //CE suit values but shuffled to a tighter focus on the job hazards
flags = PHORONGUARD
item_flags = THICKMATERIAL
siemens_coefficient = 0
offline_slowdown = 2.5
slowdown = 0
emp_protection = 40 //change this to 30 if too high.
req_one_access = list()
allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/storage)
offline_vision_restriction = 1
initial_modules = list(
)
air_type = /obj/item/weapon/tank/vox
max_heat_protection_temperature = FIRE_HELMET_MAX_HEAT_PROTECTION_TEMPERATURE
/obj/item/weapon/rig/vox_engine_technition_control_module/equipped
req_access = list(access_engine)
initial_modules = list(
/obj/item/rig_module/maneuvering_jets,
/obj/item/rig_module/device/plasmacutter,
/obj/item/rig_module/device/rcd,
/obj/item/rig_module/vision/meson
)
//ChompEdit Ends

View File

@@ -261,6 +261,7 @@
slowdown = 0.5
offline_vision_restriction = 1
siemens_coefficient= 0.75
seal_delay = 5
helm_type = /obj/item/clothing/head/helmet/space/rig/medical

View File

@@ -106,8 +106,8 @@
// Job Cloaks
/obj/item/clothing/suit/storage/teshari/cloak/jobs/cap
name = "facility director cloak"
desc = "A soft Teshari cloak made for the Facility Director"
name = "site manager cloak"
desc = "A soft Teshari cloak made for the Site Manager"
icon_state = "tesh_cloak_cap"
//Cargo

View File

@@ -74,12 +74,12 @@
desc = "Knightly armor for a mount who doesn't need any rider. This one is marked to the house of Mason."
icon_state = "Mason_barding"
/obj/item/clothing/suit/taur_dress
/obj/item/clothing/suit/taur
icon = 'icons/mob/taursuits_horse_vr.dmi'
body_parts_covered = UPPER_TORSO|LOWER_TORSO
pixel_x = -16
/obj/item/clothing/suit/taur_dress/white
/obj/item/clothing/suit/taur/dress
name = "white wedding dress"
desc = "A fancy white dress with a blue underdress."
icon_state = "whitedress1"

View File

@@ -18,6 +18,16 @@
desc = "It has WIZZARD written across it in sequins. Comes with a cool beard."
icon_state = "wizard-fake"
body_parts_covered = HEAD|FACE
siemens_coefficient = 1
/obj/item/clothing/head/wizard/fake/realistic
desc = "A cool-looking 'magic' hat."
icon_state = "wizard"
body_parts_covered = HEAD
/obj/item/clothing/head/wizard/fake/realistic/colorable
desc = "A cool-looking 'magic' hat."
icon_state = "wizard-white"
/obj/item/clothing/head/wizard/marisa
name = "Witch Hat"

View File

@@ -300,6 +300,10 @@
name = "medal of exceptional heroism"
desc = "An extremely rare golden medal awarded only by high ranking officials. To recieve such a medal is the highest honor and as such, very few exist. This medal is almost never awarded to anybody but distinguished veteran staff."
/obj/item/clothing/accessory/medal/gold/casino
name = "medal of true lucky winner"
desc = "A gaudy golden medal with a logo of a casino engraved on top. The only achievement you had to earn this was great luck or great richness, neither of which is an achievement. Still, it instills a feeling of hope and smell of fresh bagels."
// Base type for 'medals' found in a "dungeon" submap, as a sort of trophy to celebrate the player's conquest.
/obj/item/clothing/accessory/medal/dungeon

View File

@@ -409,3 +409,30 @@
icon_state = "talon_pin"
item_state = "talonpin"
overlay_state = "talonpin"
//Casino Sentient Prize Collar
/obj/item/clothing/accessory/collar/casinosentientprize
name = "disabled Sentient Prize Collar"
desc = "A collar worn by sentient prizes registered to a SPASM. Although the red text on it shows its disconnected and nonfunctional."
icon_state = "casinoslave"
item_state = "casinoslave"
overlay_state = "casinoslave"
var/sentientprizename = null //Name for system to put on collar description
var/ownername = null //Name for system to put on collar description
var/sentientprizeckey = null //Ckey for system to check who is the person and ensure no abuse of system or errors
var/sentientprizeflavor = null //Description to show on the SPASM
var/sentientprizeooc = null //OOC text to show on the SPASM
/obj/item/clothing/accessory/collar/casinosentientprize/attack_self(mob/user as mob)
//keeping it blank so people don't tag and reset collar status
/obj/item/clothing/accessory/collar/casinosentientprize_fake
name = "Sentient Prize Collar"
desc = "A collar worn by sentient prizes registered to a SPASM. This one has been disconnected from the system and is now an accessory!"
icon_state = "casinoslave_owned"
item_state = "casinoslave_owned"
overlay_state = "casinoslave_owned"

View File

@@ -3,16 +3,12 @@
desc = "A small device used to measure body radiation and warning one after a certain threshold. \
Read manual before use! Can be held, attached to the uniform or worn around the neck."
w_class = ITEMSIZE_SMALL
icon = 'icons/inventory/accessory/item_vr.dmi'
icon_override = 'icons/inventory/accessory/item_vr.dmi'
icon_state = "dosimeter"
item_state = "dosimeter"
overlay_state = "dosimeter"
slot_flags = SLOT_TIE
var/obj/item/weapon/dosimeter_film/current_film = null
/obj/item/clothing/accessory/dosimeter/New()
@@ -80,19 +76,15 @@
current_film.icon_state = "dosimeter_film[tostate]"
else
icon_state = "[initial(icon_state)]-empty"
update_icon()
/obj/item/weapon/dosimeter_film
name = "dosimeter film"
desc = "These films can be inserted into dosimeters. It turns from white to black, depending on how much radiation it endured."
w_class = ITEMSIZE_SMALL
icon = 'icons/inventory/accessory/item_vr.dmi'
icon_override = 'icons/inventory/accessory/item_vr.dmi'
icon_state = "dosimeter_film0"
var/state = 0 //0 - White, 1 - Darker, 2 - Black (same as iconstates)
/obj/item/weapon/dosimeter_film/proc/update_state(var/tostate)
@@ -117,10 +109,13 @@
/obj/item/weapon/storage/box/dosimeter
name = "dosimeter case"
desc = "This case can only hold the Dosimeter, a few films and a manual."
icon = 'icons/inventory/accessory/item_vr.dmi'
icon_override = 'icons/inventory/accessory/item_vr.dmi'
icon_state = "dosimeter_case"
item_state_slots = list(slot_r_hand_str = "syringe_kit", slot_l_hand_str = "syringe_kit")
storage_slots = 5
can_hold = list(/obj/item/weapon/paper/dosimeter_manual, /obj/item/clothing/accessory/dosimeter, /obj/item/weapon/dosimeter_film)
max_storage_space = (ITEMSIZE_COST_SMALL * 2) + (ITEMSIZE_COST_TINY * 3)
max_storage_space = (ITEMSIZE_COST_SMALL * 4) + (ITEMSIZE_COST_TINY * 1)
w_class = ITEMSIZE_SMALL
/obj/item/weapon/storage/box/dosimeter/New()

View File

@@ -45,9 +45,11 @@
/obj/item/clothing/accessory/holster/machete/rapier/holster(var/obj/item/I, var/mob/living/user)
..()
occupied()
if(has_suit)
has_suit.update_clothing_icon()
/obj/item/clothing/accessory/holster/machete/rapier/unholster(var/obj/item/I, var/mob/living/user)
..()
occupied()
if(has_suit)
has_suit.update_clothing_icon()

View File

@@ -377,3 +377,14 @@
desc = "A very descript undersuit, intended for wearing under a voidsuit or other EVA equipment. This one is specifically made for NanoTrasen Central Command officers, and comes with a swanky gold trim and other fancy markings."
icon_state = "bodysuit_cent"
item_state = "bodysuit_cent"
/obj/item/clothing/under/taur
icon = 'icons/mob/taursuits_horse_vr.dmi'
body_parts_covered = UPPER_TORSO|LOWER_TORSO
pixel_x = -16
/obj/item/clothing/under/taur/skirt
name = "black skirt"
desc = "A fancy black skirt with white corset."
icon_state = "skirt_colorable"
flags_inv = HIDESHOES

View File

@@ -221,8 +221,8 @@
//Job Undercoats
/obj/item/clothing/under/teshari/undercoat/jobs/cap
name = "facility director undercoat"
desc = "A traditional Teshari garb made for the Facility Director"
name = "site manager undercoat"
desc = "A traditional Teshari garb made for the Site Manager"
icon_state = "tesh_uniform_cap"
/obj/item/clothing/under/teshari/undercoat/jobs/hop

View File

@@ -28,7 +28,7 @@
h_user.drop_from_inventory(src)
h_user.drop_from_inventory(SC)
h_user.put_in_hands(SC)
user << "<span class='notice'>You combine the casino chips to a stack of [SC.worth] of credits.</span>"
user << "<span class='notice'>You combine the casino chips to a stack of [SC.worth] credits.</span>"
qdel(src)
/obj/item/weapon/spacecasinocash/update_icon()
@@ -57,7 +57,7 @@
M.Turn(pick(-45, -27.5, 0, 0, 0, 0, 0, 0, 0, 27.5, 45))
banknote.transform = M
src.overlays += banknote
src.desc = "They are worth [worth] of credits."
src.desc = "They are worth [worth] credits."
/obj/item/weapon/spacecasinocash/proc/adjust_worth(var/adjust_worth = 0, var/update = 1)
worth += adjust_worth

View File

@@ -3538,3 +3538,18 @@
/obj/item/weapon/reagent_containers/food/drinks/cans/root_beer = 1)
idle_power_usage = 211 //refrigerator - believe it or not, this is actually the average power consumption of a refrigerated vending machine according to NRCan.
vending_sound = "machines/vending/vending_cans.ogg"
/obj/machinery/vending/altevian
name = "Altevian Imported Meals"
desc = "A vending machine containing imported foods from Altevian Hegemony. Delicious and nutritious. No natural ingridients guaranteed!"
icon = 'icons/obj/vending_vr.dmi'
icon_state = "rattevendor"
product_slogans = "Spacer's choice!;Voidborn food for voidborn people!;Most processed foods ever!"
product_ads = "Perfectly edible!;Squeaky clean foods!;Cheesed to meet you!;Made for spacers, by spacers, of spacers!"
products = list(/obj/item/weapon/reagent_containers/food/snacks/ratprotein = 15,
/obj/item/weapon/reagent_containers/food/snacks/ratveggies = 15,
/obj/item/weapon/reagent_containers/food/snacks/ratliquid = 15)
prices = list(/obj/item/weapon/reagent_containers/food/snacks/ratprotein = 8,
/obj/item/weapon/reagent_containers/food/snacks/ratveggies = 8,
/obj/item/weapon/reagent_containers/food/snacks/ratliquid = 8)

View File

@@ -54,7 +54,8 @@
/obj/machinery/vending/sol,
/obj/machinery/vending/snix,
/obj/machinery/vending/snlvend,
/obj/machinery/vending/sovietvend)
/obj/machinery/vending/sovietvend,
/obj/machinery/vending/altevian)
/obj/item/weapon/refill_cartridge/multitype/drink
name = "drinks vendor refill cartridge"
@@ -121,6 +122,9 @@
/obj/item/weapon/refill_cartridge/autoname/food/sovietvend
refill_type = /obj/machinery/vending/sovietvend
/obj/item/weapon/refill_cartridge/autoname/food/altevian
refill_type = /obj/machinery/vending/altevian
/obj/item/weapon/refill_cartridge/autoname/drink
icon_state = "rc_drink"

View File

@@ -1,121 +0,0 @@
//////////////////CHOMP//////////////////////////
/datum/reagent/ethanol/cloverclub
glass_icon_state = "cloverclub"
glass_icon_source = 'icons/obj/drinks_ch.dmi'
glass_center_of_mass = list("x"=16, "y"=8)
/datum/reagent/ethanol/spiderdrink
glass_icon_state = "glassofspiders"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
/datum/reagent/drink/tea/minttea
glass_icon_file = "bigteacup"
/datum/reagent/drink/tea/lemontea
glass_icon_file = "bigteacup"
/datum/reagent/drink/tea/limetea
glass_icon_file = "bigteacup"
/datum/reagent/drink/tea/orangetea
glass_icon_file = "bigteacup"
/datum/reagent/drink/tea/berrytea
glass_icon_file = "bigteacup"
/datum/reagent/drink/tea/cherrytea
glass_icon_file = "bigteacup"
/datum/reagent/drink/tea/watermelontea
glass_icon_file = "bigteacup"
/datum/reagent/drink/bubbleteawatermelon
glass_icon_state = "bubbleteawatermelonglass"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
glass_center_of_mass = list("x"=16, "y"=9)
/datum/reagent/drink/bubbleteastrawberry
glass_icon_state = "bubbleteastrawberryglass"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
glass_center_of_mass = list("x"=16, "y"=9)
/datum/reagent/drink/bubbleteacherry
glass_icon_state = "bubbleteacherryglass"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
glass_center_of_mass = list("x"=16, "y"=9)
/datum/reagent/drink/bubbleteacoffee
glass_icon_state = "bubbleteacoffeeglass"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
glass_center_of_mass = list("x"=16, "y"=9)
/datum/reagent/drink/bubbleteabanana
glass_icon_state = "bubbleteabananaglass"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
glass_center_of_mass = list("x"=16, "y"=9)
/datum/reagent/drink/tea/matcha_latte
glass_icon_state = "bigteacup"
/datum/reagent/drink/horchata
glass_icon_state = "horchata"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
glass_center_of_mass = list("x"=16, "y"=7)
/datum/reagent/toxin/bluetrain
glass_icon_state = "bluetrain"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
glass_center_of_mass = list("x"=16, "y"=8)
/datum/reagent/drink/lovepotion
glass_icon_state = "lovepotion"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
/datum/reagent/drink/lowpower
glass_icon_state = "lowpower"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
/datum/reagent/ethanol/coffee/jackbrew
glass_icon_state = "jackbrew"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
/datum/reagent/ethanol/bookwyrm
glass_icon_state = "bookwyrm"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
/datum/reagent/drink/highpower
glass_icon_state = "highpower"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
/datum/reagent/ethanol/flapper
glass_icon_state = "flapper"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
/datum/reagent/toxin/oilslide
glass_icon_state = "oilslide"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
/datum/reagent/ethanol/sitonmyface
glass_icon_state = "sitonmyface"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
/datum/reagent/ethanol/hachi
glass_icon_state = "hachi"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
/datum/reagent/ethanol/mojito
glass_icon_state = "mojito"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
/datum/reagent/slimedrink
glass_icon_state = "slimedrink"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
/datum/reagent/ethanol/arachnidslammer
glass_icon_state = "arachnidslammer"
glass_icon_file = 'icons/obj/drinks_ch.dmi'
/datum/reagent/drink/pilk
glass_icon_state = "whiskeyglass"
glass_icon_file = 'icons/obj/drinks.dmi'

View File

@@ -774,3 +774,55 @@
. = ..()
reagents.add_reagent("uranium", 3)
reagents.add_reagent("pyrotoxin", 3)
// Altevian Foobs
/obj/item/weapon/reagent_containers/food/snacks/ratprotein
name = "AN Flavor Unit C"
desc = "A snack made from a group of space-faring rodents that is packed with the maximized potential of caloric intake to cubic inch. This one seems to be flavored of smoked cheddar and salami."
icon = 'icons/obj/food_vr.dmi'
icon_state = "altevian_cheese_block"
package_open_state = "altevian_cheese_block-open"
package = TRUE
trash = /obj/item/trash/ratcheese
nutriment_amt = 5
nutriment_desc = list("smoked cheese" = 4)
/obj/item/weapon/reagent_containers/food/snacks/ratveggies
name = "Premium Ration Packet - VEG"
desc = "A package of a mixture of somehow still fresh from day 1 greens with a light hint of vinegar dressing to add extra kick."
icon = 'icons/obj/food_vr.dmi'
icon_state = "altevian_veggies"
package_open_state = "altevian_veggies-open"
package = TRUE
trash = /obj/item/trash/ratveg
nutriment_amt = 3
nutriment_desc = list("fresh mixed veggies" = 3, "vinegar" = 1)
/obj/item/weapon/reagent_containers/food/snacks/ratliquid
name = "Admiral's Choice Space-Safe Meal"
desc = "A vacuum sealed pouch of a liquid meal. This one seems to be flavored with the accent of steak."
icon = 'icons/obj/food_vr.dmi'
icon_state = "altevian_juice"
package_open_state = "altevian_juice-open"
package = TRUE
trash = /obj/item/trash/ratjuice
nutriment_amt = 2
nutriment_desc = list("essence of steak" = 6)
/obj/item/weapon/reagent_containers/food/snacks/ratliquid/Initialize()
. = ..()
reagents.add_reagent("protein", 4)
/obj/item/weapon/reagent_containers/food/snacks/ratsteak
name = "altevian traditional steak"
desc = "This abomination of processed foods resembles a steak plate. Probably contains nothing a normal steak does, but mimics its flavor and nutrition well-enough."
icon = 'icons/obj/food_vr.dmi'
icon_state = "altevian_steak"
trash = /obj/item/trash/plate
nutriment_amt = 8
nutriment_desc = list("steak" = 5, "smoked cheese" = 2, "veggies" = 1)
/obj/item/weapon/reagent_containers/food/snacks/ratsteak/Initialize()
. = ..()
reagents.add_reagent("protein", 3)

View File

@@ -185,3 +185,11 @@
reagents = list("sugar" = 5, "nutriment" = 5)
items = list()
result = /obj/item/weapon/reagent_containers/food/snacks/honey_candy
/datum/recipe/altevian_steak
items = list(
/obj/item/weapon/reagent_containers/food/snacks/ratprotein,
/obj/item/weapon/reagent_containers/food/snacks/ratveggies,
/obj/item/weapon/reagent_containers/food/snacks/ratliquid
)
result = /obj/item/weapon/reagent_containers/food/snacks/ratsteak

View File

@@ -132,7 +132,10 @@
2 * age >= seed.get_trait(TRAIT_MATURATION) && \
!(locate(/obj/effect/plant) in get_turf(src)) && \
prob(2 * seed.get_trait(TRAIT_POTENCY)))
new /obj/effect/plant(get_turf(src), seed)
// CHOMPEdit Start - Need to start processing the vine or it'll never spread.
var/obj/effect/plant/D = new /obj/effect/plant(get_turf(src), seed)
SSplants.add_plant(D)
// CHOMPEdit End
if(prob(3)) // On each tick, there's a chance the pest population will increase
pestlevel += 0.1 * HYDRO_SPEED_MULTIPLIER

View File

@@ -141,8 +141,8 @@
if(dead)
channels_playing -= channel
channels_idle += channel
for(var/mob/M as anything in hearing_mobs)
for(var/mob/M in hearing_mobs)
M.stop_sound_channel(channelnumber)
else
for(var/mob/M as anything in hearing_mobs)
for(var/mob/M in hearing_mobs)
M.set_sound_channel_volume(channelnumber, (current_volume * 0.01) * volume * using_instrument.volume_multiplier)

View File

@@ -309,6 +309,8 @@ Book Cart End
var/list/pages = list() //the contents of each page
/obj/item/weapon/book/bundle/proc/show_content(mob/user as mob)
if(!pages.len)
return
var/dat
var/obj/item/weapon/W = pages[page]
// first

View File

@@ -0,0 +1,263 @@
/client
var/datum/mentor/mentorholder = null
var/list/mentor_datums = list()
var/list/mentor_verbs_default = list(
/client/proc/cmd_mentor_ticket_panel,
/client/proc/cmd_mentor_say,
/client/proc/cmd_dementor
)
/datum/mentor
var/client/owner = null
/datum/mentor/New(ckey)
if(!ckey)
error("Mentor datum created without a ckey argument. Datum has been deleted")
qdel(src)
return
mentor_datums[ckey] = src
/datum/mentor/proc/associate(client/C)
if(istype(C))
owner = C
owner.mentorholder = src
owner.add_mentor_verbs()
GLOB.mentors |= C
/datum/mentor/proc/disassociate()
if(owner)
GLOB.mentors -= owner
owner.remove_mentor_verbs()
owner.mentorholder = null
mentor_datums[owner.ckey] = null
qdel(src)
/client/proc/add_mentor_verbs()
if(mentorholder)
verbs += mentor_verbs_default
/client/proc/remove_mentor_verbs()
if(mentorholder)
verbs -= mentor_verbs_default
/client/proc/make_mentor()
set category = "Special Verbs"
set name = "Make Mentor"
if(!holder)
to_chat(src, "<span class='pm warning'>Error: Only administrators may use this command.</span>")
return
var/list/client/targets[0]
for(var/client/T in GLOB.clients)
targets["[T.key]"] = T
var/target = tgui_input_list(src,"Who do you want to make a mentor?","Make Mentor", sortList(targets))
if(!target)
return
var/client/C = targets[target]
if(has_mentor_powers(C) || C.deadmin_holder) // If an admin is deadminned you could mentor them and that will cause fuckery if they readmin
to_chat(src, "<span class='pm warning'>Error: They already have mentor powers.</span>")
return
var/datum/mentor/M = new /datum/mentor(C.ckey)
M.associate(C)
to_chat(C, "<span class='pm notice'>You have been granted mentorship.</span>")
to_chat(src, "<span class='pm notice'>You have made [C] a mentor.</span>")
log_admin("[key_name(src)] made [key_name(C)] a mentor.")
feedback_add_details("admin_verb","Make Mentor") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/unmake_mentor()
set category = "Special Verbs"
set name = "Unmake Mentor"
if(!holder)
to_chat(src, "<span class='pm warning'>Error: Only administrators may use this command.</span>")
return
var/list/client/targets[0]
for(var/client/T in GLOB.mentors)
targets["[T.key]"] = T
var/target = tgui_input_list(src,"Which mentor do you want to unmake?","Unmake Mentor", sortList(targets))
if(!target)
return
var/client/C = targets[target]
C.mentorholder.disassociate()
to_chat(C, "<span class='pm warning'>Your mentorship has been revoked.</span>")
to_chat(src, "<span class='pm notice'>You have revoked [C]'s mentorship.</span>")
log_admin("[key_name(src)] revoked [key_name(C)]'s mentorship.")
feedback_add_details("admin_verb","Unmake Mentor") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/cmd_mentor_say(msg as text)
set category = "Admin"
set name ="Mentorsay"
//check rights
if (!has_mentor_powers(src))
return
msg = sanitize(msg)
if (!msg)
return
log_admin("Mentorsay: [key_name(src)]: [msg]")
for(var/client/C in GLOB.mentors)
to_chat(C, create_text_tag("mentor", "MENTOR:", C) + " <span class='mentor_channel'><span class='name'>[src]</span>: <span class='message'>[msg]</span></span>")
for(var/client/C in GLOB.admins)
to_chat(C, create_text_tag("mentor", "MENTOR:", C) + " <span class='mentor_channel'><span class='name'>[src]</span>: <span class='message'>[msg]</span></span>")
/proc/mentor_commands(href, href_list, client/C)
if(href_list["mhelp"])
var/mhelp_ref = href_list["mhelp"]
var/datum/mentor_help/MH = locate(mhelp_ref)
if (MH && istype(MH, /datum/mentor_help))
MH.Action(href_list["mhelp_action"])
else
to_chat(C, "Ticket [mhelp_ref] has been deleted!")
if (href_list["mhelp_tickets"])
GLOB.mhelp_tickets.BrowseTickets(text2num(href_list["mhelp_tickets"]))
/datum/mentor/Topic(href, href_list)
..()
if (usr.client != src.owner || (!usr.client.mentorholder))
log_admin("[key_name(usr)] tried to illegally use mentor functions.")
message_admins("[usr.key] tried to illegally use mentor functions.")
return
mentor_commands(href, href_list, usr)
/client/proc/cmd_dementor()
set category = "Admin"
set name = "De-mentor"
if(tgui_alert(usr, "Confirm self-dementor for the round? You can't re-mentor yourself without someone promoting you.","Dementor",list("Yes","No")) == "Yes")
src.mentorholder.disassociate()
/client/proc/cmd_mhelp_reply(whom)
if(prefs.muted & MUTE_ADMINHELP)
to_chat(src, "<span class='pm warning'>Error: Mentor-PM: You are unable to use admin PM-s (muted).</span>")
return
var/client/C
if(istext(whom))
C = GLOB.directory[whom]
else if(istype(whom,/client))
C = whom
if(!C)
if(has_mentor_powers(src))
to_chat(src, "<span class='pm warning'>Error: Mentor-PM: Client not found.</span>")
return
var/datum/mentor_help/MH = C.current_mentorhelp
if(MH)
message_mentors("<span class='mentor_channel'>[src] has started replying to [C]'s mentor help.</span>")
var/msg = tgui_input_text(src,"Message:", "Private message to [C]")
if (!msg)
message_mentors("<span class='mentor_channel'>[src] has cancelled their reply to [C]'s mentor help.</span>")
return
cmd_mentor_pm(whom, msg, MH)
/proc/has_mentor_powers(client/C)
return C.holder || C.mentorholder
// This not really a great place to put it, but this verb replaces adminhelp in hotkeys so that people requesting help can select the type they need
// You can still directly adminhelp if necessary, this ONLY replaces the inbuilt hotkeys
/client/verb/requesthelp()
set category = "Admin"
set name = "Request help"
set hidden = 1
var/mhelp = tgui_alert(usr, "Select the help you need.","Request for Help",list("Adminhelp","Mentorhelp")) == "Mentorhelp"
var/msg = tgui_input_text(usr, "Input your request for help.", "Request for Help")
if (mhelp)
mentorhelp(msg)
return
adminhelp(msg)
/client/proc/cmd_mentor_pm(whom, msg, datum/mentor_help/MH)
set category = "Admin"
set name = "Mentor-PM"
set hidden = 1
if(prefs.muted & MUTE_ADMINHELP)
to_chat(src, "<span class='pm warning'>Error: Mentor-PM: You are unable to use admin PM-s (muted).</span>")
return
//Not a mentor and no open ticket
if(!has_mentor_powers(src) && !current_mentorhelp)
to_chat(src, "<span class='pm warning'>You can no longer reply to this ticket, please open another one by using the Mentorhelp verb if need be.</span>")
to_chat(src, "<span class='pm notice'>Message: [msg]</span>")
return
var/client/recipient
if(istext(whom))
recipient = GLOB.directory[whom]
else if(istype(whom,/client))
recipient = whom
//get message text, limit it's length.and clean/escape html
if(!msg)
msg = tgui_input_text(src,"Message:", "Mentor-PM to [whom]")
if(!msg)
return
if(prefs.muted & MUTE_ADMINHELP)
to_chat(src, "<span class='pm warning'>Error: Mentor-PM: You are unable to use admin PM-s (muted).</span>")
return
if(!recipient)
if(has_mentor_powers(src))
to_chat(src, "<span class='pm warning'>Error:Mentor-PM: Client not found.</span>")
to_chat(src, msg)
else
log_admin("Mentorhelp: [key_name(src)]: [msg]")
current_mentorhelp.MessageNoRecipient(msg)
return
//Has mentor powers but the recipient no longer has an open ticket
if(has_mentor_powers(src) && !recipient.current_mentorhelp)
to_chat(src, "<span class='pm warning'>You can no longer reply to this ticket.</span>")
to_chat(src, "<span class='pm notice'>Message: [msg]</span>")
return
if (src.handle_spam_prevention(msg,MUTE_ADMINHELP))
return
msg = trim(sanitize(copytext(msg,1,MAX_MESSAGE_LEN)))
if(!msg)
return
var/interaction_message = "<span class='pm notice'>Mentor-PM from-<b>[src]</b> to-<b>[recipient]</b>: [msg]</span>"
if (recipient.current_mentorhelp && !has_mentor_powers(recipient))
recipient.current_mentorhelp.AddInteraction(interaction_message)
if (src.current_mentorhelp && !has_mentor_powers(src))
src.current_mentorhelp.AddInteraction(interaction_message)
// It's a little fucky if they're both mentors, but while admins may need to adminhelp I don't really see any reason a mentor would have to mentorhelp since you can literally just ask any other mentors online
if (has_mentor_powers(recipient) && has_mentor_powers(src))
if (recipient.current_mentorhelp)
recipient.current_mentorhelp.AddInteraction(interaction_message)
if (src.current_mentorhelp)
src.current_mentorhelp.AddInteraction(interaction_message)
to_chat(recipient, "<i><span class='mentor'>Mentor-PM from-<b><a href='?mentorhelp_msg=\ref[src]'>[src]</a></b>: [msg]</span></i>")
to_chat(src, "<i><span class='mentor'>Mentor-PM to-<b>[recipient]</b>: [msg]</span></i>")
log_admin("[key_name(src)]->[key_name(recipient)]: [msg]")
if(recipient.is_preference_enabled(/datum/client_preference/play_mentorhelp_ping))
recipient << 'sound/effects/mentorhelp.mp3'
for(var/client/C in GLOB.mentors)
if (C != recipient && C != src)
to_chat(C, interaction_message)
for(var/client/C in GLOB.admins)
if (C != recipient && C != src)
to_chat(C, interaction_message)

View File

@@ -0,0 +1,415 @@
/client/var/datum/mentor_help/current_mentorhelp
//
//TICKET MANAGER
//
GLOBAL_DATUM_INIT(mhelp_tickets, /datum/mentor_help_tickets, new)
/datum/mentor_help_tickets
var/list/active_tickets = list()
var/list/resolved_tickets = list()
var/obj/effect/statclick/mticket_list/astatclick = new(null, null, AHELP_ACTIVE)
var/obj/effect/statclick/mticket_list/rstatclick = new(null, null, AHELP_RESOLVED)
/datum/mentor_help_tickets/Destroy()
QDEL_LIST(active_tickets)
QDEL_LIST(resolved_tickets)
QDEL_NULL(astatclick)
QDEL_NULL(rstatclick)
return ..()
//private
/datum/mentor_help_tickets/proc/ListInsert(datum/mentor_help/new_ticket)
var/list/mticket_list
switch(new_ticket.state)
if(AHELP_ACTIVE)
mticket_list = active_tickets
if(AHELP_RESOLVED)
mticket_list = resolved_tickets
else
CRASH("Invalid ticket state: [new_ticket.state]")
var/num_closed = mticket_list.len
if(num_closed)
for(var/I in 1 to num_closed)
var/datum/mentor_help/MH = mticket_list[I]
if(MH.id > new_ticket.id)
mticket_list.Insert(I, new_ticket)
return
mticket_list += new_ticket
//opens the ticket listings, only two states here
/datum/mentor_help_tickets/proc/BrowseTickets(state)
var/list/l2b
var/title
switch(state)
if(AHELP_ACTIVE)
l2b = active_tickets
title = "Active Tickets"
if(AHELP_RESOLVED)
l2b = resolved_tickets
title = "Resolved Tickets"
if(!l2b)
return
var/list/dat = list("<html><head><title>[title]</title></head>")
dat += "<A HREF='?_src_=mentorholder;mhelp_tickets=[state]'>Refresh</A><br><br>"
for(var/datum/mentor_help/MH as anything in l2b)
dat += "<span class='adminnotice'><span class='adminhelp'>Ticket #[MH.id]</span>: <A HREF='?_src_=mentorholder;mhelp=\ref[MH];mhelp_action=ticket'>[MH.initiator_ckey]: [MH.name]</A></span><br>"
usr << browse(dat.Join(), "window=mhelp_list[state];size=600x480")
//Tickets statpanel
/datum/mentor_help_tickets/proc/stat_entry()
var/num_disconnected = 0
stat("Active Tickets:", astatclick.update("[active_tickets.len]"))
for(var/datum/mentor_help/MH as anything in active_tickets)
if(MH.initiator)
stat("#[MH.id]. [MH.initiator_ckey]:", MH.statclick.update())
else
++num_disconnected
if(num_disconnected)
stat("Disconnected:", astatclick.update("[num_disconnected]"))
stat("Resolved Tickets:", rstatclick.update("[resolved_tickets.len]"))
//Reassociate still open ticket if one exists
/datum/mentor_help_tickets/proc/ClientLogin(client/C)
C.current_mentorhelp = CKey2ActiveTicket(C.ckey)
if(C.current_mentorhelp)
C.current_mentorhelp.AddInteraction("Client reconnected.")
C.current_mentorhelp.initiator = C
//Dissasociate ticket
/datum/mentor_help_tickets/proc/ClientLogout(client/C)
if(C.current_mentorhelp)
C.current_mentorhelp.AddInteraction("Client disconnected.")
C.current_mentorhelp.initiator = null
C.current_mentorhelp = null
//Get a ticket given a ckey
/datum/mentor_help_tickets/proc/CKey2ActiveTicket(ckey)
for(var/datum/admin_help/MH as anything in active_tickets)
if(MH.initiator_ckey == ckey)
return MH
//
//TICKET LIST STATCLICK
//
/obj/effect/statclick/mticket_list
var/current_state
/obj/effect/statclick/mticket_list/New(loc, name, state)
current_state = state
..()
/obj/effect/statclick/mticket_list/Click()
GLOB.mhelp_tickets.BrowseTickets(current_state)
//
//TICKET DATUM
//
/datum/mentor_help
var/id
var/name
var/state = AHELP_ACTIVE
var/opened_at
var/closed_at
var/client/initiator //semi-misnomer, it's the person who ahelped/was bwoinked
var/initiator_ckey
var/initiator_key_name
var/list/_interactions //use AddInteraction() or, preferably, admin_ticket_log()
var/obj/effect/statclick/ahelp/statclick
var/static/ticket_counter = 0
//call this on its own to create a ticket, don't manually assign current_mentorhelp
//msg is the title of the ticket: usually the ahelp text
/datum/mentor_help/New(msg, client/C)
//clean the input msg
msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
if(!msg || !C || !C.mob)
qdel(src)
return
id = ++ticket_counter
opened_at = world.time
name = msg
initiator = C
initiator_ckey = C.ckey
initiator_key_name = key_name(initiator, FALSE, TRUE)
if(initiator.current_mentorhelp) //This is a bug
log_debug("Ticket erroneously left open by code")
initiator.current_mentorhelp.AddInteraction("Ticket erroneously left open by code")
initiator.current_mentorhelp.Resolve()
initiator.current_mentorhelp = src
statclick = new(null, src)
_interactions = list()
log_admin("Mentorhelp: [key_name(C)]: [msg]")
MessageNoRecipient(msg)
//show it to the person adminhelping too
to_chat(C, "<i><span class='mentor'>Mentor-PM to-<b>Mentors</b>: [name]</span></i>")
GLOB.mhelp_tickets.active_tickets += src
/datum/mentor_help/Destroy()
RemoveActive()
GLOB.mhelp_tickets.resolved_tickets -= src
return ..()
/datum/mentor_help/proc/AddInteraction(formatted_message)
_interactions += "[gameTimestamp()]: [formatted_message]"
//private
/datum/mentor_help/proc/ClosureLinks(ref_src)
if(!ref_src)
ref_src = "\ref[src]"
. = " (<A HREF='?_src_=mentorholder;mhelp=[ref_src];mhelp_action=resolve'>RSLVE</A>)"
//private
/datum/mentor_help/proc/LinkedReplyName(ref_src)
if(!ref_src)
ref_src = "\ref[src]"
return "<A HREF='?_src_=mentorholder;mhelp=[ref_src];mhelp_action=reply'>[initiator_ckey]</A>"
//private
/datum/mentor_help/proc/TicketHref(msg, ref_src, action = "ticket")
if(!ref_src)
ref_src = "\ref[src]"
return "<A HREF='?_src_=mentorholder;mhelp=[ref_src];mhelp_action=[action]'>[msg]</A>"
//message from the initiator without a target, all people with mentor powers will see this
/datum/mentor_help/proc/MessageNoRecipient(msg)
var/ref_src = "\ref[src]"
var/chat_msg = "<span class='notice'>(<A HREF='?_src_=mentorholder;mhelp=[ref_src];mhelp_action=escalate'>ESCALATE</A>) Ticket [TicketHref("#[id]", ref_src)]<b>: [LinkedReplyName(ref_src)]:</b> [msg]</span>"
AddInteraction("<font color='red'>[LinkedReplyName(ref_src)]: [msg]</font>")
for (var/client/C in GLOB.mentors)
if (C.is_preference_enabled(/datum/client_preference/play_mentorhelp_ping))
C << 'sound/effects/mentorhelp.mp3'
for (var/client/C in GLOB.admins)
if (C.is_preference_enabled(/datum/client_preference/play_mentorhelp_ping))
C << 'sound/effects/mentorhelp.mp3'
message_mentors(chat_msg)
//Reopen a closed ticket
/datum/mentor_help/proc/Reopen()
if(state == AHELP_ACTIVE)
to_chat(usr, "<span class='warning'>This ticket is already open.</span>")
return
if(GLOB.mhelp_tickets.CKey2ActiveTicket(initiator_ckey))
to_chat(usr, "<span class='warning'>This user already has an active ticket, cannot reopen this one.</span>")
return
statclick = new(null, src)
GLOB.mhelp_tickets.active_tickets += src
GLOB.mhelp_tickets.resolved_tickets -= src
switch(state)
if(AHELP_RESOLVED)
feedback_dec("mhelp_resolve")
state = AHELP_ACTIVE
closed_at = null
if(initiator)
initiator.current_mentorhelp = src
AddInteraction("<font color='purple'>Reopened by [usr.ckey]</font>")
if(initiator)
to_chat(initiator, "<span class='filter_adminlog'><font color='purple'>Ticket [TicketHref("#[id]")] was reopened by [usr.ckey].</font></span>")
var/msg = "<span class='adminhelp'>Ticket [TicketHref("#[id]")] reopened by [usr.ckey].</span>"
message_mentors(msg)
log_admin(msg)
feedback_inc("mhelp_reopen")
TicketPanel() //can only be done from here, so refresh it
//private
/datum/mentor_help/proc/RemoveActive()
if(state != AHELP_ACTIVE)
return
closed_at = world.time
QDEL_NULL(statclick)
GLOB.mhelp_tickets.active_tickets -= src
if(initiator && initiator.current_mentorhelp == src)
initiator.current_mentorhelp = null
//Mark open ticket as resolved/legitimate, returns mentorhelp verb
/datum/mentor_help/proc/Resolve(silent = FALSE)
if(state != AHELP_ACTIVE)
return
RemoveActive()
state = AHELP_RESOLVED
GLOB.mhelp_tickets.ListInsert(src)
AddInteraction("<span class='filter_adminlog'><font color='green'>Resolved by [usr.ckey].</font></span>")
if(initiator)
to_chat(initiator, "<span class='filter_adminlog'><font color='green'>Ticket [TicketHref("#[id]")] was marked resolved by [usr.ckey].</font></span>")
if(!silent)
feedback_inc("mhelp_resolve")
var/msg = "Ticket [TicketHref("#[id]")] resolved by [usr.ckey]"
message_mentors(msg)
log_admin(msg)
//Show the ticket panel
/datum/mentor_help/proc/TicketPanel()
var/list/dat = list("<html><head><title>Ticket #[id]</title></head>")
var/ref_src = "\ref[src]"
dat += "<h4>Mentor Help Ticket #[id]: [LinkedReplyName(ref_src)]</h4>"
dat += "<b>State: "
switch(state)
if(AHELP_ACTIVE)
dat += "<font color='red'>OPEN</font>"
if(AHELP_RESOLVED)
dat += "<font color='green'>RESOLVED</font>"
else
dat += "UNKNOWN"
dat += "</b>[GLOB.TAB][TicketHref("Refresh", ref_src)]"
if(state != AHELP_ACTIVE)
dat += "[GLOB.TAB][TicketHref("Reopen", ref_src, "reopen")]"
dat += "<br><br>Opened at: [gameTimestamp(wtime = opened_at)] (Approx [(world.time - opened_at) / 600] minutes ago)"
if(closed_at)
dat += "<br>Closed at: [gameTimestamp(wtime = closed_at)] (Approx [(world.time - closed_at) / 600] minutes ago)"
dat += "<br><br>"
if(initiator)
dat += "<b>Actions:</b> [Context(ref_src)]<br>"
else
dat += "<b>DISCONNECTED</b>[GLOB.TAB][ClosureLinks(ref_src)]<br>"
dat += "<br><b>Log:</b><br><br>"
for(var/I in _interactions)
dat += "[I]<br>"
usr << browse(dat.Join(), "window=mhelp[id];size=620x480")
//Kick ticket to admins
/datum/mentor_help/proc/Escalate()
if(tgui_alert(usr, "Really escalate this ticket to admins? No mentors will ever be able to interact with it again if you do.","Escalate",list("Yes","No")) != "Yes")
return
if (src.initiator == null) // You can't escalate a mentorhelp of someone who's logged out because it won't create the adminhelp properly
to_chat(usr, "<span class='pm warning'>Error: client not found, unable to escalate.</span>")
return
var/datum/admin_help/AH = new /datum/admin_help(src.name, src.initiator, FALSE)
message_mentors("[usr.ckey] escalated Ticket [TicketHref("#[id]")]")
log_admin("[key_name(usr)] escalated mentorhelp [src.name]")
to_chat(src.initiator, "<span class='mentor'>[usr.ckey] escalated your mentorhelp to admins.</span>")
AH._interactions = src._interactions
GLOB.mhelp_tickets.active_tickets -= src
GLOB.mhelp_tickets.resolved_tickets -= src
qdel(src)
/datum/mentor_help/proc/Context(ref_src)
if(!ref_src)
ref_src = "\ref[src]"
if(state == AHELP_ACTIVE)
. += ClosureLinks(ref_src)
if(state != AHELP_RESOLVED)
. += " (<A HREF='?_src_=mentorholder;mhelp=[ref_src];mhelp_action=escalate'>ESCALATE</A>)"
//Forwarded action from admin/Topic OR mentor/Topic depending on which rank the caller has
/datum/mentor_help/proc/Action(action)
switch(action)
if("ticket")
TicketPanel()
if("reply")
usr.client.cmd_mhelp_reply(initiator)
if("resolve")
Resolve()
if("reopen")
Reopen()
if("escalate")
Escalate()
//
// TICKET STATCLICK
//
/obj/effect/statclick/mhelp
var/datum/mentor_help/mhelp_datum
/obj/effect/statclick/mhelp/New(loc, datum/mentor_help/MH)
mhelp_datum = MH
..(loc)
/obj/effect/statclick/mhelp/update()
return ..(mhelp_datum.name)
/obj/effect/statclick/mhelp/Click()
mhelp_datum.TicketPanel()
/obj/effect/statclick/mhelp/Destroy()
mhelp_datum = null
return ..()
//
// CLIENT PROCS
//
/client/verb/mentorhelp(msg as text)
set category = "Admin"
set name = "Mentorhelp"
if(say_disabled) //This is here to try to identify lag problems
to_chat(usr, "<span class='danger'>Speech is currently admin-disabled.</span>")
return
//handle muting and automuting
if(prefs.muted & MUTE_ADMINHELP)
to_chat(src, "<span class='danger'>Error: Mentor-PM: You cannot send adminhelps (Muted).</span>")
return
if(handle_spam_prevention(msg,MUTE_ADMINHELP))
return
if(!msg)
return
//remove out adminhelp verb temporarily to prevent spamming of admins.
src.verbs -= /client/verb/mentorhelp
spawn(600)
src.verbs += /client/verb/mentorhelp // 1 minute cool-down for mentorhelps
feedback_add_details("admin_verb","Mentorhelp") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
if(current_mentorhelp)
if(tgui_alert(usr, "You already have a ticket open. Is this for the same issue?","Duplicate?",list("Yes","No")) != "No")
if(current_mentorhelp)
log_admin("Mentorhelp: [key_name(src)]: [msg]")
current_mentorhelp.MessageNoRecipient(msg)
to_chat(usr, "<span class='adminnotice'><span class='mentor'>Mentor-PM to-<b>Mentors</b>: [msg]</span></span>")
return
else
to_chat(usr, "<span class='warning'>Ticket not found, creating new one...</span>")
else
current_mentorhelp.AddInteraction("[usr.ckey] opened a new ticket.")
current_mentorhelp.Resolve()
new /datum/mentor_help(msg, src, FALSE)
//admin proc
/client/proc/cmd_mentor_ticket_panel()
set name = "Mentor Ticket List"
set category = "Admin"
var/browse_to
switch(tgui_input_list(usr, "Display which ticket list?", "List Choice", list("Active Tickets", "Resolved Tickets")))
if("Active Tickets")
browse_to = AHELP_ACTIVE
if("Resolved Tickets")
browse_to = AHELP_RESOLVED
else
return
GLOB.mhelp_tickets.BrowseTickets(browse_to)
/proc/message_mentors(var/msg)
msg = "<span class='mentor_channel'><span class='prefix'>Mentor:</span> <span class=\"message\">[msg]</span></span>"
for(var/client/C in GLOB.mentors)
to_chat(C, msg)
for(var/client/C in GLOB.admins)
to_chat(C, msg)

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