Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into tgui-alerts-and-what-not

This commit is contained in:
SandPoot
2021-10-16 14:11:00 -03:00
30 changed files with 8625 additions and 7826 deletions
+35 -5
View File
@@ -161,13 +161,14 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
var/client/initiator //semi-misnomer, it's the person who ahelped/was bwoinked
var/initiator_ckey
var/initiator_key_name
var/heard_by_no_admins = FALSE
var/list/_interactions //use AddInteraction() or, preferably, admin_ticket_log()
var/obj/effect/statclick/ahelp/statclick
var/static/ticket_counter = 0
/// did we send "answered" to irc yet
var/answered = FALSE
//call this on its own to create a ticket, don't manually assign current_ticket
//msg is the title of the ticket: usually the ahelp text
@@ -209,7 +210,6 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
log_admin_private("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 irc.</span>")
heard_by_no_admins = TRUE
else
// citadel edit: send anyways
send2adminchat(initiator_ckey, "Ticket #[id]: [name] - Heard by [admin_number_present] admins present with +BAN.")
@@ -223,9 +223,8 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
return ..()
/datum/admin_help/proc/AddInteraction(formatted_message)
// if(heard_by_no_admins usr && usr.ckey != initiator_ckey)
// heard_by_no_admins = FALSE
if(usr && (usr.ckey != initiator_ckey))
if(usr && (usr.ckey != initiator_ckey) && !answered)
answered = TRUE
send2adminchat(initiator_ckey, "Ticket #[id]: Answered by [key_name(usr)]")
_interactions += "[TIME_STAMP("hh:mm:ss", FALSE)]: [formatted_message]"
@@ -732,3 +731,34 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
return founds
return msg
/**
* Checks a given message to see if any of the words contain an active admin's ckey with an @ before it
*
* Returns nothing if no pings are found, otherwise returns an associative list with ckey -> client
* Also modifies msg to underline the pings, then stores them in the key [ADMINSAY_PING_UNDERLINE_NAME_INDEX] for returning
*
* Arguments:
* * msg - the message being scanned
*/
/proc/check_admin_pings(msg)
//explode the input msg into a list
var/list/msglist = splittext(msg, " ")
var/list/admins_to_ping = list()
var/i = 0
for(var/word in msglist)
i++
if(!length(word))
continue
if(word[1] != "@")
continue
var/ckey_check = lowertext(copytext(word, 2))
var/client/client_check = GLOB.directory[ckey_check]
if(client_check?.holder)
msglist[i] = "<u>[word]</u>"
admins_to_ping[ckey_check] = client_check
if(length(admins_to_ping))
admins_to_ping[ADMINSAY_PING_UNDERLINE_NAME_INDEX] = jointext(msglist, " ") // without tuples, we must make do!
return admins_to_ping
+13
View File
@@ -8,6 +8,19 @@
msg = copytext_char(sanitize(msg), 1, MAX_MESSAGE_LEN)
if(!msg)
return
var/list/pinged_admin_clients = check_admin_pings(msg)
if(length(pinged_admin_clients) && pinged_admin_clients[ADMINSAY_PING_UNDERLINE_NAME_INDEX])
msg = pinged_admin_clients[ADMINSAY_PING_UNDERLINE_NAME_INDEX]
pinged_admin_clients -= ADMINSAY_PING_UNDERLINE_NAME_INDEX
for(var/iter_ckey in pinged_admin_clients)
var/client/iter_admin_client = pinged_admin_clients[iter_ckey]
if(!iter_admin_client?.holder)
continue
window_flash(iter_admin_client)
SEND_SOUND(iter_admin_client.mob, sound('sound/misc/bloop.ogg'))
msg = emoji_parse(msg)
mob.log_talk(msg, LOG_ASAY)
+3
View File
@@ -145,6 +145,9 @@
else
to_chat(src,"<span class='userlove'>You can't make that genital [picked_organ.aroused_state ? "unaroused" : "aroused"]!</span>")
picked_organ.update_appearance()
if(ishuman(src))
var/mob/living/carbon/human/human = src
human.update_genitals()
return
+23
View File
@@ -183,6 +183,29 @@
var/item = pick(contains)
new item(C)
/datum/supply_pack/security/armory/frontier
name = "Old West Surplus Crate"
desc = "Do you have a fauna problem? Do you want to live out your frontier-taming fantasies on a state-of-the-art plasma research and mining station? Do you want to pretend you lived in the Old West of Earthen fame? Well, this box - and its many hats - may be for you."
cost = 7500
contraband = TRUE
contains = list(/obj/effect/spawner/bundle/crate/cowboyhat,
/obj/effect/spawner/bundle/crate/cowboyboots,
/obj/item/clothing/under/pants/chaps,
/obj/item/reagent_containers/food/snacks/butterbiscuit,
/obj/item/reagent_containers/food/snacks/butterbiscuit,
/obj/item/reagent_containers/food/snacks/plumphelmetbiscuit,
/obj/item/reagent_containers/food/snacks/plumphelmetbiscuit,
/obj/item/ammo_box/c38/pouch,
/obj/item/ammo_box/c38/pouch,
/obj/item/ammo_box/c38/pouch,
/obj/effect/spawner/bundle/crate/levergun
)
/datum/supply_pack/security/armory/frontier/fill(obj/structure/closet/crate/C)
for(var/i in 1 to 5)
var/item = pick(contains)
new item(C)
/datum/supply_pack/security/armory/swat
name = "SWAT Crate"
desc = "Contains two fullbody sets of tough, fireproof, pressurized suits designed in a joint effort by IS-ERI and Nanotrasen. Each set contains a suit, helmet, mask, combat belt, and combat gloves. Requires Armory access to open."
+6 -3
View File
@@ -27,9 +27,12 @@
. = ..()
if(!ishuman(user))
return
if(slot == ITEM_SLOT_GLOVES)
var/mob/living/carbon/human/H = user
tackler = H.AddComponent(/datum/component/tackler, stamina_cost=tackle_stam_cost, base_knockdown = base_knockdown, range = tackle_range, speed = tackle_speed, skill_mod = skill_mod, min_distance = min_distance)
switch(slot) // I didn't like how it looked
if(SLOT_GLOVES)
var/mob/living/carbon/human/H = user
tackler = H.AddComponent(/datum/component/tackler, stamina_cost=tackle_stam_cost, base_knockdown = base_knockdown, range = tackle_range, speed = tackle_speed, skill_mod = skill_mod, min_distance = min_distance)
else
qdel(tackler) // Only wearing it!
/obj/item/clothing/gloves/tackler/dropped(mob/user)
. = ..()
@@ -1,11 +1,8 @@
#define MINER_DASH_RANGE 4
/*
BLOOD-DRUNK MINER
Effectively a highly aggressive miner, the blood-drunk miner has very few attacks but compensates by being highly aggressive.
The blood-drunk miner's attacks are as follows
- If not in KA range, it will rapidly dash at its target
- If in KA range, it will fire its kinetic accelerator
@@ -13,11 +10,8 @@ The blood-drunk miner's attacks are as follows
- After any of these attacks, may transform its cleaving saw:
Untransformed, it attacks very rapidly for smaller amounts of damage
Transformed, it attacks at normal speed for higher damage and cleaves enemies hit
When the blood-drunk miner dies, it leaves behind the cleaving saw it was using and its kinetic accelerator.
Difficulty: Medium
*/
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner
@@ -37,7 +31,7 @@ Difficulty: Medium
move_to_delay = 2
projectiletype = /obj/item/projectile/kinetic/miner
projectilesound = 'sound/weapons/kenetic_accel.ogg'
ranged = 1
ranged = TRUE
ranged_cooldown_time = 16
pixel_x = -16
crusher_loot = list(/obj/item/melee/transforming/cleaving_saw, /obj/item/gun/energy/kinetic_accelerator/premiumka, /obj/item/crusher_trophy/miner_eye, /obj/item/disk/design_disk/modkit_disc/mob_and_turf_aoe,
@@ -55,18 +49,56 @@ Difficulty: Medium
var/dashing = FALSE
var/dash_cooldown = 15
var/guidance = FALSE
var/transform_stop_attack = FALSE // stops the blood drunk miner from attacking after transforming his weapon until the next attack chain
deathmessage = "falls to the ground, decaying into glowing particles."
death_sound = "bodyfall"
deathsound = "bodyfall"
footstep_type = FOOTSTEP_MOB_HEAVY
attack_action_types = list(/datum/action/innate/megafauna_attack/dash,
/datum/action/innate/megafauna_attack/kinetic_accelerator,
/datum/action/innate/megafauna_attack/transform_weapon)
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/guidance
guidance = TRUE
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/hunter/AttackingTarget()
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Initialize()
. = ..()
if(. && prob(12))
INVOKE_ASYNC(src, .proc/dash)
miner_saw = new(src)
/datum/action/innate/megafauna_attack/dash
name = "Dash To Target"
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
chosen_message = "<span class='colossus'>You are now dashing to your target.</span>"
chosen_attack_num = 1
/datum/action/innate/megafauna_attack/kinetic_accelerator
name = "Fire Kinetic Accelerator"
icon_icon = 'icons/obj/guns/energy.dmi'
button_icon_state = "kineticgun"
chosen_message = "<span class='colossus'>You are now shooting your kinetic accelerator.</span>"
chosen_attack_num = 2
/datum/action/innate/megafauna_attack/transform_weapon
name = "Transform Weapon"
icon_icon = 'icons/obj/lavaland/artefacts.dmi'
button_icon_state = "cleaving_saw"
chosen_message = "<span class='colossus'>You are now transforming your weapon.</span>"
chosen_attack_num = 3
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/OpenFire()
if(client)
switch(chosen_attack)
if(1)
dash(target)
if(2)
shoot_ka()
if(3)
transform_weapon()
return
Goto(target, move_to_delay, minimum_distance)
if(get_dist(src, target) > MINER_DASH_RANGE && dash_cooldown <= world.time)
dash_attack()
else
shoot_ka()
transform_weapon()
/obj/item/melee/transforming/cleaving_saw/miner //nerfed saw because it is very murdery
force = 6
@@ -74,7 +106,7 @@ Difficulty: Medium
/obj/item/melee/transforming/cleaving_saw/miner/attack(mob/living/target, mob/living/carbon/human/user)
target.add_stun_absorption("miner", 10, INFINITY)
. = ..()
..()
target.stun_absorption -= "miner"
/obj/item/projectile/kinetic/miner
@@ -83,22 +115,16 @@ Difficulty: Medium
icon_state = "ka_tracer"
range = MINER_DASH_RANGE
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Initialize()
. = ..()
internal = new/obj/item/gps/internal/miner(src)
miner_saw = new(src)
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
var/adjustment_amount = amount * 0.1
if(world.time + adjustment_amount > next_action)
DelayNextAction(adjustment_amount, considered_action = FALSE, flush = TRUE) //attacking it interrupts it attacking, but only briefly
DelayNextAction(adjustment_amount) //attacking it interrupts it attacking, but only briefly
. = ..()
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/death()
if(health > 0)
return
new /obj/effect/temp_visual/dir_setting/miner_death(loc, dir)
return ..()
. = ..()
if(.)
new /obj/effect/temp_visual/dir_setting/miner_death(loc, dir)
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Move(atom/newloc)
if(dashing || (newloc && newloc.z == z && (islava(newloc) || ischasm(newloc)))) //we're not stupid!
@@ -110,11 +136,14 @@ Difficulty: Medium
return
return ..()
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/MeleeAction(patience = TRUE)
transform_stop_attack = FALSE
return ..()
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/AttackingTarget()
if(QDELETED(target))
return
if(!CheckActionCooldown() || !Adjacent(target)) //some cheating
INVOKE_ASYNC(src, .proc/quick_attack_loop)
if(client)
transform_stop_attack = FALSE
if(QDELETED(target) || transform_stop_attack)
return
face_atom(target)
if(isliving(target))
@@ -129,12 +158,10 @@ Difficulty: Medium
adjustHealth(-(L.maxHealth * 0.5))
L.gib()
return TRUE
miner_saw.melee_attack_chain(src, target, null, ATTACK_IGNORE_CLICKDELAY)
FlushCurrentAction()
DelayNextAction(CLICK_CD_MELEE)
miner_saw.melee_attack_chain(src, target)
if(guidance)
adjustHealth(-2)
transform_weapon()
INVOKE_ASYNC(src, .proc/quick_attack_loop)
return TRUE
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
@@ -147,16 +174,10 @@ Difficulty: Medium
. = ..()
if(. && target && !targets_the_same)
wander = TRUE
transform_weapon()
INVOKE_ASYNC(src, .proc/quick_attack_loop)
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/OpenFire()
Goto(target, move_to_delay, minimum_distance)
if(get_dist(src, target) > MINER_DASH_RANGE && dash_cooldown <= world.time)
INVOKE_ASYNC(src, .proc/dash, target)
else
shoot_ka()
transform_weapon()
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/dash_attack()
INVOKE_ASYNC(src, .proc/dash, target)
shoot_ka()
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/shoot_ka()
if(ranged_cooldown <= world.time && get_dist(src, target) <= MINER_DASH_RANGE && !Adjacent(target))
@@ -165,22 +186,7 @@ Difficulty: Medium
face_atom(target)
new /obj/effect/temp_visual/dir_setting/firing_effect(loc, dir)
Shoot(target)
DelayNextAction(CLICK_CD_RANGE, flush = TRUE)
//I'm still of the belief that this entire proc needs to be wiped from existence.
// do not take my touching of it to be endorsement of it. ~mso
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/quick_attack_loop()
while(!QDELETED(target) && !CheckActionCooldown()) //this is done this way because next_move can change to be sooner while we sleep.
stoplag(1)
sleep((next_action - world.time) * 1.5) //but don't ask me what the fuck this is about
if(QDELETED(target))
return
if(dashing || !CheckActionCooldown() || !Adjacent(target))
if(dashing && next_action <= world.time)
SetNextAction(1, considered_action = FALSE, immediate = FALSE, flush = TRUE)
INVOKE_ASYNC(src, .proc/quick_attack_loop) //lets try that again.
return
AttackingTarget()
DelayNextAction(CLICK_CD_RANGE)
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/dash(atom/dash_target)
if(world.time < dash_cooldown)
@@ -225,19 +231,23 @@ Difficulty: Medium
dashing = TRUE
alpha = 0
animate(src, alpha = 255, time = 5)
sleep(2)
SLEEP_CHECK_DEATH(2)
D.forceMove(step_forward_turf)
forceMove(target_turf)
playsound(target_turf, 'sound/weapons/punchmiss.ogg', 40, 1, -1)
sleep(1)
SLEEP_CHECK_DEATH(1)
dashing = FALSE
shoot_ka()
return TRUE
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/transform_weapon()
if(time_until_next_transform <= world.time)
miner_saw.transform_cooldown = 0
miner_saw.transform_weapon(src, TRUE)
if(!miner_saw.active)
rapid_melee = 5 // 4 deci cooldown before changes, npcpool subsystem wait is 20, 20/4 = 5
else
rapid_melee = 3 // same thing but halved (slightly rounded up)
transform_stop_attack = TRUE
icon_state = "miner[miner_saw.active ? "_transformed":""]"
icon_living = "miner[miner_saw.active ? "_transformed":""]"
time_until_next_transform = world.time + rand(50, 100)
@@ -269,6 +279,14 @@ Difficulty: Medium
desc = "The sweet blood, oh, it sings to me."
invisibility = 100
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/guidance
guidance = TRUE
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/hunter/AttackingTarget()
. = ..()
if(. && prob(12))
INVOKE_ASYNC(src, .proc/dash)
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/doom
name = "hostile-environment miner"
desc = "A miner destined to hop across dimensions for all eternity, hunting anomalous creatures."
@@ -277,4 +295,5 @@ Difficulty: Medium
ranged_cooldown_time = 8
dash_cooldown = 8
#undef MINER_DASH_RANGE
@@ -39,7 +39,7 @@
/obj/item/ammo_casing/c38/lethal
name = ".38 bullet casing"
desc = "A .38 bullet casing"
desc = "A .38 bullet casing."
projectile_type = /obj/item/projectile/bullet/c38
/obj/item/ammo_casing/c38/trac
@@ -60,6 +60,13 @@
desc = "Designed to quickly reload revolvers. These rounds are manufactured within extremely tight tolerances, making them easy to show off trickshots with."
ammo_type = /obj/item/ammo_casing/c38/match
/obj/item/ammo_box/c38/pouch
name = "ammo packet (.38)"
desc = "A small ammunition packet made of synthleather. Not particularly useful for speedily reloading, but can hold a bit more."
multiload = FALSE
max_ammo = 8
icon_state = "38pch"
/obj/item/ammo_box/g4570
name = "ammo box (.45-70 GOVT)"
desc = "Brought to you at great expense,this box contains 10 more .45-70 GOVT bullets."
@@ -61,3 +61,7 @@
ammo_type = /obj/item/ammo_casing/c38 // they're rubber by default, i guess
caliber = "38"
max_ammo = 7
/obj/item/ammo_box/magazine/internal/shot/levergun/brush
name = "brush gun internal magazine"
ammo_type = /obj/item/ammo_casing/g4570
@@ -122,7 +122,7 @@
icon_state = "c20r[magazine ? "-[CEILING(get_ammo(0)/4, 1)*4]" : ""][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]"
/obj/item/gun/ballistic/automatic/wt550
name = "security semi-auto smg"
name = "security semi-auto PDW"
desc = "An outdated personal defence weapon. Uses 4.6x30mm rounds and is designated the WT-550 Semi-Automatic SMG."
icon_state = "wt550"
item_state = "arg"
@@ -11,6 +11,7 @@
mag_type = /obj/item/ammo_box/magazine/internal/shot
casing_ejector = FALSE
var/recentpump = 0 // to prevent spammage
var/clip_delay = CLICK_CD_MELEE
weapon_weight = WEAPON_HEAVY
sawn_item_state = "sawnshotgun"
@@ -24,7 +25,8 @@
playsound(user, 'sound/weapons/shotguninsert.ogg', 60, 1)
A.update_icon()
update_icon()
user.SetNextAction(CLICK_CD_MELEE)
if(istype(A, /obj/item/ammo_box))
user.SetNextAction(clip_delay)
/obj/item/gun/ballistic/shotgun/process_chamber(mob/living/user, empty_chamber = 0)
return ..() //changed argument value
@@ -359,9 +361,13 @@
icon_state = "levercarabine"
item_state = "leveraction"
sawn_item_state = "maresleg"
var/can_cut = TRUE
/obj/item/gun/ballistic/shotgun/leveraction/attackby(obj/item/A, mob/user, params)
..()
if(!can_cut)
to_chat(user, "<span class='warning'>You can't cut \the [src] down!</span>")
return
if(A.tool_behaviour == TOOL_SAW || istype(A, /obj/item/gun/energy/plasmacutter))
sawoff(user)
if(istype(A, /obj/item/melee/transforming/energy))
@@ -377,3 +383,11 @@
icon_state = "[unique_reskin[current_skin]][sawn_off ? "-sawn" : ""][chambered ? "" : "-e"]"
else
icon_state = "[initial(icon_state)][sawn_off ? "-sawn" : ""][chambered ? "" : "-e"]"
/obj/item/gun/ballistic/shotgun/leveraction/brush
name = "brush gun"
desc = "While lever-actions have been horribly out of date for hundreds of years now, \
putting a nicely sized hole in a man-sized target with a .45-70 round has stayed relatively timeless."
icon_state = "brushgun"
can_cut = FALSE
mag_type = /obj/item/ammo_box/magazine/internal/shot/levergun/brush
+2 -1
View File
@@ -14,7 +14,8 @@
/obj/item/storage/fancy/rollingpapers = 5)
contraband = list(/obj/item/lighter = 3,
/obj/item/clothing/mask/vape = 5,
/obj/item/storage/fancy/cigarettes/cigpack_shadyjims = 1)
/obj/item/storage/fancy/cigarettes/cigpack_shadyjims = 1,
/obj/item/clothing/mask/cigarette/dart = 3)
premium = list(/obj/item/storage/fancy/cigarettes/cigpack_robustgold = 3,
/obj/item/storage/fancy/cigarettes/cigars = 1,
/obj/item/storage/fancy/cigarettes/cigars/havana = 1,