mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-12 11:13:16 +00:00
Merge branch 'CHOMPStation2:master' into craft
This commit is contained in:
14
modular_chomp/code/_onclick/hud/alert.dm
Normal file
14
modular_chomp/code/_onclick/hud/alert.dm
Normal file
@@ -0,0 +1,14 @@
|
||||
/obj/screen/alert/open_ticket
|
||||
icon = 'modular_chomp/icons/logo.dmi'
|
||||
name = "Admin Chat Request"
|
||||
desc = "A Administrator would like to chat with you. \
|
||||
Click here to begin."
|
||||
icon_state = "32x32"
|
||||
|
||||
/obj/screen/alert/open_ticket/Click()
|
||||
if(!usr || !usr.client) return
|
||||
|
||||
// Open a new chat with the user
|
||||
var/datum/ticket_chat/TC = new()
|
||||
TC.T = usr.client.current_ticket
|
||||
TC.tgui_interact(usr.client.mob)
|
||||
99
modular_chomp/code/datums/supplypacks/contraband.dm
Normal file
99
modular_chomp/code/datums/supplypacks/contraband.dm
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Here is where any supply packs that may or may not be legal
|
||||
* and require modification of the supply controller live.
|
||||
*/
|
||||
|
||||
|
||||
/datum/supply_pack/randomised/contraband
|
||||
num_contained = 5
|
||||
contains = list(
|
||||
/obj/item/seeds/bloodtomatoseed,
|
||||
/obj/item/weapon/storage/pill_bottle/zoom,
|
||||
/obj/item/weapon/storage/pill_bottle/happy,
|
||||
/obj/item/weapon/reagent_containers/food/drinks/bottle/pwine
|
||||
)
|
||||
|
||||
name = "Contraband crate"
|
||||
cost = 25
|
||||
containertype = /obj/structure/closet/crate
|
||||
containername = "Unlabeled crate"
|
||||
contraband = 1
|
||||
group = "Supplies"
|
||||
|
||||
/datum/supply_pack/security/specialops
|
||||
name = "Special Ops supplies"
|
||||
contains = list(
|
||||
/obj/item/weapon/storage/box/emps,
|
||||
/obj/item/weapon/grenade/smokebomb = 4,
|
||||
/obj/item/weapon/grenade/chem_grenade/incendiary
|
||||
)
|
||||
cost = 25
|
||||
containertype = /obj/structure/closet/crate/weapon
|
||||
containername = "Special Ops crate"
|
||||
contraband = 1
|
||||
|
||||
/datum/supply_pack/supply/moghes
|
||||
name = "Moghes imports"
|
||||
contains = list(
|
||||
/obj/item/weapon/reagent_containers/food/drinks/bottle/redeemersbrew = 2,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/unajerky = 4
|
||||
)
|
||||
cost = 25
|
||||
containertype = /obj/structure/closet/crate/unathi
|
||||
containername = "Moghes imports crate"
|
||||
contraband = 1
|
||||
|
||||
/datum/supply_pack/munitions/bolt_rifles_militia
|
||||
name = "Weapon - Surplus militia rifles"
|
||||
contains = list(
|
||||
/obj/item/weapon/gun/projectile/shotgun/pump/rifle = 3,
|
||||
/obj/item/ammo_magazine/clip/c762 = 6
|
||||
)
|
||||
cost = 1000
|
||||
contraband = 1
|
||||
containertype = /obj/structure/closet/crate/hedberg
|
||||
containername = "Ballistic weapons crate"
|
||||
|
||||
/datum/supply_pack/randomised/misc/telecrate
|
||||
name = "Confiscated equipment"
|
||||
num_contained = 1
|
||||
contains = list(
|
||||
list( //the operator,
|
||||
/obj/item/clothing/suit/storage/vest/heavy/merc,
|
||||
/obj/item/clothing/glasses/night,
|
||||
/obj/item/weapon/storage/box/anti_photons
|
||||
),
|
||||
list( //the indian,
|
||||
/obj/item/weapon/gun/projectile/dartgun,
|
||||
/obj/item/ammo_magazine/chemdart
|
||||
),
|
||||
|
||||
list( //the doc,
|
||||
/obj/item/weapon/storage/firstaid/combat,
|
||||
/obj/item/weapon/reagent_containers/hypospray
|
||||
),
|
||||
|
||||
list( //the sapper,
|
||||
/obj/item/weapon/melee/energy/sword/ionic_rapier,
|
||||
/obj/item/weapon/storage/box/syndie_kit/space, //doesn't matter what species you are,
|
||||
/obj/item/device/multitool/ai_detector,
|
||||
/obj/item/weapon/storage/toolbox/syndicate/powertools
|
||||
),
|
||||
list( //the infiltrator,
|
||||
/obj/item/device/chameleon,
|
||||
/obj/item/weapon/storage/box/syndie_kit/chameleon,
|
||||
/obj/item/device/encryptionkey/syndicate,
|
||||
/obj/item/weapon/card/id/syndicate,
|
||||
/obj/item/clothing/mask/gas/voice,
|
||||
/obj/item/weapon/makeover
|
||||
),
|
||||
list( //the professional,
|
||||
/obj/item/weapon/gun/energy/ionrifle/pistol,
|
||||
/obj/item/weapon/material/knife/tacknife/combatknife,
|
||||
/obj/item/clothing/mask/balaclava
|
||||
)
|
||||
)
|
||||
cost = 400 //price,
|
||||
contraband = 1
|
||||
containertype = /obj/structure/closet/crate/large
|
||||
containername = "Suspicious crate"
|
||||
@@ -1,5 +1,5 @@
|
||||
/obj/item/weapon/flame/lighter/safesmzippo
|
||||
name = "Supermatter Zippo"
|
||||
/obj/item/weapon/flame/lighter/supermatter
|
||||
name = "Hardlight Supermatter Zippo" // Base SM Lighter
|
||||
desc = "State of the Art Supermatter Lighter."
|
||||
description_fluff = "A zippo style lighter with a tiny supermatter sliver held by a hardlight shield. When lighting a cigar, make sure to hover the tip near the sliver, not against it!"
|
||||
icon = 'icons/obj/zippo_ch.dmi'
|
||||
@@ -8,8 +8,8 @@
|
||||
activation_sound = 'modular_chomp/sound/items/open.ogg'
|
||||
deactivation_sound = 'sound/items/zippo_off.ogg'
|
||||
|
||||
/obj/item/weapon/flame/lighter/syndismzippo
|
||||
name = "Syndicate SM Zippo"
|
||||
/obj/item/weapon/flame/lighter/supermatter/syndismzippo
|
||||
name = "Phoron Supermatter Zippo" // Syndicate SM Lighter
|
||||
desc = "State of the Art Supermatter Lighter."
|
||||
description_fluff = "A red zippo style lighter with a tiny supermatter sliver held by a phoron field."
|
||||
icon = 'icons/obj/zippo_ch.dmi'
|
||||
@@ -18,8 +18,18 @@
|
||||
activation_sound = 'modular_chomp/sound/items/open.ogg'
|
||||
deactivation_sound = 'sound/items/zippo_off.ogg'
|
||||
|
||||
/obj/item/weapon/flame/lighter/supermatter/expsmzippo
|
||||
name = "Experimental SM Lighter" // Dangerous WIP (admin/event only ATM)
|
||||
desc = "State of the Art Supermatter Lighter"
|
||||
description_fluff = "A unique take originating from the zippo design, a shard of supermatter placed within lead-lined walls. Cautious, VERY DANGEROUS do NOT touch!"
|
||||
icon = 'icons/obj/zippo_ch.dmi'
|
||||
icon_state = "ExpSMzippo"
|
||||
item_state = "ExpSMzippo"
|
||||
activation_sound = 'modular_chomp/sound/items/button-open.ogg'
|
||||
deactivation_sound = 'modular_chomp/sound/items/button-close.ogg'
|
||||
|
||||
// safe smzippo
|
||||
/obj/item/weapon/flame/lighter/safesmzippo/attack_self(mob/living/user)
|
||||
/obj/item/weapon/flame/lighter/supermatter/attack_self(mob/living/user)
|
||||
if(!base_state)
|
||||
base_state = icon_state
|
||||
if(!lit)
|
||||
@@ -32,7 +42,7 @@
|
||||
else
|
||||
if(prob(95))
|
||||
user.visible_message("<span class='notice'>After a few attempts, [user] manages to excite the supermatter within the [src].</span>")
|
||||
else
|
||||
else // Just like the cheap lighter, this time you can shock/burn yourself a little on the hardlight shield
|
||||
to_chat(user, "<span class='warning'>You hurt yourself on the shielding!</span>")
|
||||
if (user.get_left_hand() == src)
|
||||
user.apply_damage(1,SEARING,"l_hand")
|
||||
@@ -40,10 +50,10 @@
|
||||
user.apply_damage(3,CLONE,"l_hand")
|
||||
user.apply_damage(4,ELECTROMAG,"l_hand")
|
||||
else
|
||||
user.apply_damage(1,SEARING,"l_hand")
|
||||
user.apply_damage(1,SEARING,"r_hand")
|
||||
user.apply_damage(2,ELECTROCUTE,"r_hand")
|
||||
user.apply_damage(3,CLONE,"r_hand")
|
||||
user.apply_damage(4,ELECTROMAG,"l_hand")
|
||||
user.apply_damage(4,ELECTROMAG,"r_hand")
|
||||
user.visible_message("<span class='notice'>After a few attempts, [user] manages to activate the [src], they however sting themselves on the shielding!</span>")
|
||||
|
||||
set_light(2)
|
||||
@@ -53,7 +63,7 @@
|
||||
icon_state = "[base_state]"
|
||||
item_state = "[base_state]"
|
||||
playsound(src, deactivation_sound, 75, 1)
|
||||
if(istype(src, /obj/item/weapon/flame/lighter/safesmzippo) )
|
||||
if(istype(src, /obj/item/weapon/flame/lighter/supermatter) )
|
||||
user.visible_message("<span class='rose'>You hear a quiet click, as [user] shuts the [src] without even looking at what they're doing.</span>")
|
||||
else
|
||||
user.visible_message("<span class='notice'>[user] quietly shuts the [src].</span>")
|
||||
@@ -63,7 +73,7 @@
|
||||
return
|
||||
|
||||
|
||||
/obj/item/weapon/flame/lighter/safesmzippo/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
|
||||
/obj/item/weapon/flame/lighter/supermatter/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
|
||||
if(!istype(M, /mob))
|
||||
return
|
||||
|
||||
@@ -76,21 +86,21 @@
|
||||
if(M == user)
|
||||
cig.attackby(src, user)
|
||||
else
|
||||
if(istype(src, /obj/item/weapon/flame/lighter/zippo))
|
||||
if(istype(src, /obj/item/weapon/flame/lighter/supermatter))
|
||||
cig.light("<span class='rose'>[user] whips the [name] out and holds it for [M].</span>")
|
||||
else
|
||||
cig.light("<span class='notice'>[user] holds the [name] out for [M], and lights the [cig.name].</span>")
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/weapon/flame/lighter/safesmzippo/process()
|
||||
/obj/item/weapon/flame/lighter/supermatter/process()
|
||||
var/turf/location = get_turf(src)
|
||||
if(location)
|
||||
location.hotspot_expose(700, 5)
|
||||
return
|
||||
|
||||
// syndicate smzippo
|
||||
/obj/item/weapon/flame/lighter/syndismzippo/attack_self(mob/living/user)
|
||||
/obj/item/weapon/flame/lighter/supermatter/syndismzippo/attack_self(mob/living/user)
|
||||
if(!base_state)
|
||||
base_state = icon_state
|
||||
if(!lit)
|
||||
@@ -101,18 +111,18 @@
|
||||
if(prob(50))
|
||||
user.visible_message("<span class='rose'>[user] safely activates the [src] with a push of a button!</span>")
|
||||
else
|
||||
if(prob(99))
|
||||
if(prob(95))
|
||||
user.visible_message("<span class='notice'>After a few attempts, [user] manages to excite the supermatter within the [src].</span>")
|
||||
else
|
||||
else // Just like with the cheap lighter, but this time you can hurt yourself on the heated phoron field
|
||||
to_chat(user, "<span class='warning'>You singe yourself on the phoron shielding the excited supermatter!</span>")
|
||||
if (user.get_left_hand() == src)
|
||||
user.apply_damage(30,HALLOSS,"l_hand")
|
||||
user.apply_damage(20,CLONE,"l_hand")
|
||||
user.apply_effect(20,IRRADIATE)
|
||||
user.apply_damage(5,BURN,"l_hand")
|
||||
user.apply_damage(5,ELECTROCUTE,"l_hand")
|
||||
else
|
||||
user.apply_damage(30,HALLOSS,"r_hand")
|
||||
user.apply_damage(20,CLONE,"r_hand")
|
||||
user.apply_effect(20,IRRADIATE)
|
||||
user.apply_damage(5,BURN,"r_hand")
|
||||
user.apply_damage(5,ELECTROCUTE,"r_hand")
|
||||
user.visible_message("<span class='notice'>After a few attempts, [user] manages to activate the [src], they however burn themselves with the heated phoron field!</span>")
|
||||
@@ -124,7 +134,7 @@
|
||||
icon_state = "[base_state]"
|
||||
item_state = "[base_state]"
|
||||
playsound(src, deactivation_sound, 75, 1)
|
||||
if(istype(src, /obj/item/weapon/flame/lighter/syndismzippo) )
|
||||
if(istype(src, /obj/item/weapon/flame/lighter/supermatter/syndismzippo) )
|
||||
user.visible_message("<span class='rose'>You hear a quiet click, as [user] shuts the [src] without even looking at what they're doing.</span>")
|
||||
else
|
||||
user.visible_message("<span class='notice'>[user] quietly shuts the [src].</span>")
|
||||
@@ -134,7 +144,7 @@
|
||||
return
|
||||
|
||||
|
||||
/obj/item/weapon/flame/lighter/syndismzippo/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
|
||||
/obj/item/weapon/flame/lighter/supermatter/syndismzippo/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
|
||||
if(!istype(M, /mob))
|
||||
return
|
||||
|
||||
@@ -147,7 +157,7 @@
|
||||
if(M == user)
|
||||
cig.attackby(src, user)
|
||||
else
|
||||
if(istype(src, /obj/item/weapon/flame/lighter/syndismzippo))
|
||||
if(istype(src, /obj/item/weapon/flame/lighter/supermatter/syndismzippo))
|
||||
cig.light("<span class='rose'>[user] whips the [name] out and holds it for [M].</span>")
|
||||
else
|
||||
cig.light("<span class='notice'>[user] holds the [name] out for [M], and lights the [cig.name].</span>")
|
||||
@@ -159,3 +169,169 @@
|
||||
if(location)
|
||||
location.hotspot_expose(700, 5)
|
||||
return
|
||||
|
||||
// Experimental smzippo
|
||||
/obj/item/weapon/flame/lighter/supermatter/expsmzippo/attack_self(mob/living/user)
|
||||
if (!base_state)
|
||||
base_state = icon_state
|
||||
if (!lit)
|
||||
lit = 1
|
||||
icon_state = "[base_state]on"
|
||||
item_state = "[base_state]on"
|
||||
playsound(src, activation_sound, 75, 1)
|
||||
var/i = rand(1, 100)
|
||||
switch(i)
|
||||
if(1 to 22)
|
||||
to_chat("<span class='rose'>[user] safely reveals the supermatter shard within the [src]!</span>")
|
||||
user.visible_message("<span class='rose'>You safely revealed the supermatter shard within the [src]!</span>")
|
||||
if (user.get_left_hand() == src)
|
||||
user.apply_damage(1, IRRADIATE, "l_hand")
|
||||
else // Even using this safely will irradiate you a tiny tiny bit.
|
||||
user.apply_damage(1, IRRADIATE, "r_hand")
|
||||
if(23 to 33)
|
||||
to_chat(user, "<span class='warning'>[user]'s hand slipped and they brush against the supermatter within [src]!</span>")
|
||||
user.visible_message("<span class='notice'>You accidentally grazed your hand across the supermatter!</span>")
|
||||
if (user.get_left_hand() == src)
|
||||
user.apply_damage(10, IRRADIATE, "l_hand")
|
||||
user.apply_damage(20, BURN, "l_hand")
|
||||
user.apply_damage(20, ELECTROCUTE, "l_hand")
|
||||
user.apply_damage(50, AGONY, "l_hand")
|
||||
else // One of the outcomes will burn and shock you, the pain is the worst part of this one though.
|
||||
user.apply_damage(10, IRRADIATE, "r_hand")
|
||||
user.apply_damage(20, BURN, "r_hand")
|
||||
user.apply_damage(20, ELECTROCUTE, "r_hand")
|
||||
user.apply_damage(50, AGONY, "r_hand")
|
||||
if(34 to 44)
|
||||
to_chat(user, "<span class='warning'>[user] burned themselves on the [src]!</span>")
|
||||
user.visible_message("<span class='notice'>You accidentally burn yourself on the [src]!</span>")
|
||||
if (user.get_left_hand() == src)
|
||||
user.apply_damage(30, IRRADIATE, "l_hand")
|
||||
user.apply_damage(20, SEARING, "l_hand")
|
||||
user.apply_damage(15, BURN, "l_hand")
|
||||
else // One of the outcomes is pure burn and radiation.
|
||||
user.apply_damage(30, IRRADIATE, "r_hand")
|
||||
user.apply_damage(20, SEARING, "r_hand")
|
||||
user.apply_damage(15, BURN, "r_hand")
|
||||
if(45 to 55)
|
||||
to_chat(user, "<span class='warning'>[user] fumbled the [src] and the supermatter let out sparks!</span>")
|
||||
user.visible_message("<span class='notice'>You fumble the [src], letting the supermatter spark as the case opens!</span>")
|
||||
if (user.get_left_hand() == src)
|
||||
user.apply_damage(1, ELECTROCUTE, "l_hand")
|
||||
user.apply_damage(100, ELECTROMAG, "l_hand")
|
||||
else // This one is mostly dangerous to synthetics and it will EMP you. But otherwise it's safe.
|
||||
user.apply_damage(1, ELECTROCUTE, "r_hand")
|
||||
user.apply_damage(100, ELECTROMAG, "r_hand")
|
||||
if(56 to 66)
|
||||
to_chat(user, "<span class='warning'>[user] struggles to open their [src], but when they do they get burned by the extreme heat within!</span>")
|
||||
user.visible_message("<span class='notice'>You struggle to get the case to open, and when it does the heat that pours out of the [src] burns!</span>")
|
||||
if (user.get_left_hand() == src)
|
||||
user.apply_damage(1, IRRADIATE, "l_hand")
|
||||
user.apply_damage(1, BRUISE, "l_hand")
|
||||
user.apply_damage(200, BURN, "l_hand")
|
||||
user.drop_l_hand()
|
||||
else // This will INSTA-DUST your hand that you're holding the item in, and then make you drop the lighter.
|
||||
user.apply_damage(1, IRRADIATE, "r_hand")
|
||||
user.apply_damage(1, BRUISE, "r_hand")
|
||||
user.apply_damage(200, BURN, "r_hand")
|
||||
user.drop_r_hand()
|
||||
if(67 to 77)
|
||||
to_chat(user, "<span class='warning'>Ouch! While pushing on the release to open the [src], [user]'s finger slipped right as the case opened, pressing their finger firm against the supermatter!</span>")
|
||||
user.visible_message("<span class='notice'>You accidentally pushed your finger against the supermatter!</span>")
|
||||
if (user.get_left_hand() == src)
|
||||
user.apply_damage(50, HALLOSS, "l_hand")
|
||||
user.apply_damage(40, IRRADIATE, "l_hand")
|
||||
user.apply_damage(30, BURN, "l_hand")
|
||||
user.apply_damage(20, TOX, "l_hand")
|
||||
user.apply_damage(10, ELECTROCUTE, "l_hand")
|
||||
user.apply_effect(25, STUTTER)
|
||||
user.apply_effect(15, SLUR)
|
||||
user.apply_effect(5, STUN)
|
||||
else // This one is VERY punishing, you get a ton of damage, a lot of pain, and a minor stun. Once the stun goes away you'll be stuttering for awhile as if in crit.
|
||||
user.apply_damage(50, HALLOSS, "r_hand")
|
||||
user.apply_damage(40, IRRADIATE, "r_hand")
|
||||
user.apply_damage(30, BURN, "r_hand")
|
||||
user.apply_damage(20, TOX, "r_hand")
|
||||
user.apply_damage(10, ELECTROCUTE, "r_hand")
|
||||
user.apply_effect(25, STUTTER)
|
||||
user.apply_effect(15, SLUR)
|
||||
user.apply_effect(5, STUN)
|
||||
if(78 to 88)
|
||||
to_chat(user, "<span class='notice'>[user] managed to pinch themselves on the case of their [src]... it could have been worse.</span>")
|
||||
user.visible_message("<span class='notice'>You manage to pinch yourself on the case!</span>")
|
||||
if (user.get_left_hand() == src)
|
||||
user.apply_damage(1, CLONE, "l_hand")
|
||||
user.apply_damage(1, HALLOSS, "l_hand")
|
||||
else // Aside from the base, this one isn't punishing outside of giving you genetic damage.
|
||||
user.apply_damage(1, CLONE, "r_hand")
|
||||
user.apply_damage(1, HALLOSS, "r_hand")
|
||||
if(89 to 99)
|
||||
to_chat(user, "<span class='notice'>[user] opened the [src] but forgot that you aren't supposed to look at supermatter!</span>")
|
||||
user.visible_message("<span class='notice'>You find yourself looking at the supermatter for longer than you should...</span>")
|
||||
if (user.get_left_hand() == src)
|
||||
user.apply_damage(15, HALLOSS, "l_hand")
|
||||
user.apply_effect(5, WEAKEN)
|
||||
user.apply_damage(15, IRRADIATE, "l_hand")
|
||||
user.apply_effect(100, EYE_BLUR)
|
||||
user.apply_effect(50, AGONY)
|
||||
user.apply_damage(5, OXY)
|
||||
user.eye_blurry = 10
|
||||
else // This one just blinds and blurs your screen, but otherwise doesn't actually risk harming you. Even the oxy damage heals on its own.
|
||||
user.apply_damage(15, HALLOSS, "r_hand")
|
||||
user.apply_effect(5, WEAKEN)
|
||||
user.apply_damage(15, IRRADIATE, "l_hand")
|
||||
user.apply_effect(100, EYE_BLUR)
|
||||
user.apply_effect(50, AGONY)
|
||||
user.apply_damage(15, OXY)
|
||||
user.eye_blurry = 10
|
||||
if(100) // This is the part that makes it admin only for the moment, it spawns 500 rads from the carbon's position, and dusts the carbon instantly. It does also drop everything unlike the supermatter crystal though, so hopefully you won't lose any items if you fumble this badly!
|
||||
to_chat(user, "<span class='warning'>OH NO! [user] almost dropped their live [src]! Thank goodness they caught it... by the glowing yellow crystal... oh.</span>")
|
||||
user.visible_message("<span class='danger'>You almost dropped your [src], thank goodness you caught it! By the glowing crystal within. You find your ears filled with unearthly ringing and your last thought is \"Oh, fuck.\"</span>")
|
||||
user.drop_r_hand() // To ensure the lighter is dropped <3
|
||||
user.drop_l_hand() // To ensure the lighter is dropped <3
|
||||
for(var/obj/item/e in user)
|
||||
user.drop_from_inventory(e)
|
||||
log_and_message_admins("[user] dusted themselves and caused massive radiation with [src]!",user)
|
||||
user.dust()
|
||||
var/rads = 500
|
||||
SSradiation.radiate(src, rads)
|
||||
|
||||
set_light(5)
|
||||
START_PROCESSING(SSobj, src)
|
||||
else
|
||||
lit = 0
|
||||
icon_state = "[base_state]"
|
||||
item_state = "[base_state]"
|
||||
playsound(src, deactivation_sound, 75, 1)
|
||||
if (istype(src, /obj/item/weapon/flame/lighter/supermatter/expsmzippo))
|
||||
user.visible_message("<span class='rose'>You hear a quiet click, as [user] closes the [src].</span>")
|
||||
else
|
||||
user.visible_message("<span class='notice'>[user] quietly shuts the [src].</span>")
|
||||
|
||||
set_light(0)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/weapon/flame/lighter/supermatter/expsmzippo/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
|
||||
if (!istype(M, /mob))
|
||||
return
|
||||
|
||||
if (lit == 1)
|
||||
M.IgniteMob()
|
||||
add_attack_logs(user, M, "Lit on fire with [src]")
|
||||
|
||||
if (istype(M.wear_mask, /obj/item/clothing/mask/smokable/cigarette) && user.zone_sel.selecting == O_MOUTH && lit)
|
||||
var/obj/item/clothing/mask/smokable/cigarette/cig = M.wear_mask
|
||||
if (M == user)
|
||||
cig.attackby(src, user)
|
||||
else
|
||||
if (istype(src, /obj/item/weapon/flame/lighter/supermatter/expsmzippo))
|
||||
cig.light("<span class='rose'>[user] whips the [name] out and holds it for [M].</span>")
|
||||
else
|
||||
cig.light("<span class='notice'>[user] holds the [name] out for [M], and lights the [cig.name].</span>")
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/weapon/flame/lighter/supermatter/expsmzippo/process()
|
||||
var/turf/location = get_turf(src)
|
||||
if (location)
|
||||
location.hotspot_expose(700, 5)
|
||||
return
|
||||
|
||||
@@ -0,0 +1,339 @@
|
||||
/obj/structure/closet/secure_closet/captains
|
||||
name = "site manager's locker"
|
||||
req_access = list(access_captain)
|
||||
closet_appearance = /decl/closet_appearance/secure_closet/command
|
||||
|
||||
starts_with = list(
|
||||
/obj/item/weapon/storage/backpack/dufflebag/captain,
|
||||
/obj/item/clothing/head/helmet,
|
||||
/obj/item/clothing/suit/storage/vest,
|
||||
/obj/item/weapon/cartridge/captain,
|
||||
/obj/item/weapon/storage/lockbox/medal,
|
||||
/obj/item/device/radio/headset/heads/captain,
|
||||
/obj/item/device/radio/headset/heads/captain/alt,
|
||||
/obj/item/weapon/gun/energy/gun,
|
||||
/obj/item/weapon/melee/telebaton,
|
||||
/obj/item/device/flash,
|
||||
/obj/item/weapon/storage/box/ids)
|
||||
|
||||
|
||||
/obj/structure/closet/secure_closet/hop
|
||||
name = "head of personnel's locker"
|
||||
req_access = list(access_hop)
|
||||
closet_appearance = /decl/closet_appearance/secure_closet/command/hop
|
||||
|
||||
starts_with = list(
|
||||
/obj/item/clothing/suit/storage/vest,
|
||||
/obj/item/clothing/head/helmet,
|
||||
/obj/item/weapon/cartridge/hop,
|
||||
/obj/item/device/radio/headset/heads/hop,
|
||||
/obj/item/device/radio/headset/heads/hop/alt,
|
||||
/obj/item/weapon/storage/box/ids = 2,
|
||||
/obj/item/weapon/gun/energy/gun/compact,
|
||||
/obj/item/weapon/storage/box/commandkeys,
|
||||
/obj/item/weapon/storage/box/servicekeys,
|
||||
/obj/item/device/flash)
|
||||
|
||||
/obj/structure/closet/secure_closet/hop2
|
||||
name = "head of personnel's attire"
|
||||
req_access = list(access_hop)
|
||||
closet_appearance = /decl/closet_appearance/secure_closet/command/hop
|
||||
|
||||
starts_with = list(
|
||||
/obj/item/clothing/under/rank/head_of_personnel,
|
||||
/obj/item/clothing/under/dress/dress_hop,
|
||||
/obj/item/clothing/under/dress/dress_hr,
|
||||
/obj/item/clothing/under/lawyer/female,
|
||||
/obj/item/clothing/under/lawyer/black,
|
||||
/obj/item/clothing/under/lawyer/black/skirt,
|
||||
/obj/item/clothing/under/lawyer/red,
|
||||
/obj/item/clothing/under/lawyer/red/skirt,
|
||||
/obj/item/clothing/under/lawyer/oldman,
|
||||
/obj/item/clothing/under/rank/neo_hop,
|
||||
/obj/item/clothing/under/rank/neo_hop_skirt,
|
||||
/obj/item/clothing/under/rank/neo_hop_parade_masc,
|
||||
/obj/item/clothing/under/rank/neo_hop_parade_fem,
|
||||
/obj/item/clothing/under/rank/neo_hop_turtle,
|
||||
/obj/item/clothing/under/rank/neo_hop_turtle_skirt,
|
||||
/obj/item/clothing/under/rank/neo_cmd_gorka,
|
||||
/obj/item/clothing/suit/storage/toggle/labcoat/neo_hopformal,
|
||||
/obj/item/clothing/suit/storage/toggle/labcoat/neo_civ_dep,
|
||||
/obj/item/clothing/shoes/brown,
|
||||
/obj/item/clothing/shoes/black,
|
||||
/obj/item/clothing/shoes/laceup,
|
||||
/obj/item/clothing/shoes/laceup/brown,
|
||||
/obj/item/clothing/shoes/white,
|
||||
/obj/item/clothing/under/rank/head_of_personnel_whimsy,
|
||||
/obj/item/clothing/head/caphat/hop,
|
||||
/obj/item/clothing/under/suit_jacket/teal,
|
||||
/obj/item/clothing/under/suit_jacket/teal/skirt,
|
||||
/obj/item/clothing/glasses/sunglasses,
|
||||
/obj/item/clothing/suit/storage/hooded/wintercoat/hop,
|
||||
/obj/item/clothing/head/caphat/hop/beret,
|
||||
/obj/item/clothing/head/caphat/hop/beret/white)
|
||||
|
||||
|
||||
/obj/structure/closet/secure_closet/hos
|
||||
name = "head of security's locker"
|
||||
req_access = list(access_hos)
|
||||
storage_capacity = 2.5 * MOB_MEDIUM
|
||||
closet_appearance = /decl/closet_appearance/secure_closet/security/hos
|
||||
|
||||
starts_with = list(
|
||||
/obj/item/clothing/head/helmet/HoS,
|
||||
/obj/item/clothing/head/helmet/HoS/hat,
|
||||
/obj/item/clothing/suit/storage/vest/hos,
|
||||
/obj/item/clothing/under/rank/head_of_security/jensen,
|
||||
/obj/item/clothing/under/rank/head_of_security/corp,
|
||||
/obj/item/clothing/suit/storage/vest/hoscoat/jensen,
|
||||
/obj/item/clothing/suit/storage/vest/hoscoat,
|
||||
/obj/item/clothing/head/helmet/dermal,
|
||||
/obj/item/weapon/cartridge/hos,
|
||||
/obj/item/device/radio/headset/heads/hos,
|
||||
/obj/item/device/radio/headset/heads/hos/alt,
|
||||
/obj/item/clothing/glasses/sunglasses/sechud,
|
||||
/obj/item/taperoll/police,
|
||||
/obj/item/weapon/shield/riot,
|
||||
/obj/item/weapon/shield/riot/tele,
|
||||
/obj/item/weapon/storage/box/holobadge/hos,
|
||||
/obj/item/clothing/accessory/badge/holo/hos,
|
||||
/obj/item/weapon/reagent_containers/spray/pepper,
|
||||
/obj/item/weapon/tool/crowbar/red,
|
||||
/obj/item/weapon/storage/box/flashbangs,
|
||||
/obj/item/weapon/storage/belt/security,
|
||||
/obj/item/device/flash,
|
||||
/obj/item/weapon/melee/baton/loaded,
|
||||
/obj/item/weapon/gun/magnetic/railgun/heater/pistol/hos,
|
||||
/obj/item/weapon/rcd_ammo/large,
|
||||
/obj/item/weapon/cell/device/weapon,
|
||||
/obj/item/clothing/accessory/holster/waist,
|
||||
/obj/item/weapon/melee/telebaton,
|
||||
/obj/item/clothing/head/beret/sec/corporate/hos,
|
||||
/obj/item/clothing/suit/storage/hooded/wintercoat/security,
|
||||
/obj/item/clothing/suit/storage/hooded/wintercoat/security/hos,
|
||||
/obj/item/clothing/shoes/boots/winter/security,
|
||||
/obj/item/device/flashlight/maglight,
|
||||
/obj/item/clothing/mask/gas/half,
|
||||
/obj/item/clothing/mask/gas/sechailer/swat/hos)
|
||||
|
||||
/obj/structure/closet/secure_closet/hos/Initialize()
|
||||
if(prob(50))
|
||||
starts_with += /obj/item/weapon/storage/backpack/security
|
||||
else
|
||||
starts_with += /obj/item/weapon/storage/backpack/satchel/sec
|
||||
if(prob(50))
|
||||
starts_with += /obj/item/weapon/storage/backpack/dufflebag/sec
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/structure/closet/secure_closet/warden
|
||||
name = "warden's locker"
|
||||
storage_capacity = 42
|
||||
req_access = list(access_armory)
|
||||
closet_appearance = /decl/closet_appearance/secure_closet/security/warden
|
||||
|
||||
starts_with = list(
|
||||
/obj/item/clothing/suit/storage/vest/warden,
|
||||
/obj/item/clothing/under/rank/warden,
|
||||
/obj/item/clothing/under/rank/warden/corp,
|
||||
/obj/item/clothing/suit/storage/vest/wardencoat,
|
||||
/obj/item/clothing/suit/storage/vest/wardencoat/alt,
|
||||
/obj/item/clothing/suit/storage/vest/wardencoat/alt2, //VOREStation Add,
|
||||
/obj/item/clothing/head/helmet/dermal,
|
||||
/obj/item/clothing/head/helmet/warden,
|
||||
/obj/item/clothing/head/helmet/warden/hat,
|
||||
/obj/item/clothing/under/rank/neo_warden_red,
|
||||
/obj/item/clothing/under/rank/neo_warden_red_skirt,
|
||||
/obj/item/clothing/under/rank/neo_warden_blue,
|
||||
/obj/item/clothing/suit/storage/vest/wardencoat/neo_armsco_trench,
|
||||
/obj/item/clothing/suit/storage/vest/wardencoat/neo_bluewarden,
|
||||
/obj/item/clothing/suit/storage/vest/wardencoat/neo_warden_heavy,
|
||||
/obj/item/clothing/under/rank/neo_sec_gorka,
|
||||
/obj/item/weapon/cartridge/security,
|
||||
/obj/item/device/radio/headset/headset_sec,
|
||||
/obj/item/device/radio/headset/headset_sec/alt,
|
||||
/obj/item/clothing/glasses/sunglasses/sechud,
|
||||
/obj/item/taperoll/police,
|
||||
/obj/item/clothing/accessory/badge/holo/warden,
|
||||
/obj/item/weapon/storage/box/flashbangs,
|
||||
/obj/item/weapon/storage/belt/security,
|
||||
/obj/item/weapon/reagent_containers/spray/pepper,
|
||||
/obj/item/weapon/melee/baton/loaded,
|
||||
/obj/item/weapon/gun/energy/gun,
|
||||
/obj/item/weapon/cell/device/weapon,
|
||||
/obj/item/weapon/storage/box/holobadge,
|
||||
/obj/item/clothing/head/beret/sec/corporate/warden,
|
||||
/obj/item/clothing/suit/storage/hooded/wintercoat/security,
|
||||
/obj/item/clothing/shoes/boots/winter/security,
|
||||
/obj/item/device/flashlight/maglight,
|
||||
/obj/item/device/megaphone,
|
||||
/obj/item/clothing/mask/gas/sechailer/swat/warden,
|
||||
/obj/item/weapon/gun/projectile/revolvershotgun,
|
||||
/obj/item/ammo_magazine/m12gdrumjack/beanbag,
|
||||
/obj/item/ammo_magazine/m12gdrumjack/beanbag,
|
||||
/obj/item/device/ticket_printer, //CHOMPStation addition
|
||||
/obj/item/device/retail_scanner/security //CHOMPStation addition
|
||||
)
|
||||
|
||||
/obj/structure/closet/secure_closet/warden/Initialize()
|
||||
if(prob(50))
|
||||
starts_with += /obj/item/weapon/storage/backpack/security
|
||||
else
|
||||
starts_with += /obj/item/weapon/storage/backpack/satchel/sec
|
||||
if(prob(50))
|
||||
starts_with += /obj/item/weapon/storage/backpack/dufflebag/sec
|
||||
return ..()
|
||||
|
||||
/obj/structure/closet/secure_closet/security
|
||||
name = "security officer's locker"
|
||||
req_access = list(access_brig)
|
||||
closet_appearance = /decl/closet_appearance/secure_closet/security
|
||||
|
||||
starts_with = list(
|
||||
/obj/item/clothing/suit/storage/vest/officer,
|
||||
/obj/item/clothing/head/helmet,
|
||||
/obj/item/clothing/mask/gas/sechailer/swat/officer,
|
||||
/obj/item/weapon/cartridge/security,
|
||||
/obj/item/device/radio/headset/headset_sec,
|
||||
/obj/item/device/radio/headset/headset_sec/alt,
|
||||
/obj/item/weapon/storage/belt/security,
|
||||
/obj/item/device/flash,
|
||||
/obj/item/weapon/reagent_containers/spray/pepper,
|
||||
/obj/item/weapon/grenade/flashbang,
|
||||
/obj/item/weapon/melee/baton/loaded,
|
||||
/obj/item/clothing/glasses/sunglasses/sechud,
|
||||
/obj/item/taperoll/police,
|
||||
/obj/item/device/hailer,
|
||||
/obj/item/device/flashlight/flare,
|
||||
/obj/item/clothing/accessory/storage/black_vest,
|
||||
/obj/item/clothing/head/soft/sec/corp,
|
||||
/obj/item/clothing/under/rank/security/corp,
|
||||
/obj/item/ammo_magazine/m45/rubber,
|
||||
/obj/item/weapon/gun/energy/taser,
|
||||
/obj/item/weapon/cell/device/weapon,
|
||||
/obj/item/clothing/suit/storage/hooded/wintercoat/security,
|
||||
/obj/item/clothing/shoes/boots/winter/security,
|
||||
/obj/item/device/flashlight/maglight,
|
||||
/obj/item/device/holowarrant, //CHOMPStation addition
|
||||
/obj/item/device/retail_scanner/security, //CHOMPStation addition
|
||||
/obj/item/clothing/glasses/hud/security, //CHOMPStation addition
|
||||
/obj/item/device/ticket_printer //CHOMPStation addition
|
||||
)
|
||||
|
||||
/obj/structure/closet/secure_closet/security/Initialize()
|
||||
if(prob(50))
|
||||
starts_with += /obj/item/weapon/storage/backpack/security
|
||||
else
|
||||
starts_with += /obj/item/weapon/storage/backpack/satchel/sec
|
||||
if(prob(50))
|
||||
starts_with += /obj/item/weapon/storage/backpack/dufflebag/sec
|
||||
if(prob(30))
|
||||
starts_with += /obj/item/poster/nanotrasen
|
||||
return ..()
|
||||
|
||||
/obj/structure/closet/secure_closet/security/cargo/Initialize()
|
||||
starts_with += /obj/item/clothing/accessory/armband/cargo
|
||||
starts_with += /obj/item/device/encryptionkey/headset_cargo
|
||||
return ..()
|
||||
|
||||
/obj/structure/closet/secure_closet/security/engine/Initialize()
|
||||
starts_with += /obj/item/clothing/accessory/armband/engine
|
||||
starts_with += /obj/item/device/encryptionkey/headset_eng
|
||||
return ..()
|
||||
|
||||
/obj/structure/closet/secure_closet/security/science/Initialize()
|
||||
starts_with += /obj/item/clothing/accessory/armband/science
|
||||
starts_with += /obj/item/device/encryptionkey/headset_sci
|
||||
return ..()
|
||||
|
||||
/obj/structure/closet/secure_closet/security/med/Initialize()
|
||||
starts_with += /obj/item/clothing/accessory/armband/medblue
|
||||
starts_with += /obj/item/device/encryptionkey/headset_med
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/structure/closet/secure_closet/detective
|
||||
name = "detective's cabinet"
|
||||
req_access = list(access_forensics_lockers)
|
||||
closet_appearance = /decl/closet_appearance/cabinet/secure
|
||||
|
||||
open_sound = 'sound/effects/wooden_closet_open.ogg'
|
||||
close_sound = 'sound/effects/wooden_closet_close.ogg'
|
||||
|
||||
starts_with = list(
|
||||
/obj/item/clothing/accessory/badge/holo/detective,
|
||||
/obj/item/clothing/gloves/forensic, //CHOMP Edit replaces black gloves
|
||||
/obj/item/gunbox, //CHOMP Edit undoes vorestation removal and adds back gunbox
|
||||
/obj/item/gunbox/stun,
|
||||
/obj/item/weapon/storage/belt/detective,
|
||||
/obj/item/weapon/storage/box/evidence,
|
||||
/obj/item/device/radio/headset/headset_sec,
|
||||
/obj/item/device/radio/headset/headset_sec/alt,
|
||||
/obj/item/clothing/suit/storage/vest/detective,
|
||||
/obj/item/taperoll/police,
|
||||
/obj/item/clothing/accessory/holster/armpit,
|
||||
/obj/item/device/flashlight/maglight,
|
||||
/obj/item/weapon/reagent_containers/food/drinks/flask/detflask,
|
||||
/obj/item/weapon/storage/briefcase/crimekit,
|
||||
/obj/item/device/taperecorder,
|
||||
/obj/item/weapon/storage/bag/detective,
|
||||
/obj/item/device/tape/random = 3,
|
||||
/obj/item/device/retail_scanner/security, //CHOMPStation addition
|
||||
/obj/item/clothing/glasses/hud/security //CHOMPStation addition
|
||||
)
|
||||
|
||||
/obj/structure/closet/secure_closet/injection
|
||||
name = "lethal injections locker"
|
||||
req_access = list(access_captain)
|
||||
closet_appearance = /decl/closet_appearance/secure_closet/courtroom
|
||||
|
||||
starts_with = list(
|
||||
/obj/item/weapon/reagent_containers/syringe/ld50_syringe/choral = 2)
|
||||
|
||||
GLOBAL_LIST_BOILERPLATE(all_brig_closets, /obj/structure/closet/secure_closet/brig)
|
||||
|
||||
/obj/structure/closet/secure_closet/brig
|
||||
name = "brig locker"
|
||||
req_access = list(access_brig)
|
||||
closet_appearance = /decl/closet_appearance/secure_closet/brig
|
||||
anchored = TRUE
|
||||
var/id = null
|
||||
|
||||
starts_with = list(
|
||||
/obj/item/clothing/under/color/prison,
|
||||
/obj/item/clothing/shoes/orange)
|
||||
|
||||
/obj/structure/closet/secure_closet/posters
|
||||
name = "morale storage"
|
||||
req_access = list(access_security)
|
||||
anchored = TRUE
|
||||
|
||||
starts_with = list(
|
||||
/obj/item/poster/nanotrasen,
|
||||
/obj/item/poster/nanotrasen,
|
||||
/obj/item/poster/nanotrasen,
|
||||
/obj/item/poster/nanotrasen,
|
||||
/obj/item/poster/nanotrasen)
|
||||
|
||||
/obj/structure/closet/secure_closet/courtroom
|
||||
name = "courtroom locker"
|
||||
req_access = list(access_lawyer)
|
||||
closet_appearance = /decl/closet_appearance/secure_closet/courtroom
|
||||
|
||||
starts_with = list(
|
||||
/obj/item/clothing/shoes/brown,
|
||||
/obj/item/weapon/paper/Court = 3,
|
||||
/obj/item/weapon/pen,
|
||||
/obj/item/clothing/suit/judgerobe,
|
||||
/obj/item/clothing/head/powdered_wig,
|
||||
/obj/item/weapon/storage/briefcase)
|
||||
|
||||
|
||||
/obj/structure/closet/secure_closet/wall
|
||||
name = "wall locker"
|
||||
req_access = list(access_security)
|
||||
closet_appearance = /decl/closet_appearance/wall
|
||||
density = TRUE
|
||||
|
||||
//too small to put a man in
|
||||
large = 0
|
||||
@@ -101,10 +101,26 @@
|
||||
|
||||
switch(pred.a_intent)
|
||||
if(I_HELP)
|
||||
if(pred.m_intent == "run")
|
||||
message_prey = "[pred] moves, pressing down on you within their [name] with each step."
|
||||
else
|
||||
message_prey = "As [pred] walks, their foot presses you tightly against the sole of their [name]!"
|
||||
if(prob(40)) //Reducing spam exclusively on I_HELP. Still more frequent than old pitiful prob(1)
|
||||
if(pred.m_intent == "run")
|
||||
message_prey = pick(
|
||||
"You feel weightless for a brief moment as \the [name] move upwards.",
|
||||
"[pred]'s weight bears down on you with each of their steps.",
|
||||
"\The [name] are a ride you've got no choice but to participate in as the wearer moves.",
|
||||
"The wearer of \the [name] moves, and their feet press down on you with each step.",
|
||||
"With each step, you're sandwiched again between [pred]'s feet and the insole of their boots.",
|
||||
"As [pred] moves, their foot presses you tightly against the insole of their boots with each step.")
|
||||
else
|
||||
message_prey = pick(
|
||||
"You feel weightless for a brief moment as \the [name] move upwards.",
|
||||
"[pred]'s weight bears down on you with each of the calm steps of their walk.",
|
||||
"\The [name] are a ride you've got no choice but to participate in as the wearer walks.",
|
||||
"The wearer of \the [name] walks, and their feet press down on you heavily with each step.",
|
||||
"With each step of their unhurried walk, you're tightly sandwiched between [pred]'s feet and the insole of their boots.",
|
||||
"As [pred] walks, their foot presses you tightly against the insole of their boots with each step.")
|
||||
to_chat(prey, span_emote_subtle("<I>[message_prey]</I>"))
|
||||
|
||||
return //No message for pred if I_HELP
|
||||
|
||||
if(I_DISARM)
|
||||
if(pred.m_intent == "run")
|
||||
@@ -151,7 +167,7 @@
|
||||
I.take_damage(damage, 0)
|
||||
|
||||
if(message_pred != null)
|
||||
to_chat(pred, "<span class='warning'>[message_pred]</span>")
|
||||
to_chat(prey, "<span class='warning'>[message_prey]</span>")
|
||||
to_chat(pred, span_warning(message_pred))
|
||||
to_chat(prey, span_warning(message_prey))
|
||||
|
||||
return
|
||||
|
||||
169
modular_chomp/code/modules/clothing/masks/hailer.dm
Normal file
169
modular_chomp/code/modules/clothing/masks/hailer.dm
Normal file
@@ -0,0 +1,169 @@
|
||||
/obj/item/clothing/mask/gas/sechailer
|
||||
name = "hailer face mask"
|
||||
desc = "A compact, durable gas mask that can be connected to an air supply. This one possesses a security hailer."
|
||||
description_info = "This mask has a hailer attached, you can activate it on the button or use the Halt! verb, for switching phrases you can alt+click it or change it using the change phrase verb."
|
||||
icon_state = "halfgas"
|
||||
armor = list(melee = 10, bullet = 10, laser = 10, energy = 0, bomb = 0, bio = 55, rad = 0)
|
||||
action_button_name = "HALT!"
|
||||
body_parts_covered = FACE
|
||||
var/obj/item/device/hailer/hailer
|
||||
var/cooldown = 0
|
||||
var/phrase = 1
|
||||
var/aggressiveness = 1
|
||||
var/safety = 1
|
||||
var/list/phrase_list = list(
|
||||
"halt" = "HALT! HALT! HALT! HALT!",
|
||||
"bobby" = "Stop in the name of the Law.",
|
||||
"compliance" = "Compliance is in your best interest.",
|
||||
"justice" = "Prepare for justice!",
|
||||
"running" = "Running will only increase your sentence.",
|
||||
"dontmove" = "Don't move, Creep!",
|
||||
"floor" = "Down on the floor, Creep!",
|
||||
"robocop" = "Dead or alive you're coming with me.",
|
||||
"god" = "God made today for the crooks we could not catch yesterday.",
|
||||
"freeze" = "Freeze, Scum Bag!",
|
||||
"imperial" = "Stop right there, criminal scum!",
|
||||
"bash" = "Stop or I'll bash you.",
|
||||
"harry" = "Go ahead, make my day.",
|
||||
"asshole" = "Stop breaking the law, asshole.",
|
||||
"stfu" = "You have the right to shut the fuck up",
|
||||
"shutup" = "Shut up crime!",
|
||||
"super" = "Face the wrath of the golden bolt.",
|
||||
"dredd" = "I am, the LAW!"
|
||||
)
|
||||
|
||||
/obj/item/clothing/mask/gas/sechailer/swat/hos
|
||||
name = "\improper HOS SWAT mask"
|
||||
desc = "A close-fitting tactical mask with an especially aggressive Compli-o-nator 3000. It has a tan stripe."
|
||||
icon_state = "hosmask"
|
||||
|
||||
|
||||
/obj/item/clothing/mask/gas/sechailer/swat/warden
|
||||
name = "\improper Warden SWAT mask"
|
||||
desc = "A close-fitting tactical mask with an especially aggressive Compli-o-nator 3000. It has a blue stripe."
|
||||
icon_state = "wardenmask"
|
||||
|
||||
/obj/item/clothing/mask/gas/sechailer/swat/officer //Just a little nicer to begin with. Can always up the anger with a screwdriver!
|
||||
aggressiveness = 1
|
||||
phrase = 1
|
||||
|
||||
/obj/item/clothing/mask/gas/sechailer/swat
|
||||
name = "\improper SWAT mask"
|
||||
desc = "A close-fitting tactical mask with an especially aggressive Compli-o-nator 3000."
|
||||
icon_state = "officermask"
|
||||
body_parts_covered = HEAD|FACE|EYES
|
||||
flags_inv = HIDEFACE|BLOCKHAIR
|
||||
aggressiveness = 3
|
||||
phrase = 12
|
||||
|
||||
|
||||
/obj/item/clothing/mask/gas/sechailer/ui_action_click()
|
||||
halt()
|
||||
|
||||
/obj/item/clothing/mask/gas/sechailer/AltClick(mob/user)
|
||||
selectphrase()
|
||||
|
||||
/obj/item/clothing/mask/gas/sechailer/verb/selectphrase()
|
||||
set name = "Select gas mask phrase"
|
||||
set category = "Object"
|
||||
set desc = "Alter the message shouted by your complionator gas mask."
|
||||
|
||||
var/key = phrase_list[phrase]
|
||||
var/message = phrase_list[key]
|
||||
|
||||
if (!safety)
|
||||
to_chat(usr, "<span class='notice'>You set the restrictor to: FUCK YOUR CUNT YOU SHIT EATING COCKSUCKER MAN EAT A DONG FUCKING ASS RAMMING SHIT FUCK EAT PENISES IN YOUR FUCK FACE AND SHIT OUT ABORTIONS OF FUCK AND DO SHIT IN YOUR ASS YOU COCK FUCK SHIT MONKEY FUCK ASS WANKER FROM THE DEPTHS OF SHIT.</span>")
|
||||
return
|
||||
switch(aggressiveness)
|
||||
if(1)
|
||||
phrase = (phrase < 6) ? (phrase + 1) : 1
|
||||
key = phrase_list[phrase]
|
||||
message = phrase_list[key]
|
||||
to_chat(usr,"<span class='notice'>You set the restrictor to: [message]</span>")
|
||||
if(2)
|
||||
phrase = (phrase < 11 && phrase >= 7) ? (phrase + 1) : 7
|
||||
key = phrase_list[phrase]
|
||||
message = phrase_list[key]
|
||||
to_chat(usr,"<span class='notice'>You set the restrictor to: [message]</span>")
|
||||
if(3)
|
||||
phrase = (phrase < 18 && phrase >= 12 ) ? (phrase + 1) : 12
|
||||
key = phrase_list[phrase]
|
||||
message = phrase_list[key]
|
||||
to_chat(usr,"<span class='notice'>You set the restrictor to: [message]</span>")
|
||||
if(4)
|
||||
phrase = (phrase < 18 && phrase >= 1 ) ? (phrase + 1) : 1
|
||||
key = phrase_list[phrase]
|
||||
message = phrase_list[key]
|
||||
to_chat(usr,"<span class='notice'>You set the restrictor to: [message]</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>It's broken.</span>")
|
||||
|
||||
/obj/item/clothing/mask/gas/sechailer/emag_act(mob/user)
|
||||
if(safety)
|
||||
safety = 0
|
||||
to_chat(user, "<span class='warning'>You silently fry [src]'s vocal circuit with the cryptographic sequencer.</span>")
|
||||
else
|
||||
return
|
||||
|
||||
/obj/item/clothing/mask/gas/sechailer/attackby(obj/item/I, mob/user)
|
||||
if(I.is_screwdriver())
|
||||
switch(aggressiveness)
|
||||
if(1)
|
||||
to_chat(user, "<span class='notice'>You set the aggressiveness restrictor to the second position.</span>")
|
||||
aggressiveness = 2
|
||||
phrase = 7
|
||||
if(2)
|
||||
to_chat(user, "<span class='notice'>You set the aggressiveness restrictor to the third position.</span>")
|
||||
aggressiveness = 3
|
||||
phrase = 13
|
||||
if(3)
|
||||
to_chat(user, "<span class='notice'>You set the aggressiveness restrictor to the fourth position.</span>")
|
||||
aggressiveness = 4
|
||||
phrase = 1
|
||||
if(4)
|
||||
to_chat(user, "<span class='notice'>You set the aggressiveness restrictor to the first position.</span>")
|
||||
aggressiveness = 1
|
||||
phrase = 1
|
||||
if(5)
|
||||
to_chat(user, "<span class='warning'>You adjust the restrictor but nothing happens, probably because its broken.</span>")
|
||||
if(I.is_wirecutter())
|
||||
if(aggressiveness != 5)
|
||||
to_chat(user, "<span class='warning'>You broke it!</span>")
|
||||
aggressiveness = 5
|
||||
if(I.is_crowbar())
|
||||
if(!hailer)
|
||||
to_chat(user, "<span class='warning'>This mask has an integrated hailer, you can't remove it!</span>")
|
||||
else
|
||||
var/obj/N = new /obj/item/clothing/mask/gas/half(src.loc)
|
||||
playsound(src, 'sound/items/Screwdriver.ogg', 50, 1)
|
||||
N.fingerprints = src.fingerprints
|
||||
N.fingerprintshidden = src.fingerprintshidden
|
||||
N.fingerprintslast = src.fingerprintslast
|
||||
N.suit_fibers = src.suit_fibers
|
||||
if(!isturf(N.loc))
|
||||
user.put_in_hands(hailer)
|
||||
user.put_in_hands(N)
|
||||
else
|
||||
hailer.loc = N.loc
|
||||
qdel(src)
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/clothing/mask/gas/sechailer/verb/halt()
|
||||
set name = "HALT!"
|
||||
set category = "Objects"
|
||||
set desc = "Activate your face mask hailer."
|
||||
var/key = phrase_list[phrase]
|
||||
var/message = phrase_list[key]
|
||||
|
||||
if(cooldown < world.time - 35) // A cooldown, to stop people being jerks
|
||||
if(!safety)
|
||||
message = "FUCK YOUR CUNT YOU SHIT EATING COCKSUCKER MAN EAT A DONG FUCKING ASS RAMMING SHIT FUCK EAT PENISES IN YOUR FUCK FACE AND SHIT OUT ABORTIONS OF FUCK AND DO SHIT IN YOUR ASS YOU COCK FUCK SHIT MONKEY FUCK ASS WANKER FROM THE DEPTHS OF SHIT."
|
||||
usr.visible_message("[usr]'s Compli-o-Nator: <font color='red' size='4'><b>[message]</b></font>")
|
||||
playsound(src, 'sound/voice/binsult.ogg', 50, 0, 4) //Future sound channel = something like SFX
|
||||
cooldown = world.time
|
||||
return
|
||||
|
||||
usr.visible_message("[usr]'s Compli-o-Nator: <font color='red' size='4'><b>[message]</b></font>")
|
||||
playsound(src, "sound/voice/complionator/[key].ogg", 50, 0, 4) //future sound channel = something like SFX
|
||||
cooldown = world.time
|
||||
@@ -1,4 +1,4 @@
|
||||
/datum/trait/positive/hardfeet
|
||||
/datum/trait/neutral/hardfeet
|
||||
custom_only = FALSE
|
||||
|
||||
/datum/trait/positive/linguist
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
/obj/item/weapon/circuitboard,
|
||||
/obj/item/weapon/smes_coil,
|
||||
/obj/item/weapon/fuel_assembly,
|
||||
/obj/item/weapon/ore/bluespace_crystal
|
||||
/obj/item/weapon/bluespace_crystal
|
||||
) // CHOMPEdit - Buffing the gripper to allow bluespace crystal use for telesci building.
|
||||
|
||||
var/obj/item/wrapped = null // Item currently being held.
|
||||
|
||||
@@ -1,45 +1,52 @@
|
||||
//Unfiying spider health, into two catagories. Disrupters and tanks.
|
||||
/mob/living/simple_mob/animal/giant_spider/carrier //Disrupter, old 100
|
||||
maxHealth = 70
|
||||
health = 70
|
||||
maxHealth = 60
|
||||
health = 60
|
||||
|
||||
/mob/living/simple_mob/animal/giant_spider/electric //disrupter, old 210
|
||||
maxHealth = 70
|
||||
health = 70
|
||||
maxHealth = 60
|
||||
health = 60
|
||||
projectiletype = /obj/item/projectile/energy/mob/electric_spider
|
||||
|
||||
/mob/living/simple_mob/animal/giant_spider/frost //tank, old 175
|
||||
maxHealth = 130
|
||||
health = 130
|
||||
maxHealth = 120
|
||||
health = 120
|
||||
|
||||
/mob/living/simple_mob/animal/giant_spider //tank, old 200
|
||||
maxHealth = 120
|
||||
health = 120
|
||||
|
||||
/mob/living/simple_mob/animal/giant_spider/ion //disrupter, old 90
|
||||
maxHealth = 70
|
||||
health = 70
|
||||
maxHealth = 60
|
||||
health = 60
|
||||
|
||||
/mob/living/simple_mob/animal/giant_spider/hunter //disrupter, old 120
|
||||
maxHealth = 70
|
||||
health = 70
|
||||
maxHealth = 60
|
||||
health = 60
|
||||
|
||||
/mob/living/simple_mob/animal/giant_spider/lurker //disrupter, old 100
|
||||
maxHealth = 70
|
||||
health = 70
|
||||
maxHealth = 60
|
||||
health = 60
|
||||
|
||||
/mob/living/simple_mob/animal/giant_spider/pepper //tank, old 210
|
||||
maxHealth = 130
|
||||
health = 130
|
||||
maxHealth = 120
|
||||
health = 120
|
||||
|
||||
/mob/living/simple_mob/animal/giant_spider/phorogenic //tank, old 225
|
||||
maxHealth = 130
|
||||
health = 130
|
||||
maxHealth = 120
|
||||
health = 120
|
||||
|
||||
/mob/living/simple_mob/animal/giant_spider/thermic //tank, old 175
|
||||
maxHealth = 130
|
||||
health = 130
|
||||
maxHealth = 120
|
||||
health = 120
|
||||
|
||||
/mob/living/simple_mob/animal/giant_spider/tunneler_spider //disrupter, old 120
|
||||
maxHealth = 70
|
||||
health = 70
|
||||
maxHealth = 60
|
||||
health = 60
|
||||
|
||||
/mob/living/simple_mob/animal/giant_spider/webslinger //disrupter, old 90
|
||||
maxHealth = 70
|
||||
health = 70
|
||||
maxHealth = 60
|
||||
health = 60
|
||||
|
||||
/obj/effect/spider/eggcluster
|
||||
spider_type = /obj/effect/spider/spiderling/varied
|
||||
@@ -283,7 +283,7 @@
|
||||
vore_max_size = RESIZE_HUGE
|
||||
vore_min_size = RESIZE_SMALL
|
||||
vore_pounce_chance = 0 // Beat them into crit before eating.
|
||||
vore_icons = null
|
||||
vore_icons = SA_ICON_LIVING
|
||||
|
||||
can_be_drop_prey = FALSE //CHOMP Add
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/mob/living/simple_mob/animal/wolf/direwolf/Initialize()
|
||||
/mob/living/simple_mob/vore/wolf/direwolf/Initialize()
|
||||
. = ..()
|
||||
verbs += /mob/living/simple_mob/proc/pick_color
|
||||
|
||||
/mob/living/simple_mob/animal/wolf/direwolf
|
||||
/mob/living/simple_mob/vore/wolf/direwolf
|
||||
maxHealth = 100
|
||||
health = 100
|
||||
health = 100
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
icon_state = "meb_m_hi"
|
||||
maxcharge = 10000
|
||||
charge_amount = 20
|
||||
origin_tech = list(TECH_POWER = 5, TECH_PRECURSOR = 1)
|
||||
origin_tech = list(TECH_POWER = 8)
|
||||
|
||||
/obj/item/weapon/cell/device/giga/empty/Initialize()
|
||||
. = ..()
|
||||
@@ -161,10 +161,10 @@
|
||||
catalogue_data = list(/datum/category_item/catalogue/anomalous/precursor_a/alien_void_cell)
|
||||
icon = 'icons/obj/abductor.dmi'
|
||||
icon_state = "cell"
|
||||
maxcharge = 3600
|
||||
charge_amount = 180 // 5%.
|
||||
maxcharge = 5000
|
||||
charge_amount = 130 // 2.5%.
|
||||
charge_delay = 50 // Every five seconds, bit faster than the default.
|
||||
origin_tech = list(TECH_POWER = 7, TECH_ENGINEERING = 5, TECH_PHORON = 5, TECH_ARCANE = 1, TECH_PRECURSOR = 1)
|
||||
origin_tech = list(TECH_POWER = 7, TECH_ENGINEERING = 6, TECH_PHORON = 6, TECH_ARCANE = 2, TECH_PRECURSOR = 2)
|
||||
|
||||
/obj/item/weapon/cell/device/weapon/recharge/alien/update_icon()
|
||||
return // No overlays please.
|
||||
@@ -192,8 +192,8 @@
|
||||
origin_tech = list(TECH_POWER = 8, TECH_ENGINEERING = 6)
|
||||
icon = 'icons/obj/abductor.dmi'
|
||||
icon_state = "cell"
|
||||
maxcharge = 4800 //10x the device version
|
||||
charge_amount = 1200 //10x the device version
|
||||
maxcharge = 10000
|
||||
charge_amount = 500
|
||||
self_recharge = TRUE
|
||||
charge_delay = 50
|
||||
matter = null
|
||||
@@ -224,11 +224,12 @@
|
||||
//YAWN Addtion
|
||||
/obj/item/weapon/cell/device/weapon/recharge/alien/omni
|
||||
name = "omni weapon power cell"
|
||||
desc = "A mix between alien technology and phoron tech. Seems to fit in almost any cell slot..."
|
||||
charge_amount = 120 // 2.5%.
|
||||
maxcharge = 4800
|
||||
desc = "A mix between alien technology and phoron-based tech. Not quite as good as a true void cell though."
|
||||
charge_amount = 90 // 2.5%.
|
||||
maxcharge = 3600
|
||||
charge_delay = 50
|
||||
origin_tech = list(TECH_POWER = 8, TECH_ENGINEERING = 6, TECH_PHORON = 6, TECH_ARCANE = 2, TECH_PRECURSOR = 2)
|
||||
swaps_to = null
|
||||
origin_tech = list(TECH_POWER = 8, TECH_ENGINEERING = 6, TECH_PHORON = 6, TECH_ARCANE = 1, TECH_PRECURSOR = 1)
|
||||
|
||||
/obj/item/weapon/cell/device/weapon/recharge/alien/omni/empty/Initialize()
|
||||
. = ..()
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
name = "security borg rechargable D battery"
|
||||
origin_tech = list(TECH_POWER = 0)
|
||||
icon_state = "secborg"
|
||||
maxcharge = 600 //600 max charge / 100 charge per shot = six shots
|
||||
maxcharge = 2400 //who the hell thought 6 shots was enough for a dogborg taser?
|
||||
matter = list(MAT_STEEL = 700, MAT_GLASS = 40)
|
||||
|
||||
/obj/item/weapon/cell/secborg/empty/New()
|
||||
@@ -88,7 +88,7 @@
|
||||
*/
|
||||
/obj/item/weapon/cell/giga
|
||||
name = "giga-capacity power cell"
|
||||
origin_tech = list(TECH_POWER = 6, TECH_PRECURSOR = 1)
|
||||
origin_tech = list(TECH_POWER = 8)
|
||||
icon_state = "meb_b_hi"
|
||||
maxcharge = 40000
|
||||
matter = list(MAT_STEEL = 1000, MAT_GLASS = 100)
|
||||
@@ -162,7 +162,7 @@
|
||||
icon_state = "yellow slime extract" //"potato_battery"
|
||||
description_info = "This 'cell' holds a max charge of 20k and self recharges over time."
|
||||
maxcharge = 20000
|
||||
charge_amount = 1000 // 5%.
|
||||
charge_amount = 500 // 2.5%.
|
||||
matter = null
|
||||
self_recharge = TRUE
|
||||
standard_overlays = FALSE
|
||||
|
||||
29
modular_chomp/code/modules/research/designs/implants.dm
Normal file
29
modular_chomp/code/modules/research/designs/implants.dm
Normal file
@@ -0,0 +1,29 @@
|
||||
/datum/design/item/organ/internal/augment/AssembleDesignName()
|
||||
..()
|
||||
name = "Biotech implant device prototype ([item_name])"
|
||||
|
||||
|
||||
/datum/design/item/organ/internal/augment/armmounted/hand
|
||||
desc = "An augment that fits neatly into the hand, useful for determining the usefulness of an object for research."
|
||||
id = "research_implant"
|
||||
req_tech = list(TECH_BIO = 5, TECH_MATERIAL = 2)
|
||||
materials = list(MAT_STEEL = 3000, MAT_GLASS = 3000)
|
||||
build_path = /obj/item/organ/internal/augment/armmounted/hand
|
||||
sort_string = "JVACE"
|
||||
|
||||
|
||||
/datum/design/item/organ/internal/augment/armmounted/shoulder/multiple
|
||||
desc = "A large implant that fits into a subject's arm. It deploys an array of tools by some painful means."
|
||||
id = "tool_implant"
|
||||
req_tech = list(TECH_BIO = 5, TECH_MATERIAL = 2, TECH_ENGINEERING = 3)
|
||||
materials = list(MAT_STEEL = 6000, MAT_GLASS = 6000)
|
||||
build_path = /obj/item/organ/internal/augment/armmounted/shoulder/multiple
|
||||
sort_string = "JVACI"
|
||||
|
||||
/datum/design/item/organ/internal/augment/armmounted/shoulder/multiple/medical
|
||||
desc = "A large implant that fits into a subject's arm. It deploys an array of tools by some painful means."
|
||||
id = "surgical_implant"
|
||||
req_tech = list(TECH_BIO = 6, TECH_MATERIAL = 4)
|
||||
materials = list(MAT_STEEL = 6000, MAT_GLASS = 6000, MAT_SILVER = 1000)
|
||||
build_path = /obj/item/organ/internal/augment/armmounted/shoulder/multiple/medical
|
||||
sort_string = "JVACJ"
|
||||
@@ -57,8 +57,8 @@
|
||||
/datum/design/item/powercell/giga
|
||||
name = "giga-capacity"
|
||||
id = "giga_cell"
|
||||
req_tech = list(TECH_POWER = 6, TECH_MATERIAL = 5, TECH_PRECURSOR = 1, TECH_PHORON = 4)
|
||||
materials = list(MAT_STEEL = 1000, MAT_GOLD = 300, MAT_SILVER = 300, MAT_GLASS = 100, MAT_PHORON = 1000, MAT_METALHYDROGEN = 250, MAT_DURASTEEL = 100, MAT_URANIUM = 100)
|
||||
req_tech = list(TECH_POWER = 7, TECH_MATERIAL = 5, TECH_ARCANE = 1, TECH_PHORON = 4)
|
||||
materials = list(MAT_STEEL = 1000, MAT_GOLD = 300, MAT_SILVER = 300, MAT_GLASS = 100, MAT_PHORON = 1000, MAT_DURASTEEL = 100, MAT_URANIUM = 100)
|
||||
build_path = /obj/item/weapon/cell/giga
|
||||
category = list("Misc")
|
||||
sort_string = "BAAAE"
|
||||
@@ -140,8 +140,8 @@
|
||||
/datum/design/item/powercell/giga_device
|
||||
name = "device, giga"
|
||||
id = "giga_device"
|
||||
req_tech = list(TECH_POWER = 6, TECH_MATERIAL = 6, TECH_PRECURSOR = 1, TECH_PHORON = 4)
|
||||
materials = list(MAT_STEEL = 2000, MAT_GOLD = 500, MAT_SILVER = 500, MAT_GLASS = 100, MAT_PHORON = 2000, MAT_METALHYDROGEN = 500, MAT_DURASTEEL = 200, MAT_URANIUM = 200)
|
||||
req_tech = list(TECH_POWER = 7, TECH_MATERIAL = 6, TECH_ARCANE = 1, TECH_PHORON = 4)
|
||||
materials = list(MAT_STEEL = 2000, MAT_GOLD = 500, MAT_SILVER = 500, MAT_GLASS = 100, MAT_PHORON = 2000, MAT_DURASTEEL = 200, MAT_URANIUM = 200)
|
||||
build_path = /obj/item/weapon/cell/device/giga
|
||||
category = list("Misc")
|
||||
sort_string = "BAAAH"
|
||||
|
||||
@@ -39,35 +39,35 @@
|
||||
/datum/design/item/weapon/phase/frontier_holdout
|
||||
id = "holdout frontier phaser"
|
||||
req_tech = list(TECH_COMBAT = 4, TECH_POWER = 7, TECH_MATERIAL = 6, TECH_PHORON = 6)
|
||||
materials = list(MAT_STEEL = 6000, MAT_GLASS = 900, MAT_DURASTEEL = 100, MAT_METALHYDROGEN = 150, MAT_VERDANTIUM = 100, MAT_PHORON = 1000)
|
||||
materials = list(MAT_STEEL = 6000, MAT_GLASS = 900, MAT_DURASTEEL = 100, MAT_VERDANTIUM = 100, MAT_PHORON = 1000)
|
||||
build_path = /obj/item/weapon/gun/energy/locked/frontier/holdout
|
||||
sort_string = "MACAE"
|
||||
|
||||
/datum/design/item/weapon/phase/frontier_phaser
|
||||
id = "frontier phaser"
|
||||
req_tech = list(TECH_COMBAT = 4, TECH_POWER = 7, TECH_MATERIAL = 6, TECH_PHORON = 6)
|
||||
materials = list(MAT_STEEL = 7000, MAT_GLASS = 900, MAT_DURASTEEL = 100, MAT_METALHYDROGEN = 200, MAT_VERDANTIUM = 150, MAT_PHORON = 2000)
|
||||
materials = list(MAT_STEEL = 7000, MAT_GLASS = 900, MAT_DURASTEEL = 100, MAT_VERDANTIUM = 150, MAT_PHORON = 2000)
|
||||
build_path = /obj/item/weapon/gun/energy/locked/frontier
|
||||
sort_string = "MACAF"
|
||||
|
||||
/datum/design/item/weapon/phase/frontier_carbine
|
||||
id = "carbine frontier phaser"
|
||||
req_tech = list(TECH_COMBAT = 4, TECH_POWER = 8, TECH_MATERIAL = 6, TECH_PHORON = 6)
|
||||
materials = list(MAT_STEEL = 6500, MAT_GLASS = 900, MAT_DURASTEEL = 150, MAT_METALHYDROGEN = 250, MAT_VERDANTIUM = 200, MAT_PHORON = 4000)
|
||||
materials = list(MAT_STEEL = 6500, MAT_GLASS = 900, MAT_DURASTEEL = 150, MAT_VERDANTIUM = 200, MAT_PHORON = 4000)
|
||||
build_path = /obj/item/weapon/gun/energy/locked/frontier/carbine
|
||||
sort_string = "MACAG"
|
||||
|
||||
/datum/design/item/weapon/phase/frontier_rifle
|
||||
id = "marksman rifle frontier phaser"
|
||||
req_tech = list(TECH_COMBAT = 4, TECH_POWER = 7, TECH_MATERIAL = 6, TECH_PHORON = 6)
|
||||
materials = list(MAT_STEEL = 8000, MAT_GLASS = 900, MAT_DURASTEEL = 200, MAT_METALHYDROGEN = 300, MAT_VERDANTIUM = 250, MAT_PHORON = 2000)
|
||||
materials = list(MAT_STEEL = 8000, MAT_GLASS = 900, MAT_DURASTEEL = 200, MAT_VERDANTIUM = 250, MAT_PHORON = 2000)
|
||||
build_path = /obj/item/weapon/gun/energy/locked/frontier/rifle
|
||||
sort_string = "MACAH"
|
||||
|
||||
/datum/design/item/weapon/phase/frontier_handbow
|
||||
id = "handbow frontier phaser"
|
||||
req_tech = list(TECH_COMBAT = 4, TECH_POWER = 7, TECH_MATERIAL = 6, TECH_PHORON = 6)
|
||||
materials = list(MAT_STEEL = 5000, MAT_GLASS = 900, MAT_DURASTEEL = 100, MAT_METALHYDROGEN = 200, MAT_VERDANTIUM = 150, MAT_PHORON = 1000)
|
||||
materials = list(MAT_STEEL = 5000, MAT_GLASS = 900, MAT_DURASTEEL = 100, MAT_VERDANTIUM = 150, MAT_PHORON = 1000)
|
||||
build_path = /obj/item/weapon/gun/energy/locked/frontier/handbow
|
||||
sort_string = "MACAI"
|
||||
|
||||
@@ -79,3 +79,10 @@
|
||||
build_path = /obj/item/weapon/gun/projectile/caseless/prototype
|
||||
sort_string = "MACBA"
|
||||
|
||||
/datum/design/item/weapon/energy/lasercannon
|
||||
desc = "The lasing medium of this prototype is enclosed in a tube lined with uranium-235 and subjected to high neutron flux in a nuclear reactor core."
|
||||
id = "lasercannon"
|
||||
req_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 6, TECH_POWER = 5)
|
||||
materials = list(MAT_STEEL = 4000, MAT_GLASS = 1000, MAT_DIAMOND = 2000, MAT_TITANIUM = 4000, MAT_LEAD = 4000, MAT_URANIUM = 5000)
|
||||
build_path = /obj/item/weapon/gun/energy/lasercannon
|
||||
sort_string = "MAAAD"
|
||||
|
||||
48
modular_chomp/code/modules/tgui/feedback.dm
Normal file
48
modular_chomp/code/modules/tgui/feedback.dm
Normal file
@@ -0,0 +1,48 @@
|
||||
/datum/tgui_feedback
|
||||
var/selected_window
|
||||
|
||||
/datum/tgui_feedback/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "TguiFeedback", "TGUI Feedback Submission")
|
||||
ui.open()
|
||||
|
||||
/datum/tgui_feedback/tgui_state(mob/user)
|
||||
return GLOB.tgui_always_state
|
||||
|
||||
/datum/tgui_feedback/tgui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
data["open_windows"] = list()
|
||||
for(var/datum/tgui/ui in user.tgui_open_uis)
|
||||
data["open_windows"] += ui.title
|
||||
|
||||
return data
|
||||
|
||||
/datum/tgui_feedback/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
data["selected_window"] = selected_window
|
||||
|
||||
return data
|
||||
|
||||
/datum/tgui_feedback/tgui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("pick_window")
|
||||
if(!params["win"])
|
||||
return
|
||||
|
||||
selected_window = sanitize(params["win"])
|
||||
. = TRUE
|
||||
if("submit")
|
||||
message_admins("TGUI Feedback: Rating [params["rating"]] - Comment: [params["comment"]]")
|
||||
. = TRUE
|
||||
|
||||
/client/verb/tgui_feedback()
|
||||
set name = "Submit TGUI Feedback"
|
||||
set category = "OOC"
|
||||
|
||||
var/datum/tgui_feedback/feedback = new()
|
||||
feedback.tgui_interact(usr)
|
||||
13
modular_chomp/code/modules/tgui/states/ticket.dm
Normal file
13
modular_chomp/code/modules/tgui/states/ticket.dm
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* tgui state: ticket_state
|
||||
*
|
||||
* Grants the user UI_INTERACTIVE, if a ticket is open.
|
||||
**/
|
||||
|
||||
GLOBAL_DATUM_INIT(tgui_ticket_state, /datum/tgui_state/ticket_state, new)
|
||||
|
||||
/datum/tgui_state/ticket_state/can_use_topic(src_object, mob/user)
|
||||
//if (user.client.current_ticket)
|
||||
// return STATUS_INTERACTIVE
|
||||
//return STATUS_CLOSE
|
||||
return STATUS_INTERACTIVE
|
||||
173
modular_chomp/code/modules/tickets/procs.dm
Normal file
173
modular_chomp/code/modules/tickets/procs.dm
Normal file
@@ -0,0 +1,173 @@
|
||||
//
|
||||
// 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_ticket)
|
||||
if(tgui_alert(usr, "You already have a ticket open. Is this for the same issue?","Duplicate?",list("Yes","No")) != "No")
|
||||
if(current_ticket)
|
||||
log_admin("Mentorhelp: [key_name(src)]: [msg]")
|
||||
current_ticket.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_ticket.AddInteraction("[usr.ckey] opened a new ticket.")
|
||||
current_ticket.Resolve()
|
||||
|
||||
new /datum/ticket(msg, src, FALSE, 1)
|
||||
|
||||
//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.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)
|
||||
|
||||
//
|
||||
// CLIENT PROCS
|
||||
//
|
||||
|
||||
/client/verb/adminhelp(msg as text)
|
||||
set category = "Admin"
|
||||
set name = "Adminhelp"
|
||||
|
||||
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: Admin-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/adminhelp
|
||||
spawn(1200)
|
||||
src.verbs += /client/verb/adminhelp // 2 minute cool-down for adminhelps
|
||||
|
||||
feedback_add_details("admin_verb","Adminhelp") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
if(current_ticket)
|
||||
if(tgui_alert(usr, "You already have a ticket open. Is this for the same issue?","Duplicate?",list("Yes","No")) != "No")
|
||||
if(current_ticket)
|
||||
current_ticket.MessageNoRecipient(msg)
|
||||
to_chat(usr, "<span class='adminnotice'>PM to-<b>Admins</b>: [msg]</span>")
|
||||
return
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Ticket not found, creating new one...</span>")
|
||||
else
|
||||
current_ticket.AddInteraction("[key_name_admin(usr)] opened a new ticket.")
|
||||
current_ticket.Close()
|
||||
|
||||
new /datum/ticket(msg, src, FALSE, 0)
|
||||
|
||||
//admin proc
|
||||
/client/proc/cmd_admin_ticket_panel()
|
||||
set name = "Show Ticket List"
|
||||
set category = "Admin"
|
||||
|
||||
if(!check_rights(R_ADMIN|R_MOD|R_DEBUG|R_EVENT, TRUE))
|
||||
return
|
||||
|
||||
var/browse_to
|
||||
|
||||
switch(tgui_input_list(usr, "Display which ticket list?", "List Choice", list("Active Tickets", "Closed Tickets", "Resolved Tickets")))
|
||||
if("Active Tickets")
|
||||
browse_to = AHELP_ACTIVE
|
||||
if("Closed Tickets")
|
||||
browse_to = AHELP_CLOSED
|
||||
if("Resolved Tickets")
|
||||
browse_to = AHELP_RESOLVED
|
||||
else
|
||||
return
|
||||
|
||||
GLOB.tickets.BrowseTickets(browse_to)
|
||||
|
||||
//// VOREstation Additions Below
|
||||
|
||||
/datum/ticket/proc/send2adminchat()
|
||||
if(!config.chat_webhook_url)
|
||||
return
|
||||
|
||||
var/list/adm = get_admin_counts()
|
||||
var/list/afkmins = adm["afk"]
|
||||
var/list/allmins = adm["total"]
|
||||
|
||||
spawn(0) //Unreliable world.Exports()
|
||||
var/query_string = "type=adminhelp"
|
||||
query_string += "&key=[url_encode(config.chat_webhook_key)]"
|
||||
query_string += "&from=[url_encode(key_name(initiator))]"
|
||||
query_string += "&msg=[url_encode(html_decode(name))]"
|
||||
query_string += "&admin_number=[allmins.len]"
|
||||
query_string += "&admin_number_afk=[afkmins.len]"
|
||||
world.Export("[config.chat_webhook_url]?[query_string]")
|
||||
|
||||
/client/verb/adminspice()
|
||||
set category = "Admin"
|
||||
set name = "Request Spice"
|
||||
set desc = "Request admins to spice round up for you"
|
||||
|
||||
//handle muting and automuting
|
||||
if(prefs.muted & MUTE_ADMINHELP)
|
||||
to_chat(usr, "<span class='danger'>Error: You cannot request spice (muted from adminhelps).</span>")
|
||||
return
|
||||
|
||||
if(tgui_alert(usr, "Are you sure you want to request the admins spice things up for you? You accept the consequences if you do.","Spicy!",list("Yes","No")) != "No")
|
||||
message_admins("[ADMIN_FULLMONTY(usr)] has requested the round be spiced up a little.")
|
||||
to_chat(usr, "<span class='notice'>You have requested some more spice in your round.</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>Spice request cancelled.</span>")
|
||||
return
|
||||
|
||||
//if they requested spice, then remove spice verb temporarily to prevent spamming
|
||||
usr.verbs -= /client/verb/adminspice
|
||||
spawn(10 MINUTES)
|
||||
if(usr) // In case we left in the 10 minute cooldown
|
||||
usr.verbs += /client/verb/adminspice // 10 minute cool-down for spice request
|
||||
806
modular_chomp/code/modules/tickets/tickets.dm
Normal file
806
modular_chomp/code/modules/tickets/tickets.dm
Normal file
@@ -0,0 +1,806 @@
|
||||
/*
|
||||
|
||||
CHOMPedit - This file has been excluded from the compilation.
|
||||
Reason: Replaced with "Tickets System". Main logic has been moved to: modular_chomp/modules/tickets/tickets.dm
|
||||
|
||||
*/
|
||||
|
||||
/client/var/datum/ticket/current_ticket //the current ticket the (usually) not-admin client is dealing with
|
||||
/client/var/datum/ticket/selected_ticket //the current ticket being viewed in the Tickets Panel (usually) admin/mentor client
|
||||
|
||||
// CHOMPEdit Begin
|
||||
/proc/get_ahelp_channel()
|
||||
var/datum/tgs_api/v5/api = TGS_READ_GLOBAL(tgs)
|
||||
if(istype(api) && config.ahelp_channel_tag)
|
||||
for(var/datum/tgs_chat_channel/channel in api.chat_channels)
|
||||
if(channel.custom_tag == config.ahelp_channel_tag)
|
||||
return list(channel)
|
||||
return 0
|
||||
|
||||
/proc/ahelp_discord_message(var/message)
|
||||
if(!message)
|
||||
return
|
||||
if(config.discord_ahelps_disabled)
|
||||
return
|
||||
var/datum/tgs_chat_channel/ahelp_channel = get_ahelp_channel()
|
||||
if(ahelp_channel)
|
||||
world.TgsChatBroadcast(message,ahelp_channel)
|
||||
else
|
||||
world.TgsTargetedChatBroadcast(message,TRUE)
|
||||
// CHOMPEdit End
|
||||
|
||||
//
|
||||
//TICKET MANAGER
|
||||
//
|
||||
|
||||
GLOBAL_DATUM_INIT(tickets, /datum/tickets, new)
|
||||
|
||||
/datum/tickets
|
||||
var/list/active_tickets = list()
|
||||
var/list/closed_tickets = list()
|
||||
var/list/resolved_tickets = list()
|
||||
|
||||
var/obj/effect/statclick/ticket_list/astatclick = new(null, null, AHELP_ACTIVE)
|
||||
var/obj/effect/statclick/ticket_list/cstatclick = new(null, null, AHELP_CLOSED)
|
||||
var/obj/effect/statclick/ticket_list/rstatclick = new(null, null, AHELP_RESOLVED)
|
||||
|
||||
/datum/tickets/Destroy()
|
||||
QDEL_LIST(active_tickets)
|
||||
QDEL_LIST(closed_tickets)
|
||||
QDEL_LIST(resolved_tickets)
|
||||
QDEL_NULL(astatclick)
|
||||
QDEL_NULL(cstatclick)
|
||||
QDEL_NULL(rstatclick)
|
||||
return ..()
|
||||
|
||||
//private
|
||||
/datum/tickets/proc/ListInsert(datum/ticket/new_ticket)
|
||||
var/list/ticket_list
|
||||
switch(new_ticket.state)
|
||||
if(AHELP_ACTIVE)
|
||||
ticket_list = active_tickets
|
||||
if(AHELP_CLOSED)
|
||||
ticket_list = closed_tickets
|
||||
if(AHELP_RESOLVED)
|
||||
ticket_list = resolved_tickets
|
||||
else
|
||||
CRASH("Invalid ticket state: [new_ticket.state]")
|
||||
var/num_closed = ticket_list.len
|
||||
if(num_closed)
|
||||
for(var/I in 1 to num_closed)
|
||||
var/datum/ticket/T = ticket_list[I]
|
||||
if(T.id > new_ticket.id)
|
||||
ticket_list.Insert(I, new_ticket)
|
||||
return
|
||||
ticket_list += new_ticket
|
||||
|
||||
/datum/tickets/proc/BrowseTickets(state)
|
||||
tgui_interact(usr)
|
||||
|
||||
//opens the ticket listings for one of the 3 states
|
||||
/datum/tickets/proc/BrowseTicketsLegacy(state)
|
||||
var/list/l2b
|
||||
var/title
|
||||
switch(state)
|
||||
if(AHELP_ACTIVE)
|
||||
l2b = active_tickets
|
||||
title = "Active Tickets"
|
||||
if(AHELP_CLOSED)
|
||||
l2b = closed_tickets
|
||||
title = "Closed 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_=holder;[HrefToken()];ahelp_tickets=[state]'>Refresh</A><br><br>"
|
||||
for(var/datum/ticket/T as anything in l2b)
|
||||
dat += "<span class='adminnotice'><span class='adminhelp'>Ticket #[T.id]</span>: <A HREF='?_src_=holder;ahelp=\ref[T];[HrefToken()];ahelp_action=ticket'>[T.initiator_key_name]: [T.name]</A></span><br>"
|
||||
|
||||
usr << browse(dat.Join(), "window=ahelp_list[state];size=600x480")
|
||||
|
||||
//Tickets statpanel
|
||||
/datum/tickets/proc/stat_entry()
|
||||
var/num_disconnected = 0
|
||||
stat("== Tickets ==")
|
||||
stat("Active Tickets:", astatclick.update("[active_tickets.len]"))
|
||||
for(var/datum/ticket/T as anything in active_tickets)
|
||||
if(T.initiator)
|
||||
var/type = "N/A"
|
||||
switch(T.level)
|
||||
if(0)
|
||||
type = "ADM"
|
||||
if(1)
|
||||
type = "MEN"
|
||||
|
||||
if(usr.client.holder || T.level > 0)
|
||||
stat("\[[type]\] #[T.id]. [T.initiator_key_name]:", T.statclick.update())
|
||||
else
|
||||
++num_disconnected
|
||||
if(num_disconnected)
|
||||
stat("Disconnected:", astatclick.update("[num_disconnected]"))
|
||||
stat("Closed Tickets:", cstatclick.update("[closed_tickets.len]"))
|
||||
stat("Resolved Tickets:", rstatclick.update("[resolved_tickets.len]"))
|
||||
|
||||
//Reassociate still open ticket if one exists
|
||||
/datum/tickets/proc/ClientLogin(client/C)
|
||||
C.current_ticket = CKey2ActiveTicket(C.ckey)
|
||||
if(C.current_ticket)
|
||||
C.current_ticket.AddInteraction("Client reconnected.")
|
||||
C.current_ticket.initiator = C
|
||||
C.current_ticket.initiator.mob.throw_alert("open ticket", /obj/screen/alert/open_ticket)
|
||||
|
||||
//Dissasociate ticket
|
||||
/datum/tickets/proc/ClientLogout(client/C)
|
||||
if(C.current_ticket)
|
||||
C.current_ticket.AddInteraction("Client disconnected.")
|
||||
C.current_ticket.initiator.mob.clear_alert("open ticket")
|
||||
C.current_ticket.initiator = null
|
||||
C.current_ticket = null
|
||||
|
||||
//Get a ticket given a ckey
|
||||
/datum/tickets/proc/CKey2ActiveTicket(ckey)
|
||||
for(var/datum/ticket/T as anything in active_tickets)
|
||||
if(T.initiator_ckey == ckey)
|
||||
return T
|
||||
|
||||
//Get a ticket by ticket id
|
||||
/datum/tickets/proc/ID2Ticket(id)
|
||||
if(!usr?.client.holder || !has_mentor_powers(usr?.client))
|
||||
message_admins("[usr] has attempted to look up a ticket with ID [id] without sufficent privileges.")
|
||||
return
|
||||
|
||||
for(var/datum/ticket/T as anything in active_tickets)
|
||||
if(T.id == id)
|
||||
return T
|
||||
|
||||
for(var/datum/ticket/T as anything in resolved_tickets)
|
||||
if(T.id == id)
|
||||
return T
|
||||
|
||||
for(var/datum/ticket/T as anything in closed_tickets)
|
||||
if(T.id == id)
|
||||
return T
|
||||
|
||||
//
|
||||
//TICKET LIST STATCLICK
|
||||
//
|
||||
|
||||
/obj/effect/statclick/ticket_list
|
||||
var/current_state
|
||||
|
||||
/obj/effect/statclick/ticket_list/New(loc, name, state)
|
||||
current_state = state
|
||||
..()
|
||||
|
||||
/obj/effect/statclick/ticket_list/Click()
|
||||
GLOB.tickets.BrowseTickets(current_state)
|
||||
|
||||
//
|
||||
//TICKET DATUM
|
||||
//
|
||||
|
||||
/datum/ticket
|
||||
var/id
|
||||
var/name
|
||||
var/level = 0 // 0 = Admin, 1 = Mentor
|
||||
var/list/tags
|
||||
var/state = AHELP_ACTIVE
|
||||
|
||||
var/opened_at
|
||||
var/closed_at
|
||||
|
||||
var/client/initiator //semi-misnomer, it's the person who ahelped/was bwoinked
|
||||
var/handler = "/Unassigned\\" // The admin handling the ticket
|
||||
var/initiator_ckey
|
||||
var/initiator_key_name
|
||||
|
||||
var/list/_interactions //use AddInteraction() or, preferably, admin_ticket_log()
|
||||
|
||||
var/obj/effect/statclick/ticket/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)
|
||||
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 */
|
||||
|
||||
/**
|
||||
* public
|
||||
*
|
||||
* Create a new Ticket.
|
||||
* Call this on its own to create a ticket, don't manually assign current_ticket
|
||||
*
|
||||
* required msg string The title of the ticket: usually the ahelp text
|
||||
* required C client The object or datum which owns the UI.
|
||||
* required is_bwoink boolean TRUE if this ticket was started by an admin PM
|
||||
* required level integer The level of the ticket. 0 = Admin, 1 = Mentor
|
||||
*/
|
||||
/datum/ticket/New(msg, client/C, is_bwoink, ticket_level)
|
||||
//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
|
||||
|
||||
level = ticket_level
|
||||
|
||||
initiator = C
|
||||
initiator_ckey = initiator.ckey
|
||||
initiator_key_name = key_name(initiator, FALSE, TRUE)
|
||||
if(initiator.current_ticket) //This is a bug
|
||||
log_debug("Multiple ahelp current_tickets")
|
||||
initiator.current_ticket.AddInteraction("Ticket erroneously left open by code")
|
||||
initiator.current_ticket.Close()
|
||||
initiator.current_ticket = src
|
||||
|
||||
var/parsed_message = keywords_lookup(msg)
|
||||
|
||||
statclick = new(null, src)
|
||||
_interactions = list()
|
||||
|
||||
if(is_bwoink)
|
||||
AddInteraction("<font color='blue'>[key_name_admin(usr)] PM'd [LinkedReplyName()]</font>")
|
||||
message_admins("<font color='blue'>Ticket [TicketHref("#[id]")] created</font>")
|
||||
else
|
||||
MessageNoRecipient(parsed_message)
|
||||
send2adminchat() //VOREStation Add
|
||||
//show it to the person adminhelping too
|
||||
to_chat(C, "<span class='adminnotice'>PM to-<b>Admins</b>: [name]</span>")
|
||||
|
||||
//send it to irc if nobody is on and tell us how many were on
|
||||
var/admin_number_present = send2irc_adminless_only(initiator_ckey, name)
|
||||
log_admin("Ticket #[id]: [key_name(initiator)]: [name] - heard by [admin_number_present] non-AFK admins who have +BAN.")
|
||||
if(admin_number_present <= 0)
|
||||
to_chat(C, "<span class='notice'>No active admins are online, your adminhelp was sent to the admin discord.</span>") //VOREStation Edit
|
||||
send2adminchat() //VOREStation Add
|
||||
//YW EDIT START
|
||||
var/list/adm = get_admin_counts()
|
||||
var/list/activemins = adm["present"]
|
||||
var activeMins = activemins.len
|
||||
if(is_bwoink)
|
||||
ahelp_discord_message("ADMINHELP: FROM: [key_name_admin(usr)] TO [initiator_ckey]/[initiator_key_name] - MSG: **[msg]** - Heard by [activeMins] NON-AFK staff members.") //CHOMPEdit
|
||||
else
|
||||
ahelp_discord_message("ADMINHELP: FROM: [initiator_ckey]/[initiator_key_name] - MSG: **[msg]** - Heard by [activeMins] NON-AFK staff members.") //CHOMPEdit
|
||||
//YW EDIT END
|
||||
|
||||
// Also send it to discord since that's the hip cool thing now.
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_AHELP_SENT,
|
||||
list(
|
||||
"name" = "Ticket ([id]) (Game ID: [game_id]) ticket opened.",
|
||||
"body" = "[key_name(initiator)] has opened a ticket. \n[msg]",
|
||||
"color" = COLOR_WEBHOOK_POOR
|
||||
)
|
||||
)
|
||||
|
||||
GLOB.tickets.active_tickets += src
|
||||
|
||||
// Open a new chat with the user
|
||||
//var/datum/ticket_chat/TC = new()
|
||||
//TC.T = src
|
||||
//TC.tgui_interact(C.mob)
|
||||
C.mob.throw_alert("open ticket", /obj/screen/alert/open_ticket)
|
||||
|
||||
/datum/ticket/Destroy()
|
||||
RemoveActive()
|
||||
GLOB.tickets.closed_tickets -= src
|
||||
GLOB.tickets.resolved_tickets -= src
|
||||
return ..()
|
||||
|
||||
/datum/ticket/proc/AddInteraction(formatted_message)
|
||||
var/curinteraction = "[gameTimestamp()]: [formatted_message]"
|
||||
if(config.discord_ahelps_all) //CHOMPEdit
|
||||
ahelp_discord_message("ADMINHELP: TICKETID:[id] [strip_html_properly(curinteraction)]") //CHOMPEdit
|
||||
_interactions += curinteraction
|
||||
|
||||
/datum/ticket/proc/TicketPanel()
|
||||
tgui_interact(usr.client.mob)
|
||||
|
||||
//private
|
||||
/datum/ticket/proc/FullMonty(ref_src)
|
||||
if(!ref_src)
|
||||
ref_src = "\ref[src]"
|
||||
if(initiator && initiator.mob)
|
||||
. = ADMIN_FULLMONTY_NONAME(initiator.mob)
|
||||
else
|
||||
. = "Initiator disconnected."
|
||||
if(state == AHELP_ACTIVE)
|
||||
. += ClosureLinks(ref_src)
|
||||
|
||||
//private
|
||||
/datum/ticket/proc/ClosureLinks(ref_src)
|
||||
if(!ref_src)
|
||||
ref_src = "\ref[src]"
|
||||
|
||||
if(level == 0)
|
||||
. = " (<A HREF='?_src_=holder;ticket=[ref_src];[HrefToken(TRUE)];ticket_action=reject'>REJT</A>)"
|
||||
. += " (<A HREF='?_src_=holder;ticket=[ref_src];[HrefToken(TRUE)];ticket_action=icissue'>IC</A>)"
|
||||
. += " (<A HREF='?_src_=holder;ticket=[ref_src];[HrefToken(TRUE)];ticket_action=close'>CLOSE</A>)"
|
||||
. += " (<A HREF='?_src_=holder;ticket=[ref_src];[HrefToken(TRUE)];ticket_action=resolve'>RSLVE</A>)"
|
||||
. += " (<A HREF='?_src_=holder;ticket=[ref_src];[HrefToken(TRUE)];ticket_action=handleissue'>HANDLE</A>)"
|
||||
else
|
||||
. = " (<A HREF='?_src_=holder;ticket=[ref_src];[HrefToken(TRUE)];ticket_action=resolve'>RSLVE</A>)"
|
||||
|
||||
//private
|
||||
/datum/ticket/proc/LinkedReplyName(ref_src)
|
||||
if(!ref_src)
|
||||
ref_src = "\ref[src]"
|
||||
return "<A HREF='?_src_=holder;ticket=[ref_src];[HrefToken()];ticket_action=reply'>[initiator_key_name]</A>"
|
||||
|
||||
//private
|
||||
/datum/ticket/proc/TicketHref(msg, ref_src, action = "ticket")
|
||||
if(!ref_src)
|
||||
ref_src = "\ref[src]"
|
||||
return "<A HREF='?_src_=holder;ticket=[ref_src];[HrefToken()];ticket_action=[action]'>[msg]</A>"
|
||||
|
||||
/*
|
||||
var/chat_msg = "<span class='notice'>(<A HREF='?_src_=mentorholder;mhelp=[ref_src];[HrefToken()];mhelp_action=escalate'>ESCALATE</A>) Ticket [TicketHref("#[id]", ref_src)]<b>: [LinkedReplyName(ref_src)]:</b> [msg]</span>"
|
||||
*/
|
||||
|
||||
//message from the initiator without a target, all admins will see this
|
||||
//won't bug irc
|
||||
/datum/ticket/proc/MessageNoRecipient(msg)
|
||||
var/ref_src = "\ref[src]"
|
||||
var/chat_msg = "<span class='adminnotice'><span class='adminhelp'>Ticket [TicketHref("#[id]", ref_src)]</span><b>: [LinkedReplyName(ref_src)] [FullMonty(ref_src)]:</b> [msg]</span>"
|
||||
|
||||
AddInteraction("<font color='red'>[LinkedReplyName(ref_src)]: [msg]</font>")
|
||||
//send this msg to all admins
|
||||
|
||||
if(level == 1)
|
||||
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)
|
||||
else if(level == 0)
|
||||
for(var/client/X in GLOB.admins)
|
||||
if(X.is_preference_enabled(/datum/client_preference/holder/play_adminhelp_ping))
|
||||
X << 'sound/effects/adminhelp.ogg'
|
||||
window_flash(X)
|
||||
to_chat(X, chat_msg)
|
||||
|
||||
/*
|
||||
//Reopen a closed ticket
|
||||
/datum/mentor_help/proc/Reopen()
|
||||
switch(state)
|
||||
if(AHELP_RESOLVED)
|
||||
feedback_dec("mhelp_resolve")
|
||||
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)
|
||||
*/
|
||||
|
||||
//Reopen a closed ticket
|
||||
/datum/ticket/proc/Reopen()
|
||||
if(state == AHELP_ACTIVE)
|
||||
to_chat(usr, "<span class='warning'>This ticket is already open.</span>")
|
||||
return
|
||||
|
||||
if(GLOB.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.tickets.active_tickets += src
|
||||
GLOB.tickets.closed_tickets -= src
|
||||
GLOB.tickets.resolved_tickets -= src
|
||||
switch(state)
|
||||
if(AHELP_CLOSED)
|
||||
feedback_dec("ticket_close")
|
||||
if(AHELP_RESOLVED)
|
||||
feedback_dec("ticket_resolve")
|
||||
state = AHELP_ACTIVE
|
||||
closed_at = null
|
||||
if(initiator)
|
||||
initiator.current_ticket = src
|
||||
|
||||
AddInteraction("<font color='purple'>Reopened by [key_name_admin(usr)]</font>")
|
||||
if(initiator)
|
||||
to_chat(initiator, "<span class='filter_adminlog'><font color='purple'>Ticket [TicketHref("#[id]")] was reopened by [key_name(usr,FALSE,FALSE)].</font></span>")
|
||||
var/msg = "<span class='adminhelp'>Ticket [TicketHref("#[id]")] reopened by [key_name_admin(usr)].</span>"
|
||||
message_admins(msg)
|
||||
log_admin(msg)
|
||||
feedback_inc("ticket_reopen")
|
||||
//TicketPanel() //can only be done from here, so refresh it
|
||||
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_AHELP_SENT,
|
||||
list(
|
||||
"name" = "Ticket ([id]) (Game ID: [game_id]) reopened.",
|
||||
"body" = "Reopened by [key_name(usr)]."
|
||||
)
|
||||
)
|
||||
|
||||
//private
|
||||
/datum/ticket/proc/RemoveActive()
|
||||
if(state != AHELP_ACTIVE)
|
||||
return
|
||||
closed_at = world.time
|
||||
QDEL_NULL(statclick)
|
||||
GLOB.tickets.active_tickets -= src
|
||||
if(initiator && initiator.current_ticket == src)
|
||||
initiator.current_ticket = null
|
||||
|
||||
//Mark open ticket as closed/meme
|
||||
/datum/ticket/proc/Close(silent = FALSE)
|
||||
if(state != AHELP_ACTIVE)
|
||||
return
|
||||
RemoveActive()
|
||||
state = AHELP_CLOSED
|
||||
GLOB.tickets.ListInsert(src)
|
||||
AddInteraction("<span class='filter_adminlog'><font color='red'>Closed by [key_name_admin(usr)].</font></span>")
|
||||
if(initiator)
|
||||
to_chat(initiator, "<span class='filter_adminlog'><font color='red'>Ticket [TicketHref("#[id]")] was closed by [key_name(usr,FALSE,FALSE)].</font></span>")
|
||||
if(!silent)
|
||||
feedback_inc("ahelp_close")
|
||||
var/msg = "Ticket [TicketHref("#[id]")] closed by [key_name_admin(usr)]."
|
||||
message_admins(msg)
|
||||
log_admin(msg)
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_AHELP_SENT,
|
||||
list(
|
||||
"name" = "Ticket ([id]) (Game ID: [game_id]) closed.",
|
||||
"body" = "Closed by [key_name(usr)].",
|
||||
"color" = COLOR_WEBHOOK_BAD
|
||||
)
|
||||
)
|
||||
initiator?.mob?.clear_alert("open ticket")
|
||||
|
||||
//Mark open ticket as resolved/legitimate, returns ahelp verb
|
||||
/datum/ticket/proc/Resolve(silent = FALSE)
|
||||
if(state != AHELP_ACTIVE)
|
||||
return
|
||||
RemoveActive()
|
||||
state = AHELP_RESOLVED
|
||||
GLOB.tickets.ListInsert(src)
|
||||
|
||||
AddInteraction("<span class='filter_adminlog'><font color='green'>Resolved by [key_name_admin(usr)].</font></span>")
|
||||
if(initiator)
|
||||
to_chat(initiator, "<span class='filter_adminlog'><font color='green'>Ticket [TicketHref("#[id]")] was marked resolved by [key_name(usr,FALSE,FALSE)].</font></span>")
|
||||
if(!silent)
|
||||
feedback_inc("ticket_resolve")
|
||||
var/msg = "Ticket [TicketHref("#[id]")] resolved by [key_name_admin(usr)]"
|
||||
if(type == 1)
|
||||
message_mentors(msg)
|
||||
else if (type == 0)
|
||||
message_admins(msg)
|
||||
|
||||
log_admin(msg)
|
||||
if(type == 1)
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_AHELP_SENT,
|
||||
list(
|
||||
"name" = "Ticket ([id]) (Game ID: [game_id]) resolved.",
|
||||
"body" = "Marked as Resolved by [key_name(usr)].",
|
||||
"color" = COLOR_WEBHOOK_GOOD
|
||||
)
|
||||
)
|
||||
initiator?.mob?.clear_alert("open ticket")
|
||||
|
||||
//Close and return ahelp verb, use if ticket is incoherent
|
||||
/datum/ticket/proc/Reject(key_name = key_name_admin(usr))
|
||||
if(state != AHELP_ACTIVE)
|
||||
return
|
||||
|
||||
if(initiator)
|
||||
if(initiator.is_preference_enabled(/datum/client_preference/holder/play_adminhelp_ping))
|
||||
initiator << 'sound/effects/adminhelp.ogg'
|
||||
|
||||
to_chat(initiator, "<span class='filter_pm'><font color='red' size='4'><b>- AdminHelp Rejected! -</b></font><br>\
|
||||
<font color='red'><b>Your admin help was rejected.</b></font><br>\
|
||||
Please try to be calm, clear, and descriptive in admin helps, do not assume the admin has seen any related events, and clearly state the names of anybody you are reporting.</span>")
|
||||
|
||||
feedback_inc("ahelp_reject")
|
||||
var/msg = "Ticket [TicketHref("#[id]")] rejected by [key_name_admin(usr)]"
|
||||
message_admins(msg)
|
||||
log_admin(msg)
|
||||
AddInteraction("Rejected by [key_name_admin(usr)].")
|
||||
Close(silent = TRUE)
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_AHELP_SENT,
|
||||
list(
|
||||
"name" = "Ticket ([id]) (Game ID: [game_id]) rejected.",
|
||||
"body" = "Rejected by [key_name(usr)].",
|
||||
"color" = COLOR_WEBHOOK_BAD
|
||||
)
|
||||
)
|
||||
|
||||
//Resolve ticket with IC Issue message
|
||||
/datum/ticket/proc/ICIssue(key_name = key_name_admin(usr))
|
||||
if(state != AHELP_ACTIVE)
|
||||
return
|
||||
|
||||
var/msg = "<span class='filter_pm'><font color='red' size='4'><b>- AdminHelp marked as IC issue! -</b></font><br>"
|
||||
msg += "<font color='red'><b>This is something that can be solved ICly, and does not currently require staff intervention.</b></font><br>"
|
||||
msg += "<font color='red'>Your AdminHelp may also be unanswerable due to ongoing events.</font></span>"
|
||||
|
||||
if(initiator)
|
||||
to_chat(initiator, msg)
|
||||
|
||||
feedback_inc("ahelp_icissue")
|
||||
msg = "Ticket [TicketHref("#[id]")] marked as IC by [key_name_admin(usr)]"
|
||||
message_admins(msg)
|
||||
log_admin(msg)
|
||||
AddInteraction("Marked as IC issue by [key_name_admin(usr)]")
|
||||
Resolve(silent = TRUE)
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_AHELP_SENT,
|
||||
list(
|
||||
"name" = "Ticket ([id]) (Game ID: [game_id]) marked as IC issue.",
|
||||
"body" = "Marked as IC Issue by [key_name(usr)].",
|
||||
"color" = COLOR_WEBHOOK_BAD
|
||||
)
|
||||
)
|
||||
|
||||
//Resolve ticket with IC Issue message
|
||||
/datum/ticket/proc/HandleIssue()
|
||||
if(state != AHELP_ACTIVE)
|
||||
return
|
||||
|
||||
if(handler == key_name(usr, FALSE, TRUE))
|
||||
to_chat("<font color='red'>You are already handling this ticket.</font>")
|
||||
return
|
||||
|
||||
var/msg = "<font color='red'>Your AdminHelp is being handled by [key_name(usr,FALSE,FALSE)] please be patient.</font>"
|
||||
|
||||
if(initiator)
|
||||
to_chat(initiator, msg)
|
||||
|
||||
feedback_inc("ahelp_handling")
|
||||
msg = "Ticket [TicketHref("#[id]")] being handled by [key_name(usr,FALSE,FALSE)]"
|
||||
message_admins(msg)
|
||||
log_admin(msg)
|
||||
AddInteraction("[key_name_admin(usr)] is now handling this ticket.")
|
||||
handler = key_name(usr, FALSE, TRUE)
|
||||
SSwebhooks.send(
|
||||
WEBHOOK_AHELP_SENT,
|
||||
list(
|
||||
"name" = "Ticket ([id]) (Game ID: [game_id]) being handled.",
|
||||
"body" = "[key_name(usr)] is now handling the ticket."
|
||||
)
|
||||
)
|
||||
|
||||
/datum/ticket/proc/Retitle()
|
||||
var/new_title = tgui_input_text(usr, "Enter a title for the ticket", "Rename Ticket", name)
|
||||
if(new_title)
|
||||
name = new_title
|
||||
//not saying the original name cause it could be a long ass message
|
||||
var/msg = "Ticket [TicketHref("#[id]")] titled [name] by [key_name_admin(usr)]"
|
||||
message_admins(msg)
|
||||
log_admin(msg)
|
||||
//TicketPanel() //we have to be here to do this
|
||||
|
||||
//Kick ticket to next level
|
||||
/datum/ticket/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
|
||||
|
||||
level = level - 1
|
||||
|
||||
message_mentors("[usr.ckey] escalated Ticket [TicketHref("#[id]")]")
|
||||
log_admin("[key_name(usr)] escalated ticket [src.name]")
|
||||
to_chat(src.initiator, "<span class='mentor'>[usr.ckey] escalated your ticket to admins.</span>")
|
||||
|
||||
/datum/ticket/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
|
||||
/datum/ticket/proc/Action(action)
|
||||
testing("Ahelp action: [action]")
|
||||
switch(action)
|
||||
if("ticket")
|
||||
TicketPanel()
|
||||
if("retitle")
|
||||
Retitle()
|
||||
if("reject")
|
||||
Reject()
|
||||
if("reply")
|
||||
usr.client.cmd_ahelp_reply(initiator)
|
||||
if("icissue")
|
||||
ICIssue()
|
||||
if("close")
|
||||
Close()
|
||||
if("resolve")
|
||||
Resolve()
|
||||
if("handleissue")
|
||||
HandleIssue()
|
||||
if("reopen")
|
||||
Reopen()
|
||||
if("escalate")
|
||||
Escalate()
|
||||
|
||||
//
|
||||
// TICKET STATCLICK
|
||||
//
|
||||
|
||||
/obj/effect/statclick/ticket
|
||||
var/datum/ticket/ticket_datum
|
||||
|
||||
/obj/effect/statclick/ticket/New(loc, datum/ticket/T)
|
||||
ticket_datum = T
|
||||
..(loc)
|
||||
|
||||
/obj/effect/statclick/ticket/update()
|
||||
return ..(ticket_datum.name)
|
||||
|
||||
/obj/effect/statclick/ticket/Click()
|
||||
ticket_datum.TicketPanel()
|
||||
|
||||
/obj/effect/statclick/ticket/Destroy()
|
||||
ticket_datum = null
|
||||
return ..()
|
||||
|
||||
//
|
||||
// LOGGING
|
||||
//
|
||||
|
||||
//Use this proc when an admin takes action that may be related to an open ticket on what
|
||||
//what can be a client, ckey, or mob
|
||||
/proc/admin_ticket_log(what, message)
|
||||
var/client/C
|
||||
var/mob/Mob = what
|
||||
if(istype(Mob))
|
||||
C = Mob.client
|
||||
else
|
||||
C = what
|
||||
if(istype(C) && C.current_ticket)
|
||||
C.current_ticket.AddInteraction(message)
|
||||
return C.current_ticket
|
||||
if(istext(what)) //ckey
|
||||
var/datum/ticket/T = GLOB.tickets.CKey2ActiveTicket(what)
|
||||
if(T)
|
||||
T.AddInteraction(message)
|
||||
return T
|
||||
|
||||
//
|
||||
// HELPER PROCS
|
||||
//
|
||||
|
||||
/proc/get_admin_counts(requiredflags = R_BAN)
|
||||
. = list("total" = list(), "noflags" = list(), "afk" = list(), "stealth" = list(), "present" = list())
|
||||
for(var/client/X in GLOB.admins)
|
||||
.["total"] += X
|
||||
if(requiredflags != 0 && !check_rights(rights_required = requiredflags, show_msg = FALSE, C = X))
|
||||
.["noflags"] += X
|
||||
else if(X.is_afk())
|
||||
.["afk"] += X
|
||||
else if(X.holder.fakekey)
|
||||
.["stealth"] += X
|
||||
else
|
||||
.["present"] += X
|
||||
|
||||
/proc/send2irc_adminless_only(source, msg, requiredflags = R_BAN)
|
||||
var/list/adm = get_admin_counts()
|
||||
var/list/activemins = adm["present"]
|
||||
. = activemins.len
|
||||
if(. <= 0)
|
||||
var/final = ""
|
||||
var/list/afkmins = adm["afk"]
|
||||
var/list/stealthmins = adm["stealth"]
|
||||
var/list/powerlessmins = adm["noflags"]
|
||||
var/list/allmins = adm["total"]
|
||||
if(!afkmins.len && !stealthmins.len && !powerlessmins.len)
|
||||
final = "[msg] - No admins online"
|
||||
else
|
||||
final = "[msg] - All admins stealthed\[[english_list(stealthmins)]\], AFK\[[english_list(afkmins)]\], or lacks +BAN\[[english_list(powerlessmins)]\]! Total: [allmins.len] "
|
||||
send2irc(source,final)
|
||||
|
||||
/proc/ircadminwho()
|
||||
var/list/message = list("Admins: ")
|
||||
var/list/admin_keys = list()
|
||||
for(var/client/C as anything in GLOB.admins)
|
||||
admin_keys += "[C][C.holder.fakekey ? "(Stealth)" : ""][C.is_afk() ? "(AFK)" : ""]"
|
||||
|
||||
for(var/admin in admin_keys)
|
||||
if(LAZYLEN(admin_keys) > 1)
|
||||
message += ", [admin]"
|
||||
else
|
||||
message += "[admin]"
|
||||
|
||||
return jointext(message, "")
|
||||
|
||||
/proc/keywords_lookup(msg,irc)
|
||||
|
||||
//This is a list of words which are ignored by the parser when comparing message contents for names. MUST BE IN LOWER CASE!
|
||||
var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","alien","as", "i")
|
||||
|
||||
//explode the input msg into a list
|
||||
var/list/msglist = splittext(msg, " ")
|
||||
|
||||
//generate keywords lookup
|
||||
var/list/surnames = list()
|
||||
var/list/forenames = list()
|
||||
var/list/ckeys = list()
|
||||
var/founds = ""
|
||||
for(var/mob/M in mob_list)
|
||||
var/list/indexing = list(M.real_name, M.name)
|
||||
if(M.mind)
|
||||
indexing += M.mind.name
|
||||
|
||||
for(var/string in indexing)
|
||||
var/list/L = splittext(string, " ")
|
||||
var/surname_found = 0
|
||||
//surnames
|
||||
for(var/i=L.len, i>=1, i--)
|
||||
var/word = ckey(L[i])
|
||||
if(word)
|
||||
surnames[word] = M
|
||||
surname_found = i
|
||||
break
|
||||
//forenames
|
||||
for(var/i=1, i<surname_found, i++)
|
||||
var/word = ckey(L[i])
|
||||
if(word)
|
||||
forenames[word] = M
|
||||
//ckeys
|
||||
ckeys[M.ckey] = M
|
||||
|
||||
var/ai_found = 0
|
||||
msg = ""
|
||||
var/list/mobs_found = list()
|
||||
for(var/original_word in msglist)
|
||||
var/word = ckey(original_word)
|
||||
if(word)
|
||||
if(!(word in adminhelp_ignored_words))
|
||||
if(word == "ai")
|
||||
ai_found = 1
|
||||
else
|
||||
var/mob/found = ckeys[word]
|
||||
if(!found)
|
||||
found = surnames[word]
|
||||
if(!found)
|
||||
found = forenames[word]
|
||||
if(found)
|
||||
if(!(found in mobs_found))
|
||||
mobs_found += found
|
||||
if(!ai_found && isAI(found))
|
||||
ai_found = 1
|
||||
var/is_antag = 0
|
||||
if(found.mind && found.mind.special_role)
|
||||
is_antag = 1
|
||||
founds += "Name: [found.name]([found.real_name]) Ckey: [found.ckey] [is_antag ? "(Antag)" : null] "
|
||||
msg += "[original_word]<font size='1' color='[is_antag ? "red" : "black"]'>(<A HREF='?_src_=holder;[HrefToken()];adminmoreinfo=\ref[found]'>?</A>|<A HREF='?_src_=holder;[HrefToken()];adminplayerobservefollow=\ref[found]'>F</A>)</font> "
|
||||
continue
|
||||
msg += "[original_word] "
|
||||
if(irc)
|
||||
if(founds == "")
|
||||
return "Search Failed"
|
||||
else
|
||||
return founds
|
||||
|
||||
return msg
|
||||
44
modular_chomp/code/modules/tickets/tickets_player_ui.dm
Normal file
44
modular_chomp/code/modules/tickets/tickets_player_ui.dm
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
//PLAYERSIDE TICKET UI
|
||||
//
|
||||
|
||||
/datum/ticket_chat
|
||||
var/datum/ticket/T
|
||||
|
||||
/datum/ticket_chat/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "TicketChat", "Ticket #[T.id] - [T.LinkedReplyName("\ref[T]")]")
|
||||
ui.open()
|
||||
user.clear_alert("open ticket")
|
||||
|
||||
/datum/ticket_chat/tgui_close(mob/user)
|
||||
. = ..()
|
||||
if(user.client.current_ticket)
|
||||
user.throw_alert("open ticket", /obj/screen/alert/open_ticket)
|
||||
|
||||
/datum/ticket_chat/tgui_state(mob/user)
|
||||
return GLOB.tgui_ticket_state
|
||||
|
||||
/datum/ticket_chat/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
data["id"] = T.id
|
||||
|
||||
data["level"] = T.level
|
||||
data["handler"] = T.handler
|
||||
|
||||
data["log"] = T._interactions
|
||||
|
||||
return data
|
||||
|
||||
/datum/ticket_chat/tgui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("send_msg")
|
||||
if(!params["msg"])
|
||||
return
|
||||
|
||||
usr.client.cmd_admin_pm(usr.client, sanitize(params["msg"]), T)
|
||||
. = TRUE
|
||||
340
modular_chomp/code/modules/tickets/tickets_ui.dm
Normal file
340
modular_chomp/code/modules/tickets/tickets_ui.dm
Normal file
@@ -0,0 +1,340 @@
|
||||
//
|
||||
//TICKET MANAGER
|
||||
//
|
||||
|
||||
/datum/tickets/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "TicketsPanel", "Tickets")
|
||||
ui.open()
|
||||
|
||||
/datum/tickets/tgui_state(mob/user)
|
||||
return GLOB.tgui_admin_state
|
||||
|
||||
/datum/tickets/proc/get_ticket_state(state)
|
||||
var/ticket_state
|
||||
switch(state)
|
||||
if(AHELP_ACTIVE)
|
||||
ticket_state = "open"
|
||||
// TODO: Mentor tickets cannot be resolved
|
||||
if(AHELP_RESOLVED)
|
||||
ticket_state = "resolved"
|
||||
if(AHELP_CLOSED)
|
||||
ticket_state = "closed"
|
||||
else
|
||||
ticket_state = "unknown"
|
||||
|
||||
return ticket_state
|
||||
|
||||
/datum/tickets/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
var/list/tickets = list()
|
||||
|
||||
var/selected_ticket = null
|
||||
|
||||
if(user.client.selected_ticket)
|
||||
var/datum/ticket/T = user.client.selected_ticket
|
||||
selected_ticket = list(
|
||||
"id" = T.id,
|
||||
"name" = T.LinkedReplyName(),
|
||||
"state" = get_ticket_state(T.state),
|
||||
"level" = T.level,
|
||||
"handler" = T.handler,
|
||||
"opened_at" = (world.time - T.opened_at),
|
||||
"closed_at" = (world.time - T.closed_at),
|
||||
"opened_at_date" = gameTimestamp(wtime = T.opened_at),
|
||||
"closed_at_date" = gameTimestamp(wtime = T.closed_at),
|
||||
"actions" = T.FullMonty(),
|
||||
"log" = T._interactions,
|
||||
)
|
||||
|
||||
for(var/datum/ticket/T as anything in GLOB.tickets.active_tickets)
|
||||
if(user.client.holder || (has_mentor_powers(user.client) && T.level > 0))
|
||||
tickets.Add(list(list(
|
||||
"id" = T.id,
|
||||
"name" = T.initiator_key_name,
|
||||
"state" = get_ticket_state(T.state),
|
||||
"level" = T.level,
|
||||
"handler" = T.handler,
|
||||
"opened_at" = (world.time - T.opened_at),
|
||||
"closed_at" = (world.time - T.closed_at),
|
||||
"opened_at_date" = gameTimestamp(wtime = T.opened_at),
|
||||
"closed_at_date" = gameTimestamp(wtime = T.closed_at),
|
||||
)))
|
||||
|
||||
for(var/datum/ticket/T as anything in GLOB.tickets.closed_tickets)
|
||||
if(user.client.holder || (has_mentor_powers(user.client) && T.level > 0))
|
||||
tickets.Add(list(list(
|
||||
"id" = T.id,
|
||||
"name" = T.initiator_key_name,
|
||||
"state" = get_ticket_state(T.state),
|
||||
"level" = T.level,
|
||||
"handler" = T.handler,
|
||||
"opened_at" = (world.time - T.opened_at),
|
||||
"closed_at" = (world.time - T.closed_at),
|
||||
"opened_at_date" = gameTimestamp(wtime = T.opened_at),
|
||||
"closed_at_date" = gameTimestamp(wtime = T.closed_at),
|
||||
)))
|
||||
|
||||
for(var/datum/ticket/T as anything in GLOB.tickets.resolved_tickets)
|
||||
if(user.client.holder || (has_mentor_powers(user.client) && T.level > 0))
|
||||
tickets.Add(list(list(
|
||||
"id" = T.id,
|
||||
"name" = T.initiator_key_name,
|
||||
"state" = get_ticket_state(T.state),
|
||||
"level" = T.level,
|
||||
"handler" = T.handler,
|
||||
"opened_at" = (world.time - T.opened_at),
|
||||
"closed_at" = (world.time - T.closed_at),
|
||||
"opened_at_date" = gameTimestamp(wtime = T.opened_at),
|
||||
"closed_at_date" = gameTimestamp(wtime = T.closed_at),
|
||||
)))
|
||||
data["tickets"] = tickets
|
||||
|
||||
data["selected_ticket"] = selected_ticket
|
||||
|
||||
return data
|
||||
|
||||
/datum/tickets/tgui_act(action, params, datum/tgui/ui)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("legacy")
|
||||
var/choice = tgui_input_list(usr, "Which tickets do you want to list?", "Tickets", list("Active", "Closed", "Resolved"))
|
||||
TicketListLegacy(choice)
|
||||
. = TRUE
|
||||
if("new_ticket")
|
||||
var/list/ckeys = list()
|
||||
for(var/client/C in GLOB.clients)
|
||||
ckeys += C.key
|
||||
|
||||
var/ckey = lowertext(tgui_input_list(usr, "Please select the ckey of the user.", "Select CKEY", ckeys))
|
||||
if(!ckey)
|
||||
return
|
||||
|
||||
var/client/player
|
||||
for(var/client/C in GLOB.clients)
|
||||
if(C.ckey == ckey)
|
||||
player = C
|
||||
|
||||
if(!player)
|
||||
to_chat(usr, "<span class='warning'>Ckey ([ckey]) not online.</span>")
|
||||
return
|
||||
|
||||
var/ticket_text = tgui_input_text(usr, "What should the initial text be?", "New Ticket")
|
||||
if(!ticket_text)
|
||||
to_chat(usr, "<span class='warning'>Ticket message cannot be empty.</span>")
|
||||
return
|
||||
|
||||
var/level = tgui_alert(usr, "Is this ticket Admin-Level or Mentor-Level?", "Ticket Level", list("Admin", "Mentor"))
|
||||
if(!level)
|
||||
return
|
||||
|
||||
feedback_add_details("admin_verb","Admincreatedticket") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
if(player.current_ticket)
|
||||
if(tgui_alert(usr, "The player already has a ticket open. Is this for the same issue?","Duplicate?",list("Yes","No")) != "No")
|
||||
if(player.current_ticket)
|
||||
player.current_ticket.MessageNoRecipient(ticket_text)
|
||||
to_chat(usr, "<span class='adminnotice'>PM to-<b>Admins</b>: [ticket_text]</span>")
|
||||
return
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Ticket not found, creating new one...</span>")
|
||||
else
|
||||
player.current_ticket.AddInteraction("[key_name_admin(usr)] opened a new ticket.")
|
||||
player.current_ticket.Close()
|
||||
|
||||
// Create a new ticket and handle it. You created it afterall!
|
||||
var/datum/ticket/T = new /datum/ticket(ticket_text, player, TRUE, level)
|
||||
if(level == "Admin")
|
||||
T.level = 0
|
||||
else
|
||||
T.level = 1
|
||||
T.HandleIssue()
|
||||
usr.client.cmd_admin_pm(player, ticket_text, T)
|
||||
. = TRUE
|
||||
if("pick_ticket")
|
||||
var/datum/ticket/T = ID2Ticket(params["ticket_id"])
|
||||
usr.client.selected_ticket = T
|
||||
. = TRUE
|
||||
if("retitle_ticket")
|
||||
usr.client.selected_ticket.Retitle()
|
||||
. = TRUE
|
||||
if("reopen_ticket")
|
||||
usr.client.selected_ticket.Reopen()
|
||||
. = TRUE
|
||||
if("undock_ticket")
|
||||
usr.client.selected_ticket.tgui_interact(usr)
|
||||
usr.client.selected_ticket = null
|
||||
. = TRUE
|
||||
if("send_msg")
|
||||
if(!params["msg"])
|
||||
return
|
||||
|
||||
usr.client.cmd_admin_pm(usr.client.selected_ticket.initiator, sanitize(params["msg"]), usr.client.selected_ticket)
|
||||
. = TRUE
|
||||
|
||||
/datum/tickets/tgui_fallback(payload)
|
||||
if(..())
|
||||
return
|
||||
|
||||
var/choice = tgui_input_list(usr, "Which tickets do you want to list?", "Tickets", list("Active", "Closed", "Resolved"))
|
||||
|
||||
TicketListLegacy(choice)
|
||||
|
||||
//
|
||||
//TICKET DATUM
|
||||
//
|
||||
|
||||
/datum/ticket/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "Ticket", "Ticket #[id] - [LinkedReplyName("\ref[src]")]")
|
||||
ui.open()
|
||||
|
||||
/datum/ticket/tgui_state(mob/user)
|
||||
return GLOB.tgui_admin_state
|
||||
|
||||
/datum/ticket/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
data["id"] = id
|
||||
|
||||
var/ref_src = "\ref[src]"
|
||||
data["title"] = name
|
||||
data["name"] = LinkedReplyName(ref_src)
|
||||
data["ticket_ref"] = ref_src
|
||||
|
||||
switch(state)
|
||||
if(AHELP_ACTIVE)
|
||||
data["state"] = "open"
|
||||
// TODO: Mentor tickets cannot be resolved
|
||||
if(AHELP_RESOLVED)
|
||||
data["state"] = "resolved"
|
||||
if(AHELP_CLOSED)
|
||||
data["state"] = "closed"
|
||||
else
|
||||
data["state"] = "unknown"
|
||||
|
||||
data["level"] = level
|
||||
data["handler"] = handler
|
||||
|
||||
data["opened_at"] = (world.time - opened_at)
|
||||
data["closed_at"] = (world.time - closed_at)
|
||||
data["opened_at_date"] = gameTimestamp(wtime = opened_at)
|
||||
data["closed_at_date"] = gameTimestamp(wtime = closed_at)
|
||||
|
||||
data["actions"] = FullMonty(ref_src)
|
||||
|
||||
data["log"] = _interactions
|
||||
|
||||
return data
|
||||
|
||||
/datum/ticket/tgui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("retitle")
|
||||
Retitle()
|
||||
. = TRUE
|
||||
if("reopen")
|
||||
Reopen()
|
||||
. = TRUE
|
||||
if("legacy")
|
||||
TicketPanelLegacy()
|
||||
. = TRUE
|
||||
if("send_msg")
|
||||
if(!params["msg"] || !params["ticket_ref"])
|
||||
return
|
||||
|
||||
var/datum/ticket/T = locate(params["ticket_ref"])
|
||||
|
||||
usr.client.cmd_admin_pm(T.initiator, sanitize(params["msg"]), T)
|
||||
. = TRUE
|
||||
|
||||
/datum/ticket/tgui_fallback(payload)
|
||||
if(..())
|
||||
return
|
||||
|
||||
TicketPanelLegacy()
|
||||
|
||||
/*
|
||||
/datum/mentor_help/proc/TicketPanelLegacy()
|
||||
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") */
|
||||
|
||||
/datum/ticket/proc/TicketPanelLegacy()
|
||||
var/list/dat = list("<html><head><title>Ticket #[id]</title></head>")
|
||||
var/ref_src = "\ref[src]"
|
||||
dat += "<h4>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>"
|
||||
if(AHELP_CLOSED)
|
||||
dat += "CLOSED"
|
||||
else
|
||||
dat += "UNKNOWN"
|
||||
dat += "</b>[GLOB.TAB][TicketHref("Refresh", ref_src)][GLOB.TAB][TicketHref("Re-Title", ref_src, "retitle")]"
|
||||
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> [FullMonty(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=ahelp[id];size=620x480")
|
||||
|
||||
/datum/tickets/proc/TicketListLegacy(var/state)
|
||||
var/list/dat = list("<html><head><title>[state] Tickets</title></head>")
|
||||
var/tickets_found = 0
|
||||
|
||||
if(state == "Active")
|
||||
for(var/datum/ticket/T as anything in GLOB.tickets.active_tickets)
|
||||
dat += "[T.level == 0 ? "Adminhelp" : "Mentorhelp"] - [T.TicketHref("#[T.id] - [T.initiator_ckey]: [T.name]")]"
|
||||
tickets_found++
|
||||
else if(state == "Closed")
|
||||
for(var/datum/ticket/T as anything in GLOB.tickets.closed_tickets)
|
||||
dat += "[T.level == 0 ? "Adminhelp" : "Mentorhelp"] - [T.TicketHref("#[T.id] - [T.initiator_ckey]: [T.name]")]"
|
||||
tickets_found++
|
||||
else if(state == "Resolved")
|
||||
for(var/datum/ticket/T as anything in GLOB.tickets.resolved_tickets)
|
||||
dat += "[T.level == 0 ? "Adminhelp" : "Mentorhelp"] - [T.TicketHref("#[T.id] - [T.initiator_ckey]: [T.name]")]"
|
||||
tickets_found++
|
||||
|
||||
if(tickets_found == 0)
|
||||
dat += "No [state] tickets found."
|
||||
|
||||
usr << browse(dat.Join(), "window=ahelp-list;size=250x350")
|
||||
Reference in New Issue
Block a user