From dc69cf69c0d6b46e21e5f64067faccec1d0ccf45 Mon Sep 17 00:00:00 2001 From: Duck- Date: Sun, 21 Dec 2014 22:49:07 -0500 Subject: [PATCH 1/3] IPCs, prosthetics, suits Fixes suit cooling units so they no longer have infinite power. Made their batteries last much longer, too. Anom suits can now hold suit coolers. Softsuits can now hold large o2 tanks. Prosthetics now malfunction at brute+burn-11% chance so getting your arm scratched doesn't turn you into humpty dumpty. BSTs get a new verb to ruin everything. --- .../objects/items/devices/suit_cooling.dm | 58 +++++++++---------- code/modules/aurora/bluespacetech.dm | 14 +++++ code/modules/clothing/clothing.dm | 2 +- .../clothing/spacesuits/miscellaneous.dm | 2 +- code/modules/organs/organ_external.dm | 2 +- .../xenoarchaeology/tools/anomaly_suit.dm | 2 +- data/investigate/gravity.html | 14 ++++- 7 files changed, 59 insertions(+), 35 deletions(-) diff --git a/code/game/objects/items/devices/suit_cooling.dm b/code/game/objects/items/devices/suit_cooling.dm index 6355fd26..0da99369 100644 --- a/code/game/objects/items/devices/suit_cooling.dm +++ b/code/game/objects/items/devices/suit_cooling.dm @@ -5,57 +5,57 @@ icon = 'icons/obj/device.dmi' icon_state = "suitcooler0" slot_flags = SLOT_BACK //you can carry it on your back if you want, but it won't do anything unless attached to suit storage - + //copied from tank.dm flags = FPRINT | TABLEPASS | CONDUCT force = 5.0 throwforce = 10.0 throw_speed = 1 throw_range = 4 - + origin_tech = "magnets=2;materials=2" - + var/on = 0 //is it turned on? var/cover_open = 0 //is the cover open? var/obj/item/weapon/cell/cell var/max_cooling = 12 //in degrees per second - probably don't need to mess with heat capacity here - var/charge_consumption = 16.6 //charge per second at max_cooling + var/charge_consumption = 2 //16.6 //charge per second at max_cooling //16.6 is the original value. It eats batteries too fast. var/thermostat = T20C - + //TODO: make it heat up the surroundings when not in space /obj/item/device/suit_cooling_unit/New() processing_objects |= src - + cell = new/obj/item/weapon/cell() //comes with the crappy default power cell - high-capacity ones shouldn't be hard to find cell.loc = src /obj/item/device/suit_cooling_unit/process() - if (!on || !cell) + if (!on || !cell) return - + if (!ismob(loc)) return - + if (!attached_to_suit(loc)) //make sure they have a suit and we are attached to it return - + var/mob/living/carbon/human/H = loc - + var/efficiency = 1 - H.get_pressure_weakness() //you need to have a good seal for effective cooling var/env_temp = get_environment_temperature() //wont save you from a fire var/temp_adj = min(H.bodytemperature - max(thermostat, env_temp), max_cooling) - + if (temp_adj < 0.5) //only cools, doesn't heat, also we don't need extreme precision return - + var/charge_usage = (temp_adj/max_cooling)*charge_consumption - + H.bodytemperature -= temp_adj*efficiency - + cell.use(charge_usage) - - if(cell.charge <= 0) + + if(cell.charge <= charge_usage) turn_off() /obj/item/device/suit_cooling_unit/proc/get_environment_temperature() @@ -70,22 +70,22 @@ var/turf/T = get_turf(src) if(istype(T, /turf/space)) return 0 //space has no temperature, this just makes sure the cooling unit works in space - + var/datum/gas_mixture/environment = T.return_air() if (!environment) return 0 - + return environment.temperature /obj/item/device/suit_cooling_unit/proc/attached_to_suit(mob/M) - if (!ishuman(M)) + if (!ishuman(M)) return 0 - + var/mob/living/carbon/human/H = M - + if (!H.wear_suit || H.s_store != src) return 0 - + return 1 /obj/item/device/suit_cooling_unit/proc/turn_on() @@ -93,7 +93,7 @@ return if(cell.charge <= 0) return - + on = 1 updateicon() @@ -149,7 +149,7 @@ user << "You insert the [cell]." updateicon() return - + return ..() /obj/item/device/suit_cooling_unit/proc/updateicon() @@ -163,9 +163,9 @@ /obj/item/device/suit_cooling_unit/examine() set src in view(1) - + ..() - + if (on) if (attached_to_suit(src.loc)) usr << "It's switched on and running." @@ -173,13 +173,13 @@ usr << "It's switched on, but not attached to anything." else usr << "It is switched off." - + if (cover_open) if(cell) usr << "The panel is open, exposing the [cell]." else usr << "The panel is open." - + if (cell) usr << "The charge meter reads [round(cell.percent())]%." else diff --git a/code/modules/aurora/bluespacetech.dm b/code/modules/aurora/bluespacetech.dm index 0de534d1..024a96e5 100644 --- a/code/modules/aurora/bluespacetech.dm +++ b/code/modules/aurora/bluespacetech.dm @@ -256,6 +256,20 @@ var/verb = "says in a subdued tone" ..(message, verb) + verb/bstwalk() + set name = "Ruin Everything" + set desc = "Uses bluespace technology to phase through solid matter and also move fast." + set category = "BST" + set popup_menu = 0 + + if(!src.incorporeal_move) + src.incorporeal_move = 2 + src << "\blue You will now phase through solid matter." + else + src.incorporeal_move = 0 + src << "\blue You will no-longer phase through solid matter." + return + //Equipment. All should have canremove set to 0 //All items with a /bst need the attack_hand() proc overrided to stop people getting overpowered items. diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index b56c078d..3bd9bff6 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -335,7 +335,7 @@ BLIND // can't see anything permeability_coefficient = 0.02 flags = FPRINT | TABLEPASS | STOPSPRESSUREDMAGE | THICKMATERIAL body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS - allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank/emergency_oxygen,/obj/item/device/suit_cooling_unit) + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit) slowdown = 3 armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 50) flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm index c729c4a4..32ff5a09 100644 --- a/code/modules/clothing/spacesuits/miscellaneous.dm +++ b/code/modules/clothing/spacesuits/miscellaneous.dm @@ -22,7 +22,7 @@ allowed = list(/obj/item/weapon/tank/emergency_oxygen, /obj/item/device/flashlight,/obj/item/weapon/gun/energy, /obj/item/weapon/gun/projectile, /obj/item/ammo_magazine, /obj/item/ammo_casing, /obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs) slowdown = 1.5 armor = list(melee = 65, bullet = 50, laser = 50, energy = 25, bomb = 50, bio = 100, rad = 50) - flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE siemens_coefficient = 0.7 diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index 66081658..ce0577ef 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -816,7 +816,7 @@ Note that amputating the affected organ does in fact remove the infection from t return ((status & ORGAN_BROKEN) && !(status & ORGAN_SPLINTED)) /datum/organ/external/proc/is_malfunctioning() - return ((status & ORGAN_ROBOT) && prob(brute_dam + burn_dam)) + return ((status & ORGAN_ROBOT) && prob(brute_dam + burn_dam - 11)) //for arms and hands /datum/organ/external/proc/process_grasp(var/obj/item/c_hand, var/hand_name) diff --git a/code/modules/research/xenoarchaeology/tools/anomaly_suit.dm b/code/modules/research/xenoarchaeology/tools/anomaly_suit.dm index 05e6d02d..48ac8785 100644 --- a/code/modules/research/xenoarchaeology/tools/anomaly_suit.dm +++ b/code/modules/research/xenoarchaeology/tools/anomaly_suit.dm @@ -20,7 +20,7 @@ icon_state = "cespace_suit" item_state = "cespace_suit" armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 100) - allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank) + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank, /obj/item/device/suit_cooling_unit) /obj/item/clothing/head/helmet/space/anomaly name = "Excavation hood" diff --git a/data/investigate/gravity.html b/data/investigate/gravity.html index 4864ca62..cbab9d0b 100644 --- a/data/investigate/gravity.html +++ b/data/investigate/gravity.html @@ -1,2 +1,12 @@ -00:14 [0x20077d3] (92,152,1) || the gravitational generator has regained power.
-00:14 [0x20077d3] (92,152,1) || the gravitational generator is now charging.
+22:30 [0x20078ca] (92,152,1) || the gravitational generator has regained power.
+22:30 [0x20078ca] (92,152,1) || the gravitational generator is now charging.
+22:31 [0x20078ca] (92,152,1) || the gravitational generator has regained power.
+22:31 [0x20078ca] (92,152,1) || the gravitational generator is now charging.
+22:31 [0x20078ca] (92,152,1) || the gravitational generator has regained power.
+22:31 [0x20078ca] (92,152,1) || the gravitational generator is now charging.
+22:36 [0x20078ca] (92,152,1) || the gravitational generator has regained power.
+22:36 [0x20078ca] (92,152,1) || the gravitational generator is now charging.
+22:41 [0x20078ca] (92,152,1) || the gravitational generator has regained power.
+22:41 [0x20078ca] (92,152,1) || the gravitational generator is now charging.
+22:45 [0x20078ca] (92,152,1) || the gravitational generator has regained power.
+22:45 [0x20078ca] (92,152,1) || the gravitational generator is now charging.
From 0b344ff76a1532cae792b9117b7c4b1c82862b2c Mon Sep 17 00:00:00 2001 From: Duck- Date: Mon, 22 Dec 2014 00:31:54 -0500 Subject: [PATCH 2/3] TRAINS CHOO CHOO --- aurora.dme | 3 + code/datums/supplypacks.dm | 16 + code/game/objects/items/weapons/cards_ids.dm | 9 +- code/modules/mob/living/carbon/human/human.dm | 3 +- code/modules/mob/mob_movement.dm | 6 +- code/modules/vehicles/cargo_train.dm | 303 +++++++++++++++ code/modules/vehicles/train.dm | 229 +++++++++++ code/modules/vehicles/vehicle.dm | 358 ++++++++++++++++++ data/investigate/gravity.html | 30 +- icons/obj/vehicles.dmi | Bin 6970 -> 10594 bytes 10 files changed, 938 insertions(+), 19 deletions(-) create mode 100644 code/modules/vehicles/cargo_train.dm create mode 100644 code/modules/vehicles/train.dm create mode 100644 code/modules/vehicles/vehicle.dm diff --git a/aurora.dme b/aurora.dme index 858cb0a4..c1df4764 100644 --- a/aurora.dme +++ b/aurora.dme @@ -1441,6 +1441,9 @@ #include "code\modules\telesci\gps.dm" #include "code\modules\telesci\telepad.dm" #include "code\modules\telesci\telesci_computer.dm" +#include "code\modules\vehicles\cargo_train.dm" +#include "code\modules\vehicles\train.dm" +#include "code\modules\vehicles\vehicle.dm" #include "code\modules\virus2\analyser.dm" #include "code\modules\virus2\antibodies.dm" #include "code\modules\virus2\centrifuge.dm" diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm index f09a659a..6616fda5 100644 --- a/code/datums/supplypacks.dm +++ b/code/datums/supplypacks.dm @@ -251,6 +251,22 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee containername = "MULEbot Crate" group = "Operations" +/datum/supply_packs/cargotrain + name = "Cargo Train Tug" + contains = list(/obj/vehicle/train/cargo/engine) + cost = 30 + containertype = /obj/structure/largecrate + containername = "Cargo Train Tug Crate" + group = "Operations" + +/datum/supply_packs/cargotrailer + name = "Cargo Train Trolley" + contains = list(/obj/vehicle/train/cargo/trolley) + cost = 20 + containertype = /obj/structure/largecrate + containername = "Cargo Train Trolley Crate" + group = "Operations" + /datum/supply_packs/lisa name = "Corgi Crate" contains = list() diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index 931edd3d..71b1629f 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -100,7 +100,8 @@ /obj/machinery/bot, /obj/machinery/door, /obj/machinery/telecomms, - /obj/machinery/mecha_part_fabricator + /obj/machinery/mecha_part_fabricator, + /obj/vehicle ) @@ -200,7 +201,7 @@ access = list(access_maint_tunnels, access_syndicate, access_external_airlocks) origin_tech = "syndicate=3" var/registered_user=null - + /obj/item/weapon/card/id/syndicate/New(mob/user as mob) ..() if(!isnull(user)) // Runtime prevention on laggy starts or where users log out because of lag at round start. @@ -208,7 +209,7 @@ else registered_name = "Agent Card" assignment = "Agent" - name = "[registered_name]'s ID Card ([assignment])" + name = "[registered_name]'s ID Card ([assignment])" /obj/item/weapon/card/id/syndicate/afterattack(var/obj/item/weapon/O as obj, mob/user as mob, proximity) if(!proximity) return @@ -239,7 +240,7 @@ registered_user = user else if(!registered_user || registered_user == user) - if(!registered_user) registered_user = user // + if(!registered_user) registered_user = user // switch(alert("Would you like to display the ID, or retitle it?","Choose.","Rename","Show")) if("Rename") diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 6d81acee..49f0c755 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -478,10 +478,9 @@ var/obj/machinery/bot/mulebot/MB = AM MB.RunOver(src) -/* if(istype(AM, /obj/vehicle)) + if(istype(AM, /obj/vehicle)) var/obj/vehicle/V = AM V.RunOver(src) -*/ //gets assignment from ID or ID inside PDA or PDA itself //Useful when player do something with computers diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index ca8015e6..3e58626b 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -203,7 +203,8 @@ if(!mob.canmove) - return + if (mob.buckled && (istype(mob.buckled, /obj/structure/stool/bed/chair/wheelchair) || istype(mob.buckled, /obj/vehicle))) // Exception for wheelchairs + else return //if(istype(mob.loc, /turf/space) || (mob.flags & NOGRAV)) // if(!mob.Process_Spacemove(0)) return 0 @@ -257,6 +258,9 @@ if(mob.machine.relaymove(mob,direct)) return + if(istype(mob.buckled, /obj/vehicle)) + return mob.buckled.relaymove(mob,direct) + if(mob.pulledby || mob.buckled) // Wheelchair driving! if(istype(mob.loc, /turf/space)) return // No wheelchair driving in space diff --git a/code/modules/vehicles/cargo_train.dm b/code/modules/vehicles/cargo_train.dm new file mode 100644 index 00000000..ea3f7b72 --- /dev/null +++ b/code/modules/vehicles/cargo_train.dm @@ -0,0 +1,303 @@ +/obj/vehicle/train/cargo/engine + name = "cargo train tug" + desc = "A ridable electric car designed for pulling cargo trolleys." + icon = 'icons/obj/vehicles.dmi' + icon_state = "cargo_engine" + on = 0 + powered = 1 + locked = 0 + + load_item_visible = 1 + load_offset_x = 0 + mob_offset_y = 7 + + var/car_limit = 3 //how many cars an engine can pull before performance degrades + active_engines = 1 + var/obj/item/weapon/key/cargo_train/key + +/obj/item/weapon/key/cargo_train + name = "key" + desc = "A keyring with a small steel key, and a yellow fob reading \"Choo Choo!\"." + icon = 'icons/obj/vehicles.dmi' + icon_state = "train_keys" + w_class = 1 + +/obj/vehicle/train/cargo/trolley + name = "cargo train trolley" + icon = 'icons/obj/vehicles.dmi' + icon_state = "cargo_trailer" + anchored = 0 + passenger_allowed = 0 + locked = 0 + + load_item_visible = 1 + load_offset_x = 0 + load_offset_y = 4 + mob_offset_y = 8 + +//------------------------------------------- +// Standard procs +//------------------------------------------- +/obj/vehicle/train/cargo/engine/New() + ..() + cell = new /obj/item/weapon/cell/high + verbs -= /atom/movable/verb/pull + key = new() + var/image/I = new(icon = 'icons/obj/vehicles.dmi', icon_state = "cargo_engine_overlay", layer = src.layer + 0.2) //over mobs + overlays += I + turn_off() //so engine verbs are correctly set + +/obj/vehicle/train/cargo/engine/Move() + if(on && cell.charge < charge_use) + turn_off() + update_stats() + if(load && is_train_head()) + load << "The drive motor briefly whines, then drones to a stop." + + if(is_train_head() && !on) + return 0 + + return ..() + +/obj/vehicle/train/cargo/trolley/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(open && istype(W, /obj/item/weapon/wirecutters)) + passenger_allowed = !passenger_allowed + user.visible_message("[user] [passenger_allowed ? "cuts" : "mends"] a cable in [src].","You [passenger_allowed ? "cut" : "mend"] the load limiter cable.") + else + ..() + +/obj/vehicle/train/cargo/engine/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/key/cargo_train)) + if(!key) + user.drop_item() + W.forceMove(src) + key = W + verbs += /obj/vehicle/train/cargo/engine/verb/remove_key + return + ..() + +/obj/vehicle/train/cargo/update_icon() + if(open) + icon_state = initial(icon_state) + "_open" + else + icon_state = initial(icon_state) + +/obj/vehicle/train/cargo/trolley/insert_cell(var/obj/item/weapon/cell/C, var/mob/living/carbon/human/H) + return + +/obj/vehicle/train/cargo/engine/insert_cell(var/obj/item/weapon/cell/C, var/mob/living/carbon/human/H) + ..() + update_stats() + +/obj/vehicle/train/cargo/engine/remove_cell(var/mob/living/carbon/human/H) + ..() + update_stats() + +/obj/vehicle/train/cargo/engine/Bump(atom/Obstacle) + var/obj/machinery/door/D = Obstacle + var/mob/living/carbon/human/H = load + if(istype(D) && istype(H)) + D.Bumped(H) //a little hacky, but hey, it works, and respects access rights + + ..() + +/obj/vehicle/train/cargo/trolley/Bump(atom/Obstacle) + if(!lead) + return //so people can't knock others over by pushing a trolley around + ..() + +//------------------------------------------- +// Train procs +//------------------------------------------- +/obj/vehicle/train/cargo/engine/turn_on() + if(!key) + return + else + ..() + update_stats() + + verbs -= /obj/vehicle/train/cargo/engine/verb/stop_engine + verbs -= /obj/vehicle/train/cargo/engine/verb/start_engine + + if(on) + verbs += /obj/vehicle/train/cargo/engine/verb/stop_engine + else + verbs += /obj/vehicle/train/cargo/engine/verb/start_engine + +/obj/vehicle/train/cargo/engine/turn_off() + ..() + + verbs -= /obj/vehicle/train/cargo/engine/verb/stop_engine + verbs -= /obj/vehicle/train/cargo/engine/verb/start_engine + + if(!on) + verbs += /obj/vehicle/train/cargo/engine/verb/start_engine + else + verbs += /obj/vehicle/train/cargo/engine/verb/stop_engine + +/obj/vehicle/train/cargo/RunOver(var/mob/living/carbon/human/H) + var/list/parts = list("head", "chest", "l_leg", "r_leg", "l_arm", "r_arm") + + H.apply_effects(5, 5) + for(var/i = 0, i < rand(1,3), i++) + H.apply_damage(rand(1,5), BRUTE, pick(parts)) + +/obj/vehicle/train/cargo/trolley/RunOver(var/mob/living/carbon/human/H) + ..() + attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey])") + +/obj/vehicle/train/cargo/engine/RunOver(var/mob/living/carbon/human/H) + ..() + + if(is_train_head() && istype(load, /mob/living/carbon/human)) + var/mob/living/carbon/human/D = load + D << "\red \b You ran over [H]!" + visible_message("\red \The [src] ran over [H]!") + attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey]), driven by [D.name] ([D.ckey])") + msg_admin_attack("[D.name] ([D.ckey]) ran over [H.name] ([H.ckey]). (JMP)") + else + attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey])") + + +//------------------------------------------- +// Interaction procs +//------------------------------------------- +/obj/vehicle/train/cargo/engine/relaymove(mob/user, direction) + if(user != load) + return 0 + + if(is_train_head()) + if(direction == reverse_direction(dir) && tow) + return 0 + if(Move(get_step(src, direction))) + return 1 + return 0 + else + return ..() + +/obj/vehicle/train/cargo/engine/examine() + ..() + + if(!istype(usr, /mob/living/carbon/human)) + return + + if(get_dist(usr,src) <= 1) + usr << "The power light is [on ? "on" : "off"].\nThere are[key ? "" : " no"] keys in the ignition." + usr << "The charge meter reads [cell? round(cell.percent(), 0.01) : 0]%" + +/obj/vehicle/train/cargo/engine/verb/start_engine() + set name = "Start engine" + set category = "Object" + set src in view(1) + + if(!istype(usr, /mob/living/carbon/human)) + return + + if(on) + usr << "The engine is already running." + return + + turn_on() + if (on) + usr << "You start [src]'s engine." + else + if(cell.charge < charge_use) + usr << "[src] is out of power." + else + usr << "[src]'s engine won't start." + +/obj/vehicle/train/cargo/engine/verb/stop_engine() + set name = "Stop engine" + set category = "Object" + set src in view(1) + + if(!istype(usr, /mob/living/carbon/human)) + return + + if(!on) + usr << "The engine is already stopped." + return + + turn_off() + if (!on) + usr << "You stop [src]'s engine." + +/obj/vehicle/train/cargo/engine/verb/remove_key() + set name = "Remove key" + set category = "Object" + set src in view(1) + + if(!istype(usr, /mob/living/carbon/human)) + return + + if(!key || (load && load != usr)) + return + + if(on) + turn_off() + + key.loc = usr.loc + if(!usr.get_active_hand()) + usr.put_in_hands(key) + key = null + + verbs -= /obj/vehicle/train/cargo/engine/verb/remove_key + +//------------------------------------------- +// Loading/unloading procs +//------------------------------------------- +/obj/vehicle/train/cargo/trolley/load(var/atom/movable/C) + if(ismob(C) && !passenger_allowed) + return 0 + if(!istype(C,/obj/machinery) && !istype(C,/obj/structure/closet) && !istype(C,/obj/structure/largecrate) && !istype(C,/obj/structure/reagent_dispensers) && !istype(C,/obj/structure/ore_box) && !istype(C, /mob/living/carbon/human)) + return 0 + + ..() + + if(load) + return 1 + +/obj/vehicle/train/cargo/engine/load(var/atom/movable/C) + if(!istype(C, /mob/living/carbon/human)) + return 0 + + return ..() + + +//------------------------------------------------------- +// Stat update procs +// +// Update the trains stats for speed calculations. +// The longer the train, the slower it will go. car_limit +// sets the max number of cars one engine can pull at +// full speed. Adding more cars beyond this will slow the +// train proportionate to the length of the train. Adding +// more engines increases this limit by car_limit per +// engine. +//------------------------------------------------------- +/obj/vehicle/train/cargo/engine/update_car(var/train_length, var/active_engines) + src.train_length = train_length + src.active_engines = active_engines + + //Update move delay + if(!is_train_head() || !on) + move_delay = initial(move_delay) //so that engines that have been turned off don't lag behind + else + move_delay = max(0, (-car_limit * active_engines) + train_length - active_engines) //limits base overweight so you cant overspeed trains + move_delay *= (1 / max(1, active_engines)) * 2 //overweight penalty (scaled by the number of engines) + move_delay += config.run_speed //base reference speed + move_delay *= 1.1 //makes cargo trains 10% slower than running when not overweight + +/obj/vehicle/train/cargo/trolley/update_car(var/train_length, var/active_engines) + src.train_length = train_length + src.active_engines = active_engines + + if(!lead && !tow) + anchored = 0 + if(verbs.Find(/atom/movable/verb/pull)) + return + else + verbs += /atom/movable/verb/pull + else + anchored = 1 + verbs -= /atom/movable/verb/pull diff --git a/code/modules/vehicles/train.dm b/code/modules/vehicles/train.dm new file mode 100644 index 00000000..d8e372d8 --- /dev/null +++ b/code/modules/vehicles/train.dm @@ -0,0 +1,229 @@ +/obj/vehicle/train + name = "train" + dir = 4 + + move_delay = 1 + + health = 100 + maxhealth = 100 + fire_dam_coeff = 0.7 + brute_dam_coeff = 0.5 + + var/passenger_allowed = 1 + + var/active_engines = 0 + var/train_length = 0 + + var/obj/vehicle/train/lead + var/obj/vehicle/train/tow + + +//------------------------------------------- +// Standard procs +//------------------------------------------- +/obj/vehicle/train/initialize() + for(var/obj/vehicle/train/T in orange(1, src)) + latch(T) + +/obj/vehicle/train/Move() + var/old_loc = get_turf(src) + if(..()) + if(tow) + tow.Move(old_loc) + return 1 + else + if(lead) + unattach() + return 0 + +/obj/vehicle/train/Bump(atom/Obstacle) + if(!istype(Obstacle, /atom/movable)) + return + var/atom/movable/A = Obstacle + + if(!A.anchored) + var/turf/T = get_step(A, dir) + if(isturf(T)) + A.Move(T) //bump things away when hit + + if(emagged) + if(istype(A, /mob/living)) + var/mob/living/M = A + visible_message("\red [src] knocks over [M]!") + M.apply_effects(5, 5) //knock people down if you hit them + M.apply_damages(22 / move_delay) // and do damage according to how fast the train is going + if(istype(load, /mob/living/carbon/human)) + var/mob/living/D = load + D << "\red You hit [M]!" + msg_admin_attack("[D.name] ([D.ckey]) hit [M.name] ([M.ckey]) with [src]. (JMP)") + + +//------------------------------------------- +// Vehicle procs +//------------------------------------------- +/obj/vehicle/train/explode() + if (tow) + tow.unattach() + unattach() + ..() + + +//------------------------------------------- +// Interaction procs +//------------------------------------------- +/obj/vehicle/train/relaymove(mob/user, direction) + var/turf/T = get_step_to(src, get_step(src, direction)) + if(!T) + user << "You can't find a clear area to step onto." + return 0 + + if(user != load) + if(user in src) //for handling players stuck in src - this shouldn't happen - but just in case it does + user.forceMove(T) + return 1 + return 0 + + unload(user, direction) + + user << "\blue You climb down from [src]." + + return 1 + +/obj/vehicle/train/MouseDrop_T(var/atom/movable/C, mob/user as mob) + if(user.buckled || user.stat || user.restrained() || !Adjacent(user) || !user.Adjacent(C) || !istype(C) || (user == C && !user.canmove)) + return + if(istype(C,/obj/vehicle/train)) + latch(C, user) + else + if(!load(C)) + user << "\red You were unable to load [C] on [src]." + +/obj/vehicle/train/attack_hand(mob/user as mob) + if(user.stat || user.restrained() || !Adjacent(user)) + return 0 + + if(user != load && (user in src)) + user.forceMove(loc) //for handling players stuck in src + else if(load) + unload(user) //unload if loaded + else if(!load && !user.buckled) + load(user) //else try climbing on board + else + return 0 + +/obj/vehicle/train/verb/unlatch_v() + set name = "Unlatch" + set desc = "Unhitches this train from the one in front of it." + set category = "Object" + set src in view(1) + + if(!istype(usr, /mob/living/carbon/human)) + return + + if(!usr.canmove || usr.stat || usr.restrained() || !Adjacent(usr)) + return + + unattach(usr) + + +//------------------------------------------- +// Latching/unlatching procs +//------------------------------------------- + +//attempts to attach src as a follower of the train T +/obj/vehicle/train/proc/attach_to(obj/vehicle/train/T, mob/user) + if (get_dist(src, T) > 1) + user << "\red [src] is too far away from [T] to hitch them together." + return + + if (lead) + user << "\red [src] is already hitched to something." + return + + if (T.tow) + user << "\red [T] is already towing something." + return + + //check for cycles. + var/obj/vehicle/train/next_car = T + while (next_car) + if (next_car == src) + user << "\red That seems very silly." + return + next_car = next_car.lead + + //latch with src as the follower + lead = T + T.tow = src + dir = lead.dir + + if(user) + user << "\blue You hitch [src] to [T]." + + update_stats() + + +//detaches the train from whatever is towing it +/obj/vehicle/train/proc/unattach(mob/user) + if (!lead) + user << "\red [src] is not hitched to anything." + return + + lead.tow = null + lead.update_stats() + + user << "\blue You unhitch [src] from [lead]." + lead = null + + update_stats() + +/obj/vehicle/train/proc/latch(obj/vehicle/train/T, mob/user) + if(!istype(T) || !Adjacent(T)) + return 0 + + var/T_dir = get_dir(src, T) //figure out where T is wrt src + + if(dir == T_dir) //if car is ahead + src.attach_to(T, user) + else if(reverse_direction(dir) == T_dir) //else if car is behind + T.attach_to(src, user) + +//returns 1 if this is the lead car of the train +/obj/vehicle/train/proc/is_train_head() + if (lead) + return 0 + return 1 + +//------------------------------------------------------- +// Stat update procs +// +// Used for updating the stats for how long the train is. +// These are useful for calculating speed based on the +// size of the train, to limit super long trains. +//------------------------------------------------------- +/obj/vehicle/train/update_stats() + //first, seek to the end of the train + var/obj/vehicle/train/T = src + while(T.tow) + //check for cyclic train. + if (T.tow == src) + lead.tow = null + lead.update_stats() + + lead = null + update_stats() + return + T = T.tow + + //now walk back to the front. + var/active_engines = 0 + var/train_length = 0 + while(T) + train_length++ + if (powered && on) + active_engines++ + T.update_car(train_length, active_engines) + T = T.lead + +/obj/vehicle/train/proc/update_car(var/train_length, var/active_engines) + return diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm new file mode 100644 index 00000000..76fd7d89 --- /dev/null +++ b/code/modules/vehicles/vehicle.dm @@ -0,0 +1,358 @@ +/obj/vehicle + name = "vehicle" + icon = 'icons/obj/vehicles.dmi' + layer = MOB_LAYER + 0.1 //so it sits above objects including mobs + density = 1 + anchored = 1 + animate_movement=1 + luminosity = 3 + + var/attack_log = null + var/on = 0 + var/health = 0 //do not forget to set health for your vehicle! + var/maxhealth = 0 + var/fire_dam_coeff = 1.0 + var/brute_dam_coeff = 1.0 + var/open = 0 //Maint panel + var/locked = 1 + var/stat = 0 + var/emagged = 0 + var/powered = 0 //set if vehicle is powered and should use fuel when moving + var/move_delay = 1 //set this to limit the speed of the vehicle + var/movable = 1 + + var/obj/item/weapon/cell/cell + var/charge_use = 5 //set this to adjust the amount of power the vehicle uses per move + + var/atom/movable/load //all vehicles can take a load, since they should all be a least drivable + var/load_item_visible = 1 //set if the loaded item should be overlayed on the vehicle sprite + var/load_offset_x = 0 //pixel_x offset for item overlay + var/load_offset_y = 0 //pixel_y offset for item overlay + var/mob_offset_y = 0 //pixel_y offset for mob overlay + +//------------------------------------------- +// Standard procs +//------------------------------------------- +/obj/vehicle/New() + ..() + //spawn the cell you want in each vehicle + +/obj/vehicle/Move() + if(world.time > l_move_time + move_delay) + if(on && powered && cell.charge < charge_use) + turn_off() + + var/init_anc = anchored + anchored = 0 + if(!..()) + anchored = init_anc + return 0 + + anchored = init_anc + + if(on && powered) + cell.use(charge_use) + + if(load) + load.forceMove(loc)// = loc + load.dir = dir + + return 1 + else + return 0 + +/obj/vehicle/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/hand_labeler)) + return + if(istype(W, /obj/item/weapon/screwdriver)) + if(!locked) + open = !open + update_icon() + user << "Maintenance panel is now [open ? "opened" : "closed"]." + else if(istype(W, /obj/item/weapon/crowbar) && cell && open) + remove_cell(user) + + else if(istype(W, /obj/item/weapon/cell) && !cell && open) + insert_cell(W, user) + else if(istype(W, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/T = W + if(T.welding) + if(health < maxhealth) + if(open) + health = min(maxhealth, health+10) + user.visible_message("\red [user] repairs [src]!","\blue You repair [src]!") + else + user << "Unable to repair with the maintenance panel closed." + else + user << "[src] does not need a repair." + else + user << "Unable to repair while [src] is off." + else if(istype(W, /obj/item/weapon/card/emag) && !emagged) + Emag(user) + else if(hasvar(W,"force") && hasvar(W,"damtype")) + switch(W.damtype) + if("fire") + health -= W.force * fire_dam_coeff + if("brute") + health -= W.force * brute_dam_coeff + ..() + healthcheck() + else + ..() + +/obj/vehicle/attack_animal(var/mob/living/simple_animal/M as mob) + if(M.melee_damage_upper == 0) return + health -= M.melee_damage_upper + src.visible_message("\red [M] has [M.attacktext] [src]!") + M.attack_log += text("\[[time_stamp()]\] attacked [src.name]") + if(prob(10)) + new /obj/effect/decal/cleanable/blood/oil(src.loc) + healthcheck() + +/obj/vehicle/bullet_act(var/obj/item/projectile/Proj) + health -= Proj.damage + ..() + healthcheck() + +/obj/vehicle/meteorhit() + explode() + return + +/obj/vehicle/blob_act() + src.health -= rand(20,40)*fire_dam_coeff + healthcheck() + return + +/obj/vehicle/ex_act(severity) + switch(severity) + if(1.0) + explode() + return + if(2.0) + health -= rand(5,10)*fire_dam_coeff + health -= rand(10,20)*brute_dam_coeff + healthcheck() + return + if(3.0) + if (prob(50)) + health -= rand(1,5)*fire_dam_coeff + health -= rand(1,5)*brute_dam_coeff + healthcheck() + return + return + +/obj/vehicle/emp_act(severity) + var/was_on = on + stat |= EMPED + var/obj/effect/overlay/pulse2 = new/obj/effect/overlay ( src.loc ) + pulse2.icon = 'icons/effects/effects.dmi' + pulse2.icon_state = "empdisable" + pulse2.name = "emp sparks" + pulse2.anchored = 1 + pulse2.dir = pick(cardinal) + + spawn(10) + pulse2.delete() + if(on) + turn_off() + spawn(severity*300) + stat &= ~EMPED + if(was_on) + turn_on() + +/obj/vehicle/attack_ai(mob/user as mob) + return + +/obj/vehicle/proc/handle_rotation() + return + +//------------------------------------------- +// Vehicle procs +//------------------------------------------- +/obj/vehicle/proc/turn_on() + if(stat) + return 0 + if(powered && cell.charge < charge_use) + return 0 + on = 1 + luminosity = initial(luminosity) + update_icon() + return 1 + +/obj/vehicle/proc/turn_off() + on = 0 + luminosity = 0 + update_icon() + +/obj/vehicle/proc/Emag(mob/user as mob) + emagged = 1 + + if(locked) + locked = 0 + user << "You bypass [src]'s controls." + +/obj/vehicle/proc/explode() + src.visible_message("\red [src] blows apart!", 1) + var/turf/Tsec = get_turf(src) + + new /obj/item/stack/rods(Tsec) + new /obj/item/stack/rods(Tsec) +// new /obj/item/stack/cable_coil/cut(Tsec) THIS DOESN'T WORK SO I'M GETTING RID OF IT. + + if(cell) + cell.forceMove(Tsec) + cell.update_icon() + cell = null + + //stuns people who are thrown off a train that has been blown up + if(istype(load, /mob/living)) + var/mob/living/M = load + M.apply_effects(5, 5) + + unload() + + new /obj/effect/gibspawner/robot(Tsec) + new /obj/effect/decal/cleanable/blood/oil(src.loc) + + del(src) + +/obj/vehicle/proc/healthcheck() + if(health <= 0) + explode() + +/obj/vehicle/proc/powercheck() + if(!cell && !powered) + return + + if(!cell && powered) + turn_off() + return + + if(cell.charge < charge_use) + turn_off() + return + + if(cell && powered) + turn_on() + return + +/obj/vehicle/proc/insert_cell(var/obj/item/weapon/cell/C, var/mob/living/carbon/human/H) + if(cell) + return + if(!istype(C)) + return + + H.drop_from_inventory(C) + C.forceMove(src) + cell = C + powercheck() + usr << "You install [C] in [src]." + +/obj/vehicle/proc/remove_cell(var/mob/living/carbon/human/H) + if(!cell) + return + + usr << "You remove [cell] from [src]." + cell.forceMove(get_turf(H)) + H.put_in_hands(cell) + cell = null + powercheck() + +/obj/vehicle/proc/RunOver(var/mob/living/carbon/human/H) + return //write specifics for different vehicles + +//------------------------------------------- +// Loading/unloading procs +// +// Set specific item restriction checks in +// the vehicle load() definition before +// calling this parent proc. +//------------------------------------------- +/obj/vehicle/proc/load(var/atom/movable/C) + //define allowed items for loading in specific vehicle definitions + + if(!isturf(C.loc)) //To prevent loading things from someone's inventory, which wouldn't get handled properly. + return 0 + if(load || C.anchored) + return 0 + + // if a create/closet, close before loading + var/obj/structure/closet/crate = C + if(istype(crate)) + crate.close() + + C.forceMove(loc) + C.dir = dir + C.anchored = 1 + + load = C + + if(load_item_visible) + C.pixel_x += load_offset_x + if(ismob(C)) + C.pixel_y += mob_offset_y + else + C.pixel_y += load_offset_y + C.layer = layer + 0.1 //so it sits above the vehicle + + if(ismob(C)) + var/mob/M = C + M.buckled = src + M.update_canmove() + + return 1 + + +/obj/vehicle/proc/unload(var/mob/user, var/direction) + if(!load) + return + + var/turf/dest = null + + //find a turf to unload to + if(direction) //if direction specified, unload in that direction + dest = get_step(src, direction) + else if(user) //if a user has unloaded the vehicle, unload at their feet + dest = get_turf(user) + + if(!dest) + dest = get_step_to(src, get_step(src, turn(dir, 90))) //try unloading to the side of the vehicle first if neither of the above are present + + //if these all result in the same turf as the vehicle or nullspace, pick a new turf with open space + if(!dest || dest == get_turf(src)) + var/list/options = new() + for(var/test_dir in alldirs) + var/new_dir = get_step_to(src, get_step(src, test_dir)) + if(new_dir && load.Adjacent(new_dir)) + options += new_dir + if(options.len) + dest = pick(options) + else + dest = get_turf(src) //otherwise just dump it on the same turf as the vehicle + + if(!isturf(dest)) //if there still is nowhere to unload, cancel out since the vehicle is probably in nullspace + return 0 + + load.forceMove(dest) + load.dir = get_dir(loc, dest) + load.anchored = initial(load.anchored) + load.pixel_x = initial(load.pixel_x) + load.pixel_y = initial(load.pixel_y) + load.layer = initial(load.layer) + + if(ismob(load)) + var/mob/M = load + M.buckled = null + M.anchored = initial(M.anchored) + M.update_canmove() + + load = null + + return 1 + + +//------------------------------------------------------- +// Stat update procs +//------------------------------------------------------- +/obj/vehicle/proc/update_stats() + return \ No newline at end of file diff --git a/data/investigate/gravity.html b/data/investigate/gravity.html index cbab9d0b..7166030e 100644 --- a/data/investigate/gravity.html +++ b/data/investigate/gravity.html @@ -1,12 +1,18 @@ -22:30 [0x20078ca] (92,152,1) || the gravitational generator has regained power.
-22:30 [0x20078ca] (92,152,1) || the gravitational generator is now charging.
-22:31 [0x20078ca] (92,152,1) || the gravitational generator has regained power.
-22:31 [0x20078ca] (92,152,1) || the gravitational generator is now charging.
-22:31 [0x20078ca] (92,152,1) || the gravitational generator has regained power.
-22:31 [0x20078ca] (92,152,1) || the gravitational generator is now charging.
-22:36 [0x20078ca] (92,152,1) || the gravitational generator has regained power.
-22:36 [0x20078ca] (92,152,1) || the gravitational generator is now charging.
-22:41 [0x20078ca] (92,152,1) || the gravitational generator has regained power.
-22:41 [0x20078ca] (92,152,1) || the gravitational generator is now charging.
-22:45 [0x20078ca] (92,152,1) || the gravitational generator has regained power.
-22:45 [0x20078ca] (92,152,1) || the gravitational generator is now charging.
+23:57 [0x200793a] (92,152,1) || the gravitational generator has regained power.
+23:57 [0x200793a] (92,152,1) || the gravitational generator is now charging.
+23:57 [0x200793a] (92,152,1) || the gravitational generator has regained power.
+23:57 [0x200793a] (92,152,1) || the gravitational generator is now charging.
+23:58 [0x200793a] (92,152,1) || the gravitational generator has regained power.
+23:58 [0x200793a] (92,152,1) || the gravitational generator is now charging.
+00:03 [0x200793a] (92,152,1) || the gravitational generator has regained power.
+00:03 [0x200793a] (92,152,1) || the gravitational generator is now charging.
+00:08 [0x200793a] (92,152,1) || the gravitational generator has regained power.
+00:08 [0x200793a] (92,152,1) || the gravitational generator is now charging.
+00:12 [0x200793a] (92,152,1) || the gravitational generator has regained power.
+00:12 [0x200793a] (92,152,1) || the gravitational generator is now charging.
+00:17 [0x200793a] (92,152,1) || the gravitational generator has regained power.
+00:17 [0x200793a] (92,152,1) || the gravitational generator is now charging.
+00:22 [0x200793a] (92,152,1) || the gravitational generator has regained power.
+00:22 [0x200793a] (92,152,1) || the gravitational generator is now charging.
+00:27 [0x200793a] (92,152,1) || the gravitational generator has regained power.
+00:27 [0x200793a] (92,152,1) || the gravitational generator is now charging.
diff --git a/icons/obj/vehicles.dmi b/icons/obj/vehicles.dmi index fd6daee8bd4b59531061149219c3ccd5e641631f..e70275591fc4ea810bbdf564cc1ad63db9bbad72 100644 GIT binary patch literal 10594 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 bpsMmHsSvRVSf+W literal 6970 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 Date: Tue, 23 Dec 2014 00:53:22 -0500 Subject: [PATCH 3/3] Reloadable lasers- needs sprites Reloadable lasers plus upgrade thing stuff. Tested, works. Not added to game yet. Not twohanded yet-- maybe we should leave it onehanded? Numbers for the laser are still up in the air. It's pretty neat. You can load it with different types of lasers and stuff. --- aurora.dme | 1 + .../projectiles/guns/energy/erifles.dm | 2 +- code/modules/projectiles/guns/energy/laser.dm | 2 +- code/modules/projectiles/guns/projectile.dm | 4 +- .../guns/projectile/reloadlaser.dm | 179 ++++++++++++++++++ code/modules/projectiles/projectile.dm | 2 +- code/modules/projectiles/projectile/beams.dm | 7 +- code/modules/projectiles/projectile/energy.dm | 27 +++ code/modules/vehicles/cargo_train.dm | 20 +- code/modules/vehicles/train.dm | 20 +- data/investigate/gravity.html | 24 +-- 11 files changed, 243 insertions(+), 45 deletions(-) create mode 100644 code/modules/projectiles/guns/projectile/reloadlaser.dm diff --git a/aurora.dme b/aurora.dme index c1df4764..d823f29d 100644 --- a/aurora.dme +++ b/aurora.dme @@ -1275,6 +1275,7 @@ #include "code\modules\projectiles\guns\projectile\bow.dm" #include "code\modules\projectiles\guns\projectile\pistol.dm" #include "code\modules\projectiles\guns\projectile\pneumatic.dm" +#include "code\modules\projectiles\guns\projectile\reloadlaser.dm" #include "code\modules\projectiles\guns\projectile\revolver.dm" #include "code\modules\projectiles\guns\projectile\rocket.dm" #include "code\modules\projectiles\guns\projectile\shotgun.dm" diff --git a/code/modules/projectiles/guns/energy/erifles.dm b/code/modules/projectiles/guns/energy/erifles.dm index 96eadadf..4d12c857 100644 --- a/code/modules/projectiles/guns/energy/erifles.dm +++ b/code/modules/projectiles/guns/energy/erifles.dm @@ -52,7 +52,7 @@ ///////////LASER RIFLE////////////// /obj/item/weapon/gun/energy/rifle/laser name = "laser rifle" - desc = "a basic weapon designed kill with concentrated energy bolts" + desc = "a basic weapon designed to kill with concentrated energy bolts" icon_state = "laser" item_state = "laser" fire_sound = 'sound/weapons/Laser.ogg' diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index a9b5b86c..e912275a 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -1,6 +1,6 @@ /obj/item/weapon/gun/energy/laser name = "laser rifle" - desc = "a basic weapon designed kill with concentrated energy bolts" + desc = "a basic weapon designed to kill with concentrated energy bolts" icon_state = "laser" item_state = "laser" fire_sound = 'sound/weapons/Laser.ogg' diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm index 2ce69211..7172382e 100644 --- a/code/modules/projectiles/guns/projectile.dm +++ b/code/modules/projectiles/guns/projectile.dm @@ -38,12 +38,14 @@ loaded -= AC //Remove casing from loaded list. if(isnull(AC) || !istype(AC)) return 0 - AC.loc = get_turf(src) //Eject casing onto ground. + if(ejectshell == 1) + AC.loc = get_turf(src) //Eject casing onto ground. If 0, casings stay in the gun. Totally a good idea trust me okay. if(AC.BB) AC.desc += " This one is spent." //descriptions are magic - only when there's a projectile in the casing in_chamber = AC.BB //Load projectile into chamber. AC.BB.loc = src //Set projectile loc to gun. return 1 + return 0 diff --git a/code/modules/projectiles/guns/projectile/reloadlaser.dm b/code/modules/projectiles/guns/projectile/reloadlaser.dm new file mode 100644 index 00000000..39da20cd --- /dev/null +++ b/code/modules/projectiles/guns/projectile/reloadlaser.dm @@ -0,0 +1,179 @@ +/obj/item/weapon/gun/projectile/laser //butts + desc = "a basic weapon designed to kill with concentrated energy bolts." + name = "laser rifle" + caliber = "laser" + w_class = 3.0 + recoil = 0 + ammo_type = "/obj/item/ammo_casing/laser" + max_shells = 100 + load_method = 2 //0 = Single shells or quick loader, 1 = box, 2 = magazine + fire_delay = 6 + ejectshell = 0 + slot_flags = SLOT_BACK + var/modded = 0 + var/obj/item/weapon/reloadlasermodkit/mod + + //placeholders// + icon_state = "laser" + item_state = "laser" + fire_sound = 'sound/weapons/Laser.ogg' + //placeholders// Well, okay, not the sound. + + New() + for(var/i = 1, i <= 30, i++) + loaded += new ammo_type(src) + update_icon() + + empty_mag = new /obj/item/ammo_magazine/laser/empty(src) + update_icon() + return + + + + +/obj/item/ammo_magazine/laser/empty + max_ammo = 0 + +/obj/item/ammo_magazine/laser + name = "charge cell (laser)" + desc = "A standard 30-shot cell." + icon_state = "12mm" + origin_tech = "combat=2" + ammo_type = "/obj/item/ammo_casing/laser" + max_ammo = 30 +// multiple_sprites = 1 + +/obj/item/ammo_magazine/laser/pulse + name = "charge cell (pulse)" + desc = "A heavy-duty 15-shot pulse cell." + ammo_type = "/obj/item/ammo_casing/laser/pulse" + max_ammo = 15 + +/obj/item/ammo_magazine/laser/heavy + name = "charge cell (heavy)" + desc = "A 15-shot cell designed to overload your projectiles with an extremely heavy charge." + ammo_type = "/obj/item/ammo_casing/laser/heavy" + max_ammo = 15 + +/obj/item/ammo_magazine/laser/practice + name = "charge cell (practice)" + desc = "A hundred-shot cell keyed in to a harmless wavelength for practice shooting." + ammo_type = "/obj/item/ammo_casing/laser/practice" + max_ammo = 100 + +/obj/item/ammo_magazine/laser/light + name = "charge cell (light)" + desc = "A 60-shot cell designed with capacity in mind. The lasers are weaker, though." + ammo_type = "/obj/item/ammo_casing/laser/light" + max_ammo = 60 + +/obj/item/ammo_magazine/laser/stun + name = "charge cell (stun)" + desc = "A 20-shot cell that fires lethal incapacitating bolts. Not standard issue." + ammo_type = "/obj/item/ammo_casing/laser/stun" + max_ammo = 20 + +//////////////////////////// +//Shells for the magazines// +//////////////////////////// + +//don't spawn these you butts// + +/obj/item/ammo_casing/laser + desc = "A LASER SHELL. You shouldn't be seeing this." + caliber = "laser" + projectile_type = "/obj/item/projectile/beam" + +/obj/item/ammo_casing/laser/pulse + desc = "A PULSE SHELL. You shouldn't be seeing this." + caliber = "laser" + projectile_type = "/obj/item/projectile/beam/pulse" + +/obj/item/ammo_casing/laser/heavy + desc = "A LASER CANNON SHELL. You shouldn't be seeing this." + caliber = "laser" + projectile_type = "/obj/item/projectile/beam/heavylaser" + +/obj/item/ammo_casing/laser/practice + desc = "A PRACTICE BLANK FAKE LASER SHELL. You shouldn't be seeing this." + caliber = "laser" + projectile_type = "/obj/item/projectile/beam/practice" + +/obj/item/ammo_casing/laser/light + desc = "A LIGHT LASER XRAY SHELL. You shouldn't be seeing this." + caliber = "laser" + projectile_type = "/obj/item/projectile/beam/xray/burst" + +/obj/item/ammo_casing/laser/stun + desc = "A STUN LASER SHELL. You shouldn't be seeing this." + caliber = "laser" + projectile_type = "/obj/item/projectile/beam/stun" + + +//////////////////////////////// +//////////////mods////////////// +//////////////////////////////// + +/obj/item/weapon/reloadlasermodkit + desc = "A cheap, disposable modkit designed to rapidly and permanently augment NT-standard laser rifles." + name = "rifle nanokit" + var/modtype = 0 + var/uses = 1 + var/emagged + icon = 'icons/obj/assemblies.dmi' + icon_state = "posibrain" //the placeholders are real + +/* Not sure about this yet. +/obj/item/device/megaphone/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/weapon/card/emag) && !emagged) + user << "\red You sneakily unlock the highly illegal military-grade burstfire augment." + emagged = 1 + return + return +*/ +/obj/item/weapon/reloadlasermodkit/attack_self(var/mob/user as mob) + + if (!emagged) + if (modtype == 0) + user << "Size modification selected." + modtype = 1 + else if (modtype == 1) + user << "Rapid-fire modification selected." + modtype = 2 + else if (modtype == 2) + user << "Silencer modification selected." + modtype = 0 + else if (emagged) //We'll see. Burst is ridiculous, especially on a full-power laser. + user << "Burstfire modification selected." + modtype = 3 + +/obj/item/weapon/gun/projectile/laser/attackby(obj/item/I as obj, mob/user as mob) + if(istype(I, /obj/item/weapon/reloadlasermodkit)) + if(user.l_hand != src && user.r_hand != src) //if we're not in his hands + user << "You'll need [src] in your hands to do that." + return + if(src.modded == 1) + user << "The frame can only handle one mod." + return + user.drop_item() + user << "You activate the modkit and watch the nanites swarm over [src]." + I.loc = src.mod + src.mod = I + src.modded = 1 + if (mod.modtype == 0) + user << "[src]'s firerate has been increased." + src.fire_delay = 4 + else if (mod.modtype == 1) + user << "[src]'s shape changes rapidly, becoming smaller and more economical." + src.w_class = 3 + else if (mod.modtype == 2) + user << "[src] sprouts wave-cancelling emitters. Its shots are now silenced." + src.silenced = 1 + else if (mod.modtype == 3) + user << "[src] rapidly reshapes its firing mechanism. It now fires in bursts." + src.fire_delay = 0 + src.projectiles_per_shot = 3 + src.fire_cooldown = 1 + fire_sound = 'sound/weapons/Gunshot_smg.ogg' + return + ..() diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index e57d13e6..439bce57 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -87,7 +87,7 @@ return 0// nope.avi var/distance = get_dist(starting,loc) - var/miss_modifier = -30 + var/miss_modifier = -60 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 diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index 236517f3..063cbc7b 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -99,12 +99,13 @@ var/list/beam_master = list() name = "xray beam" icon_state = "xray" damage = 30 +// forcedodge = -1 /obj/item/projectile/beam/xray/burst name = "xray beam" icon_state = "xray" // damage = 15 this makes rapidlasers kill almost exactly as fast as the rifle, but since they do a tripleburst, armor is much more effective. plus. rng miss. - damage = 20 //hence 20 damage. slight advantage over regular lasers. half-capacity for damage. use for coolness. use laser cannons for powergame. + damage = 25 //hence 25 damage. slight advantage over regular lasers. half-capacity for damage. use for coolness. use laser cannons for powergame. /obj/item/projectile/beam/pulse name = "pulse" @@ -122,10 +123,10 @@ var/list/beam_master = list() icon_state = "emitter" damage = 30 -/obj/item/projectile/beam/stunrevolver +/obj/item/projectile/beam/stun name = "stun beam" icon_state = "stun" - damage = 10 + damage = 20 agony = 45 /obj/item/projectile/beam/lastertag/blue diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm index a9175887..d30d0217 100644 --- a/code/modules/projectiles/projectile/energy.dm +++ b/code/modules/projectiles/projectile/energy.dm @@ -88,3 +88,30 @@ */ agony = 70 damage_type = HALLOSS + + +/obj/item/projectile/energy/mining //not in the game. i'll play with it later probably. + name = "electrode" + icon_state = "spark" + damage = 5 + kill_count = 3 + var/life = 5 + + Bump(atom/A) + A.bullet_act(src, def_zone) + src.life -= 1 + if(life <= 0) + del(src) + return + +/turf/simulated/mineral/bullet_act(var/obj/item/projectile/Proj) + if(istype(Proj ,/obj/item/projectile/energy/mining)) + src.GetDrilled() + ..() + return 0 + +/obj/structure/boulder/bullet_act(var/obj/item/projectile/Proj) + if(istype(Proj ,/obj/item/projectile/energy/mining)) + del(src) + ..() + return 0 \ No newline at end of file diff --git a/code/modules/vehicles/cargo_train.dm b/code/modules/vehicles/cargo_train.dm index ea3f7b72..cc416aa3 100644 --- a/code/modules/vehicles/cargo_train.dm +++ b/code/modules/vehicles/cargo_train.dm @@ -53,7 +53,7 @@ update_stats() if(load && is_train_head()) load << "The drive motor briefly whines, then drones to a stop." - + if(is_train_head() && !on) return 0 @@ -118,7 +118,7 @@ verbs -= /obj/vehicle/train/cargo/engine/verb/stop_engine verbs -= /obj/vehicle/train/cargo/engine/verb/start_engine - + if(on) verbs += /obj/vehicle/train/cargo/engine/verb/stop_engine else @@ -129,7 +129,7 @@ verbs -= /obj/vehicle/train/cargo/engine/verb/stop_engine verbs -= /obj/vehicle/train/cargo/engine/verb/start_engine - + if(!on) verbs += /obj/vehicle/train/cargo/engine/verb/start_engine else @@ -180,7 +180,7 @@ if(!istype(usr, /mob/living/carbon/human)) return - + if(get_dist(usr,src) <= 1) usr << "The power light is [on ? "on" : "off"].\nThere are[key ? "" : " no"] keys in the ignition." usr << "The charge meter reads [cell? round(cell.percent(), 0.01) : 0]%" @@ -192,7 +192,7 @@ if(!istype(usr, /mob/living/carbon/human)) return - + if(on) usr << "The engine is already running." return @@ -210,10 +210,10 @@ set name = "Stop engine" set category = "Object" set src in view(1) - + if(!istype(usr, /mob/living/carbon/human)) return - + if(!on) usr << "The engine is already stopped." return @@ -229,10 +229,10 @@ if(!istype(usr, /mob/living/carbon/human)) return - + if(!key || (load && load != usr)) return - + if(on) turn_off() @@ -291,7 +291,7 @@ /obj/vehicle/train/cargo/trolley/update_car(var/train_length, var/active_engines) src.train_length = train_length src.active_engines = active_engines - + if(!lead && !tow) anchored = 0 if(verbs.Find(/atom/movable/verb/pull)) diff --git a/code/modules/vehicles/train.dm b/code/modules/vehicles/train.dm index d8e372d8..c5ca6329 100644 --- a/code/modules/vehicles/train.dm +++ b/code/modules/vehicles/train.dm @@ -116,7 +116,7 @@ set desc = "Unhitches this train from the one in front of it." set category = "Object" set src in view(1) - + if(!istype(usr, /mob/living/carbon/human)) return @@ -139,11 +139,11 @@ if (lead) user << "\red [src] is already hitched to something." return - + if (T.tow) user << "\red [T] is already towing something." return - + //check for cycles. var/obj/vehicle/train/next_car = T while (next_car) @@ -151,15 +151,15 @@ user << "\red That seems very silly." return next_car = next_car.lead - + //latch with src as the follower lead = T T.tow = src dir = lead.dir - + if(user) user << "\blue You hitch [src] to [T]." - + update_stats() @@ -168,10 +168,10 @@ if (!lead) user << "\red [src] is not hitched to anything." return - + lead.tow = null lead.update_stats() - + user << "\blue You unhitch [src] from [lead]." lead = null @@ -190,7 +190,7 @@ //returns 1 if this is the lead car of the train /obj/vehicle/train/proc/is_train_head() - if (lead) + if (lead) return 0 return 1 @@ -209,7 +209,7 @@ if (T.tow == src) lead.tow = null lead.update_stats() - + lead = null update_stats() return diff --git a/data/investigate/gravity.html b/data/investigate/gravity.html index 7166030e..df50bfda 100644 --- a/data/investigate/gravity.html +++ b/data/investigate/gravity.html @@ -1,18 +1,6 @@ -23:57 [0x200793a] (92,152,1) || the gravitational generator has regained power.
-23:57 [0x200793a] (92,152,1) || the gravitational generator is now charging.
-23:57 [0x200793a] (92,152,1) || the gravitational generator has regained power.
-23:57 [0x200793a] (92,152,1) || the gravitational generator is now charging.
-23:58 [0x200793a] (92,152,1) || the gravitational generator has regained power.
-23:58 [0x200793a] (92,152,1) || the gravitational generator is now charging.
-00:03 [0x200793a] (92,152,1) || the gravitational generator has regained power.
-00:03 [0x200793a] (92,152,1) || the gravitational generator is now charging.
-00:08 [0x200793a] (92,152,1) || the gravitational generator has regained power.
-00:08 [0x200793a] (92,152,1) || the gravitational generator is now charging.
-00:12 [0x200793a] (92,152,1) || the gravitational generator has regained power.
-00:12 [0x200793a] (92,152,1) || the gravitational generator is now charging.
-00:17 [0x200793a] (92,152,1) || the gravitational generator has regained power.
-00:17 [0x200793a] (92,152,1) || the gravitational generator is now charging.
-00:22 [0x200793a] (92,152,1) || the gravitational generator has regained power.
-00:22 [0x200793a] (92,152,1) || the gravitational generator is now charging.
-00:27 [0x200793a] (92,152,1) || the gravitational generator has regained power.
-00:27 [0x200793a] (92,152,1) || the gravitational generator is now charging.
+00:42 [0x20078ca] (92,152,1) || the gravitational generator has regained power.
+00:42 [0x20078ca] (92,152,1) || the gravitational generator is now charging.
+00:43 [0x20078ca] (92,152,1) || the gravitational generator has regained power.
+00:43 [0x20078ca] (92,152,1) || the gravitational generator is now charging.
+00:43 [0x20078ca] (92,152,1) || the gravitational generator has regained power.
+00:43 [0x20078ca] (92,152,1) || the gravitational generator is now charging.