From cf6580111939cec7023fb4ba4217640ea333c874 Mon Sep 17 00:00:00 2001 From: lectronyx <78713019+lectronyx@users.noreply.github.com> Date: Thu, 13 Jun 2024 00:58:34 -0400 Subject: [PATCH] restores ballistic.dm --- code/modules/projectiles/guns/ballistic.dm | 485 +++++++++++++++++++++ shiptest.dme | 266 +++++++++++ 2 files changed, 751 insertions(+) create mode 100644 code/modules/projectiles/guns/ballistic.dm diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm new file mode 100644 index 0000000000..e5345c0eab --- /dev/null +++ b/code/modules/projectiles/guns/ballistic.dm @@ -0,0 +1,485 @@ +#define EMPTY_GUN_HELPER(gun_type) \ + /obj/item/gun/ballistic/##gun_type/no_mag { \ + spawnwithmagazine = FALSE; \ + } + +///Subtype for any kind of ballistic gun +///This has a shitload of vars on it, and I'm sorry for that, but it does make making new subtypes really easy +/obj/item/gun/ballistic + desc = "Now comes in flavors like GUN. Uses 10mm ammo, for some reason." + name = "projectile gun" + icon_state = "pistol" + w_class = WEIGHT_CLASS_NORMAL + + has_safety = TRUE + safety = TRUE + + ///sound when inserting magazine + var/load_sound = 'sound/weapons/gun/general/magazine_insert_full.ogg' + ///sound when inserting an empty magazine + var/load_empty_sound = 'sound/weapons/gun/general/magazine_insert_empty.ogg' + ///volume of loading sound + var/load_sound_volume = 40 + ///whether loading sound should vary + var/load_sound_vary = TRUE + ///sound of racking + var/rack_sound = 'sound/weapons/gun/general/bolt_rack.ogg' + ///volume of racking + var/rack_sound_volume = 60 + ///whether racking sound should vary + var/rack_sound_vary = TRUE + ///sound of when the bolt is locked back manually + var/lock_back_sound = 'sound/weapons/gun/general/slide_lock_1.ogg' + ///volume of lock back + var/lock_back_sound_volume = 60 + ///whether lock back varies + var/lock_back_sound_vary = TRUE + ///Sound of ejecting a magazine + var/eject_sound = 'sound/weapons/gun/general/magazine_remove_full.ogg' + ///sound of ejecting an empty magazine + var/eject_empty_sound = 'sound/weapons/gun/general/magazine_remove_empty.ogg' + ///volume of ejecting a magazine + var/eject_sound_volume = 40 + ///whether eject sound should vary + var/eject_sound_vary = TRUE + ///sound of dropping the bolt or releasing a slide + var/bolt_drop_sound = 'sound/weapons/gun/general/bolt_drop.ogg' + ///volume of bolt drop/slide release + var/bolt_drop_sound_volume = 60 + ///empty alarm sound (if enabled) + var/empty_alarm_sound = 'sound/weapons/gun/general/empty_alarm.ogg' + ///empty alarm volume sound + var/empty_alarm_volume = 70 + ///whether empty alarm sound varies + var/empty_alarm_vary = TRUE + + ///Whether the gun will spawn loaded with a magazine + var/spawnwithmagazine = TRUE + ///Compatible magazines with the gun + var/mag_type = /obj/item/ammo_box/magazine/m10mm //Removes the need for max_ammo and caliber info + ///Whether the sprite has a visible magazine or not + var/show_magazine_on_sprite = FALSE + ///Whether the sprite has a visible ammo display or not + var/show_magazine_on_sprite_ammo = FALSE + ///Whether the sprite has a visible indicator for being empty or not. + var/empty_indicator = FALSE + ///Whether the gun alarms when empty or not. + var/empty_alarm = FALSE + ///Do we eject the magazine upon runing out of ammo? + var/empty_autoeject = FALSE + ///Whether the gun supports multiple special mag types + var/unique_mag_sprites_for_variants = FALSE + ///The bolt type of the gun, affects quite a bit of functionality, see combat.dm defines for bolt types: BOLT_TYPE_STANDARD; BOLT_TYPE_LOCKING; BOLT_TYPE_OPEN; BOLT_TYPE_NO_BOLT + var/bolt_type = BOLT_TYPE_STANDARD + ///Used for locking bolt and open bolt guns. Set a bit differently for the two but prevents firing when true for both. + var/bolt_locked = FALSE + ///Whether the gun has to be racked each shot or not. + var/semi_auto = TRUE + ///Actual magazine currently contained within the gun + var/obj/item/ammo_box/magazine/magazine + ///whether the gun ejects the chambered casing + var/casing_ejector = TRUE + ///Whether the gun has an internal magazine or a detatchable one. Overridden by BOLT_TYPE_NO_BOLT. + var/internal_magazine = FALSE + ///Phrasing of the bolt in examine and notification messages; ex: bolt, slide, etc. + var/bolt_wording = "bolt" + ///Phrasing of the magazine in examine and notification messages; ex: magazine, box, etx + var/magazine_wording = "magazine" + ///Phrasing of the cartridge in examine and notification messages; ex: bullet, shell, dart, etc. + var/cartridge_wording = "bullet" + ///length between individual racks + var/rack_delay = 5 + ///time of the most recent rack, used for cooldown purposes + var/recent_rack = 0 + ///Whether the gun can be sawn off by sawing tools + var/can_be_sawn_off = FALSE + + ///Whether the gun can be tacloaded by slapping a fresh magazine directly on it + var/tac_reloads = TRUE //Snowflake mechanic no more. + ///If we have the 'snowflake mechanic,' how long should it take to reload? + var/tactical_reload_delay = 1 SECONDS + +/obj/item/gun/ballistic/Initialize() + . = ..() + if (!spawnwithmagazine) + bolt_locked = TRUE + update_appearance() + return + if (!magazine) + magazine = new mag_type(src) + chamber_round() + update_appearance() + +/obj/item/gun/ballistic/update_icon_state() + if(current_skin) + icon_state = "[unique_reskin[current_skin]][sawn_off ? "_sawn" : ""]" + else + icon_state = "[base_icon_state || initial(icon_state)][sawn_off ? "_sawn" : ""]" + return ..() + +/obj/item/gun/ballistic/update_overlays() + . = ..() + if (bolt_type == BOLT_TYPE_LOCKING) + . += "[icon_state]_bolt[bolt_locked ? "_locked" : ""]" + if (bolt_type == BOLT_TYPE_OPEN && bolt_locked) + . += "[icon_state]_bolt" + if (suppressed) + . += "[icon_state]_suppressor" + if (magazine) + if (unique_mag_sprites_for_variants) + . += "[icon_state]_mag_[magazine.base_icon_state]" + if (!magazine.ammo_count()) + . += "[icon_state]_mag_empty" + else + . += "[icon_state]_mag" + var/capacity_number = 0 + switch(get_ammo() / magazine.max_ammo) + if(0.2 to 0.39) + capacity_number = 20 + if(0.4 to 0.59) + capacity_number = 40 + if(0.6 to 0.79) + capacity_number = 60 + if(0.8 to 0.99) + capacity_number = 80 + if(1.0) + capacity_number = 100 + if (capacity_number) + . += "[icon_state]_mag_[capacity_number]" + if(!chambered && empty_indicator) + . += "[icon_state]_empty" + +/obj/item/gun/ballistic/process_chamber(empty_chamber = TRUE, from_firing = TRUE, chamber_next_round = TRUE, atom/shooter) + if(!semi_auto && from_firing) + return + var/obj/item/ammo_casing/casing = chambered //Find chambered round + if(istype(casing)) //there's a chambered round + if(casing_ejector || !from_firing) + casing.on_eject(shooter) + chambered = null + else if(empty_chamber) + chambered = null + if (chamber_next_round && (magazine?.max_ammo > 1)) + chamber_round() + SEND_SIGNAL(src, COMSIG_GUN_CHAMBER_PROCESSED) + +///Used to chamber a new round and eject the old one +/obj/item/gun/ballistic/proc/chamber_round(keep_bullet = FALSE) + if (chambered || !magazine) + return + if (magazine.ammo_count()) + chambered = magazine.get_round(keep_bullet || bolt_type == BOLT_TYPE_NO_BOLT) + if (bolt_type != BOLT_TYPE_OPEN) + chambered.forceMove(src) + +///updates a bunch of racking related stuff and also handles the sound effects and the like +/obj/item/gun/ballistic/proc/rack(mob/user = null) + if (bolt_type == BOLT_TYPE_NO_BOLT) //If there's no bolt, nothing to rack + return + if (bolt_type == BOLT_TYPE_OPEN) + if(!bolt_locked) //If it's an open bolt, racking again would do nothing + if (user) + to_chat(user, "\The [src]'s [bolt_wording] is already cocked!") + return + bolt_locked = FALSE + if (user) + to_chat(user, "You rack the [bolt_wording] of \the [src].") + process_chamber(!chambered, FALSE, shooter = user) + if (bolt_type == BOLT_TYPE_LOCKING && !chambered) + bolt_locked = TRUE + playsound(src, lock_back_sound, lock_back_sound_volume, lock_back_sound_vary) + else + playsound(src, rack_sound, rack_sound_volume, rack_sound_vary) + update_appearance() + SEND_SIGNAL(src, COMSIG_UPDATE_AMMO_HUD) + +///Drops the bolt from a locked position +/obj/item/gun/ballistic/proc/drop_bolt(mob/user = null) + playsound(src, bolt_drop_sound, bolt_drop_sound_volume, FALSE) + if (user) + to_chat(user, "You drop the [bolt_wording] of \the [src].") + chamber_round() + bolt_locked = FALSE + update_appearance() + +///Handles all the logic needed for magazine insertion +/obj/item/gun/ballistic/proc/insert_magazine(mob/user, obj/item/ammo_box/magazine/AM, display_message = TRUE) + if(!istype(AM, mag_type)) + to_chat(user, "\The [AM] doesn't seem to fit into \the [src]...") + return FALSE + if(user.transferItemToLoc(AM, src)) + magazine = AM + if (display_message) + to_chat(user, "You load a new [magazine_wording] into \the [src].") + if (magazine.ammo_count()) + playsound(src, load_sound, load_sound_volume, load_sound_vary) + else + playsound(src, load_empty_sound, load_sound_volume, load_sound_vary) + if (bolt_type == BOLT_TYPE_OPEN && !bolt_locked) + chamber_round(TRUE) + update_appearance() + SEND_SIGNAL(src, COMSIG_UPDATE_AMMO_HUD) + return TRUE + else + to_chat(user, "You cannot seem to get \the [src] out of your hands!") + return FALSE + +///Handles all the logic of magazine ejection, if tac_load is set that magazine will be tacloaded in the place of the old eject +/obj/item/gun/ballistic/proc/eject_magazine(mob/user, display_message = TRUE, obj/item/ammo_box/magazine/tac_load = null) + if(bolt_type == BOLT_TYPE_OPEN) + chambered = null + if (magazine.ammo_count()) + playsound(src, eject_sound, eject_sound_volume, eject_sound_vary) + else + playsound(src, eject_empty_sound, eject_sound_volume, eject_sound_vary) + magazine.forceMove(drop_location()) + var/obj/item/ammo_box/magazine/old_mag = magazine + old_mag.update_appearance() + magazine = null + if (display_message) + to_chat(user, "You pull the [magazine_wording] out of \the [src].") + update_appearance() + SEND_SIGNAL(src, COMSIG_UPDATE_AMMO_HUD) + if (tac_load) + if(do_after(user, tactical_reload_delay, TRUE, src)) + if (insert_magazine(user, tac_load, FALSE)) + to_chat(user, "You perform a tactical reload on \the [src].") + else + to_chat(user, "You dropped the old [magazine_wording], but the new one doesn't fit. How embarassing.") + else + to_chat(user, "Your reload was interupted!") + return + if(user) + user.put_in_hands(old_mag) + update_appearance() + SEND_SIGNAL(src, COMSIG_UPDATE_AMMO_HUD) + +/obj/item/gun/ballistic/can_shoot() + if(safety) + return FALSE + return chambered + +/obj/item/gun/ballistic/attackby(obj/item/A, mob/user, params) + . = ..() + if (.) + return + if (!internal_magazine && istype(A, /obj/item/ammo_box/magazine)) + var/obj/item/ammo_box/magazine/AM = A + if (!magazine) + insert_magazine(user, AM) + else + if (tac_reloads) + eject_magazine(user, FALSE, AM) + else + to_chat(user, "There's already a [magazine_wording] in \the [src].") + return + if (istype(A, /obj/item/ammo_casing) || istype(A, /obj/item/ammo_box)) + if (bolt_type == BOLT_TYPE_NO_BOLT || internal_magazine) + if (chambered && !chambered.BB) + chambered.on_eject(shooter = user) + chambered = null + var/num_loaded = magazine.attackby(A, user, params) + if (num_loaded) + to_chat(user, "You load [num_loaded] [cartridge_wording]\s into \the [src].") + playsound(src, load_sound, load_sound_volume, load_sound_vary) + if (chambered == null && bolt_type == BOLT_TYPE_NO_BOLT) + chamber_round() + A.update_appearance() + update_appearance() + return + if(istype(A, /obj/item/suppressor)) + var/obj/item/suppressor/S = A + if(!can_suppress) + to_chat(user, "You can't seem to figure out how to fit [S] on [src]!") + return + if(!user.is_holding(src)) + to_chat(user, "You need be holding [src] to fit [S] to it!") + return + if(suppressed) + to_chat(user, "[src] already has a suppressor!") + return + if(user.transferItemToLoc(A, src)) + to_chat(user, "You screw \the [S] onto \the [src].") + install_suppressor(A) + return + if (can_be_sawn_off) + if (sawoff(user, A)) + return + return FALSE + +///Installs a new suppressor, assumes that the suppressor is already in the contents of src +/obj/item/gun/ballistic/proc/install_suppressor(obj/item/suppressor/S) + suppressed = S + w_class += S.w_class //so pistols do not fit in pockets when suppressed + update_appearance() + +/obj/item/gun/ballistic/AltClick(mob/user) + if (unique_reskin && !current_skin && user.canUseTopic(src, BE_CLOSE, NO_DEXTERITY)) + reskin_obj(user) + return + if(loc == user) + if(suppressed && can_unsuppress) + var/obj/item/suppressor/S = suppressed + if(!user.is_holding(src)) + return ..() + to_chat(user, "You unscrew \the [suppressed] from \the [src].") + user.put_in_hands(suppressed) + w_class -= S.w_class + suppressed = null + update_appearance() + return + +///Prefire empty checks for the bolt drop +/obj/item/gun/ballistic/proc/prefire_empty_checks() + if (!chambered && !get_ammo()) + if (bolt_type == BOLT_TYPE_OPEN && !bolt_locked) + bolt_locked = TRUE + playsound(src, bolt_drop_sound, bolt_drop_sound_volume) + update_appearance() + +///postfire empty checks for bolt locking and sound alarms +/obj/item/gun/ballistic/proc/postfire_empty_checks(last_shot_succeeded) + if (!chambered && !get_ammo()) + if (empty_alarm && last_shot_succeeded) + playsound(src, empty_alarm_sound, empty_alarm_volume, empty_alarm_vary) + update_appearance() + if (empty_autoeject && last_shot_succeeded && !internal_magazine) + eject_magazine(display_message = FALSE) + update_appearance() + if (last_shot_succeeded && bolt_type == BOLT_TYPE_LOCKING) + bolt_locked = TRUE + update_appearance() + +/obj/item/gun/ballistic/pre_fire(atom/target, mob/living/user, message = TRUE, flag, params = null, zone_override = "", bonus_spread = 0, dual_wielded_gun = FALSE) + prefire_empty_checks() + return ..() + +/obj/item/gun/ballistic/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, burst_firing = FALSE, spread_override = 0, iteration = 0) + . = ..() //The gun actually firing + postfire_empty_checks(.) + +//ATTACK HAND IGNORING PARENT RETURN VALUE +/obj/item/gun/ballistic/attack_hand(mob/user) + if(!internal_magazine && loc == user && user.is_holding(src) && magazine) + eject_magazine(user) + return + return ..() + +/obj/item/gun/ballistic/unique_action(mob/living/user) + if(bolt_type == BOLT_TYPE_NO_BOLT) + chambered = null + var/num_unloaded = 0 + for(var/obj/item/ammo_casing/CB in get_ammo_list(FALSE, TRUE)) + CB.forceMove(drop_location()) + + var/angle_of_movement =(rand(-3000, 3000) / 100) + dir2angle(turn(user.dir, 180)) + CB.AddComponent(/datum/component/movable_physics, _horizontal_velocity = rand(350, 450) / 100, _vertical_velocity = rand(400, 450) / 100, _horizontal_friction = rand(20, 24) / 100, _z_gravity = PHYSICS_GRAV_STANDARD, _z_floor = 0, _angle_of_movement = angle_of_movement, _bounce_sound = CB.bounce_sfx_override) + + num_unloaded++ + SSblackbox.record_feedback("tally", "station_mess_created", 1, CB.name) + if (num_unloaded) + to_chat(user, "You unload [num_unloaded] [cartridge_wording]\s from [src].") + playsound(user, eject_sound, eject_sound_volume, eject_sound_vary) + update_appearance() + else + to_chat(user, "[src] is empty!") + return + if(bolt_type == BOLT_TYPE_LOCKING && bolt_locked) + drop_bolt(user) + return + if (recent_rack > world.time) + return + recent_rack = world.time + rack_delay + rack(user) + return + + +/obj/item/gun/ballistic/examine(mob/user) + . = ..() + var/count_chambered = !(bolt_type == BOLT_TYPE_NO_BOLT || bolt_type == BOLT_TYPE_OPEN) + . += "It has [get_ammo(count_chambered)] round\s remaining." + if (!chambered) + . += "It does not seem to have a round chambered." + if (bolt_locked) + . += "The [bolt_wording] is locked back and needs to be released before firing." + if (suppressed) + . += "It has a suppressor attached that can be removed with alt+click." + . += "You can [bolt_wording] [src] by pressing the unqiue action key. By default, this is space" + +///Gets the number of bullets in the gun +/obj/item/gun/ballistic/proc/get_ammo(countchambered = TRUE) + var/boolets = 0 //mature var names for mature people + if (chambered && countchambered) + boolets++ + if (magazine) + boolets += magazine.ammo_count() + return boolets + +///gets a list of every bullet in the gun +/obj/item/gun/ballistic/proc/get_ammo_list(countchambered = TRUE, drop_all = FALSE) + var/list/rounds = list() + if(chambered && countchambered) + rounds.Add(chambered) + if(drop_all) + chambered = null + rounds.Add(magazine.ammo_list(drop_all)) + return rounds + +GLOBAL_LIST_INIT(gun_saw_types, typecacheof(list( + /obj/item/gun/energy/plasmacutter, + /obj/item/melee/transforming/energy, + ))) + +///Handles all the logic of sawing off guns, +/obj/item/gun/ballistic/proc/sawoff(mob/user, obj/item/saw) + if(!saw.get_sharpness() || !is_type_in_typecache(saw, GLOB.gun_saw_types) && saw.tool_behaviour != TOOL_SAW) //needs to be sharp. Otherwise turned off eswords can cut this. + return + if(sawn_off) + to_chat(user, "\The [src] is already shortened!") + return + if(bayonet) + to_chat(user, "You cannot saw-off \the [src] with \the [bayonet] attached!") + return + user.changeNext_move(CLICK_CD_MELEE) + user.visible_message("[user] begins to shorten \the [src].", "You begin to shorten \the [src]...") + + //if there's any live ammo inside the gun, makes it go off + if(blow_up(user)) + user.visible_message("\The [src] goes off!", "\The [src] goes off in your face!") + return + + if(do_after(user, 30, target = src)) + if(sawn_off) + return + user.visible_message("[user] shortens \the [src]!", "You shorten \the [src].") + name = "sawn-off [src.name]" + desc = sawn_desc + w_class = WEIGHT_CLASS_NORMAL + item_state = "gun" + slot_flags &= ~ITEM_SLOT_BACK //you can't sling it on your back + slot_flags |= ITEM_SLOT_BELT //but you can wear it on your belt (poorly concealed under a trenchcoat, ideally) + recoil = SAWN_OFF_RECOIL + sawn_off = TRUE + update_appearance() + return TRUE + +///used for sawing guns, causes the gun to fire without the input of the user +/obj/item/gun/ballistic/proc/blow_up(mob/user) + . = FALSE + for(var/obj/item/ammo_casing/AC in magazine.stored_ammo) + if(AC.BB) + process_fire(user, user, FALSE) + . = TRUE + + +/obj/item/suppressor + name = "suppressor" + desc = "A syndicate small-arms suppressor for maximum espionage." + icon = 'icons/obj/guns/projectile.dmi' + icon_state = "suppressor" + w_class = WEIGHT_CLASS_TINY + + +/obj/item/suppressor/specialoffer + name = "cheap suppressor" + desc = "A foreign knock-off suppressor, it feels flimsy, cheap, and brittle. Still fits most weapons." diff --git a/shiptest.dme b/shiptest.dme index dbe36dfd05..3a66313419 100644 --- a/shiptest.dme +++ b/shiptest.dme @@ -6,6 +6,272 @@ // BEGIN_FILE_DIR #define FILE_DIR . +#define FILE_DIR "code" +#define FILE_DIR "code/modules" +#define FILE_DIR "code/modules/donator" +#define FILE_DIR "config" +#define FILE_DIR "config/title_music" +#define FILE_DIR "config/title_music/sounds" +#define FILE_DIR "html" +#define FILE_DIR "icons" +#define FILE_DIR "icons/ass" +#define FILE_DIR "icons/blanks" +#define FILE_DIR "icons/effects" +#define FILE_DIR "icons/effects/light_overlays" +#define FILE_DIR "icons/effects/mouse_pointers" +#define FILE_DIR "icons/hud" +#define FILE_DIR "icons/materials" +#define FILE_DIR "icons/mecha" +#define FILE_DIR "icons/misc" +#define FILE_DIR "icons/mob" +#define FILE_DIR "icons/mob/actions" +#define FILE_DIR "icons/mob/augmentation" +#define FILE_DIR "icons/mob/clothing" +#define FILE_DIR "icons/mob/clothing/faction" +#define FILE_DIR "icons/mob/clothing/faction/clip" +#define FILE_DIR "icons/mob/clothing/faction/gezena" +#define FILE_DIR "icons/mob/clothing/faction/nanotrasen" +#define FILE_DIR "icons/mob/clothing/faction/suns" +#define FILE_DIR "icons/mob/clothing/head" +#define FILE_DIR "icons/mob/clothing/species" +#define FILE_DIR "icons/mob/clothing/suits" +#define FILE_DIR "icons/mob/clothing/under" +#define FILE_DIR "icons/mob/clothing/underwear" +#define FILE_DIR "icons/mob/clothing/underwear/species" +#define FILE_DIR "icons/mob/icemoon" +#define FILE_DIR "icons/mob/inhands" +#define FILE_DIR "icons/mob/inhands/antag" +#define FILE_DIR "icons/mob/inhands/clothing" +#define FILE_DIR "icons/mob/inhands/equipment" +#define FILE_DIR "icons/mob/inhands/faction" +#define FILE_DIR "icons/mob/inhands/faction/gezena" +#define FILE_DIR "icons/mob/inhands/faction/nanotrasen" +#define FILE_DIR "icons/mob/inhands/faction/suns" +#define FILE_DIR "icons/mob/inhands/misc" +#define FILE_DIR "icons/mob/inhands/weapons" +#define FILE_DIR "icons/mob/jungle" +#define FILE_DIR "icons/mob/large-worn-icons" +#define FILE_DIR "icons/mob/large-worn-icons/64x64" +#define FILE_DIR "icons/mob/lavaland" +#define FILE_DIR "icons/mob/species" +#define FILE_DIR "icons/mob/species/ethereal" +#define FILE_DIR "icons/mob/species/humanoid_husk" +#define FILE_DIR "icons/mob/species/ipc" +#define FILE_DIR "icons/mob/species/kepori" +#define FILE_DIR "icons/mob/species/lizard" +#define FILE_DIR "icons/mob/species/misc" +#define FILE_DIR "icons/mob/species/moth" +#define FILE_DIR "icons/mob/species/plasmaman" +#define FILE_DIR "icons/mob/species/rachnid" +#define FILE_DIR "icons/mob/species/vox" +#define FILE_DIR "icons/obj" +#define FILE_DIR "icons/obj/assemblies" +#define FILE_DIR "icons/obj/atmospherics" +#define FILE_DIR "icons/obj/atmospherics/components" +#define FILE_DIR "icons/obj/atmospherics/pipes" +#define FILE_DIR "icons/obj/clothing" +#define FILE_DIR "icons/obj/clothing/faction" +#define FILE_DIR "icons/obj/clothing/faction/clip" +#define FILE_DIR "icons/obj/clothing/faction/gezena" +#define FILE_DIR "icons/obj/clothing/faction/nanotrasen" +#define FILE_DIR "icons/obj/clothing/faction/suns" +#define FILE_DIR "icons/obj/clothing/head" +#define FILE_DIR "icons/obj/clothing/suits" +#define FILE_DIR "icons/obj/clothing/under" +#define FILE_DIR "icons/obj/doors" +#define FILE_DIR "icons/obj/doors/airlocks" +#define FILE_DIR "icons/obj/doors/airlocks/abductor" +#define FILE_DIR "icons/obj/doors/airlocks/centcom" +#define FILE_DIR "icons/obj/doors/airlocks/clockwork" +#define FILE_DIR "icons/obj/doors/airlocks/cult" +#define FILE_DIR "icons/obj/doors/airlocks/cult/runed" +#define FILE_DIR "icons/obj/doors/airlocks/cult/unruned" +#define FILE_DIR "icons/obj/doors/airlocks/external" +#define FILE_DIR "icons/obj/doors/airlocks/glass_large" +#define FILE_DIR "icons/obj/doors/airlocks/hatch" +#define FILE_DIR "icons/obj/doors/airlocks/highsec" +#define FILE_DIR "icons/obj/doors/airlocks/shuttle" +#define FILE_DIR "icons/obj/doors/airlocks/station" +#define FILE_DIR "icons/obj/doors/airlocks/station2" +#define FILE_DIR "icons/obj/doors/airlocks/survival" +#define FILE_DIR "icons/obj/doors/airlocks/vault" +#define FILE_DIR "icons/obj/doors/puzzledoor" +#define FILE_DIR "icons/obj/drinks" +#define FILE_DIR "icons/obj/flora" +#define FILE_DIR "icons/obj/food" +#define FILE_DIR "icons/obj/gang" +#define FILE_DIR "icons/obj/guns" +#define FILE_DIR "icons/obj/guns/faction" +#define FILE_DIR "icons/obj/guns/faction/gezena" +#define FILE_DIR "icons/obj/hydroponics" +#define FILE_DIR "icons/obj/ice_moon" +#define FILE_DIR "icons/obj/implants" +#define FILE_DIR "icons/obj/item" +#define FILE_DIR "icons/obj/lavaland" +#define FILE_DIR "icons/obj/machines" +#define FILE_DIR "icons/obj/plumbing" +#define FILE_DIR "icons/obj/power_cond" +#define FILE_DIR "icons/obj/smooth_structures" +#define FILE_DIR "icons/obj/smooth_structures/alien" +#define FILE_DIR "icons/obj/spacepods" +#define FILE_DIR "icons/obj/structures" +#define FILE_DIR "icons/obj/structures/chairs" +#define FILE_DIR "icons/obj/structures/signs" +#define FILE_DIR "icons/obj/tesla_engine" +#define FILE_DIR "icons/pda_icons" +#define FILE_DIR "icons/program_icons" +#define FILE_DIR "icons/runtime" +#define FILE_DIR "icons/stamp_icons" +#define FILE_DIR "icons/Testing" +#define FILE_DIR "icons/turf" +#define FILE_DIR "icons/turf/connectors" +#define FILE_DIR "icons/turf/floors" +#define FILE_DIR "icons/turf/walls" +#define FILE_DIR "icons/turf/walls/rwalls" +#define FILE_DIR "icons/UI_Icons" +#define FILE_DIR "icons/UI_Icons/Achievements" +#define FILE_DIR "icons/UI_Icons/Achievements/Boss" +#define FILE_DIR "icons/UI_Icons/Achievements/Misc" +#define FILE_DIR "icons/UI_Icons/Achievements/Skills" +#define FILE_DIR "icons/UI_Icons/Arcade" +#define FILE_DIR "icons/UI_Icons/chat" +#define FILE_DIR "icons/UI_Icons/fishing" +#define FILE_DIR "icons/UI_Icons/Pills" +#define FILE_DIR "icons/UI_Icons/tgui" +#define FILE_DIR "icons/vending_icons" +#define FILE_DIR "sound" +#define FILE_DIR "sound/ai" +#define FILE_DIR "sound/ambience" +#define FILE_DIR "sound/ambience/antag" +#define FILE_DIR "sound/arcade" +#define FILE_DIR "sound/creatures" +#define FILE_DIR "sound/effects" +#define FILE_DIR "sound/effects/footstep" +#define FILE_DIR "sound/effects/thunder" +#define FILE_DIR "sound/effects/turbolift" +#define FILE_DIR "sound/hallucinations" +#define FILE_DIR "sound/health" +#define FILE_DIR "sound/hornetnoises" +#define FILE_DIR "sound/items" +#define FILE_DIR "sound/items/equip" +#define FILE_DIR "sound/items/geiger" +#define FILE_DIR "sound/items/handling" +#define FILE_DIR "sound/items/storage" +#define FILE_DIR "sound/lavaland" +#define FILE_DIR "sound/machines" +#define FILE_DIR "sound/machines/airlocks" +#define FILE_DIR "sound/machines/airlocks/external" +#define FILE_DIR "sound/machines/airlocks/hatch" +#define FILE_DIR "sound/machines/airlocks/shutters" +#define FILE_DIR "sound/machines/airlocks/standard" +#define FILE_DIR "sound/machines/apc" +#define FILE_DIR "sound/machines/clockcult" +#define FILE_DIR "sound/machines/computer" +#define FILE_DIR "sound/machines/fryer" +#define FILE_DIR "sound/machines/generator" +#define FILE_DIR "sound/machines/gravgen" +#define FILE_DIR "sound/machines/keyboard" +#define FILE_DIR "sound/machines/microwave" +#define FILE_DIR "sound/machines/nuke" +#define FILE_DIR "sound/machines/shower" +#define FILE_DIR "sound/machines/sm" +#define FILE_DIR "sound/machines/sm/accent" +#define FILE_DIR "sound/machines/sm/accent/delam" +#define FILE_DIR "sound/machines/sm/accent/normal" +#define FILE_DIR "sound/machines/sm/loops" +#define FILE_DIR "sound/machines/smes" +#define FILE_DIR "sound/machines/tcomms" +#define FILE_DIR "sound/machines/vending" +#define FILE_DIR "sound/magic" +#define FILE_DIR "sound/magic/clockwork" +#define FILE_DIR "sound/mecha" +#define FILE_DIR "sound/misc" +#define FILE_DIR "sound/roundend" +#define FILE_DIR "sound/roundstart" +#define FILE_DIR "sound/runtime" +#define FILE_DIR "sound/runtime/chatter" +#define FILE_DIR "sound/runtime/hyperspace" +#define FILE_DIR "sound/runtime/instruments" +#define FILE_DIR "sound/runtime/instruments/accordion" +#define FILE_DIR "sound/runtime/instruments/banjo" +#define FILE_DIR "sound/runtime/instruments/bikehorn" +#define FILE_DIR "sound/runtime/instruments/eguitar" +#define FILE_DIR "sound/runtime/instruments/glockenspiel" +#define FILE_DIR "sound/runtime/instruments/guitar" +#define FILE_DIR "sound/runtime/instruments/harmonica" +#define FILE_DIR "sound/runtime/instruments/piano" +#define FILE_DIR "sound/runtime/instruments/recorder" +#define FILE_DIR "sound/runtime/instruments/saxophone" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/brass" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/brass/crisis_brass" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/brass/crisis_trombone" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/brass/crisis_trumpet" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/chromatic" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/chromatic/fluid_celeste" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/chromatic/sgmbox" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/chromatic/vibraphone1" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/guitar" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/guitar/crisis_clean" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/guitar/crisis_muted" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/guitar/crisis_nylon" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/guitar/crisis_steel" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/organ" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/organ/crisis_accordian" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/organ/crisis_church" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/organ/crisis_hammond" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/organ/crisis_harmonica" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/organ/crisis_tangaccordian" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/piano" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/piano/crisis_bright_piano" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/piano/crisis_grand_piano" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/piano/crisis_harpsichord" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/piano/fluid_harpsi" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/piano/fluid_piano" +#define FILE_DIR "sound/runtime/instruments/synthesis_samples/tones" +#define FILE_DIR "sound/runtime/instruments/trombone" +#define FILE_DIR "sound/runtime/instruments/violin" +#define FILE_DIR "sound/runtime/instruments/xylophone" +#define FILE_DIR "sound/spookoween" +#define FILE_DIR "sound/surgery" +#define FILE_DIR "sound/vehicles" +#define FILE_DIR "sound/voice" +#define FILE_DIR "sound/voice/beepsky" +#define FILE_DIR "sound/voice/firebot" +#define FILE_DIR "sound/voice/human" +#define FILE_DIR "sound/voice/kepori" +#define FILE_DIR "sound/voice/lizard" +#define FILE_DIR "sound/voice/medbot" +#define FILE_DIR "sound/voice/moth" +#define FILE_DIR "sound/voice/squid" +#define FILE_DIR "sound/voice/vox" +#define FILE_DIR "sound/vox_fem" +#define FILE_DIR "sound/weapons" +#define FILE_DIR "sound/weapons/effects" +#define FILE_DIR "sound/weapons/gun" +#define FILE_DIR "sound/weapons/gun/commissar" +#define FILE_DIR "sound/weapons/gun/energy" +#define FILE_DIR "sound/weapons/gun/flamethrower" +#define FILE_DIR "sound/weapons/gun/gauss" +#define FILE_DIR "sound/weapons/gun/general" +#define FILE_DIR "sound/weapons/gun/hit" +#define FILE_DIR "sound/weapons/gun/hmg" +#define FILE_DIR "sound/weapons/gun/l6" +#define FILE_DIR "sound/weapons/gun/laser" +#define FILE_DIR "sound/weapons/gun/pistol" +#define FILE_DIR "sound/weapons/gun/revolver" +#define FILE_DIR "sound/weapons/gun/rifle" +#define FILE_DIR "sound/weapons/gun/shotgun" +#define FILE_DIR "sound/weapons/gun/smg" +#define FILE_DIR "sound/weapons/gun/sniper" +#define FILE_DIR "sound/weather" +#define FILE_DIR "sound/weather/ashstorm" +#define FILE_DIR "sound/weather/ashstorm/inside" +#define FILE_DIR "sound/weather/ashstorm/outside" +#define FILE_DIR "sound/weather/fallout" +#define FILE_DIR "sound/weather/wind" +#define FILE_DIR "tools" +#define FILE_DIR "tools/SS13SmoothingCutter" // END_FILE_DIR // BEGIN_PREFERENCES