diff --git a/baystation12.dme b/baystation12.dme index e49f506a2f4e7..3e66613f03988 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -50,6 +50,7 @@ #include "code\__defines\integrated_circuits.dm" #include "code\__defines\inventory_sizes.dm" #include "code\__defines\is_helpers.dm" +#include "code\__defines\items.dm" #include "code\__defines\items_clothing.dm" #include "code\__defines\jobs.dm" #include "code\__defines\languages.dm" @@ -79,6 +80,7 @@ #include "code\__defines\subsystems.dm" #include "code\__defines\targeting.dm" #include "code\__defines\temperature.dm" +#include "code\__defines\tools_and_qualities.dm" #include "code\__defines\topic.dm" #include "code\__defines\turfs.dm" #include "code\__defines\webhooks.dm" @@ -1099,11 +1101,34 @@ #include "code\game\objects\items\weapons\tanks\jetpack.dm" #include "code\game\objects\items\weapons\tanks\tank_types.dm" #include "code\game\objects\items\weapons\tanks\tanks.dm" +#include "code\game\objects\items\weapons\tools\_tools.dm" +#include "code\game\objects\items\weapons\tools\bonesetters.dm" +#include "code\game\objects\items\weapons\tools\cauterys.dm" #include "code\game\objects\items\weapons\tools\crowbar.dm" +#include "code\game\objects\items\weapons\tools\crowbars.dm" +#include "code\game\objects\items\weapons\tools\hammer.dm" +#include "code\game\objects\items\weapons\tools\hemostats.dm" +#include "code\game\objects\items\weapons\tools\knives.dm" +#include "code\game\objects\items\weapons\tools\misc.dm" +#include "code\game\objects\items\weapons\tools\multitool.dm" +#include "code\game\objects\items\weapons\tools\pickaxe.dm" +#include "code\game\objects\items\weapons\tools\retractors.dm" +#include "code\game\objects\items\weapons\tools\saws.dm" +#include "code\game\objects\items\weapons\tools\scalpels.dm" #include "code\game\objects\items\weapons\tools\screwdriver.dm" +#include "code\game\objects\items\weapons\tools\screwdrivers.dm" +#include "code\game\objects\items\weapons\tools\shovel.dm" +#include "code\game\objects\items\weapons\tools\simple_weapons.dm" +#include "code\game\objects\items\weapons\tools\surgicaldrills.dm" +#include "code\game\objects\items\weapons\tools\tape.dm" #include "code\game\objects\items\weapons\tools\weldingtool.dm" +#include "code\game\objects\items\weapons\tools\weldingtools.dm" #include "code\game\objects\items\weapons\tools\wirecutter.dm" +#include "code\game\objects\items\weapons\tools\wirecutters.dm" #include "code\game\objects\items\weapons\tools\wrench.dm" +#include "code\game\objects\items\weapons\tools\wrenches.dm" +#include "code\game\objects\items\weapons\tools\mods\_upgrades.dm" +#include "code\game\objects\items\weapons\tools\mods\mod_types.dm" #include "code\game\objects\random\date_based.dm" #include "code\game\objects\random\random.dm" #include "code\game\objects\structures\ai_decoy.dm" diff --git a/code/__defines/items.dm b/code/__defines/items.dm new file mode 100644 index 0000000000000..34307f9b9db52 --- /dev/null +++ b/code/__defines/items.dm @@ -0,0 +1,136 @@ +#define REQ_FUEL 1 +#define REQ_CELL 2 +#define REQ_FUEL_OR_CELL 4 + +//Aspect defines +#define UPGRADE_PRECISION "precision" +#define UPGRADE_WORKSPEED "workspeed" +#define UPGRADE_DEGRADATION_MULT "degradation_mult" +#define UPGRADE_FORCE_MULT "force_mult" +#define UPGRADE_FORCE_MOD "force_mod" +#define UPGRADE_FUELCOST_MULT "fuelcost_mult" +#define UPGRADE_POWERCOST_MULT "powercost_mult" + +#define UPGRADE_BULK "bulk_mod" + +#define UPGRADE_HEALTH_THRESHOLD "health_threshold_modifier" + +#define UPGRADE_MAXFUEL "max_fuel" + +#define UPGRADE_MAXUPGRADES "max_upgrades" + +#define UPGRADE_SANCTIFY "sanctify" + +#define UPGRADE_COLOR "color" + +//boolean +#define UPGRADE_SHARP "sharp" + +#define UPGRADE_CELLPLUS "cell_hold_upgrade" + +//flags +#define UPGRADE_ITEMFLAGPLUS "item_flag_add" + +// Weapon minimum fire_delay +#define GUN_MINIMUM_FIRETIME 1.1 // 110 MS , ~9 shots per second. + +//Weapon upgrade defines + +//Int multiplier +#define GUN_UPGRADE_DAMAGE_MULT "damage_mult" +#define GUN_UPGRADE_PEN_MULT "penetration_mult" +#define GUN_UPGRADE_PIERC_MULT "pierce_mult" +#define GUN_UPGRADE_RICO_MULT "ricochet_mult" +#define GUN_UPGRADE_FIRE_DELAY_MULT "fire_delay_mult" +#define GUN_UPGRADE_MOVE_DELAY_MULT "move_delay_mult" +#define GUN_UPGRADE_RECOIL "recoil_mult" +#define GUN_UPGRADE_MUZZLEFLASH "muzzleflash_mult" +#define GUN_UPGRADE_STEPDELAY_MULT "stepdelay_mult" +#define GUN_UPGRADE_CHARGECOST "chargecost_mult" +#define GUN_UPGRADE_OVERCHARGE_MAX "overcharge_max_mult" +#define GUN_UPGRADE_OVERCHARGE_RATE "overcharge_rate_mult" +#define GUN_UPGRADE_ONEHANDPENALTY "onehandpenalty_mult" + +//Int additive +#define GUN_UPGRADE_DAMAGEMOD_PLUS "damage_plus" +#define GUN_UPGRADE_MAGUP "magazine_addition" + +#define GUN_UPGRADE_DAMAGE_BRUTE "brute_damage" +#define GUN_UPGRADE_DAMAGE_BURN "burn_damage" +#define GUN_UPGRADE_DAMAGE_TOX "toxin_damage" +#define GUN_UPGRADE_DAMAGE_OXY "oxygen_damage" +#define GUN_UPGRADE_DAMAGE_CLONE "clone_damage" +#define GUN_UPGRADE_DAMAGE_HALLOSS "hallucination_damage" +#define GUN_UPGRADE_DAMAGE_RADIATION "radiation_damage" +#define GUN_UPGRADE_DAMAGE_PSY "psy_damage" +#define GUN_UPGRADE_MELEEDAMAGE "melee_damage" +#define GUN_UPGRADE_MELEEPENETRATION "melee_penetration" + +#define GUN_UPGRADE_OFFSET "offset" //Constant offset, in degrees +#define GUN_UPGRADE_ZOOM "zoom" + + + +//boolean +#define GUN_UPGRADE_SILENCER "silencable" +#define GUN_UPGRADE_FORCESAFETY "safety force" +#define GUN_UPGRADE_HONK "why" +#define GUN_UPGRADE_FULLAUTO "full auto" +#define GUN_UPGRADE_EXPLODE "self destruct" +#define GUN_UPGRADE_RIGGED "rigged" +#define GUN_UPGRADE_THERMAL "thermal scope" +#define GUN_UPGRADE_BAYONET "bayonet" +#define GUN_UPGRADE_GILDED "gilded" +#define GUN_UPGRADE_DNALOCK "biocoded" +#define GUN_UPGRADE_FOREGRIP "foregrip" +#define GUN_UPGRADE_BIPOD "bipod" + +//Location Tag defines + +#define GUN_UNDERBARREL "underbarrel slot" +#define GUN_BARREL "barrel slot" +#define GUN_TRIGGER "trigger slot" +#define GUN_MUZZLE "muzzle slot" +#define GUN_SCOPE "scope slot" +#define GUN_MECHANISM "misc slot" +#define GUN_GRIP "grip slot" +#define GUN_COSMETIC "cosmetic slot" + +//Whitelist Tag defines +#define GUN_SILENCABLE "silencable" +#define GUN_PROJECTILE "projectile firing" +#define GUN_ENERGY "energy firing" +#define GUN_LASER "laser firing" +#define GUN_REVOLVER "revolver" +#define GUN_INTERNAL_MAG "internal mag" +#define GUN_GILDABLE "gildable" +#define GUN_FA_MODDABLE "full auto moddable" + +#define GUN_CALIBRE_35 "caliber .35" + +#define GUN_AMR "Is a SA AMR \"Hristov\"" + +// // A rare, random item +// #define RANDOM_RARE_ITEM list(\ +// /obj/spawner/oddities = 8,\ +// /obj/spawner/material/resources/rare = 3,\ +// /obj/spawner/tool/advanced = 5,\ +// /obj/spawner/gun/normal = 3,\ +// /obj/spawner/lathe_disk/advanced = 2,\ +// /obj/item/cell/small/moebius/nuclear = 1,\ +// /obj/item/cell/medium/moebius/hyper = 1,\ +// /obj/spawner/rig = 1.5,\ +// /obj/spawner/rig/damaged = 1.5,\ +// /obj/spawner/voidsuit = 4,\ +// /obj/spawner/pouch = 2,\ +// /obj/spawner/tool_upgrade/rare = 4,\ +// /obj/spawner/rig_module/rare = 4,\ +// /obj/spawner/credits/c1000 = 3,\ +// /obj/spawner/exosuit_equipment = 3,\ +// /obj/spawner/cloth/holster = 4,\ +// /obj/item/stash_spawner = 4,\ +// /obj/item/storage/deferred/crate/german_uniform = 4) + +GLOBAL_LIST_INIT(tool_aspects_blacklist, list(UPGRADE_COLOR, UPGRADE_ITEMFLAGPLUS, UPGRADE_CELLPLUS, UPGRADE_SHARP, UPGRADE_BULK)) +GLOBAL_LIST_INIT(weapon_aspects_blacklist, list(GUN_UPGRADE_SILENCER, GUN_UPGRADE_FORCESAFETY, GUN_UPGRADE_HONK, GUN_UPGRADE_FULLAUTO, + GUN_UPGRADE_EXPLODE, GUN_UPGRADE_RIGGED, UPGRADE_SANCTIFY)) diff --git a/code/__defines/tools_and_qualities.dm b/code/__defines/tools_and_qualities.dm new file mode 100644 index 0000000000000..bee80fb748537 --- /dev/null +++ b/code/__defines/tools_and_qualities.dm @@ -0,0 +1,66 @@ +#define ABORT_CHECK -1 +#define TOOL_USE_FAIL -1 +#define TOOL_USE_CANCEL 0 +#define TOOL_USE_SUCCESS 1 + +#define QUALITY_BOLT_TURNING "bolt turning" +#define QUALITY_PULSING "pulsing" +#define QUALITY_PRYING "prying" +#define QUALITY_WELDING "welding" +#define QUALITY_SCREW_DRIVING "screw driving" +#define QUALITY_WIRE_CUTTING "wire cutting" +#define QUALITY_CLAMPING "clamping" +#define QUALITY_CAUTERIZING "cauterizing" +#define QUALITY_RETRACTING "retracting" +#define QUALITY_DRILLING "drilling" +#define QUALITY_HAMMERING "hammering" +#define QUALITY_SAWING "sawing" +#define QUALITY_BONE_SETTING "bone setting" +#define QUALITY_SHOVELING "shoveling" +#define QUALITY_DIGGING "digging" +#define QUALITY_EXCAVATION "excavation" +#define QUALITY_CUTTING "cutting" +#define QUALITY_LASER_CUTTING "laser cutting" //laser scalpels and e-swords - bloodless cutting +#define QUALITY_ADHESIVE "adhesive" +#define QUALITY_SEALING "sealing" + +//Time for a work for tool system calculated in that way: basic time - tool level - stat check.. +//It means that basic tools will give -30 on time, and people on right job should have -20 at least, or even more. +#define WORKTIME_INSTANT 0 +#define WORKTIME_NEAR_INSTANT 30 +#define WORKTIME_FAST 60 +#define WORKTIME_NORMAL 90 +#define WORKTIME_SLOW 120 +#define WORKTIME_LONG 170 +#define WORKTIME_EXTREMELY_LONG 250 + +//Fail chance for tool system calculated in that way: basic chance - tool level - stat check. +//Basic tools will give -30% on fail chance, and people on right job should have -20% at least. +#define FAILCHANCE_ZERO 0 +#define FAILCHANCE_VERY_EASY 30 +#define FAILCHANCE_EASY 50 +#define FAILCHANCE_NORMAL 60 +#define FAILCHANCE_HARD 80 +#define FAILCHANCE_CHALLENGING 90 +#define FAILCHANCE_VERY_HARD 120 +#define FAILCHANCE_IMPOSSIBLE 150 + +//Sounds for working with tools +#define NO_WORKSOUND -1 + +#define WORKSOUND_CIRCULAR_SAW 'sound/weapons/circsawhit.ogg' +#define WORKSOUND_SIMPLE_SAW 'sound/items/saw.ogg' +#define WORKSOUND_WRENCHING 'sound/items/Ratchet.ogg' +#define WORKSOUND_WIRECUTTING 'sound/items/Wirecutter.ogg' +#define WORKSOUND_WELDING "weld" +#define WORKSOUND_PULSING 'sound/items/multitool_pulse.ogg' +#define WORKSOUND_SCREW_DRIVING 'sound/items/Screwdriver.ogg' +#define WORKSOUND_EASY_CROWBAR 'sound/items/Crowbar.ogg' +#define WORKSOUND_HAMMER 'sound/items/hammer.ogg' +#define WORKSOUND_REMOVING 'sound/items/Deconstruct.ogg' +#define WORKSOUND_DRIVER_TOOL 'sound/items/e_screwdriver.ogg' +#define WORKSOUND_PICKAXE 'sound/items/pickaxe.ogg' +#define WORKSOUND_HARD_SLASH 'sound/weapons/bladeslice.ogg' +#define WORKSOUND_CHAINSAW 'sound/items/chainsaw.ogg' +#define WORKSOUND_TAPE 'sound/items/duct_tape.ogg' +#define WORKSOUND_HONK 'sound/items/bikehorn.ogg' diff --git a/code/game/objects/items/weapons/tools/_tools.dm b/code/game/objects/items/weapons/tools/_tools.dm new file mode 100644 index 0000000000000..8d9c6e6cb84e9 --- /dev/null +++ b/code/game/objects/items/weapons/tools/_tools.dm @@ -0,0 +1,1116 @@ +#define NOMODE null +#define EXCAVATE 0 +#define DIG 1 + +// Time added to tool operations in percent based on original time +// (if you dig hole in 10 seconds then 50 ADDITIONAL_TIME_LOWHEALTH will add 0 on full health, 2.5sec on 50% health and 5sec ~0% health) +#define ADDITIONAL_TIME_LOWHEALTH 60 + +/obj/item/tool + name = "tool" + icon = 'icons/obj/tools.dmi' + slot_flags = SLOT_BELT + force = WEAPON_FORCE_NORMAL + throwforce = WEAPON_FORCE_NORMAL + w_class = ITEM_SIZE_SMALL + + //spawn values + bad_type = /obj/item/tool + spawn_tags = SPAWN_TAG_TOOL + + price_tag = 20 + + var/tool_in_use = FALSE + + var/force_upgrade_mults = 1 + + var/force_upgrade_mods = 0 + + var/sparks_on_use = FALSE //Set to TRUE if you want to have sparks on each use of a tool + var/eye_hazard = FALSE //Set to TRUE should damage users eyes if they without eye protection + + var/use_power_cost = 0 //For tool system, determinze how much power tool will drain from cells, 0 means no cell needed + var/obj/item/cell/cell + var/suitable_cell //Dont forget to edit this for a tool, if you want in to consume cells + var/passive_power_cost = 1 //Energy consumed per process tick while active + + var/use_fuel_cost = 0 //Same, only for fuel. And for the sake of God, DONT USE CELLS AND FUEL SIMULTANEOUSLY. + var/passive_fuel_cost = 0.03 //Fuel consumed per process tick while active + var/max_fuel = 0 + + var/mode = NOMODE //For various tool icon updates. + + //Third type of resource, stock. A tool that uses physical objects (or itself) in order to work + //Currently used for tape roll + var/use_stock_cost = 0 + var/stock = 0 + var/max_stock = 0 + var/allow_decimal_stock = TRUE + var/delete_when_empty = TRUE + + + //Variables used for tool degradation + health = 0 // Health of a tool. + max_health = 1000 + var/degradation = 0.8 //If nonzero, the health of the tool decreases by this amount after each tool operation + var/health_threshold = 40 // threshold in percent on which tool health stops dropping + var/lastNearBreakMessage = 0 // used to show messages that tool is about to break + var/isBroken = FALSE + + + var/toggleable = FALSE //Determines if it can be switched ON or OFF, for example, if you need a tool that will consume power/fuel upon turning it ON only. Such as welder. + var/switched_on = FALSE //Curent status of tool. Dont edit this in subtypes vars, its for procs only. + var/switched_on_qualities //This var will REPLACE tool_qualities when tool will be toggled on. + var/switched_on_force + var/switched_on_hitsound + var/switched_off_qualities //This var will REPLACE tool_qualities when tool will be toggled off. So its possible for tool to have diferent qualities both for ON and OFF state. + var/create_hot_spot = FALSE //Set this TRUE to ignite plasma on turf with tool upon activation + var/glow_color //Set color of glow upon activation, or leave it null if you dont want any light + var/last_tooluse = 0 //When the tool was last used for a tool operation. This is set both at the start of an operation, and after the doafter call + + //Vars for tool upgrades + var/precision = 0 //Subtracted from failure rates + var/workspeed = 1 //Worktimes are divided by this + var/extra_bulk = 0 //Extra physicial volume added by certain mods + var/list/prefixes = list() + +/****************************** + /* Core Procs */ +*******************************/ +//Fuel and cell spawn +/obj/item/tool/New() + ..() + if(!cell && suitable_cell) + cell = new suitable_cell(src) + + if(use_fuel_cost) + create_reagents(max_fuel) + reagents.add_reagent("fuel", max_fuel) + + if(use_stock_cost) + stock = max_stock + + if(max_health) + health = max_health + + update_icon() + return + +/obj/item/tool/Initialize(mapload, ...) + . = ..() + var/obj/screen/item_action/action = new /obj/screen/item_action/top_bar/tool_info + action.owner = src + hud_actions = list(action) + +//Fuel and cell spawn +/obj/item/tool/Created() + QDEL_NULL(cell) + if(use_fuel_cost) + consume_fuel(get_fuel()) + + + +//For killing processes like hot spots +/obj/item/tool/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/tool/proc/adjustToolHealth(amount, user) + health = min(max_health, max(max_health * (health_threshold/100), health + amount)) + if(!isBroken && health == 0) + breakTool() + isBroken = TRUE + else if(isBroken && health > 0) + isBroken = FALSE + + +//Ignite plasma around, if we need it +/obj/item/tool/Process() + SSnano.update_uis(src) + if(switched_on) + if(create_hot_spot) + var/turf/location = get_turf(src) + if(location) + location.hotspot_expose(700, 5) + if(tool_in_use && sparks_on_use && !(item_flags & SILENT) && prob(50)) + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() + sparks.set_up(3, 0, get_turf(src)) + sparks.start() + + if(use_fuel_cost && passive_fuel_cost) + if(!consume_fuel(passive_fuel_cost)) + turn_off() + + if(use_power_cost && passive_power_cost) + if(!cell?.checked_use(passive_power_cost)) + turn_off() + + +//Cell reload +/obj/item/tool/MouseDrop(over_object) + if((src.loc == usr) && istype(over_object, /obj/screen/inventory/hand) && eject_item(cell, usr)) + cell = null + update_icon() + else + ..() + +/obj/item/tool/get_cell() + return cell + +/obj/item/tool/attackby(obj/item/C, mob/living/user) + if(istype(C, suitable_cell) && !cell && insert_item(C, user)) + src.cell = C + update_icon() + return + + if(isBroken) + to_chat(user, SPAN_WARNING("\The [src] is broken.")) + return + .=..() + + +//Turning it on/off +/obj/item/tool/attack_self(mob/user) + if(isBroken) + to_chat(user, SPAN_WARNING("\The [src] is broken.")) + return + if(toggleable) + if(switched_on) + turn_off(user) + else + turn_on(user) + SSnano.update_uis(src) + ..() + return + + +/obj/item/tool/nano_ui_data(mob/user) + var/list/data = list() + + if(tool_qualities) + data["tool_qualities"] = list() + for(var/name in tool_qualities) + data["tool_qualities"] += list(list("name" = capitalize(name), "number" = tool_qualities[name])) + + data["precision"] = precision + data["precision_state"] = precision > 0 ? "good" : precision < 0 ? "bad" : "" + + data["workspeed"] = workspeed + data["workspeed_state"] = initial(workspeed) < workspeed ? "good" : initial(workspeed) > workspeed ? "bad" : "" + data["workspeed_max"] = initial(workspeed) * 20 + + data["degradation"] = degradation + data["degradation_state"] = initial(degradation) > degradation ? "good" : initial(degradation) < degradation ? "bad" : "" + data["degradation_max"] = initial(degradation) * 10 + + if(use_power_cost) + data["cell_charge"] = cell ? cell.percent() : null + data["use_power_cost"] = use_power_cost + data["use_power_cost_state"] = initial(use_power_cost) > use_power_cost ? "good" : initial(use_power_cost) < use_power_cost ? "bad" : "" + data["use_power_cost_max"] = initial(use_power_cost) * 10 + + if(use_fuel_cost) + data["fuel"] = reagents ? reagents.nano_ui_data() : null + data["max_fuel"] = max_fuel + data["use_fuel_cost"] = use_fuel_cost + data["use_fuel_cost_state"] = initial(use_fuel_cost) > use_fuel_cost ? "good" : initial(use_fuel_cost) < use_fuel_cost ? "bad" : "" + data["use_fuel_cost_max"] = initial(use_fuel_cost) * 10 + + data["health"] = health + data["health_max"] = max_health + data["health_threshold"] = health_threshold + + data["force"] = force + data["force_max"] = initial(force) * 10 + + data["armor_divisor"] = armor_divisor + + data["extra_volume"] = extra_bulk + + data["upgrades_max"] = max_upgrades + + data["edge"] = edge + data["sharp"] = sharp + data["extended_reach"] = extended_reach + data["forced_broad_strike"] = forced_broad_strike + data["screen_shake"] = screen_shake + data["push_attack"] = push_attack + data["w_class"] = w_class + + // it could be done with catalog using one line but whatever + if(item_upgrades.len) + data["attachments"] = list() + for(var/atom/A in item_upgrades) + data["attachments"] += list(list("name" = A.name, "icon" = SSassets.transport.get_asset_url(name))) + + return data + +/obj/item/tool/nano_ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = GLOB.default_state) + var/list/data = nano_ui_data(user) + + var/datum/asset/toolupgrageds = get_asset_datum(/datum/asset/simple/tool_upgrades) + if (toolupgrageds.send(user.client)) + user.client.browse_queue_flush() // stall loading nanoui until assets actualy gets sent + + ui = SSnano.try_update_ui(user, src, ui_key, ui, data, force_open) + if(!ui) + ui = new(user, src, ui_key, "tool_stats.tmpl", name, 650, 550, state = state) + ui.auto_update_layout = 1 + ui.set_initial_data(data) + ui.open() + +// saves troubles for some one else who will expand this +// delete this comment if you are the chosen one +/obj/item/tool/Topic(href, href_list) + if(..()) + return 1 + +//Damaged tools are worth less matter for recycling +/obj/item/tool/get_matter() + if(!matter || !matter.len || !degradation) + return ..() + + //If it's this broken, you get nothing + if(health <= 20) + return null + + var/list/tm = matter.Copy() + //Every point of damage reduces matter by 2% of total + for(var/mat in tm) + tm[mat] *= health / max_health + + return tm + +/obj/item/tool/get_storage_cost() + return (..() + extra_bulk) + +/****************************** + /* Tool Usage */ +*******************************/ + +//Simple form ideal for basic use. That proc will return TRUE only when everything was done right, and FALSE if something went wrong, ot user was unlucky. +//Editionaly, handle_failure proc will be called for a critical failure roll. +/obj/item/proc/use_tool(mob/living/user, atom/target, base_time, required_quality, fail_chance, required_stat, instant_finish_tier = 110, forced_sound = null, sound_repeat = 2.5 SECONDS) + var/obj/item/tool/T + if(istool(src)) + T = src + T.tool_in_use = TRUE + + var/result = use_tool_extended(user, target, base_time, required_quality, fail_chance, required_stat, instant_finish_tier, forced_sound) + + if(T) + T.tool_in_use = FALSE + SSnano.update_uis(src) + switch(result) + if(TOOL_USE_CANCEL) + return FALSE + if(TOOL_USE_FAIL) + handle_failure(user, target, required_stat = required_stat, required_quality = required_quality) //We call it here because extended proc mean to be used only when you need to handle tool fail by yourself + return FALSE + if(TOOL_USE_SUCCESS) + return TRUE + +//Use this proc if you want to handle all types of failure yourself. It used in surgery, for example, to deal damage to patient. +/obj/item/proc/use_tool_extended(mob/living/user, atom/target, base_time, required_quality, fail_chance, required_stat, instant_finish_tier = 110, forced_sound = null, sound_repeat = 2.5 SECONDS) + + var/obj/item/tool/T + if(istool(src)) + T = src + T.last_tooluse = world.time + + if(!has_quality(required_quality)) + return TOOL_USE_CANCEL + + if(is_hot() >= HEAT_MOBIGNITE_THRESHOLD) + if(isliving(target)) + var/mob/living/L = target + L.IgniteMob() + + if(target.used_now) + to_chat(user, SPAN_WARNING("[target.name] is used by someone. Wait for them to finish.")) + return TOOL_USE_CANCEL + + + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.shock_stage >= 30) + to_chat(user, SPAN_WARNING("Pain distracts you from your task.")) + fail_chance += round(H.shock_stage/120 * 40) + base_time += round(H.shock_stage/120 * 40) + + + //Start time and time spent are used to calculate resource use + var/start_time = world.time + var/time_spent = 0 + + //Precalculate worktime here + var/time_to_finish = 0 + if(base_time) + if(islist(required_stat)) + time_to_finish = base_time - get_tool_quality(required_quality) - user.stats.getMaxStat(required_stat) + else + time_to_finish = base_time - get_tool_quality(required_quality) - user.stats.getStat(required_stat) + + //Workspeed var, can be improved by upgrades + if(T && T.workspeed > 0) + time_to_finish /= T.workspeed + // the worse tool condition - the more time required + if(T && T.degradation) + // so basically we adding time based on percent of missing health multiplied by ADDITIONAL_TIME_LOWHEALTH for easier balancing + time_to_finish = time_to_finish + (time_to_finish/100 * (ADDITIONAL_TIME_LOWHEALTH * (1 -(T.health/T.max_health)))) + + if((instant_finish_tier < get_tool_quality(required_quality)) || time_to_finish < 0) + time_to_finish = 0 + + if(T && !T.check_tool_effects(user, time_to_finish)) + return TOOL_USE_CANCEL + + //Repeating sound code! + //A datum/repeating_sound is a little object we can use to make a sound repeat a few times + var/datum/repeating_sound/toolsound = null + if(forced_sound != NO_WORKSOUND) + var/volume = 70 + var/extrarange = 0 + + if(T && T.item_flags & SILENT) + volume = 3 + extrarange = -6 + else if(T && T.item_flags & LOUD) + volume = 500 + extrarange = 10 + + var/soundfile + if(T && T.item_flags & HONKING) + soundfile = WORKSOUND_HONK + else if(forced_sound) + soundfile = forced_sound + else + soundfile = worksound + + if(sound_repeat && time_to_finish) + //It will repeat roughly every 2.5 seconds until our tool finishes + toolsound = new/datum/repeating_sound(sound_repeat,time_to_finish,0.15, src, soundfile, volume, 1, extrarange) + else + playsound(src.loc, soundfile, volume, 1, extrarange) + + //The we handle the doafter for the tool usage + if(time_to_finish) + target.used_now = TRUE + + if(!do_after(user, time_to_finish, target)) + //If the doafter fails + to_chat(user, SPAN_WARNING("You need to stand still to finish the task properly!")) + target.used_now = FALSE + time_spent = world.time - start_time //We failed, spent only part of the time working + if(T) + T.consume_resources(time_spent, user) + T.last_tooluse = world.time + if(toolsound) + //We abort the repeating sound. + //Stop function will delete itself too + toolsound.stop() + toolsound = null + return TOOL_USE_CANCEL + else + if(T) + T.last_tooluse = world.time + + target.used_now = FALSE + + //If we get here the operation finished correctly, we spent the full time working + time_spent = time_to_finish + if(T) + T.consume_resources(time_spent, user) + + //Safe cleanup + if(toolsound) + toolsound.stop() + toolsound = null + + var/stat_modifer = 0 + if(required_stat) + stat_modifer = user.stats.getStat(required_stat) + fail_chance = fail_chance - get_tool_quality(required_quality) - stat_modifer + + // handle tool breaking + if(T && T.health == 0) + T.breakTool(user) + return TOOL_USE_FAIL + else if(T && !T.health_threshold) + if(user.stats.getStat(STAT_MEC) >= STAT_LEVEL_BASIC && T.health < T.max_health/100 * 5)// tool health is < 5% + if(T.lastNearBreakMessage > world.time + 60 SECONDS) // once in 1 minute + T.lastNearBreakMessage = world.time + to_chat(user, SPAN_DANGER("Your [src.name] is about to fall apart.")) + else if(user.stats.getStat(STAT_MEC) >= STAT_LEVEL_ADEPT && T.health < T.max_health/100 * 15) // tool health is < 15% + if(T.lastNearBreakMessage > world.time + 300 SECONDS) // once in 5 minutes + T.lastNearBreakMessage = world.time + to_chat(user, SPAN_WARNING("Some parts in your [src.name] are reeling.")) + else + //lets give peasants a chance + if(T.health < T.max_health/100 * 5 && prob(10))// tool health is < 5% and chance a 10% to notice + if(T.lastNearBreakMessage > world.time + 60 SECONDS) // once in 1 minute + T.lastNearBreakMessage = world.time + to_chat(user, SPAN_DANGER("Your [src.name] is about to fall apart.")) + + //precision reduce failure rates + if(T) + fail_chance -= T.precision + + fail_chance = round(fail_chance) // Stops <1% failure chance tasks from faling. Also makes falure chance in failure message look less weird. + + if(fail_chance < 0) + fail_chance = 0 + + if(fail_chance >= 100) + to_chat(user, SPAN_WARNING("You failed to finish your task with [src.name]! Considering your skills and this tool, it is impossible.")) + return TOOL_USE_FAIL + if(prob(fail_chance)) + var/chanceMessage = "near imposible" + if(fail_chance < 5) + chanceMessage = "great" + else if(fail_chance < 25) + chanceMessage = "good" + else if(fail_chance < 50) + chanceMessage = "moderate" + else if(fail_chance < 75) + chanceMessage = "small" + else if(fail_chance < 95) + chanceMessage = "tiny" + to_chat(user, SPAN_WARNING("You failed to finish your task with [src.name]! There was a [chanceMessage] chance to succeed.")) + return TOOL_USE_FAIL + + return TOOL_USE_SUCCESS + +/obj/item/tool/proc/breakTool(mob/user) + if(user) + to_chat(user, SPAN_DANGER("Your [src] broke!")) + new /obj/item/material/shard/shrapnel(user.loc) + else + new /obj/item/material/shard/shrapnel(get_turf(src)) + if(istype(loc, /obj/machinery/door/airlock)) + var/obj/machinery/door/airlock/AD = loc + AD.take_out_wedged_item() + playsound(get_turf(src), 'sound/effects/impacts/thud1.ogg', 50, 1, -3) + isBroken = TRUE + return + +/****************************** + /* Tool Failure */ +*******************************/ + +//Critical failure rolls. If you use use_tool_extended, you might want to call that proc as well. +/obj/item/proc/handle_failure(mob/living/user, atom/target, required_stat, required_quality) + var/obj/item/tool/T + if(istool(src)) + T = src + + var/crit_fail_chance = 25 + + if(required_stat) + crit_fail_chance = crit_fail_chance - user.stats.getStat(required_stat) + + if(crit_fail_chance <= 0) + return + + //This list initially contains the fail types that are always valid, even for robots + var/list/failtypes = list() + + if(T && T.use_fuel_cost) + //Robots can do this one too + failtypes["burn"] = 0.5 + + if(canremove) + failtypes["throw"] = 1 + + if(T && T.degradation) + failtypes["damage"] = 2.5 + + if(user) + failtypes["slip"] = 2 + failtypes["swing"] = 1 + if(ishuman(user)) + if(canremove) + failtypes["drop"] = 2 + if(sharp) + failtypes["stab"] = 1 + + //This one is limited to humans only since robots often can't remove/replace their device cells + if(locate(/obj/item/cell) in contents) + failtypes["overload"] = 0.5 + + if(prob(crit_fail_chance)) + var/fail_type = pickweight(failtypes) + + switch(fail_type) + //Damage the tool + if("damage") + if(user) + to_chat(user, SPAN_DANGER("Your hand slips and you damage [src] a bit.")) + if(T) + T.adjustToolHealth(-(30 * T.degradation), user) //Failing incurs 30 uses worth of damage + return + //Drop the tool on the floor + if("drop") + if(user) + to_chat(user, SPAN_DANGER("You drop [src] on the floor.")) + user.drop_from_inventory(src) + else if(istype(loc, /obj/machinery/door/airlock)) + var/obj/machinery/door/airlock/AD = loc + AD.take_out_wedged_item() + else + forceMove(get_turf(src)) + return + + //Hit yourself + if("slip") + var/mob/living/carbon/human/H = user + to_chat(user, SPAN_DANGER("Your hand slips while working with [src]!")) + attack(H, H, H.get_holding_hand(src)) + return + + //Hit a random atom around you + if("swing") + var/list/targets = list() + for(var/atom/movable/AM in orange(user, 1)) + targets.Add(AM) + if(!targets.len) + return + + var/newtarget = pick(targets) + var/mob/living/carbon/human/H = user + + to_chat(user, SPAN_DANGER("Your hand slips and you hit [target] with [src]!")) + spawn() + H.ClickOn(newtarget) + return + + //Throw the tool in a random direction + if("throw") + if(user) + var/mob/living/carbon/human/H = user + var/throw_target = pick(RANGE_TURFS(6, user)) + to_chat(user, SPAN_DANGER("Your [src] flies away!")) + H.unEquip(src) + throw_at(throw_target, src.throw_range, src.throw_speed, H) + return + if(istype(loc, /obj/machinery/door/airlock)) + var/obj/machinery/door/airlock/AD = loc + AD.take_out_wedged_item() + else + forceMove(get_turf(src)) + var/throw_target = pick(RANGE_TURFS(6, src)) + throw_at(throw_target, src.throw_range, src.throw_speed) + return + + //Stab yourself in the hand so hard your tool embeds + if("stab") + var/mob/living/carbon/human/H = user + to_chat(user, SPAN_DANGER("You accidentally stuck [src] in your hand!")) + H.get_organ(H.get_holding_hand(src)).embed(src) + return + + //The fuel in the tool ignites and sets you aflame + if("burn") + to_chat(user, SPAN_DANGER("You ignite the fuel of the [src]!")) + var/fuel = T.get_fuel() + T.consume_fuel(fuel) + user.adjust_fire_stacks(fuel/10) + user.IgniteMob() + T.update_icon() + return + + //The cell explodes + //This can happen even with non-tools which contain a cell + if("overload") + var/obj/item/cell/C + if(T) + C = T.cell + else + C = locate(/obj/item/cell) in contents + + + if(user) + to_chat(user, SPAN_DANGER("You overload the cell in the [src]!")) + C.explode() + if(T) + T.cell = null + + update_icon() + return + + + + + +/****************************** + /* Data and Checking */ +*******************************/ +/obj/item/proc/has_quality(quality_id) + return !quality_id || (quality_id in tool_qualities) + +//A special version of the above that also checks the switched on list +//As a result, it checks what qualities the tool is ever capable of having, not just those it has right now +/obj/item/tool/proc/ever_has_quality(quality_id) + .=has_quality(quality_id) + if(!.) + if(quality_id in switched_on_qualities) + return TRUE + +/obj/item/proc/get_tool_quality(quality_id) + if(tool_qualities && tool_qualities.len) + return tool_qualities[quality_id] + return null + +//We are cheking if our item got required qualities. If we require several qualities, and item posses more than one of those, we ask user to choose how that item should be used +/obj/item/proc/get_tool_type(mob/living/user, list/required_qualities, atom/use_on, datum/callback/CB) + if(!tool_qualities) //This is not a tool, or does not have tool qualities + return + + var/list/L = required_qualities & tool_qualities + + if(L.len) + if(L.len == 1) + return L[1] + for(var/i in L) + L[i] = image(icon = 'icons/mob/radial/tools.dmi', icon_state = i) + return show_radial_menu(user, use_on ? use_on : user, L, tooltips = TRUE, require_near = TRUE, custom_check = CB) + +/obj/item/tool/proc/turn_on(mob/user) + if(use_power_cost) + if(!cell) + to_chat(user, SPAN_WARNING("\The [src] has no cell!")) + return FALSE + if(cell.charge < use_power_cost) + to_chat(user, SPAN_WARNING("\The [src] does not have enough power!")) + return FALSE + if(user) + to_chat(user, SPAN_NOTICE("\The [src] turns on.")) + switched_on = TRUE + tool_qualities = switched_on_qualities + if(switched_on_hitsound) + hitsound = switched_on_hitsound + if(!isnull(switched_on_force)) + force = switched_on_force + if(wielded) + force *= 1.3 + if(glow_color) + set_light(l_range = 1.7, l_power = 1.3, l_color = glow_color) + START_PROCESSING(SSobj, src) + update_icon() + update_wear_icon() + return TRUE + +/obj/item/tool/proc/turn_off(mob/user) + if(user) + to_chat(user, SPAN_NOTICE("\The [src] turns off.")) + switched_on = FALSE + STOP_PROCESSING(SSobj, src) + tool_qualities = switched_off_qualities + hitsound = initial(hitsound) + force = initial(force) + if(glow_color) + set_light(l_range = 0, l_power = 0, l_color = glow_color) + update_icon() + update_wear_icon() + + + + + + + + +/********************* + Resource Consumption +**********************/ +/obj/item/proc/consume_resources(timespent, user) + return + +/obj/item/tool/consume_resources(timespent, user) + //We will always use a minimum of 0.5 second worth of resources + if(timespent < 5) + timespent = 5 + + if(use_power_cost) + if(!cell?.checked_use(use_power_cost*timespent)) + to_chat(user, SPAN_WARNING("[src] battery is dead or missing.")) + return FALSE + + if(use_fuel_cost) + if(!consume_fuel(use_fuel_cost*timespent)) + to_chat(user, SPAN_NOTICE("You need more welding fuel to complete this task.")) + return FALSE + + if(use_stock_cost) + var/scost = use_stock_cost * timespent + if(!allow_decimal_stock) + scost = round(scost, 1) + consume_stock(scost) + + //Makeshift tools get worse with each use + if(degradation) + adjustToolHealth(-degradation, user) + +//Power and fuel drain, sparks spawn +/obj/item/tool/proc/check_tool_effects(mob/living/user, time) + + if(use_power_cost) + if(!cell || !cell.check_charge(use_power_cost*time)) + to_chat(user, SPAN_WARNING("[src] battery is dead or missing.")) + return FALSE + + if(use_fuel_cost) + if(get_fuel() < (use_fuel_cost*time)) + to_chat(user, SPAN_NOTICE("You need more welding fuel to complete this task.")) + return FALSE + + if(use_stock_cost) + if(stock < (use_stock_cost*time)) + to_chat(user, SPAN_NOTICE("There is not enough left in [src] to complete this task.")) + return FALSE + + if(eye_hazard) + eyecheck(user) + + if(sparks_on_use && !(item_flags & SILENT)) + var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread() + sparks.set_up(3, 0, get_turf(src)) + sparks.start() + + update_icon() + return TRUE + +//Returns the amount of fuel in tool +/obj/item/tool/proc/get_fuel() + return (reagents ? reagents.get_reagent_amount("fuel") : 0) + +/obj/item/tool/proc/consume_fuel(volume) + if(get_fuel() >= volume) + reagents.remove_reagent("fuel", volume) + return TRUE + return FALSE + + +/obj/item/tool/proc/consume_stock(number) + if(stock >= number) + stock -= number + else + stock = 0 + + if(delete_when_empty && stock <= 0) + qdel(src) + + +/*************************** + Tool Upgrades +****************************/ +/obj/item/tool/refresh_upgrades() +//First of all, lets reset any var that could possibly be altered by an upgrade + degradation = initial(degradation) + workspeed = initial(workspeed) + precision = initial(precision) + suitable_cell = initial(suitable_cell) + max_fuel = initial(max_fuel) + health_threshold = initial(health_threshold) + + use_fuel_cost = initial(use_fuel_cost) + use_power_cost = initial(use_power_cost) + force = initial(force) + force_upgrade_mults = initial(force_upgrade_mults) + force_upgrade_mods = initial(force_upgrade_mods) + switched_on_force = initial(switched_on_force) + extra_bulk = initial(extra_bulk) + item_flags = initial(item_flags) + name = initial(name) + max_upgrades = initial(max_upgrades) + color = initial(color) + sharp = initial(sharp) + prefixes = list() + + //Now lets have each upgrade reapply its modifications + SEND_SIGNAL(src, COMSIG_APPVAL, src) + + for(var/prefix in prefixes) + name = "[prefix] [name]" + + health_threshold = max(0, health_threshold) + + //Set the fuel volume, incase any mods altered our max fuel + if(reagents) + reagents.maximum_volume = max_fuel + SSnano.update_uis(src) + + +/obj/item/tool/examine(mob/user) + if(!..(user,2)) + return + + if(use_power_cost) + if(!cell) + to_chat(user, SPAN_WARNING("There is no cell inside to power the tool")) + else + to_chat(user, "The charge meter reads [round(cell.percent())]%.") + + if(use_fuel_cost) + to_chat(user, text("\icon[] [] contains []/[] units of fuel!", src, src.name, get_fuel(),src.max_fuel )) + + if(use_stock_cost) + to_chat(user, SPAN_NOTICE("it has [stock] / [max_stock] units remaining.")) + + //Display a bunch of stats but only if they're nondefault values + if(precision != 0) + to_chat(user, "Precision: [SPAN_NOTICE("[precision]")]") + + if(workspeed != 1) + to_chat(user, "Work Speed: [SPAN_NOTICE("[workspeed*100]%")]") + + if(item_upgrades.len) + to_chat(user, "It has the following upgrades installed:") + for(var/obj/item/TU in item_upgrades) + to_chat(user, SPAN_NOTICE(TU.name)) + + if(health) + if(health > max_health * 0.95) + return + else if(health > max_health * 0.80) + to_chat(user, "It has a few light scratches.") + else if(health > max_health * 0.40) + to_chat(user, SPAN_NOTICE("It shows minor signs of stress and wear.")) + else if(health > max_health * 0.20) + to_chat(user, SPAN_WARNING("It looks a bit cracked and worn.")) + else if(health > max_health * 0.10) + to_chat(user, SPAN_WARNING("Whatever use this tool once had is fading fast.")) + else if(health > max_health * 0.05) + to_chat(user, SPAN_WARNING("Attempting to use this thing as a tool is probably not going to work out well.")) + else + to_chat(user, SPAN_DANGER("It's falling apart. This is one slip away from just being a pile of assorted trash.")) + +//Recharge the fuel at fueltank, also explode if switched on +/obj/item/tool/afterattack(obj/O, mob/user, proximity) + // i assume tape cant be broken + if(isBroken) + to_chat(user, SPAN_WARNING("\The [src] is broken.")) + return + if(use_fuel_cost) + if(!proximity) + return + if((istype(O, /obj/structure/reagent_dispensers/fueltank) || istype(O, /obj/item/weldpack)) && get_dist(src,O) <= 1 && !has_quality(QUALITY_WELDING)) + O.reagents.trans_to_obj(src, max_fuel) + to_chat(user, SPAN_NOTICE("[src] refueled")) + playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) + return + else if((istype(O, /obj/structure/reagent_dispensers/fueltank) || istype(O, /obj/item/weldpack)) && get_dist(src,O) <= 1 && has_quality(QUALITY_WELDING)) + message_admins("[key_name_admin(user)] triggered an explosion with a welding tool.") + log_game("[key_name(user)] triggered an explosion with a welding tool.") + to_chat(user, SPAN_DANGER("You begin welding on the [O] and with a moment of lucidity you realize, this might not have been the smartest thing you've ever done.")) + if(istype(O, /obj/structure/reagent_dispensers/fueltank)) + var/obj/structure/reagent_dispensers/fueltank/T = O + T.explode() + else if(istype(O, /obj/item/weldpack)) + var/obj/item/weldpack/P = O + P.explode() + return +/* + else if(istype(O, /mob/living/carbon/superior_animal/roach/benzin)) + var/mob/living/carbon/superior_animal/roach/benzin/B = O + if(B.stat != DEAD) + if(has_quality(QUALITY_WELDING)) + B.fire_act() + else + O.reagents.trans_to_obj(src, max_fuel) + to_chat(user, SPAN_NOTICE("[src] refueled")) + playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) + return +*/ + if(switched_on) + var/turf/location = get_turf(user) + if(isliving(O)) + var/mob/living/L = O + L.IgniteMob() + if(istype(location, /turf)) + location.hotspot_expose(700, 50, 1) + + if(has_quality(QUALITY_ADHESIVE) && proximity) + //Tape can be used to repair other tools + if(istool(O)) + var/obj/item/tool/T = O + if(T.health) + user.visible_message(SPAN_NOTICE("[user] begins repairing \the [O] with the [src]!")) + //Toolception! + if(use_tool(user, T, 60, QUALITY_ADHESIVE, FAILCHANCE_EASY, STAT_MEC)) + T.adjustToolHealth(T.max_health * 0.8 + (user.stats.getStat(STAT_MEC)/2)/100, user) + if(user.stats.getStat(STAT_MEC) > STAT_LEVEL_BASIC/2) + to_chat(user, SPAN_NOTICE("You knowledge in tools helped you repair it better.")) + refresh_upgrades() + return + + if(stick(O, user)) + return + //Triggers degradation and resource use upon attacks + if(!(flags & NOBLUDGEON) && (world.time - last_tooluse) > 2) + consume_resources(5,user) + + return ..() + +//Triggers degradation and resource use upon attacks +/obj/item/tool/resolve_attackby(atom/A, mob/user, params) + if(isBroken) + to_chat(user, SPAN_WARNING("\The [src] is broken.")) + return + .=..() + //If the parent return value is true, then there won't be an attackby + //If there will be an attackby, we'll handle it there + //Checking the last tooluse time prevents consuming twice for a tool action + if(. && loc == user && (!(flags & NOBLUDGEON)) && (world.time - last_tooluse) > 2) + consume_resources(5,user) + +//Decides whether or not to damage a player's eyes based on what they're wearing as protection +//Note: This should probably be moved to mob +/obj/item/tool/proc/eyecheck(var/mob/user) + if(!iscarbon(user)) + return TRUE + if(ishuman(user)) + var/mob/living/carbon/human/H = user + var/obj/item/organ/internal/eyes/E = H.random_organ_by_process(OP_EYES) + if(!E) + return + var/safety = H.eyecheck() + switch(safety) + if(FLASH_PROTECTION_MODERATE) + to_chat(H, SPAN_WARNING("Your eyes sting a little.")) + E.damage += rand(1, 2) + if(E.damage > 12) + H.eye_blurry += rand(3,6) + if(FLASH_PROTECTION_MINOR) + to_chat(H, SPAN_WARNING("The searing light burns your eyes through your insufficient protection.")) + E.damage += rand(2, 3) + if(E.damage > 11) + E.damage += rand(4,8) + if(FLASH_PROTECTION_NONE) + to_chat(H, SPAN_WARNING("Your eyes burn.")) + E.damage += rand(2, 4) + if(E.damage > 10) + E.damage += rand(4,10) + if(FLASH_PROTECTION_REDUCED) + to_chat(H, SPAN_DANGER("Your equipment intensify the welder's glow. Your eyes itch and burn severely.")) + H.eye_blurry += rand(12,20) + E.damage += rand(12, 16) + if(safety 10) + to_chat(user, SPAN_WARNING("Your eyes are really starting to hurt. This can't be good for you!")) + + +/obj/item/tool/attack(mob/living/M, mob/living/user, target_zone) + if(isBroken) + to_chat(user, SPAN_WARNING("\The [src] is broken.")) + return + if((user.a_intent == I_HELP) && ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/S = H.organs_by_name[user.targeted_organ] + + if(!istype(S) || !BP_IS_ROBOTIC(S)) + return ..() + + if(get_tool_type(user, list(QUALITY_WELDING), H)) //Prosthetic repair + if(S.brute_dam) + if(S.brute_dam < ROBOLIMB_SELF_REPAIR_CAP) + for(var/datum/wound/W in S.wounds) + if(W.internal) + return + if(W.damtype_sanitize() != BRUTE) + continue + if(!use_tool(user, M, W.damage/5, QUALITY_WELDING, FAILCHANCE_NORMAL, required_stat = STAT_MEC)) + to_chat(user, SPAN_NOTICE("You must stand still to repair \the [S].")) + break + W.heal_damage(CLAMP(user.stats.getStat(STAT_MEC)/2.5, 5, 15)) + to_chat(user, SPAN_NOTICE("You patch some wounds on \the [S].")) + S.update_damages() + if(S.brute_dam) + to_chat(user, SPAN_WARNING("\The [S] still needs further repair.")) + return + else if(S.open != 2) + to_chat(user, SPAN_DANGER("The damage is far too severe to patch over externally.")) + return 1 + else if(S.open != 2) // For surgery. + to_chat(user, SPAN_NOTICE("Nothing to fix!")) + return 1 + + return ..() + +/obj/item/tool/update_icon() + cut_overlays() + + if(switched_on && toggleable) + overlays += "[icon_state]_on" + + if(use_power_cost) + var/ratio = 0 + //make sure that rounding down will not give us the empty state even if we have charge for a shot left. + if(cell && cell.charge >= use_power_cost) + ratio = cell.charge / cell.maxcharge + ratio = max(round(ratio, 0.25) * 100, 25) + overlays += "[icon_state]-[ratio]" + + if(use_fuel_cost) + var/ratio = 0 + //make sure that rounding down will not give us the empty state even if we have charge for a shot left. + if(get_fuel() >= use_fuel_cost) + ratio = get_fuel() / max_fuel + ratio = max(round(ratio, 0.25) * 100, 25) + overlays += "[icon_state]-[ratio]" + + if(ismob(loc)) + var/tooloverlay + switch(mode) + if(EXCAVATE) + tooloverlay = "excavate" + if(DIG) + tooloverlay = "dig" + overlays += (tooloverlay) + +/*************************** + Misc/utility procs +****************************/ + +//Used by adhesive tools to stick an item to stuff +/obj/item/tool/proc/stick(obj/item/target, mob/user) + return + + +/obj/item/tool/admin_debug + name = "Electric Boogaloo 3000" + icon_state = "omnitool" + item_state = "omnitool" + spawn_tags = null + tool_qualities = list(QUALITY_BOLT_TURNING = 100, + QUALITY_PRYING = 100, + QUALITY_WELDING = 100, + QUALITY_SCREW_DRIVING = 100, + QUALITY_CLAMPING = 100, + QUALITY_CAUTERIZING = 100, + QUALITY_WIRE_CUTTING = 100, + QUALITY_RETRACTING = 100, + QUALITY_DRILLING = 100, + QUALITY_SAWING = 100, + QUALITY_VEIN_FIXING = 100, + QUALITY_BONE_SETTING = 100, + QUALITY_BONE_FIXING = 100, + QUALITY_SHOVELING = 100, + QUALITY_DIGGING = 100, + QUALITY_EXCAVATION = 100, + QUALITY_CUTTING = 100, + QUALITY_HAMMERING = 100) + +#undef ADDITIONAL_TIME_LOWHEALTH + +/obj/screen/item_action/top_bar/tool_info + icon = 'icons/mob/screen/gun_actions.dmi' + screen_loc = "8,1:13" + minloc = "7,2:13" + name = "Tool information" + icon_state = "info" + +/obj/item/tool/ui_action_click(mob/living/user, action_name) + switch(action_name) + if("Tool information") + nano_ui_interact(user) diff --git a/code/game/objects/items/weapons/tools/bonesetters.dm b/code/game/objects/items/weapons/tools/bonesetters.dm new file mode 100644 index 0000000000000..1d2f7e61be83d --- /dev/null +++ b/code/game/objects/items/weapons/tools/bonesetters.dm @@ -0,0 +1,10 @@ +/obj/item/tool/bonesetter + name = "bone setter" + icon_state = "bone setter" + item_state = "bone_setter" + w_class = ITEM_SIZE_SMALL + matter = list(MATERIAL_STEEL = 4) + flags = CONDUCT + attack_verb = list("attacked", "hit", "bludgeoned") + tool_qualities = list(QUALITY_BONE_SETTING = 30) + spawn_tags = SPAWN_TAG_SURGERY_TOOL diff --git a/code/game/objects/items/weapons/tools/cauterys.dm b/code/game/objects/items/weapons/tools/cauterys.dm new file mode 100644 index 0000000000000..9fc734c362d74 --- /dev/null +++ b/code/game/objects/items/weapons/tools/cauterys.dm @@ -0,0 +1,11 @@ +/obj/item/tool/cautery + name = "cautery" + desc = "This stops bleeding." + icon_state = "cautery" + item_state = "cautery" + matter = list(MATERIAL_STEEL = 5, MATERIAL_GLASS = 2) + flags = CONDUCT + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1) + attack_verb = list("burnt") + tool_qualities = list(QUALITY_CAUTERIZING = 30) + spawn_tags = SPAWN_TAG_SURGERY_TOOL diff --git a/code/game/objects/items/weapons/tools/crowbars.dm b/code/game/objects/items/weapons/tools/crowbars.dm new file mode 100644 index 0000000000000..08ace3bb10778 --- /dev/null +++ b/code/game/objects/items/weapons/tools/crowbars.dm @@ -0,0 +1,65 @@ +/obj/item/tool/crowbar + name = "crowbar" + desc = "Used to remove floors and to pry open doors." + icon_state = "crowbar" + item_state = "crowbar" + flags = CONDUCT + force = WEAPON_FORCE_PAINFUL + worksound = WORKSOUND_EASY_CROWBAR + w_class = ITEM_SIZE_NORMAL + origin_tech = list(TECH_ENGINEERING = 1) + matter = list(MATERIAL_STEEL = 4) + attack_verb = list("attacked", "bashed", "battered", "bludgeoned", "whacked") + tool_qualities = list(QUALITY_PRYING = 25, QUALITY_DIGGING = 10, QUALITY_HAMMERING = 10) + rarity_value = 4 + +/obj/item/tool/crowbar/improvised + name = "rebar" + desc = "A pair of metal rods laboriously twisted into a useful shape. Has more space for tool mods because it's hand-made." + icon_state = "impro_crowbar" + item_state = "impro_crowbar" + tool_qualities = list(QUALITY_PRYING = 10, QUALITY_DIGGING = 10,QUALITY_HAMMERING = 10) + degradation = 5 //This one breaks REALLY fast + max_upgrades = 5 //all makeshift tools get more mods to make them actually viable for mid-late game + rarity_value = 2 + spawn_tags = SPAWN_TAG_JUNKTOOL + +/obj/item/tool/crowbar/onestar + name = "One Star crowbar" + desc = "Looks like a classic one, but more durable. Has more space for mods too." + icon_state = "one_star_crowbar" + item_state = "onestar_crowbar" + matter = list(MATERIAL_STEEL = 3, MATERIAL_PLATINUM = 1) + tool_qualities = list(QUALITY_PRYING = 25, QUALITY_DIGGING = 10) + origin_tech = list(TECH_ENGINEERING = 1, TECH_MATERIAL = 2) + degradation = 0.6 + workspeed = 1.2 + spawn_blacklisted = TRUE + rarity_value = 10 + spawn_tags = SPAWN_TAG_OS_TOOL + +/obj/item/tool/crowbar/pneumatic + name = "pneumatic crowbar" + desc = "When you really need to crack open something." + icon_state = "pneumo_crowbar" + item_state = "pneumo_crowbar" + matter = list(MATERIAL_STEEL = 6, MATERIAL_PLASTEEL = 1, MATERIAL_PLASTIC = 2) + tool_qualities = list(QUALITY_PRYING = 40, QUALITY_DIGGING = 35) + degradation = 0.7 + use_power_cost = 0.8 + max_upgrades = 4 + suitable_cell = /obj/item/cell/medium + rarity_value = 24 + spawn_tags = SPAWN_TAG_TOOL_ADVANCED + +/obj/item/tool/crowbar/pneumatic/hivemind + name = "modified pneumatic crowbar" + desc = "A pneumatic crowbar with numerous growths on it. Doubt you will be able to use it for anything other than prying." + icon_state = "hivemind_pneumo_crowbar" + item_state = "hivemind_pneumo_crowbar" + origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 4, TECH_BIO = 2) + matter = list(MATERIAL_STEEL = 8, MATERIAL_PLASTEEL = 1, MATERIAL_PLASTIC = 2, MATERIAL_BIOMATTER = 3) + tool_qualities = list(QUALITY_PRYING = 50) + degradation = 0.4 + use_power_cost = 0.4 + spawn_blacklisted = TRUE diff --git a/code/game/objects/items/weapons/tools/hammer.dm b/code/game/objects/items/weapons/tools/hammer.dm new file mode 100644 index 0000000000000..039d22a1ae153 --- /dev/null +++ b/code/game/objects/items/weapons/tools/hammer.dm @@ -0,0 +1,257 @@ +/obj/item/tool/hammer //needs new sprite + name = "hammer" + desc = "Used for applying blunt force to a surface." + icon_state = "hammer" + item_state = "hammer" + force = WEAPON_FORCE_PAINFUL + w_class = ITEM_SIZE_SMALL + worksound = WORKSOUND_HAMMER + flags = CONDUCT + push_attack = TRUE + origin_tech = list(TECH_ENGINEERING = 1) + tool_qualities = list(QUALITY_HAMMERING = 20, QUALITY_PRYING = 10) + matter = list(MATERIAL_STEEL = 4, MATERIAL_WOOD = 2) + attack_verb = list("attacked", "bashed", "battered", "bludgeoned", "whacked","flattened","pulped") + hitsound = 'sound/weapons/melee/blunthit.ogg' + rarity_value = 5 + +/obj/item/tool/hammer/wield(mob/living/user) + screen_shake = TRUE + ..() + +/obj/item/tool/hammer/unwield(mob/living/user) + screen_shake = FALSE + ..() + +/obj/item/tool/hammer/powered_hammer //to be made into proper two-handed tool as small "powered" hammer doesn't make sense + name = "powered hammer" //lacks normal sprites, both icon, item and twohanded for this + desc = "Used for applying excessive blunt force to a surface. Powered edition." + icon_state = "powered_hammer" + item_state = "powered_hammer" + structure_damage_factor = STRUCTURE_DAMAGE_BREACHING + armor_divisor = ARMOR_PEN_HALF + force = WEAPON_FORCE_BRUTAL + w_class = ITEM_SIZE_HUGE + tool_qualities = list(QUALITY_HAMMERING = 30) + matter = list(MATERIAL_STEEL = 5, MATERIAL_PLASTEEL = 10, MATERIAL_PLASTIC = 1) + degradation = 0.7 + use_power_cost = 2 + suitable_cell = /obj/item/cell/medium + max_upgrades = 4 + rarity_value = 24 + +/obj/item/tool/hammer/sledgehammer + name = "sledgehammer" + desc = "With this in your hands, every problem looks like a nail." + icon_state = "sledgehammer" + item_state = "sledgehammer" + wielded_icon = "sledgehammer_wielded" + structure_damage_factor = STRUCTURE_DAMAGE_BREACHING + armor_divisor = ARMOR_PEN_MODERATE + force = WEAPON_FORCE_DANGEROUS + force_wielded_multiplier = 1.4 + w_class = ITEM_SIZE_HUGE + slot_flags = SLOT_BACK + matter = list(MATERIAL_STEEL = 10, MATERIAL_WOOD = 2) + tool_qualities = list(QUALITY_HAMMERING = 30) + max_upgrades = 2 + rarity_value = 2 + +/obj/item/tool/hammer/sledgehammer/advanced + name = "advanced sledgehammer" + desc = "Used for applying excessive blunt force to a problem, now with even more force." + icon_state = "sledgehammer_advanced" + item_state = "sledgehammer_advanced" + wielded_icon = "sledgehammer_advanced_wielded" + structure_damage_factor = STRUCTURE_DAMAGE_POWERFUL + armor_divisor = ARMOR_PEN_HALF + force = WEAPON_FORCE_ROBUST + tool_qualities = list(QUALITY_HAMMERING = 40) + matter = list(MATERIAL_STEEL = 5, MATERIAL_PLASTEEL = 10, MATERIAL_PLASTIC = 3) + max_upgrades = 3 + spawn_blacklisted = TRUE + +/obj/item/tool/hammer/sledgehammer/improvised + name = "homewrecker" + desc = "A large steel chunk welded to a long handle which resembles a sledgehammer. Extremely heavy." + icon_state = "homewrecker0" + item_state = "homewrecker" + wielded_icon = "homewrecker1" + structure_damage_factor = STRUCTURE_DAMAGE_HEAVY + armor_divisor = ARMOR_PEN_SHALLOW + force = WEAPON_FORCE_PAINFUL + slot_flags = SLOT_BELT|SLOT_BACK + tool_qualities = list(QUALITY_HAMMERING = 15) + matter = list(MATERIAL_STEEL = 15, MATERIAL_PLASTIC = 1) + max_upgrades = 3 + spawn_tags = SPAWN_TAG_JUNKTOOL + rarity_value = 32 + +/obj/item/tool/hammer/sledgehammer/ironhammer //triple hammer! + name = "FS \"Ironhammer\" Breaching Hammer" + desc = "A modified sledgehammer produced by Frozen Star for Ironhammer forces. This tool can take down standard walls and if the user is strong enough, reinforced walls." + icon = 'icons/obj/weapons.dmi' + icon_state = "iron_hammer" + item_state = "iron_hammer" + wielded_icon = "iron_hammer_wielded" + armor_divisor = ARMOR_PEN_HALF + force = WEAPON_FORCE_ROBUST + structure_damage_factor = STRUCTURE_DAMAGE_POWERFUL + tool_qualities = list(QUALITY_HAMMERING = 40, QUALITY_PRYING = 1) + matter = list(MATERIAL_STEEL = 15, MATERIAL_PLASTIC = 1, MATERIAL_PLASTEEL = 2) + spawn_blacklisted = TRUE + +/obj/item/tool/hammer/sledgehammer/onestar + name = "One Star sledgehammer" + desc = "A sledgehammer model produced by One Star, used for applying immeasurable blunt force to anything in your way. Capable of breaching even the toughtest obstacles, and cracking the most resilient skulls." + icon_state = "onehammer" + item_state = "onehammer" + wielded_icon = "onehammer_on" + structure_damage_factor = STRUCTURE_DAMAGE_DESTRUCTIVE + armor_divisor = ARMOR_PEN_HALF + force= WEAPON_FORCE_BRUTAL + force_wielded_multiplier = 1.5 + w_class = ITEM_SIZE_HUGE + slot_flags = SLOT_BACK + matter = list(MATERIAL_STEEL = 10, MATERIAL_PLATINUM = 5, MATERIAL_DIAMOND = 5) + tool_qualities = list(QUALITY_HAMMERING = 50) + suitable_cell = /obj/item/cell/medium + degradation = 0.6 + use_power_cost = 1.5 + workspeed = 1.5 + max_upgrades = 2 + spawn_blacklisted = TRUE + rarity_value = 10 + spawn_tags = SPAWN_TAG_OS_TOOL + +/obj/item/tool/hammer/mace + name = "mace" + desc = "Used for applying blunt force trauma to a person's ribcage." + icon = 'icons/obj/weapons.dmi' + icon_state = "mace" + item_state = "mace" + w_class = ITEM_SIZE_NORMAL + armor_divisor = ARMOR_PEN_HALF + force = WEAPON_FORCE_ROBUST + tool_qualities = list(QUALITY_HAMMERING = 20) + spawn_tags = SPAWN_TAG_WEAPON + rarity_value = 15 + structure_damage_factor = STRUCTURE_DAMAGE_BLUNT + +/obj/item/tool/hammer/mace/makeshift + name = "makeshift mace" + desc = "Some metal attached to the end of a stick, for applying blunt force trauma to a roach." + icon_state = "ghetto_mace" + item_state = "ghetto_mace" + force = WEAPON_FORCE_DANGEROUS + tool_qualities = list(QUALITY_HAMMERING = 15) + degradation = 3 //This one breaks fast + max_upgrades = 5 //all makeshift tools get more mods to make them actually viable for mid-late game + rarity_value = 30 + spawn_tags = SPAWN_TAG_JUNKTOOL + + +/obj/item/tool/hammer/mace/makeshift/baseballbat + name = "baseball bat" + desc = "HOME RUN!" + icon_state = "woodbat0" + wielded_icon = "woodbat1" + item_state = "woodbat0" + force = WEAPON_FORCE_DANGEROUS + armor_divisor = ARMOR_PEN_MODERATE + attack_verb = list("smashed", "beaten", "slammed", "smacked", "struck", "battered", "bonked") + hitsound = 'sound/weapons/genhit3.ogg' + slot_flags = SLOT_BELT|SLOT_BACK + +/obj/item/tool/hammer/mace/makeshift/baseballbat/bone + name = "bone club" + desc = "Seems like someone gave up an arm and a leg for this thing. And a head." + icon_state = "bonemace" + item_state = "bonemace" + slot_flags = SLOT_BELT + degradation = 1.5 //Something something bones are hard. + spawn_blacklisted = TRUE + +/obj/item/tool/hammer/charge + name = "charge hammer" + desc = "After many issues with scientists trying to hammer a nail, one bright individual wondered what could be achieved by attaching a stellar-grade ship engine to the back." + icon = 'icons/obj/weapons.dmi' + icon_state = "chargehammer" + item_state = "chargehammer" + w_class = ITEM_SIZE_HUGE + switched_on_force = WEAPON_FORCE_BRUTAL + armor_divisor = ARMOR_PEN_EXTREME + structure_damage_factor = STRUCTURE_DAMAGE_BREACHING + switched_on_qualities = list(QUALITY_HAMMERING = 60) + switched_off_qualities = list(QUALITY_HAMMERING = 35) + toggleable = TRUE + slot_flags = SLOT_BACK + suitable_cell = /obj/item/cell/medium + use_power_cost = 15 + rarity_value = 100 + spawn_frequency = 4 + var/datum/effect/effect/system/trail/T + var/last_launch + +/obj/item/tool/hammer/charge/New() + ..() + T = new /datum/effect/effect/system/trail/fire() + T.set_up(src) + +/obj/item/tool/hammer/charge/Destroy() + QDEL_NULL(T) + return ..() + +/obj/item/tool/hammer/charge/afterattack(atom/target, mob/user, proximity_flag, params) + if(!switched_on || world.time < last_launch + 3 SECONDS) + return + var/cost = use_power_cost*get_dist(target, user) + if(user.check_gravity()) + cost *= (user.mob_size/10) + + if(cell?.checked_use(cost)) + if(!wielded) + var/drop_prob = 30 + if(ishuman(user)) + var/mob/living/carbon/human/H = user + drop_prob *= H.stats.getMult(STAT_ROB, STAT_LEVEL_EXPERT) + if(prob(drop_prob)) + to_chat(user, SPAN_WARNING("\The [src] launches from your grasp!")) + user.drop_item(src) + T.start() + playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0) + throw_at(target, get_dist(target, user), 1, user) + T.stop() + last_launch = world.time + return + last_launch = world.time + T.start() + playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0) + user.throw_at(target, get_dist(target, user), 1, user) + T.stop() + +/obj/item/tool/hammer/dumbbell + name = "dumbbell" + desc = "To get stronger with this thing, you need to regularly train for many a month. But to hammer a nail, or crack a skull..." + icon_state = "dumbbell" + item_state = "dumbbell" + tool_qualities = list(QUALITY_HAMMERING = 15) + matter = list(MATERIAL_STEEL = 5) + rarity_value = 35 + +/obj/item/tool/hammer/staff + name = "makeshift staff" + desc = "Three rods, some duct tape and a lot of bloodlust give you this. Its size helps greatly with blocking melee attacks and reaching far." + icon = 'icons/obj/weapons.dmi' + icon_state = "staff" + item_state = "staff" + wielded_icon = "staff_wielded" + tool_qualities = list(QUALITY_HAMMERING = 5) + matter = list(MATERIAL_STEEL = 3) + extended_reach = TRUE + rarity_value = 70 + max_upgrades = 3 + armor_divisor = ARMOR_PEN_GRAZING //blunt force trauma strong + force = WEAPON_FORCE_PAINFUL + force_wielded_multiplier = 1.3 + w_class = ITEM_SIZE_HUGE diff --git a/code/game/objects/items/weapons/tools/hemostats.dm b/code/game/objects/items/weapons/tools/hemostats.dm new file mode 100644 index 0000000000000..d590e438b2044 --- /dev/null +++ b/code/game/objects/items/weapons/tools/hemostats.dm @@ -0,0 +1,11 @@ +/obj/item/tool/hemostat + name = "hemostat" + desc = "You think you have seen this before." + icon_state = "hemostat" + matter = list(MATERIAL_STEEL = 2) + flags = CONDUCT + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1) + attack_verb = list("attacked", "pinched") + hitsound = 'sound/weapons/melee/lightstab.ogg' + tool_qualities = list(QUALITY_CLAMPING = 30) + spawn_tags = SPAWN_TAG_SURGERY_TOOL diff --git a/code/game/objects/items/weapons/tools/knives.dm b/code/game/objects/items/weapons/tools/knives.dm new file mode 100644 index 0000000000000..0d44b2a90b12a --- /dev/null +++ b/code/game/objects/items/weapons/tools/knives.dm @@ -0,0 +1,420 @@ + +//Knifes +/obj/item/tool/knife + name = "kitchen knife" + desc = "A general purpose Chef's Knife made by Asters Merchant Guild. Guaranteed to stay sharp for years to come." + icon = 'icons/obj/kitchen.dmi' + icon_state = "knife" + description_info = "Could be attached to a gun" + flags = CONDUCT + sharp = TRUE + edge = TRUE + worksound = WORKSOUND_HARD_SLASH + w_class = ITEM_SIZE_SMALL //2 + force = WEAPON_FORCE_NORMAL //10 + throwforce = WEAPON_FORCE_WEAK + armor_divisor = ARMOR_PEN_SHALLOW + max_upgrades = 2 + tool_qualities = list(QUALITY_CUTTING = 20, QUALITY_WIRE_CUTTING = 10, QUALITY_SCREW_DRIVING = 5) + matter = list(MATERIAL_STEEL = 3, MATERIAL_PLASTIC = 1) + attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + hitsound = 'sound/weapons/melee/lightstab.ogg' + slot_flags = SLOT_BELT + structure_damage_factor = STRUCTURE_DAMAGE_BLADE + + //spawn values + rarity_value = 10 + spawn_tags = SPAWN_TAG_KNIFE + +/obj/item/tool/knife/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.weapon_upgrades = list( + GUN_UPGRADE_BAYONET = TRUE, + GUN_UPGRADE_MELEEDAMAGE = 5, + GUN_UPGRADE_MELEEPENETRATION = ARMOR_PEN_MODERATE, + GUN_UPGRADE_OFFSET = 4 + ) + I.gun_loc_tag = GUN_UNDERBARREL + I.req_gun_tags = list(SLOT_BAYONET) + +/obj/item/tool/knife/boot + name = "boot knife" + desc = "A small fixed-blade knife for putting inside a boot." + icon = 'icons/obj/weapons.dmi' + icon_state = "tacknife" + item_state = "knife" + matter = list(MATERIAL_PLASTEEL = 2, MATERIAL_PLASTIC = 1) + force = WEAPON_FORCE_PAINFUL + tool_qualities = list(QUALITY_CUTTING = 20, QUALITY_WIRE_CUTTING = 10, QUALITY_SCREW_DRIVING = 15) + rarity_value = 20 + +/obj/item/tool/knife/hook + name = "meat hook" + desc = "A sharp, metal hook what sticks into things." + icon_state = "hook_knife" + item_state = "hook_knife" + matter = list(MATERIAL_PLASTEEL = 5, MATERIAL_PLASTIC = 2) + force = WEAPON_FORCE_DANGEROUS + armor_divisor = ARMOR_PEN_HALF //Should be countered be embedding + embed_mult = 1.5 //This is designed for embedding + rarity_value = 5 + +/obj/item/tool/knife/ritual + name = "ritual knife" + desc = "The unearthly energies that once powered this blade are now dormant." + icon = 'icons/obj/wizard.dmi' + icon_state = "render" + force = WEAPON_FORCE_PAINFUL + rarity_value = 20 + +/obj/item/tool/knife/butch + name = "butcher's cleaver" + icon_state = "butch" + desc = "A huge thing used for chopping and chopping up meat. This includes roaches and roach-by-products." + force = WEAPON_FORCE_DANGEROUS + throwforce = WEAPON_FORCE_NORMAL + armor_divisor = ARMOR_PEN_MODERATE + attack_verb = list("cleaved", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + matter = list(MATERIAL_STEEL = 5, MATERIAL_PLASTIC = 1) + tool_qualities = list(QUALITY_CUTTING = 20, QUALITY_WIRE_CUTTING = 15) + rarity_value = 5 + +/obj/item/tool/knife/neotritual + name = "NeoTheology ritual knife" + desc = "The sweet embrace of mercy, for relieving the soul from a tortured vessel." + icon = 'icons/obj/weapons.dmi' + icon_state = "neot-knife" + item_state = "knife" + matter = list(MATERIAL_PLASTEEL = 4, MATERIAL_PLASTIC = 1) + force = WEAPON_FORCE_PAINFUL + embed_mult = 6 + max_upgrades = 3 + spawn_blacklisted = TRUE + +/obj/item/tool/knife/neotritual/equipped(mob/living/H) + . = ..() + if(is_held() && is_neotheology_disciple(H)) + embed_mult = 0.05 + else + embed_mult = initial(embed_mult) + +/obj/item/tool/knife/tacknife + name = "tactical knife" + desc = "You'd be killing loads of people if this was Medal of Valor: Heroes of Space. Could be attached to a gun." + icon = 'icons/obj/weapons.dmi' + icon_state = "tacknife_guard" + item_state = "knife" + matter = list(MATERIAL_PLASTEEL = 3, MATERIAL_PLASTIC = 2) + force = WEAPON_FORCE_PAINFUL + armor_divisor = ARMOR_PEN_MODERATE + embed_mult = 0.6 + max_upgrades = 3 + +/obj/item/tool/knife/dagger + name = "dagger" + desc = "A sharp implement; difference between this and a knife is it is sharp on both sides. Good for finding holes in armor and exploiting them." + icon = 'icons/obj/weapons.dmi' + icon_state = "dagger" + item_state = "dagger" + matter = list(MATERIAL_PLASTEEL = 3, MATERIAL_PLASTIC = 2) + force = WEAPON_FORCE_NORMAL * 1.3 + armor_divisor = ARMOR_PEN_MASSIVE + rarity_value = 15 + +/obj/item/tool/knife/dagger/ceremonial + name = "ceremonial dagger" + desc = "Given to high ranking officers during their time in the stellar navy. A practical showing of accomplishment." + icon_state = "fancydagger" + item_state = "fancydagger" + matter = list(MATERIAL_PLASTEEL = 3, MATERIAL_PLASTIC = 2, MATERIAL_GOLD = 1, MATERIAL_SILVER = 1) + armor_divisor = ARMOR_PEN_MASSIVE + embed_mult = 0.6 + max_upgrades = 4 + spawn_blacklisted = TRUE + +/obj/item/tool/knife/dagger/bluespace + name = "Moebius \"Displacement Dagger\"" + desc = "A teleportation matrix attached to a dagger, for sending things you stab it into very far away." + icon_state = "bluespace_dagger" + item_state = "bluespace_dagger" + matter = list(MATERIAL_PLASTEEL = 3, MATERIAL_PLASTIC = 2, MATERIAL_SILVER = 10, MATERIAL_GOLD = 5, MATERIAL_PLASMA = 20) + force = WEAPON_FORCE_NORMAL+1 + embed_mult = 50 //You WANT it to embed + suitable_cell = /obj/item/cell/small + toggleable = TRUE + use_power_cost = 0.4 + passive_power_cost = 0.4 + origin_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 2, TECH_BLUESPACE = 4) + spawn_blacklisted = TRUE + price_tag = 400 + var/mob/living/embedded + var/last_teleport + var/entropy_value = 3 + +/obj/item/tool/knife/dagger/bluespace/on_embed(mob/user) + embedded = user + +/obj/item/tool/knife/dagger/bluespace/on_embed_removal(mob/user) + embedded = null + +/obj/item/tool/knife/dagger/bluespace/Process() + ..() + if(switched_on && embedded && cell) + if(last_teleport + max(3 SECONDS, embedded.mob_size*(cell.charge/cell.maxcharge)) < world.time) + var/area/A = random_ship_area() + var/turf/T = A.random_space() + if(T && cell.checked_use(use_power_cost*embedded.mob_size)) + last_teleport = world.time + playsound(T, "sparks", 50, 1) + anim(T,embedded,'icons/mob/mob.dmi',,"phaseout",,embedded.dir) + go_to_bluespace(get_turf(embedded), entropy_value, TRUE, embedded, T) + anim(T,embedded,'icons/mob/mob.dmi',,"phasein",,embedded.dir) + +/obj/item/tool/knife/dagger/assassin + name = "dagger" + desc = "A sharp implement, with a twist; The handle acts as a reservoir for reagents, and the blade injects those that it hits." + icon_state = "assdagger" + item_state = "ass_dagger" + reagent_flags = INJECTABLE|TRANSPARENT + matter = list(MATERIAL_PLASTEEL = 4, MATERIAL_DIAMOND = 2) + spawn_blacklisted = TRUE + +/obj/item/tool/knife/dagger/assassin/New() + ..() + create_reagents(80) + +/obj/item/tool/knife/dagger/assassin/resolve_attackby(atom/target, mob/user) + .=..() + if(!target.reagents || !isliving(target)) + return + + if(!reagents.total_volume) + return + + if(!target.reagents.get_free_space()) + return + var/modifier = 1 + var/reagent_modifier = 1 + if(ishuman(user)) + var/mob/living/carbon/human/H = user + modifier += min(30,H.stats.getStat(STAT_ROB)) + reagent_modifier = CLAMP(round(H.stats.getStat(STAT_BIO)/10), 1, 5) + var/mob/living/L = target + if(prob(min(100,(100-L.getarmor(user.targeted_organ, ARMOR_MELEE))+modifier))) + var/trans = reagents.trans_to_mob(target, rand(1,3)*reagent_modifier, CHEM_BLOOD) + admin_inject_log(user, target, src, reagents.log_list(), trans) + to_chat(user, SPAN_NOTICE("You inject [trans] units of the solution. [src] now contains [src.reagents.total_volume] units.")) + +/obj/item/tool/knife/butterfly + name = "butterfly knife" + desc = "A basic metal blade concealed in a lightweight plasteel grip. Small enough when folded to fit in a pocket." + icon = 'icons/obj/weapons.dmi' + icon_state = "butterflyknife" + item_state = "butterflyknife" + flags = CONDUCT + edge = FALSE + sharp = FALSE + force = WEAPON_FORCE_WEAK + switched_on_force = WEAPON_FORCE_PAINFUL + matter = list(MATERIAL_PLASTEEL = 4, MATERIAL_STEEL = 6) + switched_on_qualities = list(QUALITY_CUTTING = 20, QUALITY_WIRE_CUTTING = 10, QUALITY_SCREW_DRIVING = 5) + w_class = ITEM_SIZE_TINY + var/switched_on_w_class = ITEM_SIZE_SMALL + tool_qualities = list() + toggleable = TRUE + rarity_value = 25 + spawn_tags = SPAWN_TAG_KNIFE_CONTRABAND + +/obj/item/tool/knife/butterfly/turn_on(mob/user) + item_state = "[initial(item_state)]_on" + to_chat(user, SPAN_NOTICE("You flip out [src].")) + playsound(user, 'sound/weapons/flipblade.ogg', 15, 1) + edge = TRUE + sharp = TRUE + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + switched_on = TRUE + tool_qualities = switched_on_qualities + w_class = switched_on_w_class + if (!isnull(switched_on_force)) + force = switched_on_force + update_icon() + update_wear_icon() + +/obj/item/tool/knife/butterfly/turn_off(mob/user) + hitsound = initial(hitsound) + icon_state = initial(icon_state) + item_state = initial(item_state) + attack_verb = list("punched","cracked") + playsound(user, 'sound/weapons/flipblade.ogg', 15, 1) + to_chat(user, SPAN_NOTICE("You flip [src] back into the handle gracefully.")) + switched_on = FALSE + tool_qualities = switched_off_qualities + force = initial(force) + w_class = initial(w_class) + update_icon() + update_wear_icon() + +/obj/item/tool/knife/switchblade + name = "switchblade" + desc = "A classic switchblade with gold engraving. Just holding it makes you feel like a gangster." + icon = 'icons/obj/weapons.dmi' + icon_state = "switchblade" + item_state = "switchblade" + flags = CONDUCT + edge = FALSE + sharp = FALSE + force = WEAPON_FORCE_WEAK + switched_on_force = WEAPON_FORCE_PAINFUL + w_class = ITEM_SIZE_TINY + var/switched_on_w_class = ITEM_SIZE_SMALL + matter = list(MATERIAL_PLASTEEL = 4, MATERIAL_STEEL = 6, MATERIAL_GOLD= 0.5) + switched_on_qualities = list(QUALITY_CUTTING = 20, QUALITY_WIRE_CUTTING = 10, QUALITY_SCREW_DRIVING = 5) + tool_qualities = list() + toggleable = TRUE + rarity_value = 30 + spawn_tags = SPAWN_TAG_KNIFE_CONTRABAND + +/obj/item/tool/knife/switchblade/turn_on(mob/user) + item_state = "[initial(item_state)]_on" + to_chat(user, SPAN_NOTICE("You press a button on the handle and [src] slides out.")) + playsound(user, 'sound/weapons/flipblade.ogg', 15, 1) + edge = TRUE + sharp = TRUE + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + switched_on = TRUE + tool_qualities = switched_on_qualities + if (!isnull(switched_on_force)) + force = switched_on_force + w_class = switched_on_w_class + update_icon() + update_wear_icon() + +/obj/item/tool/knife/switchblade/turn_off(mob/user) + hitsound = initial(hitsound) + icon_state = initial(icon_state) + item_state = initial(item_state) + attack_verb = list("punched","cracked") + playsound(user, 'sound/weapons/flipblade.ogg', 15, 1) + to_chat(user, SPAN_NOTICE("You press the button and [src] swiftly retracts.")) + switched_on = FALSE + tool_qualities = switched_off_qualities + force = initial(force) + w_class = initial(w_class) + update_icon() + update_wear_icon() + +//A makeshift knife, for doing all manner of cutting and stabbing tasks in a half-assed manner +/obj/item/tool/knife/shiv + name = "shiv" + desc = "A pointy piece of glass, abraded to an edge and wrapped in tape for a handle. Could become a decent tool or weapon with right tool mods." + icon = 'icons/obj/tools.dmi' + icon_state = "impro_shiv" + item_state = "shiv" + worksound = WORKSOUND_HARD_SLASH + matter = list(MATERIAL_GLASS = 1) + sharp = TRUE + edge = TRUE + force = WEAPON_FORCE_NORMAL + w_class = ITEM_SIZE_TINY + slot_flags = SLOT_EARS + tool_qualities = list(QUALITY_CUTTING = 15, QUALITY_WIRE_CUTTING = 5, QUALITY_DRILLING = 5) + degradation = 4 //Gets worse with use + max_upgrades = 5 //all makeshift tools get more mods to make them actually viable for mid-late game + spawn_tags = SPAWN_TAG_JUNKTOOL + +/obj/item/tool/spear + name = "glass spear" + desc = "A piece of glass tied using cable coil onto two welded rods. Impressive work." + icon = 'icons/obj/weapons.dmi' + icon_state = "spear_glass" + item_state = "spear_glass" + wielded_icon = "spear_glass_wielded" + flags = CONDUCT + sharp = TRUE + edge = TRUE + extended_reach = TRUE + push_attack = TRUE + worksound = WORKSOUND_HARD_SLASH + w_class = ITEM_SIZE_BULKY //4 , it's a spear mate + force = WEAPON_FORCE_PAINFUL + throwforce = WEAPON_FORCE_DANGEROUS + armor_divisor = ARMOR_PEN_MODERATE + throw_speed = 3 + max_upgrades = 5 + tool_qualities = list(QUALITY_CUTTING = 10, QUALITY_WIRE_CUTTING = 5, QUALITY_SCREW_DRIVING = 1) + matter = list(MATERIAL_STEEL = 1, MATERIAL_GLASS = 1) + attack_verb = list("slashed", "stabbed") //there's not much you can do with a spear aside from stabbing and slashing with it + hitsound = 'sound/weapons/melee/heavystab.ogg' + slot_flags = SLOT_BACK + structure_damage_factor = STRUCTURE_DAMAGE_BLADE + allow_spin = FALSE + style_damage = 20 + + rarity_value = 20 + spawn_tags = SPAWN_TAG_KNIFE + +/obj/item/tool/spear/steel + name = "steel spear" + desc = "A steel spearhead welded to a crude metal shaft, made from two welded rods. It'll serve well enough." + icon_state = "spear_steel" + item_state = "spear_steel" + wielded_icon = "spear_steel_wielded" + force = WEAPON_FORCE_DANGEROUS + throwforce = WEAPON_FORCE_ROBUST + armor_divisor = ARMOR_PEN_DEEP + tool_qualities = list(QUALITY_CUTTING = 10, QUALITY_WIRE_CUTTING = 5, QUALITY_SCREW_DRIVING = 5) + matter = list(MATERIAL_STEEL = 3) + structure_damage_factor = STRUCTURE_DAMAGE_WEAK + style_damage = 30 + + rarity_value = 60 + +/obj/item/tool/spear/plasteel + name = "plasteel spear" + desc = "A carefully crafted plasteel spearhead affixed to a metal shaft, it is welded securely on and feels balanced. Show them the past still lives." + icon_state = "spear_plasteel" + item_state = "spear_plasteel" + wielded_icon = "spear_plasteel_wielded" + force = WEAPON_FORCE_ROBUST + throwforce = WEAPON_FORCE_BRUTAL + armor_divisor = ARMOR_PEN_DEEP + tool_qualities = list(QUALITY_CUTTING = 15, QUALITY_WIRE_CUTTING = 10, QUALITY_SCREW_DRIVING = 10) + matter = list(MATERIAL_STEEL = 1, MATERIAL_PLASTEEL = 2) + structure_damage_factor = STRUCTURE_DAMAGE_NORMAL + style_damage = 50 + +/obj/item/tool/spear/uranium + name = "uranium spear" + desc = "A steel spear with a uranium lined spearhead. Your foes may survive the stab, but the toxin will linger." + icon_state = "spear_uranium" + item_state = "spear_uranium" + wielded_icon = "spear_uranium_wielded" + force = WEAPON_FORCE_DANGEROUS + throwforce = WEAPON_FORCE_DANGEROUS + armor_divisor = ARMOR_PEN_DEEP + tool_qualities = list(QUALITY_CUTTING = 10, QUALITY_WIRE_CUTTING = 5, QUALITY_SCREW_DRIVING = 5) + matter = list(MATERIAL_STEEL = 3, MATERIAL_URANIUM = 1) + style_damage = 50 + +/obj/item/tool/spear/uranium/apply_hit_effect(mob/living/carbon/human/target, mob/living/user, hit_zone) + ..() + if(istype(target)) + target.apply_effect(rand(5, 10), IRRADIATE) + +/obj/item/tool/spear/makeshift_halberd + name = "makeshift halberd" + desc = "Slap a heavy blade on some rods duct-taped together and call it a day." + icon_state = "makeshift_halberd" + item_state = "makeshift_halberd" + wielded_icon = "makeshift_halberd_wielded" + force = WEAPON_FORCE_ROBUST + throwforce = WEAPON_FORCE_NORMAL + armor_divisor = ARMOR_PEN_SHALLOW + tool_qualities = list(QUALITY_CUTTING = 10) + matter = list(MATERIAL_STEEL = 5) + forced_broad_strike = TRUE + rarity_value = 90 + degradation = 3 diff --git a/code/game/objects/items/weapons/tools/misc.dm b/code/game/objects/items/weapons/tools/misc.dm new file mode 100644 index 0000000000000..88581badbbcfa --- /dev/null +++ b/code/game/objects/items/weapons/tools/misc.dm @@ -0,0 +1,162 @@ +/obj/item/tool/omnitool + name = "Asters \"Munchkin 5000\"" + desc = "A fuel powered monster of a tool. Its welding attachment is capable of welding things without an eye-damaging flash, so no eye protection is required." + icon_state = "omnitool" + w_class = ITEM_SIZE_NORMAL + worksound = WORKSOUND_DRIVER_TOOL + switched_on_qualities = list(QUALITY_SCREW_DRIVING = 50, QUALITY_BOLT_TURNING = 50, QUALITY_DRILLING = 20, QUALITY_WELDING = 30, QUALITY_CAUTERIZING = 10) + price_tag = 1000 + use_fuel_cost = 0.1 + max_fuel = 50 + + toggleable = TRUE + create_hot_spot = TRUE + glow_color = COLOR_ORANGE + max_upgrades = 2 + rarity_value = 96 + spawn_tags = SPAWN_TAG_TOOL_ADVANCED + +/obj/item/tool/medmultitool + name = "One Star medmultitool" + desc = "A compact One Star medical multitool. It has all surgery tools." + icon_state = "medmulti" + matter = list(MATERIAL_STEEL = 3, MATERIAL_GLASS = 2, MATERIAL_PLATINUM = 2) + flags = CONDUCT + origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 4) + tool_qualities = list(QUALITY_CLAMPING = 30, QUALITY_RETRACTING = 30, QUALITY_BONE_SETTING = 30, QUALITY_CAUTERIZING = 30, QUALITY_SAWING = 15, QUALITY_CUTTING = 30, QUALITY_WIRE_CUTTING = 25) + + max_upgrades = 2 + workspeed = 1.2 + spawn_blacklisted = TRUE + rarity_value = 10 + spawn_frequency = 10 + spawn_tags = SPAWN_TAG_OS_TOOL + +/obj/item/tool/medmultitool/medimplant + name = "Medical Omnitool" + desc = "An all-in-one medical tool implant based on the legendary One Star model. While convenient, it is less efficient than more advanced surgical tools, such as laser scalpels, and requires a power cell." + icon_state = "medimplant" + matter = null + force = WEAPON_FORCE_PAINFUL + sharp = TRUE + edge = TRUE + worksound = WORKSOUND_DRIVER_TOOL + flags = CONDUCT + tool_qualities = list(QUALITY_CLAMPING = 30, QUALITY_RETRACTING = 30, QUALITY_BONE_SETTING = 30, QUALITY_CAUTERIZING = 30, QUALITY_SAWING = 15, QUALITY_CUTTING = 30, QUALITY_WIRE_CUTTING = 15) + degradation = 0.5 + workspeed = 0.8 + + use_power_cost = 1.2 + suitable_cell = /obj/item/cell/medium + + max_upgrades = 1 + spawn_tags = null + +/obj/item/tool/multitool_improvised + name= "improvised multitool implant" + desc = "A jury-rigged implant, holding cobbled-together tools. For those who are more interested in tool carrying than scared of tetanus." + icon = 'icons/obj/surgery.dmi' + icon_state = "multitool_improvised" + force = WEAPON_FORCE_PAINFUL + switched_on_force = WEAPON_FORCE_PAINFUL * 0.8 + worksound = WORKSOUND_DRIVER_TOOL + flags = CONDUCT + switched_on_qualities = list( + QUALITY_CUTTING = 15, + QUALITY_DRILLING = 5, + QUALITY_SCREW_DRIVING = 15, + QUALITY_WIRE_CUTTING = 20, + QUALITY_RETRACTING = 10, + QUALITY_BONE_SETTING = 10, + QUALITY_PRYING = 10, + QUALITY_HAMMERING = 10, + QUALITY_BOLT_TURNING = 20, + QUALITY_SHOVELING = 25, + QUALITY_DIGGING = 25, + QUALITY_EXCAVATION = 10, + QUALITY_SAWING = 15, + QUALITY_WELDING = 15, + QUALITY_CAUTERIZING = 10) + bad_type = /obj/item/tool/multitool_improvised + degradation = 1.5 + workspeed = 0.8 + + max_upgrades = 3 + + sparks_on_use = TRUE + eye_hazard = FALSE + + use_fuel_cost = 0.1 + max_fuel = 30 + + toggleable = TRUE + create_hot_spot = TRUE + glow_color = COLOR_ORANGE + + heat = 2250 + + +/obj/item/tool/engimplant + name = "Engineering Omnitool" + desc = "An all-in-one engineering tool implant. Convenient to use and more effective than the basics, but much less efficient than customized or more specialized tools." + icon_state = "engimplant" + force = WEAPON_FORCE_DANGEROUS + worksound = WORKSOUND_DRIVER_TOOL + flags = CONDUCT + tool_qualities = list(QUALITY_SCREW_DRIVING = 35, QUALITY_BOLT_TURNING = 35, QUALITY_DRILLING = 15, QUALITY_WELDING = 30, QUALITY_CAUTERIZING = 10, QUALITY_PRYING = 25, QUALITY_DIGGING = 20, QUALITY_PULSING = 30, QUALITY_WIRE_CUTTING = 30, QUALITY_HAMMERING = 25) + degradation = 0.5 + workspeed = 0.8 + + use_power_cost = 0.8 + suitable_cell = /obj/item/cell/medium + + max_upgrades = 1 + spawn_tags = null + + var/buffer_name + var/atom/buffer_object + +/obj/item/tool/engimplant/Destroy() // code for omnitool buffers was copied from multitools.dm + unregister_buffer(buffer_object) + return ..() + +/obj/item/tool/engimplant/proc/get_buffer(typepath) + get_buffer_name(TRUE) + if(buffer_object && (!typepath || istype(buffer_object, typepath))) + return buffer_object + +/obj/item/tool/engimplant/proc/get_buffer_name(null_name_if_missing = FALSE) + if(buffer_object) + buffer_name = buffer_object.name + else if(null_name_if_missing) + buffer_name = null + return buffer_name + +/obj/item/tool/engimplant/proc/set_buffer(atom/buffer) + if(!buffer || istype(buffer)) + buffer_name = buffer ? buffer.name : null + if(buffer != buffer_object) + unregister_buffer(buffer_object) + buffer_object = buffer + if(buffer_object) + GLOB.destroyed_event.register(buffer_object, src, /obj/item/tool/engimplant/proc/unregister_buffer) + +/obj/item/tool/engimplant/proc/unregister_buffer(atom/buffer_to_unregister) + // Only remove the buffered object, don't reset the name + // This means one cannot know if the buffer has been destroyed until one attempts to use it. + if(buffer_to_unregister == buffer_object && buffer_object) + GLOB.destroyed_event.unregister(buffer_object, src) + buffer_object = null + +/obj/item/tool/engimplant/resolve_attackby(atom/A, mob/user) + if(!isobj(A)) + return ..(A, user) + + var/obj/O = A + var/datum/extension/multitool/MT = get_extension(O, /datum/extension/multitool) + if(!MT) + return ..(A, user) + + user.AddTopicPrint(src) + MT.interact(src, user) + return 1 diff --git a/code/game/objects/items/weapons/tools/mods/_upgrades.dm b/code/game/objects/items/weapons/tools/mods/_upgrades.dm new file mode 100644 index 0000000000000..fea049bd6c1e6 --- /dev/null +++ b/code/game/objects/items/weapons/tools/mods/_upgrades.dm @@ -0,0 +1,659 @@ +/* + A tool upgrade is a little attachment for a tool that improves it in some way + Tool upgrades are generally permanant + + Some upgrades have multiple bonuses. Some have drawbacks in addition to boosts +*/ + +/*/client/verb/debugupgrades() + for (var/t in subtypesof(/obj/item/tool_upgrade)) + new t(usr.loc) +*/ +/datum/component/item_upgrade + dupe_mode = COMPONENT_DUPE_UNIQUE + can_transfer = TRUE + var/prefix = "upgraded" //Added to the tool's name + + var/removal_time = WORKTIME_SLOW + var/removal_difficulty = FAILCHANCE_CHALLENGING + var/destroy_on_removal = FALSE + //The upgrade can be applied to a tool that has any of these qualities + var/list/required_qualities = list() + var/removable = TRUE + var/breakable = TRUE //Some mods meant to be tamper-resistant and should be removed only in a hard way + + //The upgrade can not be applied to a tool that has any of these qualities + var/list/negative_qualities = list() + + //If REQ_FUEL, can only be applied to tools that use fuel. If REQ_CELL, can only be applied to tools that use cell, If REQ_FUEL_OR_CELL, can be applied if it has fuel OR a cell + var/req_fuel_cell = FALSE + + var/exclusive_type + + //Actual effects of upgrades + var/list/tool_upgrades = list() //variable name(string) -> num + + //Weapon upgrades + var/list/gun_loc_tag //Define(string). For checking if the gun already has something of this installed (No double trigger mods, for instance) + var/list/req_gun_tags = list() //Define(string). Must match all to be able to install it. + var/list/weapon_upgrades = list() //variable name(string) -> num + +/datum/component/item_upgrade/RegisterWithParent() + RegisterSignal(parent, COMSIG_IATTACK, .proc/attempt_install) + RegisterSignal(parent, COMSIG_EXAMINE, .proc/on_examine) + RegisterSignal(parent, COMSIG_REMOVE, .proc/uninstall) + +/datum/component/item_upgrade/proc/attempt_install(atom/A, mob/living/user, params) + return can_apply(A, user) && apply(A, user) + +/datum/component/item_upgrade/proc/can_apply(atom/A, mob/living/user) + if(isrobot(A)) + return check_robot(A, user) + + if(isitem(A)) + var/obj/item/T = A + //No using multiples of the same upgrade + for (var/obj/item/I in T.item_upgrades) + if(I.type == parent.type || (exclusive_type && istype(I.type, exclusive_type))) + if(user) + to_chat(user, SPAN_WARNING("An upgrade of this type is already installed!")) + return FALSE + + if(istool(A)) + return check_tool(A, user) + + if(isgun(A)) + return check_gun(A, user) + + return FALSE + +/datum/component/item_upgrade/proc/check_robot(mob/living/silicon/robot/R, mob/living/user) + if(!R.opened) + if(user) + to_chat(user, SPAN_WARNING("You need to open [R]'s panel to access its tools.")) + return FALSE + var/list/robotools = list() + for(var/obj/item/tool/robotool in R.module.modules) + robotools.Add(robotool) + if(robotools.len) + var/obj/item/tool/chosen_tool = input(user,"Which tool are you trying to modify?","Tool Modification","Cancel") in robotools + "Cancel" + if(chosen_tool == "Cancel") + return FALSE + return can_apply(chosen_tool,user) + if(user) + to_chat(user, SPAN_WARNING("[R] has no modifiable tools.")) + return FALSE + +/datum/component/item_upgrade/proc/check_tool(obj/item/tool/T, mob/living/user) + if(!tool_upgrades.len) + to_chat(user, SPAN_WARNING("\The [parent] can not be attached to a tool.")) + return FALSE + + if(T.item_upgrades.len >= T.max_upgrades) + if(user) + to_chat(user, SPAN_WARNING("This tool can't fit anymore modifications!")) + return FALSE + + if(required_qualities.len) + var/qmatch = FALSE + for (var/q in required_qualities) + if(T.ever_has_quality(q)) + qmatch = TRUE + break + + if(!qmatch) + if(user) + to_chat(user, SPAN_WARNING("This tool lacks the required qualities!")) + return FALSE + + if(negative_qualities.len) + for(var/i in negative_qualities) + if(T.ever_has_quality(i)) + if(user) + to_chat(user, SPAN_WARNING("This tool can not accept the modification!")) + return FALSE + + if((req_fuel_cell & REQ_FUEL) && !T.use_fuel_cost) + if(user) + to_chat(user, SPAN_WARNING("This tool does not use fuel!")) + return FALSE + + if((req_fuel_cell & REQ_CELL) && !T.use_power_cost) + if(user) + to_chat(user, SPAN_WARNING("This tool does not use power!")) + return FALSE + + if((req_fuel_cell & REQ_FUEL_OR_CELL) && (!T.use_power_cost && !T.use_fuel_cost)) + if(user) + to_chat(user, SPAN_WARNING("This tool does not use [T.use_power_cost?"fuel":"power"]!")) + return FALSE + + if(tool_upgrades[UPGRADE_SANCTIFY]) + if(SANCTIFIED in T.aspects) + if(user) + to_chat(user, SPAN_WARNING("This tool already sanctified!")) + return FALSE + + if(tool_upgrades[UPGRADE_CELLPLUS]) + if(!(T.suitable_cell == /obj/item/cell/medium || T.suitable_cell == /obj/item/cell/small)) + if(user) + to_chat(user, SPAN_WARNING("This tool does not require a cell holding upgrade.")) + return FALSE + if(T.cell) + if(user) + to_chat(user, SPAN_WARNING("Remove the cell from the tool first!")) + return FALSE + + return TRUE + +/datum/component/item_upgrade/proc/check_gun(obj/item/gun/G, mob/living/user) + if(!weapon_upgrades.len) + if(user) + to_chat(user, SPAN_WARNING("\The [parent] can not be applied to guns!")) + return FALSE //Can't be applied to a weapon + + if(G.item_upgrades.len >= G.max_upgrades) + if(user) + to_chat(user, SPAN_WARNING("This weapon can't fit anymore modifications!")) + return FALSE + + for(var/obj/I in G.item_upgrades) + var/datum/component/item_upgrade/IU = I.GetComponent(/datum/component/item_upgrade) + if(IU && IU.gun_loc_tag == gun_loc_tag) + if(user) + to_chat(user, SPAN_WARNING("There is already something attached to \the [G]'s [gun_loc_tag]!")) + return FALSE + + for(var/I in req_gun_tags) + if(!G.gun_tags.Find(I)) + if(user) + to_chat(user, SPAN_WARNING("\The [G] lacks the following property: [I]")) + return FALSE + + if((req_fuel_cell & REQ_CELL) && !istype(G, /obj/item/gun/energy)) + if(user) + to_chat(user, SPAN_WARNING("This weapon does not use power!")) + return FALSE + return TRUE + +/datum/component/item_upgrade/proc/apply(obj/item/A, mob/living/user) + if(user) + user.visible_message(SPAN_NOTICE("[user] starts applying [parent] to [A]"), SPAN_NOTICE("You start applying \the [parent] to \the [A]")) + var/obj/item/I = parent + if(!I.use_tool(user = user, target = A, base_time = WORKTIME_FAST, required_quality = null, fail_chance = FAILCHANCE_ZERO, required_stat = STAT_MEC, forced_sound = WORKSOUND_WRENCHING)) + return FALSE + to_chat(user, SPAN_NOTICE("You have successfully installed \the [parent] in \the [A]")) + user.drop_from_inventory(parent) + //If we get here, we succeeded in the applying + var/obj/item/I = parent + I.forceMove(A) + A.item_upgrades.Add(I) + RegisterSignal(A, COMSIG_APPVAL, .proc/apply_values) + RegisterSignal(A, COMSIG_ADDVAL, .proc/add_values) + A.AddComponent(/datum/component/upgrade_removal) + A.refresh_upgrades() + return TRUE + +/datum/component/item_upgrade/proc/uninstall(obj/item/I, mob/living/user) + var/obj/item/P = parent + I.item_upgrades -= P + if(destroy_on_removal) + UnregisterSignal(I, COMSIG_ADDVAL) + UnregisterSignal(I, COMSIG_APPVAL) + qdel(P) + return + P.forceMove(get_turf(I)) + UnregisterSignal(I, COMSIG_ADDVAL) + UnregisterSignal(I, COMSIG_APPVAL) + +/datum/component/item_upgrade/proc/apply_values(atom/holder) + if(!holder) + return + if(istool(holder)) + apply_values_tool(holder) + if(isgun(holder)) + apply_values_gun(holder) + return TRUE + +/datum/component/item_upgrade/proc/add_values(atom/holder) + ASSERT(holder) + if(isgun(holder)) + add_values_gun(holder) + return TRUE + +/datum/component/item_upgrade/proc/apply_values_tool(obj/item/tool/T) + if(tool_upgrades[UPGRADE_SANCTIFY]) + T.aspects += list(SANCTIFIED) + if(tool_upgrades[UPGRADE_PRECISION]) + T.precision += tool_upgrades[UPGRADE_PRECISION] + if(tool_upgrades[UPGRADE_WORKSPEED]) + T.workspeed += tool_upgrades[UPGRADE_WORKSPEED] + if(tool_upgrades[UPGRADE_DEGRADATION_MULT]) + T.degradation *= tool_upgrades[UPGRADE_DEGRADATION_MULT] + if(tool_upgrades[UPGRADE_FORCE_MULT]) + T.force_upgrade_mults += tool_upgrades[UPGRADE_FORCE_MULT] - 1 + if(tool_upgrades[UPGRADE_FORCE_MOD]) + T.force_upgrade_mods += tool_upgrades[UPGRADE_FORCE_MOD] + if(tool_upgrades[UPGRADE_FUELCOST_MULT]) + T.use_fuel_cost *= tool_upgrades[UPGRADE_FUELCOST_MULT] + if(tool_upgrades[UPGRADE_POWERCOST_MULT]) + T.use_power_cost *= tool_upgrades[UPGRADE_POWERCOST_MULT] + if(tool_upgrades[UPGRADE_BULK]) + T.extra_bulk += tool_upgrades[UPGRADE_BULK] + if(tool_upgrades[UPGRADE_HEALTH_THRESHOLD]) + T.health_threshold += tool_upgrades[UPGRADE_HEALTH_THRESHOLD] + if(tool_upgrades[UPGRADE_MAXFUEL]) + T.max_fuel += tool_upgrades[UPGRADE_MAXFUEL] + if(tool_upgrades[UPGRADE_MAXUPGRADES]) + T.max_upgrades += tool_upgrades[UPGRADE_MAXUPGRADES] + if(tool_upgrades[UPGRADE_SHARP]) + T.sharp = tool_upgrades[UPGRADE_SHARP] + if(tool_upgrades[UPGRADE_COLOR]) + T.color = tool_upgrades[UPGRADE_COLOR] + if(tool_upgrades[UPGRADE_ITEMFLAGPLUS]) + T.item_flags |= tool_upgrades[UPGRADE_ITEMFLAGPLUS] + if(tool_upgrades[UPGRADE_CELLPLUS]) + switch(T.suitable_cell) + if(/obj/item/cell/medium) + T.suitable_cell = /obj/item/cell/large + prefix = "large-cell" + if(/obj/item/cell/small) + T.suitable_cell = /obj/item/cell/medium + T.force = initial(T.force) * T.force_upgrade_mults + T.force_upgrade_mods + T.switched_on_force = initial(T.switched_on_force) * T.force_upgrade_mults + T.force_upgrade_mods + T.prefixes |= prefix + +/datum/component/item_upgrade/proc/apply_values_gun(var/obj/item/gun/G) + if(weapon_upgrades[GUN_UPGRADE_DAMAGE_MULT]) + G.damage_multiplier *= weapon_upgrades[GUN_UPGRADE_DAMAGE_MULT] + if(weapon_upgrades[GUN_UPGRADE_DAMAGEMOD_PLUS]) + G.damage_multiplier += weapon_upgrades[GUN_UPGRADE_DAMAGEMOD_PLUS] + if(weapon_upgrades[GUN_UPGRADE_PEN_MULT]) + G.penetration_multiplier += weapon_upgrades[GUN_UPGRADE_PEN_MULT] + if(weapon_upgrades[GUN_UPGRADE_PIERC_MULT]) + G.pierce_multiplier += weapon_upgrades[GUN_UPGRADE_PIERC_MULT] + if(weapon_upgrades[GUN_UPGRADE_RICO_MULT]) + G.ricochet_multiplier += weapon_upgrades[GUN_UPGRADE_RICO_MULT] + if(weapon_upgrades[GUN_UPGRADE_STEPDELAY_MULT]) + G.proj_step_multiplier *= weapon_upgrades[GUN_UPGRADE_STEPDELAY_MULT] + if(weapon_upgrades[GUN_UPGRADE_FIRE_DELAY_MULT]) + G.fire_delay *= weapon_upgrades[GUN_UPGRADE_FIRE_DELAY_MULT] + if(weapon_upgrades[GUN_UPGRADE_MOVE_DELAY_MULT]) + G.move_delay *= weapon_upgrades[GUN_UPGRADE_MOVE_DELAY_MULT] + if(weapon_upgrades[GUN_UPGRADE_RECOIL]) + G.recoil = G.recoil.modifyAllRatings(weapon_upgrades[GUN_UPGRADE_RECOIL]) + if(weapon_upgrades[GUN_UPGRADE_MUZZLEFLASH]) + G.muzzle_flash *= weapon_upgrades[GUN_UPGRADE_MUZZLEFLASH] + if(weapon_upgrades[GUN_UPGRADE_SILENCER]) + G.silenced = weapon_upgrades[GUN_UPGRADE_SILENCER] + if(weapon_upgrades[GUN_UPGRADE_OFFSET]) + G.init_offset = max(0, G.init_offset+weapon_upgrades[GUN_UPGRADE_OFFSET]) + if(weapon_upgrades[GUN_UPGRADE_DAMAGE_BRUTE]) + G.proj_damage_adjust[BRUTE] += weapon_upgrades[GUN_UPGRADE_DAMAGE_BRUTE] + if(weapon_upgrades[GUN_UPGRADE_DAMAGE_BURN]) + G.proj_damage_adjust[BURN] += weapon_upgrades[GUN_UPGRADE_DAMAGE_BURN] + if(weapon_upgrades[GUN_UPGRADE_DAMAGE_TOX]) + G.proj_damage_adjust[TOX] += weapon_upgrades[GUN_UPGRADE_DAMAGE_TOX] + if(weapon_upgrades[GUN_UPGRADE_DAMAGE_OXY]) + G.proj_damage_adjust[OXY] += weapon_upgrades[GUN_UPGRADE_DAMAGE_OXY] + if(weapon_upgrades[GUN_UPGRADE_DAMAGE_CLONE]) + G.proj_damage_adjust[CLONE] += weapon_upgrades[GUN_UPGRADE_DAMAGE_CLONE] + if(weapon_upgrades[GUN_UPGRADE_DAMAGE_HALLOSS]) + G.proj_damage_adjust[HALLOSS] += weapon_upgrades[GUN_UPGRADE_DAMAGE_HALLOSS] + if(weapon_upgrades[GUN_UPGRADE_DAMAGE_RADIATION]) + G.proj_damage_adjust[IRRADIATE] += weapon_upgrades[GUN_UPGRADE_DAMAGE_RADIATION] + if(weapon_upgrades[GUN_UPGRADE_DAMAGE_PSY]) + G.proj_damage_adjust[PSY] += weapon_upgrades[GUN_UPGRADE_DAMAGE_PSY] + if(weapon_upgrades[GUN_UPGRADE_HONK]) + G.fire_sound = 'sound/items/bikehorn.ogg' + if(weapon_upgrades[GUN_UPGRADE_RIGGED]) + G.rigged = TRUE + if(weapon_upgrades[GUN_UPGRADE_FOREGRIP]) + G.braceable = 0 + if(weapon_upgrades[GUN_UPGRADE_BIPOD]) + G.braceable = 2 + if(weapon_upgrades[GUN_UPGRADE_EXPLODE]) + G.rigged = 2 + if(weapon_upgrades[GUN_UPGRADE_ZOOM]) + if(G.zoom_factors.len <1) + var/newtype = weapon_upgrades[GUN_UPGRADE_ZOOM] + G.zoom_factors.Add(newtype) + G.initialize_scope() + if(ismob(G.loc)) + var/mob/user = G.loc + user.update_action_buttons() + if(weapon_upgrades[GUN_UPGRADE_THERMAL]) + G.vision_flags = SEE_MOBS + if(weapon_upgrades[GUN_UPGRADE_GILDED]) + G.gilded = TRUE + + if(weapon_upgrades[GUN_UPGRADE_BAYONET]) + G.attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + G.sharp = TRUE + if(weapon_upgrades[GUN_UPGRADE_MELEEDAMAGE]) + G.force += weapon_upgrades[GUN_UPGRADE_MELEEDAMAGE] + if(weapon_upgrades[GUN_UPGRADE_MELEEPENETRATION]) + G.armor_divisor += weapon_upgrades[GUN_UPGRADE_MELEEPENETRATION] + if(weapon_upgrades[GUN_UPGRADE_ONEHANDPENALTY]) + G.recoil = G.recoil.modifyRating(_one_hand_penalty = weapon_upgrades[GUN_UPGRADE_ONEHANDPENALTY]) + + if(weapon_upgrades[GUN_UPGRADE_DNALOCK]) + G.dna_compare_samples = TRUE + if(G.dna_lock_sample == "not_set") + G.dna_lock_sample = usr.real_name + + if(G.dna_compare_samples == FALSE) + G.dna_lock_sample = "not_set" + + if(G.dna_lock_sample == "not_set") //that may look stupid, but without it previous two lines won't trigger on DNALOCK removal. + G.dna_compare_samples = FALSE + + if(!isnull(weapon_upgrades[GUN_UPGRADE_FORCESAFETY])) + G.restrict_safety = TRUE + G.safety = weapon_upgrades[GUN_UPGRADE_FORCESAFETY] + if(istype(G, /obj/item/gun/energy)) + var/obj/item/gun/energy/E = G + if(weapon_upgrades[GUN_UPGRADE_CHARGECOST]) + E.charge_cost *= weapon_upgrades[GUN_UPGRADE_CHARGECOST] + if(weapon_upgrades[GUN_UPGRADE_OVERCHARGE_MAX]) + E.overcharge_rate *= weapon_upgrades[GUN_UPGRADE_OVERCHARGE_MAX] + if(weapon_upgrades[GUN_UPGRADE_OVERCHARGE_MAX]) + E.overcharge_max *= weapon_upgrades[GUN_UPGRADE_OVERCHARGE_MAX] + + if(istype(G, /obj/item/gun/projectile)) + var/obj/item/gun/projectile/P = G + if(weapon_upgrades[GUN_UPGRADE_MAGUP]) + P.max_shells += weapon_upgrades[GUN_UPGRADE_MAGUP] + + for(var/datum/firemode/F in G.firemodes) + apply_values_firemode(F) + +/datum/component/item_upgrade/proc/add_values_gun(obj/item/gun/G) + if(weapon_upgrades[GUN_UPGRADE_FULLAUTO]) + G.add_firemode(FULL_AUTO_400) + +/datum/component/item_upgrade/proc/apply_values_firemode(datum/firemode/F) + for(var/i in F.settings) + switch(i) + if("fire_delay") + if(weapon_upgrades[GUN_UPGRADE_FIRE_DELAY_MULT]) + F.settings[i] *= weapon_upgrades[GUN_UPGRADE_FIRE_DELAY_MULT] + if("move_delay") + if(weapon_upgrades[GUN_UPGRADE_MOVE_DELAY_MULT]) + F.settings[i] *= weapon_upgrades[GUN_UPGRADE_MOVE_DELAY_MULT] + +/datum/component/item_upgrade/proc/on_examine(mob/user) + if(tool_upgrades[UPGRADE_SANCTIFY]) + to_chat(user, SPAN_NOTICE("Does additional burn damage to mutants.")) + if (tool_upgrades[UPGRADE_PRECISION] > 0) + to_chat(user, SPAN_NOTICE("Enhances precision by [tool_upgrades[UPGRADE_PRECISION]]")) + else if(tool_upgrades[UPGRADE_PRECISION] < 0) + to_chat(user, SPAN_WARNING("Reduces precision by [abs(tool_upgrades[UPGRADE_PRECISION])]")) + if(tool_upgrades[UPGRADE_WORKSPEED]) + to_chat(user, SPAN_NOTICE("Enhances workspeed by [tool_upgrades[UPGRADE_WORKSPEED]*100]%")) + + if(tool_upgrades[UPGRADE_DEGRADATION_MULT]) + if(tool_upgrades[UPGRADE_DEGRADATION_MULT] < 1) + to_chat(user, SPAN_NOTICE("Reduces tool degradation by [(1-tool_upgrades[UPGRADE_DEGRADATION_MULT])*100]%")) + else if (tool_upgrades[UPGRADE_DEGRADATION_MULT] > 1) + to_chat(user, SPAN_WARNING("Increases tool degradation by [(tool_upgrades[UPGRADE_DEGRADATION_MULT]-1)*100]%")) + + if(tool_upgrades[UPGRADE_FORCE_MULT] >= 1) + to_chat(user, SPAN_NOTICE("Increases tool damage by [(tool_upgrades[UPGRADE_FORCE_MULT]-1)*100]%")) + if(tool_upgrades[UPGRADE_FORCE_MOD]) + to_chat(user, SPAN_NOTICE("Increases tool damage by [tool_upgrades[UPGRADE_FORCE_MOD]]")) + if(tool_upgrades[UPGRADE_POWERCOST_MULT] >= 1) + to_chat(user, SPAN_WARNING("Modifies power usage by [(tool_upgrades[UPGRADE_POWERCOST_MULT]-1)*100]%")) + if(tool_upgrades[UPGRADE_FUELCOST_MULT] >= 1) + to_chat(user, SPAN_WARNING("Modifies fuel usage by [(tool_upgrades[UPGRADE_FUELCOST_MULT]-1)*100]%")) + if(tool_upgrades[UPGRADE_MAXFUEL]) + to_chat(user, SPAN_NOTICE("Modifies fuel storage by [tool_upgrades[UPGRADE_MAXFUEL]] units.")) + if(tool_upgrades[UPGRADE_BULK]) + to_chat(user, SPAN_WARNING("Increases tool size by [tool_upgrades[UPGRADE_BULK]]")) + if(tool_upgrades[UPGRADE_MAXUPGRADES]) + to_chat(user, SPAN_NOTICE("Adds [tool_upgrades[UPGRADE_MAXUPGRADES]] additional modification slots.")) + if(required_qualities.len) + to_chat(user, SPAN_WARNING("Requires a tool with one of the following qualities:")) + to_chat(user, english_list(required_qualities, and_text = " or ")) + + if(weapon_upgrades.len) + to_chat(user, SPAN_NOTICE("Can be attached to a firearm, giving the following benefits:")) + + if(weapon_upgrades[GUN_UPGRADE_DAMAGE_MULT]) + var/amount = weapon_upgrades[GUN_UPGRADE_DAMAGE_MULT]-1 + if(amount > 0) + to_chat(user, SPAN_NOTICE("Increases projectile damage by [amount*100]%")) + else + to_chat(user, SPAN_WARNING("Decreases projectile damage by [abs(amount*100)]%")) + + if(weapon_upgrades[GUN_UPGRADE_PEN_MULT]) + var/amount = weapon_upgrades[GUN_UPGRADE_PEN_MULT] + if(amount > 0) + to_chat(user, SPAN_NOTICE("Increases projectile penetration by [amount*100]%")) + else + to_chat(user, SPAN_WARNING("Decreases projectile penetration by [abs(amount*100)]%")) + + if(weapon_upgrades[GUN_UPGRADE_PIERC_MULT]) + var/amount = weapon_upgrades[GUN_UPGRADE_PIERC_MULT] + if(amount > 1) + to_chat(user, SPAN_NOTICE("Increases projectile piercing penetration by [amount] walls")) + else if(amount == 1) + to_chat(user, SPAN_NOTICE("Increases projectile piercing penetration by [amount] wall")) + else if(amount == -1) + to_chat(user, SPAN_WARNING("Decreases projectile piercing penetration by [amount] wall")) + else + to_chat(user, SPAN_WARNING("Decreases projectile piercing penetration by [amount] walls")) + + if(weapon_upgrades[GUN_UPGRADE_RICO_MULT]) + var/amount = weapon_upgrades[GUN_UPGRADE_RICO_MULT] + if(amount > 0) + to_chat(user, SPAN_WARNING("Increases projectile ricochet by [amount*100]%")) + else + to_chat(user, SPAN_NOTICE("Decreases projectile ricochet by [abs(amount*100)]%")) + + if(weapon_upgrades[GUN_UPGRADE_FIRE_DELAY_MULT]) + var/amount = weapon_upgrades[GUN_UPGRADE_FIRE_DELAY_MULT]-1 + if(amount > 0) + to_chat(user, SPAN_WARNING("Increases fire delay by [amount*100]%")) + else + to_chat(user, SPAN_NOTICE("Decreases fire delay by [abs(amount*100)]%")) + + if(weapon_upgrades[GUN_UPGRADE_MOVE_DELAY_MULT]) + var/amount = weapon_upgrades[GUN_UPGRADE_MOVE_DELAY_MULT]-1 + if(amount > 0) + to_chat(user, SPAN_WARNING("Increases move delay by [amount*100]%")) + else + to_chat(user, SPAN_NOTICE("Decreases move delay by [abs(amount*100)]%")) + + if(weapon_upgrades[GUN_UPGRADE_STEPDELAY_MULT]) + var/amount = weapon_upgrades[GUN_UPGRADE_STEPDELAY_MULT]-1 + if(amount > 0) + to_chat(user, SPAN_WARNING("Slows down the weapons projectile by [amount*100]%")) + else + to_chat(user, SPAN_NOTICE("Speeds up the weapons projectile by [abs(amount*100)]%")) + + if(weapon_upgrades[GUN_UPGRADE_DAMAGE_BRUTE]) + to_chat(user, SPAN_NOTICE("Modifies projectile brute damage by [weapon_upgrades[GUN_UPGRADE_DAMAGE_BRUTE]] damage points")) + + if(weapon_upgrades[GUN_UPGRADE_DAMAGE_BURN]) + to_chat(user, SPAN_NOTICE("Modifies projectile burn damage by [weapon_upgrades[GUN_UPGRADE_DAMAGE_BURN]] damage points")) + + if(weapon_upgrades[GUN_UPGRADE_DAMAGE_TOX]) + to_chat(user, SPAN_NOTICE("Modifies projectile toxic damage by [weapon_upgrades[GUN_UPGRADE_DAMAGE_TOX]] damage points")) + + if(weapon_upgrades[GUN_UPGRADE_DAMAGE_OXY]) + to_chat(user, SPAN_NOTICE("Modifies projectile oxy-loss damage by [weapon_upgrades[GUN_UPGRADE_DAMAGE_OXY]] damage points")) + + if(weapon_upgrades[GUN_UPGRADE_DAMAGE_CLONE]) + to_chat(user, SPAN_NOTICE("Modifies projectile clone damage by [weapon_upgrades[GUN_UPGRADE_DAMAGE_CLONE]] damage points")) + + if(weapon_upgrades[GUN_UPGRADE_DAMAGE_HALLOSS]) + to_chat(user, SPAN_NOTICE("Modifies projectile pseudo damage by [weapon_upgrades[GUN_UPGRADE_DAMAGE_HALLOSS]] damage points")) + + if(weapon_upgrades[GUN_UPGRADE_DAMAGE_RADIATION]) + to_chat(user, SPAN_NOTICE("Modifies projectile radiation damage by [weapon_upgrades[GUN_UPGRADE_DAMAGE_RADIATION]] damage points")) + + if(weapon_upgrades[GUN_UPGRADE_DAMAGE_PSY]) + to_chat(user, SPAN_NOTICE("Modifies projectile psy damage by [weapon_upgrades[GUN_UPGRADE_DAMAGE_PSY]] damage points")) + + if(weapon_upgrades[GUN_UPGRADE_RECOIL]) + var/amount = weapon_upgrades[GUN_UPGRADE_RECOIL]-1 + if(amount > 0) + to_chat(user, SPAN_WARNING("Increases kickback by [amount*100]%")) + else + to_chat(user, SPAN_NOTICE("Decreases kickback by [abs(amount*100)]%")) + + if(weapon_upgrades[GUN_UPGRADE_MUZZLEFLASH]) + var/amount = weapon_upgrades[GUN_UPGRADE_MUZZLEFLASH]-1 + if(amount > 0) + to_chat(user, SPAN_WARNING("Increases muzzle flash by [amount*100]%")) + else + to_chat(user, SPAN_NOTICE("Decreases muzzle flash by [abs(amount*100)]%")) + + if(weapon_upgrades[GUN_UPGRADE_MAGUP]) + var/amount = weapon_upgrades[GUN_UPGRADE_MAGUP] + if(amount > 1) + to_chat(user, SPAN_NOTICE("Increases internal magazine size by [amount]")) + else + to_chat(user, SPAN_WARNING("Decreases internal magazine size by [amount]")) + + if(weapon_upgrades[GUN_UPGRADE_SILENCER] == 1) + to_chat(user, SPAN_NOTICE("Silences the weapon.")) + + if(weapon_upgrades[GUN_UPGRADE_FORCESAFETY] == 0) + to_chat(user, SPAN_WARNING("Disables the safety toggle of the weapon.")) + else if(weapon_upgrades[GUN_UPGRADE_FORCESAFETY] == 1) + to_chat(user, SPAN_WARNING("Forces the safety toggle of the weapon to always be on.")) + + if(weapon_upgrades[GUN_UPGRADE_DNALOCK] == 1) + to_chat(user, SPAN_WARNING("Adds a biometric scanner to the weapon.")) + + if(weapon_upgrades[GUN_UPGRADE_CHARGECOST]) + var/amount = weapon_upgrades[GUN_UPGRADE_CHARGECOST]-1 + if(amount > 0) + to_chat(user, SPAN_WARNING("Increases cell firing cost by [amount*100]%")) + else + to_chat(user, SPAN_NOTICE("Decreases cell firing cost by [abs(amount*100)]%")) + + if(weapon_upgrades[GUN_UPGRADE_OVERCHARGE_MAX]) + var/amount = weapon_upgrades[GUN_UPGRADE_OVERCHARGE_MAX]-1 + if(amount > 0) + to_chat(user, SPAN_WARNING("Increases overcharge maximum by [amount*100]%")) + else + to_chat(user, SPAN_NOTICE("Decreases overcharge maximum by [abs(amount*100)]%")) + + if(weapon_upgrades[GUN_UPGRADE_OVERCHARGE_RATE]) + var/amount = weapon_upgrades[GUN_UPGRADE_OVERCHARGE_RATE]-1 + if(amount > 0) + to_chat(user, SPAN_NOTICE("Increases overcharge rate by [amount*100]%")) + else + to_chat(user, SPAN_WARNING("Decreases overcharge rate by [abs(amount*100)]%")) + + if(weapon_upgrades[GUN_UPGRADE_OFFSET]) + var/amount = weapon_upgrades[GUN_UPGRADE_OFFSET]-1 + if(amount > 0) + to_chat(user, SPAN_WARNING("Increases weapon inaccuracy by [amount*100]%")) + else + to_chat(user, SPAN_NOTICE("Decreases weapon inaccuracy by [abs(amount*100)]%")) + + if(weapon_upgrades[GUN_UPGRADE_HONK]) + to_chat(user, SPAN_WARNING("Cheers up the firing sound of the weapon.")) + + if(weapon_upgrades[GUN_UPGRADE_RIGGED]) + to_chat(user, SPAN_WARNING("Rigs the weapon to fire back on its user.")) + + if(weapon_upgrades[GUN_UPGRADE_EXPLODE]) + to_chat(user, SPAN_WARNING("Rigs the weapon to explode.")) + + if(weapon_upgrades[GUN_UPGRADE_ZOOM]) + var/amount = weapon_upgrades[GUN_UPGRADE_ZOOM] + if(amount > 0) + to_chat(user, SPAN_NOTICE("Increases scope zoom by x[amount]")) + else + to_chat(user, SPAN_WARNING("Decreases scope zoom by x[amount]")) + + to_chat(user, SPAN_WARNING("Requires a weapon with the following properties")) + to_chat(user, english_list(req_gun_tags)) + +/datum/component/item_upgrade/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_IATTACK) + UnregisterSignal(parent, COMSIG_EXAMINE) + UnregisterSignal(parent, COMSIG_REMOVE) + +/datum/component/item_upgrade/PostTransfer() + return COMPONENT_TRANSFER + +/datum/component/upgrade_removal + dupe_mode = COMPONENT_DUPE_UNIQUE + +/datum/component/upgrade_removal/RegisterWithParent() + RegisterSignal(parent, COMSIG_ATTACKBY, .proc/attempt_uninstall) + +/datum/component/upgrade_removal/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_ATTACKBY) + +/datum/component/upgrade_removal/proc/attempt_uninstall(obj/item/C, mob/living/user) + if(!isitem(C)) + return 0 + + var/obj/item/upgrade_loc = parent + + var/obj/item/tool/T //For dealing damage to the item + + if(istool(upgrade_loc)) + T = upgrade_loc + + ASSERT(istype(upgrade_loc)) + //Removing upgrades from a tool. Very difficult, but passing the check only gets you the perfect result + //You can also get a lesser success (remove the upgrade but break it in the process) if you fail + //Using a laser guided stabilised screwdriver is recommended. Precision mods will make this easier + if(upgrade_loc.item_upgrades.len && C.has_quality(QUALITY_SCREW_DRIVING)) + var/list/possibles = upgrade_loc.item_upgrades.Copy() + possibles += "Cancel" + var/obj/item/tool_upgrade/toremove = input("Which upgrade would you like to try to remove? The upgrade will probably be destroyed in the process","Removing Upgrades") in possibles + if(toremove == "Cancel") + return 1 + var/datum/component/item_upgrade/IU = toremove.GetComponent(/datum/component/item_upgrade) + if(IU.removable == FALSE) + to_chat(user, SPAN_DANGER("\the [toremove] seems to be fused with the [upgrade_loc]")) + else + if(C.use_tool(user = user, target = upgrade_loc, base_time = IU.removal_time, required_quality = QUALITY_SCREW_DRIVING, fail_chance = IU.removal_difficulty, required_stat = STAT_MEC)) + //If you pass the check, then you manage to remove the upgrade intact + if(!IU.destroy_on_removal && user) + to_chat(user, SPAN_NOTICE("You successfully remove \the [toremove] while leaving it intact.")) + SEND_SIGNAL(toremove, COMSIG_REMOVE, upgrade_loc) + upgrade_loc.refresh_upgrades() + return 1 + else + //You failed the check, lets see what happens + if(IU.breakable == FALSE) + to_chat(user, SPAN_DANGER("You failed to remove \the [toremove].")) + upgrade_loc.refresh_upgrades() + user.update_action_buttons() + else if(prob(50)) + //50% chance to break the upgrade and remove it + to_chat(user, SPAN_DANGER("You successfully remove \the [toremove], but destroy it in the process.")) + SEND_SIGNAL(toremove, COMSIG_REMOVE, parent) + QDEL_NULL(toremove) + upgrade_loc.refresh_upgrades() + user.update_action_buttons() + return 1 + else if(T && T.degradation) //Because robot tools are unbreakable + //otherwise, damage the host tool a bit, and give you another try + to_chat(user, SPAN_DANGER("You only managed to damage \the [upgrade_loc], but you can retry.")) + T.adjustToolHealth(-(5 * T.degradation), user) // inflicting 4 times use damage + upgrade_loc.refresh_upgrades() + user.update_action_buttons() + return 1 + return 0 + +/obj/item/tool_upgrade + name = "tool upgrade" + icon = 'icons/obj/tool_upgrades.dmi' + icon_state = "placeholder" // Needed for UI + force = WEAPON_FORCE_HARMLESS + w_class = ITEM_SIZE_SMALL + spawn_tags = SPAWN_TAG_TOOL_UPGRADE + price_tag = 200 + rarity_value = 15 + bad_type = /obj/item/tool_upgrade diff --git a/code/game/objects/items/weapons/tools/mods/mod_types.dm b/code/game/objects/items/weapons/tools/mods/mod_types.dm new file mode 100644 index 0000000000000..4650b9d12e741 --- /dev/null +++ b/code/game/objects/items/weapons/tools/mods/mod_types.dm @@ -0,0 +1,822 @@ +/****************************** + UPGRADE TYPES +******************************/ +// REINFORCEMENT: REDUCES TOOL DEGRADATION +//------------------------------------------------ + +//This can be attached to basically any long tool +//This includes most mechanical ones +/obj/item/tool_upgrade/reinforcement + bad_type = /obj/item/tool_upgrade/reinforcement + +/obj/item/tool_upgrade/reinforcement/stick + name = "brace bar" + desc = "A sturdy pole made of fiber tape and plasteel rods. Can be used to reinforce the shaft of many tools." + icon_state = "brace_bar" + + price_tag = 120 + matter = list(MATERIAL_PLASTEEL = 5, MATERIAL_PLASTIC = 1) + +//list/tool_upgrades, list/required_qualities, list/negative_qualities, prefix, req_fuel, req_cell + +/obj/item/tool_upgrade/reinforcement/stick/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_DEGRADATION_MULT = 0.65, + UPGRADE_FORCE_MOD = 1, + ) + + I.required_qualities = list(QUALITY_BOLT_TURNING,QUALITY_PRYING, QUALITY_SAWING,QUALITY_SHOVELING,QUALITY_DIGGING,QUALITY_EXCAVATION) + I.prefix = "braced" + +//Heatsink can be attached to any tool that uses fuel or power +/obj/item/tool_upgrade/reinforcement/heatsink + name = "heatsink" + desc = "An array of plasteel fins which dissipates heat, reducing damage and extending the lifespan of power tools." + icon_state = "heatsink" + matter = list(MATERIAL_PLASTEEL = 5, MATERIAL_PLASTIC = 1) + +/obj/item/tool_upgrade/reinforcement/heatsink/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_DEGRADATION_MULT = 0.65, + UPGRADE_HEALTH_THRESHOLD = 10 + ) + I.prefix = "heatsunk" + I.req_fuel_cell = REQ_FUEL_OR_CELL + +/obj/item/tool_upgrade/reinforcement/plating + name = "reinforced plating" + desc = "A sturdy bit of plasteel that can be bolted onto any tool to protect it. Tough, but bulky." + icon_state = "plate" + matter = list(MATERIAL_PLASTEEL = 5, MATERIAL_STEEL = 2) //steel to compensate for metal rods used in crafting + +/obj/item/tool_upgrade/reinforcement/plating/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_DEGRADATION_MULT = 0.55, + UPGRADE_FORCE_MOD = 1, + UPGRADE_PRECISION = -5, + UPGRADE_BULK = 1, + UPGRADE_HEALTH_THRESHOLD = 10) + I.prefix = "reinforced" + +/obj/item/tool_upgrade/reinforcement/guard + name = "metal guard" + desc = "A bent piece of metal that wraps around sensitive parts of a tool, protecting it from impacts, debris, and stray fingers." + icon_state = "guard" + rarity_value = 20 + spawn_tags = SPAWN_TAG_TOOL_UPGRADE_RARE + matter = list(MATERIAL_PLASTEEL = 5) + +/obj/item/tool_upgrade/reinforcement/guard/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_DEGRADATION_MULT = 0.75, + UPGRADE_PRECISION = 5, + UPGRADE_HEALTH_THRESHOLD = 10 + ) + I.required_qualities = list(QUALITY_CUTTING,QUALITY_DRILLING, QUALITY_SAWING, QUALITY_DIGGING, QUALITY_EXCAVATION, QUALITY_WELDING, QUALITY_HAMMERING) + I.prefix = "shielded" + +// Plasmablock can be attached to any tool that uses fuel or power +/obj/item/tool_upgrade/reinforcement/plasmablock + name = "plasmablock" + desc = "A plasmablock is way more efficient to dissipate heat than classic heatsinks or waterblocks thanks to the tremendous heat-transfer capacity of liquid plasma. The fluid that is actively pumped through a radiator and cooled by fans. It greatly extends the lifespan of power tools." + icon_state = "plasmablock" + matter = list(MATERIAL_PLASTEEL = 5, MATERIAL_PLASTIC = 2, MATERIAL_PLASMA = 1) + +/obj/item/tool_upgrade/reinforcement/plasmablock/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_DEGRADATION_MULT = 0.45, + UPGRADE_HEALTH_THRESHOLD = 10, + UPGRADE_POWERCOST_MULT = 1.05, + UPGRADE_FUELCOST_MULT = 1.05 + ) + I.prefix = "plasma-cooled" + I.req_fuel_cell = REQ_FUEL_OR_CELL + +/obj/item/tool_upgrade/reinforcement/rubbermesh + name = "rubber mesh" + desc = "A rubber mesh that can wrapped around sensitive parts of a tool, protecting them from impacts and debris." + icon_state = "rubbermesh" + matter = list(MATERIAL_PLASTIC = 3) + +/obj/item/tool_upgrade/reinforcement/rubbermesh/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_DEGRADATION_MULT = 0.7, + UPGRADE_HEALTH_THRESHOLD = 5 + ) + I.required_qualities = list(QUALITY_CUTTING,QUALITY_DRILLING, QUALITY_SAWING, QUALITY_DIGGING, QUALITY_EXCAVATION, QUALITY_WELDING, QUALITY_HAMMERING) + I.prefix = "rubber-wrapped" + +// PRODUCTIVITY: INCREASES WORKSPEED +//------------------------------------------------ +/obj/item/tool_upgrade/productivity + bad_type = /obj/item/tool_upgrade/productivity + +/obj/item/tool_upgrade/productivity/ergonomic_grip + name = "ergonomic grip" + desc = "A replacement grip for a tool which allows it to be more precisely controlled with one hand. Can be placed under a gun\'s barrel to reduce recoil. However, it also makes bracing impossible." + icon_state = "ergonomic" + matter = list(MATERIAL_STEEL = 1, MATERIAL_PLASTIC = 5) + spawn_tags = SPAWN_TAG_TOOL_UPGRADE_RARE + +/obj/item/tool_upgrade/productivity/ergonomic_grip/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_WORKSPEED = 0.15 + ) + I.weapon_upgrades = list( + GUN_UPGRADE_RECOIL = 0.9, + ) + I.gun_loc_tag = GUN_UNDERBARREL + + I.prefix = "ergonomic" + +/obj/item/tool_upgrade/productivity/ratchet + name = "ratcheting mechanism" + desc = "A mechanical upgrade for wrenches and screwdrivers which allows the tool to only turn in one direction." + icon_state = "ratchet" + matter = list(MATERIAL_STEEL = 4, MATERIAL_PLASTEEL = 4, MATERIAL_PLASTIC = 1) + +/obj/item/tool_upgrade/productivity/ratchet/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_WORKSPEED = 0.25 + ) + I.required_qualities = list(QUALITY_BOLT_TURNING,QUALITY_SCREW_DRIVING) + I.prefix = "ratcheting" + +/obj/item/tool_upgrade/productivity/red_paint + name = "red paint" + desc = "Do red tools really work faster, or is the effect purely psychological?" + icon_state = "paint_red" + rarity_value = 20 + spawn_tags = SPAWN_TAG_TOOL_UPGRADE_RARE + matter = list(MATERIAL_STEEL = 3, MATERIAL_PLASTIC = 1) + +/obj/item/tool_upgrade/productivity/red_paint/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_WORKSPEED = 0.20, + UPGRADE_PRECISION = -10, + UPGRADE_COLOR = "#FF4444" + ) + I.prefix = "red" + +/obj/item/tool_upgrade/productivity/whetstone + name = "sharpening block" + desc = "A rough single-use block to sharpen a blade. The honed edge cuts smoothly." + icon_state = "whetstone" + rarity_value = 30 + matter = list(MATERIAL_PLASTEEL = 5, MATERIAL_DIAMOND = 3) + +/obj/item/tool_upgrade/productivity/whetstone/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_WORKSPEED = 0.15, + UPGRADE_PRECISION = 5, + UPGRADE_FORCE_MULT = 1.15 + ) + I.required_qualities = list(QUALITY_CUTTING,QUALITY_SAWING, QUALITY_SHOVELING, QUALITY_WIRE_CUTTING) + I.negative_qualities = list(QUALITY_WELDING, QUALITY_LASER_CUTTING) + I.prefix = "sharpened" + +/obj/item/tool_upgrade/productivity/diamond_blade + name = "Asters \"Gleaming Edge\": Diamond blade" + desc = "An adaptable industrial grade cutting disc, with diamond dust worked into the metal. Exceptionally durable." + icon_state = "diamond_blade" + price_tag = 300 + rarity_value = 60 + matter = list(MATERIAL_PLASTEEL = 3, MATERIAL_DIAMOND = 4) + spawn_tags = SPAWN_TAG_TOOL_UPGRADE_RARE + +/obj/item/tool_upgrade/productivity/diamond_blade/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_WORKSPEED = 0.25, + UPGRADE_DEGRADATION_MULT = 0.85, + UPGRADE_FORCE_MULT = 1.10, + ) + I.required_qualities = list(QUALITY_CUTTING, QUALITY_SHOVELING, QUALITY_SAWING, QUALITY_WIRE_CUTTING, QUALITY_PRYING) + I.negative_qualities = list(QUALITY_WELDING, QUALITY_LASER_CUTTING) + I.prefix = "diamond-edged" + +/obj/item/tool_upgrade/productivity/oxyjet + name = "oxyjet canister" + desc = "A canister of pure, compressed oxygen with adapters for mounting onto a welding tool. Used alongside fuel, it allows for higher burn temperatures." + icon_state = "oxyjet" + rarity_value = 20 + matter = list(MATERIAL_PLASTEEL = 5, MATERIAL_PLASTIC = 1) + +/obj/item/tool_upgrade/productivity/oxyjet/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_WORKSPEED = 0.20, + UPGRADE_FORCE_MULT = 1.15, + UPGRADE_DEGRADATION_MULT = 1.15, + UPGRADE_HEALTH_THRESHOLD = -10 + ) + I.required_qualities = list(QUALITY_WELDING) + I.prefix = "oxyjet" + +//Enhances power tools majorly, but also increases costs +/obj/item/tool_upgrade/productivity/motor + name = "high power motor" + desc = "A motor for power tools with a higher horsepower than usually expected. Significantly enhances productivity and lifespan, but more expensive to run and harder to control." + icon_state = "motor" + rarity_value = 20 + spawn_tags = SPAWN_TAG_TOOL_UPGRADE_RARE + matter = list(MATERIAL_STEEL = 4, MATERIAL_PLASTEEL = 4) + +/obj/item/tool_upgrade/productivity/motor/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_WORKSPEED = 0.5, + UPGRADE_FORCE_MULT = 1.15, + UPGRADE_DEGRADATION_MULT = 1.15, + UPGRADE_POWERCOST_MULT = 1.35, + UPGRADE_FUELCOST_MULT = 1.35, + UPGRADE_PRECISION = -10, + UPGRADE_HEALTH_THRESHOLD = -10 + ) + I.required_qualities = list(QUALITY_SCREW_DRIVING, QUALITY_DRILLING, QUALITY_SAWING, QUALITY_DIGGING, QUALITY_EXCAVATION, QUALITY_HAMMERING) + I.prefix = "high-power" + I.req_fuel_cell = REQ_FUEL_OR_CELL + +/obj/item/tool_upgrade/productivity/antistaining + name = "anti-staining paint" + desc = "Applying a thin coat of this paint on a tool prevents stains, dirt or dust to adhere to its surface. Everyone works better and faster with clean tools." + icon_state = "antistaining" + matter = list(MATERIAL_STEEL = 3, MATERIAL_PLASTIC = 2) + +/obj/item/tool_upgrade/productivity/antistaining/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_WORKSPEED = 0.30, + UPGRADE_PRECISION = 5, + UPGRADE_ITEMFLAGPLUS = NOBLOODY + ) + I.prefix = "anti-stain coated" + +/obj/item/tool_upgrade/productivity/booster + name = "booster" + desc = "When you do not care about energy comsumption and just want to get shit done quickly. This device shunts the power safeties of your tool whether it uses fuel or electricity." + icon_state = "booster" + matter = list(MATERIAL_STEEL = 3, MATERIAL_PLASTIC = 2, MATERIAL_GOLD = 1) + +/obj/item/tool_upgrade/productivity/booster/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_WORKSPEED = 0.35, + UPGRADE_DEGRADATION_MULT = 1.15, + UPGRADE_POWERCOST_MULT = 1.25, + UPGRADE_FUELCOST_MULT = 1.25 + ) + I.prefix = "boosted" + I.req_fuel_cell = REQ_FUEL_OR_CELL + +/obj/item/tool_upgrade/productivity/injector + name = "plasma injector" + desc = "If the words \"safety regulations\" do not mean anything to you, you may consider installing this fine piece of technology on your tool. It injects small amounts of plasma in the fuel mix before combustion to greatly increase its power output, making all kinds of tasks easier to perform." + icon_state = "injector" + matter = list(MATERIAL_STEEL = 3, MATERIAL_PLASTIC = 2, MATERIAL_PLASMA = 2) + +/obj/item/tool_upgrade/productivity/injector/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_WORKSPEED = 0.75, + UPGRADE_DEGRADATION_MULT = 1.3, + UPGRADE_POWERCOST_MULT = 1.3, + UPGRADE_FUELCOST_MULT = 1.3, + UPGRADE_HEALTH_THRESHOLD = -10 + ) + I.prefix = "plasma-fueled" + I.req_fuel_cell = REQ_FUEL + +// REFINEMENT: INCREASES PRECISION +//------------------------------------------------ +/obj/item/tool_upgrade/refinement + bad_type = /obj/item/tool_upgrade/refinement + +/obj/item/tool_upgrade/refinement/laserguide + name = "Asters \"Guiding Light\" laser guide" + desc = "A small visible laser which can be strapped onto any tool, giving an accurate representation of its target. Helps improve precision." + icon_state = "laser_guide" + spawn_tags = SPAWN_TAG_TOOL_UPGRADE_RARE + matter = list(MATERIAL_PLASTIC = 2, MATERIAL_URANIUM = 1) + +/obj/item/tool_upgrade/refinement/laserguide/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_PRECISION = 10) + I.weapon_upgrades = list( + GUN_UPGRADE_RECOIL = 0.9) + I.prefix = "laser-guided" + +//Fits onto generally small tools that require precision, especially surgical tools +//Doesn't work onlarger things like crowbars and drills +/obj/item/tool_upgrade/refinement/stabilized_grip + name = "gyrostabilized grip" + desc = "A fancy mechanical grip that partially floats around a tool, absorbing tremors and shocks. Allows precise work with a shaky hand, or shooting more precisely with one hand if the gun isn't intended for one-handed use." + icon_state = "stabilizing" + spawn_tags = SPAWN_TAG_TOOL_UPGRADE_RARE + matter = list(MATERIAL_PLASTIC = 3) + +/obj/item/tool_upgrade/refinement/stabilized_grip/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.weapon_upgrades = list( + GUN_UPGRADE_PEN_MULT = -0.3, + GUN_UPGRADE_ONEHANDPENALTY = 0.3 + ) + I.gun_loc_tag = GUN_GRIP + I.req_gun_tags = list(GUN_PROJECTILE, GUN_GRIP) + + I.tool_upgrades = list( + UPGRADE_PRECISION = 10, + UPGRADE_HEALTH_THRESHOLD = 10) + I.required_qualities = list(QUALITY_CUTTING,QUALITY_WIRE_CUTTING, QUALITY_SCREW_DRIVING, QUALITY_WELDING,QUALITY_PULSING, QUALITY_CLAMPING, QUALITY_CAUTERIZING, QUALITY_BONE_SETTING, QUALITY_LASER_CUTTING) + I.prefix = "stabilized" + +/obj/item/tool_upgrade/refinement/magbit + name = "magnetic bit" + desc = "Magnetises tools used for handling small objects, reducing instances of dropping screws and bolts." + icon_state = "magnetic" + rarity_value = 20 + matter = list(MATERIAL_STEEL = 2, MATERIAL_PLASTEEL = 2) + +/obj/item/tool_upgrade/refinement/magbit/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_PRECISION = 10 + ) + I.required_qualities = list(QUALITY_SCREW_DRIVING, QUALITY_BOLT_TURNING, QUALITY_CLAMPING, QUALITY_BONE_SETTING) + I.prefix = "magnetic" + +/obj/item/tool_upgrade/refinement/ported_barrel + name = "ported barrel" + desc = "A barrel extension for a welding tool which helps manage gas pressure and keep the torch steady." + icon_state = "ported_barrel" + rarity_value = 30 + matter = list(MATERIAL_STEEL = 2, MATERIAL_PLASTEEL = 2) + +/obj/item/tool_upgrade/refinement/ported_barrel/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_PRECISION = 12, + UPGRADE_DEGRADATION_MULT = 1.15, + UPGRADE_BULK = 1, + UPGRADE_HEALTH_THRESHOLD = 10 + ) + I.required_qualities = list(QUALITY_WELDING) + I.prefix = "ported" + +/obj/item/tool_upgrade/refinement/compensatedbarrel + name = "gravity compensated barrel" + desc = "A barrel extension for welding tools that integrates a miniaturized gravity generator that help keep the torch steady by compensating the weight of the tool." + icon_state = "compensatedbarrel" + matter = list(MATERIAL_STEEL = 2, MATERIAL_PLASTEEL = 1, MATERIAL_PLASTIC = 1, MATERIAL_GOLD = 1) + +/obj/item/tool_upgrade/refinement/compensatedbarrel/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_PRECISION = 20, + UPGRADE_DEGRADATION_MULT = 1.15, + UPGRADE_POWERCOST_MULT = 1.05, + UPGRADE_FUELCOST_MULT = 1.05, + UPGRADE_BULK = 1 + ) + I.required_qualities = list(QUALITY_WELDING) + I.prefix = "gravity-compensated" + I.req_fuel_cell = REQ_FUEL_OR_CELL + +/obj/item/tool_upgrade/refinement/vibcompensator + name = "vibration compensator" + desc = "A ground-breaking innovation that dampens the vibration of a tool by emitting sound waves in a specific pattern. It does not make any sense but neither do you by installing that on your tool." + icon_state = "vibcompensator" + matter = list(MATERIAL_STEEL = 2, MATERIAL_PLASTIC = 1, MATERIAL_GOLD = 1) + +/obj/item/tool_upgrade/refinement/vibcompensator/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_PRECISION = 15, + UPGRADE_HEALTH_THRESHOLD = 5, + UPGRADE_ITEMFLAGPLUS = HONKING + ) + I.required_qualities = list(QUALITY_CUTTING,QUALITY_WIRE_CUTTING, QUALITY_SCREW_DRIVING, QUALITY_WELDING,QUALITY_PULSING, QUALITY_CLAMPING, QUALITY_CAUTERIZING, QUALITY_BONE_SETTING, QUALITY_LASER_CUTTING) + I.prefix = "vibration-compensated" + +//onestar stabilizer +/obj/item/tool_upgrade/refinement/gravenhancer + name = "OneStar microgravity stabilizer" + desc = "A large strange contraption, it appears to manipulate gravity around it, to make a weapon or tool more stable at the cost of increasing it\'s size." + icon_state = "grav_enhancer" + spawn_tags = SPAWN_TAG_TOOL_UPGRADE_OS + matter = list(MATERIAL_PLASTIC = 8, MATERIAL_URANIUM = 3) + spawn_blacklisted = TRUE + price_tag = 1500 + +/obj/item/tool_upgrade/refinement/gravenhancer/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_PRECISION = 25, + UPGRADE_WORKSPEED = 0.1, + UPGRADE_BULK = 1, + ) + I.weapon_upgrades = list( + GUN_UPGRADE_RECOIL = 0.5, + UPGRADE_BULK = 1, + ) + I.prefix = "gravity-stabilized" + +// AUGMENTS: MISCELLANEOUS AND UTILITY +//------------------------------------------------ + +//Allows the tool to use a cell one size category larger than it currently uses. Small to medium, medium to large, etc +/obj/item/tool_upgrade/augment + bad_type = /obj/item/tool_upgrade/augment + +/obj/item/tool_upgrade/augment/cell_mount + name = "heavy cell mount" + icon_state = "cell_mount" + desc = "A bulky adapter which allows oversized power cells to be installed into small tools." + matter = list(MATERIAL_STEEL = 4, MATERIAL_PLASTEEL = 2, MATERIAL_PLASTIC = 1) + rarity_value = 20 + +/obj/item/tool_upgrade/augment/cell_mount/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_BULK = 1, + UPGRADE_DEGRADATION_MULT = 1.15, + UPGRADE_HEALTH_THRESHOLD = -10, + UPGRADE_CELLPLUS = 1 + ) + I.prefix = "medium-cell" + I.req_fuel_cell = REQ_CELL + +//Stores moar fuel! +/obj/item/tool_upgrade/augment/fuel_tank + name = "Expanded fuel tank" + desc = "An auxiliary tank which stores 100 extra units of fuel at the cost of degradation." + icon_state = "canister" + matter = list(MATERIAL_PLASTEEL = 4, MATERIAL_PLASTIC = 1) + +/obj/item/tool_upgrade/augment/fuel_tank/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_BULK = 1, + UPGRADE_DEGRADATION_MULT = 1.15, + UPGRADE_HEALTH_THRESHOLD = -10, + UPGRADE_MAXFUEL = 100) + I.prefix = "expanded" + I.req_fuel_cell = REQ_FUEL + +//OneStar fuel mod +/obj/item/tool_upgrade/augment/holding_tank + name = "Expanded fuel tank of holding" + desc = "Rare relic of OneStar uses the bluetech space to store additional 600 units of fuel at the cost of degradation." + icon_state = "canister_holding" + matter = list(MATERIAL_PLASTIC = 2, MATERIAL_PLASTEEL = 4, MATERIAL_PLATINUM = 4) + spawn_tags = SPAWN_TAG_TOOL_UPGRADE_OS + spawn_blacklisted = TRUE + price_tag = 800 + +/obj/item/tool_upgrade/augment/holding_tank/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_BULK = 1, + UPGRADE_DEGRADATION_MULT = 1.30, + UPGRADE_HEALTH_THRESHOLD = -20, + UPGRADE_MAXFUEL = 600 + ) + I.prefix = "holding" + I.req_fuel_cell = REQ_FUEL + bluespace_entropy(5, get_turf(src)) + +//Penalises the tool, but unlocks several more augment slots. +/obj/item/tool_upgrade/augment/expansion + name = "expansion port" + icon_state = "expand" + desc = "A bulky adapter which allows more modifications to be attached to the tool. A bit fragile but you can compensate." + matter = list(MATERIAL_STEEL = 1, MATERIAL_PLASTEEL = 3, MATERIAL_PLASTIC = 1) + rarity_value = 60 + spawn_tags = SPAWN_TAG_TOOL_UPGRADE_RARE + +/obj/item/tool_upgrade/augment/expansion/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_BULK = 2, + UPGRADE_DEGRADATION_MULT = 1.3, + UPGRADE_PRECISION = -10, + UPGRADE_HEALTH_THRESHOLD = -20, + UPGRADE_MAXUPGRADES = 3 + ) + I.prefix = "custom" + +/obj/item/tool_upgrade/augment/spikes + name = "spikes" + icon_state = "spike" + desc = "An array of sharp bits of plasteel, seemingly adapted for easy affixing to a tool. Would make it into a better weapon, but won't do much for productivity." + matter = list(MATERIAL_PLASTEEL = 3, MATERIAL_STEEL = 2) + +/obj/item/tool_upgrade/augment/spikes/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_FORCE_MOD = 4, + UPGRADE_PRECISION = -5, + UPGRADE_DEGRADATION_MULT = 1.15, + UPGRADE_WORKSPEED = -0.15, + UPGRADE_HEALTH_THRESHOLD = -10, + UPGRADE_SHARP = TRUE + ) + I.prefix = "spiked" + +/obj/item/tool_upgrade/augment/sanctifier + name = "NT 'Sanctifier' tool blessing" + icon_state = "sanctifier" + desc = "This odd piece of equipment can be applied to any tool or melee weapon, causing the object to deal extra burn damage to mutants and carrions." + spawn_blacklisted = TRUE + matter = list(MATERIAL_BIOMATTER = 3, MATERIAL_STEEL = 2) + +/obj/item/tool_upgrade/augment/sanctifier/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_SANCTIFY = TRUE + ) + I.prefix = "sanctified" + +/obj/item/tool_upgrade/augment/hammer_addon + name = "Flat surface" + icon_state = "hammer_addon" + desc = "An attachment that fits on almost everything, that gives a simple flat surface to employ the tool for hammering." + matter = list(MATERIAL_PLASTEEL = 3, MATERIAL_STEEL = 2) + rarity_value = 20 + +/obj/item/tool_upgrade/augment/hammer_addon/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_WORKSPEED = -0.1, + UPGRADE_HEALTH_THRESHOLD = 5, + tool_qualities = list(QUALITY_HAMMERING = 10) + ) + I.prefix = "flattened" + +//Vastly reduces tool sounds, for stealthy hacking +/obj/item/tool_upgrade/augment/dampener + name = "aural dampener" + desc = "This aural dampener is a cutting edge tool attachment which mostly nullifies sound waves within a tiny radius. It minimises the noise created during use, perfect for stealth operations." + icon_state = "dampener" + matter = list(MATERIAL_PLASTIC = 1, MATERIAL_PLASTEEL = 1, MATERIAL_PLATINUM = 1) + rarity_value = 30 + spawn_tags = SPAWN_TAG_TOOL_UPGRADE_RARE + +/obj/item/tool_upgrade/augment/dampener/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_COLOR = "#AAAAAA", + UPGRADE_HEALTH_THRESHOLD = -10, + UPGRADE_ITEMFLAGPLUS = SILENT + ) + I.prefix = "silenced" + +/obj/item/tool_upgrade/augment/ai_tool + name = "Nanointegrated AI" + desc = "A forgotten OneStar tech. Due to its unique installation method of \"slapping it hard enough onto anything should do the trick\", it is highly sought after. \ + A powerful AI will integrate itself into this tool with the aid of nanotechnology, and improve it in every way possible." + icon_state = "ai_tool" + matter = list(MATERIAL_PLASTIC = 1, MATERIAL_PLASTEEL = 1, MATERIAL_PLATINUM = 1) + rarity_value = 50 + spawn_tags = SPAWN_TAG_TOOL_UPGRADE_OS + spawn_blacklisted = TRUE + price_tag = 2500 + +/obj/item/tool_upgrade/augment/ai_tool/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_POWERCOST_MULT = 1.20, + UPGRADE_PRECISION = 14, + UPGRADE_WORKSPEED = 7, + UPGRADE_HEALTH_THRESHOLD = -10, + ) + I.prefix = "intelligent" + I.req_fuel_cell = REQ_CELL + I.weapon_upgrades = list( + GUN_UPGRADE_RECOIL = 0.8, + GUN_UPGRADE_DAMAGE_MULT = 1.2, + GUN_UPGRADE_PEN_MULT = 0.2, + GUN_UPGRADE_FIRE_DELAY_MULT = 0.8, + GUN_UPGRADE_MOVE_DELAY_MULT = 0.8, + GUN_UPGRADE_MUZZLEFLASH = 0.8, + GUN_UPGRADE_CHARGECOST = 0.8, + GUN_UPGRADE_OVERCHARGE_MAX = 0.8, + GUN_UPGRADE_OVERCHARGE_RATE = 1.2) + +/obj/item/tool_upgrade/augment/repair_nano + name = "repair nano" + desc = "Very rare tool mod from OneStar powered by their nanomachines. It repairs the tool while in use and makes it near unbreakable." + icon_state = "repair_nano" + matter = list(MATERIAL_PLASTIC = 1, MATERIAL_PLASTEEL = 1, MATERIAL_PLATINUM = 1) + spawn_tags = SPAWN_TAG_TOOL_UPGRADE_OS + price_tag = 500 + spawn_blacklisted = TRUE + +/obj/item/tool_upgrade/augment/repair_nano/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_DEGRADATION_MULT = 0.01, + UPGRADE_WORKSPEED = 0.2, + UPGRADE_HEALTH_THRESHOLD = 10 + ) + I.prefix = "self-healing" + +/obj/item/tool_upgrade/augment/hydraulic + name = "hydraulic circuits" + desc = "A complex set of hydraulic circuits that can be installed on a tool to greatly improve its functions. It's loud as hell though so do not plan on being stealthy." + icon_state = "hydraulic" + matter = list(MATERIAL_STEEL = 3, MATERIAL_PLASTEEL = 3, MATERIAL_PLASTIC = 3) + spawn_blacklisted = TRUE + +/obj/item/tool_upgrade/augment/hydraulic/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_WORKSPEED = 1, + UPGRADE_PRECISION = 10, + UPGRADE_ITEMFLAGPLUS = LOUD + ) + I.prefix = "hydraulic" + +// Randomizes a bunch of weapon stats on application - stats are set on creation of the item to prevent people from re-rolling until they get what they want +/obj/item/tool_upgrade/augment/randomizer + name = "BSL \"Randomizer\" tool polish" + desc = "This unidentified tar-like liquid warps and bends reality around it. Applying it to a tool may have unexpected results." + icon_state = "randomizer" + matter = list(MATERIAL_PLASMA = 4, MATERIAL_URANIUM = 4) + rarity_value = 80 + spawn_tags = SPAWN_TAG_TOOL_UPGRADE_RARE + +/obj/item/tool_upgrade/augment/randomizer/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_DEGRADATION_MULT = rand(-1,10), + UPGRADE_HEALTH_THRESHOLD = rand(-10,10), + UPGRADE_WORKSPEED = rand(-1,3), + UPGRADE_PRECISION = rand(-20,20), + UPGRADE_FORCE_MOD = rand(-5,5), + UPGRADE_BULK = rand(-1,2), + UPGRADE_COLOR = "#3366ff" + ) + I.prefix = "theoretical" + +/obj/item/tool_upgrade/artwork_tool_mod + name = "Weird Revolver" + desc = "This is an artistically-made tool mod." + icon_state = "artmod_1" + spawn_frequency = 0 + price_tag = 200 + +/obj/item/tool_upgrade/artwork_tool_mod/Initialize(mapload, prob_rare = 33) + . = ..() + name = get_weapon_name(capitalize = TRUE) + icon_state = "artmod_[rand(1,16)]" + var/sanity_value = 0.2 + pick(0,0.1,0.2) + AddComponent(/datum/component/atom_sanity, sanity_value, "") + var/obj/randomcatcher/CATCH = new(src) + var/obj/item/tool_upgrade/spawn_type = pickweight(list(/obj/spawner/tool_upgrade = max(100-prob_rare,0), /obj/spawner/tool_upgrade/rare = prob_rare), 0) + spawn_type = CATCH.get_item(spawn_type) + spawn_type.TransferComponents(src) + GET_COMPONENT(tool_comp, /datum/component/item_upgrade) + for(var/upgrade in (tool_comp.tool_upgrades - GLOB.tool_aspects_blacklist)) + if(isnum(tool_comp.tool_upgrades[upgrade])) + tool_comp.tool_upgrades[upgrade] = tool_comp.tool_upgrades[upgrade] * rand(5,15)/10 + tool_comp.tool_upgrades[UPGRADE_BULK] = rand(-1,2) + QDEL_NULL(spawn_type) + QDEL_NULL(CATCH) + price_tag += rand(0, 1000) + +/obj/item/tool_upgrade/artwork_tool_mod/get_item_cost(export) + . = ..() + GET_COMPONENT(comp_sanity, /datum/component/atom_sanity) + . += comp_sanity.affect * 100 + +/obj/item/tool_upgrade/pai + name = "Integrated P-AI" + desc = "A P-AI integrated within the architecture of the tool, helping the user in utilizing it." + spawn_blacklisted = TRUE + price_tag = 200 + +/obj/item/tool_upgrade/pai/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_WORKSPEED = 0.3, + UPGRADE_PRECISION = 10 + ) + I.destroy_on_removal = TRUE + I.prefix = "assisted" + +/obj/item/tool_upgrade/flow_mechanism + name = "Flowing metal system" + desc = "This tool makes use of liquid metal within its architecture." + spawn_blacklisted = TRUE + price_tag = 300 + +/obj/item/tool_upgrade/flow_mechanism/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_DEGRADATION_MULT = 0.2, + UPGRADE_FORCE_MULT = 1.3, + UPGRADE_MAXUPGRADES = 2 + ) + I.destroy_on_removal = TRUE + I.prefix = "flowing" + +/obj/item/tool_upgrade/magni_grip + name = "Waved magnetic grip" + desc = "A wavy metallic sheet that attaches to most gloves automatically." + spawn_blacklisted = TRUE + price_tag = 200 + +/obj/item/tool_upgrade/magni_grip/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_WORKSPEED = 0.2, + UPGRADE_PRECISION = 15 + ) + I.destroy_on_removal = TRUE + I.prefix = "magnetized" + +/obj/item/tool_upgrade/resonator + name = "Resonator sink" + desc = "A special module which prevents the tool from resonating." + spawn_blacklisted = TRUE + price_tag = 400 + +/obj/item/tool_upgrade/resonator/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_WORKSPEED = 0.1, + UPGRADE_ITEMFLAGPLUS = SILENT + ) + I.destroy_on_removal = TRUE + I.prefix = "still" + +/obj/item/tool_upgrade/plasma_coating + name = "Plasma coating" + desc = "This tool is coated with plasma, granting it more durability." + spawn_blacklisted = TRUE + price_tag = 600 + +/obj/item/tool_upgrade/plasma_coating/New() + ..() + var/datum/component/item_upgrade/I = AddComponent(/datum/component/item_upgrade) + I.tool_upgrades = list( + UPGRADE_DEGRADATION_MULT = 0.1, + UPGRADE_MAXUPGRADES = 3 + ) + I.destroy_on_removal = TRUE + I.prefix = "plasma coated" + + +#define GREAT_TOOLMODS list(/obj/item/tool_upgrade/pai, /obj/item/tool_upgrade/flow_mechanism, /obj/item/tool_upgrade/magni_grip, \ + /obj/item/tool_upgrade/resonator, /obj/item/tool_upgrade/plasma_coating) diff --git a/code/game/objects/items/weapons/tools/multitool.dm b/code/game/objects/items/weapons/tools/multitool.dm new file mode 100644 index 0000000000000..a93f3dbc66d50 --- /dev/null +++ b/code/game/objects/items/weapons/tools/multitool.dm @@ -0,0 +1,72 @@ +/** + * Multitool -- A multitool is used for hacking electronic devices. + * TO-DO -- Using it as a power measurement tool for cables etc. Nannek. + * + */ + +/obj/item/tool/multitool + name = "multitool" + desc = "Used for pulsing wires to test which to cut. You can use this on airlocks or APCs to try to hack them." + description_info = "Contrary to popular belief , you can install upgrades onto the multitool" + description_antag = "Can be used to brute-force any locker. It however takes time" + icon_state = "multitool" + flags = CONDUCT + force = WEAPON_FORCE_HARMLESS + w_class = ITEM_SIZE_SMALL + throwforce = WEAPON_FORCE_HARMLESS + worksound = WORKSOUND_PULSING + tool_qualities = list(QUALITY_PULSING = 30) + matter = list(MATERIAL_PLASTIC = 2, MATERIAL_GLASS = 1) + + origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1) + rarity_value = 12 + + var/buffer_name + var/atom/buffer_object + +/obj/item/tool/multitool/Destroy() + unregister_buffer(buffer_object) + return ..() + +/obj/item/tool/multitool/proc/get_buffer(typepath) + // Only allow clearing the buffer name when someone fetches the buffer. + // Means you cannot be sure the source hasn't been destroyed until the very moment it's needed. + get_buffer_name(TRUE) + if(buffer_object && (!typepath || istype(buffer_object, typepath))) + return buffer_object + +/obj/item/tool/multitool/proc/get_buffer_name(null_name_if_missing = FALSE) + if(buffer_object) + buffer_name = buffer_object.name + else if(null_name_if_missing) + buffer_name = null + return buffer_name + +/obj/item/tool/multitool/proc/set_buffer(atom/buffer) + if(!buffer || istype(buffer)) + buffer_name = buffer ? buffer.name : null + if(buffer != buffer_object) + unregister_buffer(buffer_object) + buffer_object = buffer + if(buffer_object) + GLOB.destroyed_event.register(buffer_object, src, /obj/item/tool/multitool/proc/unregister_buffer) + +/obj/item/tool/multitool/proc/unregister_buffer(atom/buffer_to_unregister) + // Only remove the buffered object, don't reset the name + // This means one cannot know if the buffer has been destroyed until one attempts to use it. + if(buffer_to_unregister == buffer_object && buffer_object) + GLOB.destroyed_event.unregister(buffer_object, src) + buffer_object = null + +/obj/item/tool/multitool/resolve_attackby(atom/A, mob/user) + if(!isobj(A)) + return ..(A, user) + + var/obj/O = A + var/datum/extension/multitool/MT = get_extension(O, /datum/extension/multitool) + if(!MT) + return ..(A, user) + + user.AddTopicPrint(src) + MT.interact(src, user) + return 1 diff --git a/code/game/objects/items/weapons/tools/pickaxe.dm b/code/game/objects/items/weapons/tools/pickaxe.dm new file mode 100644 index 0000000000000..00facc5ad0d3a --- /dev/null +++ b/code/game/objects/items/weapons/tools/pickaxe.dm @@ -0,0 +1,171 @@ +/obj/item/tool/pickaxe + name = "pickaxe" + desc = "The most basic of mining tools, for short excavations and small mineral extractions." + flags = CONDUCT + slot_flags = SLOT_BELT + force = WEAPON_FORCE_DANGEROUS + armor_divisor = ARMOR_PEN_HALF // It's a pickaxe. It's destined to poke holes in things, even armor. + throwforce = WEAPON_FORCE_NORMAL + icon_state = "pickaxe" + item_state = "pickaxe" + w_class = ITEM_SIZE_BULKY + matter = list(MATERIAL_STEEL = 6) + tool_qualities = list(QUALITY_EXCAVATION = 10, QUALITY_PRYING = 20) //So it still shares its switch off quality despite not yet being used. + switched_off_qualities = list(QUALITY_EXCAVATION = 10, QUALITY_PRYING = 20) + switched_on_qualities = list(QUALITY_DIGGING = 30, QUALITY_PRYING = 20) + toggleable = TRUE + origin_tech = list(TECH_MATERIAL = 1, TECH_ENGINEERING = 1) + attack_verb = list("hit", "pierced", "sliced", "attacked") + hitsound = 'sound/weapons/melee/heavystab.ogg' + sharp = TRUE + structure_damage_factor = STRUCTURE_DAMAGE_DESTRUCTIVE //Drills and picks are made for getting through hard materials + //They are the best anti-structure melee weapons + embed_mult = 1.2 //Digs deep + mode = EXCAVATE //Mode should be whatever is the starting tool and off quality. + rarity_value = 24 + +/obj/item/tool/pickaxe/equipped(mob/user) + ..() + update_icon() + +/obj/item/tool/pickaxe/dropped(mob/user) + ..() + update_icon() + +/obj/item/tool/pickaxe/turn_on(mob/user) + .=..() + if(.) + mode = DIG + to_chat(user, SPAN_NOTICE("You tighten your grip on [src], and ready yourself to strike earth.")) + +/obj/item/tool/pickaxe/turn_off(mob/user) + + mode = EXCAVATE + to_chat(user, SPAN_NOTICE("You loosen your grip on [src], and prepare to remove debris.")) + ..() + + +/obj/item/tool/pickaxe/onestar //TODO: Add sound to /turn_on proc + name = "One Star pickaxe" + desc = "A standard One Star basic tool. There used energy technologies what makes it enough powerful and cheap at the same time." + icon_state = "one_star_pickaxe" + item_state = "pickaxe" + matter = list(MATERIAL_STEEL = 4, MATERIAL_PLATINUM = 2, MATERIAL_DIAMOND = 2) + origin_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 2, TECH_POWER = 3) + switched_on_force = WEAPON_FORCE_ROBUST + tool_qualities = list(QUALITY_EXCAVATION = 15, QUALITY_PRYING = 25) + switched_off_qualities = list(QUALITY_EXCAVATION = 15, QUALITY_PRYING = 25) + switched_on_qualities = list(QUALITY_DIGGING = 40, QUALITY_PRYING = 20) + glow_color = COLOR_BLUE_LIGHT + degradation = 0.6 + workspeed = 1.2 + use_power_cost = 0 + spawn_blacklisted = TRUE + rarity_value = 10 + spawn_tags = SPAWN_TAG_OS_TOOL + + +/obj/item/tool/pickaxe/jackhammer + name = "jackhammer" + desc = "Cracks rocks with blasts, perfect for killing cave lizards." + icon_state = "jackhammer" + item_state = "jackhammer" + matter = list(MATERIAL_STEEL = 6, MATERIAL_PLASTIC = 2) + tool_qualities = list(QUALITY_EXCAVATION = 10) + switched_off_qualities = list(QUALITY_EXCAVATION = 10) + switched_on_qualities = list(QUALITY_DIGGING = 35) + origin_tech = list(TECH_MATERIAL = 3, TECH_POWER = 2, TECH_ENGINEERING = 2) + degradation = 0.7 + use_power_cost = 0.4 + suitable_cell = /obj/item/cell/medium + rarity_value = 48 + hitsound = 'sound/weapons/melee/blunthit.ogg' + +/obj/item/tool/pickaxe/jackhammer/onestar + name = "One Star jackhammer" + desc = "A heavy One Star tool that cracks rocks with blasts, perfect for killing capitalist pigs." + icon_state = "one_star_jackhammer" + item_state = "jackhammer" + matter = list(MATERIAL_STEEL = 7, MATERIAL_PLATINUM = 2) + tool_qualities = list(QUALITY_EXCAVATION = 10) + switched_off_qualities = list(QUALITY_EXCAVATION = 10) + switched_on_qualities = list(QUALITY_DIGGING = 35) + origin_tech = list(TECH_MATERIAL = 4, TECH_POWER = 2, TECH_ENGINEERING = 3) + degradation = 0.6 + workspeed = 1.7 + max_upgrades = 2 + use_power_cost = 0.6 + spawn_blacklisted = TRUE + rarity_value = 10 + spawn_tags = SPAWN_TAG_OS_TOOL + +/obj/item/tool/pickaxe/drill + name = "mining drill" // Can dig sand as well! + desc = "Yours is the drill that will pierce through the rock walls." + icon_state = "handdrill" + item_state = "jackhammer" + tool_qualities = list(QUALITY_EXCAVATION = 10, QUALITY_DRILLING = 10) + switched_off_qualities = list(QUALITY_EXCAVATION = 10, QUALITY_DRILLING = 10) + switched_on_qualities = list(QUALITY_DIGGING = 40, QUALITY_DRILLING = 10) + matter = list(MATERIAL_STEEL = 8, MATERIAL_PLASTIC = 2) + origin_tech = list(TECH_MATERIAL = 2, TECH_POWER = 3, TECH_ENGINEERING = 2) + degradation = 0.7 + use_fuel_cost = 0.07 + max_fuel = 100 + rarity_value = 48 + hitsound = 'sound/weapons/melee/blunthit.ogg' + +/obj/item/tool/pickaxe/drill/onestar + name = "One Star mining drill" + desc = "Yours is the drill that will pierce through the worker, metaphorically." + icon_state = "one_star_drill" + tool_qualities = list(QUALITY_EXCAVATION = 10, QUALITY_DRILLING = 10) + switched_off_qualities = list(QUALITY_EXCAVATION = 10, QUALITY_DRILLING = 10) + switched_on_qualities = list(QUALITY_DIGGING = 40, QUALITY_DRILLING = 10) + matter = list(MATERIAL_STEEL = 8, MATERIAL_PLATINUM = 2) + origin_tech = list(TECH_MATERIAL = 4, TECH_POWER = 3, TECH_ENGINEERING = 2) + degradation = 0.6 + workspeed = 1.7 + max_upgrades = 2 + use_fuel_cost = 0.10 + max_fuel = 90 + spawn_blacklisted = TRUE + rarity_value = 10 + spawn_tags = SPAWN_TAG_OS_TOOL + +/obj/item/tool/pickaxe/diamonddrill + name = "diamond-point mining drill" + desc = "Yours is the drill that will pierce the heavens!" + icon_state = "diamonddrill" + item_state = "jackhammer" + force = WEAPON_FORCE_DANGEROUS * 1.15 + tool_qualities = list(QUALITY_EXCAVATION = 10, QUALITY_DRILLING = 20) + switched_off_qualities = list(QUALITY_EXCAVATION = 10, QUALITY_DRILLING = 20) + switched_on_qualities = list(QUALITY_DIGGING = 50, QUALITY_DRILLING = 20) + matter = list(MATERIAL_STEEL = 8, MATERIAL_PLASTEEL = 2, MATERIAL_PLASTIC = 2, MATERIAL_DIAMOND = 1) + origin_tech = list(TECH_MATERIAL = 6, TECH_POWER = 4, TECH_ENGINEERING = 5) + max_upgrades = 4 + degradation = 0.1 + use_fuel_cost = 0.07 + max_fuel = 120 + rarity_value = 96 + spawn_tags = SPAWN_TAG_TOOL_ADVANCED + hitsound = 'sound/weapons/melee/blunthit.ogg' + +/obj/item/tool/pickaxe/diamonddrill/rig + use_fuel_cost = 0 + passive_fuel_cost = 0 + spawn_tags = null + +/obj/item/tool/pickaxe/excavation + name = "hand pickaxe" + desc = "A smaller, more precise version of the pickaxe, used for archeology excavation." + icon_state = "pick_hand" + item_state = "syringe_0" + force = WEAPON_FORCE_PAINFUL //It's smaller + tool_qualities = list(QUALITY_EXCAVATION = 30, QUALITY_PRYING = 15) + switched_off_qualities = list(QUALITY_EXCAVATION = 30, QUALITY_PRYING = 15) + switched_on_qualities = list(QUALITY_DIGGING = 15, QUALITY_PRYING = 15) + w_class = ITEM_SIZE_NORMAL + matter = list(MATERIAL_STEEL = 3) + rarity_value = 48 diff --git a/code/game/objects/items/weapons/tools/retractors.dm b/code/game/objects/items/weapons/tools/retractors.dm new file mode 100644 index 0000000000000..cd38dca9964f1 --- /dev/null +++ b/code/game/objects/items/weapons/tools/retractors.dm @@ -0,0 +1,9 @@ +/obj/item/tool/retractor + name = "retractor" + desc = "Retracts stuff." + icon_state = "retractor" + matter = list(MATERIAL_STEEL = 2) + flags = CONDUCT + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1) + tool_qualities = list(QUALITY_RETRACTING = 30) + spawn_tags = SPAWN_TAG_SURGERY_TOOL diff --git a/code/game/objects/items/weapons/tools/saws.dm b/code/game/objects/items/weapons/tools/saws.dm new file mode 100644 index 0000000000000..894b934f760b9 --- /dev/null +++ b/code/game/objects/items/weapons/tools/saws.dm @@ -0,0 +1,92 @@ +/obj/item/tool/saw //tier 2 + name = "metal saw" + desc = "For cutting wood and other objects to pieces. Or sawing bones, in case of emergency." + icon_state = "metal_saw" + force = WEAPON_FORCE_NORMAL + throwforce = WEAPON_FORCE_NORMAL + worksound = WORKSOUND_SIMPLE_SAW + flags = CONDUCT + w_class = ITEM_SIZE_NORMAL + matter = list(MATERIAL_STEEL = 3, MATERIAL_PLASTIC = 1) + attack_verb = list("attacked", "slashed", "sawed", "cut") + hitsound = 'sound/weapons/bladeslice.ogg' + sharp = TRUE + edge = TRUE + forced_broad_strike = TRUE + tool_qualities = list(QUALITY_SAWING = 30, QUALITY_CUTTING = 20, QUALITY_WIRE_CUTTING = 20) + embed_mult = 1.3 //Serrated blades catch on bone more easily + +/obj/item/tool/saw/improvised //tier 1 + name = "choppa" + desc = "A wicked serrated blade made of whatever nasty sharp things you could find. It would make a pretty decent weapon, given there are more space for some tool mods too." + icon_state = "impro_saw" + force = WEAPON_FORCE_PAINFUL //doubles as makeshift melee weapon, thus must have more damage than tier 2 saw + tool_qualities = list(QUALITY_SAWING = 15, QUALITY_CUTTING = 10, QUALITY_WIRE_CUTTING = 10) + degradation = 1 + max_upgrades = 5 //all makeshift tools get more mods to make them actually viable for mid-late game + spawn_tags = SPAWN_TAG_JUNKTOOL + rarity_value = 3 + +/obj/item/tool/saw/circular //tier 3 + name = "circular saw" + desc = "For heavy duty cutting." + icon_state = "saw" + hitsound = WORKSOUND_CIRCULAR_SAW + worksound = WORKSOUND_CIRCULAR_SAW + force = WEAPON_FORCE_DANGEROUS * 1.15 + armor_divisor = ARMOR_PEN_MODERATE + matter = list(MATERIAL_STEEL = 5, MATERIAL_PLASTIC = 2) + tool_qualities = list(QUALITY_SAWING = 40, QUALITY_CUTTING = 30, QUALITY_WIRE_CUTTING = 30) + + use_power_cost = 0.15 + suitable_cell = /obj/item/cell/small + spawn_tags = SPAWN_TAG_SURGERY_TOOL + +/obj/item/tool/saw/circular/advanced //tier 4, focusing on armor penetration + name = "advanced circular saw" + desc = "You think you can cut anything with it." + icon_state = "advanced_saw" + force = WEAPON_FORCE_ROBUST + armor_divisor = ARMOR_PEN_DEEP + matter = list(MATERIAL_STEEL = 6, MATERIAL_PLASTEEL = 1, MATERIAL_PLASTIC = 2) + tool_qualities = list(QUALITY_SAWING = 50, QUALITY_CUTTING = 40, QUALITY_WIRE_CUTTING = 40) + degradation = 0.7 + use_power_cost = 0.22 + max_upgrades = 4 + spawn_blacklisted = TRUE + rarity_value = 20 + +/obj/item/tool/saw/chain //tier 4, focusing on damage, fuel variant + name = "chainsaw" + desc = "You can cut trees, people, walls and zombies with it, just watch out for fuel." + icon_state = "chainsaw" + hitsound = WORKSOUND_CHAINSAW + worksound = WORKSOUND_CHAINSAW + force = WEAPON_FORCE_BRUTAL //Rip and tear! + armor_divisor = ARMOR_PEN_SHALLOW + matter = list(MATERIAL_STEEL = 3, MATERIAL_PLASTEEL = 10, MATERIAL_PLASTIC = 2) + tool_qualities = list(QUALITY_SAWING = 60, QUALITY_CUTTING = 50, QUALITY_WIRE_CUTTING = 20) //not the best choice to cut wires + w_class = ITEM_SIZE_BULKY + max_upgrades = 4 + use_fuel_cost = 0.1 + max_fuel = 80 + rarity_value = 96 + spawn_tags = SPAWN_TAG_TOOL_ADVANCED + +/obj/item/tool/saw/hyper //tier 4, focusing on damage, cell variant + name = "TM hypersaw" + desc = "This eco-friendly chainsaw will Rip and Tear until it is done." + icon_state = "hypersaw" + hitsound = WORKSOUND_CHAINSAW + worksound = WORKSOUND_CHAINSAW + force = WEAPON_FORCE_BRUTAL + armor_divisor = ARMOR_PEN_SHALLOW + matter = list(MATERIAL_SILVER = 2, MATERIAL_PLASTEEL = 10, MATERIAL_PLASTIC = 3) + tool_qualities = list(QUALITY_SAWING = 60, QUALITY_CUTTING = 50, QUALITY_WIRE_CUTTING = 20) + w_class = ITEM_SIZE_BULKY + max_upgrades = 4 + degradation = 0.7 + use_power_cost = 1 + suitable_cell = /obj/item/cell/medium + rarity_value = 96 + spawn_tags = SPAWN_TAG_TOOL_ADVANCED diff --git a/code/game/objects/items/weapons/tools/scalpels.dm b/code/game/objects/items/weapons/tools/scalpels.dm new file mode 100644 index 0000000000000..d9d44ba1587e2 --- /dev/null +++ b/code/game/objects/items/weapons/tools/scalpels.dm @@ -0,0 +1,50 @@ +/obj/item/tool/scalpel + name = "scalpel" + desc = "Cut, cut, and once more cut." + icon_state = "scalpel_t3" + flags = CONDUCT + force = WEAPON_FORCE_PAINFUL + armor_divisor = ARMOR_PEN_SHALLOW + sharp = TRUE + edge = TRUE + w_class = ITEM_SIZE_TINY + worksound = WORKSOUND_HARD_SLASH + slot_flags = SLOT_EARS + throw_speed = WEAPON_FORCE_WEAK + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1) + matter = list(MATERIAL_STEEL = 4) + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + hitsound = 'sound/weapons/melee/lightstab.ogg' + tool_qualities = list(QUALITY_CUTTING = 30, QUALITY_WIRE_CUTTING = 10) + spawn_tags = SPAWN_TAG_SURGERY_TOOL + +/obj/item/tool/scalpel/advanced + name = "advanced scalpel" + desc = "Made of more expensive materials, sharper and generally more reliable." + icon_state = "scalpel_t4" + matter = list(MATERIAL_STEEL = 5, MATERIAL_PLASTEEL = 1) + tool_qualities = list(QUALITY_CUTTING = 40, QUALITY_WIRE_CUTTING = 10) + degradation = 0.12 + max_upgrades = 4 + rarity_value = 20 + +/obj/item/tool/scalpel/laser + name = "laser scalpel" + desc = "A scalpel which uses a directed laser to slice instead of a blade, for more precise surgery while also cauterizing as it cuts." + icon_state = "scalpel_t5" + damtype = "fire" + force = WEAPON_FORCE_DANGEROUS + armor_divisor = ARMOR_PEN_MODERATE + matter = list(MATERIAL_STEEL = 4, MATERIAL_PLASTIC = 4) + tool_qualities = list(QUALITY_CUTTING = 40, QUALITY_WIRE_CUTTING = 20, QUALITY_LASER_CUTTING = 40, QUALITY_CAUTERIZING = 20) + degradation = 0.11 + use_power_cost = 0.12 + suitable_cell = /obj/item/cell/small + max_upgrades = 4 + rarity_value = 30 + +// Laser cutting overrides normal cutting +/obj/item/tool/scalpel/laser/get_tool_type(mob/living/user, list/required_qualities, atom/use_on, datum/callback/CB) + if(QUALITY_LASER_CUTTING in required_qualities) + required_qualities -= QUALITY_CUTTING + return ..(user, required_qualities, use_on, CB) diff --git a/code/game/objects/items/weapons/tools/screwdrivers.dm b/code/game/objects/items/weapons/tools/screwdrivers.dm new file mode 100644 index 0000000000000..bd35c70d67bfe --- /dev/null +++ b/code/game/objects/items/weapons/tools/screwdrivers.dm @@ -0,0 +1,78 @@ +/obj/item/tool/screwdriver + name = "screwdriver" + desc = "You can use this to open panels, screw stuff and such things." + icon_state = "screwdriver" + flags = CONDUCT + worksound = WORKSOUND_SCREW_DRIVING + slot_flags = SLOT_BELT | SLOT_EARS + w_class = ITEM_SIZE_TINY + matter = list(MATERIAL_STEEL = 2, MATERIAL_PLASTIC = 1) + attack_verb = list("stabbed") + hitsound = 'sound/weapons/melee/lightstab.ogg' + tool_qualities = list(QUALITY_SCREW_DRIVING = 30, QUALITY_BONE_SETTING = 10) + rarity_value = 6 + +/obj/item/tool/screwdriver/improvised + name = "screwpusher" + desc = "A little metal rod wrapped in tape, barely qualifies as a tool. This can be fixed with enough tool mods, for which it has ample capacity." + icon_state = "impro_screwdriver" + tool_qualities = list(QUALITY_SCREW_DRIVING = 15) + degradation = 2 + max_upgrades = 5 //all makeshift tools get more mods to make them actually viable for mid-late game + rarity_value = 3 + spawn_tags = SPAWN_TAG_JUNKTOOL + +/obj/item/tool/screwdriver/electric + name = "electric screwdriver" + desc = "An electrical screwdriver, powered by an S class cell. Can be used as a drilling tool if necessary, though is not well suited to do so." + icon_state = "e-screwdriver" + worksound = WORKSOUND_DRIVER_TOOL + matter = list(MATERIAL_STEEL = 2, MATERIAL_PLASTIC = 1) + tool_qualities = list(QUALITY_SCREW_DRIVING = 40, QUALITY_DRILLING = 10, QUALITY_BONE_SETTING = 10) + degradation = 0.7 + max_upgrades = 4 + use_power_cost = 0.18 + suitable_cell = /obj/item/cell/small + rarity_value = 24 + +/obj/item/tool/screwdriver/combi_driver + name = "combi driver" + desc = "Drive screws, drive bolts, drill bones - you can do everything with it." + icon_state = "combi_driver" + w_class = ITEM_SIZE_NORMAL + worksound = WORKSOUND_DRIVER_TOOL + slot_flags = SLOT_BELT + matter = list(MATERIAL_STEEL = 3, MATERIAL_PLASTEEL = 1, MATERIAL_PLASTIC = 2) + tool_qualities = list(QUALITY_SCREW_DRIVING = 50, QUALITY_BOLT_TURNING = 50, QUALITY_DRILLING = 20) + degradation = 0.7 + use_power_cost = 0.24 + suitable_cell = /obj/item/cell/small + max_upgrades = 4 + rarity_value = 48 + spawn_tags = SPAWN_TAG_TOOL_ADVANCED + +/obj/item/tool/screwdriver/attack(mob/living/carbon/M, mob/living/carbon/user) + if(!istype(M) || user.a_intent == "help") + return ..() + if(user.targeted_organ != BP_EYES && user.targeted_organ != BP_HEAD) + return ..() +/* if((CLUMSY in user.mutations) && prob(50)) + M = user */ + return eyestab(M,user) + + +/obj/item/tool/screwdriver/combi_driver/onestar + name = "One Star combi driver" + desc = "A One Star combi driver. Does better than the standard combi drivers on the market, but has less slots for tool mods." + icon_state = "one_star_combidriver" + matter = list(MATERIAL_STEEL = 4, MATERIAL_PLATINUM = 2) + tool_qualities = list(QUALITY_SCREW_DRIVING = 60, QUALITY_BOLT_TURNING = 60, QUALITY_DRILLING = 25) + origin_tech = list(TECH_ENGINEERING = 3, TECH_MATERIAL = 2) + degradation = 0.6 + workspeed = 1.7 + use_power_cost = 0.3 + suitable_cell = /obj/item/cell/small + max_upgrades = 2 + spawn_blacklisted = TRUE + rarity_value = 10 + spawn_tags = SPAWN_TAG_OS_TOOL diff --git a/code/game/objects/items/weapons/tools/shovel.dm b/code/game/objects/items/weapons/tools/shovel.dm new file mode 100644 index 0000000000000..e08309055a042 --- /dev/null +++ b/code/game/objects/items/weapons/tools/shovel.dm @@ -0,0 +1,57 @@ +/obj/item/tool/shovel + name = "shovel" + desc = "A large tool for digging and moving dirt and rock." + icon_state = "shovel" + item_state = "shovel" + flags = CONDUCT + slot_flags = SLOT_BELT + force = WEAPON_FORCE_PAINFUL + throwforce = WEAPON_FORCE_WEAK + w_class = ITEM_SIZE_NORMAL + origin_tech = list(TECH_MATERIAL = 1, TECH_ENGINEERING = 1) + matter = list(MATERIAL_STEEL = 5) + attack_verb = list("bashed", "bludgeoned", "thrashed", "whacked") + hitsound = 'sound/weapons/melee/blunthit.ogg' + sharp = FALSE + edge = TRUE + tool_qualities = list(QUALITY_SHOVELING = 30, QUALITY_DIGGING = 30, QUALITY_EXCAVATION = 10, QUALITY_HAMMERING = 10) + rarity_value = 9.6 + +/obj/item/tool/shovel/improvised + name = "junk shovel" + desc = "A large but fragile tool for moving dirt and rock, made by hand. Has more than enough space for tool mods to make it better." + icon_state = "impro_shovel" + tool_qualities = list(QUALITY_SHOVELING = 25, QUALITY_DIGGING = 25, QUALITY_EXCAVATION = 10, QUALITY_HAMMERING = 10) + degradation = 1.5 + max_upgrades = 5 //all makeshift tools get more mods to make them actually viable for mid-late game + rarity_value = 5 + spawn_tags = SPAWN_TAG_JUNKTOOL + +/obj/item/tool/shovel/spade + name = "spade" + desc = "A small tool ofter used for simple gardening task such as digging soil and moving dirt." + icon_state = "spade" + item_state = "spade" + force = WEAPON_FORCE_NORMAL + throwforce = WEAPON_FORCE_HARMLESS + w_class = ITEM_SIZE_SMALL + matter = list(MATERIAL_STEEL = 3, MATERIAL_PLASTIC = 1) + tool_qualities = list(QUALITY_SHOVELING = 20, QUALITY_DIGGING = 20, QUALITY_EXCAVATION = 10,QUALITY_HAMMERING = 10) + max_upgrades = 2 + rarity_value = 19.2 + +/obj/item/tool/shovel/power + name = "power shovel 9000" + desc = "A powered shovel for all your dumpster diving needs." + icon_state = "powershovel" + item_state = "shovel" + force = WEAPON_FORCE_PAINFUL + throwforce = WEAPON_FORCE_WEAK + w_class = ITEM_SIZE_NORMAL + matter = list(MATERIAL_PLASTEEL = 6, MATERIAL_STEEL = 3, MATERIAL_PLASTIC = 1) + tool_qualities = list(QUALITY_SHOVELING = 60, QUALITY_DIGGING = 40, QUALITY_EXCAVATION = 20, QUALITY_HAMMERING = 15) + use_power_cost = 0.8 + degradation = 0.7 + max_upgrades = 4 + suitable_cell = /obj/item/cell/medium + rarity_value = 48 diff --git a/code/game/objects/items/weapons/tools/simple_weapons.dm b/code/game/objects/items/weapons/tools/simple_weapons.dm new file mode 100644 index 0000000000000..a5061a5b33b23 --- /dev/null +++ b/code/game/objects/items/weapons/tools/simple_weapons.dm @@ -0,0 +1,257 @@ +//Those are all weapons that don't had tool modding at some point, but should have it for balance purposes. + +/obj/item/tool/broken_bottle + name = "broken bottle" + desc = "A bottle with a sharp broken bottom." + icon = 'icons/obj/drinks.dmi' + icon_state = "broken_bottle" + matter = list(MATERIAL_GLASS = 2) + worksound = WORKSOUND_HARD_SLASH + force = WEAPON_FORCE_PAINFUL + throwforce = WEAPON_FORCE_WEAK + item_state = "beer" + attack_verb = list("stabbed", "slashed", "attacked") + sharp = TRUE + edge = FALSE + max_upgrades = 1 //it's not even a tool + tool_qualities = list(QUALITY_CUTTING = 10) + var/icon/broken_outline = icon('icons/obj/drinks.dmi', "broken") + spawn_tags = SPAWN_TAG_JUNKTOOL + +/obj/item/tool/nailstick + name = "nailed stick" + desc = "Stick with some nails in it. Looks sharp enough." + icon = 'icons/obj/weapons.dmi' + icon_state = "hm_spikeclub" + item_state = "hm_spikeclub" + force = WEAPON_FORCE_PAINFUL + throwforce = WEAPON_FORCE_PAINFUL + w_class = ITEM_SIZE_NORMAL + origin_tech = list(TECH_COMBAT = 2) + attack_verb = list("beaten", "slammed", "smacked", "struck", "battered") + hitsound = 'sound/weapons/melee/blunthit.ogg' + structure_damage_factor = STRUCTURE_DAMAGE_HEAVY + max_upgrades = 5 + tool_qualities = list(QUALITY_HAMMERING = 10) + spawn_tags = SPAWN_TAG_JUNKTOOL + +/obj/item/tool/hatchet + name = "hatchet" + desc = "A very sharp axe blade upon a short fibremetal handle. It has a long history of chopping things, but now it is used for chopping wood." + icon = 'icons/obj/weapons.dmi' + icon_state = "hatchet" + matter = list(MATERIAL_STEEL = 4, MATERIAL_PLASTIC = 3) + worksound = WORKSOUND_HARD_SLASH + force = WEAPON_FORCE_PAINFUL + throwforce = WEAPON_FORCE_PAINFUL + w_class = ITEM_SIZE_SMALL + sharp = TRUE + edge = TRUE + armor_divisor = ARMOR_PEN_SHALLOW + origin_tech = list(TECH_MATERIAL = 2, TECH_COMBAT = 1) + attack_verb = list("chopped", "torn", "cut") + hitsound = 'sound/weapons/bladeslice.ogg' + tool_qualities = list(QUALITY_CUTTING = 20) + +/obj/item/tool/makeshiftaxe + name = "makeshift axe" + desc = "A heavy plasteel blade affixed to a welded metal shaft, for close up carnage." + icon = 'icons/obj/weapons.dmi' + icon_state = "makeshift_axe" + item_state = "makeshift_axe" + wielded_icon = "makeshift_axe_wielded" + matter = list(MATERIAL_STEEL = 3, MATERIAL_PLASTEEL = 3) + worksound = WORKSOUND_HARD_SLASH + force = WEAPON_FORCE_DANGEROUS + throwforce = WEAPON_FORCE_NORMAL + armor_divisor = ARMOR_PEN_MODERATE + w_class = ITEM_SIZE_NORMAL + slot_flags = SLOT_BACK + sharp = TRUE + edge = TRUE + attack_verb = list("chopped", "torn", "cut", "cleaved", "slashed") + hitsound = 'sound/weapons/melee/heavystab.ogg' + tool_qualities = list(QUALITY_CUTTING = 10) + structure_damage_factor = STRUCTURE_DAMAGE_BREACHING + embed_mult = 1.1 + degradation = 1.5 //not quite as sturdy as a normal weapon + max_upgrades = 5 //all makeshift tools get more mods to make them actually viable for mid-late game + rarity_value = 60 + spawn_tags = SPAWN_TAG_JUNKTOOL + +/obj/item/tool/fireaxe + name = "fire axe" + desc = "Truly, the weapon of a madman. Who would think to fight fire with an axe?" + icon = 'icons/obj/weapons.dmi' + icon_state = "fireaxe0" + wielded_icon = "fireaxe1" + sharp = TRUE + edge = TRUE + armor_divisor = ARMOR_PEN_DEEP + tool_qualities = list(QUALITY_CUTTING = 10, QUALITY_PRYING = 20) + w_class = ITEM_SIZE_HUGE + slot_flags = SLOT_BACK + force = WEAPON_FORCE_NORMAL + force_wielded_multiplier = 3.4 + attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut") + hitsound = 'sound/weapons/bladeslice.ogg' + structure_damage_factor = STRUCTURE_DAMAGE_BREACHING + embed_mult = 1.2 //Axes cut deep, and their hooked shape catches on things + rarity_value = 48 + +/obj/item/tool/fireaxe/afterattack(atom/A as mob|obj|turf|area, mob/user, proximity) + if(!proximity) return + ..() + if(A && wielded) + if(istype(A,/obj/effect/plant)) + var/obj/effect/plant/P = A + P.die_off() + +/obj/item/tool/minihoe + name = "mini hoe" + desc = "It's used for removing weeds or scratching your back." + icon = 'icons/obj/weapons.dmi' + icon_state = "hoe" + item_state = "hoe" + matter = list(MATERIAL_PLASTEEL = 2, MATERIAL_PLASTIC = 2) + force = WEAPON_FORCE_WEAK + throwforce = WEAPON_FORCE_WEAK + max_upgrades = 2 + tool_qualities = list(QUALITY_SHOVELING = 10) + w_class = ITEM_SIZE_SMALL + attack_verb = list("slashed", "sliced", "cut", "clawed") + +/obj/item/tool/scythe + name = "scythe" + desc = "A sharp and curved blade on a long fibremetal handle, this tool makes it easy to reap what you sow." + icon = 'icons/obj/weapons.dmi' + icon_state = "scythe0" + matter = list(MATERIAL_PLASTEEL = 7, MATERIAL_PLASTIC = 3) + sharp = TRUE + edge = TRUE + worksound = WORKSOUND_HARD_SLASH + force = WEAPON_FORCE_PAINFUL + throwforce = WEAPON_FORCE_PAINFUL + w_class = ITEM_SIZE_BULKY + slot_flags = SLOT_BACK + attack_verb = list("chopped", "sliced", "cut", "reaped") + hitsound = 'sound/weapons/bladeslice.ogg' + tool_qualities = list(QUALITY_CUTTING = 15) + spawn_tags = SPAWN_TAG_KNIFE + rarity_value = 30 + +//Swords +/obj/item/tool/sword + name = "claymore" + desc = "What are you standing around staring at this for? Get to killing!" + icon = 'icons/obj/weapons.dmi' + icon_state = "claymore" + item_state = "claymore" + matter = list(MATERIAL_PLASTEEL = 15, MATERIAL_PLASTIC = 5) + sharp = TRUE + edge = TRUE + w_class = ITEM_SIZE_NORMAL + slot_flags = SLOT_BELT | SLOT_BACK + worksound = WORKSOUND_HARD_SLASH + force = WEAPON_FORCE_ROBUST + armor_divisor = ARMOR_PEN_DEEP + + throwforce = WEAPON_FORCE_NORMAL + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + hitsound = 'sound/weapons/melee/sharphit.ogg' + tool_qualities = list(QUALITY_CUTTING = 10) + structure_damage_factor = STRUCTURE_DAMAGE_BLADE + spawn_frequency = 8 + spawn_tags = SPAWN_TAG_SWORD + rarity_value = 25 + +/obj/item/tool/sword/saber + name = "officer's saber" + desc = "A saber with golden grip, for the real heads of this ship." + icon_state = "saber" + item_state = "saber" + matter = list(MATERIAL_PLASTEEL = 15, MATERIAL_WOOD = 10, MATERIAL_GOLD = 10, MATERIAL_DIAMOND = 1) + slot_flags = SLOT_BELT + force = WEAPON_FORCE_BRUTAL + armor_divisor = ARMOR_PEN_MODERATE + spawn_blacklisted = TRUE + price_tag = 10000 + +/obj/item/tool/sword/improvised + name = "junkblade" + desc = "Hack and slash!" + icon_state = "msword" + item_state = "msword" + armor_divisor = ARMOR_PEN_MODERATE + tool_qualities = list(QUALITY_CUTTING = 15) // a little better than the regular swords. + degradation = 1.5 //not quite as sturdy as a normal weapon + max_upgrades = 5 //all makeshift tools get more mods to make them actually viable for mid-late game + rarity_value = 60 + spawn_tags = SPAWN_TAG_JUNKTOOL + +/obj/item/tool/sword/katana //slightly less penetration, slightly more damage + name = "katana" + desc = "Modern japanese-style blade that has no curve to it. This one looks pretty sharp." + icon_state = "katana" + item_state = "katana" + matter = list(MATERIAL_PLASTEEL = 10, MATERIAL_STEEL = 5, MATERIAL_DIAMOND = 1) //sharpened using diamond dust or whatever + force = WEAPON_FORCE_DANGEROUS * 1.5 + armor_divisor = ARMOR_PEN_MODERATE + rarity_value = 35 + +/obj/item/tool/sword/katana/nano + name = "\improper Moebius \"Muramasa\" katana" + desc = "After an extensive binge of ancient animated recordings, a scientist decided to upgrade a recovered katana." + icon_state = "eutactic_katana" + item_state = "eutactic_katana" + toggleable = TRUE + max_upgrades = 1 + + suitable_cell = /obj/item/cell/small + + use_power_cost = 0.4 + passive_power_cost = 0.4 + + switched_on_qualities = list(QUALITY_CUTTING = 25) + origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 6) + switched_on_force = WEAPON_FORCE_BRUTAL + rarity_value = 60 + spawn_blacklisted = TRUE + +/obj/item/tool/sword/katana/nano/turn_on(mob/user) + .=..() + if(.) + embed_mult = 0 + playsound(user, 'sound/weapons/saberon.ogg', 50, 1) + +/obj/item/tool/sword/katana/nano/turn_off(mob/user) + ..() + embed_mult = initial(embed_mult) + playsound(user, 'sound/weapons/saberoff.ogg', 50, 1) + +/obj/item/tool/sword/katana/nano/update_icon() + ..() + if(cell) + overlays += "[icon_state]_cell" + if(switched_on) + overlays += "[icon_state]_power_on" + else + overlays += "[icon_state]_power_off" + +//Flails +/obj/item/tool/chainofcommand + name = "chain of command" + desc = "A tool used by great men to placate the frothing masses." + icon = 'icons/obj/weapons.dmi' + icon_state = "chain" + item_state = "chain" + flags = CONDUCT + slot_flags = SLOT_BELT + force = WEAPON_FORCE_DANGEROUS + throwforce = WEAPON_FORCE_DANGEROUS + w_class = ITEM_SIZE_NORMAL + origin_tech = list(TECH_COMBAT = 4) + attack_verb = list("flogged", "whipped", "lashed", "disciplined") + max_upgrades = 2 + tool_qualities = list(QUALITY_HAMMERING = 5) + spawn_blacklisted = TRUE diff --git a/code/game/objects/items/weapons/tools/surgicaldrills.dm b/code/game/objects/items/weapons/tools/surgicaldrills.dm new file mode 100644 index 0000000000000..3e9b7debc06d4 --- /dev/null +++ b/code/game/objects/items/weapons/tools/surgicaldrills.dm @@ -0,0 +1,18 @@ +/obj/item/tool/surgicaldrill + name = "surgical drill" + desc = "You can drill using this item. You dig?" + icon_state = "drill" + hitsound = WORKSOUND_DRIVER_TOOL + worksound = WORKSOUND_DRIVER_TOOL + matter = list(MATERIAL_STEEL = 4, MATERIAL_PLASTIC = 2) + flags = CONDUCT + force = WEAPON_FORCE_DANGEROUS + armor_divisor = ARMOR_PEN_MODERATE + w_class = ITEM_SIZE_NORMAL + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1) + attack_verb = list("drilled") + tool_qualities = list(QUALITY_DRILLING = 30) + spawn_tags = SPAWN_TAG_SURGERY_TOOL + + use_power_cost = 0.24 + suitable_cell = /obj/item/cell/small diff --git a/code/game/objects/items/weapons/tools/tape.dm b/code/game/objects/items/weapons/tools/tape.dm new file mode 100644 index 0000000000000..470a1fffe7262 --- /dev/null +++ b/code/game/objects/items/weapons/tools/tape.dm @@ -0,0 +1,222 @@ +/obj/item/tool/tape_roll + name = "duct tape" + desc = "The technomancer's eternal friend. Fixes just about anything, for a while at least." + icon = 'icons/obj/tools.dmi' + description_info = "Can be used for crafting or to repair tools" + description_antag = "Can be used to make makeshift mouthwraps and to tape cameras silently" + icon_state = "taperoll" + w_class = ITEM_SIZE_SMALL + tool_qualities = list(QUALITY_ADHESIVE = 30, QUALITY_SEALING = 30) + matter = list(MATERIAL_PLASTIC = 3) + worksound = WORKSOUND_TAPE + use_stock_cost = 0.15 + max_stock = 100 + degradation = 0 //its consumable anyway + flags = NOBLUDGEON //Its not a weapon + max_upgrades = 0 //These are consumable, so no wasting upgrades on them + rarity_value = 4 + +/obj/item/tool/tape_roll/web + name = "web tape" + desc = "A strip of fabric covered in an all-natural adhesive. Holds things together with the power of thoughts and prayers." + tool_qualities = list(QUALITY_ADHESIVE = 15, QUALITY_SEALING = 15) + use_stock_cost = 0.17 + max_stock = 30 + alpha = 150 + rarity_value = 2 + spawn_tags = SPAWN_TAG_JUNKTOOL + +/obj/item/tool/tape_roll/fiber + name = "fiber tape" + desc = "A roll of flexible adhesive polymer mesh, which sets as strong as welded steel." + icon_state = "fiber_tape" + tool_qualities = list(QUALITY_ADHESIVE = 50, QUALITY_SEALING = 50) + matter = list(MATERIAL_PLASTIC = 20) + use_stock_cost = 0.10 + max_stock = 100 + spawn_frequency = 8 + rarity_value = 24 + spawn_tags = SPAWN_TAG_TOOL_ADVANCED + +/obj/item/tool/tape_roll/glue + name = "superglue" + desc = "A bucket of milky white fluid. Can be used to stick things together, but unlike tape, it cannot be used to seal things." + icon = 'icons/obj/tools.dmi' + icon_state = "glue" + tool_qualities = list(QUALITY_ADHESIVE = 40, QUALITY_CAUTERIZING = 5) // Better than duct tape, but can't seal things and is mostly used in crafting - also, it's glue, so it can be used as an extremely shitty way of sealing wounds + matter = list(MATERIAL_BIOMATTER = 30) + worksound = NO_WORKSOUND + +/obj/item/tool/tape_roll/attack(mob/living/carbon/human/H, mob/user) + if(istype(H)) + if(user.targeted_organ == BP_EYES) + + if(!H.organs_by_name[BP_HEAD]) + to_chat(user, SPAN_WARNING("\The [H] doesn't have a head.")) + return + if(!H.has_eyes()) + to_chat(user, SPAN_WARNING("\The [H] doesn't have any eyes.")) + return + if(H.glasses) + to_chat(user, SPAN_WARNING("\The [H] is already wearing somethign on their eyes.")) + return + if(H.head && (H.head.body_parts_covered & FACE)) + to_chat(user, SPAN_WARNING("Remove their [H.head] first.")) + return + user.visible_message(SPAN_DANGER("\The [user] begins taping over \the [H]'s eyes!")) + + if(!use_tool(user, H, 70, QUALITY_ADHESIVE)) + return + + // Repeat failure checks. + if(!H || !src || !H.organs_by_name[BP_HEAD] || !H.has_eyes() || H.glasses || (H.head && (H.head.body_parts_covered & FACE))) + return + + user.visible_message(SPAN_DANGER("\The [user] has taped up \the [H]'s eyes!")) + H.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses/blindfold/tape(H), slot_glasses) + + else if(user.targeted_organ == BP_MOUTH || user.targeted_organ == BP_HEAD) + if(!H.organs_by_name[BP_HEAD]) + to_chat(user, SPAN_WARNING("\The [H] doesn't have a head.")) + return + if(!H.check_has_mouth()) + to_chat(user, SPAN_WARNING("\The [H] doesn't have a mouth.")) + return + if(H.wear_mask) + to_chat(user, SPAN_WARNING("\The [H] is already wearing a mask.")) + return + if(H.head && (H.head.body_parts_covered & FACE)) + to_chat(user, SPAN_WARNING("Remove their [H.head] first.")) + return + user.visible_message(SPAN_DANGER("\The [user] begins taping up \the [H]'s mouth!")) + + if(!use_tool(user, H, 70, QUALITY_ADHESIVE)) + return + + // Repeat failure checks. + if(!H || !src || !H.organs_by_name[BP_HEAD] || !H.check_has_mouth() || H.wear_mask || (H.head && (H.head.body_parts_covered & FACE))) + return + + user.visible_message(SPAN_DANGER("\The [user] has taped up \the [H]'s mouth!")) + H.equip_to_slot_or_del(new /obj/item/clothing/mask/muzzle/tape(H), slot_wear_mask) + + else if(user.targeted_organ == BP_R_ARM || user.targeted_organ == BP_L_ARM) + if(use_tool(user, H, 90, QUALITY_ADHESIVE)) + var/obj/item/handcuffs/cable/tape/T = new(user) + if(!T.place_handcuffs(H, user)) + user.unEquip(T) + qdel(T) + else + return ..() + return 1 + +/obj/item/tool/tape_roll/stick(obj/item/target, mob/user) + if (!istype(target) || target.anchored) + return + + if (target.w_class > ITEM_SIZE_SMALL) + to_chat(user, SPAN_WARNING("The [target] is too big to stick with tape!")) + return + if (istype(target.loc, /obj)) + return + consume_resources(10, user) + user.drop_from_inventory(target) + var/obj/item/ducttape/tape = new(get_turf(src)) + tape.attach(target) + user.put_in_hands(tape) + return TRUE + + +/obj/item/ducttape + name = "tape" + desc = "A piece of sticky tape." + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "tape" + w_class = ITEM_SIZE_TINY + layer = BELOW_MOB_LAYER + anchored = TRUE //it's sticky, no you cant move it + spawn_frequency = 0 + bad_type = /obj/item/ducttape + + var/obj/item/stuck + +/obj/item/ducttape/New() + ..() + flags |= NOBLUDGEON + +/obj/item/ducttape/update_plane() + ..() + update_icon() + + +/obj/item/ducttape/examine(mob/user) + return stuck.examine(user) + +/obj/item/ducttape/proc/attach(obj/item/W) + stuck = W + W.forceMove(src) + update_icon() + name = W.name + " (taped)" + +/obj/item/ducttape/update_icon() + if (!stuck) + return + + if (istype(stuck, /obj/item/paper)) + icon_state = stuck.icon_state + cut_overlays() + overlays = stuck.overlays + "tape_overlay" + else + var/mutable_appearance/MA = new(stuck) + MA.layer = layer-0.1 + MA.plane = plane + MA.pixel_x = 0 + MA.pixel_y = 0 + underlays.Cut() + underlays += MA + +/obj/item/ducttape/attack_self(mob/user) + if(!stuck) + return + + to_chat(user, "You remove \the [initial(name)] from [stuck].") + + user.drop_from_inventory(src) + stuck.forceMove(get_turf(src)) + user.put_in_hands(stuck) + stuck = null + overlays = null + qdel(src) + +/obj/item/ducttape/afterattack(A, mob/user, flag, params) + + if(!in_range(user, A) || istype(A, /obj/machinery/door) || !stuck) + return + + var/turf/target_turf = get_turf(A) + var/turf/source_turf = get_turf(user) + + var/dir_offset = 0 + if(target_turf != source_turf) + dir_offset = get_dir(source_turf, target_turf) + if(!(dir_offset in cardinal)) + to_chat(user, "You cannot reach that from here.") // can only place stuck papers in cardinal directions, to + return // reduce papers around corners issue. + + user.drop_from_inventory(src) + forceMove(source_turf) + + if(params) + var/list/mouse_control = params2list(params) + if(mouse_control["icon-x"]) + pixel_x = text2num(mouse_control["icon-x"]) - 16 + if(dir_offset & EAST) + pixel_x += 32 + else if(dir_offset & WEST) + pixel_x -= 32 + if(mouse_control["icon-y"]) + pixel_y = text2num(mouse_control["icon-y"]) - 16 + if(dir_offset & NORTH) + pixel_y += 32 + else if(dir_offset & SOUTH) + pixel_y -= 32 diff --git a/code/game/objects/items/weapons/tools/weldingtools.dm b/code/game/objects/items/weapons/tools/weldingtools.dm new file mode 100644 index 0000000000000..c1931d2bcf356 --- /dev/null +++ b/code/game/objects/items/weapons/tools/weldingtools.dm @@ -0,0 +1,113 @@ +/obj/item/tool/weldingtool + name = "welding tool" + icon_state = "welder" + item_state = "welder" + rarity_value = 6 + flags = CONDUCT + force = WEAPON_FORCE_WEAK + switched_on_force = WEAPON_FORCE_PAINFUL + throwforce = WEAPON_FORCE_WEAK + worksound = WORKSOUND_WELDING + matter = list(MATERIAL_STEEL = 5) + origin_tech = list(TECH_ENGINEERING = 1) + switched_on_qualities = list(QUALITY_WELDING = 30, QUALITY_CAUTERIZING = 10, QUALITY_WIRE_CUTTING = 10) + switched_on_hitsound = 'sound/items/Welder.ogg' + + sparks_on_use = TRUE + eye_hazard = TRUE + + use_fuel_cost = 0.1 + max_fuel = 25 + + toggleable = TRUE + create_hot_spot = TRUE + glow_color = COLOR_ORANGE + + heat = 2250 + +/obj/item/tool/weldingtool/turn_on(mob/user) + .=..() + if(.) + playsound(loc, 'sound/items/welderactivate.ogg', 50, 1) + damtype = BURN + START_PROCESSING(SSobj, src) + +/obj/item/tool/weldingtool/turn_off(mob/user) + item_state = initial(item_state) + playsound(loc, 'sound/items/welderdeactivate.ogg', 50, 1) + ..() + damtype = initial(damtype) + + +/obj/item/tool/weldingtool/is_hot() + if (damtype == BURN) + return heat + + +/obj/item/tool/weldingtool/improvised + name = "jury-rigged torch" + desc = "An assembly of pipes attached to a little gas tank. Serves capably as a welder, though a bit risky. Can be improved greatly with large amount of tool mods." + icon_state = "ghettowelder" + item_state = "ghettowelder" + switched_on_force = WEAPON_FORCE_PAINFUL * 0.8 + max_fuel = 15 + switched_on_qualities = list(QUALITY_WELDING = 15, QUALITY_CAUTERIZING = 10, QUALITY_WIRE_CUTTING = 10) + degradation = 1.5 + max_upgrades = 5 //all makeshift tools get more mods to make them actually viable for mid-late game + rarity_value = 4 + spawn_tags = SPAWN_TAG_JUNKTOOL + +//The improvised welding tool is created with a full tank of fuel. +//It's implied that it's burning the oxygen in the emergency tank that was used to create it +/obj/item/tool/weldingtool/improvised/Created() + return + + +/obj/item/tool/weldingtool/advanced + name = "advanced welding tool" + icon_state = "adv_welder" + item_state = "adv_welder" + glow_color = COLOR_BLUE_LIGHT + switched_on_qualities = list(QUALITY_WELDING = 40, QUALITY_CAUTERIZING = 15, QUALITY_WIRE_CUTTING = 15) + max_fuel = 40 + switched_on_force = WEAPON_FORCE_PAINFUL * 1.15 //Slightly more powerful, not much more so + heat = 3773 + degradation = 0.7 + max_upgrades = 4 + rarity_value = 24 + spawn_tags = SPAWN_TAG_TOOL_ADVANCED + +/obj/item/tool/weldingtool/onestar + name = "One Star welding tool" + desc = "An old and legendary One Star welding tool. Very powerful and reliable, but its compact design causes it to suffer from a lack of both fuel storage and efficiency." + icon_state = "one_star_welder" + item_state = "welder" + matter = list(MATERIAL_STEEL = 4, MATERIAL_PLATINUM = 2) + origin_tech = list(TECH_ENGINEERING = 2, TECH_MATERIAL = 3) + switched_on_qualities = list(QUALITY_WELDING = 30, QUALITY_CAUTERIZING = 10, QUALITY_WIRE_CUTTING = 10) + glow_color = COLOR_RED_LIGHT + use_fuel_cost = 0.15 + max_fuel = 20 + degradation = 0.6 + heat = 2750 + max_upgrades = 2 + workspeed = 1.7 + spawn_blacklisted = TRUE + rarity_value = 10 + spawn_tags = SPAWN_TAG_OS_TOOL + +/obj/item/tool/weldingtool/hivemind + name = "modified welding tool" + icon_state = "hivemind_welder" + item_state = "hivemind_welder" + desc = "A welding tool with numerous growths on it, the fuel tank is bloated. Doubt you will be able to use it for anything other than welding." + glow_color = COLOR_LIME + origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 4, TECH_BIO = 2) + matter = list(MATERIAL_STEEL = 7, MATERIAL_BIOMATTER = 3) + switched_on_qualities = list(QUALITY_WELDING = 50) + use_fuel_cost = 0.2 + max_fuel = 60 + max_upgrades = 4 + degradation = 0.4 +// fuel_type = "blood" + spawn_blacklisted = TRUE diff --git a/code/game/objects/items/weapons/tools/wirecutters.dm b/code/game/objects/items/weapons/tools/wirecutters.dm new file mode 100644 index 0000000000000..b271e67f9f801 --- /dev/null +++ b/code/game/objects/items/weapons/tools/wirecutters.dm @@ -0,0 +1,64 @@ +/obj/item/tool/wirecutters + name = "wirecutters" + desc = "Cuts wires and other objects with it." + icon_state = "cutters" + flags = CONDUCT + force = WEAPON_FORCE_WEAK + worksound = WORKSOUND_WIRECUTTING + origin_tech = list(TECH_MATERIAL = 1, TECH_ENGINEERING = 1) + matter = list(MATERIAL_STEEL = 2, MATERIAL_PLASTIC = 1) + attack_verb = list("pinched", "nipped") + hitsound = 'sound/weapons/melee/lightstab.ogg' + sharp = TRUE + edge = TRUE + tool_qualities = list(QUALITY_WIRE_CUTTING = 30, QUALITY_RETRACTING = 15, QUALITY_BONE_SETTING = 15) + rarity_value = 12 + +//Better and more flexible than most improvised tools, but more bulky and annoying to make +/obj/item/tool/wirecutters/improvised + name = "wiremanglers" + desc = "An improvised monstrosity made of bent rods which can sometimes be used to snip things. Could serve you well if you stuff it with enough tool mods." + icon_state = "impro_cutter" + w_class = ITEM_SIZE_NORMAL + force = WEAPON_FORCE_NORMAL + tool_qualities = list(QUALITY_WIRE_CUTTING = 20, QUALITY_RETRACTING = 10, QUALITY_BONE_SETTING = 10) + degradation = 1.5 + max_upgrades = 5 //all makeshift tools get more mods to make them actually viable for mid-late game + rarity_value = 6 + spawn_tags = SPAWN_TAG_JUNKTOOL + +/obj/item/tool/wirecutters/armature + name = "armature cutter" + desc = "Bigger brother of wirecutter. Can't do much in terms of emergency surgery, but does its main job better." + icon_state = "arm-cutter" + w_class = ITEM_SIZE_NORMAL + force = WEAPON_FORCE_NORMAL + matter = list(MATERIAL_STEEL = 4, MATERIAL_PLASTEEL = 1, MATERIAL_PLASTIC = 1) + tool_qualities = list(QUALITY_WIRE_CUTTING = 40, QUALITY_CUTTING = 30) + degradation = 0.7 + max_upgrades = 4 + rarity_value = 24 + spawn_tags = SPAWN_TAG_TOOL_ADVANCED + +/obj/item/tool/wirecutters/pliers //hybrid of wirecutters, wrench and cautery + name = "pliers" + desc = "A multitool from the world of maintenance. Useful for pinching, clamping, and occasional bolt turning." + icon_state = "pliers" + edge = FALSE + sharp = FALSE + tool_qualities = list(QUALITY_WIRE_CUTTING = 10, QUALITY_CLAMPING = 20, QUALITY_BOLT_TURNING = 15, QUALITY_BONE_SETTING = 20) + +/obj/item/tool/wirecutters/attack(mob/living/carbon/C, mob/user) + if(istype(C) && user.a_intent == I_HELP && (C.handcuffed) && (istype(C.handcuffed, /obj/item/handcuffs/cable))) + usr.visible_message( + "\The [usr] cuts \the [C]'s restraints with \the [src]!", + "You cut \the [C]'s restraints with \the [src]!", + "You hear cable being cut." + ) + C.handcuffed = null + if(C.buckled && C.buckled.buckle_require_restraints) + C.buckled.unbuckle_mob() + C.update_inv_handcuffed() + return + else + ..() diff --git a/code/game/objects/items/weapons/tools/wrenches.dm b/code/game/objects/items/weapons/tools/wrenches.dm new file mode 100644 index 0000000000000..6eaece49266a3 --- /dev/null +++ b/code/game/objects/items/weapons/tools/wrenches.dm @@ -0,0 +1,41 @@ +/obj/item/tool/wrench + name = "wrench" + desc = "A wrench with many common uses. Can be usually found in your hand." + icon_state = "wrench" + flags = CONDUCT + force = WEAPON_FORCE_NORMAL + worksound = WORKSOUND_WRENCHING + throwforce = WEAPON_FORCE_NORMAL + origin_tech = list(TECH_MATERIAL = 1, TECH_ENGINEERING = 1) + matter = list(MATERIAL_STEEL = 3) + attack_verb = list("bashed", "battered", "bludgeoned", "whacked") + hitsound = 'sound/weapons/melee/blunthit.ogg' + tool_qualities = list(QUALITY_BOLT_TURNING = 30, QUALITY_HAMMERING = 10) + rarity_value = 6 + +/obj/item/tool/wrench/improvised + name = "sheet spanner" + desc = "A flat bit of metal with some usefully shaped holes cut into it. Would perform better than a regular wrench with some tool mods investment." + icon_state = "impro_wrench" + degradation = 4 + force = WEAPON_FORCE_HARMLESS + tool_qualities = list(QUALITY_BOLT_TURNING = 20, QUALITY_HAMMERING = 5) + matter = list(MATERIAL_STEEL = 1) + max_upgrades = 5 //all makeshift tools get more mods to make them actually viable for mid-late game + rarity_value = 3 + spawn_tags = SPAWN_TAG_JUNKTOOL + +/obj/item/tool/wrench/big_wrench + name = "big wrench" + desc = "If everything else failed - bring a bigger wrench." + icon_state = "big-wrench" + w_class = ITEM_SIZE_NORMAL + tool_qualities = list(QUALITY_BOLT_TURNING = 40,QUALITY_HAMMERING = 15) + matter = list(MATERIAL_STEEL = 4, MATERIAL_PLASTEEL = 1) + force = WEAPON_FORCE_PAINFUL * 1.2 + structure_damage_factor = STRUCTURE_DAMAGE_HEAVY + throwforce = WEAPON_FORCE_PAINFUL + degradation = 0.7 + max_upgrades = 4 + rarity_value = 24 + spawn_tags = SPAWN_TAG_TOOL_ADVANCED