diff --git a/code/__DEFINES/movespeed_modification.dm b/code/__DEFINES/movespeed_modification.dm index 1883df6e8e..5d35da5382 100644 --- a/code/__DEFINES/movespeed_modification.dm +++ b/code/__DEFINES/movespeed_modification.dm @@ -68,4 +68,6 @@ #define MOVESPEED_ID_SHOVE "SHOVE" -#define MOVESPEED_ID_MKULTRA "MKULTRA" \ No newline at end of file +#define MOVESPEED_ID_MKULTRA "MKULTRA" + +#define MOVESPEED_ID_ELECTROSTAFF "ELECTROSTAFF" \ No newline at end of file diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index f42948f4ae..40d3550d1b 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -90,6 +90,9 @@ #define STATUS_EFFECT_NO_COMBAT_MODE /datum/status_effect/no_combat_mode //Wont allow combat mode and will disable it #define STATUS_EFFECT_MESMERIZE /datum/status_effect/no_combat_mode/mesmerize //Just reskinned no_combat_mode + +#define STATUS_EFFECT_ELECTROSTAFF /datum/status_effect/electrostaff //slows down victim + ///////////// // NEUTRAL // ///////////// diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index c694f27d64..ae535b1db3 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -609,6 +609,19 @@ icon_state = "ichorial_stain" alerttooltipstyle = "clockcult" +/datum/status_effect/electrostaff + id = "electrostaff" + alert_type = null + status_type = STATUS_EFFECT_REPLACE + +/datum/status_effect/electrostaff/on_creation(mob/living/new_owner, set_duration) + if(isnum(set_duration)) + duration = set_duration + . = ..() + owner.add_movespeed_modifier(MOVESPEED_ID_ELECTROSTAFF, multiplicative_slowdown = 1, movetypes = GROUND) + +/datum/status_effect/electrostaff/on_remove() + owner.remove_movespeed_modifier(MOVESPEED_ID_ELECTROSTAFF) //GOLEM GANG diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index 29921c4584..aa97aa821a 100755 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -16,6 +16,7 @@ /obj/item/melee/baton, /obj/item/ammo_box/magazine/recharge, /obj/item/modular_computer, + /obj/item/twohanded/electrostaff, /obj/item/gun/ballistic/automatic/magrifle)) /obj/machinery/recharger/RefreshParts() diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm index 0cd60804db..24cb265093 100644 --- a/code/game/objects/items/twohanded.dm +++ b/code/game/objects/items/twohanded.dm @@ -24,7 +24,7 @@ * Twohanded */ /obj/item/twohanded - var/wielded = 0 + var/wielded = FALSE var/force_unwielded // default to null, the number force will be set to on unwield() var/force_wielded // same as above but for wield() var/wieldsound = null @@ -1017,6 +1017,259 @@ user.client.pixel_x = 0 user.client.pixel_y = 0 +/obj/item/twohanded/electrostaff + icon = 'icons/obj/items_and_weapons.dmi' + icon_state = "electrostaff" + item_state = "electrostaff" + lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi' + name = "riot suppression electrostaff" + desc = "A large quarterstaff, with massive silver electrodes mounted at the end." + w_class = WEIGHT_CLASS_HUGE + slot_flags = ITEM_SLOT_BACK | ITEM_SLOT_OCLOTHING + force_unwielded = 5 + force_wielded = 10 + throwforce = 15 //if you are a madman and finish someone off with this, power to you. + throw_speed = 1 + item_flags = NO_MAT_REDEMPTION | SLOWS_WHILE_IN_HAND + block_chance = 30 + attack_verb = list("struck", "beaten", "thwacked", "pulped") + total_mass = 5 //yeah this is a heavy thing, beating people with it while it's off is not going to do you any favors. (to curb stun-kill rampaging without it being on) + var/obj/item/stock_parts/cell/cell = /obj/item/stock_parts/cell/high + var/on = FALSE + var/can_block_projectiles = FALSE //can't block guns + var/lethal_cost = 400 //10000/400*20 = 500. decent enough? + var/lethal_damage = 20 + var/lethal_stam_cost = 4 + var/stun_cost = 333 //10000/333*25 = 750. stunbatons are at time of writing 10000/1000*49 = 490. + var/stun_status_effect = STATUS_EFFECT_ELECTROSTAFF //a small slowdown effect + var/stun_stamdmg = 40 + var/stun_status_duration = 25 + var/stun_stam_cost = 3.5 + +/obj/item/twohanded/electrostaff/Initialize(mapload) + . = ..() + if(ispath(cell)) + cell = new cell + +/obj/item/twohanded/electrostaff/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/twohanded/electrostaff/get_cell() + . = cell + if(iscyborg(loc)) + var/mob/living/silicon/robot/R = loc + . = R.get_cell() + +/obj/item/twohanded/electrostaff/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + if(!on) + return FALSE + if((attack_type == PROJECTILE_ATTACK) && !can_block_projectiles) + return FALSE + return ..() + +/obj/item/twohanded/electrostaff/proc/min_hitcost() + return min(stun_cost, lethal_cost) + +/obj/item/twohanded/electrostaff/proc/turn_on(mob/user, silent = FALSE) + if(on) + return + if(!cell) + if(user) + to_chat(user, "[src] has no cell.") + return + if(cell.charge < min_hitcost()) + if(user) + to_chat(user, "[src] is out of charge.") + return + on = TRUE + START_PROCESSING(SSobj, src) + if(user) + to_chat(user, "You turn [src] on.") + update_icon() + if(!silent) + playsound(src, "sparks", 75, 1, -1) + +/obj/item/twohanded/electrostaff/proc/turn_off(mob/user, silent = FALSE) + if(!on) + return + if(user) + to_chat(user, "You turn [src] off.") + on = FALSE + STOP_PROCESSING(SSobj, src) + update_icon() + if(!silent) + playsound(src, "sparks", 75, 1, -1) + +/obj/item/twohanded/electrostaff/proc/toggle(mob/user, silent = FALSE) + if(on) + turn_off(user, silent) + else + turn_on(user, silent) + +/obj/item/twohanded/electrostaff/wield(mob/user) + . = ..() + if(wielded) + turn_on(user) + add_fingerprint(user) + +/obj/item/twohanded/electrostaff/unwield(mob/user) + . = ..() + if(!wielded) + turn_off(user) + add_fingerprint(user) + +/obj/item/twohanded/electrostaff/update_icon() + . = ..() + if(!wielded) + icon_state = "electrostaff_3" + item_state = "electrostaff" + else + icon_state = item_state = (on? "electrostaff_1" : "electrostaff_3") + set_light(7, on? 1 : 0, LIGHT_COLOR_CYAN) + +/obj/item/twohanded/electrostaff/examine(mob/living/user) + . = ..() + if(cell) + . += "The cell charge is [round(cell.percent())]%." + else + . += "There is no cell installed!" + +/obj/item/twohanded/electrostaff/attackby(obj/item/W, mob/user, params) + if(istype(W, /obj/item/stock_parts/cell)) + var/obj/item/stock_parts/cell/C = W + if(cell) + to_chat(user, "[src] already has a cell!") + else + if(C.maxcharge < min_hit_cost()) + to_chat(user, "[src] requires a higher capacity cell.") + return + if(!user.transferItemToLoc(W, src)) + return + cell = C + to_chat(user, "You install a cell in [src].") + + else if(W.tool_behaviour == TOOL_SCREWDRIVER) + if(cell) + cell.update_icon() + cell.forceMove(get_turf(src)) + cell = null + to_chat(user, "You remove the cell from [src].") + turn_off(user, TRUE) + else + return ..() + +/obj/item/twohanded/electrostaff/process() + deductcharge(50) //Wasteful! + +/obj/item/twohanded/electrostaff/proc/min_hit_cost() + return min(lethal_cost, stun_cost) + +/obj/item/twohanded/electrostaff/proc/deductcharge(amount) + var/obj/item/stock_parts/cell/C = get_cell() + if(!C) + turn_off() + return FALSE + C.use(min(amount, C.charge)) + if(QDELETED(src)) + return FALSE + if(C.charge < min_hit_cost()) + turn_off() + +/obj/item/twohanded/electrostaff/attack(mob/living/target, mob/living/user) + if(user.getStaminaLoss() >= STAMINA_SOFTCRIT)//CIT CHANGE - makes it impossible to baton in stamina softcrit + to_chat(user, "You're too exhausted for that.")//CIT CHANGE - ditto + return //CIT CHANGE - ditto + if(on && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) + clowning_around(user) //ouch! + return + if(iscyborg(target)) + ..() + return + if(target.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK)) //No message; check_shields() handles that + playsound(target, 'sound/weapons/genhit.ogg', 50, 1) + return FALSE + if(user.a_intent != INTENT_HARM) + if(stun_act(target, user)) + user.do_attack_animation(target) + user.adjustStaminaLossBuffered(stun_stam_cost) + return + else if(!harm_act(target, user)) + return ..() //if you can't fry them just beat them with it + else //we did harm act them + user.do_attack_animation(target) + user.adjustStaminaLossBuffered(lethal_stam_cost) + +/obj/item/twohanded/electrostaff/proc/stun_act(mob/living/target, mob/living/user, no_charge_and_force = FALSE) + var/stunforce = stun_stamdmg + if(!no_charge_and_force) + if(!on) + target.visible_message("[user] has bapped [target] with [src]. Luckily it was off.", \ + "[user] has bapped you with [src]. Luckily it was off") + turn_off() //if it wasn't already off + return FALSE + var/obj/item/stock_parts/cell/C = get_cell() + var/chargeleft = C.charge + deductcharge(stun_cost) + if(QDELETED(src) || QDELETED(C)) //boom + return FALSE + if(chargeleft < stun_cost) + stunforce *= round(chargeleft/stun_cost, 0.1) + target.adjustStaminaLoss(stunforce) + target.apply_effect(EFFECT_STUTTER, stunforce) + SEND_SIGNAL(target, COMSIG_LIVING_MINOR_SHOCK) + if(user) + target.lastattacker = user.real_name + target.lastattackerckey = user.ckey + target.visible_message("[user] has shocked [target] with [src]!", \ + "[user] has shocked you with [src]!") + log_combat(user, user, "stunned with an electrostaff") + playsound(src, 'sound/weapons/staff.ogg', 50, 1, -1) + target.apply_status_effect(stun_status_effect, stun_status_duration) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + H.forcesay(GLOB.hit_appends) + return TRUE + +/obj/item/twohanded/electrostaff/proc/harm_act(mob/living/target, mob/living/user, no_charge_and_force = FALSE) + var/lethal_force = lethal_damage + if(!no_charge_and_force) + if(!on) + return FALSE //standard item attack + var/obj/item/stock_parts/cell/C = get_cell() + var/chargeleft = C.charge + deductcharge(lethal_cost) + if(QDELETED(src) || QDELETED(C)) //boom + return FALSE + if(chargeleft < stun_cost) + lethal_force *= round(chargeleft/lethal_cost, 0.1) + target.adjustFireLoss(lethal_force) //good against ointment spam + SEND_SIGNAL(target, COMSIG_LIVING_MINOR_SHOCK) + if(user) + target.lastattacker = user.real_name + target.lastattackerckey = user.ckey + target.visible_message("[user] has seared [user] with [src]!", \ + "[user] has seared you with [src]!") + log_combat(user, user, "burned with an electrostaff") + playsound(src, 'sound/weapons/sear.ogg', 50, 1, -1) + return TRUE + +/obj/item/twohanded/electrostaff/proc/clowning_around(mob/living/user) + user.visible_message("[user] accidentally hits [user.p_them()]self with [src]!", \ + "You accidentally hit yourself with [src]!") + SEND_SIGNAL(user, COMSIG_LIVING_MINOR_SHOCK) + harm_act(user, user, TRUE) + stun_act(user, user, TRUE) + deductcharge(lethal_cost) + +/obj/item/twohanded/electrostaff/emp_act(severity) + . = ..() + if (!(. & EMP_PROTECT_SELF)) + turn_off() + if(!iscyborg(loc)) + deductcharge(1000 / severity, TRUE, FALSE) + /obj/item/twohanded/broom name = "broom" desc = "This is my BROOMSTICK! It can be used manually or braced with two hands to sweep items as you move. It has a telescopic handle for compact storage." //LIES @@ -1078,4 +1331,4 @@ /obj/item/twohanded/broom/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J) //bless you whoever fixes this copypasta J.put_in_cart(src, user) J.mybroom=src - J.update_icon() \ No newline at end of file + J.update_icon() diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index 88c8d51479..bec1c893ae 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -265,12 +265,15 @@ new /obj/item/clothing/head/helmet/alt(src) new /obj/item/clothing/mask/gas/sechailer(src) new /obj/item/clothing/suit/armor/bulletproof(src) + /obj/structure/closet/secure_closet/lethalshots - name = "shotgun lethal rounds" + name = "lethal ammunition and riot staves" req_access = list(ACCESS_ARMORY) icon_state = "tac" /obj/structure/closet/secure_closet/lethalshots/PopulateContents() ..() + new /obj/item/twohanded/electrostaff(src) + new /obj/item/twohanded/electrostaff(src) for(var/i in 1 to 3) new /obj/item/storage/box/lethalshot(src) diff --git a/icons/mob/back.dmi b/icons/mob/back.dmi index 7a28827903..1a2c0e189a 100644 Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ diff --git a/icons/mob/inhands/weapons/staves_lefthand.dmi b/icons/mob/inhands/weapons/staves_lefthand.dmi index 8b96b84236..ca1694b1f1 100644 Binary files a/icons/mob/inhands/weapons/staves_lefthand.dmi and b/icons/mob/inhands/weapons/staves_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/staves_righthand.dmi b/icons/mob/inhands/weapons/staves_righthand.dmi index 202bab9e21..4d366d950f 100644 Binary files a/icons/mob/inhands/weapons/staves_righthand.dmi and b/icons/mob/inhands/weapons/staves_righthand.dmi differ diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi index 30c43985fa..41f2693800 100644 Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ diff --git a/icons/obj/items_and_weapons.dmi b/icons/obj/items_and_weapons.dmi index 7058b9918b..bdad12b0b6 100644 Binary files a/icons/obj/items_and_weapons.dmi and b/icons/obj/items_and_weapons.dmi differ diff --git a/sound/weapons/staff.ogg b/sound/weapons/staff.ogg new file mode 100644 index 0000000000..35b42dfd8d Binary files /dev/null and b/sound/weapons/staff.ogg differ