diff --git a/baystation12.dme b/baystation12.dme index 7031dd98066..0c737c09539 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -874,7 +874,6 @@ #include "code\modules\clothing\spacesuits\rig\modules\computer.dm" #include "code\modules\clothing\spacesuits\rig\modules\modules.dm" #include "code\modules\clothing\spacesuits\rig\modules\ninja.dm" -#include "code\modules\clothing\spacesuits\rig\modules\rig_weapons.dm" #include "code\modules\clothing\spacesuits\rig\modules\utility.dm" #include "code\modules\clothing\spacesuits\rig\modules\vision.dm" #include "code\modules\clothing\spacesuits\rig\suits\alien.dm" diff --git a/code/_onclick/hud/monkey.dm b/code/_onclick/hud/monkey.dm index 65924284b51..0081fbe6b52 100644 --- a/code/_onclick/hud/monkey.dm +++ b/code/_onclick/hud/monkey.dm @@ -226,7 +226,7 @@ if (mymob.client.gun_mode) // If in aim mode, correct the sprite mymob.gun_setting_icon.set_dir(2) for(var/obj/item/weapon/gun/G in mymob) // If targeting someone, display other buttons - if (G.target) + if (G.aim_targets) mymob.item_use_icon = new /obj/screen/gun/item(null) if (mymob.client.target_can_click) mymob.item_use_icon.set_dir(1) diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm index 644b8113765..2738cf3a7d6 100644 --- a/code/_onclick/hud/robot.dm +++ b/code/_onclick/hud/robot.dm @@ -157,7 +157,7 @@ var/obj/screen/robot_inventory if (mymob.client.gun_mode) // If in aim mode, correct the sprite mymob.gun_setting_icon.set_dir(2) for(var/obj/item/weapon/gun/G in mymob) // If targeting someone, display other buttons - if (G.target) + if (G.aim_targets) mymob.item_use_icon = new /obj/screen/gun/item(null) if (mymob.client.target_can_click) mymob.item_use_icon.set_dir(1) diff --git a/code/game/gamemodes/wizard/rightandwrong.dm b/code/game/gamemodes/wizard/rightandwrong.dm index d9f129a27e0..1e16da590b3 100644 --- a/code/game/gamemodes/wizard/rightandwrong.dm +++ b/code/game/gamemodes/wizard/rightandwrong.dm @@ -26,7 +26,7 @@ if("revolver") new /obj/item/weapon/gun/projectile(get_turf(H)) if("detective") - new /obj/item/weapon/gun/projectile/detective(get_turf(H)) + new /obj/item/weapon/gun/projectile/revolver/detective(get_turf(H)) if("smg") new /obj/item/weapon/gun/projectile/automatic/c20r(get_turf(H)) if("nuclear") diff --git a/code/game/machinery/bots/ed209bot.dm b/code/game/machinery/bots/ed209bot.dm index 24e29e28397..639da55bf5b 100644 --- a/code/game/machinery/bots/ed209bot.dm +++ b/code/game/machinery/bots/ed209bot.dm @@ -34,10 +34,10 @@ var/obj/item/weapon/gun/energy/taser/G = new /obj/item/weapon/gun/energy/taser(Tsec) G.power_supply.charge = 0 else if(lasercolor == "b") - var/obj/item/weapon/gun/energy/laser/bluetag/G = new /obj/item/weapon/gun/energy/laser/bluetag(Tsec) + var/obj/item/weapon/gun/energy/lasertag/blue/G = new (Tsec) G.power_supply.charge = 0 else if(lasercolor == "r") - var/obj/item/weapon/gun/energy/laser/redtag/G = new /obj/item/weapon/gun/energy/laser/redtag(Tsec) + var/obj/item/weapon/gun/energy/lasertag/red/G = new (Tsec) G.power_supply.charge = 0 if (prob(50)) new /obj/item/robot_parts/l_leg(Tsec) @@ -137,11 +137,11 @@ if(7) switch(lasercolor) if("b") - if( !istype(W, /obj/item/weapon/gun/energy/laser/bluetag) ) + if( !istype(W, /obj/item/weapon/gun/energy/lasertag/blue) ) return name = "bluetag ED-209 assembly" if("r") - if( !istype(W, /obj/item/weapon/gun/energy/laser/redtag) ) + if( !istype(W, /obj/item/weapon/gun/energy/lasertag/red) ) return name = "redtag ED-209 assembly" if("") diff --git a/code/game/machinery/bots/secbot.dm b/code/game/machinery/bots/secbot.dm index 1dcc02fbb91..6aa43c1b390 100644 --- a/code/game/machinery/bots/secbot.dm +++ b/code/game/machinery/bots/secbot.dm @@ -702,10 +702,10 @@ Auto Patrol: []"}, switch(lasercolor) if("b") target_suit = /obj/item/clothing/suit/redtag - target_weapon = /obj/item/weapon/gun/energy/laser/redtag + target_weapon = /obj/item/weapon/gun/energy/lasertag/red if("r") target_suit = /obj/item/clothing/suit/bluetag - target_weapon = /obj/item/weapon/gun/energy/laser/bluetag + target_weapon = /obj/item/weapon/gun/energy/lasertag/blue if((istype(perp.r_hand, target_weapon)) || (istype(perp.l_hand, target_weapon))) threat += 4 diff --git a/code/game/machinery/portable_tag_turret.dm b/code/game/machinery/portable_tag_turret.dm index 13f7032aa3a..c9c2331e6df 100644 --- a/code/game/machinery/portable_tag_turret.dm +++ b/code/game/machinery/portable_tag_turret.dm @@ -5,13 +5,13 @@ /obj/machinery/porta_turret/tag // Reasonable defaults, in case someone manually spawns us var/lasercolor = "r" //Something to do with lasertag turrets, blame Sieve for not adding a comment. - installation = /obj/item/weapon/gun/energy/laser/redtag + installation = /obj/item/weapon/gun/energy/lasertag/red /obj/machinery/porta_turret/tag/red /obj/machinery/porta_turret/tag/blue lasercolor = "b" - installation = /obj/item/weapon/gun/energy/laser/bluetag + installation = /obj/item/weapon/gun/energy/lasertag/blue /obj/machinery/porta_turret/tag/New() ..() @@ -19,8 +19,8 @@ /obj/machinery/porta_turret/tag/weapon_setup(var/obj/item/weapon/gun/energy/E) switch(E.type) - if(/obj/item/weapon/gun/energy/laser/bluetag) - eprojectile = /obj/item/weapon/gun/energy/laser/bluetag + if(/obj/item/weapon/gun/energy/lasertag/blue) + eprojectile = /obj/item/weapon/gun/energy/lasertag/blue lasercolor = "b" req_access = list(access_maint_tunnels, access_theatre) check_arrest = 0 @@ -30,8 +30,8 @@ check_anomalies = 0 shot_delay = 30 - if(/obj/item/weapon/gun/energy/laser/redtag) - eprojectile = /obj/item/weapon/gun/energy/laser/redtag + if(/obj/item/weapon/gun/energy/lasertag/red) + eprojectile = /obj/item/weapon/gun/energy/lasertag/red lasercolor = "r" req_access = list(access_maint_tunnels, access_theatre) check_arrest = 0 @@ -86,13 +86,13 @@ ..() if(lasercolor == "b" && disabled == 0) - if(istype(Proj, /obj/item/weapon/gun/energy/laser/redtag)) + if(istype(Proj, /obj/item/weapon/gun/energy/lasertag/red)) disabled = 1 del(Proj) // qdel sleep(100) disabled = 0 if(lasercolor == "r" && disabled == 0) - if(istype(Proj, /obj/item/weapon/gun/energy/laser/bluetag)) + if(istype(Proj, /obj/item/weapon/gun/energy/lasertag/blue)) disabled = 1 del(Proj) // qdel sleep(100) @@ -110,10 +110,10 @@ switch(lasercolor) if("b") target_suit = /obj/item/clothing/suit/redtag - target_weapon = /obj/item/weapon/gun/energy/laser/redtag + target_weapon = /obj/item/weapon/gun/energy/lasertag/red if("r") target_suit = /obj/item/clothing/suit/bluetag - target_weapon = /obj/item/weapon/gun/energy/laser/bluetag + target_weapon = /obj/item/weapon/gun/energy/lasertag/blue if(target_suit)//Lasertag turrets target the opposing team, how great is that? -Sieve diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index c531e53f963..a2dda1e4006 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -733,7 +733,7 @@ gun_charge = E.power_supply.charge //the gun's charge is stored in gun_charge user << "You add [I] to the turret." - if(istype(installation, /obj/item/weapon/gun/energy/laser/bluetag) || istype(installation, /obj/item/weapon/gun/energy/laser/redtag)) + if(istype(installation, /obj/item/weapon/gun/energy/lasertag/blue) || istype(installation, /obj/item/weapon/gun/energy/lasertag/red)) target_type = /obj/machinery/porta_turret/tag else target_type = /obj/machinery/porta_turret diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index f9d3e356ce6..9bc40c779d8 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -121,7 +121,7 @@ usr << "There's no mounting point for the module!" return 0 - var/obj/item/weapon/gun/energy/taser/cyborg/T = locate() in R.module + var/obj/item/weapon/gun/energy/taser/mounted/cyborg/T = locate() in R.module if(!T) T = locate() in R.module.contents if(!T) diff --git a/code/game/objects/structures/crates_lockers/closets/fitness.dm b/code/game/objects/structures/crates_lockers/closets/fitness.dm index 05e7968a931..b42fe3f9502 100644 --- a/code/game/objects/structures/crates_lockers/closets/fitness.dm +++ b/code/game/objects/structures/crates_lockers/closets/fitness.dm @@ -54,8 +54,8 @@ /obj/structure/closet/lasertag/red/New() ..() - new /obj/item/weapon/gun/energy/laser/redtag(src) - new /obj/item/weapon/gun/energy/laser/redtag(src) + new /obj/item/weapon/gun/energy/lasertag/red(src) + new /obj/item/weapon/gun/energy/lasertag/red(src) new /obj/item/clothing/suit/redtag(src) new /obj/item/clothing/suit/redtag(src) @@ -68,7 +68,7 @@ /obj/structure/closet/lasertag/blue/New() ..() - new /obj/item/weapon/gun/energy/laser/bluetag(src) - new /obj/item/weapon/gun/energy/laser/bluetag(src) + new /obj/item/weapon/gun/energy/lasertag/blue(src) + new /obj/item/weapon/gun/energy/lasertag/blue(src) new /obj/item/clothing/suit/bluetag(src) new /obj/item/clothing/suit/bluetag(src) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index f0a67bddee5..ccaf07516e5 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -261,7 +261,7 @@ new /obj/item/ammo_magazine/c45m/rubber(src) new /obj/item/ammo_magazine/c45m/rubber(src) new /obj/item/taperoll/police(src) - new /obj/item/weapon/gun/projectile/detective/semiauto(src) + new /obj/item/weapon/gun/projectile/detective(src) new /obj/item/clothing/accessory/holster/armpit(src) return diff --git a/code/modules/clothing/spacesuits/rig/modules/rig_weapons.dm b/code/modules/clothing/spacesuits/rig/modules/rig_weapons.dm deleted file mode 100644 index 792a6ed0d05..00000000000 --- a/code/modules/clothing/spacesuits/rig/modules/rig_weapons.dm +++ /dev/null @@ -1,51 +0,0 @@ -//Weapon types intended to be used with rig modules - -/obj/item/weapon/gun/energy/lasercannon/mounted/load_into_chamber() - if(in_chamber) - return 1 - var/obj/item/rig_module/module = loc - if(!istype(module)) - return 0 - if(module.holder && module.holder.wearer) - var/mob/living/carbon/human/H = module.holder.wearer - if(istype(H) && H.back) - var/obj/item/weapon/rig/suit = H.back - if(istype(suit) && suit.cell && suit.cell.charge >= 250) - suit.cell.use(250) - in_chamber = new /obj/item/projectile/beam/heavylaser(src) - return 1 - return 0 - -/obj/item/weapon/gun/energy/gun/mounted/load_into_chamber() - if(in_chamber) - return 1 - var/obj/item/rig_module/module = loc - if(!istype(module)) - return 0 - if(module.holder && module.holder.wearer) - var/mob/living/carbon/human/H = module.holder.wearer - if(istype(H) && H.back) - var/obj/item/weapon/rig/suit = H.back - if(istype(suit) && suit.cell && suit.cell.charge >= 250) - suit.cell.use(250) - var/prog_path = projectile_type - in_chamber = new prog_path(src) - return 1 - return 0 - -/obj/item/weapon/gun/energy/taser/mounted/load_into_chamber() - if(in_chamber) - return 1 - var/obj/item/rig_module/module = loc - if(!istype(module)) - return 0 - if(module.holder && module.holder.wearer) - var/mob/living/carbon/human/H = module.holder.wearer - if(istype(H) && H.back) - var/obj/item/weapon/rig/suit = H.back - if(istype(suit) && suit.cell && suit.cell.charge >= 250) - suit.cell.use(250) - var/prog_path = projectile_type - in_chamber = new prog_path(src) - return 1 - return 0 \ No newline at end of file diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 7549e9cbe5d..acc8443f90e 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -197,7 +197,7 @@ armor = list(melee = 60, bullet = 60, laser = 60, energy = 40, bomb = 20, bio = 0, rad = 0) siemens_coefficient = 0.7 var/obj/item/clothing/accessory/holster/holster - + /obj/item/clothing/suit/armor/tactical/New() ..() holster = new(src) @@ -220,7 +220,7 @@ return holster.holster(W, usr) else - holster.unholster(usr) + holster.unholster(usr) //Non-hardsuit ERT armor. /obj/item/clothing/suit/armor/vest/ert diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index 09e67ea871b..bcca81141c6 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -15,7 +15,7 @@ item_state = "bluetag" blood_overlay_type = "armor" body_parts_covered = UPPER_TORSO - allowed = list (/obj/item/weapon/gun/energy/laser/bluetag) + allowed = list (/obj/item/weapon/gun/energy/lasertag/blue) siemens_coefficient = 3.0 /obj/item/clothing/suit/redtag @@ -25,7 +25,7 @@ item_state = "redtag" blood_overlay_type = "armor" body_parts_covered = UPPER_TORSO - allowed = list (/obj/item/weapon/gun/energy/laser/redtag) + allowed = list (/obj/item/weapon/gun/energy/lasertag/red) siemens_coefficient = 3.0 /* diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm index 11a3fa03d48..95593385a00 100644 --- a/code/modules/customitems/item_defines.dm +++ b/code/modules/customitems/item_defines.dm @@ -1340,22 +1340,21 @@ desc = "A stun baton used for incapacitating targets; there seems to be a bunch of tally marks set into the handle." ///// Deckard .44 - Callum Leamas - Roaper -/obj/item/weapon/gun/projectile/detective/fluff/callum_leamas +/obj/item/weapon/gun/projectile/revolver/detective/fluff/callum_leamas name = "Deckard .44" desc = "A custom built revolver, based off the semi-popular Detective Special model." icon = 'icons/obj/custom_items.dmi' icon_state = "leamas-empty" + ammo_type = /obj/item/ammo_magazine/c38/rubber -/obj/item/weapon/gun/projectile/detective/fluff/callum_leamas/update_icon() - +/obj/item/weapon/gun/projectile/revolver/detective/fluff/callum_leamas/update_icon() ..() if(loaded.len) icon_state = "leamas-loaded" else icon_state = "leamas-empty" -/obj/item/weapon/gun/projectile/attackby(var/obj/item/A as obj, mob/user as mob) - +/obj/item/weapon/gun/projectile/revolver/detective/fluff/callum_leamas/load_ammo(var/obj/item/A, mob/user) if(istype(A, /obj/item/ammo_magazine)) flick("leamas-reloading",src) ..() diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 3458a5bb47f..9f213ad7e53 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -223,9 +223,9 @@ src.modules += new /obj/item/borg/sight/hud/sec(src) src.modules += new /obj/item/weapon/handcuffs/cyborg(src) src.modules += new /obj/item/weapon/melee/baton/robot(src) - src.modules += new /obj/item/weapon/gun/energy/taser/cyborg(src) + src.modules += new /obj/item/weapon/gun/energy/taser/mounted/cyborg(src) src.modules += new /obj/item/taperoll/police(src) - src.emag = new /obj/item/weapon/gun/energy/laser/cyborg(src) + src.emag = new /obj/item/weapon/gun/energy/laser/mounted(src) return /obj/item/weapon/robot_module/security/respawn_consumable(var/mob/living/silicon/robot/R) @@ -236,7 +236,7 @@ F.icon_state = "flash" else if(F.times_used) F.times_used-- - var/obj/item/weapon/gun/energy/taser/cyborg/T = locate() in src.modules + var/obj/item/weapon/gun/energy/taser/mounted/cyborg/T = locate() in src.modules if(T.power_supply.charge < T.power_supply.maxcharge) T.power_supply.give(T.charge_cost) T.update_icon() @@ -383,11 +383,11 @@ ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/borg/sight/thermal(src) - src.modules += new /obj/item/weapon/gun/energy/laser/cyborg(src) + src.modules += new /obj/item/weapon/gun/energy/laser/mounted(src) src.modules += new /obj/item/weapon/pickaxe/plasmacutter(src) src.modules += new /obj/item/borg/combat/shield(src) src.modules += new /obj/item/borg/combat/mobility(src) - src.emag = new /obj/item/weapon/gun/energy/lasercannon/cyborg(src) + src.emag = new /obj/item/weapon/gun/energy/lasercannon/mounted(src) return /obj/item/weapon/robot_module/drone diff --git a/code/modules/mob/living/silicon/robot/robot_upgrades.dm b/code/modules/mob/living/silicon/robot/robot_upgrades.dm index 71f22a3029f..a6d08bd5348 100644 --- a/code/modules/mob/living/silicon/robot/robot_upgrades.dm +++ b/code/modules/mob/living/silicon/robot/robot_upgrades.dm @@ -108,7 +108,7 @@ usr << "There's no mounting point for the module!" return 0 - var/obj/item/weapon/gun/energy/taser/cyborg/T = locate() in R.module + var/obj/item/weapon/gun/energy/taser/mounted/cyborg/T = locate() in R.module if(!T) T = locate() in R.module.contents if(!T) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index c744e1940f3..eeeb60692be 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -1,3 +1,4 @@ +//Parent gun type. Guns are weapons that can be aimed at mobs and act over a distance /obj/item/weapon/gun name = "gun" desc = "Its a gun. It's pretty terrible, though." @@ -7,32 +8,32 @@ flags = CONDUCT slot_flags = SLOT_BELT|SLOT_HOLSTER matter = list("metal" = 2000) - w_class = 3.0 + w_class = 3 throwforce = 5 throw_speed = 4 throw_range = 5 - force = 5.0 + force = 5 origin_tech = "combat=1" attack_verb = list("struck", "hit", "bashed") - var/fire_sound = 'sound/weapons/Gunshot.ogg' - var/obj/item/projectile/in_chamber = null - var/caliber = "" - var/silenced = 0 - var/recoil = 0 - var/ejectshell = 1 - var/clumsy_check = 1 - var/tmp/list/mob/living/target //List of who yer targeting. - var/tmp/lock_time = -100 - var/tmp/mouthshoot = 0 ///To stop people from suiciding twice... >.> - var/automatic = 0 //Used to determine if you can target multiple people. - var/tmp/mob/living/last_moved_mob //Used to fire faster at more than one person. - var/tmp/told_cant_shoot = 0 //So that it doesn't spam them with the fact they cannot hit them. - var/firerate = 0 //0 for keep shooting until aim is lowered - // 1 for one bullet after tarrget moves and aim is lowered var/fire_delay = 6 + var/fire_sound = 'sound/weapons/Gunshot.ogg' + var/fire_sound_text = "gunshot" + var/recoil = 0 //screen shake + var/silenced = 0 + var/last_fired = 0 + //aiming system stuff + var/keep_aim = 1 //1 for keep shooting until aim is lowered + //0 for one bullet after tarrget moves and aim is lowered + var/multi_aim = 0 //Used to determine if you can target multiple people. + var/tmp/list/mob/living/aim_targets //List of who yer targeting. + var/tmp/mob/living/last_moved_mob //Used to fire faster at more than one person. + var/tmp/told_cant_shoot = 0 //So that it doesn't spam them with the fact they cannot hit them. + var/tmp/lock_time = -100 + +//Returns 1 if the gun is able to be fired /obj/item/weapon/gun/proc/ready_to_fire() if(world.time >= last_fired + fire_delay) last_fired = world.time @@ -40,24 +41,41 @@ else return 0 -/obj/item/weapon/gun/proc/load_into_chamber() - return 0 - -/obj/item/weapon/gun/proc/special_check(var/mob/M) //Placeholder for any special checks, like detective's revolver. - return 1 +//Checks whether a given mob can use the gun +/obj/item/weapon/gun/proc/special_check(var/mob/user) + if(!istype(user, /mob/living)) + return 0 + if(!user.IsAdvancedToolUser()) + return 0 + + var/mob/living/M = user + + if(HULK in M.mutations) + M << "Your fingers are much too large for the trigger guard!" + return 0 + if((CLUMSY in M.mutations) && prob(40) && can_fire()) //Clumsy handling + var/obj/in_chamber = get_next_projectile() + if(in_chamber) + if(process_projectile(in_chamber, user, user, pick("l_foot", "r_foot"))) + handle_post_fire(user, user) + user.visible_message( + "[user] shoots \himself in the foot with \the [src]!", + "You shoot yourself in the foot with \the [src]!" + ) + M.drop_item() + return 0 + return 1 /obj/item/weapon/gun/emp_act(severity) for(var/obj/O in contents) O.emp_act(severity) -/obj/item/weapon/gun/afterattack(atom/A as mob|obj|turf|area, mob/living/user as mob|obj, flag, params) - if(flag) return //It's adjacent, is the user, or is on the user's person - if(istype(target, /obj/machinery/recharger) && istype(src, /obj/item/weapon/gun/energy)) return//Shouldnt flag take care of this? - +/obj/item/weapon/gun/afterattack(atom/A, mob/living/user, adjacent, params) + if(adjacent) return //A is adjacent, is the user, or is on the user's person //decide whether to aim or shoot normally var/aiming = 0 - if(user && user.client && !(A in target)) + if(user && user.client && !(A in aim_targets)) var/client/C = user.client //If help intent is on and we have clicked on an eligible target, switch to aim mode automatically if(user.a_intent == "help" && isliving(A) && !C.gun_mode) @@ -72,27 +90,16 @@ else Fire(A,user,params) //Otherwise, fire normally. -/obj/item/weapon/gun/proc/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)//TODO: go over this - //Exclude lasertag guns from the CLUMSY check. - if(!user) return +/obj/item/weapon/gun/attack(atom/A, mob/living/user, def_zone) + if (A == user && user.zone_sel.selecting == "mouth" && !mouthshoot) + handle_suicide(user) + else if(user.a_intent == "hurt") //point blank shooting + Fire(A, user, pointblank=1) + else + return ..() //Pistolwhippin' - if(clumsy_check) - if(istype(user, /mob/living)) - var/mob/living/M = user - if ((CLUMSY in M.mutations) && prob(50)) - M << "[src] blows up in your face." - M.take_organ_damage(0,20) - M.drop_item() - del(src) - return - - if (!user.IsAdvancedToolUser()) - return - if(istype(user, /mob/living)) - var/mob/living/M = user - if (HULK in M.mutations) - M << "Your fingers are much too large for the trigger guard!" - return +/obj/item/weapon/gun/proc/Fire(atom/target, mob/living/user, params, pointblank=0, reflex=0) + if(!user || !target) return add_fingerprint(user) @@ -104,22 +111,70 @@ user << "[src] is not ready to fire again!" return - if(!load_into_chamber()) //CHECK - return click_empty(user) - + var/obj/in_chamber = get_next_projectile() if(!in_chamber) + handle_click_empty(user) return + user.next_move = world.time + 4 + + if(process_projectile(in_chamber, user, target, user.zone_sel.selecting, params, pointblank, reflex)) + handle_post_fire(user, target, pointblank, reflex) + + update_icon() + if(user.hand) + user.update_inv_l_hand() + else + user.update_inv_r_hand() + + +//returns the next projectile to fire +/obj/item/weapon/gun/proc/get_next_projectile() + return null + +//TODO integrate this with gun code better. +//TODO maybe provide user so that subtypes can emit messages if they want? +/obj/item/weapon/gun/proc/can_fire() + return 0 + +//used by aiming code +/obj/item/weapon/gun/proc/can_hit(atom/target as mob, var/mob/living/user as mob) + if(!special_check(user)) + return 2 + return 0 //in_chamber.check_fire(target,user) + +//called if there was no projectile to shoot +/obj/item/weapon/gun/proc/handle_click_empty(mob/user) + if (user) + user.visible_message("*click click*", "*click*") + else + src.visible_message("*click click*") + playsound(src.loc, 'sound/weapons/empty.ogg', 100, 1) + +//called after successfully firing +/obj/item/weapon/gun/proc/handle_post_fire(mob/user, atom/target, var/pointblank=0, var/reflex=0) if(silenced) playsound(user, fire_sound, 10, 1) else playsound(user, fire_sound, 50, 1) - user.visible_message("[user] fires [src][reflex ? " by reflex":""]!", \ - "You fire [src][reflex ? "by reflex":""]!", \ - "You hear a [istype(in_chamber, /obj/item/projectile/beam) ? "laser blast" : "gunshot"]!") - - user.next_move = world.time + 4 + user.visible_message( + "[user] fires [src][pointblank ? " point blank at [target]":""][reflex ? " by reflex":""]!", + "You fire [src][reflex ? "by reflex":""]!", + "You hear a [fire_sound_text]!" + ) + + if(recoil) + spawn() + shake_camera(user, recoil + 1, recoil) +//does the actual shooting +/obj/item/weapon/gun/proc/process_projectile(obj/projectile, mob/user, atom/target, var/target_zone, var/params=null, var/pointblank=0, var/reflex=0) + if(!istype(projectile, /obj/item/projectile)) + return 0 //default behaviour only applies to true projectiles + + var/obj/item/projectile/P = projectile + + //shooting while in shock var/x_offset = 0 var/y_offset = 0 if(istype(user, /mob/living/carbon)) @@ -131,93 +186,52 @@ y_offset = rand(-1,1) x_offset = rand(-1,1) - if(in_chamber) - if(params) - in_chamber.set_clickpoint(params) + //Point blank bonus + if(pointblank) P.damage *= 1.3 - var/fail = in_chamber.launch( - target = target, - user = user, - launcher = src, - target_zone = user.zone_sel.selecting, - x_offset = x_offset, - y_offset = y_offset - ) + //TODO: accuracy modifiers - if(fail) return + if(params) + P.set_clickpoint(params) - if(recoil) - spawn() - shake_camera(user, recoil + 1, recoil) + return !P.launch(target, user, src, target_zone, x_offset, y_offset) - sleep(1) - in_chamber = null - - update_icon() - - if(user.hand) - user.update_inv_l_hand() - else - user.update_inv_r_hand() - -/obj/item/weapon/gun/proc/can_fire() - return load_into_chamber() - -/obj/item/weapon/gun/proc/can_hit(var/mob/living/target as mob, var/mob/living/user as mob) - return in_chamber.check_fire(target,user) - -/obj/item/weapon/gun/proc/click_empty(mob/user = null) - if (user) - user.visible_message("*click click*", "\red *click*") - playsound(user, 'sound/weapons/empty.ogg', 100, 1) - else - src.visible_message("*click click*") - playsound(src.loc, 'sound/weapons/empty.ogg', 100, 1) - -/obj/item/weapon/gun/attack(mob/living/M as mob, mob/living/user as mob, def_zone) - //Suicide handling. - if (M == user && user.zone_sel.selecting == "mouth" && !mouthshoot) - mouthshoot = 1 - M.visible_message("\red [user] sticks their gun in their mouth, ready to pull the trigger...") - if(!do_after(user, 40)) - M.visible_message("\blue [user] decided life was worth living") - mouthshoot = 0 - return - if (load_into_chamber()) - user.visible_message("[user] pulls the trigger.") - if(silenced) - playsound(user, fire_sound, 10, 1) - else - playsound(user, fire_sound, 50, 1) - if(istype(in_chamber, /obj/item/projectile/beam/lastertag)) - user.show_message("You feel rather silly, trying to commit suicide with a toy.") - mouthshoot = 0 - return - - in_chamber.on_hit(M) - if (in_chamber.damage_type != HALLOSS) - user.apply_damage(in_chamber.damage*2.5, in_chamber.damage_type, "head", used_weapon = "Point blank shot in the mouth with \a [in_chamber]", sharp=1) - user.death() - else - user << "Ow..." - user.apply_effect(110,AGONY,0) - del(in_chamber) - mouthshoot = 0 - return +//Suicide handling. +/obj/item/weapon/gun/var/mouthshoot = 0 //To stop people from suiciding twice... >.> +/obj/item/weapon/gun/proc/handle_suicide(mob/living/user) + if(!ishuman(user)) + return + var/mob/living/carbon/human/M = user + + mouthshoot = 1 + M.visible_message("\red [user] sticks their gun in their mouth, ready to pull the trigger...") + if(!do_after(user, 40)) + M.visible_message("\blue [user] decided life was worth living") + mouthshoot = 0 + return + var/obj/item/projectile/in_chamber = get_next_projectile() + if (istype(in_chamber)) + user.visible_message("[user] pulls the trigger.") + if(silenced) + playsound(user, fire_sound, 10, 1) else - click_empty(user) + playsound(user, fire_sound, 50, 1) + if(istype(in_chamber, /obj/item/projectile/beam/lastertag)) + user.show_message("You feel rather silly, trying to commit suicide with a toy.") mouthshoot = 0 return - if (load_into_chamber()) - //Point blank shooting if on harm intent or target we were targeting. - if(user.a_intent == "hurt") - user.visible_message("\red \The [user] fires \the [src] point blank at [M]!") - if(istype(in_chamber)) in_chamber.damage *= 1.3 - Fire(M,user) - return - else if(target && M in target) - Fire(M,user) ///Otherwise, shoot! - return + in_chamber.on_hit(M) + if (in_chamber.damage_type != HALLOSS) + user.apply_damage(in_chamber.damage*2.5, in_chamber.damage_type, "head", used_weapon = "Point blank shot in the mouth with \a [in_chamber]", sharp=1) + user.death() + else + user << "Ow..." + user.apply_effect(110,AGONY,0) + del(in_chamber) + mouthshoot = 0 + return else - return ..() //Pistolwhippin' + handle_click_empty(user) + mouthshoot = 0 + return diff --git a/code/modules/projectiles/guns/alien.dm b/code/modules/projectiles/guns/alien.dm index f9af71acc85..c7efc4e3b6c 100644 --- a/code/modules/projectiles/guns/alien.dm +++ b/code/modules/projectiles/guns/alien.dm @@ -24,7 +24,6 @@ ..() /obj/item/weapon/gun/launcher/spikethrower/process() - if(spikes < max_spikes && world.time > last_regen + spike_gen_time) spikes++ last_regen = world.time @@ -32,7 +31,7 @@ /obj/item/weapon/gun/launcher/spikethrower/examine(mob/user) ..(user) - user << "It has [spikes] [spikes == 1 ? "spike" : "spikes"] remaining." + user << "It has [spikes] spike\s remaining." /obj/item/weapon/gun/launcher/spikethrower/update_icon() icon_state = "spikethrower[spikes]" @@ -46,21 +45,18 @@ if(H.species && H.species.name != "Vox" && H.species.name != "Vox Armalis") user << "\red \The [src] does not respond to you!" return 0 - return 1 + return ..() /obj/item/weapon/gun/launcher/spikethrower/update_release_force() return -/obj/item/weapon/gun/launcher/spikethrower/load_into_chamber() - if(in_chamber) return 1 - if(spikes < 1) return 0 +/obj/item/weapon/gun/launcher/spikethrower/can_fire() + return (spikes >= 1) +/obj/item/weapon/gun/launcher/spikethrower/get_next_projectile() + if(spikes < 1) return null spikes-- - in_chamber = new /obj/item/weapon/spike(src) - return 1 - -/obj/item/weapon/gun/launcher/spikethrower/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0) - if(..()) update_icon() + return new /obj/item/weapon/spike(src) //This gun only functions for armalis. The on-sprite is too huge to render properly on other sprites. /obj/item/weapon/gun/energy/noisecannon @@ -74,7 +70,7 @@ force = 10 projectile_type = /obj/item/projectile/energy/sonic - cell_type = "/obj/item/weapon/cell/super" + cell_type = /obj/item/weapon/cell/super fire_delay = 40 fire_sound = 'sound/effects/basscannon.ogg' @@ -94,10 +90,6 @@ user << "\red \The [src] is far too large for you to pick up." return -/obj/item/weapon/gun/energy/noisecannon/load_into_chamber() //Does not have ammo. - in_chamber = new projectile_type(src) - return 1 - /obj/item/weapon/gun/energy/noisecannon/update_icon() return diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 0ed82e9f4a4..e8997ea24fe 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -3,39 +3,79 @@ desc = "A basic energy-based gun." icon_state = "energy" fire_sound = 'sound/weapons/Taser.ogg' + fire_sound_text = "laser blast" var/obj/item/weapon/cell/power_supply //What type of power cell this uses var/charge_cost = 100 //How much energy is needed to fire. - var/cell_type = "/obj/item/weapon/cell" + var/cell_type = /obj/item/weapon/cell var/projectile_type = /obj/item/projectile/beam/practice var/modifystate + var/charge_meter = 1 //if set, the icon state will be chosen based on the current charge + + //self-recharging + var/self_recharge = 0 //if set, the weapon will recharge itself + var/use_external_power = 0 //if set, the weapon will look for an external power source to draw from, otherwise it recharges magically + var/recharge_time = 4 + var/charge_tick = 0 - emp_act(severity) - power_supply.use(round(power_supply.maxcharge / severity)) - update_icon() - ..() - - - New() - ..() - if(cell_type) - power_supply = new cell_type(src) - else - power_supply = new(src) - power_supply.give(power_supply.maxcharge) - return - - - load_into_chamber() - if(in_chamber) return 1 - if(!power_supply) return 0 - if(!power_supply.use(charge_cost)) return 0 - if(!ispath(projectile_type)) return 0 - in_chamber = new projectile_type(src) - return 1 - - +/obj/item/weapon/gun/energy/emp_act(severity) + power_supply.use(round(power_supply.maxcharge / severity)) update_icon() + ..() + +/obj/item/weapon/gun/energy/New() + ..() + if(cell_type) + power_supply = new cell_type(src) + power_supply.give(power_supply.maxcharge) + if(self_recharge) + processing_objects.Add(src) + +/obj/item/weapon/gun/energy/Del() + if(self_recharge) + processing_objects.Remove(src) + ..() + +/obj/item/weapon/gun/energy/process() + if(self_recharge) //Every [recharge_time] ticks, recharge a shot for the cyborg + charge_tick++ + if(charge_tick < recharge_time) return 0 + charge_tick = 0 + + if(!power_supply || power_supply.charge >= power_supply.maxcharge) + return 0 // check if we actually need to recharge + + if(use_external_power) + var/obj/item/weapon/cell/external = get_external_power_supply() + if(!external || !external.use(charge_cost)) //Take power from the borg... + return 0 + + power_supply.give(charge_cost) //... to recharge the shot + update_icon() + return 1 + +/obj/item/weapon/gun/energy/get_next_projectile() + if(!power_supply) return null + if(!ispath(projectile_type)) return null + if(!power_supply.use(charge_cost)) return null + return new projectile_type(src) + +/obj/item/weapon/gun/energy/proc/get_external_power_supply() + if(isrobot(src.loc)) + var/mob/living/silicon/robot/R = src.loc + return R.cell + if(istype(src.loc, /obj/item/rig_module)) + var/obj/item/rig_module/module = src.loc + if(module.holder && module.holder.wearer) + var/mob/living/carbon/human/H = module.holder.wearer + if(istype(H) && H.back) + var/obj/item/weapon/rig/suit = H.back + if(istype(suit)) + return suit.cell + return null + +/obj/item/weapon/gun/energy/update_icon() + if(charge_meter) var/ratio = power_supply.charge / power_supply.maxcharge ratio = round(ratio, 0.25) * 100 if(modifystate) diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index 24a3bb1541a..f24bd99ff22 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -5,88 +5,52 @@ item_state = "laser" fire_sound = 'sound/weapons/Laser.ogg' slot_flags = SLOT_BELT|SLOT_BACK - w_class = 3.0 + w_class = 3 force = 10 //it has a stock, might as well give some kind of perk over the egun matter = list("metal" = 2000) origin_tech = "combat=3;magnets=2" projectile_type = /obj/item/projectile/beam +/obj/item/weapon/gun/energy/laser/mounted + self_recharge = 1 + use_external_power = 1 + /obj/item/weapon/gun/energy/laser/practice name = "practice laser gun" desc = "A modified version of the basic laser gun, this one fires less concentrated energy bolts designed for target practice." projectile_type = /obj/item/projectile/beam/practice - clumsy_check = 0 obj/item/weapon/gun/energy/laser/retro name = "retro laser" icon_state = "retro" desc = "An older model of the basic lasergun, no longer used by Nanotrasen's security or military forces. Nevertheless, it is still quite deadly and easy to maintain, making it a favorite amongst pirates and other outlaws." - -/obj/item/weapon/gun/energy/laser/captain +/obj/item/weapon/gun/energy/captain name = "antique laser gun" icon_state = "caplaser" desc = "This is an antique laser gun. All craftsmanship is of the highest quality. It is decorated with assistant leather and chrome. The object menaces with spikes of energy. On the item is an image of Space Station 13. The station is exploding." - force = 10 + force = 5 + slot_flags = SLOT_BELT origin_tech = null - var/charge_tick = 0 - - - New() - ..() - processing_objects.Add(src) - - - Del() - processing_objects.Remove(src) - ..() - - - process() - charge_tick++ - if(charge_tick < 4) return 0 - charge_tick = 0 - if(!power_supply) return 0 - power_supply.give(100) - update_icon() - return 1 - - - -/obj/item/weapon/gun/energy/laser/cyborg/load_into_chamber() - if(in_chamber) - return 1 - if(isrobot(src.loc)) - var/mob/living/silicon/robot/R = src.loc - if(R && R.cell) - R.cell.use(100) - in_chamber = new/obj/item/projectile/beam(src) - return 1 - return 0 - + self_recharge = 1 /obj/item/weapon/gun/energy/lasercannon name = "laser cannon" - desc = "With the L.A.S.E.R. cannon, the lasing medium is enclosed in a tube lined with uranium-235 and subjected to high neutron flux in a nuclear reactor core. This incredible technology may help YOU achieve high excitation rates with small laser volumes!" + desc = "With the laser cannon, the lasing medium is enclosed in a tube lined with uranium-235 and subjected to high neutron flux in a nuclear reactor core. This incredible technology may help YOU achieve high excitation rates with small laser volumes!" icon_state = "lasercannon" + item_state = "laser" fire_sound = 'sound/weapons/lasercannonfire.ogg' origin_tech = "combat=4;materials=3;powerstorage=3" - slot_flags = SLOT_BELT|SLOT_BACK - projectile_type = "/obj/item/projectile/beam/heavylaser" - + slot_flags = SLOT_BELT|SLOT_BACK + projectile_type = /obj/item/projectile/beam/heavylaser + charge_cost = 250 fire_delay = 20 -/obj/item/weapon/gun/energy/lasercannon/cyborg/load_into_chamber() - if(in_chamber) - return 1 - if(isrobot(src.loc)) - var/mob/living/silicon/robot/R = src.loc - if(R && R.cell) - R.cell.use(250) - in_chamber = new/obj/item/projectile/beam/heavylaser(src) - return 1 - return 0 +/obj/item/weapon/gun/energy/lasercannon/mounted + self_recharge = 1 + use_external_power = 1 + recharge_time = 25 /obj/item/weapon/gun/energy/xray name = "xray laser gun" @@ -94,82 +58,57 @@ obj/item/weapon/gun/energy/laser/retro icon_state = "xray" fire_sound = 'sound/weapons/laser3.ogg' origin_tech = "combat=5;materials=3;magnets=2;syndicate=2" - projectile_type = "/obj/item/projectile/beam/xray" + projectile_type = /obj/item/projectile/beam/xray charge_cost = 50 +/obj/item/weapon/gun/energy/sniperrifle + name = "\improper L.W.A.P. sniper rifle" + desc = "A high-power laser rifle fitted with a SMART aiming-system scope." + icon_state = "sniper" + item_state = "laser" + fire_sound = 'sound/weapons/marauder.ogg' + origin_tech = "combat=6;materials=5;powerstorage=4" + projectile_type = /obj/item/projectile/beam/sniper + slot_flags = SLOT_BACK + charge_cost = 250 + fire_delay = 35 + force = 10 + w_class = 4 + zoomdevicename = "scope" + +/obj/item/weapon/gun/energy/sniperrifle/verb/scope() + set category = "Object" + set name = "Use Scope" + set popup_menu = 1 + + zoom() ////////Laser Tag//////////////////// -/obj/item/weapon/gun/energy/laser/bluetag +/obj/item/weapon/gun/energy/lasertag name = "laser tag gun" + item_state = "laser" + desc = "Standard issue weapon of the Imperial Guard" + origin_tech = "combat=1;magnets=2" + self_recharge = 1 + matter = list("metal" = 2000) + fire_sound = 'sound/weapons/Laser.ogg' + projectile_type = /obj/item/projectile/beam/lastertag/blue + var/required_vest + +/obj/item/weapon/gun/energy/lasertag/special_check(var/mob/living/carbon/human/M) + if(ishuman(M)) + if(!istype(M.wear_suit, required_vest)) + M << "\red You need to be wearing your laser tag vest!" + return 0 + return ..() + +/obj/item/weapon/gun/energy/lasertag/blue icon_state = "bluetag" - desc = "Standard issue weapon of the Imperial Guard" - projectile_type = "/obj/item/projectile/beam/lastertag/blue" - origin_tech = "combat=1;magnets=2" - slot_flags = SLOT_BELT|SLOT_HOLSTER - clumsy_check = 0 - var/charge_tick = 0 + projectile_type = /obj/item/projectile/beam/lastertag/blue + required_vest = /obj/item/clothing/suit/bluetag - special_check(var/mob/living/carbon/human/M) - if(ishuman(M)) - if(istype(M.wear_suit, /obj/item/clothing/suit/bluetag)) - return 1 - M << "\red You need to be wearing your laser tag vest!" - return 0 - - New() - ..() - processing_objects.Add(src) - - - Del() - processing_objects.Remove(src) - ..() - - - process() - charge_tick++ - if(charge_tick < 4) return 0 - charge_tick = 0 - if(!power_supply) return 0 - power_supply.give(100) - update_icon() - return 1 - - - -/obj/item/weapon/gun/energy/laser/redtag - name = "laser tag gun" +/obj/item/weapon/gun/energy/lasertag/red icon_state = "redtag" - desc = "Standard issue weapon of the Imperial Guard" - projectile_type = "/obj/item/projectile/beam/lastertag/red" - origin_tech = "combat=1;magnets=2" - slot_flags = SLOT_BELT|SLOT_HOLSTER - clumsy_check = 0 - var/charge_tick = 0 - - special_check(var/mob/living/carbon/human/M) - if(ishuman(M)) - if(istype(M.wear_suit, /obj/item/clothing/suit/redtag)) - return 1 - M << "\red You need to be wearing your laser tag vest!" - return 0 - - New() - ..() - processing_objects.Add(src) - - - Del() - processing_objects.Remove(src) - ..() - - - process() - charge_tick++ - if(charge_tick < 4) return 0 - charge_tick = 0 - if(!power_supply) return 0 - power_supply.give(100) - update_icon() - return 1 + projectile_type = /obj/item/projectile/beam/lastertag/red + required_vest = /obj/item/clothing/suit/redtag diff --git a/code/modules/projectiles/guns/energy/nuclear.dm b/code/modules/projectiles/guns/energy/nuclear.dm index 8047a947841..80426a9bd5d 100644 --- a/code/modules/projectiles/guns/energy/nuclear.dm +++ b/code/modules/projectiles/guns/energy/nuclear.dm @@ -1,6 +1,6 @@ /obj/item/weapon/gun/energy/gun name = "energy gun" - desc = "A basic energy-based gun with two settings: Stun and kill." + desc = "An energy-based gun with two settings: Stun and kill." icon_state = "energystun100" item_state = null //so the human update icon uses the icon_state instead. fire_sound = 'sound/weapons/Taser.ogg' @@ -12,120 +12,108 @@ var/mode = 0 //0 = stun, 1 = kill +/obj/item/weapon/gun/energy/gun/attack_self(mob/living/user as mob) + switch(mode) + if(0) + mode = 1 + charge_cost = 100 + fire_sound = 'sound/weapons/Laser.ogg' + user << "\red [src.name] is now set to kill." + projectile_type = /obj/item/projectile/beam + modifystate = "energykill" + if(1) + mode = 0 + charge_cost = 100 + fire_sound = 'sound/weapons/Taser.ogg' + user << "\red [src.name] is now set to stun." + projectile_type = /obj/item/projectile/beam/stun + modifystate = "energystun" + update_icon() + if(user.l_hand == src) + user.update_inv_l_hand() + else + user.update_inv_r_hand() - attack_self(mob/living/user as mob) - switch(mode) - if(0) - mode = 1 - charge_cost = 100 - fire_sound = 'sound/weapons/Laser.ogg' - user << "\red [src.name] is now set to kill." - projectile_type = /obj/item/projectile/beam - modifystate = "energykill" - if(1) - mode = 0 - charge_cost = 100 - fire_sound = 'sound/weapons/Taser.ogg' - user << "\red [src.name] is now set to stun." - projectile_type = /obj/item/projectile/beam/stun - modifystate = "energystun" - update_icon() - if(user.l_hand == src) - user.update_inv_l_hand() - else - user.update_inv_r_hand() +/obj/item/weapon/gun/energy/gun/mounted + self_recharge = 1 + use_external_power = 1 /obj/item/weapon/gun/energy/gun/nuclear name = "advanced energy gun" desc = "An energy gun with an experimental miniaturized reactor." icon_state = "nucgun" - origin_tech = "combat=3;materials=5;powerstorage=3" + origin_tech = "combat=3;materials=5;powerstorage=3" slot_flags = SLOT_BELT - force = 8 + force = 8 //looks heavier than a pistol + self_recharge = 1 var/lightfail = 0 - var/charge_tick = 0 - New() - ..() - processing_objects.Add(src) +//override for failcheck behaviour +/obj/item/weapon/gun/energy/gun/nuclear/process() + charge_tick++ + if(charge_tick < 4) return 0 + charge_tick = 0 + if(!power_supply) return 0 + if((power_supply.charge / power_supply.maxcharge) != 1) + if(!failcheck()) return 0 + power_supply.give(charge_cost) + update_icon() + return 1 - - Del() +/obj/item/weapon/gun/energy/gun/nuclear/proc/failcheck() + lightfail = 0 + if (prob(src.reliability)) return 1 //No failure + if (prob(src.reliability)) + for (var/mob/living/M in range(0,src)) //Only a minor failure, enjoy your radiation if you're in the same tile or carrying it + if (src in M.contents) + M << "\red Your gun feels pleasantly warm for a moment." + else + M << "\red You feel a warm sensation." + M.apply_effect(rand(3,120), IRRADIATE) + lightfail = 1 + else + for (var/mob/living/M in range(rand(1,4),src)) //Big failure, TIME FOR RADIATION BITCHES + if (src in M.contents) + M << "\red Your gun's reactor overloads!" + M << "\red You feel a wave of heat wash over you." + M.apply_effect(300, IRRADIATE) + crit_fail = 1 //break the gun so it stops recharging processing_objects.Remove(src) - ..() + update_icon() + return 0 - process() - charge_tick++ - if(charge_tick < 4) return 0 - charge_tick = 0 - if(!power_supply) return 0 - if((power_supply.charge / power_supply.maxcharge) != 1) - if(!failcheck()) return 0 - power_supply.give(100) - update_icon() - return 1 +/obj/item/weapon/gun/energy/gun/nuclear/proc/update_charge() + if (crit_fail) + overlays += "nucgun-whee" + return + var/ratio = power_supply.charge / power_supply.maxcharge + ratio = round(ratio, 0.25) * 100 + overlays += "nucgun-[ratio]" +/obj/item/weapon/gun/energy/gun/nuclear/proc/update_reactor() + if(crit_fail) + overlays += "nucgun-crit" + return + if(lightfail) + overlays += "nucgun-medium" + else if ((power_supply.charge/power_supply.maxcharge) <= 0.5) + overlays += "nucgun-light" + else + overlays += "nucgun-clean" - proc - failcheck() - lightfail = 0 - if (prob(src.reliability)) return 1 //No failure - if (prob(src.reliability)) - for (var/mob/living/M in range(0,src)) //Only a minor failure, enjoy your radiation if you're in the same tile or carrying it - if (src in M.contents) - M << "\red Your gun feels pleasantly warm for a moment." - else - M << "\red You feel a warm sensation." - M.apply_effect(rand(3,120), IRRADIATE) - lightfail = 1 - else - for (var/mob/living/M in range(rand(1,4),src)) //Big failure, TIME FOR RADIATION BITCHES - if (src in M.contents) - M << "\red Your gun's reactor overloads!" - M << "\red You feel a wave of heat wash over you." - M.apply_effect(300, IRRADIATE) - crit_fail = 1 //break the gun so it stops recharging - processing_objects.Remove(src) - update_icon() - return 0 +/obj/item/weapon/gun/energy/gun/nuclear/proc/update_mode() + if (mode == 0) + overlays += "nucgun-stun" + else if (mode == 1) + overlays += "nucgun-kill" +/obj/item/weapon/gun/energy/gun/nuclear/emp_act(severity) + ..() + reliability -= round(15/severity) - update_charge() - if (crit_fail) - overlays += "nucgun-whee" - return - var/ratio = power_supply.charge / power_supply.maxcharge - ratio = round(ratio, 0.25) * 100 - overlays += "nucgun-[ratio]" - - - update_reactor() - if(crit_fail) - overlays += "nucgun-crit" - return - if(lightfail) - overlays += "nucgun-medium" - else if ((power_supply.charge/power_supply.maxcharge) <= 0.5) - overlays += "nucgun-light" - else - overlays += "nucgun-clean" - - - update_mode() - if (mode == 0) - overlays += "nucgun-stun" - else if (mode == 1) - overlays += "nucgun-kill" - - - emp_act(severity) - ..() - reliability -= round(15/severity) - - - update_icon() - overlays.Cut() - update_charge() - update_reactor() - update_mode() +/obj/item/weapon/gun/energy/gun/nuclear/update_icon() + overlays.Cut() + update_charge() + update_reactor() + update_mode() diff --git a/code/modules/projectiles/guns/energy/pulse.dm b/code/modules/projectiles/guns/energy/pulse.dm index 3e7fee0fe81..099e99fd796 100644 --- a/code/modules/projectiles/guns/energy/pulse.dm +++ b/code/modules/projectiles/guns/energy/pulse.dm @@ -1,6 +1,6 @@ /obj/item/weapon/gun/energy/pulse_rifle name = "pulse rifle" - desc = "A heavy-duty, pulse-based energy weapon, preferred by front-line combat personnel." + desc = "A weapon that uses advanced pulse-based beam generation technology to emit powerful laser blasts. Because of its complexity and cost, it is rarely seen in use except by specialists." icon_state = "pulse" item_state = null //so the human update icon uses the icon_state instead. slot_flags = SLOT_BELT|SLOT_BACK @@ -8,55 +8,46 @@ fire_sound = 'sound/weapons/pulse.ogg' charge_cost = 200 projectile_type = /obj/item/projectile/beam/pulse - cell_type = "/obj/item/weapon/cell/super" + cell_type = /obj/item/weapon/cell/super var/mode = 2 fire_delay = 25 - attack_self(mob/living/user as mob) - switch(mode) - if(2) - mode = 0 - charge_cost = 100 - fire_sound = 'sound/weapons/Taser.ogg' - user << "\red \The [src] is now set to stun." - projectile_type = /obj/item/projectile/beam/stun - if(0) - mode = 1 - charge_cost = 100 - fire_sound = 'sound/weapons/Laser.ogg' - user << "\red \The [src] is now set to kill." - projectile_type = /obj/item/projectile/beam - if(1) - mode = 2 - charge_cost = 200 - fire_sound = 'sound/weapons/pulse.ogg' - user << "\red \The [name] is now set to DESTROY." - projectile_type = /obj/item/projectile/beam/pulse - return - -/obj/item/weapon/gun/energy/pulse_rifle/cyborg/load_into_chamber() - if(in_chamber) - return 1 - if(isrobot(src.loc)) - var/mob/living/silicon/robot/R = src.loc - if(R && R.cell) - R.cell.use(charge_cost) - in_chamber = new/obj/item/projectile/beam(src) - return 1 - return 0 +/obj/item/weapon/gun/energy/pulse_rifle/attack_self(mob/living/user as mob) + switch(mode) + if(2) + mode = 0 + charge_cost = 100 + fire_sound = 'sound/weapons/Taser.ogg' + user << "\red [src.name] is now set to stun." + projectile_type = /obj/item/projectile/beam/stun + if(0) + mode = 1 + charge_cost = 100 + fire_sound = 'sound/weapons/Laser.ogg' + user << "\red [src.name] is now set to kill." + projectile_type = /obj/item/projectile/beam + if(1) + mode = 2 + charge_cost = 200 + fire_sound = 'sound/weapons/pulse.ogg' + user << "\red [src.name] is now set to DESTROY." + projectile_type = /obj/item/projectile/beam/pulse +/obj/item/weapon/gun/energy/pulse_rifle/mounted + self_recharge = 1 + use_external_power = 1 /obj/item/weapon/gun/energy/pulse_rifle/destroyer name = "pulse destroyer" - desc = "A heavy-duty, pulse-based energy weapon." + desc = "A heavy-duty, pulse-based energy weapon. Because of its complexity and cost, it is rarely seen in use except by specialists." cell_type = "/obj/item/weapon/cell/infinite" fire_delay = 10 - attack_self(mob/living/user as mob) - user << "\red \The [src] has three settings, and they are all DESTROY." - +/obj/item/weapon/gun/energy/pulse_rifle/destroyer/attack_self(mob/living/user as mob) + user << "\red [src.name] has three settings, and they are all DESTROY." +//WHY? /obj/item/weapon/gun/energy/pulse_rifle/M1911 name = "\improper M1911-P" desc = "It's not the size of the gun, it's the size of the hole it puts through people." diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index 9b067caec84..3cd057c2c46 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -9,14 +9,12 @@ flags = CONDUCT slot_flags = SLOT_BACK charge_cost = 100 - projectile_type = "/obj/item/projectile/ion" + projectile_type = /obj/item/projectile/ion /obj/item/weapon/gun/energy/ionrifle/emp_act(severity) - if(severity <= 2) - power_supply.use(round(power_supply.maxcharge / severity)) - update_icon() - else - return + if(severity > 2) + return //so it doesn't EMP itself, I guess + ..() /obj/item/weapon/gun/energy/decloner name = "biological demolecularisor" @@ -25,59 +23,7 @@ fire_sound = 'sound/weapons/pulse3.ogg' origin_tech = "combat=5;materials=4;powerstorage=3" charge_cost = 100 - projectile_type = "/obj/item/projectile/energy/declone" - -obj/item/weapon/gun/energy/staff - name = "staff of change" - desc = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself" - icon = 'icons/obj/gun.dmi' - icon_state = "staffofchange" - item_state = "staffofchange" - fire_sound = 'sound/weapons/emitter.ogg' - flags = CONDUCT - slot_flags = SLOT_BACK - w_class = 4.0 - charge_cost = 200 - projectile_type = "/obj/item/projectile/change" - origin_tech = null - clumsy_check = 0 - var/charge_tick = 0 - - - New() - ..() - processing_objects.Add(src) - - - Del() - processing_objects.Remove(src) - ..() - - - process() - charge_tick++ - if(charge_tick < 4) return 0 - charge_tick = 0 - if(!power_supply) return 0 - power_supply.give(200) - return 1 - - update_icon() - return - - - click_empty(mob/user = null) - if (user) - user.visible_message("*fizzle*", "\red *fizzle*") - else - src.visible_message("*fizzle*") - playsound(src.loc, 'sound/effects/sparks1.ogg', 100, 1) - -/obj/item/weapon/gun/energy/staff/animate - name = "staff of animation" - desc = "An artefact that spits bolts of life-force which causes objects which are hit by it to animate and come to life! This magic doesn't affect machines." - projectile_type = "/obj/item/projectile/animate" - charge_cost = 100 + projectile_type = /obj/item/projectile/energy/declone /obj/item/weapon/gun/energy/floragun name = "floral somatoray" @@ -86,55 +32,35 @@ obj/item/weapon/gun/energy/staff item_state = "obj/item/gun.dmi" fire_sound = 'sound/effects/stealthoff.ogg' charge_cost = 100 - projectile_type = "/obj/item/projectile/energy/floramut" + projectile_type = /obj/item/projectile/energy/floramut origin_tech = "materials=2;biotech=3;powerstorage=3" modifystate = "floramut" - var/charge_tick = 0 + self_recharge = 1 var/mode = 0 //0 = mutate, 1 = yield boost -/obj/item/weapon/gun/energy/floragun/New() - ..() - processing_objects.Add(src) - -/obj/item/weapon/gun/energy/floragun/Del() - processing_objects.Remove(src) - ..() - -/obj/item/weapon/gun/energy/floragun/process() - charge_tick++ - if(charge_tick < 4) return 0 - charge_tick = 0 - if(!power_supply) return 0 - power_supply.give(100) - update_icon() - return 1 - /obj/item/weapon/gun/energy/floragun/attack_self(mob/living/user as mob) switch(mode) if(0) mode = 1 charge_cost = 100 user << "\red The [src.name] is now set to increase yield." - projectile_type = "/obj/item/projectile/energy/florayield" + projectile_type = /obj/item/projectile/energy/florayield modifystate = "florayield" if(1) mode = 0 charge_cost = 100 user << "\red The [src.name] is now set to induce mutations." - projectile_type = "/obj/item/projectile/energy/floramut" + projectile_type = /obj/item/projectile/energy/floramut modifystate = "floramut" update_icon() return -/obj/item/weapon/gun/energy/floragun/afterattack(obj/target, mob/user, flag) - - if(flag && istype(target,/obj/machinery/portable_atmospherics/hydroponics)) - var/obj/machinery/portable_atmospherics/hydroponics/tray = target - if(load_into_chamber()) - user.visible_message("\red \The [user] fires \the [src] into \the [tray]!") - Fire(target,user) +/obj/item/weapon/gun/energy/floragun/afterattack(obj/target, mob/user, adjacent_flag) + //allow shooting into adjacent hydrotrays regardless of intent + if(adjacent_flag && istype(target,/obj/machinery/portable_atmospherics/hydroponics)) + user.visible_message("\red \The [user] fires \the [src] into \the [target]!") + Fire(target,user) return - ..() /obj/item/weapon/gun/energy/meteorgun @@ -144,32 +70,12 @@ obj/item/weapon/gun/energy/staff item_state = "c20r" slot_flags = SLOT_BELT|SLOT_BACK w_class = 4 - projectile_type = "/obj/item/projectile/meteor" + projectile_type = /obj/item/projectile/meteor charge_cost = 100 cell_type = "/obj/item/weapon/cell/potato" - clumsy_check = 0 //Admin spawn only, might as well let clowns use it. - var/charge_tick = 0 - var/recharge_time = 5 //Time it takes for shots to recharge (in ticks) - - New() - ..() - processing_objects.Add(src) - - - Del() - processing_objects.Remove(src) - ..() - - process() - charge_tick++ - if(charge_tick < recharge_time) return 0 - charge_tick = 0 - if(!power_supply) return 0 - power_supply.give(100) - - update_icon() - return - + self_recharge = 1 + recharge_time = 5 //Time it takes for shots to recharge (in ticks) + charge_meter = 0 /obj/item/weapon/gun/energy/meteorgun/pen name = "meteor pen" @@ -185,9 +91,49 @@ obj/item/weapon/gun/energy/staff name = "mind flayer" desc = "A prototype weapon recovered from the ruins of Research-Station Epsilon." icon_state = "xray" - projectile_type = "/obj/item/projectile/beam/mindflayer" + projectile_type = /obj/item/projectile/beam/mindflayer fire_sound = 'sound/weapons/Laser.ogg' +/obj/item/weapon/gun/energy/toxgun + name = "phoron pistol" + desc = "A specialized firearm designed to fire lethal bolts of phoron." + icon_state = "toxgun" + fire_sound = 'sound/effects/stealthoff.ogg' + w_class = 3.0 + origin_tech = "combat=5;phorontech=4" + projectile_type = /obj/item/projectile/energy/phoron + +/* Staves */ + +/obj/item/weapon/gun/energy/staff + name = "staff of change" + desc = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself" + icon = 'icons/obj/gun.dmi' + icon_state = "staffofchange" + item_state = "staffofchange" + fire_sound = 'sound/weapons/emitter.ogg' + flags = CONDUCT + slot_flags = SLOT_BACK + w_class = 4.0 + charge_cost = 200 + projectile_type = /obj/item/projectile/change + origin_tech = null + self_recharge = 1 + charge_meter = 0 + +/obj/item/weapon/gun/energy/staff/handle_click_empty(mob/user = null) + if (user) + user.visible_message("*fizzle*", "\red *fizzle*") + else + src.visible_message("*fizzle*") + playsound(src.loc, 'sound/effects/sparks1.ogg', 100, 1) + +/obj/item/weapon/gun/energy/staff/animate + name = "staff of animation" + desc = "An artefact that spits bolts of life-force which causes objects which are hit by it to animate and come to life! This magic doesn't affect machines." + projectile_type = /obj/item/projectile/animate + charge_cost = 100 + obj/item/weapon/gun/energy/staff/focus name = "mental focus" desc = "An artefact that channels the will of the user into destructive bolts of force. If you aren't careful with it, you might poke someone's brain out." @@ -195,7 +141,7 @@ obj/item/weapon/gun/energy/staff/focus icon_state = "focus" item_state = "focus" slot_flags = SLOT_BACK - projectile_type = "/obj/item/projectile/forcebolt" + projectile_type = /obj/item/projectile/forcebolt /* attack_self(mob/living/user as mob) if(projectile_type == "/obj/item/projectile/forcebolt") @@ -208,37 +154,7 @@ obj/item/weapon/gun/energy/staff/focus projectile_type = "/obj/item/projectile/forcebolt" */ -/obj/item/weapon/gun/energy/toxgun - name = "phoron pistol" - desc = "A specialized firearm designed to fire lethal bolts of phoron." - icon_state = "toxgun" - fire_sound = 'sound/effects/stealthoff.ogg' - w_class = 3.0 - origin_tech = "combat=5;phorontech=4" - projectile_type = "/obj/item/projectile/energy/phoron" - -/obj/item/weapon/gun/energy/sniperrifle - name = "\improper L.W.A.P. sniper rifle" - desc = "A high-power laser rifle fitted with a SMART aiming-system scope." - icon = 'icons/obj/gun.dmi' - icon_state = "sniper" - fire_sound = 'sound/weapons/marauder.ogg' - origin_tech = "combat=6;materials=5;powerstorage=4" - projectile_type = "/obj/item/projectile/beam/sniper" - slot_flags = SLOT_BACK - charge_cost = 250 - fire_delay = 35 - force = 10 - w_class = 4 - zoomdevicename = "scope" - -/obj/item/weapon/gun/energy/sniperrifle/verb/scope() - set category = "Object" - set name = "Use Scope" - set popup_menu = 1 - - zoom() - +/* Adminbus guns */ // Serves as a target spotter for the Icarus. /obj/item/weapon/gun/energy/icarus @@ -287,4 +203,4 @@ obj/item/weapon/gun/energy/staff/focus if(!type) return ..() - . = ..() + . = ..() \ No newline at end of file diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm index 11cff5f1bc3..e4d1b0070a8 100644 --- a/code/modules/projectiles/guns/energy/stun.dm +++ b/code/modules/projectiles/guns/energy/stun.dm @@ -6,38 +6,15 @@ fire_sound = 'sound/weapons/Taser.ogg' charge_cost = 100 projectile_type = /obj/item/projectile/beam/stun - cell_type = "/obj/item/weapon/cell/crap" + cell_type = /obj/item/weapon/cell/crap -/obj/item/weapon/gun/energy/taser/cyborg - cell_type = "/obj/item/weapon/cell/secborg" - var/charge_tick = 0 - var/recharge_time = 10 //Time it takes for shots to recharge (in ticks) +/obj/item/weapon/gun/energy/taser/mounted + self_recharge = 1 + use_external_power = 1 - New() - ..() - processing_objects.Add(src) - - - Del() - processing_objects.Remove(src) - ..() - - process() //Every [recharge_time] ticks, recharge a shot for the cyborg - charge_tick++ - if(charge_tick < recharge_time) return 0 - charge_tick = 0 - - if(!power_supply) return 0 //sanity - if(power_supply.charge >= power_supply.maxcharge) return 0 // check if we actually need to recharge - - if(isrobot(src.loc)) - var/mob/living/silicon/robot/R = src.loc - if(R && R.cell) - R.cell.use(charge_cost) //Take power from the borg... - power_supply.give(charge_cost) //... to recharge the shot - - update_icon() - return 1 +/obj/item/weapon/gun/energy/taser/mounted/cyborg + cell_type = /obj/item/weapon/cell/secborg + recharge_time = 10 //Time it takes for shots to recharge (in ticks) /obj/item/weapon/gun/energy/stunrevolver @@ -48,8 +25,7 @@ origin_tech = "combat=3;materials=3;powerstorage=2" charge_cost = 125 projectile_type = /obj/item/projectile/beam/stun - cell_type = "/obj/item/weapon/cell" - + cell_type = /obj/item/weapon/cell /obj/item/weapon/gun/energy/crossbow @@ -64,31 +40,9 @@ silenced = 1 fire_sound = 'sound/weapons/Genhit.ogg' projectile_type = /obj/item/projectile/energy/bolt - cell_type = "/obj/item/weapon/cell/crap" - var/charge_tick = 0 - - - New() - ..() - processing_objects.Add(src) - - - Del() - processing_objects.Remove(src) - ..() - - - process() - charge_tick++ - if(charge_tick < 4) return 0 - charge_tick = 0 - if(!power_supply) return 0 - power_supply.give(100) - return 1 - - - update_icon() - return + cell_type = /obj/item/weapon/cell/crap + self_recharge = 1 + charge_meter = 0 /obj/item/weapon/gun/energy/crossbow/ninja name = "energy dart thrower" diff --git a/code/modules/projectiles/guns/energy/temperature.dm b/code/modules/projectiles/guns/energy/temperature.dm index 7a4814aca01..ad4db3d5ca6 100644 --- a/code/modules/projectiles/guns/energy/temperature.dm +++ b/code/modules/projectiles/guns/energy/temperature.dm @@ -9,73 +9,71 @@ origin_tech = "combat=3;materials=4;powerstorage=3;magnets=2" slot_flags = SLOT_BELT|SLOT_BACK - projectile_type = "/obj/item/projectile/temp" - cell_type = "/obj/item/weapon/cell/crap" + projectile_type = /obj/item/projectile/temp + cell_type = /obj/item/weapon/cell/crap - New() - ..() - processing_objects.Add(src) +/obj/item/weapon/gun/energy/temperature/New() + ..() + processing_objects.Add(src) - Del() - processing_objects.Remove(src) - ..() +/obj/item/weapon/gun/energy/temperature/Del() + processing_objects.Remove(src) + ..() - attack_self(mob/living/user as mob) - user.set_machine(src) - var/temp_text = "" - if(temperature > (T0C - 50)) - temp_text = "[temperature] ([round(temperature-T0C)]°C) ([round(temperature*1.8-459.67)]°F)" +/obj/item/weapon/gun/energy/temperature/attack_self(mob/living/user as mob) + user.set_machine(src) + var/temp_text = "" + if(temperature > (T0C - 50)) + temp_text = "[temperature] ([round(temperature-T0C)]°C) ([round(temperature*1.8-459.67)]°F)" + else + temp_text = "[temperature] ([round(temperature-T0C)]°C) ([round(temperature*1.8-459.67)]°F)" + + var/dat = {"Freeze Gun Configuration:
+ Current output temperature: [temp_text]
+ Target output temperature: - - - [current_temperature] + + +
+ "} + + user << browse(dat, "window=freezegun;size=450x300;can_resize=1;can_close=1;can_minimize=1") + onclose(user, "window=freezegun", src) + + +/obj/item/weapon/gun/energy/temperature/Topic(href, href_list) + if (..()) + return + usr.set_machine(src) + src.add_fingerprint(usr) + + + + if(href_list["temp"]) + var/amount = text2num(href_list["temp"]) + if(amount > 0) + src.current_temperature = min(500, src.current_temperature+amount) else - temp_text = "[temperature] ([round(temperature-T0C)]°C) ([round(temperature*1.8-459.67)]°F)" - - var/dat = {"Freeze Gun Configuration:
- Current output temperature: [temp_text]
- Target output temperature: - - - [current_temperature] + + +
- "} + src.current_temperature = max(0, src.current_temperature+amount) + if (istype(src.loc, /mob)) + attack_self(src.loc) + src.add_fingerprint(usr) + return - user << browse(dat, "window=freezegun;size=450x300;can_resize=1;can_close=1;can_minimize=1") - onclose(user, "window=freezegun", src) +/obj/item/weapon/gun/energy/temperature/process() + switch(temperature) + if(0 to 100) charge_cost = 1000 + if(100 to 250) charge_cost = 500 + if(251 to 300) charge_cost = 100 + if(301 to 400) charge_cost = 500 + if(401 to 500) charge_cost = 1000 - - Topic(href, href_list) - if (..()) - return - usr.set_machine(src) - src.add_fingerprint(usr) - - - - if(href_list["temp"]) - var/amount = text2num(href_list["temp"]) - if(amount > 0) - src.current_temperature = min(500, src.current_temperature+amount) + if(current_temperature != temperature) + var/difference = abs(current_temperature - temperature) + if(difference >= 10) + if(current_temperature < temperature) + temperature -= 10 else - src.current_temperature = max(0, src.current_temperature+amount) - if (istype(src.loc, /mob)) - attack_self(src.loc) - src.add_fingerprint(usr) - return - - - process() - switch(temperature) - if(0 to 100) charge_cost = 1000 - if(100 to 250) charge_cost = 500 - if(251 to 300) charge_cost = 100 - if(301 to 400) charge_cost = 500 - if(401 to 500) charge_cost = 1000 - - if(current_temperature != temperature) - var/difference = abs(current_temperature - temperature) - if(difference >= 10) - if(current_temperature < temperature) - temperature -= 10 - else - temperature += 10 - else - temperature = current_temperature - return + temperature += 10 + else + temperature = current_temperature diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm index f3e83dde597..2f8d7ffb33e 100644 --- a/code/modules/projectiles/guns/projectile.dm +++ b/code/modules/projectiles/guns/projectile.dm @@ -1,69 +1,78 @@ +#define HOLD_CASINGS 0 //do not do anything after firing. Manual action, like pump shotguns +#define EJECT_CASINGS 1 //drop spent casings on the ground after firing +#define CYCLE_CASINGS 2 //experimental: cycle casings, like a revolver. Also works for multibarrelled guns + /obj/item/weapon/gun/projectile name = "gun" desc = "A gun that fires bullets." icon_state = "revolver" - caliber = "357" origin_tech = "combat=2;materials=2" w_class = 3 matter = list("metal" = 1000) recoil = 1 - - var/eject_casings = 1 //experimental: for guns that don't eject casings, like revolvers. + + var/caliber = "357" //determines which casings will fit + var/handle_casings = EJECT_CASINGS //determines how spent casings should be handled var/load_method = SINGLE_CASING|SPEEDLOADER //1 = Single shells, 2 = box or quick loader, 3 = magazine + var/obj/item/ammo_casing/chambered = null //For SINGLE_CASING or SPEEDLOADER guns - var/max_shells = 0 - var/ammo_type = null - var/list/loaded = list() + var/max_shells = 0 //the number of casings that will fit inside + var/ammo_type = null //the type of ammo that the gun comes preloaded with + var/list/loaded = list() //stored ammo //For MAGAZINE guns - var/magazine_type = null - var/obj/item/ammo_magazine/ammo_magazine = null - var/auto_eject = 0 //if the magazine should automatically eject itself when empty. + var/magazine_type = null //the type of magazine that the gun comes preloaded with + var/obj/item/ammo_magazine/ammo_magazine = null //stored magazine + var/auto_eject = 0 //if the magazine should automatically eject itself when empty. + var/auto_eject_sound = null /obj/item/weapon/gun/projectile/New() ..() - - if(load_method & (SINGLE_CASING|SPEEDLOADER)) + if(ispath(ammo_type) && (load_method & (SINGLE_CASING|SPEEDLOADER))) for(var/i in 1 to max_shells) loaded += new ammo_type(src) - if(load_method & MAGAZINE) + if(ispath(magazine_type) && (load_method & MAGAZINE)) ammo_magazine = new magazine_type(src) - update_icon() - -//This proc is badly named. There is no "chamber." Would be better to call this get_next_projectile() or something. -/obj/item/weapon/gun/projectile/load_into_chamber() - if(in_chamber) - return 1 //{R} - - var/obj/item/ammo_casing/C = null + +/obj/item/weapon/gun/projectile/can_fire() + var/obj/item/ammo_casing/C if(loaded.len) - C = loaded[1] //load next casing. - loaded -= C + C = loaded[1] else if(ammo_magazine && ammo_magazine.stored_ammo.len) C = ammo_magazine.stored_ammo[1] - ammo_magazine.stored_ammo -= C + return (C && C.BB) - if(istype(C)) - if(eject_casings) - C.loc = get_turf(src) //Eject casing onto ground. - else - //cycle it to the end - if(ammo_magazine) - ammo_magazine.stored_ammo += C - else - loaded += C - - if(C.BB) - in_chamber = C.BB - C.BB.loc = src //Set projectile loc to gun. - C.BB = null - return 1 +/obj/item/weapon/gun/projectile/get_next_projectile() + //store the next ammo_casing in a var so that handle_post_fire() knows which one to eject + //also we might as well remove chambered here, so that we don't have to figure out where it came from later + if(loaded.len) + chambered = loaded[1] //load next casing. + if(handle_casings != HOLD_CASINGS) + loaded -= chambered + else if(ammo_magazine && ammo_magazine.stored_ammo.len) + chambered = ammo_magazine.stored_ammo[1] + if(handle_casings != HOLD_CASINGS) + ammo_magazine.stored_ammo -= chambered + return chambered.BB - return 0 +/obj/item/weapon/gun/projectile/handle_post_fire() + ..() + if(chambered) + chambered.BB = null + switch(handle_casings) + if(EJECT_CASINGS) //eject casing onto ground. + chambered.loc = get_turf(src) + if(CYCLE_CASINGS) //cycle the casubg back to the end. + if(ammo_magazine) + ammo_magazine.stored_ammo += chambered + else + loaded += chambered + chambered = null //Attempts to load A into src, depending on the type of thing being loaded and the load_method +//Maybe this should be broken up into separate procs for each load method? /obj/item/weapon/gun/projectile/proc/load_ammo(var/obj/item/A, mob/user) if(istype(A, /obj/item/ammo_magazine)) var/obj/item/ammo_magazine/AM = A @@ -95,9 +104,6 @@ if(count) user.visible_message("[user] reloads [src].", "You load [count] round\s into [src]!") AM.update_icon() - update_icon() - return - else if(istype(A, /obj/item/ammo_casing)) var/obj/item/ammo_casing/C = A if(!(load_method & SINGLE_CASING) || caliber != C.caliber) @@ -110,8 +116,9 @@ C.loc = src loaded.Insert(1, C) //add to the head of the list user.visible_message("[user] inserts \a [C] into [src].", "You insert \a [C] into [src]!") - update_icon() - return + + update_icon() + //attempts to unload src /obj/item/weapon/gun/projectile/proc/unload_ammo(mob/user) @@ -120,8 +127,6 @@ user.visible_message("[user] removes [ammo_magazine] from [src].", "You remove [ammo_magazine] from [src]!") ammo_magazine.update_icon() ammo_magazine = null - update_icon() - else if(loaded.len) //presumably, if it can be speed-loaded, it can be speed-unloaded. if(load_method & SPEEDLOADER) @@ -139,16 +144,15 @@ loaded.len-- user.put_in_hands(C) user.visible_message("[user] removes \a [C] from [src].", "You remove \a [C] from [src]!") - update_icon() - else user << "[src] is empty!" + update_icon() /obj/item/weapon/gun/projectile/attackby(var/obj/item/A as obj, mob/user as mob) load_ammo(A, user) /obj/item/weapon/gun/projectile/attack_self(mob/user as mob) - if (target) //TODO replace untargeting with a hotkey + if (aim_targets) //TODO replace untargeting with a hotkey return ..() unload_ammo(user) @@ -164,17 +168,14 @@ /obj/item/weapon/gun/projectile/afterattack(atom/A, mob/living/user) ..() - if(auto_eject && !ammo_magazine.stored_ammo.len) - eject_magazine(user) - -//called when the magazine auto-ejects -/obj/item/weapon/gun/projectile/proc/eject_magazine(mob/user) - if(ammo_magazine) + if(auto_eject && ammo_magazine && ammo_magazine.stored_ammo && !ammo_magazine.stored_ammo.len) ammo_magazine.loc = get_turf(src.loc) user.visible_message( "[ammo_magazine] falls out and clatters on the floor!", "[ammo_magazine] falls out and clatters on the floor!" ) + if(auto_eject_sound) + playsound(user, auto_eject_sound, 40, 1) ammo_magazine = null update_icon() @@ -183,10 +184,6 @@ user << "Has [getAmmo()] round\s remaining." if(ammo_magazine) user << "It has \a [ammo_magazine] loaded." -// if(in_chamber && !loaded.len) -// user << "However, it has a chambered round." -// if(in_chamber && loaded.len) -// user << "It also has a chambered round." {R} return /obj/item/weapon/gun/projectile/proc/getAmmo() @@ -195,4 +192,6 @@ bullets += loaded.len if(ammo_magazine && ammo_magazine.stored_ammo) bullets += ammo_magazine.stored_ammo.len + if(chambered) + bullets += 1 return bullets diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm index 4500f2be2d1..506ffcfff38 100644 --- a/code/modules/projectiles/guns/projectile/automatic.dm +++ b/code/modules/projectiles/guns/projectile/automatic.dm @@ -6,13 +6,12 @@ load_method = SPEEDLOADER //yup. until someone sprites a magazine for it. max_shells = 22 caliber = "9mm" - origin_tech = "combat=4;materials=2" + origin_tech = "combat=4;materials=2" slot_flags = SLOT_BELT ammo_type = /obj/item/ammo_casing/c9mm - automatic = 1 - + multi_aim = 1 fire_delay = 0 - + /obj/item/weapon/gun/projectile/automatic/mini_uzi name = "\improper Uzi" desc = "A lightweight, fast firing gun, for when you want someone dead. Uses .45 rounds." @@ -24,7 +23,6 @@ origin_tech = "combat=5;materials=2;syndicate=8" ammo_type = /obj/item/ammo_casing/c45 - /obj/item/weapon/gun/projectile/automatic/c20r name = "\improper C-20r SMG" desc = "A lightweight, fast firing gun, for when you REALLY need someone dead. Uses 12mm rounds. Has a 'Scarborough Arms - Per falcis, per pravitas' buttstamp" @@ -39,10 +37,7 @@ load_method = MAGAZINE magazine_type = /obj/item/ammo_magazine/a12mm auto_eject = 1 - -/obj/item/weapon/gun/projectile/automatic/c20r/eject_magazine(mob/user) - ..() - playsound(user, 'sound/weapons/smg_empty_alarm.ogg', 40, 1) + auto_eject_sound = 'sound/weapons/smg_empty_alarm.ogg' /obj/item/weapon/gun/projectile/automatic/c20r/update_icon() ..() @@ -96,4 +91,4 @@ if(istype(A,/obj/item/ammo_magazine) && !cover_open) user << "[src]'s cover is closed! You can't insert a new mag!" return - ..() \ No newline at end of file + ..() diff --git a/code/modules/projectiles/guns/projectile/crossbow.dm b/code/modules/projectiles/guns/projectile/crossbow.dm index e74e58fe733..a9e95254be5 100644 --- a/code/modules/projectiles/guns/projectile/crossbow.dm +++ b/code/modules/projectiles/guns/projectile/crossbow.dm @@ -51,12 +51,11 @@ icon_state = "crossbow" item_state = "crossbow-solid" fire_sound = 'sound/weapons/punchmiss.ogg' // TODO: Decent THWOK noise. - ejectshell = 0 // No spent shells. - mouthshoot = 1 // No suiciding with this weapon, causes runtimes. fire_sound_text = "a solid thunk" fire_delay = 25 slot_flags = SLOT_BACK + var/obj/item/bolt var/tension = 0 // Current draw on the bow. var/max_tension = 5 // Highest possible tension. var/release_speed = 5 // Speed per unit of tension. @@ -76,19 +75,25 @@ /obj/item/weapon/gun/launcher/crossbow/update_release_force() release_force = tension*release_speed -/obj/item/weapon/gun/launcher/crossbow/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0) +/obj/item/weapon/gun/launcher/crossbow/can_fire() + return (tension && bolt) - if(!..()) return //Only do this on a successful shot. +/obj/item/weapon/gun/launcher/crossbow/get_next_projectile() + return bolt + +/obj/item/weapon/gun/launcher/crossbow/handle_post_fire(mob/user, atom/target) + bolt = null icon_state = "crossbow" tension = 0 + ..() /obj/item/weapon/gun/launcher/crossbow/attack_self(mob/living/user as mob) if(tension) - if(in_chamber && in_chamber.loc == src) //Just in case they click it the tick after firing. - user.visible_message("[user] relaxes the tension on [src]'s string and removes [in_chamber].","You relax the tension on [src]'s string and remove [in_chamber].") - in_chamber.loc = get_turf(src) - var/obj/item/weapon/arrow/A = in_chamber - in_chamber = null + if(bolt) + user.visible_message("[user] relaxes the tension on [src]'s string and removes [bolt].","You relax the tension on [src]'s string and remove [bolt].") + bolt.loc = get_turf(src) + var/obj/item/weapon/arrow/A = bolt + bolt = null A.removed(user) else user.visible_message("[user] relaxes the tension on [src]'s string.","You relax the tension on [src]'s string.") @@ -99,7 +104,7 @@ /obj/item/weapon/gun/launcher/crossbow/proc/draw(var/mob/user as mob) - if(!in_chamber) + if(!bolt) user << "You don't have anything nocked to [src]." return @@ -113,7 +118,7 @@ /obj/item/weapon/gun/launcher/crossbow/proc/increase_tension(var/mob/user as mob) - if(!in_chamber || !tension || current_user != user) //Arrow has been fired, bow has been relaxed or user has changed. + if(!bolt || !tension || current_user != user) //Arrow has been fired, bow has been relaxed or user has changed. return tension++ @@ -127,22 +132,22 @@ spawn(25) increase_tension(user) /obj/item/weapon/gun/launcher/crossbow/attackby(obj/item/W as obj, mob/user as mob) - if(!in_chamber) + if(!bolt) if (istype(W,/obj/item/weapon/arrow)) user.drop_item() - in_chamber = W - in_chamber.loc = src - user.visible_message("[user] slides [in_chamber] into [src].","You slide [in_chamber] into [src].") + bolt = W + bolt.loc = src + user.visible_message("[user] slides [bolt] into [src].","You slide [bolt] into [src].") icon_state = "crossbow-nocked" return else if(istype(W,/obj/item/stack/rods)) var/obj/item/stack/rods/R = W if (R.use(1)) - in_chamber = new /obj/item/weapon/arrow/rod(src) - in_chamber.fingerprintslast = src.fingerprintslast - in_chamber.loc = src + bolt = new /obj/item/weapon/arrow/rod(src) + bolt.fingerprintslast = src.fingerprintslast + bolt.loc = src icon_state = "crossbow-nocked" - user.visible_message("[user] jams [in_chamber] into [src].","You jam [in_chamber] into [src].") + user.visible_message("[user] jams [bolt] into [src].","You jam [bolt] into [src].") superheat_rod(user) return @@ -169,14 +174,14 @@ ..() /obj/item/weapon/gun/launcher/crossbow/proc/superheat_rod(var/mob/user) - if(!user || !cell || !in_chamber) return + if(!user || !cell || !bolt) return if(cell.charge < 500) return - if(in_chamber.throwforce >= 15) return - if(!istype(in_chamber,/obj/item/weapon/arrow/rod)) return + if(bolt.throwforce >= 15) return + if(!istype(bolt,/obj/item/weapon/arrow/rod)) return - user << "[in_chamber] plinks and crackles as it begins to glow red-hot." - in_chamber.throwforce = 15 - in_chamber.icon_state = "metal-rod-superheated" + user << "[bolt] plinks and crackles as it begins to glow red-hot." + bolt.throwforce = 15 + bolt.icon_state = "metal-rod-superheated" cell.use(500) diff --git a/code/modules/projectiles/guns/projectile/launcher.dm b/code/modules/projectiles/guns/projectile/launcher.dm index 97f25cbc28f..82998ef60ae 100644 --- a/code/modules/projectiles/guns/projectile/launcher.dm +++ b/code/modules/projectiles/guns/projectile/launcher.dm @@ -7,78 +7,29 @@ slot_flags = SLOT_BACK var/release_force = 0 - var/fire_sound_text = "a launcher firing" - -//Check if we're drawing and if the bow is loaded. -/obj/item/weapon/gun/launcher/load_into_chamber() - return (!isnull(in_chamber)) - -//Launchers are mechanical, no other impact. -/obj/item/weapon/gun/launcher/emp_act(severity) - return + var/throw_distance = 10 + fire_sound_text = "a launcher firing" //This normally uses a proc on projectiles and our ammo is not strictly speaking a projectile. /obj/item/weapon/gun/launcher/can_hit(var/mob/living/target as mob, var/mob/living/user as mob) - return + return 1 //Override this to avoid a runtime with suicide handling. -/obj/item/weapon/gun/launcher/attack(mob/living/M as mob, mob/living/user as mob, def_zone) - if (M == user && user.zone_sel.selecting == "mouth") - user << "\red Shooting yourself with \a [src] is pretty tricky. You can't seem to manage it." - return - ..() +/obj/item/weapon/gun/launcher/handle_suicide(mob/living/user) + user << "\red Shooting yourself with \a [src] is pretty tricky. You can't seem to manage it." + return -/obj/item/weapon/gun/launcher/proc/update_release_force() +/obj/item/weapon/gun/launcher/proc/update_release_force(obj/item/projectile) return 0 -/obj/item/weapon/gun/launcher/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0) - - if (!user.IsAdvancedToolUser()) - return 0 - - add_fingerprint(user) - - //Make sure target turfs both exist. - var/turf/curloc = get_turf(user) - var/turf/targloc = get_turf(target) - if (!istype(targloc) || !istype(curloc)) - return 0 - - if(!special_check(user)) - return 0 - - if (!ready_to_fire()) - if (world.time % 3) //to prevent spam - user << "[src] is not ready to fire again!" - return 0 - - if(!load_into_chamber()) //CHECK - return click_empty(user) - - if(!in_chamber) - return 0 - - update_release_force() - - playsound(user, fire_sound, 50, 1) - user.visible_message("[user] fires [src][reflex ? " by reflex":""]!", \ - "You fire [src][reflex ? "by reflex":""]!", \ - "You hear [fire_sound_text]!") - - in_chamber.loc = get_turf(user) - in_chamber.throw_at(target,10,release_force) - - sleep(1) - - in_chamber = null - - update_icon() - - if(user.hand) - user.update_inv_l_hand() - else - user.update_inv_r_hand() - +/obj/item/weapon/gun/launcher/process_projectile(obj/projectile, mob/user, atom/target, var/target_zone, var/params=null, var/pointblank=0, var/reflex=0) + if(!istype(projectile, /obj/item)) return 0 + + var/obj/item/I = projectile + + update_release_force(I) + I.loc = get_turf(user) + I.throw_at(target, throw_distance, release_force, user) return 1 /obj/item/weapon/gun/launcher/attack_self(mob/living/user as mob) diff --git a/code/modules/projectiles/guns/projectile/pistol.dm b/code/modules/projectiles/guns/projectile/pistol.dm index 32af57100ae..d43000d55e7 100644 --- a/code/modules/projectiles/guns/projectile/pistol.dm +++ b/code/modules/projectiles/guns/projectile/pistol.dm @@ -1,3 +1,21 @@ +/obj/item/weapon/gun/projectile/detective + name = "\improper Colt M1911" + desc = "A cheap Martian knock-off of a Colt M1911. Uses less-than-lethal .45 rounds." + icon_state = "colt" + caliber = ".45" + origin_tech = "combat=2;materials=2" + load_method = MAGAZINE + magazine_type = /obj/item/ammo_magazine/c45m/rubber + +/obj/item/weapon/gun/projectile/detective/flash + name = "\improper Colt M1911 signal pistol" + desc = "A cheap Martian knock-off of a Colt M1911. Uses .45 signal flash rounds." + magazine_type = /obj/item/ammo_magazine/c45m/flash + +/obj/item/weapon/gun/projectile/detective/colt + desc = "A cheap Martian knock-off of a Colt M1911." + magazine_type = /obj/item/ammo_magazine/c45m + /obj/item/weapon/gun/projectile/silenced name = "silenced pistol" desc = "A small, quiet, easily concealable gun. Uses .45 rounds." @@ -19,10 +37,6 @@ magazine_type = /obj/item/ammo_magazine/a50 auto_eject = 1 -/obj/item/weapon/gun/projectile/deagle/eject_magazine(mob/user) - ..() - playsound(user, 'sound/weapons/smg_empty_alarm.ogg', 40, 1) - /obj/item/weapon/gun/projectile/deagle/gold desc = "A gold plated gun folded over a million times by superior martian gunsmiths. Uses .50 AE ammo." icon_state = "deagleg" @@ -32,6 +46,7 @@ desc = "A Deagle brand Deagle for operators operating operationally. Uses .50 AE ammo." icon_state = "deaglecamo" item_state = "deagleg" + auto_eject_sound = 'sound/weapons/smg_empty_alarm.ogg' @@ -47,10 +62,7 @@ load_method = MAGAZINE magazine_type = /obj/item/ammo_magazine/a75 auto_eject = 1 - -/obj/item/weapon/gun/projectile/gyropistol/eject_magazine(mob/user) - ..() - playsound(user, 'sound/weapons/smg_empty_alarm.ogg', 40, 1) + auto_eject_sound = 'sound/weapons/smg_empty_alarm.ogg' /obj/item/weapon/gun/projectile/gyropistol/update_icon() ..() diff --git a/code/modules/projectiles/guns/projectile/pneumatic.dm b/code/modules/projectiles/guns/projectile/pneumatic.dm index f83ab85570f..96dc344dd1f 100644 --- a/code/modules/projectiles/guns/projectile/pneumatic.dm +++ b/code/modules/projectiles/guns/projectile/pneumatic.dm @@ -63,7 +63,6 @@ item_state = "pneumatic-tank" user.update_icons() else if(W.w_class <= max_w_class) - var/total_stored = 0 for(var/obj/item/O in src.contents) total_stored += O.w_class @@ -80,9 +79,6 @@ /obj/item/weapon/gun/launcher/pneumatic/attack_self(mob/user as mob) if(contents.len > 0) var/obj/item/removing = contents[contents.len] - if(removing == in_chamber) - in_chamber = null - removing.loc = get_turf(src) user.put_in_hands(removing) user << "You remove [removing] from the hopper." @@ -90,12 +86,16 @@ user << "There is nothing to remove in \the [src]." return -/obj/item/weapon/gun/launcher/pneumatic/load_into_chamber() +/obj/item/weapon/gun/launcher/pneumatic/get_next_projectile() + if(!contents.len) + return null + return contents[1] + +/obj/item/weapon/gun/launcher/pneumatic/can_fire() if(!contents.len) return 0 - - in_chamber = contents[1] - return !isnull(in_chamber) + var/fire_pressure = (tank.air_contents.return_pressure()/100)*pressure_setting + return (fire_pressure >= minimum_tank_pressure) /obj/item/weapon/gun/launcher/pneumatic/examine(mob/user) if(!..(user, 2)) @@ -107,7 +107,6 @@ user << "Nothing is attached to the tank valve!" /obj/item/weapon/gun/launcher/pneumatic/special_check(user) - if (!tank) user << "There is no gas tank in [src]!" return 0 @@ -117,20 +116,23 @@ user << "There isn't enough gas in the tank to fire [src]." return 0 - return 1 + return ..() -/obj/item/weapon/gun/launcher/pneumatic/update_release_force() - if(!in_chamber) return - release_force = ((fire_pressure*tank.volume)/in_chamber.w_class)/force_divisor //projectile speed. - if(release_force >80) release_force = 80 //damage cap. +/obj/item/weapon/gun/launcher/pneumatic/update_release_force(obj/item/projectile) + if(tank) + release_force = ((fire_pressure*tank.volume)/projectile.w_class)/force_divisor //projectile speed. + if(release_force > 80) release_force = 80 //damage cap. + else + release_force = 0 -/obj/item/weapon/gun/launcher/pneumatic/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0) - - if(!tank || !..()) return //Only do this on a successful shot. - - var/lost_gas_amount = tank.air_contents.total_moles*(pressure_setting/100) - var/datum/gas_mixture/removed = tank.air_contents.remove(lost_gas_amount) - user.loc.assume_air(removed) +/obj/item/weapon/gun/launcher/pneumatic/handle_post_fire() + if(tank) + var/lost_gas_amount = tank.air_contents.total_moles*(pressure_setting/100) + var/datum/gas_mixture/removed = tank.air_contents.remove(lost_gas_amount) + + var/turf/T = get_turf(src.loc) + if(T) T.assume_air(removed) + ..() //Constructable pneumatic cannon. diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm index cc77625c0d9..36aba0f8c5b 100644 --- a/code/modules/projectiles/guns/projectile/revolver.dm +++ b/code/modules/projectiles/guns/projectile/revolver.dm @@ -4,8 +4,7 @@ icon_state = "revolver" caliber = "357" origin_tech = "combat=2;materials=2" - - eject_casings = 0 + handle_casings = CYCLE_CASINGS max_shells = 7 ammo_type = /obj/item/ammo_casing/a357 @@ -15,26 +14,23 @@ icon_state = "mateba" origin_tech = "combat=2;materials=2" -/obj/item/weapon/gun/projectile/detective +/obj/item/weapon/gun/projectile/revolver/detective name = "revolver" desc = "A cheap Martian knock-off of a Smith & Wesson Model 10. Uses .38-Special rounds." icon_state = "detective" max_shells = 6 - eject_casings = 0 caliber = "38" origin_tech = "combat=2;materials=2" ammo_type = /obj/item/ammo_casing/c38 special_check(var/mob/living/carbon/human/M) - if(caliber == initial(caliber)) - return 1 - if(prob(70 - (loaded.len * 10))) //minimum probability of 10, maximum of 60 + if(caliber == initial(caliber) && prob(70 - (loaded.len * 10))) //minimum probability of 10, maximum of 60 M << "[src] blows up in your face." M.take_organ_damage(0,20) M.drop_item() del(src) return 0 - return 1 + return ..() verb/rename_gun() set name = "Name Gun" @@ -86,28 +82,9 @@ desc = initial(desc) user << "You remove the modifications on [src]! Now it will fire .38 rounds." - -/obj/item/weapon/gun/projectile/detective/semiauto - name = "\improper Colt M1911" - desc = "A cheap Martian knock-off of a Colt M1911. Uses less-than-lethal .45 rounds." - icon_state = "colt" - caliber = ".45" - eject_casings = 1 - load_method = MAGAZINE - magazine_type = /obj/item/ammo_magazine/c45m/rubber - -/obj/item/weapon/gun/projectile/detective/semiauto/flash - name = "\improper Colt M1911 signal pistol" - desc = "A cheap Martian knock-off of a Colt M1911. Uses .45 signal flash rounds." - magazine_type = /obj/item/ammo_magazine/c45m/flash - -/obj/item/weapon/gun/projectile/detective/semiauto/colt - desc = "A cheap Martian knock-off of a Colt M1911." - magazine_type = /obj/item/ammo_magazine/c45m - +/* // A gun to play Russian Roulette! // You can spin the chamber to randomize the position of the bullet. -/* /obj/item/weapon/gun/projectile/russian name = "\improper Russian revolver" desc = "A Russian made revolver. Uses .357 ammo. It has a single slot in it's chamber for a bullet." diff --git a/code/modules/projectiles/guns/projectile/rocket.dm b/code/modules/projectiles/guns/projectile/rocket.dm index 27fb15d5713..8020c250f04 100644 --- a/code/modules/projectiles/guns/projectile/rocket.dm +++ b/code/modules/projectiles/guns/projectile/rocket.dm @@ -1,4 +1,4 @@ -/obj/item/weapon/gun/rocketlauncher +/obj/item/weapon/gun/launcher/rocket name = "rocket launcher" desc = "MAGGOT." icon_state = "rocket" @@ -10,18 +10,19 @@ flags = CONDUCT | USEDELAY slot_flags = 0 origin_tech = "combat=8;materials=5" - var/projectile = /obj/item/missile - var/missile_speed = 2 - var/missile_range = 30 + fire_sound = 'sound/effects/bang.ogg' + + release_force = 15 + throw_distance = 30 var/max_rockets = 1 var/list/rockets = new/list() -/obj/item/weapon/gun/rocketlauncher/examine(mob/user) +/obj/item/weapon/gun/launcher/rocket/examine(mob/user) if(!..(user, 2)) return user << "\blue [rockets.len] / [max_rockets] rockets." -/obj/item/weapon/gun/rocketlauncher/attackby(obj/item/I as obj, mob/user as mob) +/obj/item/weapon/gun/launcher/rocket/attackby(obj/item/I as obj, mob/user as mob) if(istype(I, /obj/item/ammo_casing/rocket)) if(rockets.len < max_rockets) user.drop_item() @@ -32,20 +33,19 @@ else usr << "\red [src] cannot hold more rockets." -/obj/item/weapon/gun/rocketlauncher/can_fire() +/obj/item/weapon/gun/launcher/rocket/can_fire() return rockets.len -/obj/item/weapon/gun/rocketlauncher/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0) +/obj/item/weapon/gun/launcher/rocket/get_next_projectile() if(rockets.len) var/obj/item/ammo_casing/rocket/I = rockets[1] - var/obj/item/missile/M = new projectile(user.loc) - playsound(user.loc, 'sound/effects/bang.ogg', 50, 1) + var/obj/item/missile/M = new (src) M.primed = 1 - M.throw_at(target, missile_range, missile_speed,user) - message_admins("[key_name_admin(user)] fired a rocket from a rocket launcher ([src.name]).") - log_game("[key_name_admin(user)] used a rocket launcher ([src.name]).") rockets -= I - del(I) - return - else - usr << "\red [src] is empty." + return M + return null + +/obj/item/weapon/gun/launcher/rocket/handle_post_fire(mob/user, atom/target) + message_admins("[key_name_admin(user)] fired a rocket from a rocket launcher ([src.name]) at [target].") + log_game("[key_name_admin(user)] used a rocket launcher ([src.name]) at [target].") + ..() diff --git a/code/modules/projectiles/guns/projectile/shotgun.dm b/code/modules/projectiles/guns/projectile/shotgun.dm index a75f3c9310a..f0706999914 100644 --- a/code/modules/projectiles/guns/projectile/shotgun.dm +++ b/code/modules/projectiles/guns/projectile/shotgun.dm @@ -12,40 +12,35 @@ origin_tech = "combat=4;materials=2" load_method = SINGLE_CASING ammo_type = /obj/item/ammo_casing/shotgun/pellet + handle_casings = HOLD_CASINGS var/recentpump = 0 // to prevent spammage - var/pumped = 0 - var/obj/item/ammo_casing/current_shell = null -/obj/item/weapon/gun/projectile/shotgun/pump/load_into_chamber() - if(in_chamber) - return 1 - return 0 +/obj/item/weapon/gun/projectile/shotgun/pump/can_fire() + return (chambered && chambered.BB) + +/obj/item/weapon/gun/projectile/shotgun/pump/get_next_projectile() + if(chambered) + return chambered.BB + return null /obj/item/weapon/gun/projectile/shotgun/pump/attack_self(mob/living/user as mob) if(world.time >= recentpump + 10) - pump(user) + pump(user) recentpump = world.time -/obj/item/weapon/gun/projectile/shotgun/pump/getAmmo() - . = ..() - if(current_shell) .++ - /obj/item/weapon/gun/projectile/shotgun/pump/proc/pump(mob/M as mob) playsound(M, 'sound/weapons/shotgunpump.ogg', 60, 1) - pumped = 0 - if(current_shell)//We have a shell in the chamber - current_shell.loc = get_turf(src)//Eject casing - current_shell = null - if(in_chamber) - in_chamber = null - if(!loaded.len) return 0 - var/obj/item/ammo_casing/AC = loaded[1] //load next casing. - loaded -= AC //Remove casing from loaded list. - current_shell = AC - if(AC.BB) - in_chamber = AC.BB //Load projectile into chamber. - update_icon() //I.E. fix the desc - return 1 + + if(chambered)//We have a shell in the chamber + chambered.loc = get_turf(src)//Eject casing + chambered = null + + if(loaded.len) + var/obj/item/ammo_casing/AC = loaded[1] //load next casing. + loaded -= AC //Remove casing from loaded list. + chambered = AC + + update_icon() /obj/item/weapon/gun/projectile/shotgun/pump/combat name = "combat shotgun" @@ -63,14 +58,14 @@ //SPEEDLOADER because rapid unloading. //In principle someone could make a speedloader for it, so it makes sense. load_method = SINGLE_CASING|SPEEDLOADER - eject_casings = 0 + handle_casings = CYCLE_CASINGS max_shells = 2 w_class = 4 force = 10 flags = CONDUCT slot_flags = SLOT_BACK caliber = "shotgun" - origin_tech = "combat=3;materials=1" + origin_tech = "combat=3;materials=1" ammo_type = /obj/item/ammo_casing/shotgun/beanbag //this is largely hacky and bad :( -Pete @@ -79,7 +74,7 @@ user << "You begin to shorten the barrel of \the [src]." if(loaded.len) for(var/i in 1 to max_shells) - afterattack(user, user) //will this work? //it will. we call it twice, for twice the FUN + afterattack(user, user) //will this work? //it will. we call it twice, for twice the FUN playsound(user, fire_sound, 50, 1) user.visible_message("The shotgun goes off!", "The shotgun goes off in your face!") return @@ -88,9 +83,9 @@ w_class = 3 item_state = "gun" slot_flags &= ~SLOT_BACK //you can't sling it on your back - slot_flags |= SLOT_BELT|SLOT_HOLSTER //but you can wear it on your belt (poorly concealed under a trenchcoat, ideally), or in a holster, why not. + slot_flags |= (SLOT_BELT|SLOT_HOLSTER) //but you can wear it on your belt (poorly concealed under a trenchcoat, ideally) - or in a holster, why not. name = "sawn-off shotgun" desc = "Omar's coming!" user << "You shorten the barrel of \the [src]!" else - ..() + ..() \ No newline at end of file diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index c2aa02f56ae..793c53616ba 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -69,16 +69,16 @@ /obj/item/projectile/proc/on_penetrate(var/atom/A) return 1 -/obj/item/projectile/proc/check_fire(var/mob/living/target as mob, var/mob/living/user as mob) //Checks if you can hit them or not. +/obj/item/projectile/proc/check_fire(atom/target as mob, var/mob/living/user as mob) //Checks if you can hit them or not. if(!istype(target) || !istype(user)) return 0 - var/obj/item/projectile/test/in_chamber = new /obj/item/projectile/test(get_step_to(user,target)) //Making the test.... - in_chamber.target = target - in_chamber.flags = flags //Set the flags... - in_chamber.pass_flags = pass_flags //And the pass flags to that of the real projectile... - in_chamber.firer = user - var/output = in_chamber.process() //Test it! - del(in_chamber) //No need for it anymore + var/obj/item/projectile/test/trace = new /obj/item/projectile/test(get_step_to(user,target)) //Making the test.... + trace.target = target + trace.flags = flags //Set the flags... + trace.pass_flags = pass_flags //And the pass flags to that of the real projectile... + trace.firer = user + var/output = trace.process() //Test it! + del(trace) //No need for it anymore return output //Send it back to the gun! //sets the click point of the projectile using mouse input params @@ -141,7 +141,7 @@ //accuracy bonus from aiming if (istype(shot_from, /obj/item/weapon/gun)) //If you aim at someone beforehead, it'll hit more often. var/obj/item/weapon/gun/daddy = shot_from //Kinda balanced by fact you need like 2 seconds to aim - if (daddy.target && original in daddy.target) //As opposed to no-delay pew pew + if (daddy.aim_targets && original in daddy.aim_targets) //As opposed to no-delay pew pew miss_modifier += -30 //roll to-hit diff --git a/code/modules/projectiles/targeting.dm b/code/modules/projectiles/targeting.dm index 496455f24e4..7fe4c9f6203 100644 --- a/code/modules/projectiles/targeting.dm +++ b/code/modules/projectiles/targeting.dm @@ -1,10 +1,10 @@ /obj/item/weapon/gun/verb/toggle_firerate() - set name = "Toggle Firerate" + set name = "Toggle Continue Aiming" set category = "Object" - firerate = !firerate + keep_aim = !keep_aim - if (firerate) + if (keep_aim) loc << "You will now continue firing when your target moves." else loc << "You will now only fire once, then lower your aim, when your target moves." @@ -12,7 +12,7 @@ /obj/item/weapon/gun/verb/lower_aim() set name = "Lower Aim" set category = "Object" - if(target) + if(aim_targets) stop_aim() usr.visible_message("\blue \The [usr] lowers \the [src]...") @@ -36,11 +36,11 @@ //Removes lock fro mall targets /obj/item/weapon/gun/proc/stop_aim() - if(target) - for(var/mob/living/M in target) + if(aim_targets) + for(var/mob/living/M in aim_targets) if(M) M.NotTargeted(src) //Untargeting people. - del(target) + del(aim_targets) //Compute how to fire..... //Return 1 if a target was found, 0 otherwise. @@ -49,13 +49,13 @@ if(lock_time > world.time - 2) return user.set_dir(get_cardinal_dir(src, A)) - if(isliving(A) && !(A in target)) + if(isliving(A) && !(A in aim_targets)) Aim(A) //Clicked a mob, aim at them return 1 //Didn't click someone, check if there is anyone along that guntrace var/mob/living/M = GunTrace(usr.x,usr.y,A.x,A.y,usr.z,usr) //Find dat mob. - if(isliving(M) && (M in view(user)) && !(M in target)) + if(isliving(M) && (M in view(user)) && !(M in aim_targets)) Aim(M) //Aha! Aim at them! return 1 @@ -63,13 +63,13 @@ //Aiming at the target mob. /obj/item/weapon/gun/proc/Aim(var/mob/living/M) - if(!target || !(M in target)) + if(!aim_targets || !(M in aim_targets)) lock_time = world.time - if(target && !automatic) //If they're targeting someone and they have a non automatic weapon. - for(var/mob/living/L in target) + if(aim_targets && !multi_aim) //If they're targeting someone and they have a non multi_aim weapon. + for(var/mob/living/L in aim_targets) if(L) L.NotTargeted(src) - del(target) + del(aim_targets) usr.visible_message("\red [usr] turns \the [src] on [M]!") else usr.visible_message("\red [usr] aims \a [src] at [M]!") @@ -90,29 +90,26 @@ return M.last_move_intent = world.time - if(can_fire()) - var/firing_check = can_hit(T,usr) //0 if it cannot hit them, 1 if it is capable of hitting, and 2 if a special check is preventing it from firing. - if(firing_check > 0) - if(firing_check == 1) - Fire(T,usr, reflex = 1) - else if(!told_cant_shoot) - M << "\red They can't be hit from here!" - told_cant_shoot = 1 - spawn(30) - told_cant_shoot = 0 - else - click_empty(M) + var/firing_check = can_hit(T,usr) //0 if it cannot hit them, 1 if it is capable of hitting, and 2 if a special check is preventing it from firing. + if(firing_check > 0) + if(firing_check == 1) + Fire(T,usr, reflex = 1) + else if(!told_cant_shoot) + M << "\red They can't be hit from here!" + told_cant_shoot = 1 + spawn(30) + told_cant_shoot = 0 usr.set_dir(get_cardinal_dir(src, T)) - if (!firerate) // If firerate is set to lower aim after one shot, untarget the target + if (!keep_aim) // If keep_aim is set to lower aim after one shot, untarget the target T.NotTargeted(src) //Yay, math! #define SIGN(X) ((X<0)?-1:1) -proc/GunTrace(X1,Y1,X2,Y2,Z=1,exc_obj,PX1=16,PY1=16,PX2=16,PY2=16) +/proc/GunTrace(X1,Y1,X2,Y2,Z=1,exc_obj,PX1=16,PY1=16,PX2=16,PY2=16) //bluh << "Tracin' [X1],[Y1] to [X2],[Y2] on floor [Z]." var/turf/T var/mob/living/M @@ -150,19 +147,19 @@ proc/GunTrace(X1,Y1,X2,Y2,Z=1,exc_obj,PX1=16,PY1=16,PX2=16,PY2=16) //Targeting management procs -mob/var +/mob/var list/targeted_by target_time = -100 last_move_intent = -100 last_target_click = -5 target_locked = null -mob/living/proc/Targeted(var/obj/item/weapon/gun/I) //Self explanitory. - if(!I.target) - I.target = list(src) - else if(I.automatic && I.target.len < 5) //Automatic weapon, they can hold down a room. - I.target += src - else if(I.target.len >= 5) +/mob/living/proc/Targeted(var/obj/item/weapon/gun/I) //Self explanitory. + if(!I.aim_targets) + I.aim_targets = list(src) + else if(I.multi_aim && I.aim_targets.len < 5) //multi_aim weapon, they can hold down a room. + I.aim_targets += src + else if(I.aim_targets.len >= 5) if(ismob(I.loc)) I.loc << "You can only target 5 people at once!" return @@ -223,43 +220,43 @@ mob/living/proc/Targeted(var/obj/item/weapon/gun/I) //Self explanitory. I.last_moved_mob = src sleep(1) -mob/living/proc/NotTargeted(var/obj/item/weapon/gun/I) +/mob/living/proc/NotTargeted(var/obj/item/weapon/gun/I) if(!I.silenced) for(var/mob/living/M in viewers(src)) M << 'sound/weapons/TargetOff.ogg' targeted_by -= I - I.target.Remove(src) //De-target them - if(!I.target.len) - del(I.target) + I.aim_targets.Remove(src) //De-target them + if(!I.aim_targets.len) + del(I.aim_targets) var/mob/living/T = I.loc //Remove the targeting icons - if(T && ismob(T) && !I.target) + if(T && ismob(T) && !I.aim_targets) T.client.remove_gun_icons() if(!targeted_by.len) del target_locked //Remove the overlay del targeted_by spawn(1) update_targeted() -mob/living/Move() +/mob/living/Move() . = ..() for(var/obj/item/weapon/gun/G in targeted_by) //Handle moving out of the gunner's view. var/mob/living/M = G.loc if(!(M in view(src))) NotTargeted(G) for(var/obj/item/weapon/gun/G in src) //Handle the gunner loosing sight of their target/s - if(G.target) - for(var/mob/living/M in G.target) + if(G.aim_targets) + for(var/mob/living/M in G.aim_targets) if(M && !(M in view(src))) M.NotTargeted(G) //If you move out of range, it isn't going to still stay locked on you any more. -client/var +/client/var target_can_move = 0 target_can_run = 0 target_can_click = 0 gun_mode = 0 //These are called by the on-screen buttons, adjusting what the victim can and cannot do. -client/proc/add_gun_icons() +/client/proc/add_gun_icons() screen += usr.item_use_icon screen += usr.gun_move_icon if (target_can_move) @@ -267,14 +264,14 @@ client/proc/add_gun_icons() -client/proc/remove_gun_icons() +/client/proc/remove_gun_icons() if(!usr) return 1 // Runtime prevention on N00k agents spawning with SMG screen -= usr.item_use_icon screen -= usr.gun_move_icon if (target_can_move) screen -= usr.gun_run_icon -client/verb/ToggleGunMode() +/client/verb/ToggleGunMode() set hidden = 1 gun_mode = !gun_mode if(gun_mode) @@ -288,7 +285,7 @@ client/verb/ToggleGunMode() usr.gun_setting_icon.icon_state = "gun[gun_mode]" -client/verb/AllowTargetMove() +/client/verb/AllowTargetMove() set hidden=1 //Changing client's permissions @@ -310,8 +307,8 @@ client/verb/AllowTargetMove() //Handling change for all the guns on client for(var/obj/item/weapon/gun/G in usr) G.lock_time = world.time + 5 - if(G.target) - for(var/mob/living/M in G.target) + if(G.aim_targets) + for(var/mob/living/M in G.aim_targets) if(target_can_move) M << "Your character may now walk at the discretion of their targeter." if(!target_can_run) @@ -320,7 +317,7 @@ client/verb/AllowTargetMove() else M << "\red Your character will now be shot if they move." -mob/living/proc/set_m_intent(var/intent) +/mob/living/proc/set_m_intent(var/intent) if (intent != "walk" && intent != "run") return 0 m_intent = intent @@ -346,14 +343,14 @@ client/verb/AllowTargetRun() //Handling change for all the guns on client for(var/obj/item/weapon/gun/G in src) G.lock_time = world.time + 5 - if(G.target) - for(var/mob/living/M in G.target) + if(G.aim_targets) + for(var/mob/living/M in G.aim_targets) if(target_can_run) M << "Your character may now run at the discretion of their targeter." else M << "\red Your character will now be shot if they run." -client/verb/AllowTargetClick() +/client/verb/AllowTargetClick() set hidden=1 //Changing client's permissions @@ -370,8 +367,8 @@ client/verb/AllowTargetClick() //Handling change for all the guns on client for(var/obj/item/weapon/gun/G in src) G.lock_time = world.time + 5 - if(G.target) - for(var/mob/living/M in G.target) + if(G.aim_targets) + for(var/mob/living/M in G.aim_targets) if(target_can_click) M << "Your character may now use items at the discretion of their targeter." else