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