diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index f8f54c991ca..ffe158eed85 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -75,7 +75,11 @@ #define TOXINLOVER 22 #define DIGITIGRADE 23 //Uses weird leg sprites. Optional for Lizards, required for ashwalkers. Don't give it to other races unless you make sprites for this (see human_parts_greyscale.dmi) -#define FLYING 65536 +//Movement Types +#define IMMOBILE 0 +#define GROUND 1 +#define FLYING 2 + /* These defines are used specifically with the atom/movable/languages bitmask. diff --git a/code/datums/action.dm b/code/datums/action.dm index 465db8e4500..cad11ff1128 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -37,23 +37,26 @@ return ..() /datum/action/proc/Grant(mob/M) - if(owner) - if(owner == M) - return + if(M) + if(owner) + if(owner == M) + return + owner = M + M.actions += src + if(M.client) + M.client.screen += button + M.update_action_buttons() + else Remove(owner) - owner = M - M.actions += src - if(M.client) - M.client.screen += button - M.update_action_buttons() /datum/action/proc/Remove(mob/M) - if(M.client) - M.client.screen -= button - button.moved = FALSE //so the button appears in its normal position when given to another owner. - M.actions -= src - M.update_action_buttons() + if(M) + if(M.client) + M.client.screen -= button + M.actions -= src + M.update_action_buttons() owner = null + button.moved = FALSE //so the button appears in its normal position when given to another owner. /datum/action/proc/Trigger() if(!IsAvailable()) diff --git a/code/game/gamemodes/blob/blobs/blob_mobs.dm b/code/game/gamemodes/blob/blobs/blob_mobs.dm index 1dcb464035e..483f0ab1a8a 100644 --- a/code/game/gamemodes/blob/blobs/blob_mobs.dm +++ b/code/game/gamemodes/blob/blobs/blob_mobs.dm @@ -94,7 +94,7 @@ environment_smash = 1 attacktext = "hits" attack_sound = 'sound/weapons/genhit1.ogg' - flying = 1 + movement_type = FLYING del_on_death = 1 deathmessage = "explodes into a cloud of gas!" var/death_cloud_size = 1 //size of cloud produced from a dying spore @@ -130,7 +130,7 @@ desc = "A shambling corpse animated by the blob." melee_damage_lower += 8 melee_damage_upper += 11 - flying = 0 + movement_type = GROUND death_cloud_size = 0 icon = H.icon icon_state = "zombie_s" diff --git a/code/game/gamemodes/clock_cult/clock_mobs.dm b/code/game/gamemodes/clock_cult/clock_mobs.dm index 9d3fc49c848..9ebd2f78ef6 100644 --- a/code/game/gamemodes/clock_cult/clock_mobs.dm +++ b/code/game/gamemodes/clock_cult/clock_mobs.dm @@ -72,7 +72,7 @@ attack_sound = 'sound/magic/clockwork/anima_fragment_attack.ogg' loot = list(/obj/item/clockwork/component/replicant_alloy/smashed_anima_fragment) weather_immunities = list("lava") - flying = 1 + movement_type = FLYING playstyle_string = "You are an anima fragment, a clockwork creation of Ratvar. As a fragment, you have low health, do decent damage, and move at \ extreme speed in addition to being immune to extreme temperatures and pressures. Taking damage will temporarily slow you down, however. \n Your goal is to serve the Justiciar and his servants \ in any way you can. You yourself are one of these servants, and will be able to utilize anything they can, assuming it doesn't require opposable thumbs." @@ -132,7 +132,7 @@ attacktext = "slashes" attack_sound = 'sound/weapons/bladeslice.ogg' weather_immunities = list("lava") - flying = 1 + movement_type = FLYING loot = list(/obj/item/clockwork/component/replicant_alloy/fallen_armor) var/true_name = "Meme Master 69" //Required to call forth the marauder var/list/possible_true_names = list("Xaven", "Melange", "Ravan", "Kel", "Rama", "Geke", "Peris", "Vestra", "Skiwa") //All fairly short and easy to pronounce diff --git a/code/game/gamemodes/miniantags/revenant/revenant.dm b/code/game/gamemodes/miniantags/revenant/revenant.dm index fcbe8fd3127..831a1ee14ad 100644 --- a/code/game/gamemodes/miniantags/revenant/revenant.dm +++ b/code/game/gamemodes/miniantags/revenant/revenant.dm @@ -38,7 +38,7 @@ status_flags = 0 wander = 0 density = 0 - flying = 1 + movement_type = FLYING anchored = 1 mob_size = MOB_SIZE_TINY pass_flags = PASSTABLE | PASSGRILLE | PASSMOB diff --git a/code/game/objects/effects/alien_acid.dm b/code/game/objects/effects/alien_acid.dm index 0f65d6156ef..650c684e5ce 100644 --- a/code/game/objects/effects/alien_acid.dm +++ b/code/game/objects/effects/alien_acid.dm @@ -64,14 +64,8 @@ /obj/effect/acid/Crossed(AM as mob|obj) if(isliving(AM)) var/mob/living/L = AM - if(ishuman(L)) - var/mob/living/carbon/human/H = L - if(FLYING in H.dna.species.specflags) - return - else if(isanimal(L)) - var/mob/living/simple_animal/SA = L - if(SA.flying) - return + if(L.movement_type & FLYING) + return if(L.m_intent != "walk" && prob(40)) var/acid_used = min(acid_level*0.05, 20) if(L.acid_act(10, acid_used, "feet")) diff --git a/code/game/objects/effects/effect_system/effects_other.dm b/code/game/objects/effects/effect_system/effects_other.dm index 585dfedf0ab..60fd3c63edc 100644 --- a/code/game/objects/effects/effect_system/effects_other.dm +++ b/code/game/objects/effects/effect_system/effects_other.dm @@ -53,8 +53,14 @@ icon_state = "ion_trails" anchored = 1 +/obj/effect/particle_effect/ion_trails/flight + icon_state = "ion_trails_flight" + /datum/effect_system/trail_follow/ion effect_type = /obj/effect/particle_effect/ion_trails + var/fadetype = "ion_fade" + var/fade = 1 + var/nograv_required = 1 /datum/effect_system/trail_follow/ion/start() //Whoever is responsible for this abomination of code should become an hero if(!on) @@ -66,11 +72,12 @@ processing = 0 var/turf/T = get_turf(holder) if(T != oldposition) - if(!T.has_gravity()) + if(!T.has_gravity() || !nograv_required) var/obj/effect/particle_effect/ion_trails/I = PoolOrNew(effect_type, oldposition) - I.setDir(holder.dir) - flick("ion_fade", I) - I.icon_state = "" + set_dir(I) + if(fade) + flick(fadetype, I) + I.icon_state = "" spawn(20) qdel(I) oldposition = T @@ -79,7 +86,18 @@ processing = 1 start() +/datum/effect_system/trail_follow/ion/proc/set_dir(obj/effect/particle_effect/ion_trails/I) + I.setDir(holder.dir) +/datum/effect_system/trail_follow/ion/flight + effect_type = /obj/effect/particle_effect/ion_trails/flight + fadetype = "ion_fade_flight" + nograv_required = 0 + +/datum/effect_system/trail_follow/ion/flight/set_dir(obj/effect/particle_effect/ion_trails/I) + if(istype(holder, /obj/item/device/flightpack)) + var/obj/item/device/flightpack/F = holder + I.setDir(F.suit.user.dir) //Reagent-based explosion effect diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index cf066f0f46a..f8af9c5fa00 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -11,10 +11,10 @@ victim << "*click*" /obj/effect/mine/Crossed(AM as mob|obj) - if(isanimal(AM)) - var/mob/living/simple_animal/SA = AM - if(!SA.flying) - triggermine(SA) + if(ismob(AM)) + var/mob/MM = AM + if(!(MM.movement_type & FLYING)) + triggermine(AM) else triggermine(AM) diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm index 4169ff9a503..0628f7dfebc 100644 --- a/code/game/objects/items/weapons/handcuffs.dm +++ b/code/game/objects/items/weapons/handcuffs.dm @@ -277,8 +277,10 @@ feedback_add_details("handcuffs","B") //Yes, I know they're legcuffs. Don't change this, no need for an extra variable. The "B" is used to tell them apart. else if(isanimal(L)) var/mob/living/simple_animal/SA = L - if(!SA.flying && SA.mob_size > MOB_SIZE_TINY) + if(SA.mob_size > MOB_SIZE_TINY) snap = 1 + if(L.movement_type & FLYING) + snap = 0 if(snap) armed = 0 icon_state = "[initial(icon_state)][armed]" diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 626c5bb1917..33e05becc96 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -180,3 +180,6 @@ /obj/proc/check_uplink_validity() return 1 + +/obj/proc/on_mob_move(dir, mob) + return diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm index 1d973a695a0..19589bbafc0 100644 --- a/code/game/turfs/open.dm +++ b/code/game/turfs/open.dm @@ -120,6 +120,8 @@ return 1 /turf/open/handle_slip(mob/living/carbon/C, s_amount, w_amount, obj/O, lube) + if(C.movement_type & FLYING) + return 0 if(has_gravity(src)) var/obj/buckled_obj if(C.buckled) diff --git a/code/game/turfs/simulated/chasm.dm b/code/game/turfs/simulated/chasm.dm index d633a040611..2d4d34e0dbb 100644 --- a/code/game/turfs/simulated/chasm.dm +++ b/code/game/turfs/simulated/chasm.dm @@ -39,9 +39,9 @@ //Portals aren't affected by gravity. Probably. return 0 //Flies right over the chasm - if(isanimal(AM)) - var/mob/living/simple_animal/SA = AM - if(SA.flying) + if(isliving(AM)) + var/mob/MM = AM + if(MM.movement_type & FLYING) return 0 if(ishuman(AM)) var/mob/living/carbon/human/H = AM @@ -51,8 +51,6 @@ visible_message("[H] falls into [src]!") J.chasm_react(H) return 0 - if(H.dna && H.dna.species && (FLYING in H.dna.species.specflags)) - return 0 return 1 /turf/open/chasm/proc/drop(atom/movable/AM) diff --git a/code/game/turfs/simulated/floor/plating/lava.dm b/code/game/turfs/simulated/floor/plating/lava.dm index 75b75c5a076..31395abc979 100644 --- a/code/game/turfs/simulated/floor/plating/lava.dm +++ b/code/game/turfs/simulated/floor/plating/lava.dm @@ -55,10 +55,11 @@ O.armor["fire"] = 50 O.fire_act(10000, 1000) - else if (isliving(thing)) . = 1 var/mob/living/L = thing + if(L.movement_type & FLYING) + continue //YOU'RE FLYING OVER IT if("lava" in L.weather_immunities) continue if(L.buckled) diff --git a/code/game/turfs/simulated/floor/reinf_floor.dm b/code/game/turfs/simulated/floor/reinf_floor.dm index fdf799d3fd7..0d78571cc89 100644 --- a/code/game/turfs/simulated/floor/reinf_floor.dm +++ b/code/game/turfs/simulated/floor/reinf_floor.dm @@ -150,7 +150,6 @@ /turf/open/floor/engine/cult/airless initial_gas_mix = "TEMP=2.7" - /turf/open/floor/engine/vacuum name = "vacuum floor" initial_gas_mix = "TEMP=2.7" diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index dc87890330f..979430920ba 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -99,6 +99,8 @@ //slipping if (istype(AM,/mob/living/carbon)) var/mob/living/carbon/M = AM + if(M.movement_type & FLYING) + return switch(wet) if(TURF_WET_WATER) if(!M.slip(0, 3, null, NO_SLIP_WHEN_WALKING)) diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm index 833068afdab..1bfdbceb1a1 100644 --- a/code/modules/assembly/mousetrap.dm +++ b/code/modules/assembly/mousetrap.dm @@ -104,16 +104,15 @@ /obj/item/device/assembly/mousetrap/Crossed(atom/movable/AM as mob|obj) if(armed) - if(ishuman(AM)) - var/mob/living/carbon/H = AM - if(H.m_intent == "run") - triggered(H) - H.visible_message("[H] accidentally steps on [src].", \ - "You accidentally step on [src]") - else if(isanimal(AM)) - var/mob/living/simple_animal/SA = AM - if(!SA.flying) - triggered(AM) + if(ismob(AM)) + var/mob/MM = AM + if(!(MM.movement_type & FLYING)) + if(ishuman(AM)) + var/mob/living/carbon/H = AM + if(H.m_intent == "run") + triggered(H) + H.visible_message("[H] accidentally steps on [src].", \ + "You accidentally step on [src]") else if(AM.density) // For mousetrap grenades, set off by anything heavy triggered(AM) ..() diff --git a/code/modules/clothing/spacesuits/flightsuit.dm b/code/modules/clothing/spacesuits/flightsuit.dm new file mode 100644 index 00000000000..fc90e917c33 --- /dev/null +++ b/code/modules/clothing/spacesuits/flightsuit.dm @@ -0,0 +1,1198 @@ + +//So how this is planned to work is it is an item that allows you to fly with some interesting movement mechanics. +//You will still move instantly like usual, but when you move in a direction you gain "momentum" towards that direction +//Momentum will have a maximum value that it will be capped to, and will go down over time +//There is toggleable "stabilizers" that will make momentum go down FAST instead of its normal slow rate +//The suit is heavy and will slow you down on the ground but is a bit faster then usual in air +//The speed at which you drift is determined by your current momentum +//Also, I should probably add in some kind of limiting mechanic but I really don't like having to refill this all the time, expecially as it will be NODROP. +//Apparently due to code limitations you have to detect mob movement with.. shoes. +//The object that handles the flying itself - FLIGHT PACK -------------------------------------------------------------------------------------- +/obj/item/device/flightpack + name = "flight pack" + desc = "An advanced back-worn system that has dual ion engines powerful enough to grant a humanoid flight. Contains an internal self-recharging high-current capacitor for short, powerful boosts." + icon_state = "flightpack_off" + item_state = "flightpack_off" + var/icon_state_active = "flightpack_on" + var/item_state_active = "flightpack_on" + var/icon_state_boost = "flightpack_boost" + var/item_state_boost = "flightpack_boost" + actions_types = list(/datum/action/item_action/flightpack/toggle_flight, /datum/action/item_action/flightpack/engage_boosters, /datum/action/item_action/flightpack/toggle_stabilizers, /datum/action/item_action/flightpack/change_power, /datum/action/item_action/flightpack/toggle_airbrake) + armor = list(melee = 20, bullet = 20, laser = 20, energy = 10, bomb = 30, bio = 100, rad = 75, fire = 100, acid = 100) + + w_class = 4 + slot_flags = SLOT_BACK + resistance_flags = FIRE_PROOF | ACID_PROOF + + var/obj/item/clothing/suit/space/hardsuit/flightsuit/suit = null + var/mob/living/carbon/human/wearer = null + var/slowdown_ground = 1 + var/slowdown_air = 0 + var/slowdown_brake = 1 + var/flight = 0 + var/flight_passflags = PASSTABLE + var/powersetting = 1 + var/powersetting_high = 3 + var/powersetting_low = 1 + var/override_safe = 0 + + var/boost = 0 + var/boost_maxcharge = 50 //Vroom! If you hit someone while boosting they'll likely be knocked flying. Fun. + var/boost_charge = 50 + var/boost_speed = 2 + var/boost_power = 50 + var/boost_chargerate = 0.5 + var/boost_drain = 10 //Keep in mind it charges and drains at the same time, so drain realistically is drain-charge=change + + var/momentum_x = 0 //Realistic physics. No more "Instant stopping while barreling down a hallway at Mach 1". + var/momentum_y = 0 + var/momentum_max = 500 + var/momentum_impact_coeff = 0.5 //At this speed you'll start coliding with people resulting in momentum loss and them being knocked back, but no injuries or knockdowns + var/momentum_impact_loss = 50 + var/momentum_crash_coeff = 0.8 //At this speed if you hit a dense object, you will careen out of control, while that object will be knocked flying. + var/momentum_speed = 0 //How fast we are drifting around + var/momentum_speed_x = 0 + var/momentum_speed_y = 0 + var/momentum_drift_tick = 0 //Cooldowns + var/momentum_passive_loss = 7 + var/momentum_gain = 20 + + var/stabilizer = 1 + var/stabilizer_decay_amount = 23 + var/gravity = 1 + var/gravity_decay_amount = 5 + var/pressure = 1 + var/pressure_decay_amount = 5 + var/pressure_threshold = 30 + var/brake = 0 + var/airbrake_decay_amount = 60 + + var/resync = 0 //Used to resync the flight-suit every 30 seconds or so. + + var/disabled = 0 //Whether it is disabled from crashes/emps/whatever + var/crash_disable_message = 0 //To not spam the user with messages + var/emp_disable_message = 0 + + //This is probably too much code just for EMP damage. + var/emp_damage = 0 //One hit should make it hard to control, continuous hits will cripple it and then simply shut it off/make it crash. Direct hits count more. + var/emp_strong_damage = 1.5 + var/emp_weak_damage = 1 + var/emp_heal_amount = 0.1 //How much emp damage to heal per process. + var/emp_disable_threshold = 3 //3 weak ion, 2 strong ion hits. + var/emp_disabled = 0 + + var/crash_damage = 0 //Same thing, but for crashes. This is in addition to possible amounts of brute damage to the wearer. + var/crash_damage_low = 1 + var/crash_damage_high = 2.5 + var/crash_disable_threshold = 5 + var/crash_heal_amount = 0.1 + var/crash_disabled = 0 + var/crash_dampening = 0 + + var/datum/effect_system/trail_follow/ion/flight/ion_trail + + var/assembled = 0 + var/obj/item/weapon/stock_parts/manipulator/part_manip = null + var/obj/item/weapon/stock_parts/scanning_module/part_scan = null + var/obj/item/weapon/stock_parts/capacitor/part_cap = null + var/obj/item/weapon/stock_parts/micro_laser/part_laser = null + var/obj/item/weapon/stock_parts/matter_bin/part_bin = null + + var/crashing = 0 //Are we currently getting wrecked? + + +//Start/Stop processing the item to use momentum and flight mechanics. +/obj/item/device/flightpack/New() + START_PROCESSING(SSfastprocess, src) + ..() + ion_trail = new + ion_trail.set_up(src) + +/obj/item/device/flightpack/full/New() + ..() + part_manip = new /obj/item/weapon/stock_parts/manipulator/pico(src) + part_scan = new /obj/item/weapon/stock_parts/scanning_module/phasic(src) + part_cap = new /obj/item/weapon/stock_parts/capacitor/super(src) + part_laser = new /obj/item/weapon/stock_parts/micro_laser/ultra(src) + part_bin = new /obj/item/weapon/stock_parts/matter_bin/super(src) + assembled = 1 + +/obj/item/device/flightpack/proc/update_parts() + boost_chargerate = initial(boost_chargerate) + boost_drain = initial(boost_drain) + powersetting_high = initial(powersetting_high) + emp_disable_threshold = initial(emp_disable_threshold) + crash_disable_threshold = initial(crash_disable_threshold) + stabilizer_decay_amount = initial(stabilizer_decay_amount) + airbrake_decay_amount = initial(airbrake_decay_amount) + var/manip = 0 //Efficiency + var/scan = 0 //Damage avoidance/other + var/cap = 0 //Charging + var/laser = 0 //Power + var/bin = 0 //Stability + assembled = 0 //Ready? + if(part_manip && part_scan && part_cap && part_laser && part_bin) + manip = part_manip.rating + scan = part_scan.rating + cap = part_cap.rating + laser = part_laser.rating + bin = part_bin.rating + assembled = 1 + boost_chargerate *= cap + boost_drain -= manip + powersetting_high = Clamp(laser, 0, 3) + emp_disable_threshold = bin*1.25 + crash_disable_threshold = bin*2 + stabilizer_decay_amount = scan*5.75 + airbrake_decay_amount = manip*15 + crash_dampening = bin + +/obj/item/device/flightpack/Destroy() + if(suit) + delink_suit() + qdel(part_manip) + qdel(part_scan) + qdel(part_cap) + qdel(part_laser) + qdel(part_bin) + STOP_PROCESSING(SSfastprocess, src) + part_manip = null + part_scan = null + part_cap = null + part_laser = null + part_bin = null + ..() + +/obj/item/device/flightpack/emp_act(severity) + var/damage = 0 + if(severity == 1) + damage = emp_strong_damage + else + damage = emp_weak_damage + if(emp_damage <= (emp_disable_threshold * 1.5)) + emp_damage += damage + wearer << "Flightpack: BZZZZZZZZZZZT" + wearer << "Flightpack: WARNING: Class [severity] EMP detected! Circuit damage at [(100/emp_disable_threshold)*emp_damage]!" + +//action BUTTON CODE +/obj/item/device/flightpack/ui_action_click(owner, action) + if(wearer != owner) + wearer = owner + if(!suit) + usermessage("The flightpack will not work without being attached to a suit first!") + return 0 + if(istype(action, /datum/action/item_action/flightpack/toggle_flight)) + if(!flight) + enable_flight() + else + disable_flight() + if(istype(action, /datum/action/item_action/flightpack/engage_boosters)) + if(!boost) + activate_booster() + else + deactivate_booster() + if(istype(action, /datum/action/item_action/flightpack/toggle_stabilizers)) + if(!stabilizer) + enable_stabilizers() + else + disable_stabilizers() + if(istype(action, /datum/action/item_action/flightpack/change_power)) + cycle_power() + if(istype(action, /datum/action/item_action/flightpack/toggle_airbrake)) + if(!brake) + enable_airbrake() + else + disable_airbrake() + +//Proc to change amount of momentum the wearer has, or dampen all momentum by a certain amount. +/obj/item/device/flightpack/proc/adjust_momentum(amountx, amounty, reduce_amount_total = 0) + if(reduce_amount_total != 0) + if(momentum_x > 0) + momentum_x = Clamp(momentum_x - reduce_amount_total, 0, momentum_max) + else if(momentum_x < 0) + momentum_x = Clamp(momentum_x + reduce_amount_total, -momentum_max, 0) + if(momentum_y > 0) + momentum_y = Clamp(momentum_y - reduce_amount_total, 0, momentum_max) + else if(momentum_y < 0) + momentum_y = Clamp(momentum_y + reduce_amount_total, -momentum_max, 0) + momentum_x = Clamp(momentum_x + amountx, -momentum_max, momentum_max) + momentum_y = Clamp(momentum_y + amounty, -momentum_max, momentum_max) + calculate_momentum_speed() + +//Called by the pair of shoes the wearer is required to wear to detect movement. +/obj/item/device/flightpack/proc/wearer_movement(dir) + if(!flight) + return + var/momentum_increment = momentum_gain + if(boost) + momentum_increment = boost_power + if(brake) + momentum_increment = 0 + switch(dir) + if(NORTH) + adjust_momentum(0, momentum_increment) + if(SOUTH) + adjust_momentum(0, -momentum_increment) + if(EAST) + adjust_momentum(momentum_increment, 0) + if(WEST) + adjust_momentum(-momentum_increment, 0) + +//The wearer has momentum left. Move them and take some away, while negating the momentum that moving the wearer would gain. Or force the wearer to lose control if they are incapacitated. +/obj/item/device/flightpack/proc/momentum_drift() + if(!flight) + return 0 + var/drift_x = 0 + var/drift_dir_x = 0 + var/drift_y = 0 + var/drift_dir_y = 0 + if(momentum_x > 0) + drift_x = 1 + drift_dir_x = EAST + if(momentum_x < 0) + drift_x = 1 + drift_dir_x = WEST + if(momentum_y > 0) + drift_y = 1 + drift_dir_y = NORTH + if(momentum_y < 0) + drift_y = 1 + drift_dir_y = SOUTH + if(momentum_speed == 0) + return 0 + if(suit) + if(wearer) + if(!wearer.canmove) + losecontrol() + momentum_decay() + for(var/i in 1 to momentum_speed) + if(drift_x) + step(wearer, drift_dir_x) + if(drift_y) + step(wearer, drift_dir_y) + sleep(1) + momentum_drift_tick = 0 + +//Make the wearer lose some momentum. +/obj/item/device/flightpack/proc/momentum_decay() + if(brake) + adjust_momentum(0, 0, airbrake_decay_amount) + if(gravity) + adjust_momentum(0, 0, gravity_decay_amount) + if(stabilizer) + adjust_momentum(0, 0, stabilizer_decay_amount) + if(pressure) + adjust_momentum(0, 0, pressure_decay_amount) + adjust_momentum(0, 0, momentum_passive_loss) + +//Check for gravity, air pressure, and whether this is still linked to a suit. Also, resync the flightpack/flight suit every minute. +/obj/item/device/flightpack/proc/check_conditions() + if(suit) + if(wearer) + if(wearer.has_gravity()) + gravity = 1 + else + gravity = 0 + var/turf/T = get_turf(wearer) + var/datum/gas_mixture/gas = T.return_air() + var/envpressure = gas.return_pressure() + if(envpressure >= pressure_threshold) + pressure = 1 + else + pressure = 0 + if(flight) + if(!assembled) + disable_flight(1) + if(!suit) + disable_flight(1) + if(!resync) + addtimer(src, "resync", 600) + resync = 1 + if(!wearer) //Oh god our user fell off! + disable_flight(1) + if(!pressure && brake) + brake = 0 + usermessage("Airbrakes deactivated due to lack of pressure!", 2) + if(!suit.deployedshoes) + if(brake || stabilizer) + brake = 0 + stabilizer = 0 + usermessage("Warning: Sensor data is not being recieved from flight shoes. Stabilizers and airbrake modules OFFLINE!", 2) + +//Resync the suit +/obj/item/device/flightpack/proc/resync() + resync = 0 + suit.resync() + +//How fast should the wearer be? +/obj/item/device/flightpack/proc/update_slowdown() + if(!flight) + suit.slowdown = slowdown_ground + return + if(brake) + suit.slowdown = slowdown_brake + else if(boost) + suit.slowdown = -boost_speed + else + suit.slowdown = slowdown_air + +/obj/item/device/flightpack/process() + if(!suit) + return 0 + update_slowdown() + update_icon() + check_conditions() + handle_flight() + calculate_momentum_speed() + momentum_drift_tick++ + momentum_drift() + handle_boost() + handle_damage() + + +/obj/item/device/flightpack/proc/handle_damage() + if(crash_damage) + crash_damage = Clamp(crash_damage-crash_heal_amount, 0, crash_disable_threshold*10) + if(crash_damage >= crash_disable_threshold) + crash_disabled = 1 + if(crash_disabled && (crash_damage <= 1)) + crash_disabled = 0 + crash_disable_message = 0 + usermessage("Gyroscopic sensors recalibrated. Flight systems re-enabled.") + if(emp_damage) + emp_damage = Clamp(emp_damage-emp_heal_amount, 0, emp_disable_threshold * 10) + if(emp_damage >= emp_disable_threshold) + emp_disabled = 1 + if(emp_disabled && (emp_damage <= 0.5)) + emp_disabled = 0 + emp_disable_message = 0 + usermessage("Electromagnetic deflection system re-activated. Flight systems re-enabled.") + disabled = crash_disabled + emp_disabled + if(disabled) + if(crash_disabled && (!crash_disable_message)) + usermessage("Internal gyroscopes scrambled from excessive impacts.", 2) + usermessage("Deactivating to recalibrate flight systems!", 2) + crash_disable_message = 1 + if(emp_disabled && (!emp_disable_message)) + usermessage("Electromagnetic deflectors overloaded. Short circuit detected in internal systems!", 1) + usermessage("Deactivating to prevent fatal power overload!", 2) + emp_disable_message = 1 + if(flight) + disable_flight(1) + +/obj/item/device/flightpack/update_icon() + if(!flight) + icon_state = initial(icon_state) + item_state = initial(item_state) + if(flight) + icon_state = icon_state_active + item_state = item_state_active + if(boost) + icon_state = icon_state_boost + item_state = item_state_boost + if(wearer) + wearer.update_inv_wear_suit() + wearer.update_inv_back() + ..() + +/obj/item/device/flightpack/proc/handle_flight() + if(!flight) + return 0 + +/obj/item/device/flightpack/proc/handle_boost() + if(boost) + boost_charge = Clamp(boost_charge-boost_drain, 0, boost_maxcharge) + if(boost_charge < 1) + deactivate_booster() + if(boost_charge < boost_maxcharge) + boost_charge = Clamp(boost_charge+boost_chargerate, 0, boost_maxcharge) + + +/obj/item/device/flightpack/proc/cycle_power() + if(powersetting < powersetting_high) + powersetting++ + else + powersetting = 1 + momentum_gain = powersetting * 10 + usermessage("Engine output set to [momentum_gain].") + +/obj/item/device/flightpack/proc/crash_damage(density, anchored, speed, victim_name) + var/crashmessagesrc = "[wearer] violently crashes into [victim_name], " + var/userdamage = 10 + userdamage -= stabilizer*3 + userdamage -= part_bin.rating + userdamage += anchored*4 + if(userdamage) + crashmessagesrc += "that really must have hurt!" + else + crashmessagesrc += "but luckily [wearer]'s impact was absorbed by their suit's stabilizers!" + wearer.adjustBruteLoss(userdamage) + usermessage("WARNING: Stabilizers taking damage!", 2) + wearer.visible_message(crashmessagesrc) + crash_damage = Clamp(crash_damage + 3, 0, crash_disable_threshold*1.5) + +/obj/item/device/flightpack/proc/userknockback(density, anchored, speed, dir) + var/angle = dir2angle(dir) + angle += 180 + if(angle > 360) + angle -= 360 + dir = angle2dir(angle) + var/turf/target = get_edge_target_turf(get_turf(wearer), dir) + wearer.throw_at_fast(target, (speed+density+anchored), 2, wearer) + wearer.visible_message("[wearer] is knocked flying by the impact!") + +/obj/item/device/flightpack/proc/flight_impact(atom/unmovablevictim) //Yes, victim. + if(unmovablevictim == wearer) + return 0 + var/atom/movable/victim = null + var/dir = null + var/mobonly = 0 + if(crashing) //We're already in the process of getting knocked around by a crash. + return 0 + if((flight && momentum_speed > 2) || boost) + crashing = 1 + dir = wearer.dir + else if (flight && momentum_speed > 1) + crashing = 1 + dir = wearer.dir + mobonly = 1 + else + return 0 + dir = wearer.dir + var/density = 0 + var/anchored = 1 + var/nocrash = 0 + if(ismob(unmovablevictim)) + var/mob/living/L = unmovablevictim + mobknockback(density, anchored, momentum_speed, L, dir) + nocrash = 1 + density = 0 + anchored = 0 + else if(isclosedturf(unmovablevictim) && !mobonly) + density = 1 + anchored = 1 + else if(ismovableatom(unmovablevictim) && !mobonly) + victim = unmovablevictim + density = victim.density + anchored = victim.anchored + victimknockback(density, anchored, momentum_speed, victim, dir) + if(!nocrash || mobonly) + crash_damage(density, anchored, momentum_speed, unmovablevictim.name) + userknockback(density, anchored, momentum_speed, dir) + losecontrol(move = FALSE) + crashing = 0 + +/obj/item/device/flightpack/proc/mobknockback(density, anchored, momentum_speed, mob/living/L, dir) + if(!ismob(L)) + return 0 + var/knockmessage = "[L] is knocked back by [wearer] as they narrowly avoid a collision!" + var/knockback = 0 + var/stun = boost * 2 + if(stun) + knockmessage += " [wearer] dashes across [L], knocking them down!" + knockmessage += "" + knockback += momentum_speed + knockback += (part_manip.rating / 2) + knockback += (part_bin.rating / 2) + knockback += boost + knockback = knockback / 3 + var/direction = pick(alldirs) + var/target = get_step(L, direction) + for(var/i in 1 to (knockback - 1)) + target = get_step(target, direction) + wearer.visible_message(knockmessage) + L.throw_at_fast(target, 7, 3) + L.Weaken(stun) + +/obj/item/device/flightpack/proc/victimknockback(density, anchored, momentum_speed, atom/movable/victim, dir) + if(!victim) + return 0 + var/knockback = 0 + var/damage = 0 + var/stun = 0 + var/turf/target + knockback -= (density * 2) + knockback += momentum_speed + knockback += (part_manip.rating / 2) + knockback += (part_bin.rating / 2) + knockback *= 4 + stun = ((part_manip.rating + part_bin.rating) / 2) + damage = knockback / 2.5 + if(anchored) + knockback = 0 + target = get_edge_target_turf(victim, dir) + victim.visible_message("[victim.name] is sent flying by the impact!") + if(knockback) + victim.throw_at_fast(target, knockback, part_manip.rating, wearer) + if(ismob(victim)) + var/mob/living/victimmob = victim + victimmob.Weaken(stun) + victimmob.adjustBruteLoss(damage) + +/obj/item/device/flightpack/proc/losecontrol(stun = FALSE, move = TRUE) + usermessage("Warning: Control system not responding. Deactivating!", 3) + wearer.visible_message("[wearer]'s flight suit abruptly shuts off and they lose control!") + if(wearer) + if(move) + while(momentum_x != 0 || momentum_y != 0) + sleep(2) + step(wearer, pick(cardinal)) + momentum_decay() + adjust_momentum(0, 0, 10) + wearer.visible_message("[wearer]'s flight suit crashes into the ground!") + if(stun) + wearer.Weaken(4) + momentum_x = 0 + momentum_y = 0 + if(flight) + disable_flight() + +/obj/item/device/flightpack/proc/enable_flight(forced = 0) + if(!suit) + usermessage("Warning: Flightpack not linked to compatible flight-suit mount!", 2) + if(disabled) + usermessage("Internal systems recalibrating. Unable to safely proceed.", 2) + wearer.movement_type |= FLYING + wearer.pass_flags |= flight_passflags + usermessage("ENGAGING FLIGHT ENGINES.") + wearer.visible_message("[wearer]'s flight engines activate as they lift into the air!") + //I DONT HAVE SOUND EFFECTS YET playsound( + flight = 1 + if(suit.shoes) + suit.shoes.toggle(1) + update_icon() + ion_trail.start() + +/obj/item/device/flightpack/proc/disable_flight(forced = 0) + if(forced) + losecontrol(stun = TRUE) + return 1 + if(abs(momentum_x) <= 20 && abs(momentum_y) <= 20) + momentum_x = 0 + momentum_y = 0 + usermessage("DISENGAGING FLIGHT ENGINES.") + wearer.visible_message("[wearer] drops to the ground as their flight engines cut out!") + //NO SOUND YET playsound( + ion_trail.stop() + wearer.movement_type &= ~FLYING + wearer.pass_flags &= ~flight_passflags + flight = 0 + if(suit.shoes) + suit.shoes.toggle(0) + else + if(override_safe) + disable_flight(1) + return 1 + usermessage("Warning: Velocity too high to safely disengage. Retry to confirm emergency shutoff.", 2) + override_safe = 1 + addtimer(src, "enable_safe", 50) + return 0 + update_icon() + +/obj/item/device/flightpack/proc/enable_safe() + if(override_safe) + override_safe = 0 + +/obj/item/device/flightpack/dropped(mob/wearer) + ..() + +/obj/item/device/flightpack/item_action_slot_check(slot) + if(slot == SLOT_BACK) + return 1 + +/obj/item/device/flightpack/equipped(mob/user, slot) + if(ishuman(user)) + wearer = user + ..() + +/obj/item/device/flightpack/proc/calculate_momentum_speed() + if(momentum_x == 0 && momentum_y == 0) + momentum_speed = 0 + else if((abs(momentum_x) >= (momentum_crash_coeff*momentum_max))||(abs(momentum_y) >= (momentum_crash_coeff*momentum_max))) + momentum_speed = 3 + if(abs(momentum_x) >= (momentum_crash_coeff*momentum_max)) + momentum_speed_x = 3 + if(abs(momentum_y) >= (momentum_crash_coeff*momentum_max)) + momentum_speed_y = 3 + else if((abs(momentum_x) >= (momentum_impact_coeff*momentum_max))||(abs(momentum_y) >= (momentum_impact_coeff*momentum_max))) + momentum_speed = 2 + if(abs(momentum_x) >= (momentum_impact_coeff*momentum_max)) + momentum_speed_x = 2 + if(abs(momentum_y) >= (momentum_impact_coeff*momentum_max)) + momentum_speed_y = 2 + else if((momentum_x != 0)||(momentum_y != 0)) + momentum_speed = 1 + momentum_speed_x = 1 + momentum_speed_y = 1 + +/obj/item/device/flightpack/item_action_slot_check(slot) + if(slot == slot_back) + return 1 + +/obj/item/device/flightpack/proc/enable_stabilizers() + usermessage("Activating automatic stabilization controller and enabling maneuvering assistance.") + stabilizer = 1 + +/obj/item/device/flightpack/proc/disable_stabilizers() + if(wearer) + if(brake) + disable_airbrake() + usermessage("Deactivating stabilization controllers!", 2) + stabilizer = 0 + +/obj/item/device/flightpack/proc/activate_booster() + if(!flight) + usermessage("Error: Engines offline!", 2) + if(boost_charge < 5) + usermessage("Insufficient charge in boost capacitors to engage.", 2) + return 0 + usermessage("Boosters engaged!") + wearer.visible_message("[wearer.name]'s flightpack engines flare in intensity as they are rocketed forward by the immense thrust!") + boost = 1 + update_slowdown() + +/obj/item/device/flightpack/proc/deactivate_booster() + usermessage("Boosters disengaged!") + boost = 0 + update_slowdown() + +/obj/item/device/flightpack/proc/enable_airbrake() + if(wearer) + if(!stabilizer) + enable_stabilizers() + usermessage("Stabilizers activated!") + usermessage("Airbrakes extended!") + brake = 1 + update_slowdown() + +/obj/item/device/flightpack/proc/disable_airbrake() + if(wearer) + usermessage("Airbrakes retracted!") + brake = 0 + update_slowdown() + +/obj/item/device/flightpack/on_mob_move(dir, mob) + wearer_movement(dir) + +/obj/item/device/flightpack/proc/relink_suit(obj/item/clothing/suit/space/hardsuit/flightsuit/F) + if(suit && suit == F) + return 0 + else + delink_suit() + if(istype(F)) + suit = F + suit.pack = src + else + suit = null + +/obj/item/device/flightpack/proc/delink_suit() + if(suit) + if(suit.pack && suit.pack == src) + suit.pack = null + suit = null + +/obj/item/device/flightpack/proc/usermessage(message, urgency = 0) + if(urgency == 0) + wearer << "\icon[src]|[message]" + if(urgency == 1) + wearer << "\icon[src]|[message]" + if(urgency == 2) + wearer << "\icon[src]|[message]" + if(urgency == 3) + wearer << "\icon[src]|[message]" + +/obj/item/device/flightpack/attackby(obj/item/I, mob/user, params) + if(ishuman(user) && !ishuman(src.loc)) + wearer = user + if(istype(I, /obj/item/weapon/stock_parts)) + var/obj/item/weapon/stock_parts/S = I + if(istype(S, /obj/item/weapon/stock_parts/manipulator)) + if((!part_manip) || (part_manip.rating < S.rating)) + usermessage("[I] has been sucessfully installed into systems.") + if(user.unEquip(I)) + I.loc = src + part_manip = I + if(istype(S, /obj/item/weapon/stock_parts/scanning_module)) + if((!part_scan) || (part_scan.rating < S.rating)) + usermessage("[I] has been sucessfully installed into systems.") + if(user.unEquip(I)) + I.loc = src + part_scan = I + if(istype(S, /obj/item/weapon/stock_parts/micro_laser)) + if((!part_laser) || (part_laser.rating < S.rating)) + usermessage("[I] has been sucessfully installed into systems.") + if(user.unEquip(I)) + I.loc = src + part_laser = I + if(istype(S, /obj/item/weapon/stock_parts/matter_bin)) + if((!part_bin) || (part_bin.rating < S.rating)) + usermessage("[I] has been sucessfully installed into systems.") + if(user.unEquip(I)) + I.loc = src + part_bin = I + if(istype(S, /obj/item/weapon/stock_parts/capacitor)) + if((!part_cap) || (part_cap.rating < S.rating)) + usermessage("[I] has been sucessfully installed into systems.") + if(user.unEquip(I)) + I.loc = src + part_cap = I + update_parts() + +//MOB MOVEMENT STUFF---------------------------------------------------------------------------------------------------------------------------------------------- + +/mob/proc/get_flightpack() + return + +/mob/living/carbon/get_flightpack() + var/obj/item/device/flightpack/F = back + if(istype(F)) + return F + else + return 0 + +/obj/item/device/flightpack/proc/allow_thrust(amount) + if(flight) + return 1 + +//FLIGHT SHOES----------------------------------------------------------------------------------------------------------------------------------------------------- + +/obj/item/clothing/shoes/flightshoes + name = "flight shoes" + desc = "A pair of specialized boots that contain stabilizers and sensors nessacary for flight gear to work" //Apparently you need these to detect mob movement. + icon_state = "flightshoes" + item_state = "flightshoes_mob" + var/obj/item/clothing/suit/space/hardsuit/flightsuit/suit = null + var/obj/item/device/flightpack/pack = null + var/mob/living/carbon/human/wearer = null + var/active = 0 + resistance_flags = FIRE_PROOF | ACID_PROOF + +/obj/item/clothing/shoes/flightshoes/Destroy() + if(suit) + suit.shoes = null + +/obj/item/clothing/shoes/flightshoes/proc/toggle(toggle) + if(suit) + active = toggle + if(active) + src.flags |= NOSLIP + if(!active) + src.flags &= ~NOSLIP + +/obj/item/clothing/shoes/flightshoes/dropped(mob/wearer) + ..() + +/obj/item/clothing/shoes/flightshoes/item_action_slot_check(slot) + if(slot == slot_shoes) + return 1 + +/obj/item/clothing/shoes/flightshoes/proc/delink_suit() + if(suit) + if(suit.shoes && suit.shoes == src) + suit.shoes = null + suit = null + +/obj/item/clothing/shoes/flightshoes/proc/relink_suit(obj/item/clothing/suit/space/hardsuit/flightsuit/F) + if(suit && suit == F) + return 0 + else + delink_suit() + if(istype(F)) + suit = F + suit.shoes = src + else + suit = null + +//FLIGHT SUIT------------------------------------------------------------------------------------------------------------------------------------------------------ +//Flight pack and flight shoes/helmet are stored in here. This has to be locked to someone to use either. For both balance reasons and practical codewise reasons. + +/obj/item/clothing/suit/space/hardsuit/flightsuit + name = "flight suit" + desc = "An advanced suit that allows the wearer flight via two high powered miniature jet engines on a deployable back-mounted unit." + icon_state = "flightsuit" + item_state = "flightsuit" + strip_delay = 30 + var/locked_strip_delay = 80 + w_class = 4 + var/obj/item/device/flightpack/pack = null + var/obj/item/clothing/shoes/flightshoes/shoes = null + var/mob/living/carbon/human/user = null + var/deployedpack = 0 + var/deployedshoes = 0 + var/locked = 0 + resistance_flags = FIRE_PROOF | ACID_PROOF + helmettype = /obj/item/clothing/head/helmet/space/hardsuit/flightsuit + jetpack = null + var/flightpack + var/flight = 0 + allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank/internals, /obj/item/weapon/gun,/obj/item/weapon/reagent_containers/spray/pepper,/obj/item/ammo_box,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/restraints/handcuffs) + actions_types = list(/datum/action/item_action/flightsuit/toggle_helmet,/datum/action/item_action/flightsuit/toggle_boots,/datum/action/item_action/flightsuit/toggle_flightpack,/datum/action/item_action/flightsuit/lock_suit) + armor = list(melee = 20, bullet = 20, laser = 20, energy = 10, bomb = 30, bio = 100, rad = 75, fire = 100, acid = 100) + var/maint_panel = 0 + max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT + +/obj/item/clothing/suit/space/hardsuit/flightsuit/full/New() + ..() + makepack() + makeshoes() + resync() + +/obj/item/clothing/suit/space/hardsuit/flightsuit/proc/usermessage(message, urgency = 0) + if(!urgency) + user << "\icon[src]|[message]" + else if(urgency == 1) + user << "\icon[src]|[message]" + else if(urgency == 2) + user << "\icon[src]|[message]" + +/obj/item/clothing/suit/space/hardsuit/flightsuit/examine(mob/user) + usermessage("SUIT: [locked ? "LOCKED" : "UNLOCKED"]") + usermessage("FLIGHTPACK: [deployedpack ? "ENGAGED" : "DISENGAGED"] FLIGHTSHOES : [deployedshoes ? "ENGAGED" : "DISENGAGED"] HELMET : [suittoggled ? "ENGAGED" : "DISENGAGED"]") + usermessage("Its maintainence panel is [maint_panel ? "OPEN" : "CLOSED"].") + +/obj/item/clothing/suit/space/hardsuit/flightsuit/Destroy() + dropped() + if(pack) + pack.delink_suit() + qdel(pack) + if(shoes) + shoes.pack = null + shoes.suit = null + qdel(shoes) + ..() + +/obj/item/clothing/suit/space/hardsuit/flightsuit/proc/resync() + if(pack) + pack.relink_suit(src) + if(user) + if(pack) + pack.wearer = user + if(shoes) + shoes.wearer = user + else + if(pack) + pack.wearer = null + if(shoes) + shoes.wearer = null + if(shoes) + shoes.relink_suit(src) + +/obj/item/clothing/suit/space/hardsuit/flightsuit/attack_hand(mob/user) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(src == H.wear_suit && locked) + usermessage("You can not take a locked hardsuit off! Unlock it first!", 1) + return + ..() + +/obj/item/clothing/suit/space/hardsuit/flightsuit/ui_action_click(owner, action) + if(istype(action, /datum/action/item_action/flightsuit/lock_suit)) + if(!locked) + lock_suit(owner) + else + unlock_suit(owner) + if(istype(action, /datum/action/item_action/flightsuit/toggle_flightpack)) + if(!deployedpack) + extend_flightpack() + else + retract_flightpack() + if(istype(action, /datum/action/item_action/flightsuit/toggle_boots)) + if(!deployedshoes) + extend_flightshoes() + else + retract_flightshoes() + if(istype(action, /datum/action/item_action/flightsuit/toggle_helmet)) + ToggleHelmet() + +/obj/item/clothing/suit/space/hardsuit/flightsuit/dropped() + if(deployedpack) + retract_flightpack(1) + if(deployedshoes) + retract_flightshoes(1) + if(locked) + unlock_suit(null) + if(user) + user = null + ..() + +/obj/item/clothing/suit/space/hardsuit/flightsuit/ToggleHelmet() + if(!suittoggled) + if(!locked) + usermessage("You must lock your suit before engaging the helmet!", 1) + return 0 + ..() + +/obj/item/clothing/suit/space/hardsuit/flightsuit/proc/lock_suit(mob/wearer) + user = wearer + user.visible_message("[wearer]'s flight suit locks around them, powered buckles and straps automatically adjusting to their body!") + playsound(src.loc, 'sound/items/rped.ogg', 65, 1) + resync() + strip_delay = locked_strip_delay + locked = 1 + return 1 + +/obj/item/clothing/suit/space/hardsuit/flightsuit/proc/unlock_suit(mob/wearer) + if(suittoggled) + usermessage("You must retract the helmet before unlocking your suit!", 1) + return 0 + if(pack && pack.flight) + usermessage("You must shut off the flight-pack before unlocking your suit!", 1) + return 0 + if(deployedpack) + usermessage("Your flightpack must be fully retracted first!", 1) + return 0 + if(deployedshoes) + usermessage("Your flight shoes must be fully retracted first!", 1) + return 0 + if(wearer) + user.visible_message("[wearer]'s flight suit detaches from their body, becoming nothing more then a bulky metal skeleton.") + playsound(src.loc, 'sound/items/rped.ogg', 65, 1) + resync() + strip_delay = initial(strip_delay) + locked = 0 + return 1 + +/obj/item/clothing/suit/space/hardsuit/flightsuit/proc/extend_flightpack(forced = 0) + if(!pack) + usermessage("There is no attached flightpack!", 1) + return 0 + if(deployedpack) + retract_flightpack() + if(!locked) + usermessage("You must lock your flight suit first before deploying anything!", 1) + return 0 + if(ishuman(user)) + if(user.back) + usermessage("You're already wearing something on your back!", 1) + return 0 + user.equip_to_slot_if_possible(pack,slot_back,0,0,1) + pack.flags |= NODROP + resync() + user.visible_message("A [pack.name] extends from [user]'s [name] and clamps to their back!") + user.update_inv_wear_suit() + playsound(src.loc, 'sound/mecha/mechmove03.ogg', 50, 1) + deployedpack = 1 + +/obj/item/clothing/suit/space/hardsuit/flightsuit/proc/retract_flightpack(forced = 0) + if(ishuman(user)) + if(pack.flight && !forced) + usermessage("You must disable the engines before retracting the flightpack!", 1) + return 0 + if(pack.flight && forced) + pack.disable_flight(1) + pack.flags &= ~NODROP + resync() + if(user) + user.unEquip(pack, 1) + user.update_inv_wear_suit() + user.visible_message("[user]'s [pack.name] detaches from their back and retracts into their [src]!") + pack.loc = src + playsound(src.loc, 'sound/mecha/mechmove03.ogg', 50, 1) + deployedpack = 0 + +/obj/item/clothing/suit/space/hardsuit/flightsuit/proc/extend_flightshoes(forced = 0) + if(!shoes) + usermessage("Flight shoes are not installed!", 1) + return 0 + if(deployedshoes) + retract_flightshoes() + if(!locked) + usermessage("You must lock your flight suit first before deploying anything!", 1) + return 0 + if(ishuman(user)) + if(user.shoes) + usermessage("You're already wearing something on your feet!", 1) + return 0 + user.equip_to_slot_if_possible(shoes,slot_shoes,0,0,1) + shoes.flags |= NODROP + user.visible_message("[user]'s [name] extends a pair of [shoes.name] over their feet!") + user.update_inv_wear_suit() + playsound(src.loc, 'sound/mecha/mechmove03.ogg', 50, 1) + deployedshoes = 1 + +/obj/item/clothing/suit/space/hardsuit/flightsuit/proc/retract_flightshoes(forced = 0) + shoes.flags &= ~NODROP + playsound(src.loc, 'sound/mecha/mechmove03.ogg', 50, 1) + deployedshoes = 0 + if(user) + user.unEquip(shoes, 1) + user.update_inv_wear_suit() + user.visible_message("[user]'s [shoes.name] retracts back into their [name]!") + shoes.loc = src + +/obj/item/clothing/suit/space/hardsuit/flightsuit/proc/makepack() + if(!pack) + pack = new /obj/item/device/flightpack/full(src) + pack.relink_suit(src) + +/obj/item/clothing/suit/space/hardsuit/flightsuit/proc/makeshoes() + if(!shoes) + shoes = new /obj/item/clothing/shoes/flightshoes(src) + shoes.pack = pack + shoes.suit = src + +/obj/item/clothing/suit/space/hardsuit/flightsuit/equipped(mob/M, slot) + if(ishuman(M)) + user = M + if(slot != slot_wear_suit) + if(deployedpack) + retract_flightpack(1) + if(deployedshoes) + retract_flightshoes(1) + if(locked) + unlock_suit(user) + ..() + +/obj/item/clothing/suit/space/hardsuit/flightsuit/proc/detach_pack() + pack.delink_suit() + pack.loc = get_turf(src) + pack = null + usermessage("You detach the flightpack.") + +/obj/item/clothing/suit/space/hardsuit/flightsuit/proc/attach_pack(obj/item/device/flightpack/F) + F.loc = src + pack = F + pack.relink_suit(src) + usermessage("You attach and fasten the flightpack.") + +/obj/item/clothing/suit/space/hardsuit/flightsuit/proc/detach_shoes() + shoes.delink_suit() + shoes.loc = get_turf(src) + shoes = null + usermessage("You detach the flight shoes.") + +/obj/item/clothing/suit/space/hardsuit/flightsuit/proc/attach_shoes(obj/item/clothing/shoes/flightshoes/S) + S.loc = src + shoes = S + shoes.relink_suit(src) + usermessage("You attach and fasten a pair of flight shoes.") + +/obj/item/clothing/suit/space/hardsuit/flightsuit/attackby(obj/item/I, mob/wearer, params) + user = wearer + if(src == user.get_item_by_slot(slot_wear_suit)) + usermessage("You can not perform any service without taking the suit off!", 1) + return 0 + if(locked) + usermessage("You can not perform any service while the suit is locked!", 1) + return 0 + if(istype(I, /obj/item/weapon/screwdriver)) + if(!maint_panel) + maint_panel = 1 + else + maint_panel = 0 + usermessage("You [maint_panel? "open" : "close"] the maintainence panel.") + if(!maint_panel) + usermessage("The maintainence panel is closed!", 1) + return 0 + if(istype(I, /obj/item/weapon/crowbar)) + var/list/inputlist = list() + if(pack) + inputlist += "Pack" + if(shoes) + inputlist += "Shoes" + if(!inputlist.len) + usermessage("There is nothing inside the flightsuit to remove!", 1) + return 0 + var/input = input(user, "What to remove?", "Removing module") as null|anything in list("Pack", "Shoes") + if(pack && input == "Pack") + if(pack.flight) + usermessage("You can not pry off an active flightpack!", 1) + return 0 + if(deployedpack) + usermessage("Disengage the flightpack first!", 1) + return 0 + detach_pack() + if(shoes && input == "Shoes") + if(deployedshoes) + usermessage("Disengage the shoes first!", 1) + return 0 + detach_shoes() + if(istype(I, /obj/item/device/flightpack)) + var/obj/item/device/flightpack/F = I + if(pack) + usermessage("[src] already has a flightpack installed!", 1) + return 0 + if(!F.assembled) + var/addmsg = " It is missing a " + var/list/addmsglist = list() + if(!F.part_manip) + addmsglist += "manipulator" + if(!F.part_cap) + addmsglist += "capacitor" + if(!F.part_scan) + addmsglist += "scanning module" + if(!F.part_laser) + addmsglist += "micro-laser" + if(!F.part_bin) + addmsglist += "matter bin" + addmsg += english_list(addmsglist) + usermessage("The flightpack you are trying to install is not fully assembled and operational![addmsg].", 1) + return 0 + if(user.unEquip(F)) + attach_pack(F) + if(istype(I, /obj/item/clothing/shoes/flightshoes)) + var/obj/item/clothing/shoes/flightshoes/S = I + if(shoes) + usermessage("There are already shoes installed!", 1) + return 0 + if(user.unEquip(S)) + attach_shoes(S) + +//FLIGHT HELMET---------------------------------------------------------------------------------------------------------------------------------------------------- +/obj/item/clothing/head/helmet/space/hardsuit/flightsuit + name = "flight helmet" + desc = "A sealed helmet attached to a flight suit for EVA usage scenerios." + icon_state = "flighthelmet" + item_state = "flighthelmet" + item_color = "flight" + resistance_flags = FIRE_PROOF | ACID_PROOF + brightness_on = 7 + armor = list(melee = 20, bullet = 20, laser = 20, energy = 10, bomb = 30, bio = 100, rad = 75, fire = 100, acid = 100) + max_heat_protection_temperature = FIRE_HELM_MAX_TEMP_PROTECT + +//ITEM actionS------------------------------------------------------------------------------------------------------------------------------------------------------ +//TODO: TOGGLED BUTTON SPRITES +/datum/action/item_action/flightsuit/toggle_boots + name = "Toggle Boots" + button_icon_state = "flightsuit_shoes" + background_icon_state = "bg_tech" + +/datum/action/item_action/flightsuit/toggle_helmet + name = "Toggle Helmet" + button_icon_state = "flightsuit_helmet" + background_icon_state = "bg_tech" + +/datum/action/item_action/flightsuit/toggle_flightpack + name = "Toggle Flightpack" + button_icon_state = "flightsuit_pack" + background_icon_state = "bg_tech" + +/datum/action/item_action/flightsuit/lock_suit + name = "Lock Suit" + button_icon_state = "flightsuit_lock" + background_icon_state = "bg_tech" + +/datum/action/item_action/flightpack/toggle_flight + name = "Toggle Flight" + button_icon_state = "flightpack_fly" + background_icon_state = "bg_tech_blue" + +/datum/action/item_action/flightpack/engage_boosters + name = "Toggle Boosters" + button_icon_state = "flightpack_boost" + background_icon_state = "bg_tech_blue" + +/datum/action/item_action/flightpack/toggle_stabilizers + name = "Toggle Stabilizers" + button_icon_state = "flightpack_stabilizer" + background_icon_state = "bg_tech_blue" + +/datum/action/item_action/flightpack/change_power + name = "Flight Power Setting" + button_icon_state = "flightpack_power" + background_icon_state = "bg_tech_blue" + +/datum/action/item_action/flightpack/toggle_airbrake + name = "Toggle Airbrake" + button_icon_state = "flightpack_airbrake" + background_icon_state = "bg_tech_blue" diff --git a/code/modules/mob/living/carbon/carbon_movement.dm b/code/modules/mob/living/carbon/carbon_movement.dm index fc44e0262e2..fa350ddd9fd 100644 --- a/code/modules/mob/living/carbon/carbon_movement.dm +++ b/code/modules/mob/living/carbon/carbon_movement.dm @@ -1,15 +1,23 @@ /mob/living/carbon/movement_delay() - . = ..() - . += grab_state * 3 //can't go fast while grabbing something. + var/FP + if(iscarbon(src)) + var/mob/living/carbon/C = src + var/obj/item/device/flightpack/F = C.get_flightpack() + if(istype(F) && F.flight) + FP = 1 + . = ..(FP) + if(!FP) + . += grab_state * 1 //Flightpacks are too powerful to be slowed too much by the weight of a corpse. + else + . += grab_state * 3 //can't go fast while grabbing something. if(!get_leg_ignore()) //ignore the fact we lack legs var/leg_amount = get_num_legs() . += 6 - 3*leg_amount //the fewer the legs, the slower the mob if(!leg_amount) . += 6 - 3*get_num_arms() //crawling is harder with fewer arms - - if(legcuffed) - . += legcuffed.slowdown + if(legcuffed) + . += legcuffed.slowdown var/const/NO_SLIP_WHEN_WALKING = 1 @@ -18,6 +26,8 @@ var/const/GALOSHES_DONT_HELP = 4 var/const/SLIDE_ICE = 8 /mob/living/carbon/slip(s_amount, w_amount, obj/O, lube) + if(movement_type & FLYING) + return 0 if(!(lube&SLIDE_ICE)) add_logs(src,, "slipped",, "on [O ? O.name : "floor"]") return loc.handle_slip(src, s_amount, w_amount, O, lube) @@ -29,6 +39,10 @@ var/const/SLIDE_ICE = 8 if(!isturf(loc)) return 0 + var/obj/item/device/flightpack/F = get_flightpack() + if(istype(F) && (F.flight) && F.allow_thrust(0.01, src)) + return 1 + // Do we have a jetpack implant (and is it on)? var/obj/item/organ/cyberimp/chest/thrusters/T = getorganslot("thrusters") if(istype(T) && movement_dir && T.allow_thrust(0.01)) @@ -38,8 +52,6 @@ var/const/SLIDE_ICE = 8 if(istype(J) && (movement_dir || J.stabilizers) && J.allow_thrust(0.01, src)) return 1 - - /mob/living/carbon/Move(NewLoc, direct) . = ..() if(.) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 042327d3ee9..4092302e54f 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -911,3 +911,9 @@ Weaken(10) return 1 ..() + +/mob/living/carbon/human/Bump(atom/A) + ..() + var/obj/item/device/flightpack/FP = get_flightpack() + if(FP) + FP.flight_impact(A) diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 3bb4c433f4c..41aacf720cc 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -3,7 +3,6 @@ . += ..() . += config.human_delay - /mob/living/carbon/human/slip(s_amount, w_amount, obj/O, lube) if(isobj(shoes) && (shoes.flags&NOSLIP) && !(lube&GALOSHES_DONT_HELP)) return 0 @@ -60,4 +59,4 @@ /mob/living/carbon/human/Process_Spacemove(movement_dir = 0) //Temporary laziness thing. Will change to handles by species reee. if(..()) return 1 - return dna.species.space_move() + return dna.species.space_move(src) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 5daad2a3604..16d476bc041 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -864,15 +864,23 @@ /datum/species/proc/movement_delay(mob/living/carbon/human/H) . = 0 + var/obj/item/device/flightpack/F = H.get_flightpack() + var/flightpack = 0 + if(istype(F) && F.flight) + flightpack = 1 + var/flight = 0 + if(H.movement_type & FLYING) + flight = 1 - if(H.status_flags & GOTTAGOFAST) - . -= 1 - if(H.status_flags & GOTTAGOREALLYFAST) - . -= 2 + if(!flightpack) + if(H.status_flags & GOTTAGOFAST) + . -= 1 + if(H.status_flags & GOTTAGOREALLYFAST) + . -= 2 if(!(H.status_flags & IGNORESLOWDOWN)) if(!H.has_gravity()) - if(FLYING in specflags) + if((H.movement_type & FLYING) && !flightpack) //No hyperstacking angel wings! . += speedmod return // If there's no gravity we have the sanic speed of jetpack. @@ -888,30 +896,36 @@ if(istype(T) && T.allow_thrust(0.01, H)) . -= 2 - else + else if(flightpack && F.allow_thrust(0.01, src)) //No jetpack/flightsuit hyperstacking! + . -= 1 + + if(H.wear_suit) + . += H.wear_suit.slowdown + if(H.shoes) + . += H.shoes.slowdown + if(H.back) + . += H.back.slowdown + for(var/obj/item/I in H.held_items) + if(I.flags & HANDSLOW) + . += I.slowdown + if(!(flightpack)) var/health_deficiency = (100 - H.health + H.staminaloss) if(health_deficiency >= 40) - . += (health_deficiency / 25) + if(flight) + . += (health_deficiency / 75) + else + . += (health_deficiency / 25) var/hungry = (500 - H.nutrition) / 5 // So overeat would be 100 and default level would be 80 - if(hungry >= 70) + if((hungry >= 70) && !flight) //Being hungry won't stop you from using flightpack controls/flapping your wings although it probably will in the wing case but who cares. . += hungry / 50 - if(H.wear_suit) - . += H.wear_suit.slowdown - if(H.shoes) - . += H.shoes.slowdown - if(H.back) - . += H.back.slowdown - for(var/obj/item/I in H.held_items) - if(I.flags & HANDSLOW) - . += I.slowdown if((H.disabilities & FAT)) - . += 1.5 + . += (1.5 - flight) if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT) . += (BODYTEMP_COLD_DAMAGE_LIMIT - H.bodytemperature) / COLD_SLOWDOWN_FACTOR - . += speedmod + . += speedmod ////////////////// // ATTACK PROCS // @@ -1335,10 +1349,10 @@ //Space Move// ////////////// -/datum/species/proc/space_move() +/datum/species/proc/space_move(mob/living/carbon/human/H) return 0 -/datum/species/proc/negates_gravity() +/datum/species/proc/negates_gravity(mob/living/carbon/human/H) return 0 diff --git a/code/modules/mob/living/carbon/human/species_types.dm b/code/modules/mob/living/carbon/human/species_types.dm index ff4349f9b3f..6b7cfae7478 100644 --- a/code/modules/mob/living/carbon/human/species_types.dm +++ b/code/modules/mob/living/carbon/human/species_types.dm @@ -15,7 +15,7 @@ /datum/species/human/qualifies_for_rank(rank, list/features) if((!features["tail_human"] || features["tail_human"] == "None") && (!features["ears"] || features["ears"] == "None")) - return 1 //Pure humans are always allowed in all roles. + return TRUE //Pure humans are always allowed in all roles. return ..() //Curiosity killed the cat's wagging tail. @@ -23,6 +23,10 @@ if(H) H.endTailWag() +/datum/species/human/space_move(mob/living/carbon/human/H) + var/obj/item/device/flightpack/F = H.get_flightpack() + if(istype(F) && (F.flight) && F.allow_thrust(0.01, src)) + return TRUE /* LIZARDPEOPLE */ @@ -1003,8 +1007,8 @@ SYNDICATE BLACK OPS /datum/species/angel/on_species_loss(mob/living/carbon/human/H) if(fly) fly.Remove(H) - if(FLYING in specflags) - specflags -= FLYING + if(H.movement_type & FLYING) + H.movement_type &= ~FLYING ToggleFlight(H,0) if(H.dna && H.dna.species &&((H.dna.features["wings"] != "None") && ("wings" in H.dna.species.mutant_bodyparts))) H.dna.features["wings"] = "None" @@ -1015,15 +1019,12 @@ SYNDICATE BLACK OPS HandleFlight(H) /datum/species/angel/proc/HandleFlight(mob/living/carbon/human/H) - if(FLYING in specflags) + if(H.movement_type & FLYING) if(!CanFly(H)) ToggleFlight(H,0) - H.float(0) return 0 - H.float(1) return 1 else - H.float(0) return 0 /datum/species/angel/proc/CanFly(mob/living/carbon/human/H) @@ -1052,7 +1053,7 @@ SYNDICATE BLACK OPS var/mob/living/carbon/human/H = owner var/datum/species/angel/A = H.dna.species if(A.CanFly(H)) - if(FLYING in A.specflags) + if(H.movement_type & FLYING) H << "You settle gently back onto the ground..." A.ToggleFlight(H,0) H.update_canmove() @@ -1089,31 +1090,31 @@ SYNDICATE BLACK OPS /datum/species/angel/spec_stun(mob/living/carbon/human/H,amount) - if(FLYING in specflags) + if(H.movement_type & FLYING) ToggleFlight(H,0) flyslip(H) . = ..() -/datum/species/angel/negates_gravity() - if(FLYING in specflags) +/datum/species/angel/negates_gravity(mob/living/carbon/human/H) + if(H.movement_type & FLYING) return 1 -/datum/species/angel/space_move() - if(FLYING in specflags) +/datum/species/angel/space_move(mob/living/carbon/human/H) + if(H.movement_type & FLYING) return 1 /datum/species/angel/proc/ToggleFlight(mob/living/carbon/human/H,flight) if(flight && CanFly(H)) stunmod = 2 speedmod = -1 - specflags += FLYING + H.movement_type |= FLYING override_float = 1 H.pass_flags |= PASSTABLE H.OpenWings() else stunmod = 1 speedmod = 0 - specflags -= FLYING + H.movement_type &= ~FLYING override_float = 0 H.pass_flags &= ~PASSTABLE H.CloseWings() diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index 19cca48a15b..205bbbd0d1d 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -50,10 +50,15 @@ if(stat != DEAD) handle_status_effects() //all special effects, stunned, weakened, jitteryness, hallucination, sleeping, etc + if(floating && (!(movement_type & FLYING))) + float(0) + + if(movement_type & FLYING) + float(1) + if(stat != DEAD) return 1 - /mob/living/proc/handle_breathing() return diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index c755ba4c402..f190acba63d 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -438,18 +438,21 @@ if (s_active && !(s_active.ClickAccessible(src, depth=STORAGE_VIEW_DEPTH) || s_active.Adjacent(src))) s_active.close(src) -/mob/living/movement_delay() +/mob/living/movement_delay(ignorewalk = 0) . = ..() - if(isopenturf(loc)) + if(isopenturf(loc) && !is_flying()) var/turf/open/T = loc . += T.slowdown - switch(m_intent) - if("run") - if(drowsyness > 0) - . += 6 - . += config.run_speed - if("walk") - . += config.walk_speed + if(!ignorewalk) + . += config.run_speed + else + switch(m_intent) + if("run") + if(drowsyness > 0) + . += 6 + . += config.run_speed + if("walk") + . += config.walk_speed /mob/living/proc/makeTrail(turf/T) if(!has_gravity()) @@ -603,6 +606,8 @@ fixed = 1 if(on && !floating && !fixed) animate(src, pixel_y = pixel_y + 2, time = 10, loop = -1) + sleep(10) + animate(src, pixel_y = pixel_y - 2, time = 10, loop = -1) floating = 1 else if(((!on || fixed) && floating)) animate(src, pixel_y = get_standard_pixel_y_offset(lying), time = 10) diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index 92617a0c333..5a7eceaf92e 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -21,7 +21,7 @@ maxbodytemp = INFINITY healable = 0 faction = list("cult") - flying = 1 + movement_type = FLYING pressure_resistance = 100 unique_name = 1 AIStatus = AI_OFF //normal constructs don't have AI diff --git a/code/modules/mob/living/simple_animal/friendly/butterfly.dm b/code/modules/mob/living/simple_animal/friendly/butterfly.dm index c4ca476732a..a359d8810f0 100644 --- a/code/modules/mob/living/simple_animal/friendly/butterfly.dm +++ b/code/modules/mob/living/simple_animal/friendly/butterfly.dm @@ -14,7 +14,7 @@ harm_intent_damage = 1 friendly = "nudges" density = 0 - flying = 1 + movement_type = FLYING pass_flags = PASSTABLE | PASSGRILLE | PASSMOB ventcrawler = 2 mob_size = MOB_SIZE_TINY diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm index 7063fe1f35f..e1eeda4aada 100644 --- a/code/modules/mob/living/simple_animal/guardian/guardian.dm +++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm @@ -21,7 +21,7 @@ var/global/list/parasites = list() //all currently existing/living guardians speed = 0 a_intent = "harm" stop_automated_movement = 1 - flying = 1 // Immunity to chasms and landmines, etc. + movement_type = FLYING // Immunity to chasms and landmines, etc. attack_sound = 'sound/weapons/punch1.ogg' atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) minbodytemp = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/bees.dm b/code/modules/mob/living/simple_animal/hostile/bees.dm index 130651c9f4a..84059e663c2 100644 --- a/code/modules/mob/living/simple_animal/hostile/bees.dm +++ b/code/modules/mob/living/simple_animal/hostile/bees.dm @@ -35,7 +35,7 @@ mouse_opacity = 2 pass_flags = PASSTABLE | PASSGRILLE | PASSMOB mob_size = MOB_SIZE_TINY - flying = 1 + movement_type = FLYING gold_core_spawnable = 1 search_objects = 1 //have to find those plant trays! diff --git a/code/modules/mob/living/simple_animal/hostile/carp.dm b/code/modules/mob/living/simple_animal/hostile/carp.dm index bf99d02e8a4..fe18390b58b 100644 --- a/code/modules/mob/living/simple_animal/hostile/carp.dm +++ b/code/modules/mob/living/simple_animal/hostile/carp.dm @@ -31,7 +31,7 @@ maxbodytemp = 1500 faction = list("carp") - flying = 1 + movement_type = FLYING pressure_resistance = 200 gold_core_spawnable = 1 diff --git a/code/modules/mob/living/simple_animal/hostile/eyeballs.dm b/code/modules/mob/living/simple_animal/hostile/eyeballs.dm index 07aeea0a523..a3e6dd65405 100644 --- a/code/modules/mob/living/simple_animal/hostile/eyeballs.dm +++ b/code/modules/mob/living/simple_animal/hostile/eyeballs.dm @@ -22,7 +22,7 @@ melee_damage_upper = 25 attacktext = "blinks at" attack_sound = 'sound/weapons/pierce.ogg' - flying = 1 + movement_type = FLYING faction = list("spooky") del_on_death = 1 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index 52532ed3294..49aff0ab8f3 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -606,7 +606,7 @@ Difficulty: Very Hard harm_intent_damage = 1 friendly = "mends" density = 0 - flying = 1 + movement_type = FLYING pass_flags = PASSTABLE | PASSGRILLE | PASSMOB ventcrawler = 2 mob_size = MOB_SIZE_TINY @@ -622,6 +622,7 @@ Difficulty: Very Hard languages_understood = ALL del_on_death = 1 unsuitable_atmos_damage = 0 + movement_type = FLYING minbodytemp = 0 maxbodytemp = 1500 obj_damage = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm index 2ec03fa2030..cfc8ab40d36 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm @@ -13,7 +13,7 @@ luminosity = 3 faction = list("mining", "boss") weather_immunities = list("lava","ash") - flying = 1 + movement_type = FLYING robust_searching = 1 ranged_ignores_vision = TRUE stat_attack = 2 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm index 1f8f60d8843..754543f29ef 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm @@ -322,7 +322,7 @@ speed = 3 maxHealth = 1 health = 1 - flying = 1 + movement_type = FLYING harm_intent_damage = 5 melee_damage_lower = 2 melee_damage_upper = 2 @@ -713,7 +713,7 @@ speak_emote = list("telepathically cries") attack_sound = 'sound/weapons/bladeslice.ogg' stat_attack = 1 - flying = TRUE + movement_type = FLYING robust_searching = 1 loot = list() butcher_results = list(/obj/item/weapon/ore/diamond = 2, /obj/item/stack/sheet/sinew = 2, /obj/item/stack/sheet/bone = 1) diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm index c28250e3fcc..9684ec508b6 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm @@ -25,7 +25,7 @@ environment_smash = 0 ventcrawler = 2 mob_size = MOB_SIZE_TINY - flying = 1 + movement_type = FLYING speak_emote = list("squeaks") var/max_co2 = 0 //to be removed once metastation map no longer use those for Sgt Araneus var/min_oxy = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm index 37ad0697c6c..3c74f7b3447 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm @@ -27,7 +27,7 @@ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) minbodytemp = 0 maxbodytemp = 1500 - flying = 1 + movement_type = FLYING pressure_resistance = 300 gold_core_spawnable = 0 //too spooky for science var/ghost_hair_style diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm index f61ea5be1d0..e6168088f9f 100644 --- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm +++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm @@ -163,7 +163,7 @@ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) minbodytemp = 0 mob_size = MOB_SIZE_TINY - flying = 1 + movement_type = FLYING limb_destroyer = 1 speak_emote = list("states") bubble_icon = "syndibot" diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm index a50171ecac6..3b99c851962 100644 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -57,7 +57,7 @@ attacktext = "chomps" friendly = "grooms" mob_size = MOB_SIZE_SMALL - flying = 1 + movement_type = FLYING gold_core_spawnable = 2 var/parrot_damage_upper = 10 diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm index bd06a445cc9..b3cb38ba21c 100644 --- a/code/modules/mob/living/simple_animal/shade.dm +++ b/code/modules/mob/living/simple_animal/shade.dm @@ -26,7 +26,7 @@ status_flags = 0 faction = list("cult") status_flags = CANPUSH - flying = 1 + movement_type = FLYING loot = list(/obj/item/weapon/ectoplasm) del_on_death = 1 diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index e01b4a2799e..17677a07b85 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -62,7 +62,6 @@ //simple_animal access var/obj/item/weapon/card/id/access_card = null //innate access uses an internal ID card - var/flying = 0 //whether it's flying or touching the ground. var/buffed = 0 //In the event that you want to have a buffing effect on the mob, but don't want it to stack with other effects, any outside force that applies a buff to a simple mob should at least set this to 1, so we have something to check against var/gold_core_spawnable = 0 //if 1 can be spawned by plasma with gold core, 2 are 'friendlies' spawned with blood diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index 090f98621f2..4b42ccfa867 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -69,4 +69,5 @@ AA.display_to(list(src)) update_client_colour() - client.click_intercept = null \ No newline at end of file + if(client) + client.click_intercept = null diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index de84e2491a8..9bf23945106 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -30,6 +30,7 @@ var/obj/machinery/machine = null var/other_mobs = null var/disabilities = 0 //Carbon + var/movement_type = GROUND //Incase you have multiple types, you automatically use the most useful one. IE: Skating on ice, flippers on water, flying over chasm/space, etc. var/atom/movable/pulling = null var/grab_state = 0 diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 0c03c4a056d..425530f6274 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -483,3 +483,8 @@ It's fairly easy to fix if dealing with single letters but not so much with comp for(var/obj/screen/wheel/talk/TW in L.hud_used.wheels) TW.Click() +/mob/proc/is_flying(mob/M = src) + if(M.movement_type & FLYING) + return 1 + else + return 0 diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 14df027d382..ea5182b8494 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -175,6 +175,9 @@ if(mob && .) mob.throwing = 0 + for(var/obj/O in mob) + O.on_mob_move(direct, src) + return . diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index 056378aff24..d392e8e55fb 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -709,3 +709,33 @@ construction_time = 100 build_path = /obj/item/device/assembly/flash/handheld category = list("Misc") + +/datum/design/flightsuit //Multi step build process/redo WIP + name = "Flight Suit" + desc = "A specialized hardsuit that is able to attach a flightpack and accessories.." + id = "flightsuit" + build_type = MECHFAB + build_path = /obj/item/clothing/suit/space/hardsuit/flightsuit + materials = list(MAT_METAL=20000, MAT_GLASS = 10000, MAT_DIAMOND = 200, MAT_GOLD = 3000, MAT_SILVER = 3000, MAT_TITANIUM = 20000) //This expensive enough for you? + construction_time = 250 + category = list("Misc") + +/datum/design/flightpack + name = "Flight Pack" + desc = "An advanced back-worn system that has dual ion engines powerful enough to grant a humanoid flight. Contains an internal self-recharging high-current capacitor for short, powerful boosts." + id = "flightpack" + build_type = MECHFAB + build_path = /obj/item/device/flightpack + materials = list(MAT_METAL=20000, MAT_GLASS = 10000, MAT_DIAMOND = 5000, MAT_GOLD = 15000, MAT_SILVER = 15000, MAT_URANIUM = 25000, MAT_PLASMA = 20000, MAT_TITANIUM = 20000) //This expensive enough for you? + construction_time = 250 + category = list("Misc") + +/datum/design/flightshoes + name = "Flight Shoes" + desc = "Flight shoes, attachable to a flight suit to provide additional functions." + id = "flightshoes" + build_type = MECHFAB + build_path = /obj/item/clothing/shoes/flightshoes + materials = list(MAT_METAL = 5000, MAT_GLASS = 5000, MAT_GOLD = 1500, MAT_SILVER = 1500, MAT_PLASMA = 2000, MAT_TITANIUM = 2000) //They're just shoes. + construction_time = 100 + category = list("Misc") \ No newline at end of file diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm index 126578de7d6..c58526b347b 100644 --- a/code/modules/surgery/bodyparts/helpers.dm +++ b/code/modules/surgery/bodyparts/helpers.dm @@ -89,7 +89,7 @@ return 1 /mob/living/carbon/human/get_leg_ignore() - if(FLYING in dna.species.specflags) + if(movement_type & FLYING) return 1 /mob/living/proc/get_missing_limbs() diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index 3d3b0040646..cc568e08d06 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/effects/trail.dmi b/icons/effects/trail.dmi new file mode 100644 index 00000000000..cb2fcff8798 Binary files /dev/null and b/icons/effects/trail.dmi differ diff --git a/icons/mob/actions.dmi b/icons/mob/actions.dmi index a445a036698..9408e9847bf 100644 Binary files a/icons/mob/actions.dmi and b/icons/mob/actions.dmi differ diff --git a/icons/mob/back.dmi b/icons/mob/back.dmi index 1f845ba1293..04c9ecaf891 100644 Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi index 4f1b40e12a7..4d42640f396 100644 Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi index b162503d9c6..77346a63d3a 100644 Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ diff --git a/icons/obj/clothing/flightsuit.dmi b/icons/obj/clothing/flightsuit.dmi new file mode 100644 index 00000000000..e08e74db1ce Binary files /dev/null and b/icons/obj/clothing/flightsuit.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index a42d1d7a129..5f771f49c7d 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/clothing/shoes.dmi b/icons/obj/clothing/shoes.dmi index 53beecf4b41..e795d162796 100644 Binary files a/icons/obj/clothing/shoes.dmi and b/icons/obj/clothing/shoes.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi index 9edba5dc137..c272acebcc3 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index 617d7824d07..8bdf0c4e427 100644 Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ diff --git a/tgstation.dme b/tgstation.dme index e4567eabc12..9e9aa46d19b 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1104,6 +1104,7 @@ #include "code\modules\clothing\shoes\magboots.dm" #include "code\modules\clothing\shoes\miscellaneous.dm" #include "code\modules\clothing\spacesuits\chronosuit.dm" +#include "code\modules\clothing\spacesuits\flightsuit.dm" #include "code\modules\clothing\spacesuits\hardsuit.dm" #include "code\modules\clothing\spacesuits\miscellaneous.dm" #include "code\modules\clothing\spacesuits\plasmamen.dm"