mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-21 19:17:50 +01:00
[READY] Syndicate Contractors (#14605)
* Syndicate Contractors initial PR * Finalize initial version DNP Finalize initial version * Baton now costs 6 Rep, show dead extraction penalty, fix scroll * Reduce total TC, add zippo, balloon, icon tweaks * Address moxian, AA and Farie * Fix mode.txt * oops * Address Farie 2 * Tweak baton to work around stam crits, address SteelSlayer * Address TM issues, TP menu * Fix wrongly merged DME * Tick contractor DM files again * Remove step_y * TC rewards always higher than preceding difficulty's reward * Address Farie * Remove extraction_turf from handle_target_return * fix doc * Merge part2 * Address AA again
This commit is contained in:
@@ -41,6 +41,9 @@
|
||||
poster_type = /obj/structure/sign/poster/official/random
|
||||
icon_state = "rolled_poster_legit"
|
||||
|
||||
/obj/item/poster/syndicate_recruitment
|
||||
poster_type = /obj/structure/sign/poster/contraband/syndicate_recruitment
|
||||
icon_state = "rolled_poster"
|
||||
|
||||
//############################## THE ACTUAL DECALS ###########################
|
||||
|
||||
|
||||
@@ -40,6 +40,10 @@
|
||||
GLOB.prisonwarp += loc
|
||||
qdel(src)
|
||||
|
||||
if("syndieprisonwarp")
|
||||
GLOB.syndieprisonwarp += loc
|
||||
qdel(src)
|
||||
|
||||
if("prisonsecuritywarp")
|
||||
GLOB.prisonsecuritywarp += loc
|
||||
qdel(src)
|
||||
|
||||
@@ -23,6 +23,10 @@ GLOBAL_LIST_EMPTY(world_uplinks)
|
||||
var/job = null
|
||||
var/temp_category
|
||||
var/uplink_type = "traitor"
|
||||
/// If set, the uplink will show the option to become a contractor through this variable.
|
||||
var/datum/antagonist/traitor/contractor/contractor = null
|
||||
/// Whether the uplink is jammed and cannot be used to order items.
|
||||
var/is_jammed = FALSE
|
||||
|
||||
/obj/item/uplink/ui_host()
|
||||
return loc
|
||||
@@ -78,6 +82,9 @@ GLOBAL_LIST_EMPTY(world_uplinks)
|
||||
return pick(random_items)
|
||||
|
||||
/obj/item/uplink/proc/buy(var/datum/uplink_item/UI, var/reference)
|
||||
if(is_jammed)
|
||||
to_chat(usr, "<span class='warning'>[src] seems to be jammed - it cannot be used here!</span>")
|
||||
return
|
||||
if(!UI)
|
||||
return
|
||||
if(UI.limited_stock == 0)
|
||||
@@ -144,7 +151,10 @@ GLOBAL_LIST_EMPTY(world_uplinks)
|
||||
// Checks to see if the value meets the target. Like a frequency being a traitor_frequency, in order to unlock a headset.
|
||||
// If true, it accesses trigger() and returns 1. If it fails, it returns false. Use this to see if you need to close the
|
||||
// current item's menu.
|
||||
/obj/item/uplink/hidden/proc/check_trigger(mob/user as mob, var/value, var/target)
|
||||
/obj/item/uplink/hidden/proc/check_trigger(mob/user, var/value, var/target)
|
||||
if(is_jammed)
|
||||
to_chat(user, "<span class='warning'>[src] seems to be jammed - it cannot be used here!</span>")
|
||||
return
|
||||
if(value == target)
|
||||
trigger(user)
|
||||
return TRUE
|
||||
@@ -160,6 +170,16 @@ GLOBAL_LIST_EMPTY(world_uplinks)
|
||||
var/list/data = list()
|
||||
|
||||
data["crystals"] = uses
|
||||
data["modal"] = ui_modal_data(src)
|
||||
|
||||
if(contractor)
|
||||
var/list/contractor_data = list(
|
||||
available = uses >= contractor.tc_cost && world.time < contractor.offer_deadline,
|
||||
affordable = uses >= contractor.tc_cost,
|
||||
accepted = !isnull(contractor.contractor_uplink),
|
||||
time_left = contractor.offer_deadline - world.time,
|
||||
)
|
||||
data["contractor"] = contractor_data
|
||||
|
||||
return data
|
||||
|
||||
@@ -198,6 +218,8 @@ GLOBAL_LIST_EMPTY(world_uplinks)
|
||||
return
|
||||
|
||||
. = TRUE
|
||||
if(tgui_act_modal(action, params))
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("lock")
|
||||
@@ -217,6 +239,28 @@ GLOBAL_LIST_EMPTY(world_uplinks)
|
||||
var/datum/uplink_item/UI = uplink_items[params["item"]]
|
||||
return buy(UI, UI ? UI.reference : "")
|
||||
|
||||
/**
|
||||
* Called in tgui_act() to process modal actions
|
||||
*
|
||||
* Arguments:
|
||||
* * action - The action passed by tgui
|
||||
* * params - The params passed by tgui
|
||||
*/
|
||||
/obj/item/uplink/hidden/proc/tgui_act_modal(action, list/params)
|
||||
. = TRUE
|
||||
var/id = params["id"]
|
||||
switch(ui_modal_act(src, action, params))
|
||||
if(UI_MODAL_OPEN)
|
||||
if(id == "become_contractor")
|
||||
ui_modal_boolean(src, id, "")
|
||||
return
|
||||
if(UI_MODAL_ANSWER)
|
||||
if(id == "become_contractor")
|
||||
if(text2num(params["answer"]))
|
||||
var/datum/antagonist/traitor/contractor/C = usr.mind.has_antag_datum(/datum/antagonist/traitor/contractor)
|
||||
C?.become_contractor(usr, src)
|
||||
return
|
||||
return FALSE
|
||||
|
||||
// I placed this here because of how relevant it is.
|
||||
// You place this in your uplinkable item to check if an uplink is active or not.
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
/// Delay in deci-seconds between two non-lethal attacks
|
||||
#define BATON_STUN_COOLDOWN 4 SECONDS
|
||||
/// Force of the telescopic baton when deployed
|
||||
#define BATON_TELESCOPIC_FORCE_DEPLOYED 10
|
||||
|
||||
/**
|
||||
* # Police Baton
|
||||
*
|
||||
@@ -18,6 +13,18 @@
|
||||
slot_flags = SLOT_BELT
|
||||
force = 12 //9 hit crit
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
// Settings
|
||||
/// Whether the baton can stun silicon mobs
|
||||
var/affect_silicon = FALSE
|
||||
/// The stun time (in life cycles) for non-silicons
|
||||
var/stun_time = 6 SECONDS_TO_LIFE_CYCLES
|
||||
/// The stun time (in life cycles) for silicons
|
||||
var/stun_time_silicon = 10 SECONDS_TO_LIFE_CYCLES
|
||||
/// Cooldown in deciseconds between two knockdowns
|
||||
var/cooldown = 4 SECONDS
|
||||
/// Sound to play when knocking someone down
|
||||
var/stun_sound = 'sound/effects/woodhit.ogg'
|
||||
// Variables
|
||||
/// Whether the baton is on cooldown
|
||||
var/on_cooldown = FALSE
|
||||
/// Whether the baton is toggled on (to allow attacking)
|
||||
@@ -39,27 +46,68 @@
|
||||
user.take_organ_damage(force * 2)
|
||||
return
|
||||
|
||||
if(user.a_intent == INTENT_HARM || isrobot(target)) // Lethal attack or it's a borg (can't knock them down!)
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
return ..()
|
||||
else if(!on_cooldown) // Non-lethal attack - knock them down
|
||||
if(on_cooldown)
|
||||
return
|
||||
if(issilicon(target) && !affect_silicon)
|
||||
return ..()
|
||||
else
|
||||
stun(target, user)
|
||||
|
||||
/**
|
||||
* Called when a target is about to be hit non-lethally.
|
||||
*
|
||||
* Arguments:
|
||||
* * target - The mob about to be hit
|
||||
* * user - The attacking user
|
||||
*/
|
||||
/obj/item/melee/classic_baton/proc/stun(mob/living/target, mob/living/user)
|
||||
if(issilicon(target))
|
||||
user.visible_message("<span class='danger'>[user] pulses [target]'s sensors with [src]!</span>",\
|
||||
"<span class='danger'>You pulse [target]'s sensors with [src]!</span>")
|
||||
on_silicon_stun(target, user)
|
||||
else
|
||||
// Check for shield/countering
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
|
||||
return
|
||||
return FALSE
|
||||
if(check_martial_counter(H, user))
|
||||
return
|
||||
// Visuals and sound
|
||||
user.do_attack_animation(target)
|
||||
playsound(target, 'sound/effects/woodhit.ogg', 75, TRUE, -1)
|
||||
add_attack_logs(user, target, "Stunned with [src]")
|
||||
target.visible_message("<span class='danger'>[user] has knocked down [target] with \the [src]!</span>", \
|
||||
"<span class='userdanger'>[user] has knocked down [target] with \the [src]!</span>")
|
||||
// Hit 'em
|
||||
target.LAssailant = iscarbon(user) ? user : null
|
||||
target.Weaken(3)
|
||||
on_cooldown = TRUE
|
||||
addtimer(CALLBACK(src, .proc/cooldown_finished), BATON_STUN_COOLDOWN)
|
||||
return FALSE
|
||||
user.visible_message("<span class='danger'>[user] knocks down [target] with [src]!</span>",\
|
||||
"<span class='danger'>You knock down [target] with [src]!</span>")
|
||||
on_non_silicon_stun(target, user)
|
||||
// Visuals and sound
|
||||
user.do_attack_animation(target)
|
||||
playsound(target, stun_sound, 75, TRUE, -1)
|
||||
add_attack_logs(user, target, "Stunned with [src]")
|
||||
// Hit 'em
|
||||
target.LAssailant = iscarbon(user) ? user : null
|
||||
target.Weaken(stun_time)
|
||||
on_cooldown = TRUE
|
||||
addtimer(CALLBACK(src, .proc/cooldown_finished), cooldown)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Called when a silicon has been stunned.
|
||||
*
|
||||
* Arguments:
|
||||
* * target - The hit mob
|
||||
* * user - The attacking user
|
||||
*/
|
||||
/obj/item/melee/classic_baton/proc/on_silicon_stun(mob/living/silicon/target, mob/living/user)
|
||||
target.flash_eyes(affect_silicon = TRUE)
|
||||
|
||||
/**
|
||||
* Called when a non-silicon has been stunned.
|
||||
*
|
||||
* Arguments:
|
||||
* * target - The hit mob
|
||||
* * user - The attacking user
|
||||
*/
|
||||
/obj/item/melee/classic_baton/proc/on_non_silicon_stun(mob/living/target, mob/living/user)
|
||||
return
|
||||
|
||||
/**
|
||||
* Called some time after a non-lethal attack
|
||||
@@ -86,13 +134,23 @@
|
||||
/obj/item/melee/classic_baton/telescopic
|
||||
name = "telescopic baton"
|
||||
desc = "A compact yet robust personal defense weapon. Can be concealed when folded."
|
||||
icon_state = "telebaton_0"
|
||||
item_state = null
|
||||
slot_flags = SLOT_BELT
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
needs_permit = FALSE
|
||||
force = 0
|
||||
on = FALSE
|
||||
/// Force when concealed
|
||||
var/force_off = 0
|
||||
/// Force when extended
|
||||
var/force_on = 10
|
||||
/// Item state when extended
|
||||
var/item_state_on = "nullrod"
|
||||
/// Icon state when concealed
|
||||
var/icon_state_off = "telebaton_0"
|
||||
/// Icon state when extended
|
||||
var/icon_state_on = "telebaton_1"
|
||||
/// Sound to play when concealing or extending
|
||||
var/extend_sound = 'sound/weapons/batonextend.ogg'
|
||||
/// Attack verbs when concealed (created on Initialize)
|
||||
var/static/list/attack_verb_off
|
||||
/// Attack verbs when extended (created on Initialize)
|
||||
@@ -103,31 +161,53 @@
|
||||
if(!attack_verb_off)
|
||||
attack_verb_off = list("hit", "poked")
|
||||
attack_verb_on = list("smacked", "struck", "cracked", "beaten")
|
||||
icon_state = icon_state_off
|
||||
force = force_off
|
||||
attack_verb = on ? attack_verb_on : attack_verb_off
|
||||
|
||||
/obj/item/melee/classic_baton/telescopic/attack_self(mob/user)
|
||||
on = !on
|
||||
icon_state = "telebaton_[on]"
|
||||
icon_state = on ? icon_state_on : icon_state_off
|
||||
if(on)
|
||||
to_chat(user, "<span class='warning'>You extend the baton.</span>")
|
||||
item_state = "nullrod"
|
||||
to_chat(user, "<span class='warning'>You extend [src].</span>")
|
||||
item_state = item_state_on
|
||||
w_class = WEIGHT_CLASS_BULKY //doesnt fit in backpack when its on for balance
|
||||
force = BATON_TELESCOPIC_FORCE_DEPLOYED //stunbaton damage
|
||||
force = force_on //stunbaton damage
|
||||
attack_verb = attack_verb_on
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You collapse the baton.</span>")
|
||||
to_chat(user, "<span class='notice'>You collapse [src].</span>")
|
||||
item_state = null //no sprite for concealment even when in hand
|
||||
slot_flags = SLOT_BELT
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
force = 0 //not so robust now
|
||||
force = force_off //not so robust now
|
||||
attack_verb = attack_verb_off
|
||||
// Update mob hand visuals
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.update_inv_l_hand()
|
||||
H.update_inv_r_hand()
|
||||
playsound(loc, 'sound/weapons/batonextend.ogg', 50, TRUE)
|
||||
// Update blood splatter
|
||||
if(blood_overlay)
|
||||
cut_overlay(blood_overlay)
|
||||
qdel(blood_overlay)
|
||||
add_blood_overlay(blood_overlay_color)
|
||||
playsound(loc, extend_sound, 50, TRUE)
|
||||
add_fingerprint(user)
|
||||
|
||||
#undef BATON_STUN_COOLDOWN
|
||||
#undef BATON_TELESCOPIC_FORCE_DEPLOYED
|
||||
/obj/item/melee/classic_baton/telescopic/blood_splatter_index()
|
||||
return "\ref[icon]-[icon_state]"
|
||||
|
||||
/obj/item/melee/classic_baton/telescopic/add_blood_overlay(color)
|
||||
var/index = blood_splatter_index()
|
||||
var/icon/blood_splatter_icon = GLOB.blood_splatter_icons[index]
|
||||
if(!blood_splatter_icon)
|
||||
blood_splatter_icon = icon(icon, icon_state)
|
||||
blood_splatter_icon.Blend("#ffffff", ICON_ADD)
|
||||
blood_splatter_icon.Blend(icon('icons/effects/blood.dmi', "itemblood"), ICON_MULTIPLY)
|
||||
blood_splatter_icon = fcopy_rsc(blood_splatter_icon)
|
||||
GLOB.blood_splatter_icons[index] = blood_splatter_icon
|
||||
|
||||
blood_overlay = image(blood_splatter_icon)
|
||||
blood_overlay.color = color
|
||||
blood_overlay_color = color
|
||||
add_overlay(blood_overlay)
|
||||
|
||||
Reference in New Issue
Block a user