diff --git a/code/__DEFINES/melee.dm b/code/__DEFINES/melee.dm index 0fa552661fe4..516e2009af13 100644 --- a/code/__DEFINES/melee.dm +++ b/code/__DEFINES/melee.dm @@ -15,6 +15,7 @@ #define MARTIALART_PRETERNISSTEALTH "preternis stealth" #define MARTIALART_EXPLOSIVEFIST "explosive fist" #define MARTIALART_GARDENWARFARE "garden warfare" +#define MARTIALART_ULTRAVIOLENCE "ultra violence" //Weapon stat defines @@ -23,4 +24,4 @@ #define ENCUMBRANCE_TIME "encumbrance_time" #define REACH "reach" #define DAMAGE_LOW "damage_low" -#define DAMAGE_HIGH "damage_high" \ No newline at end of file +#define DAMAGE_HIGH "damage_high" diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 23efc21e4c50..ce2566071dfa 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -510,6 +510,12 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." icon_state = "guardian_instealth" alerttooltipstyle = "parasite" +//IPC martial arts +/obj/screen/alert/ipcmartial + name = "Dashes" + desc = "This is how many dash charges you have." + icon_state = "ipcdash" + //SILICONS /atom/movable/screen/alert/nocell diff --git a/code/datums/martial.dm b/code/datums/martial.dm index f0b8840d6847..77443849ee5b 100644 --- a/code/datums/martial.dm +++ b/code/datums/martial.dm @@ -209,4 +209,4 @@ /datum/martial_art/proc/on_remove(mob/living/carbon/human/H) if(help_verb) remove_verb(H, help_verb) - return \ No newline at end of file + return diff --git a/code/datums/martial/ultra_violence.dm b/code/datums/martial/ultra_violence.dm new file mode 100644 index 000000000000..3bbb8bac1700 --- /dev/null +++ b/code/datums/martial/ultra_violence.dm @@ -0,0 +1,286 @@ +#define GUN_HAND "GHG" +#define POCKET_PISTOl "GG" +#define BLOOD_BURST "HHH" +#define MAX_DASH_DIST 3 + +/datum/martial_art/ultra_violence + name = "Ultra Violence" + id = MARTIALART_ULTRAVIOLENCE + no_guns = FALSE + deflection_chance = 0 + reroute_deflection = TRUE + help_verb = /mob/living/carbon/human/proc/ultra_violence_help + ///used to keep track of the dash stuff + var/dashing = FALSE + var/dashes = 3 + var/dash_timer = null + +/datum/martial_art/ultra_violence/can_use(mob/living/carbon/human/H) + return isipc(H) + +/datum/martial_art/ultra_violence/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D) + if(!can_use(A) || D.stat == DEAD)//stop hitting a corpse + return FALSE + + if(findtext(streak, POCKET_PISTOl)) + streak = "" + pocket_pistol(A,D) + speed_boost(A, 2, "pocketpistol") + return TRUE + + if(A == D) //you can pull your gun out by "grabbing" yourself + return FALSE + + if(findtext(streak, BLOOD_BURST)) + streak = "" + blood_burst(A,D) + speed_boost(A, 6, "bloodburst") + return TRUE + + if(D.health <= HEALTH_THRESHOLD_CRIT) //no getting shotguns off people that aren't fighting back + return FALSE + + if(findtext(streak, GUN_HAND)) + streak = "" + gun_hand(A) + speed_boost(A, 6, "gunhand") + return TRUE + +/datum/martial_art/ultra_violence/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) + return TRUE //no disarming + +/datum/martial_art/ultra_violence/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D) + add_to_streak("G",D) + check_streak(A,D) + return TRUE //no grabbing either + +/datum/martial_art/ultra_violence/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) + add_to_streak("H",D) + if(check_streak(A,D)) + return FALSE + return FALSE + +/datum/martial_art/ultra_violence/proc/speed_boost(mob/living/carbon/human/A, duration, tag) + A.add_movespeed_modifier(tag, update=TRUE, priority=101, multiplicative_slowdown = -0.5, blacklisted_movetypes=(FLYING|FLOATING)) + addtimer(CALLBACK(src, .proc/remove_boost, A, tag), duration, TIMER_UNIQUE|TIMER_OVERRIDE) + +/datum/martial_art/ultra_violence/proc/remove_boost(mob/living/carbon/human/A, tag) + A.remove_movespeed_modifier(tag) + +/datum/martial_art/ultra_violence/proc/blood_burst(mob/living/carbon/human/A, mob/living/carbon/human/D) + + A.add_mob_blood(D) + D.bleed(30) + D.add_splatter_floor(D.loc, TRUE) + + var/obj/effect/gibspawner/blood = new /obj/effect/gibspawner/generic(D.loc) + blood.throw_at(get_edge_target_turf(blood, pick(GLOB.alldirs)), rand(1,1), 10) + + if(D.health <= HEALTH_THRESHOLD_FULLCRIT) + D.bleed(150) + D.death() + A.adjustBruteLoss(-40, FALSE, FALSE, BODYPART_ANY) + A.adjustFireLoss(-40, FALSE, FALSE, BODYPART_ANY) //incentivising execution + var/obj/effect/gibspawner/moreblood = new /obj/effect/gibspawner/generic(D.loc) + moreblood.throw_at(get_edge_target_turf(moreblood, pick(GLOB.alldirs)), rand(1,3), 10) + var/obj/effect/gibspawner/evenmoreblood = new /obj/effect/gibspawner/generic(D.loc) + evenmoreblood.throw_at(get_edge_target_turf(evenmoreblood, pick(GLOB.alldirs)), rand(1,3), 10)//yes, technically this is all gibs, but still + + +/mob/living/carbon/human/proc/ultra_violence_help() + set name = "Cyber Grind" + set desc = "You mentally practice the teachings of Ultra Violence." + set category = "Ultra Violence" + to_chat(usr, "You search your data banks for techniques of Ultra Violence.") + + to_chat(usr, span_notice("This module has made you a hell-bound killing machine.")) + to_chat(usr, span_notice("You are immune to stuns and cannot be slowed by damage.")) + to_chat(usr, span_notice("You will deflect emps while throwmode is enabled, throwing a lightning bolt if your hands are empty.")) + to_chat(usr, span_notice("After deflecting, or getting hit by an emp you will be immune to more for 5 seconds.")) + to_chat(usr, span_warning("Your disarm has been replaced with a charged-based dash system.")) + to_chat(usr, span_warning("You cannot grab either, JUST KILL THEM!")) //seriously, no pushing or clinching, that's boring, just kill + to_chat(usr, span_notice("Getting covered in blood will heal you.")) + + to_chat(usr, "[span_notice("Disarm Intent")]: Dash in a direction.") + to_chat(usr, "[span_notice("Pocket Revolver")]: Grab Grab. Puts a loaded revolver in your hand for one shot. Target must be living, but can be yourself.") + to_chat(usr, "[span_notice("Gun Hand")]: Grab Harm Grab. Puts a loaded shotgun in your hand for one shot. Target must be living and not in crit.") + to_chat(usr, "[span_notice("Blood Burst")]: Harm Harm Harm. Explodes blood from the target, covering you in blood and healing for a bit. Executes people in hardcrit exploding more blood everywhere.") + to_chat(usr, span_notice("Completing any combo will give a speed buff with a duration scaling based on combo difficulty.")) + +/datum/martial_art/ultra_violence/teach(mob/living/carbon/human/H, make_temporary=0) + ..() + H.dna.species.attack_sound = 'sound/weapons/shotgunshot.ogg' + H.dna.species.punchdamagelow += 4 + H.dna.species.punchdamagehigh += 4 //no fancy comboes, just punches + H.dna.species.punchstunthreshold += 4 + ADD_TRAIT(H, TRAIT_NOSOFTCRIT, "martial") + ADD_TRAIT(H, TRAIT_NOLIMBDISABLE, "martial") + ADD_TRAIT(H, TRAIT_IGNOREDAMAGESLOWDOWN, "martial") + ADD_TRAIT(H, TRAIT_NO_STUN_WEAPONS, "martial") + ADD_TRAIT(H, TRAIT_STUNIMMUNE, "martial")///mainly so emps don't end you instantly, they still do damage though + H.throw_alert("dash_charge", /obj/screen/alert/ipcmartial, dashes+1) + usr.click_intercept = src //probably breaks something, don't know what though + H.dna.species.GiveSpeciesFlight(H)//because... c'mon + +/datum/martial_art/ultra_violence/on_remove(mob/living/carbon/human/H) + ..() + H.dna.species.attack_sound = initial(H.dna.species.attack_sound) //back to flimsy tin tray punches + H.dna.species.punchdamagelow -= 4 + H.dna.species.punchdamagehigh -= 4 + H.dna.species.punchstunthreshold -= 4 + REMOVE_TRAIT(H, TRAIT_NOSOFTCRIT, "martial") + REMOVE_TRAIT(H, TRAIT_NOLIMBDISABLE, "martial") + REMOVE_TRAIT(H, TRAIT_IGNOREDAMAGESLOWDOWN, "martial") + REMOVE_TRAIT(H, TRAIT_NO_STUN_WEAPONS, "martial") + REMOVE_TRAIT(H, TRAIT_STUNIMMUNE, "martial") + deltimer(dash_timer) + H.clear_alert("dash_charge") + usr.click_intercept = null //un-breaks the thing that i don't know is broken + //not likely they'll lose the martial art i guess, so i guess they can keep the wings since i don't know how to remove them + +/*--------------------------------------------------------------- + + start of pocket pistol section + +---------------------------------------------------------------*/ +/datum/martial_art/ultra_violence/proc/pocket_pistol(mob/living/carbon/human/A) + var/obj/item/gun/ballistic/revolver/martial/gun = new /obj/item/gun/ballistic/revolver/martial (A) ///I don't check does the user have an item in a hand, because it is a martial art action, and to use it... you need to have a empty hand + gun.gun_owner = A + A.put_in_hands(gun) + to_chat(A, span_notice("You whip out your revolver.")) + streak = "" + +/obj/item/gun/ballistic/revolver/martial + desc = "Your trusty revolver." + mag_type = /obj/item/ammo_box/magazine/internal/cylinder/rev38 + can_be_sawn_off = FALSE + var/mob/gun_owner + +/obj/item/gun/ballistic/revolver/martial/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_NODROP, "martial") + +/obj/item/gun/ballistic/revolver/martial/process_chamber(empty_chamber, from_firing, chamber_next_round) + . = ..() + qdel(src) + +/obj/item/gun/ballistic/revolver/martial/attack_self(mob/living/A) + to_chat(A, span_notice("You stash your revolver away.")) + qdel(src) + +/*--------------------------------------------------------------- + + end of pocket pistol section + +---------------------------------------------------------------*/ +/*--------------------------------------------------------------- + + start of shotgun punch section + +---------------------------------------------------------------*/ + +/datum/martial_art/ultra_violence/proc/gun_hand(mob/living/carbon/human/A) + var/obj/item/gun/ballistic/shotgun/martial/gun = new /obj/item/gun/ballistic/shotgun/martial (A) ///I don't check does the user have an item in a hand, because it is a martial art action, and to use it... you need to have a empty hand + gun.gun_owner = A + A.put_in_hands(gun) + to_chat(A, span_notice("You ready your gun hand.")) + streak = "" + +/obj/item/gun/ballistic/shotgun/martial + desc = "Your hand is also a shotgun." + lefthand_file = null ///We don't want it to be visible inhands because it is your hand + righthand_file = null + mag_type = /obj/item/ammo_box/magazine/internal/shot/lethal/martial + can_be_sawn_off = FALSE + var/mob/gun_owner + +/obj/item/ammo_box/magazine/internal/shot/lethal/martial + ammo_type = /obj/item/ammo_casing/shotgun/buckshot/martial + +/obj/item/ammo_casing/shotgun/buckshot/martial + projectile_type = /obj/item/projectile/bullet/pellet/shotgun_buckshot/martial + pellets = 6 + variance = 15 + +/obj/item/projectile/bullet/pellet/shotgun_buckshot/martial + wound_falloff_tile = -1.5 // more wounds + +/obj/item/projectile/bullet/pellet/shotgun_buckshot/martial/on_hit(atom/target, blocked)//the real reason i made a whole new ammo type + . = ..() + if(ishuman(target) && !blocked) + var/mob/living/carbon/human/H = target + H.add_splatter_floor(H.loc, TRUE)//janitors everywhere cry when they hear that an ipc is going off + + + +/obj/item/gun/ballistic/shotgun/martial/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_NODROP, "martial") + +/obj/item/gun/ballistic/shotgun/martial/process_chamber(empty_chamber, from_firing, chamber_next_round) + . = ..() + qdel(src) + +/obj/item/gun/ballistic/shotgun/martial/attack_self(mob/living/A) + to_chat(A, span_notice("You relax your gun hand.")) + qdel(src) + +/*--------------------------------------------------------------- + + end of shotgun punch section + +---------------------------------------------------------------*/ +/*--------------------------------------------------------------- + start of dash section + i know, it's super snowflakey to do it this way instead of just making it an ability + however, i want it to be more fluid by having it be in place of an intent +---------------------------------------------------------------*/ + +/datum/martial_art/ultra_violence/proc/regen_dash(mob/living/carbon/human/H) + dashes += 1 + dashes = clamp(dashes, 0, 3) + if(dashes == 3) + deltimer(dash_timer)//stop regen when full + H.throw_alert("dash_charge", /obj/screen/alert/ipcmartial, dashes+1) + +/datum/martial_art/ultra_violence/proc/InterceptClickOn(mob/living/carbon/human/H, params, atom/A) + if(H.a_intent == INTENT_DISARM && !H.IsUnconscious()) + dash(H, A) + +/datum/martial_art/ultra_violence/proc/dash(mob/living/carbon/human/H, atom/A) + if(dashing) + return + + if(dashes <= 0) + to_chat(H, span_alertsyndie("You are out of dash charges!")) + return + + else + playsound(H, 'sound/effects/space_wind_big.ogg', 50) + dash_timer = addtimer(CALLBACK(src, .proc/regen_dash, H), 4 SECONDS, TIMER_LOOP|TIMER_UNIQUE|TIMER_STOPPABLE)//start regen + REMOVE_TRAIT(H, TRAIT_STUNIMMUNE, "martial") //can't immobilize if has stun immune, technically means they can be stunned mid-dash + H.Immobilize(30 SECONDS) //to prevent cancelling the dash + dashing = TRUE + H.throw_at(A, MAX_DASH_DIST, 1.5, H, FALSE, TRUE, callback = CALLBACK(src, .proc/dash_end, H)) + dashes -= 1 + H.throw_alert("dash_charge", /obj/screen/alert/ipcmartial, dashes+1) + +/datum/martial_art/ultra_violence/proc/dash_end(mob/living/carbon/human/H) + dashing = FALSE + H.SetImmobilized(0 SECONDS) + ADD_TRAIT(H, TRAIT_STUNIMMUNE, "martial") + +/datum/martial_art/ultra_violence/handle_throw(atom/hit_atom, mob/living/carbon/human/A) + if(!dashing) + return ..() + return TRUE + +/*--------------------------------------------------------------- + + end of dash section + +---------------------------------------------------------------*/ + +#undef GUN_HAND +#undef BLOOD_BURST +#undef MAX_DASH_DIST diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 309c24502f9e..e27fc8c33832 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -646,6 +646,7 @@ if(length(atom_colours) >= WASHABLE_COLOUR_PRIORITY && atom_colours[WASHABLE_COLOUR_PRIORITY]) remove_atom_colour(WASHABLE_COLOUR_PRIORITY) return TRUE + return FALSE //needs this here so it won't return true if things don't wash ///Is this atom in space /atom/proc/isinspace() diff --git a/code/game/objects/items/granters.dm b/code/game/objects/items/granters.dm index 9fdfa2dca836..6d67eec75aaa 100644 --- a/code/game/objects/items/granters.dm +++ b/code/game/objects/items/granters.dm @@ -5,6 +5,7 @@ due_date = 0 // Game time in deciseconds unique = 1 // 0 Normal book, 1 Should not be treated as normal book, unable to be copied, unable to be modified var/list/remarks = list() //things to read about while learning. + var/ordered = FALSE //determines if the remarks should display in order rather than randomly var/pages_to_mastery = 3 //Essentially controls how long a mob must keep the book in his hand to actually successfully learn var/reading = FALSE //sanity var/oneuse = TRUE //default this is true, but admins can var this to 0 if we wanna all have a pass around of the rod form book @@ -13,7 +14,9 @@ /obj/item/book/granter/proc/turn_page(mob/user) playsound(user, pick('sound/effects/pageturn1.ogg','sound/effects/pageturn2.ogg','sound/effects/pageturn3.ogg'), 30, 1) if(do_after(user, 5 SECONDS, user)) - if(remarks.len) + if(remarks.len && ordered) + to_chat(user, span_notice("[popleft(remarks)]")) + else if(remarks.len) to_chat(user, span_notice("[pick(remarks)]")) else to_chat(user, span_notice("You keep reading...")) @@ -441,7 +444,6 @@ if(oneuse == TRUE) desc = "It's completely blank." name = "empty scroll" - icon_state = "blankscroll" /obj/item/book/granter/martial/preternis_stealth martial = /datum/martial_art/stealth @@ -509,6 +511,30 @@ if(oneuse == TRUE) desc = "It's completely blank." +/obj/item/book/granter/martial/ultra_violence + martial = /datum/martial_art/ultra_violence + name = "Version one upgrade module" + martialname = "Ultra Violence" + desc = "A module full of forbidden techniques from a horrific event long since passed, or perhaps yet to come." + greet = "You have installed how to perform Ultra Violence! You are able to redirect electromagnetic pulses, \ + blood heals you, and you CANNOT BE STOPPED. You can mentally practice by using Cyber Grind in the Ultra Violence tab." + icon = 'icons/obj/module.dmi' + icon_state = "cyborg_upgrade" + remarks = list("MANKIND IS DEAD.", "BLOOD IS FUEL.", "HELL IS FULL.") + ordered = TRUE + +/obj/item/book/granter/martial/ultra_violence/already_known(mob/user) + if(!isipc(user)) + to_chat(user, span_warning("You don't understand what to do with this strange electronic device.")) + return TRUE + return ..() + +/obj/item/book/granter/martial/ultra_violence/onlearned(mob/living/carbon/user) + ..() + if(oneuse == TRUE) + desc = "It's a damaged upgrade module." + name = "damaged board" + // I did not include mushpunch's grant, it is not a book and the item does it just fine. diff --git a/code/modules/mob/living/carbon/human/species_types/IPC.dm b/code/modules/mob/living/carbon/human/species_types/IPC.dm index 00ce2687b9a2..df4d4d2bcacb 100644 --- a/code/modules/mob/living/carbon/human/species_types/IPC.dm +++ b/code/modules/mob/living/carbon/human/species_types/IPC.dm @@ -206,6 +206,14 @@ datum/species/ipc/on_species_loss(mob/living/carbon/C) to_chat(H, "Alert: Internal temperature regulation systems offline; thermal damage sustained. Shutdown imminent.") H.visible_message("[H]'s cooling system fans stutter and stall. There is a faint, yet rapid beeping coming from inside their chassis.") + if(H.mind.martial_art && H.mind.martial_art.id == "ultra violence" && (H.blood_in_hands > 0 || H?.wash(CLEAN_TYPE_BLOOD)))//ipc martial art blood heal check + H.blood_in_hands = 0 + H.wash(CLEAN_TYPE_BLOOD) + to_chat(H,"You absorb the blood covering you to heal.") + H.add_splatter_floor(H.loc, TRUE)//just for that little bit more blood + H.adjustBruteLoss(-20, FALSE, FALSE, BODYPART_ANY)//getting covered in blood isn't actually that common + H.adjustFireLoss(-20, FALSE, FALSE, BODYPART_ANY) + /datum/species/ipc/eat_text(fullness, eatverb, obj/O, mob/living/carbon/C, mob/user) . = TRUE if(C == user) @@ -231,4 +239,40 @@ datum/species/ipc/on_species_loss(mob/living/carbon/C) C.visible_message(span_danger("[user] attempts to pour [O] down [C]'s port!"), \ span_userdanger("[user] attempts to pour [O] down [C]'s port!")) +/*------------------------ + +ipc martial arts stuff + +--------------------------*/ +/datum/species/ipc/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) + . = ..() + if(H.mind.martial_art && H.mind.martial_art.id == "ultra violence") + if(H.reagents.has_reagent(/datum/reagent/blood, 30))//BLOOD IS FUEL eh, might as well let them drink it + H.adjustBruteLoss(-25, FALSE, FALSE, BODYPART_ANY) + H.adjustFireLoss(-25, FALSE, FALSE, BODYPART_ANY) + H.reagents.del_reagent(chem.type)//only one big tick of healing + + +/datum/species/ipc/spec_emp_act(mob/living/carbon/human/H, severity) + if(H.mind.martial_art && H.mind.martial_art.id == "ultra violence") + if(H.in_throw_mode)//if countering the emp + add_empproof(H) + throw_lightning(H) + else//if just getting hit + addtimer(CALLBACK(src, .proc/add_empproof, H), 1, TIMER_UNIQUE) + addtimer(CALLBACK(src, .proc/remove_empproof, H), 5 SECONDS, TIMER_OVERRIDE | TIMER_UNIQUE)//removes the emp immunity after a 5 second delay + +/datum/species/ipc/proc/throw_lightning(mob/living/carbon/human/H) + siemens_coeff = 0 + tesla_zap(H, 10, 20000, TESLA_MOB_DAMAGE | TESLA_MOB_STUN) + siemens_coeff = initial(siemens_coeff) + +/datum/species/ipc/proc/add_empproof(mob/living/carbon/human/H) + H.AddComponent(/datum/component/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_CONTENTS) + +/datum/species/ipc/proc/remove_empproof(mob/living/carbon/human/H) + var/datum/component/empprotection/ipcmartial = H.GetExactComponent(/datum/component/empprotection) + if(ipcmartial) + ipcmartial.Destroy() + #undef CONCIOUSAY diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 341e8b9775e5..54ea42fa6430 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -228,7 +228,7 @@ return if(target == user && user.zone_selected != BODY_ZONE_PRECISE_MOUTH) //so we can't shoot ourselves (unless mouth selected) return - if(ismob(target) && user.a_intent == INTENT_GRAB) + if(ismob(target) && user.a_intent == INTENT_GRAB && !user.mind.martial_art)//remove gunpoint from ipc martial art, it's slow for(var/datum/component/gunpoint/G in user.GetComponents(/datum/component/gunpoint)) if(G && G.weapon == src) //spam check return diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi index 80c148ec967c..76301089081c 100644 Binary files a/icons/mob/screen_alert.dmi and b/icons/mob/screen_alert.dmi differ diff --git a/yogstation.dme b/yogstation.dme index 948d5e8ed184..59adbf1c1ffb 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -578,6 +578,7 @@ #include "code\datums\martial\plasma_fist.dm" #include "code\datums\martial\psychotic_brawl.dm" #include "code\datums\martial\sleeping_carp.dm" +#include "code\datums\martial\ultra_violence.dm" #include "code\datums\martial\wrestling.dm" #include "code\datums\materials\_material.dm" #include "code\datums\materials\basemats.dm" diff --git a/yogstation/code/modules/uplink/uplink_item.dm b/yogstation/code/modules/uplink/uplink_item.dm index 5f3010a46cfb..8df22bf8e97b 100644 --- a/yogstation/code/modules/uplink/uplink_item.dm +++ b/yogstation/code/modules/uplink/uplink_item.dm @@ -166,6 +166,15 @@ item = /obj/item/book/granter/martial/explosive_fist restricted_species = list("plasmaman") +/datum/uplink_item/race_restricted/ultra_violence + name = "Version one upgrade module" + desc = "A module full of forbidden techniques that will make you capable of ultimate bloodshed." + cost = 20 + item = /obj/item/book/granter/martial/ultra_violence + restricted_species = list("ipc") + include_objectives = list(/datum/objective/hijack, /datum/objective/martyr) + cant_discount = TRUE + /datum/uplink_item/stealthy_weapons/camera_flash name = "Camera Flash" desc = "A camera with an upgraded flashbulb. Can be used much like a handheld flash except with a longer cooldown between uses, allowing the bulb to cool down; avoid burning out altogether."