diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql
index f907fe83762..6793a5043df 100644
--- a/SQL/paradise_schema.sql
+++ b/SQL/paradise_schema.sql
@@ -368,17 +368,22 @@ DROP TABLE IF EXISTS `library`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `library` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `author` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL,
- `title` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL,
- `content` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL,
- `category` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL,
- `ckey` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
- `flagged` int(11) NOT NULL,
- PRIMARY KEY (`id`),
- KEY `ckey` (`ckey`),
- KEY `flagged` (`flagged`)
-) ENGINE=InnoDB AUTO_INCREMENT=4537 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+ `id` INT(11) NOT NULL AUTO_INCREMENT,
+ `author` MEDIUMTEXT NOT NULL COLLATE 'utf8mb4_unicode_ci',
+ `title` MEDIUMTEXT NOT NULL COLLATE 'utf8mb4_unicode_ci',
+ `content` MEDIUMTEXT NOT NULL COLLATE 'utf8mb4_unicode_ci',
+ `ckey` VARCHAR(32) NOT NULL COLLATE 'utf8mb4_unicode_ci',
+ `reports` MEDIUMTEXT NOT NULL COLLATE 'utf8mb3_general_ci',
+ `summary` MEDIUMTEXT NOT NULL COLLATE 'utf8mb3_general_ci',
+ `rating` DOUBLE NULL DEFAULT '0',
+ `raters` MEDIUMTEXT NOT NULL COLLATE 'utf8mb3_general_ci',
+ `primary_category` INT(11) NULL DEFAULT '0',
+ `secondary_category` INT(11) NOT NULL DEFAULT '0',
+ `tertiary_category` INT(11) NULL DEFAULT '0',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `ckey` (`ckey`) USING BTREE,
+ INDEX `flagged` (`reports`(1024)) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
diff --git a/SQL/updates/37-38.sql b/SQL/updates/37-38.sql
index 1e9da93ad3f..645c1234a36 100644
--- a/SQL/updates/37-38.sql
+++ b/SQL/updates/37-38.sql
@@ -1,5 +1,26 @@
-# Updating DB from 37-38
-# Adds player.keybindings (longtext) ~dearmochi
+# Updates DB from 37 to 38 -Sirryan2002
+# Creates new tables in preparation for library table conversion
-# Add column to player
-ALTER TABLE `player` ADD COLUMN `keybindings` LONGTEXT COLLATE 'utf8mb4_unicode_ci' DEFAULT NULL AFTER `colourblind_mode`;
+#Renames old table
+ALTER TABLE library RENAME TO library_old;
+
+# Create new table to track library books
+CREATE TABLE `library` (
+ `id` INT(11) NOT NULL AUTO_INCREMENT,
+ `author` MEDIUMTEXT NOT NULL COLLATE 'utf8mb4_unicode_ci',
+ `title` MEDIUMTEXT NOT NULL COLLATE 'utf8mb4_unicode_ci',
+ `content` MEDIUMTEXT NOT NULL COLLATE 'utf8mb4_unicode_ci',
+ `ckey` VARCHAR(32) NULL DEFAULT '' COLLATE 'utf8mb4_unicode_ci',
+ `reports` MEDIUMTEXT NOT NULL COLLATE 'utf8mb3_general_ci',
+ `summary` MEDIUMTEXT NOT NULL COLLATE 'utf8mb3_general_ci',
+ `rating` DOUBLE NULL DEFAULT '0',
+ `raters` MEDIUMTEXT NOT NULL COLLATE 'utf8mb3_general_ci',
+ `primary_category` INT(11) NULL DEFAULT '0',
+ `secondary_category` INT(11) NOT NULL DEFAULT '0',
+ `tertiary_category` INT(11) NULL DEFAULT '0',
+ PRIMARY KEY (`id`) USING BTREE,
+ INDEX `ckey` (`ckey`) USING BTREE,
+ INDEX `flagged` (`reports`(1024)) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+
+# YOU MUST NOW RUN 38-39.py
diff --git a/SQL/updates/38-39.py b/SQL/updates/38-39.py
new file mode 100644
index 00000000000..3b8edbf2154
--- /dev/null
+++ b/SQL/updates/38-39.py
@@ -0,0 +1,130 @@
+# :wave: hello fellow contributors, this script is brought to you ad-free by -sirryan2002-
+# In order to run this script on Windows, you need to make sure you have Python **3** installed. Tested on 3.10.4
+# In addition you must have the mysql-connector-python module installed (can be done through pip :D)
+# if you do not have that module installed, you cannot run this script
+
+# To run this, supply the following args in a command shell
+# python 38-39.py address username password database
+# Example:
+# python 38-39.py 127.0.0.1 sirryan2002 myubersecretdbpassword paradise_gamedb
+
+import json
+import mysql.connector, argparse
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("address", help="MySQL server address (use localhost for the current computer)")
+ parser.add_argument("username", help="MySQL login username")
+ parser.add_argument("password", help="MySQL login password")
+ parser.add_argument("database", help="Database name")
+
+ args = parser.parse_args()
+ db = mysql.connector.connect(host=args.address, user=args.username, passwd=args.password, db=args.database)
+ cursor = db.cursor()
+ print("Connected to {}".format(args.database))
+ #A List of old categories names + the new id number they will be assigned
+ category_name_to_id_map = {
+ "Fiction": 1,
+ "Non-Fiction": 2,
+ "Adult": 0, #0 represents a "removed"/unused category that no longer will be included
+ "Reference": 16,
+ "Religion": 3,
+ }
+
+ cursor.execute("SELECT id, author, title, content, category, ckey FROM library_old")
+ data = cursor.fetchall()
+
+ print("Loaded {} rows from library table...".format(len(data)))
+
+ new_rows = []
+ print("Modifying Categories...")
+ for entry in data:
+ book_id = entry[0]
+ author = entry[1]
+ title = entry[2]
+ content = entry[3]
+ category = entry[4]
+ ckey = entry[5]
+
+ update_entry = False
+ new_entry = [
+ book_id,
+ author,
+ title,
+ content,
+ category,
+ ckey,
+ ]
+ if category not in category_name_to_id_map.keys():
+ update_entry = True
+ new_entry[4] = 0
+ print("Corrupted Category Detected: removing \"{}\"...".format(category))
+ else:
+ for cat in category_name_to_id_map.keys():
+ if cat == category:
+ update_entry = True
+ new_entry[4] = category_name_to_id_map[cat]
+ if update_entry:
+ new_rows.append(new_entry)
+ else:
+ print("ERROR: Book {} did not have its category changed".format(book_id))
+
+ print("Modifying Content...")
+ for entry in new_rows:
+ new_content = json.dumps([entry[3]])
+ entry[3] = new_content
+ #here we're turning our content string into a JSON list
+ print("Modified Content...")
+ print("Vetting Book Titles & Contents...")
+ duplicate_books = 0
+ programmatic_books = 0
+ notitle_books = 0
+ short_books = 0
+ for entry in new_rows:
+ if "Print Job" in entry[2]:
+ print("Book {} had \"Print Job\" in title: removing record...".format(entry[0]))
+ notitle_books += 1
+ new_rows.remove(entry)
+ continue
+ if "Standard Operating Procedure" in entry[2] or "
Hello and thank you for choosing Nanotrasen for your nuclear information needs. Today's crash course will deal with the operation of a Fission Class Nanotrasen made Nuclear Device. First and foremost, DO NOT TOUCH ANYTHING UNTIL THE BOMB IS IN PLACE. Pressing any button on the compacted bomb will cause it to extend and bolt itself into place. If this is done to unbolt it one must completely log in which at this time may not be possible. To make the device functional: #1 Place bomb in designated detonation zone #2 Extend and anchor bomb (attack with hand). #3 Insert Nuclear Auth. Disk into slot. #4 Enter the nuclear authorization code: ([nuke_code]). #5 Enter your desired time until activation. #6 Disable the Safety. #6 Arm the device. You now have activated the device and it will begin counting down to detonation. Remove the Nuclear Authorization Disk and either head back to your shuttle or stay around until the Nuclear Device detonates, depending on your orders from Central Command.
The nuclear authorization code is: [nuke_code ? nuke_code : "None provided"]
Good luck, soldier!
"
+ P.name = "Special Operations Manual"
+ P.update_icon()
+ var/obj/item/stamp/centcom/stamp = new
+ P.stamp(stamp)
+ qdel(stamp)
+
+ message_admins("[key_name_admin(proccaller)] has spawned a DeathSquad.")
+ log_admin("[key_name(proccaller)] used Spawn Death Squad.")
+ return TRUE
+
+/client/proc/deathsquad_spawn(mob/ghost_mob, is_leader = FALSE, datum/async_input/new_dstype_input, obj/L, nuke_code, mission)
+ var/new_dstype
+ if(new_dstype_input)
+ new_dstype_input.close()
+ new_dstype = new_dstype_input.result
+ if(!new_dstype_input) // didn't receive any response, or didn't ask them in the first place
+ new_dstype = "Organic"
+
+ var/use_ds_borg = FALSE
+ if(new_dstype == "Cyborg")
+ use_ds_borg = TRUE
+
+ if(!ghost_mob || !ghost_mob.key || !ghost_mob.client) // Doublechecking after async request
+ return
+
+ if(use_ds_borg)
+ var/mob/living/silicon/robot/deathsquad/R = new(get_turf(L))
+ var/rnum = rand(1, 1000)
+ var/borgname = "Epsilon [rnum]"
+ R.name = borgname
+ R.custom_name = borgname
+ R.real_name = R.name
+ R.mind = new
+ R.mind.current = R
+ R.mind.set_original_mob(R)
+ R.mind.assigned_role = SPECIAL_ROLE_DEATHSQUAD
+ R.mind.special_role = SPECIAL_ROLE_DEATHSQUAD
+ R.mind.offstation_role = TRUE
+ if(!(R.mind in SSticker.minds))
+ SSticker.minds += R.mind
+ SSticker.mode.traitors += R.mind
+ R.key = ghost_mob.key
+ if(nuke_code)
+ R.mind.store_memory("Nuke Code:[nuke_code].")
+ R.mind.store_memory("Mission:[mission].")
+ to_chat(R, "You are a Deathsquad cyborg, in the service of Central Command. \nYour current mission is: [mission]")
+ else
+ var/mob/living/carbon/human/new_commando = create_deathsquad_commando(L, is_leader)
+ new_commando.mind.key = ghost_mob.key
+ new_commando.key = ghost_mob.key
+ new_commando.update_action_buttons_icon()
+ if(nuke_code)
+ new_commando.mind.store_memory("Nuke Code:[nuke_code].")
+ new_commando.mind.store_memory("Mission:[mission].")
+ to_chat(new_commando, "You are a Deathsquad [is_leader ? "TEAM LEADER" : "commando"] in the service of Central Command. Check the table ahead for detailed instructions.\nYour current mission is: [mission]")
+
+/client/proc/create_deathsquad_commando(obj/spawn_location, is_leader = FALSE)
+ var/mob/living/carbon/human/new_commando = new(spawn_location.loc)
+ var/commando_leader_rank = pick("Lieutenant", "Captain", "Major")
+ var/commando_name = pick(GLOB.deathsquad_names)
+ var/obj/item/organ/external/head/head_organ = new_commando.get_organ("head") // This appearance code is brought to you by ert.dm, basically the same code. If you change something here change somethere there too.
+
+ if(is_leader)
+ new_commando.age = rand(35, 45)
+ new_commando.real_name = "[commando_leader_rank] [commando_name]"
+ else
+ new_commando.real_name = "[commando_name]"
+
+ if(prob(50))
+ new_commando.change_gender(MALE)
+ else
+ new_commando.change_gender(FEMALE)
+
+ // All of this code down here too is also from ert.dm, I'm lazy don't blame me
+ new_commando.set_species(/datum/species/human, TRUE)
+ new_commando.dna.ready_dna(new_commando)
+ new_commando.cleanSE() //No fat/blind/colourblind/epileptic/whatever Deathsquad.
+ new_commando.overeatduration = 0
+
+ var/hair_c = pick("#8B4513","#000000","#FF4500","#FFD700") // Brown, black, red, blonde
+ var/eye_c = pick("#000000","#8B4513","1E90FF") // Black, brown, blue
+ var/skin_tone = rand(-120, 20) // A range of skin colors (This doesn't work, result is always pale white)
+
+ head_organ.facial_colour = hair_c
+ head_organ.sec_facial_colour = hair_c
+ head_organ.hair_colour = hair_c
+ head_organ.sec_hair_colour = hair_c
+ new_commando.change_eye_color(eye_c)
+ new_commando.s_tone = skin_tone
+ head_organ.h_style = random_hair_style(new_commando.gender, head_organ.dna.species.name)
+ head_organ.f_style = random_facial_hair_style(new_commando.gender, head_organ.dna.species.name)
+
+ new_commando.regenerate_icons()
+ new_commando.update_body()
+ new_commando.update_dna()
+
+ //Creates mind stuff.
+ new_commando.mind_initialize()
+ new_commando.mind.assigned_role = SPECIAL_ROLE_DEATHSQUAD
+ new_commando.mind.special_role = SPECIAL_ROLE_DEATHSQUAD
+ new_commando.mind.offstation_role = TRUE
+ SSticker.mode.traitors |= new_commando.mind //Adds them to current traitor list. Which is really the extra antagonist list.
+ new_commando.equip_deathsquad_commando(is_leader)
+ return new_commando
+
+/mob/living/carbon/human/proc/equip_deathsquad_commando(is_leader = FALSE)
+ if(is_leader)
+ equipOutfit(/datum/outfit/admin/deathsquad_commando/leader)
+ else
+ equipOutfit(/datum/outfit/admin/deathsquad_commando)
diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm
index b2cd3e0658d..a5d6c1f1f4f 100644
--- a/code/modules/admin/verbs/one_click_antag.dm
+++ b/code/modules/admin/verbs/one_click_antag.dm
@@ -297,76 +297,6 @@
return 1
*/
-/datum/admins/proc/makeDeathsquad()
- var/list/mob/candidates = list()
- var/mob/theghost = null
- var/time_passed = world.time
- var/input = "Purify the station."
- if(prob(10))
- input = "Save Runtime and any other cute things on the station."
-
- var/antnum = input(owner, "How many deathsquad members you want to create? Enter 0 to cancel.","Amount:", 0) as num
- if(!antnum || antnum <= 0)
- return
- log_admin("[key_name(owner)] tried making a [antnum] person Death Squad with One-Click-Antag")
- message_admins("[key_name_admin(owner)] tried making a [antnum] person Death Squad with One-Click-Antag")
-
- var/syndicate_leader_selected = 0 //when the leader is chosen. The last person spawned.
-
- //Generates a list of commandos from active ghosts. Then the user picks which characters to respawn as the commandos.
- for(var/mob/G in GLOB.respawnable_list)
- if(!jobban_isbanned(G, ROLE_SYNDICATE))
- spawn(0)
- switch(alert(G,"Do you wish to be considered for an elite syndicate strike team being sent in?","Please answer in 30 seconds!","Yes","No"))
- if("Yes")
- if((world.time-time_passed)>300)//If more than 30 game seconds passed.
- return
- candidates += G
- if("No")
- return
- else
- return
- sleep(300)
-
- for(var/mob/dead/observer/G in candidates)
- if(!G.key)
- candidates.Remove(G)
-
- if(candidates.len)
- //Spawns commandos and equips them.
- for(var/obj/effect/landmark/L in /area/syndicate_mothership/elite_squad)
- if(antnum <= 0)
- break
- if(L.name == "Syndicate-Commando")
- syndicate_leader_selected = antnum == 1?1:0
-
- var/mob/living/carbon/human/new_syndicate_commando = create_syndicate_death_commando(L, syndicate_leader_selected)
-
- while((!theghost || !theghost.client) && candidates.len)
- theghost = pick(candidates)
- candidates.Remove(theghost)
-
- if(!theghost)
- qdel(new_syndicate_commando)
- break
-
- new_syndicate_commando.key = theghost.key
- new_syndicate_commando.internal = new_syndicate_commando.s_store
- new_syndicate_commando.update_action_buttons_icon()
-
- //So they don't forget their code or mission.
-
-
- to_chat(new_syndicate_commando, "You are an Elite Syndicate. [!syndicate_leader_selected ? "commando" : "LEADER"] in the service of the Syndicate. \nYour current mission is: [input]")
-
- antnum--
-
- for(var/obj/effect/landmark/L in /area/shuttle/syndicate_elite)
- if(L.name == "Syndicate-Commando-Bomb")
- new /obj/effect/spawner/newbomb/timer/syndicate(L.loc)
- return 1
-
-
/proc/makeBody(mob/dead/observer/G_found) // Uses stripped down and bastardized code from respawn character
if(!G_found || !G_found.key) return
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index 489c6ecee76..2b569d689de 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -465,9 +465,8 @@ Traitors and the like can also be revived with the previous role mostly intact.
new_character.loc = get_turf(synd_spawn)
call(/datum/game_mode/proc/equip_syndicate)(new_character)
- if("Death Commando")//Leaves them at late-join spawn.
- new_character.equip_death_commando()
- new_character.internal = new_character.s_store
+ if("Deathsquad Commando")//Leaves them at late-join spawn.
+ new_character.equip_deathsquad_commando()
new_character.update_action_buttons_icon()
else//They may also be a cyborg or AI.
switch(new_character.mind.assigned_role)
diff --git a/code/modules/admin/verbs/striketeam.dm b/code/modules/admin/verbs/striketeam.dm
deleted file mode 100644
index d9c60392b70..00000000000
--- a/code/modules/admin/verbs/striketeam.dm
+++ /dev/null
@@ -1,204 +0,0 @@
-//STRIKE TEAMS
-
-#define COMMANDOS_POSSIBLE 6 //if more Commandos are needed in the future
-GLOBAL_VAR_INIT(sent_strike_team, 0)
-
-/client/proc/strike_team()
- if(!SSticker)
- to_chat(usr, "The game hasn't started yet!")
- return
- if(GLOB.sent_strike_team == 1)
- to_chat(usr, "CentComm is already sending a team.")
- return
- if(alert("Do you want to send in the CentComm death squad? Once enabled, this is irreversible.",,"Yes","No")!="Yes")
- return
- alert("This 'mode' will go on until everyone is dead or the station is destroyed. You may also admin-call the evac shuttle when appropriate. Spawned commandos have internals cameras which are viewable through a monitor inside the Spec. Ops. Office. The first one selected/spawned will be the team leader.")
-
- message_admins("[key_name_admin(usr)] has started to spawn a CentComm DeathSquad.", 1)
-
- var/input = null
- while(!input)
- input = sanitize(copytext(input(src, "Please specify which mission the death commando squad shall undertake.", "Specify Mission", ""),1,MAX_MESSAGE_LEN))
- if(!input)
- if(alert("Error, no mission set. Do you want to exit the setup process?",,"Yes","No")=="Yes")
- return
-
- if(GLOB.sent_strike_team)
- to_chat(usr, "Looks like someone beat you to it.")
- return
-
- // Find the nuclear auth code
- var/nuke_code
- var/temp_code
- for(var/obj/machinery/nuclearbomb/N in GLOB.machines)
- temp_code = text2num(N.r_code)
- if(temp_code)//if it's actually a number. It won't convert any non-numericals.
- nuke_code = N.r_code
- break
-
- // Find ghosts willing to be DS
- var/image/source = image('icons/obj/cardboard_cutout.dmi', "cutout_deathsquad")
- var/list/commando_ghosts = pollCandidatesWithVeto(src, usr, COMMANDOS_POSSIBLE, "Join the DeathSquad?",, 21, 60 SECONDS, TRUE, GLOB.role_playtime_requirements[ROLE_DEATHSQUAD], TRUE, FALSE, source = source)
- if(!length(commando_ghosts))
- to_chat(usr, "Nobody volunteered to join the DeathSquad.")
- return
-
- GLOB.sent_strike_team = 1
-
- // Spawns commandos and equips them.
- var/commando_number = COMMANDOS_POSSIBLE //for selecting a leader
- var/is_leader = TRUE // set to FALSE after leader is spawned
-
- for(var/obj/effect/landmark/spawner/ds/L in GLOB.landmarks_list)
- if(!commando_number)
- break
-
- if(!length(commando_ghosts))
- break
-
- var/use_ds_borg = FALSE
- var/mob/ghost_mob = pick(commando_ghosts)
- commando_ghosts -= ghost_mob
- if(!ghost_mob || !ghost_mob.key || !ghost_mob.client)
- continue
-
- if(!is_leader)
- var/new_dstype = alert(ghost_mob.client, "Select Deathsquad Type.", "DS Character Generation", "Organic", "Cyborg")
- if(new_dstype == "Cyborg")
- use_ds_borg = TRUE
-
- if(!ghost_mob || !ghost_mob.key || !ghost_mob.client) // Have to re-check this due to the above alert() call
- continue
-
- if(use_ds_borg)
- var/mob/living/silicon/robot/deathsquad/R = new(get_turf(L))
- var/rnum = rand(1, 1000)
- var/borgname = "Epsilon [rnum]"
- R.name = borgname
- R.custom_name = borgname
- R.real_name = R.name
- R.mind = new
- R.mind.current = R
- R.mind.set_original_mob(R)
- R.mind.assigned_role = SPECIAL_ROLE_DEATHSQUAD
- R.mind.special_role = SPECIAL_ROLE_DEATHSQUAD
- R.mind.offstation_role = TRUE
- if(!(R.mind in SSticker.minds))
- SSticker.minds += R.mind
- SSticker.mode.traitors += R.mind
- R.key = ghost_mob.key
- if(nuke_code)
- R.mind.store_memory("Nuke Code:[nuke_code].")
- R.mind.store_memory("Mission:[input].")
- to_chat(R, "You are a Special Operations cyborg, in the service of Central Command. \nYour current mission is: [input]")
- else
- var/mob/living/carbon/human/new_commando = create_death_commando(L, is_leader)
- new_commando.mind.key = ghost_mob.key
- new_commando.key = ghost_mob.key
- new_commando.internal = new_commando.s_store
- new_commando.update_action_buttons_icon()
- if(nuke_code)
- new_commando.mind.store_memory("Nuke Code:[nuke_code].")
- new_commando.mind.store_memory("Mission:[input].")
- to_chat(new_commando, "You are a Special Ops [is_leader ? "TEAM LEADER" : "commando"] in the service of Central Command. Check the table ahead for detailed instructions.\nYour current mission is: [input]")
-
- is_leader = FALSE
- commando_number--
-
- //Spawns the rest of the commando gear.
- for(var/obj/effect/landmark/spawner/commando_manual/L in GLOB.landmarks_list)
- //new /obj/item/gun/energy/pulse_rifle(L.loc)
- var/obj/item/paper/P = new(L.loc)
- P.info = "
Good morning soldier!. This compact guide will familiarize you with standard operating procedure. There are three basic rules to follow: #1 Work as a team. #2 Accomplish your objective at all costs. #3 Leave no witnesses. You are fully equipped and stocked for your mission--before departing on the Spec. Ops. Shuttle due South, make sure that all operatives are ready. Actual mission objective will be relayed to you by Central Command through your headsets. If deemed appropriate, Central Command will also allow members of your team to equip assault power-armor for the mission. You will find the armor storage due West of your position. Once you are ready to leave, utilize the Special Operations shuttle console and toggle the hull doors via the other console.
In the event that the team does not accomplish their assigned objective in a timely manner, or finds no other way to do so, attached below are instructions on how to operate a Nanotrasen Nuclear Device. Your operations LEADER is provided with a nuclear authentication disk and a pin-pointer for this reason. You may easily recognize them by their rank: Lieutenant, Captain, or Major. The nuclear device itself will be present somewhere on your destination.
Hello and thank you for choosing Nanotrasen for your nuclear information needs. Today's crash course will deal with the operation of a Fission Class Nanotrasen made Nuclear Device. First and foremost, DO NOT TOUCH ANYTHING UNTIL THE BOMB IS IN PLACE. Pressing any button on the compacted bomb will cause it to extend and bolt itself into place. If this is done to unbolt it one must completely log in which at this time may not be possible. To make the device functional: #1 Place bomb in designated detonation zone #2 Extend and anchor bomb (attack with hand). #3 Insert Nuclear Auth. Disk into slot. #4 Type numeric code into keypad ([nuke_code]). Note: If you make a mistake press R to reset the device. #5 Press the E button to log onto the device. You now have activated the device. To deactivate the buttons at anytime, for example when you have already prepped the bomb for detonation, remove the authentication disk OR press the R on the keypad. Now the bomb CAN ONLY be detonated using the timer. A manual detonation is not an option. Note: Toggle off the SAFETY. Use the - - and + + to set a detonation time between 5 seconds and 10 minutes. Then press the timer toggle button to start the countdown. Now remove the authentication disk so that the buttons deactivate. Note: THE BOMB IS STILL SET AND WILL DETONATE Now before you remove the disk if you need to move the bomb you can: Toggle off the anchor, move it, and re-anchor.
The nuclear authorization code is: [nuke_code ? nuke_code : "None provided"]
Good luck, soldier!
"
- P.name = "Spec. Ops Manual"
- P.icon = "pamphlet-ds"
- var/obj/item/stamp/centcom/stamp = new
- P.stamp(stamp)
- qdel(stamp)
-
- for(var/thing in GLOB.landmarks_list)
- var/obj/effect/landmark/L = thing
- if(L.name == "Commando-Bomb")
- new /obj/effect/spawner/newbomb/timer/syndicate(L.loc)
- qdel(L)
-
- message_admins("[key_name_admin(usr)] has spawned a CentComm DeathSquad.", 1)
- log_admin("[key_name(usr)] used Spawn Death Squad.")
- return 1
-
-/client/proc/create_death_commando(obj/spawn_location, is_leader = FALSE)
- var/mob/living/carbon/human/new_commando = new(spawn_location.loc)
- var/commando_leader_rank = pick("Lieutenant", "Captain", "Major")
- var/commando_name = pick(GLOB.commando_names)
-
- var/datum/character_save/S = new //Randomize appearance for the commando.
- S.randomise()
- if(is_leader)
- S.age = rand(35, 45)
- S.real_name = "[commando_leader_rank] [commando_name]"
- else
- S.real_name = "[commando_name]"
- S.copy_to(new_commando)
-
-
- new_commando.dna.ready_dna(new_commando)//Creates DNA.
-
- //Creates mind stuff.
- new_commando.mind_initialize()
- new_commando.mind.assigned_role = SPECIAL_ROLE_DEATHSQUAD
- new_commando.mind.special_role = SPECIAL_ROLE_DEATHSQUAD
- SSticker.mode.traitors |= new_commando.mind//Adds them to current traitor list. Which is really the extra antagonist list.
- new_commando.equip_death_commando(is_leader)
- return new_commando
-
-/mob/living/carbon/human/proc/equip_death_commando(is_leader = FALSE)
-
- var/obj/item/radio/R = new /obj/item/radio/headset/alt(src)
- R.set_frequency(DTH_FREQ)
- R.requires_tcomms = FALSE
- R.instant = TRUE
- R.freqlock = TRUE
- equip_to_slot_or_del(R, slot_l_ear)
- if(is_leader)
- equip_to_slot_or_del(new /obj/item/clothing/under/rank/centcom_officer(src), slot_w_uniform)
- else
- equip_to_slot_or_del(new /obj/item/clothing/under/color/green(src), slot_w_uniform)
- equip_to_slot_or_del(new /obj/item/clothing/shoes/magboots/advance(src), slot_shoes)
- equip_to_slot_or_del(new /obj/item/clothing/suit/space/deathsquad(src), slot_wear_suit)
- equip_to_slot_or_del(new /obj/item/clothing/gloves/combat(src), slot_gloves)
- equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/deathsquad(src), slot_head)
- equip_to_slot_or_del(new /obj/item/clothing/mask/gas/sechailer/swat(src), slot_wear_mask)
- equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal(src), slot_glasses)
-
- equip_to_slot_or_del(new /obj/item/storage/backpack/security(src), slot_back)
- equip_to_slot_or_del(new /obj/item/storage/box(src), slot_in_backpack)
-
- equip_to_slot_or_del(new /obj/item/ammo_box/a357(src), slot_in_backpack)
- equip_to_slot_or_del(new /obj/item/reagent_containers/hypospray/combat/nanites(src), slot_in_backpack)
- equip_to_slot_or_del(new /obj/item/storage/box/flashbangs(src), slot_in_backpack)
- equip_to_slot_or_del(new /obj/item/flashlight(src), slot_in_backpack)
- equip_to_slot_or_del(new /obj/item/pinpointer(src), slot_in_backpack)
- if(is_leader)
- equip_to_slot_or_del(new /obj/item/disk/nuclear/unrestricted(src), slot_in_backpack)
- else
- equip_to_slot_or_del(new /obj/item/grenade/plastic/c4/x4(src), slot_in_backpack)
-
-
- equip_to_slot_or_del(new /obj/item/melee/energy/sword/saber(src), slot_l_store)
- equip_to_slot_or_del(new /obj/item/shield/energy(src), slot_r_store)
- equip_to_slot_or_del(new /obj/item/tank/internals/emergency_oxygen/double(src), slot_s_store)
- equip_to_slot_or_del(new /obj/item/gun/projectile/revolver/mateba(src), slot_belt)
- equip_to_slot_or_del(new /obj/item/gun/energy/pulse(src), slot_r_hand)
-
- var/obj/item/implant/mindshield/L = new/obj/item/implant/mindshield(src)
- L.implant(src)
-
- var/obj/item/card/id/W = new(src)
- W.name = "[real_name]'s ID Card"
- W.icon_state = "deathsquad"
- W.assignment = "Death Commando"
- W.access = get_centcom_access(W.assignment)
- W.registered_name = real_name
- equip_to_slot_or_del(W, slot_wear_id)
-
- return 1
diff --git a/code/modules/antagonists/changeling/powers/lesserform.dm b/code/modules/antagonists/changeling/powers/lesserform.dm
index 6d8ad464c1e..74457833bc6 100644
--- a/code/modules/antagonists/changeling/powers/lesserform.dm
+++ b/code/modules/antagonists/changeling/powers/lesserform.dm
@@ -13,9 +13,6 @@
/datum/action/changeling/lesserform/sting_action(mob/living/carbon/human/user)
if(!user)
return FALSE
- if(user.has_brain_worms())
- to_chat(user, "We cannot perform this ability at the present time!")
- return FALSE
var/mob/living/carbon/human/H = user
diff --git a/code/modules/antagonists/changeling/powers/panacea.dm b/code/modules/antagonists/changeling/powers/panacea.dm
index 523d6a5a1d0..752e1579769 100644
--- a/code/modules/antagonists/changeling/powers/panacea.dm
+++ b/code/modules/antagonists/changeling/powers/panacea.dm
@@ -13,14 +13,6 @@
to_chat(user, "We cleanse impurities from our form.")
- var/mob/living/simple_animal/borer/B = user.has_brain_worms()
- if(B)
- B.leave_host()
- if(iscarbon(user))
- var/mob/living/carbon/C = user
- C.vomit(0)
- to_chat(user, "We expel a parasite from our form.")
-
var/obj/item/organ/internal/body_egg/egg = user.get_int_organ(/obj/item/organ/internal/body_egg)
if(egg)
egg.remove(user)
diff --git a/code/modules/antagonists/changeling/powers/swap_form.dm b/code/modules/antagonists/changeling/powers/swap_form.dm
index 6dde46d26c3..f3344748e17 100644
--- a/code/modules/antagonists/changeling/powers/swap_form.dm
+++ b/code/modules/antagonists/changeling/powers/swap_form.dm
@@ -25,9 +25,6 @@
if(ischangeling(target))
to_chat(user, "We are unable to swap forms with another changeling!")
return FALSE
- if(target.has_brain_worms() || user.has_brain_worms())
- to_chat(user, "A foreign presence repels us from this body!")
- return FALSE
return TRUE
/datum/action/changeling/swap_form/sting_action(mob/living/carbon/user)
diff --git a/code/modules/antagonists/traitor/contractor/items/contractor_baton.dm b/code/modules/antagonists/traitor/contractor/items/contractor_baton.dm
index 30fc73ac222..fc94e31373b 100644
--- a/code/modules/antagonists/traitor/contractor/items/contractor_baton.dm
+++ b/code/modules/antagonists/traitor/contractor/items/contractor_baton.dm
@@ -3,8 +3,10 @@
desc = "A compact, specialised baton issued to Syndicate contractors. Applies light electrical shocks to targets."
// Overrides
affect_silicon = TRUE
- stun_time = 2 SECONDS
+ knockdown_duration = 4 SECONDS
cooldown = 2.5 SECONDS
+ stamina_damage = 70
+ stamina_armour_pen = 100
force_off = 5
force_on = 15
item_state_on = "contractor_baton"
@@ -13,15 +15,12 @@
stun_sound = 'sound/weapons/contractorbatonhit.ogg'
extend_sound = 'sound/weapons/contractorbatonextend.ogg'
// Settings
- /// Stamina damage to deal on stun.
- var/stamina_damage = 70
/// Jitter to deal on stun.
var/jitter_amount = 5 SECONDS
/// Stutter to deal on stun.
var/stutter_amount = 10 SECONDS
-/obj/item/melee/classic_baton/telescopic/contractor/stun(mob/living/target, mob/living/user)
+/obj/item/melee/classic_baton/telescopic/contractor/baton_knockdown(mob/living/target, mob/living/user)
. = ..()
- target.adjustStaminaLoss(stamina_damage)
target.Jitter(jitter_amount)
target.AdjustStuttering(stutter_amount)
diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm
index c664bccdb20..895d74f25b4 100644
--- a/code/modules/assembly/holder.dm
+++ b/code/modules/assembly/holder.dm
@@ -194,7 +194,7 @@
if(normal && a_right && a_left)
if(a_right != D)
a_right.pulsed(0)
- if(a_left != D)
+ if(a_left && a_left != D) // the right pools might have sent us boom, so `a_left` can be null here
a_left.pulsed(0)
if(master)
master.receive_signal()
diff --git a/code/modules/assembly/igniter.dm b/code/modules/assembly/igniter.dm
index 7d88bbafd4a..c18b96672a6 100644
--- a/code/modules/assembly/igniter.dm
+++ b/code/modules/assembly/igniter.dm
@@ -26,16 +26,17 @@
var/turf/location = get_turf(loc)
if(location)
location.hotspot_expose(1000,1000)
+ sparks.start()
if(istype(loc, /obj/item/assembly_holder))
- if(istype(loc.loc, /obj/structure/reagent_dispensers/fueltank))
- var/obj/structure/reagent_dispensers/fueltank/tank = loc.loc
+ var/locloc = loc.loc
+ if(istype(locloc, /obj/structure/reagent_dispensers/fueltank))
+ var/obj/structure/reagent_dispensers/fueltank/tank = locloc
if(tank)
- tank.boom(TRUE)
- if(istype(loc.loc, /obj/item/reagent_containers/glass/beaker))
- var/obj/item/reagent_containers/glass/beaker/beakerbomb = loc.loc
+ tank.boom(TRUE) // this qdel's `src`
+ else if(istype(locloc, /obj/item/reagent_containers/glass/beaker))
+ var/obj/item/reagent_containers/glass/beaker/beakerbomb = locloc
if(beakerbomb)
beakerbomb.heat_beaker()
- sparks.start()
return TRUE
diff --git a/code/modules/atmospherics/environmental/LINDA_fire.dm b/code/modules/atmospherics/environmental/LINDA_fire.dm
index ace235e0c8f..d4e00991b50 100644
--- a/code/modules/atmospherics/environmental/LINDA_fire.dm
+++ b/code/modules/atmospherics/environmental/LINDA_fire.dm
@@ -45,7 +45,7 @@
//This is the icon for fire on turfs, also helps for nurturing small fires until they are full tile
/obj/effect/hotspot
- anchored = 1
+ anchored = TRUE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
icon = 'icons/goonstation/effects/fire.dmi'
icon_state = "1"
diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm
index 74dde0f4c16..fd8a4646df5 100644
--- a/code/modules/atmospherics/machinery/airalarm.dm
+++ b/code/modules/atmospherics/machinery/airalarm.dm
@@ -73,7 +73,7 @@
name = "alarm"
icon = 'icons/obj/monitors.dmi'
icon_state = "alarm0"
- anchored = 1
+ anchored = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 4
active_power_usage = 8
@@ -92,12 +92,12 @@
var/remote_control = TRUE
var/rcon_setting = RCON_AUTO
var/rcon_time = 0
- var/locked = 1
+ var/locked = TRUE
var/datum/wires/alarm/wires = null
- var/wiresexposed = 0 // If it's been screwdrivered open.
- var/aidisabled = 0
+ var/wiresexposed = FALSE // If it's been screwdrivered open.
+ var/aidisabled = FALSE
var/AAlarmwires = 31
- var/shorted = 0
+ var/shorted = FALSE
// Waiting on a device to respond.
// Specifies an id_tag. NULL means we aren't waiting.
@@ -223,7 +223,7 @@
setDir(direction)
buildstage = 0
- wiresexposed = 1
+ wiresexposed = TRUE
set_pixel_offsets_from_dir(-24, 24, -24, 24)
. = ..()
diff --git a/code/modules/atmospherics/machinery/atmospherics.dm b/code/modules/atmospherics/machinery/atmospherics.dm
index 9d76c6f1a83..7bfa0644458 100644
--- a/code/modules/atmospherics/machinery/atmospherics.dm
+++ b/code/modules/atmospherics/machinery/atmospherics.dm
@@ -9,7 +9,7 @@ Pipes -> Pipelines
Pipelines + Other Objects -> Pipe network
*/
/obj/machinery/atmospherics
- anchored = 1
+ anchored = TRUE
layer = GAS_PIPE_HIDDEN_LAYER //under wires
resistance_flags = FIRE_PROOF
max_integrity = 200
@@ -18,8 +18,8 @@ Pipelines + Other Objects -> Pipe network
active_power_usage = 0
power_channel = ENVIRON
on_blueprints = TRUE
- var/nodealert = 0
- var/can_unwrench = 0
+ var/nodealert = FALSE
+ var/can_unwrench = FALSE
/// If the machine is currently operating or not.
var/on = FALSE
/// The amount of pressure the machine wants to operate at.
@@ -290,14 +290,13 @@ Pipelines + Other Objects -> Pipe network
return
var/obj/machinery/atmospherics/target_move = findConnecting(direction)
- var/old_loc = user.loc
if(target_move)
if(is_type_in_list(target_move, GLOB.ventcrawl_machinery) && target_move.can_crawl_through())
user.remove_ventcrawl()
user.forceMove(target_move.loc) //handles entering and so on
user.visible_message("You hear something squeezing through the ducts.", "You climb out of the ventilation system.")
else if(target_move.can_crawl_through())
- if(returnPipenet() != target_move.returnPipenet())
+ if(returnPipenet(target_move) != target_move.returnPipenet())
user.update_pipe_vision(target_move)
user.forceMove(target_move)
if(world.time - user.last_played_vent > VENT_SOUND_DELAY)
@@ -306,8 +305,7 @@ Pipelines + Other Objects -> Pipe network
else
if((direction & initialize_directions) || is_type_in_list(src, GLOB.ventcrawl_machinery)) //if we move in a way the pipe can connect, but doesn't - or we're in a vent
user.remove_ventcrawl()
- user.loc = target_move.loc
- user.Moved(old_loc, get_dir(old_loc, user.loc), FALSE)
+ user.forceMove(loc)
user.visible_message("You hear something squeezing through the pipes.", "You climb out of the ventilation system.")
ADD_TRAIT(user, TRAIT_IMMOBILIZED, "ventcrawling")
spawn(1) // this is awful
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
index 90361aca549..7111d4ef4e5 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
@@ -10,11 +10,14 @@
var/obj/machinery/power/generator/generator
- anchored = 1
- density = 1
+ anchored = TRUE
+ density = TRUE
- can_unwrench = 1
- var/side_inverted = 0
+ can_unwrench = TRUE
+ var/side_inverted = FALSE
+
+ var/light_range_on = 1
+ var/light_power_on = 0.1 //just dont want it to be culled by byond.
/obj/machinery/atmospherics/binary/circulator/detailed_examine()
return "This generates electricity, depending on the difference in temperature between each side of the machine. The meter in \
@@ -44,6 +47,7 @@
if(output_starting_pressure >= input_starting_pressure - 10)
//Need at least 10 KPa difference to overcome friction in the mechanism
last_pressure_delta = 0
+ update_icon()
return null
//Calculate necessary moles to transfer using PV = nRT
@@ -52,7 +56,9 @@
var/transfer_moles = pressure_delta * outlet.volume/(inlet.temperature * R_IDEAL_GAS_EQUATION)
- last_pressure_delta = pressure_delta
+ if(last_pressure_delta != pressure_delta)
+ last_pressure_delta = pressure_delta
+ update_icon()
//log_debug("pressure_delta = [pressure_delta]; transfer_moles = [transfer_moles];")
@@ -66,59 +72,82 @@
else
last_pressure_delta = 0
-
-/obj/machinery/atmospherics/binary/circulator/process_atmos()
- ..()
- update_icon()
+ update_icon()
/obj/machinery/atmospherics/binary/circulator/proc/get_inlet_air()
- if(side_inverted==0)
- return air2
- else
+ if(side_inverted)
return air1
+ else
+ return air2
/obj/machinery/atmospherics/binary/circulator/proc/get_outlet_air()
- if(side_inverted==0)
- return air1
- else
+ if(side_inverted)
return air2
+ else
+ return air1
/obj/machinery/atmospherics/binary/circulator/proc/get_inlet_side()
if(dir==SOUTH||dir==NORTH)
- if(side_inverted==0)
- return "South"
- else
+ if(side_inverted)
return "North"
+ else
+ return "South"
/obj/machinery/atmospherics/binary/circulator/proc/get_outlet_side()
if(dir==SOUTH||dir==NORTH)
- if(side_inverted==0)
- return "North"
- else
+ if(side_inverted)
return "South"
+ else
+ return "North"
/obj/machinery/atmospherics/binary/circulator/multitool_act(mob/user, obj/item/I)
. = TRUE
if(!I.use_tool(src, user, 0, volume = I.tool_volume))
return
- if(!side_inverted)
- side_inverted = TRUE
- else
- side_inverted = FALSE
+ side_inverted = !side_inverted
to_chat(user, "You reverse the circulator's valve settings. The inlet of the circulator is now on the [get_inlet_side(dir)] side.")
desc = "A gas circulator pump and heat exchanger. Its input port is on the [get_inlet_side(dir)] side, and its output port is on the [get_outlet_side(dir)] side."
-/obj/machinery/atmospherics/binary/circulator/update_icon()
+/obj/machinery/atmospherics/binary/circulator/update_icon() //this gets called everytime atmos is updated in the circulator (alot)
..()
+ underlays.Cut()
+ cut_overlays()
if(stat & (BROKEN|NOPOWER))
icon_state = "circ[side]-p"
else if(last_pressure_delta > 0)
if(last_pressure_delta > ONE_ATMOSPHERE)
icon_state = "circ[side]-run"
+ underlays += emissive_appearance(icon,"emit[side]-run")
else
icon_state = "circ[side]-slow"
+ underlays += emissive_appearance(icon,"emit[side]-slow")
else
icon_state = "circ[side]-off"
+ underlays += emissive_appearance(icon,"emit[side]-off")
+
+ if(!side_inverted)
+ add_overlay(mutable_appearance(icon,"in_up"))
+ else
+ add_overlay(mutable_appearance(icon,"in_down"))
+
+ if(node2)
+ var/image/new_pipe_overlay = image(icon, "connected")
+ new_pipe_overlay.color = node2.pipe_color
+ add_overlay(new_pipe_overlay)
+ else
+ add_overlay(mutable_appearance(icon, "disconnected"))
return 1
+
+/obj/machinery/atmospherics/binary/circulator/power_change()
+ . = ..()
+ if(stat & (BROKEN|NOPOWER))
+ set_light(0)
+ else
+ set_light(light_range_on, light_power_on)
+ update_icon()
+
+/obj/machinery/atmospherics/binary/circulator/update_underlays()
+ . = ..()
+ update_icon()
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm
index b81fb88ee67..683a023bf16 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm
@@ -84,9 +84,6 @@
if(!istype(T))
return
- if(T.intact && node1 && node2 && node1.level == 1 && node2.level == 1 && istype(node1, /obj/machinery/atmospherics/pipe) && istype(node2, /obj/machinery/atmospherics/pipe))
- vent_icon += "h"
-
if(!powered())
vent_icon += "off"
else
@@ -111,6 +108,8 @@
add_underlay(T, node2, dir, node2.icon_connect_type)
else
add_underlay(T, node2, dir)
+ var/icon/frame = icon('icons/atmos/vent_pump.dmi', "frame")
+ underlays += frame
/obj/machinery/atmospherics/binary/dp_vent_pump/process_atmos()
..()
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm
index 1b1443f7853..ad13f06dbe2 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm
@@ -7,7 +7,7 @@
name = "passive gate"
desc = "A one-way air valve that does not require power"
- can_unwrench = 1
+ can_unwrench = TRUE
target_pressure = ONE_ATMOSPHERE
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm
index e6fb4f66f8c..2b8ccb022aa 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm
@@ -19,7 +19,7 @@ Thus, the two variables affect pump operation are set in New():
name = "gas pump"
desc = "A pump"
- can_unwrench = 1
+ can_unwrench = TRUE
target_pressure = ONE_ATMOSPHERE
@@ -55,7 +55,7 @@ Thus, the two variables affect pump operation are set in New():
/obj/machinery/atmospherics/binary/pump/on
icon_state = "map_on"
- on = 1
+ on = TRUE
/obj/machinery/atmospherics/binary/pump/update_icon()
..()
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/valve.dm b/code/modules/atmospherics/machinery/components/binary_devices/valve.dm
index e13854d04b4..283aca14f91 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/valve.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/valve.dm
@@ -5,9 +5,9 @@
name = "manual valve"
desc = "A pipe valve."
- can_unwrench = 1
+ can_unwrench = TRUE
- var/open = 0
+ var/open = FALSE
req_one_access_txt = "24;10"
@@ -19,7 +19,7 @@
return "Click this to turn the valve. If red, the pipes on each end are separated. Otherwise, they are connected."
/obj/machinery/atmospherics/binary/valve/open
- open = 1
+ open = TRUE
icon_state = "map_valve1"
/obj/machinery/atmospherics/binary/valve/update_icon(animation)
@@ -40,7 +40,7 @@
add_underlay(T, node2, get_dir(src, node2))
/obj/machinery/atmospherics/binary/valve/proc/open()
- open = 1
+ open = TRUE
update_icon()
parent1.update = 0
parent2.update = 0
@@ -49,7 +49,7 @@
return
/obj/machinery/atmospherics/binary/valve/proc/close()
- open = 0
+ open = FALSE
update_icon()
investigate_log("was closed by [usr ? key_name(usr) : "a remote signal"]", "atmos")
return
@@ -98,7 +98,7 @@
..()
/obj/machinery/atmospherics/binary/valve/digital/open
- open = 1
+ open = TRUE
icon_state = "map_valve1"
/obj/machinery/atmospherics/binary/valve/digital/power_change()
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm
index f7e50707cdb..5929225ea16 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm
@@ -19,7 +19,7 @@ Thus, the two variables affect pump operation are set in New():
name = "volumetric gas pump"
desc = "A volumetric pump"
- can_unwrench = 1
+ can_unwrench = TRUE
var/transfer_rate = 200
@@ -51,7 +51,7 @@ Thus, the two variables affect pump operation are set in New():
return ..()
/obj/machinery/atmospherics/binary/volume_pump/on
- on = 1
+ on = TRUE
icon_state = "map_on"
/obj/machinery/atmospherics/binary/volume_pump/atmos_init()
diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm
index f40ecda9147..f27d01c8969 100644
--- a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm
+++ b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm
@@ -58,7 +58,7 @@
/obj/machinery/atmospherics/trinary/filter/flipped
icon_state = "mmap"
- flipped = 1
+ flipped = TRUE
/obj/machinery/atmospherics/trinary/filter/update_icon()
..()
@@ -74,7 +74,7 @@
icon_state += on ? "on" : "off"
else
icon_state += "off"
- on = 0
+ on = FALSE
/obj/machinery/atmospherics/trinary/filter/update_underlays()
if(..())
diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm b/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm
index 3b34a95c1ba..f1568410eb9 100644
--- a/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm
+++ b/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm
@@ -2,7 +2,7 @@
icon = 'icons/atmos/mixer.dmi'
icon_state = "map"
- can_unwrench = 1
+ can_unwrench = TRUE
name = "gas mixer"
@@ -33,7 +33,7 @@
/obj/machinery/atmospherics/trinary/mixer/flipped
icon_state = "mmap"
- flipped = 1
+ flipped = TRUE
/obj/machinery/atmospherics/trinary/mixer/update_icon(safety = 0)
..()
@@ -49,7 +49,7 @@
icon_state += on ? "on" : "off"
else
icon_state += "off"
- on = 0
+ on = FALSE
/obj/machinery/atmospherics/trinary/mixer/update_underlays()
if(..())
diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/trinary_base.dm b/code/modules/atmospherics/machinery/components/trinary_devices/trinary_base.dm
index 86b1aa74699..7a6f32261b3 100644
--- a/code/modules/atmospherics/machinery/components/trinary_devices/trinary_base.dm
+++ b/code/modules/atmospherics/machinery/components/trinary_devices/trinary_base.dm
@@ -17,7 +17,7 @@
var/datum/pipeline/parent2
var/datum/pipeline/parent3
- var/flipped = 0
+ var/flipped = FALSE
/obj/machinery/atmospherics/trinary/New()
..()
diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/tvalve.dm b/code/modules/atmospherics/machinery/components/trinary_devices/tvalve.dm
index 1ad9a1095a7..d59a206d000 100644
--- a/code/modules/atmospherics/machinery/components/trinary_devices/tvalve.dm
+++ b/code/modules/atmospherics/machinery/components/trinary_devices/tvalve.dm
@@ -8,7 +8,7 @@
name = "manual switching valve"
desc = "A pipe valve"
- can_unwrench = 1
+ can_unwrench = TRUE
var/state = TVALVE_STATE_STRAIGHT
@@ -21,11 +21,11 @@
/obj/machinery/atmospherics/trinary/tvalve/flipped
icon_state = "map_tvalvem0"
- flipped = 1
+ flipped = TRUE
/obj/machinery/atmospherics/trinary/tvalve/flipped/bypass
icon_state = "map_tvalvem1"
- flipped = 1
+ flipped = TRUE
state = TVALVE_STATE_SIDE
/obj/machinery/atmospherics/trinary/tvalve/update_icon(animation)
@@ -121,11 +121,11 @@
/obj/machinery/atmospherics/trinary/tvalve/digital/flipped
icon_state = "map_tvalvem0"
- flipped = 1
+ flipped = TRUE
/obj/machinery/atmospherics/trinary/tvalve/digital/flipped/bypass
icon_state = "map_tvalvem1"
- flipped = 1
+ flipped = TRUE
state = TVALVE_STATE_SIDE
/obj/machinery/atmospherics/trinary/tvalve/digital/power_change()
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
index cd573c2f3e9..1de74b34eb0 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
@@ -6,11 +6,11 @@
desc = "Lowers the body temperature so certain medications may take effect."
icon = 'icons/obj/cryogenics.dmi'
icon_state = "pod0"
- density = 1
- anchored = 1.0
+ density = TRUE
+ anchored = TRUE
layer = ABOVE_WINDOW_LAYER
plane = GAME_PLANE
- interact_offline = 1
+ interact_offline = TRUE
max_integrity = 350
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 30, ACID = 30)
var/temperature_archived
@@ -23,7 +23,7 @@
var/current_heat_capacity = 50
var/efficiency
- var/running_bob_animation = 0 // This is used to prevent threads from building up if update_icons is called multiple times
+ var/running_bob_animation = FALSE // This is used to prevent threads from building up if update_icons is called multiple times
light_color = LIGHT_COLOR_WHITE
@@ -361,7 +361,7 @@
if(src.on && !running_bob_animation) //no bobbing if off
var/up = 0 //used to see if we are going up or down, 1 is down, 2 is up
spawn(0) // Without this, the icon update will block. The new thread will die once the occupant leaves.
- running_bob_animation = 1
+ running_bob_animation = TRUE
while(occupant)
overlays -= "lid[on]" //have to remove the overlays first, to force an update- remove cloning pod overlay
overlays -= pickle //remove mob overlay
@@ -388,7 +388,7 @@
overlays += "lid[on]" //re-add the overlay of the pod, they are inside it, not floating
sleep(7) //don't want to jiggle violently, just slowly bob
- running_bob_animation = 0
+ running_bob_animation = FALSE
/obj/machinery/atmospherics/unary/cryo_cell/proc/process_occupant()
if(air_contents.total_moles() < 10)
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/generator_input.dm b/code/modules/atmospherics/machinery/components/unary_devices/generator_input.dm
index cb095b1e551..ae4cb9d270b 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/generator_input.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/generator_input.dm
@@ -1,7 +1,7 @@
/obj/machinery/atmospherics/unary/generator_input
icon = 'icons/obj/atmospherics/heat_exchanger.dmi'
icon_state = "intact"
- density = 1
+ density = TRUE
name = "generator input"
desc = "Placeholder"
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm
index f1bf25957d8..80d4f7bc4ca 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm
@@ -6,23 +6,23 @@
resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF //really helpful in building gas chambers for xenomorphs
- can_unwrench = 1
+ can_unwrench = TRUE
name = "air injector"
desc = "Has a valve and pump attached to it"
req_one_access_txt = "24;10"
- var/injecting = 0
+ var/injecting = FALSE
var/volume_rate = 50
var/id
- Mtoollink = 1
+ Mtoollink = TRUE
settagwhitelist = list("id_tag")
/obj/machinery/atmospherics/unary/outlet_injector/on
- on = 1
+ on = TRUE
/obj/machinery/atmospherics/unary/outlet_injector/New()
..()
@@ -64,7 +64,7 @@
/obj/machinery/atmospherics/unary/outlet_injector/process_atmos()
..()
- injecting = 0
+ injecting = FALSE
if(!on || stat & NOPOWER)
return 0
@@ -85,7 +85,7 @@
if(on || injecting)
return 0
- injecting = 1
+ injecting = TRUE
if(air_contents.temperature > 0)
var/transfer_moles = (air_contents.return_pressure())*volume_rate/(air_contents.temperature * R_IDEAL_GAS_EQUATION)
@@ -157,7 +157,7 @@
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off"
else
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]exposed"
- on = 0
+ on = FALSE
return*/
/obj/machinery/atmospherics/unary/outlet_injector/multitool_menu(mob/user, obj/item/multitool/P)
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/oxygen_generator.dm b/code/modules/atmospherics/machinery/components/unary_devices/oxygen_generator.dm
index fdeb02b7b83..ac223678e69 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/oxygen_generator.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/oxygen_generator.dm
@@ -1,7 +1,7 @@
/obj/machinery/atmospherics/unary/oxygen_generator
icon = 'icons/obj/atmospherics/oxygen_generator.dmi'
icon_state = "intact_off"
- density = 1
+ density = TRUE
name = "oxygen generator"
desc = ""
@@ -19,7 +19,7 @@
else
icon_state = "exposed_off"
- on = 0
+ on = FALSE
/obj/machinery/atmospherics/unary/oxygen_generator/New()
..()
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm b/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm
index 94f9f17e4b5..2a65d9f5451 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm
@@ -6,7 +6,7 @@
name = "passive vent"
desc = "A large air vent"
- can_unwrench = 1
+ can_unwrench = TRUE
var/volume = 250
@@ -67,3 +67,5 @@
if(!istype(T))
return
add_underlay(T, node, dir)
+ var/icon/frame = icon('icons/atmos/vent_pump.dmi', "frame")
+ underlays += frame
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm b/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm
index 64aaa045c8f..5f032649e40 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm
@@ -5,7 +5,7 @@
name = "connector port"
desc = "For connecting portables devices related to atmospherics control."
- can_unwrench = 1
+ can_unwrench = TRUE
layer = GAS_FILTER_LAYER
var/obj/machinery/portable_atmospherics/connected_device
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/tank.dm b/code/modules/atmospherics/machinery/components/unary_devices/tank.dm
index ed0c438008a..9b772373fe7 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/tank.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/tank.dm
@@ -9,7 +9,7 @@
var/volume = 10000 //in liters, 1 meters by 1 meters by 2 meters ~tweaked it a little to simulate a pressure tank without needing to recode them yet
- density = 1
+ density = TRUE
/obj/machinery/atmospherics/unary/tank/update_underlays()
if(..())
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermal_plate.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermal_plate.dm
index 6cd050de022..e27754d25c9 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/thermal_plate.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/thermal_plate.dm
@@ -5,7 +5,7 @@
icon = 'icons/obj/atmospherics/cold_sink.dmi'
icon_state = "off"
- can_unwrench = 1
+ can_unwrench = TRUE
name = "thermal tansfer plate"
desc = "Transfers heat to and from an area"
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm
index ce89e03b48a..9f4afef06d1 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm
@@ -94,9 +94,6 @@
if(!istype(T))
return
- if(T.intact && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
- vent_icon += "h"
-
if(welded)
vent_icon += "weld"
else if(!powered())
@@ -104,7 +101,7 @@
else
vent_icon += "[on ? "[pump_direction ? "out" : "in"]" : "off"]"
- overlays += SSair.icon_manager.get_atmos_icon("device", , , vent_icon)
+ overlays += SSair.icon_manager.get_atmos_icon("device", state = vent_icon)
update_pipe_image()
@@ -121,6 +118,8 @@
add_underlay(T, node, dir, node.icon_connect_type)
else
add_underlay(T,, dir)
+ var/icon/frame = icon('icons/atmos/vent_pump.dmi', "frame")
+ underlays += frame
/obj/machinery/atmospherics/unary/vent_pump/hide()
update_icon()
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
index c489ae93b25..c82e9ff3710 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
@@ -1,6 +1,6 @@
/obj/machinery/atmospherics/unary/vent_scrubber
icon = 'icons/atmos/vent_scrubber.dmi'
- icon_state = "map_scrubber"
+ icon_state = "map_scrubber_off"
req_one_access_txt = "24;10"
@@ -12,7 +12,7 @@
idle_power_usage = 10
active_power_usage = 60
- can_unwrench = 1
+ can_unwrench = TRUE
var/area/initial_loc
@@ -20,17 +20,17 @@
var/list/turf/simulated/adjacent_turfs = list()
- var/scrubbing = 1 //0 = siphoning, 1 = scrubbing
- var/scrub_O2 = 0
- var/scrub_N2 = 0
- var/scrub_CO2 = 1
- var/scrub_Toxins = 0
- var/scrub_N2O = 0
+ var/scrubbing = TRUE //FALSE = siphoning, TRUE = scrubbing
+ var/scrub_O2 = FALSE
+ var/scrub_N2 = FALSE
+ var/scrub_CO2 = TRUE
+ var/scrub_Toxins = FALSE
+ var/scrub_N2O = FALSE
var/volume_rate = 200
- var/widenet = 0 //is this scrubber acting on the 3x3 area around it.
+ var/widenet = FALSE //is this scrubber acting on the 3x3 area around it.
- var/welded = 0
+ var/welded = FALSE
var/area_uid
var/radio_filter_out
@@ -40,6 +40,7 @@
/obj/machinery/atmospherics/unary/vent_scrubber/on
on = TRUE
+ icon_state = "map_scrubber"
/obj/machinery/atmospherics/unary/vent_scrubber/New()
..()
@@ -115,10 +116,13 @@
scrubber_icon += "off"
else
scrubber_icon += "[on ? "[scrubbing ? "on" : "in"]" : "off"]"
+ if(on && widenet)
+ scrubber_icon += "_expanded"
+
if(welded)
scrubber_icon = "scrubberweld"
- overlays += SSair.icon_manager.get_atmos_icon("device", , , scrubber_icon)
+ overlays += SSair.icon_manager.get_atmos_icon("device", state = scrubber_icon)
update_pipe_image()
/obj/machinery/atmospherics/unary/vent_scrubber/update_underlays()
@@ -134,6 +138,9 @@
add_underlay(T, node, dir, node.icon_connect_type)
else
add_underlay(T,, dir)
+ var/icon/frame = icon('icons/atmos/vent_scrubber.dmi', "frame")
+ underlays += frame
+
/obj/machinery/atmospherics/unary/vent_scrubber/set_frequency(new_frequency)
SSradio.remove_object(src, frequency)
@@ -201,7 +208,7 @@
return
if(!node)
- on = 0
+ on = FALSE
if(welded)
return 0
diff --git a/code/modules/atmospherics/machinery/pipes/pipe.dm b/code/modules/atmospherics/machinery/pipes/pipe.dm
index 2e79545b206..5641306414d 100644
--- a/code/modules/atmospherics/machinery/pipes/pipe.dm
+++ b/code/modules/atmospherics/machinery/pipes/pipe.dm
@@ -4,7 +4,7 @@
var/volume = 0
force = 20
use_power = NO_POWER_USE
- can_unwrench = 1
+ can_unwrench = TRUE
damage_deflection = 12
var/alert_pressure = 80*ONE_ATMOSPHERE //minimum pressure before check_pressure(...) should be called
diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm
index e945d211793..54bbd15930d 100644
--- a/code/modules/atmospherics/machinery/portable/canister.dm
+++ b/code/modules/atmospherics/machinery/portable/canister.dm
@@ -43,13 +43,13 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
name = "canister"
icon = 'icons/obj/atmos.dmi'
icon_state = "yellow"
- density = 1
+ density = TRUE
flags = CONDUCT
armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 100, BOMB = 10, BIO = 100, RAD = 100, FIRE = 80, ACID = 50)
max_integrity = 250
integrity_failure = 100
- var/valve_open = 0
+ var/valve_open = FALSE
var/release_pressure = ONE_ATMOSPHERE
var/list/canister_color //variable that stores colours
@@ -61,13 +61,13 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
//passed to the ui to render the color lists
var/list/colorcontainer
- var/can_label = 1
+ var/can_label = TRUE
var/filled = 0.5
pressure_resistance = 7 * ONE_ATMOSPHERE
var/temperature_resistance = 1000 + T0C
volume = 1000
use_power = NO_POWER_USE
- interact_offline = 1
+ interact_offline = TRUE
var/release_log = ""
var/update_flag = 0
@@ -254,9 +254,9 @@ update_flag
if(air_contents.return_pressure() < 1)
- can_label = 1
+ can_label = TRUE
else
- can_label = 0
+ can_label = FALSE
updateDialog()
return
@@ -396,31 +396,31 @@ update_flag
/obj/machinery/portable_atmospherics/canister/toxins
name = "Canister \[Toxin (Plasma)\]"
icon_state = "orange" //See New()
- can_label = 0
+ can_label = FALSE
/obj/machinery/portable_atmospherics/canister/oxygen
name = "Canister: \[O2\]"
icon_state = "blue" //See New()
- can_label = 0
+ can_label = FALSE
/obj/machinery/portable_atmospherics/canister/sleeping_agent
name = "Canister: \[N2O\]"
icon_state = "redws" //See New()
- can_label = 0
+ can_label = FALSE
/obj/machinery/portable_atmospherics/canister/nitrogen
name = "Canister: \[N2\]"
icon_state = "red" //See New()
- can_label = 0
+ can_label = FALSE
/obj/machinery/portable_atmospherics/canister/carbon_dioxide
name = "Canister \[CO2\]"
icon_state = "black" //See New()
- can_label = 0
+ can_label = FALSE
/obj/machinery/portable_atmospherics/canister/air
name = "Canister \[Air\]"
icon_state = "grey" //See New()
- can_label = 0
+ can_label = FALSE
/obj/machinery/portable_atmospherics/canister/custom_mix
name = "Canister \[Custom\]"
icon_state = "whiters" //See New()
- can_label = 0
+ can_label = FALSE
/obj/machinery/portable_atmospherics/canister/toxins/New()
diff --git a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm
index 625b47a7fe7..0f8789859d8 100644
--- a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm
+++ b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm
@@ -65,7 +65,7 @@
connected_port.build_network()
connected_port.parent.reconcile_air()
- anchored = 1 //Prevent movement
+ anchored = TRUE //Prevent movement
return 1
@@ -73,7 +73,7 @@
if(!connected_port)
return 0
- anchored = 0
+ anchored = FALSE
connected_port.connected_device = null
connected_port = null
diff --git a/code/modules/atmospherics/machinery/portable/scrubber.dm b/code/modules/atmospherics/machinery/portable/scrubber.dm
index f106e7b8406..0904fd72a55 100644
--- a/code/modules/atmospherics/machinery/portable/scrubber.dm
+++ b/code/modules/atmospherics/machinery/portable/scrubber.dm
@@ -164,14 +164,14 @@
/obj/machinery/portable_atmospherics/scrubber/huge
name = "Huge Air Scrubber"
icon_state = "scrubber:0"
- anchored = 1
+ anchored = TRUE
volume = 50000
volume_rate = 5000
- widenet = 1
+ widenet = TRUE
var/global/gid = 1
var/id = 0
- var/stationary = 0
+ var/stationary = FALSE
/obj/machinery/portable_atmospherics/scrubber/huge/New()
..()
@@ -212,6 +212,6 @@
/obj/machinery/portable_atmospherics/scrubber/huge/stationary
name = "Stationary Air Scrubber"
- stationary = 1
+ stationary = TRUE
#undef MAX_RATE
diff --git a/code/modules/awaymissions/maploader/reader.dm b/code/modules/awaymissions/maploader/reader.dm
index 48aa90651a5..795b697bc4d 100644
--- a/code/modules/awaymissions/maploader/reader.dm
+++ b/code/modules/awaymissions/maploader/reader.dm
@@ -319,7 +319,7 @@ GLOBAL_DATUM_INIT(_preloader, /datum/dmm_suite/preloader, new())
var/turf/T = locate(x, y, z)
if(T)
if(ispath(path, /turf))
- T.ChangeTurf(path, defer_change = TRUE, keep_icon = FALSE)
+ T.ChangeTurf(path, defer_change = TRUE, keep_icon = FALSE, copy_existing_baseturf = FALSE)
instance = T
else if(ispath(path, /area))
diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm
index 727d189490e..ce1838e05ec 100644
--- a/code/modules/client/preference/preferences.dm
+++ b/code/modules/client/preference/preferences.dm
@@ -15,7 +15,6 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
ROLE_DEMON = 21,
ROLE_SENTIENT = 21,
// ROLE_GANG = 21,
- ROLE_BORER = 21,
ROLE_NINJA = 21,
ROLE_GSPIDER = 21,
ROLE_ABDUCTOR = 30
diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm
index 9308bc944c1..3f071e22665 100644
--- a/code/modules/clothing/chameleon.dm
+++ b/code/modules/clothing/chameleon.dm
@@ -298,11 +298,11 @@
origin_tech = "magnets=3;syndicate=4"
vision_flags = SEE_MOBS
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
- flash_protect = -1
+ flash_protect = FLASH_PROTECTION_SENSITIVE
prescription_upgradable = TRUE
/obj/item/clothing/glasses/hud/security/chameleon
- flash_protect = 1
+ flash_protect = FLASH_PROTECTION_FLASH
var/datum/action/item_action/chameleon/change/chameleon_action
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index cff5fb44b51..2f48d7ec6ef 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -16,9 +16,9 @@
lefthand_file = 'icons/mob/inhands/clothing_lefthand.dmi'
righthand_file = 'icons/mob/inhands/clothing_righthand.dmi'
var/alt_desc = null
- var/flash_protect = 0 //What level of bright light protection item has. 1 = Flashers, Flashes, & Flashbangs | 2 = Welding | -1 = OH GOD WELDING BURNT OUT MY RETINAS
+ var/flash_protect = FLASH_PROTECTION_NONE //What level of bright light protection item has. 1 = Flashers, Flashes, & Flashbangs | 2 = Welding | -1 = OH GOD WELDING BURNT OUT MY RETINAS
var/tint = 0 //Sets the item's level of visual impairment tint, normally set to the same as flash_protect
- var/up = 0 //but seperated to allow items to protect but not impair vision, like space helmets
+ var/up = FALSE //but seperated to allow items to protect but not impair vision, like space helmets
var/visor_flags = 0 //flags that are added/removed when an item is adjusted up/down
var/visor_flags_inv = 0 //same as visor_flags, but for flags_inv
@@ -207,7 +207,7 @@
var/list/color_view = null//overrides client.color while worn
var/prescription = 0
- var/prescription_upgradable = 0
+ var/prescription_upgradable = FALSE
var/over_mask = FALSE //Whether or not the eyewear is rendered above the mask. Purely cosmetic.
strip_delay = 20 // but seperated to allow items to protect but not impair vision, like space helmets
put_on_delay = 25
@@ -602,7 +602,7 @@ BLIND // can't see anything
heat_protection = HEAD
max_heat_protection_temperature = SPACE_HELM_MAX_TEMP_PROTECT
species_restricted = list("exclude","Wryn")
- flash_protect = 2
+ flash_protect = FLASH_PROTECTION_WELDER
strip_delay = 50
put_on_delay = 50
resistance_flags = NONE
diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm
index d9a50d070f9..ee031f9f622 100644
--- a/code/modules/clothing/glasses/glasses.dm
+++ b/code/modules/clothing/glasses/glasses.dm
@@ -68,7 +68,7 @@
origin_tech = "magnets=1;engineering=2"
vision_flags = SEE_TURFS
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
- prescription_upgradable = 1
+ prescription_upgradable = TRUE
sprite_sheets = list(
"Vox" = 'icons/mob/clothing/species/vox/eyes.dmi',
@@ -84,7 +84,7 @@
origin_tech = "magnets=4;engineering=5;plasmatech=4"
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
- prescription_upgradable = 0
+ prescription_upgradable = FALSE
/obj/item/clothing/glasses/meson/prescription
prescription = 1
@@ -99,7 +99,7 @@
throw_speed = 4
attack_verb = list("sliced")
hitsound = 'sound/weapons/bladeslice.ogg'
- sharp = 1
+ sharp = TRUE
/obj/item/clothing/glasses/meson/cyber
name = "eye replacement implant"
@@ -108,7 +108,7 @@
item_state = "eyepatch"
flags = NODROP
flags_cover = null
- prescription_upgradable = 0
+ prescription_upgradable = FALSE
/obj/item/clothing/glasses/science
name = "science goggles"
@@ -182,7 +182,7 @@
desc = "Such a dapper eyepiece!"
icon_state = "monocle"
item_state = "headset" // lol
- prescription_upgradable = 1
+ prescription_upgradable = TRUE
sprite_sheets = list(
"Vox" = 'icons/mob/clothing/species/vox/eyes.dmi',
@@ -263,7 +263,7 @@
"Grey" = 'icons/mob/clothing/species/grey/eyes.dmi',
"Drask" = 'icons/mob/clothing/species/drask/eyes.dmi'
)
- prescription_upgradable = 1
+ prescription_upgradable = TRUE
/obj/item/clothing/glasses/sunglasses
name = "sunglasses"
@@ -271,9 +271,9 @@
icon_state = "sun"
item_state = "sunglasses"
see_in_dark = 1
- flash_protect = 1
+ flash_protect = FLASH_PROTECTION_FLASH
tint = 1
- prescription_upgradable = 1
+ prescription_upgradable = TRUE
dog_fashion = /datum/dog_fashion/head
sprite_sheets = list(
"Vox" = 'icons/mob/clothing/species/vox/eyes.dmi',
@@ -287,7 +287,7 @@
icon_state = "sun"
item_state = "sunglasses"
see_in_dark = 0
- flash_protect = 0
+ flash_protect = FLASH_PROTECTION_NONE
tint = 0
sprite_sheets = list(
"Vox" = 'icons/mob/clothing/species/vox/eyes.dmi',
@@ -340,7 +340,7 @@
icon_state = "sun"
item_state = "sunglasses"
see_in_dark = 1
- flash_protect = 1
+ flash_protect = FLASH_PROTECTION_FLASH
tint = 1
sprite_sheets = list(
@@ -366,7 +366,7 @@
icon_state = "welding-g"
item_state = "welding-g"
actions_types = list(/datum/action/item_action/toggle)
- flash_protect = 2
+ flash_protect = FLASH_PROTECTION_WELDER
tint = 2
visor_vars_to_toggle = VISOR_FLASHPROTECT | VISOR_TINT
sprite_sheets = list(
@@ -383,7 +383,7 @@
desc = "Welding goggles made from more expensive materials, strangely smells like potatoes."
icon_state = "rwelding-g"
item_state = "rwelding-g"
- flash_protect = 2
+ flash_protect = FLASH_PROTECTION_WELDER
tint = 0
/obj/item/clothing/glasses/sunglasses/blindfold
@@ -391,14 +391,14 @@
desc = "Covers the eyes, preventing sight."
icon_state = "blindfold"
item_state = "blindfold"
- flash_protect = 2
+ flash_protect = FLASH_PROTECTION_WELDER
tint = 3 //to make them blind
- prescription_upgradable = 0
+ prescription_upgradable = FALSE
/obj/item/clothing/glasses/sunglasses/blindfold/fake
name = "tattered blindfold"
desc = "A see-through blindfold perfect for cheating at games like pin the stunbaton on the clown."
- flash_protect = 0
+ flash_protect = FLASH_PROTECTION_NONE
tint = 0
/obj/item/clothing/glasses/sunglasses/prescription
@@ -417,7 +417,7 @@
origin_tech = "magnets=3"
vision_flags = SEE_MOBS
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
- flash_protect = -1
+ flash_protect = FLASH_PROTECTION_SENSITIVE
sprite_sheets = list(
"Vox" = 'icons/mob/clothing/species/vox/eyes.dmi',
@@ -495,7 +495,7 @@
item_state = "tajblind"
flags_cover = GLASSESCOVERSEYES
actions_types = list(/datum/action/item_action/toggle)
- up = 0
+ up = FALSE
tint = 0
sprite_sheets = list(
diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm
index 7cc16ade700..b6ad033fb45 100644
--- a/code/modules/clothing/glasses/hud.dm
+++ b/code/modules/clothing/glasses/hud.dm
@@ -3,7 +3,7 @@
desc = "A heads-up display that provides important info in (almost) real time."
flags = null //doesn't protect eyes because it's a monocle, duh
origin_tech = "magnets=3;biotech=2"
- prescription_upgradable = 1
+ prescription_upgradable = TRUE
/// The visual icons granted by wearing these glasses.
var/HUDType = null
/// List of things added to examine text, like security or medical records.
@@ -23,8 +23,8 @@
H.remove_hud_from(user)
/obj/item/clothing/glasses/hud/emp_act(severity)
- if(emagged == 0)
- emagged = 1
+ if(!emagged)
+ emagged = TRUE
desc = desc + " The display flickers slightly."
/obj/item/clothing/glasses/hud/health
@@ -49,14 +49,14 @@
origin_tech = "magnets=4;biotech=4;plasmatech=4;engineering=5"
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
- prescription_upgradable = 0
+ prescription_upgradable = FALSE
/obj/item/clothing/glasses/hud/health/sunglasses
name = "medical HUDSunglasses"
desc = "Sunglasses with a medical HUD."
icon_state = "sunhudmed"
see_in_dark = 1
- flash_protect = 1
+ flash_protect = FLASH_PROTECTION_FLASH
tint = 1
/obj/item/clothing/glasses/hud/diagnostic
@@ -80,14 +80,14 @@
origin_tech = "magnets=4;powerstorage=4;plasmatech=4;engineering=5"
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
- prescription_upgradable = 0
+ prescription_upgradable = FALSE
/obj/item/clothing/glasses/hud/diagnostic/sunglasses
name = "diagnostic sunglasses"
desc = "Sunglasses with a diagnostic HUD."
icon_state = "sunhuddiag"
item_state = "glasses"
- flash_protect = 1
+ flash_protect = FLASH_PROTECTION_FLASH
tint = 1
/obj/item/clothing/glasses/hud/security
@@ -121,7 +121,7 @@
origin_tech = "magnets=4;combat=4;plasmatech=4;engineering=5"
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE //don't render darkness while wearing these
- prescription_upgradable = 0
+ prescription_upgradable = FALSE
/obj/item/clothing/glasses/hud/security/sunglasses/read_only
examine_extensions = list(EXAMINE_HUD_SECURITY_READ)
@@ -132,9 +132,9 @@
icon_state = "sunhud"
origin_tech = "magnets=3;combat=3;engineering=3"
see_in_dark = 1
- flash_protect = 1
+ flash_protect = FLASH_PROTECTION_FLASH
tint = 1
- prescription_upgradable = 1
+ prescription_upgradable = TRUE
sprite_sheets = list(
"Vox" = 'icons/mob/clothing/species/vox/eyes.dmi',
@@ -164,7 +164,7 @@
item_state = "glasses"
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
- prescription_upgradable = 0
+ prescription_upgradable = FALSE
/obj/item/clothing/glasses/hud/security/tajblind
name = "sleek veil"
@@ -174,7 +174,7 @@
flash_protect = FLASH_PROTECTION_FLASH
flags_cover = GLASSESCOVERSEYES
actions_types = list(/datum/action/item_action/toggle)
- up = 0
+ up = FALSE
sprite_sheets = list(
"Vox" = 'icons/mob/clothing/species/vox/eyes.dmi'
@@ -190,7 +190,7 @@
item_state = "tajblind_med"
flags_cover = GLASSESCOVERSEYES
actions_types = list(/datum/action/item_action/toggle)
- up = 0
+ up = FALSE
sprite_sheets = list(
"Vox" = 'icons/mob/clothing/species/vox/eyes.dmi',
@@ -219,7 +219,7 @@
desc = "Sunglasses with a build-in skills HUD, showing the employment history of nearby NT crew members."
icon_state = "sunhudskill"
see_in_dark = 1 // None of these three can be converted to booleans. Do not try it.
- flash_protect = 1
+ flash_protect = FLASH_PROTECTION_FLASH
tint = 1
prescription_upgradable = TRUE
sprite_sheets = list(
diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm
index 1efc0aa79d0..0d42075b102 100644
--- a/code/modules/clothing/head/misc_special.dm
+++ b/code/modules/clothing/head/misc_special.dm
@@ -19,7 +19,7 @@
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
item_state = "welding"
materials = list(MAT_METAL=1750, MAT_GLASS=400)
- flash_protect = 2
+ flash_protect = FLASH_PROTECTION_WELDER
tint = 2
armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 60)
flags_inv = (HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE)
@@ -63,7 +63,7 @@
flags_inv |= (HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE)
icon_state = initial(icon_state)
to_chat(usr, "You flip [src] down to protect your eyes.")
- flash_protect = 2
+ flash_protect = FLASH_PROTECTION_WELDER
tint = 2
else
up = !up
@@ -71,7 +71,7 @@
flags_inv &= ~(HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE)
icon_state = "[initial(icon_state)]up"
to_chat(usr, "You push [src] up out of your face.")
- flash_protect = 0
+ flash_protect = FLASH_PROTECTION_NONE
tint = 0
var/mob/living/carbon/user = usr
user.update_tint()
@@ -94,7 +94,7 @@
icon_state = "cake0"
flags_cover = HEADCOVERSEYES
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0)
- var/onfire = 0.0
+ var/onfire = FALSE
var/status = 0
var/fire_resist = T0C+1300 //this is the max temp it can stand before you start to cook. although it might not burn away, you take damage
var/processing = 0 //I dont think this is used anywhere.
@@ -104,7 +104,7 @@
STOP_PROCESSING(SSobj, src)
return
- var/turf/location = src.loc
+ var/turf/location = loc
if(istype(location, /mob/))
var/mob/living/carbon/human/M = location
if(M.l_hand == src || M.r_hand == src || M.head == src)
@@ -113,19 +113,19 @@
if(istype(location, /turf))
location.hotspot_expose(700, 1)
-/obj/item/clothing/head/cakehat/attack_self(mob/user as mob)
- if(status > 1) return
- src.onfire = !( src.onfire )
- if(src.onfire)
- src.force = 3
- src.damtype = "fire"
- src.icon_state = "cake1"
+/obj/item/clothing/head/cakehat/attack_self(mob/user)
+ if(status > 1)
+ return
+ onfire = !onfire
+ if(onfire)
+ force = 3
+ damtype = BURN
+ icon_state = "cake1"
START_PROCESSING(SSobj, src)
else
- src.force = null
- src.damtype = "brute"
- src.icon_state = "cake0"
- return
+ force = null
+ damtype = BRUTE
+ icon_state = "cake0"
/*
@@ -145,13 +145,13 @@
)
/obj/item/clothing/head/ushanka/attack_self(mob/user as mob)
- if(src.icon_state == "ushankadown")
- src.icon_state = "ushankaup"
- src.item_state = "ushankaup"
+ if(icon_state == "ushankadown")
+ icon_state = "ushankaup"
+ item_state = "ushankaup"
to_chat(user, "You raise the ear flaps on the ushanka.")
else
- src.icon_state = "ushankadown"
- src.item_state = "ushankadown"
+ icon_state = "ushankadown"
+ item_state = "ushankadown"
to_chat(user, "You lower the ear flaps on the ushanka.")
/*
diff --git a/code/modules/clothing/head/soft_caps.dm b/code/modules/clothing/head/soft_caps.dm
index ebfda8ca2f4..58dae571544 100644
--- a/code/modules/clothing/head/soft_caps.dm
+++ b/code/modules/clothing/head/soft_caps.dm
@@ -4,7 +4,7 @@
icon_state = "cargosoft"
item_state = "helmet"
item_color = "cargo"
- var/flipped = 0
+ var/flipped = FALSE
actions_types = list(/datum/action/item_action/flip_cap)
dog_fashion = /datum/dog_fashion/head/cargo_tech
sprite_sheets = list(
@@ -14,7 +14,7 @@
/obj/item/clothing/head/soft/dropped()
icon_state = "[item_color]soft"
- flipped = 0
+ flipped = FALSE
..()
/obj/item/clothing/head/soft/attack_self(mob/user)
diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm
index d467406de66..0410fe45e81 100644
--- a/code/modules/clothing/masks/gasmask.dm
+++ b/code/modules/clothing/masks/gasmask.dm
@@ -28,7 +28,7 @@
icon_state = "weldingmask"
item_state = "weldingmask"
materials = list(MAT_METAL=4000, MAT_GLASS=2000)
- flash_protect = 2
+ flash_protect = FLASH_PROTECTION_WELDER
tint = 2
armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 55)
origin_tech = "materials=2;engineering=3"
diff --git a/code/modules/clothing/shoes/magboots.dm b/code/modules/clothing/shoes/magboots.dm
index f10e4e236c6..f66c407a633 100644
--- a/code/modules/clothing/shoes/magboots.dm
+++ b/code/modules/clothing/shoes/magboots.dm
@@ -4,7 +4,7 @@
icon_state = "magboots0"
origin_tech = "materials=3;magnets=4;engineering=4"
var/magboot_state = "magboots"
- var/magpulse = 0
+ var/magpulse = FALSE
var/slowdown_active = 2
var/slowdown_passive = SHOES_SLOWDOWN
var/magpulse_name = "mag-pulse traction system"
diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm
index b10ebf2af93..e9e66f49abc 100644
--- a/code/modules/clothing/shoes/miscellaneous.dm
+++ b/code/modules/clothing/shoes/miscellaneous.dm
@@ -14,7 +14,7 @@
strip_delay = 70
resistance_flags = NONE
-/obj/item/clothing/shoes/combat/swat //overpowered boots for death squads
+/obj/item/clothing/shoes/combat/swat //overpowered gimmick boots
name = "\improper SWAT shoes"
desc = "High speed, no drag combat boots."
permeability_coefficient = 0.01
diff --git a/code/modules/clothing/spacesuits/alien.dm b/code/modules/clothing/spacesuits/alien.dm
index f5e75dd2b9f..5cab13e9447 100644
--- a/code/modules/clothing/spacesuits/alien.dm
+++ b/code/modules/clothing/spacesuits/alien.dm
@@ -204,7 +204,7 @@
/obj/item/clothing/shoes/magboots/vox/attack_self(mob/user)
if(magpulse)
flags &= ~NOSLIP
- magpulse = 0
+ magpulse = FALSE
flags |= NODROP
to_chat(user, "You relax your deathgrip on the flooring.")
else
@@ -217,7 +217,7 @@
return
flags |= NOSLIP
- magpulse = 1
+ magpulse = TRUE
flags &= ~NODROP //kinda hard to take off magclaws when you are gripping them tightly.
to_chat(user, "You dig your claws deeply into the flooring, bracing yourself.")
to_chat(user, "It would be hard to take off [src] without relaxing your grip first.")
@@ -225,10 +225,10 @@
//In case they somehow come off while enabled.
/obj/item/clothing/shoes/magboots/vox/dropped(mob/user as mob)
..()
- if(src.magpulse)
+ if(magpulse)
user.visible_message("[src] go limp as they are removed from [usr]'s feet.", "[src] go limp as they are removed from your feet.")
flags &= ~NOSLIP
- magpulse = 0
+ magpulse = FALSE
flags &= ~NODROP
/obj/item/clothing/shoes/magboots/vox/examine(mob/user)
diff --git a/code/modules/clothing/spacesuits/breaches.dm b/code/modules/clothing/spacesuits/breaches.dm
deleted file mode 100644
index c739a93744d..00000000000
--- a/code/modules/clothing/spacesuits/breaches.dm
+++ /dev/null
@@ -1,214 +0,0 @@
-//A 'wound' system for space suits.
-//Breaches greatly increase the amount of lost gas and decrease the armour rating of the suit.
-//They can be healed with plastic or metal sheeting.
-
-/datum/breach
- var/class = 0 // Size. Lower is smaller.
- var/descriptor // 'gaping hole' etc.
- var/damtype = BURN // Punctured or melted
- var/obj/item/clothing/suit/space/holder // Suit containing the list of breaches holding this instance.
-
-/obj/item/clothing/suit/space
-
- var/can_breach = 0 // Set to 0 to disregard all breaching.
- var/list/breaches = list() // Breach datum container.
- var/resilience = 0.2 // Multiplier that turns damage into breach class. 1 is 100% of damage to breach, 0.1 is 10%.
- var/breach_threshold = 3 // Min damage before a breach is possible.
- var/damage = 0 // Current total damage
- var/brute_damage = 0 // Specifically brute damage.
- var/burn_damage = 0 // Specifically burn damage.
- var/base_name // Used to keep the original name safe while we apply modifiers.
-
-/obj/item/clothing/suit/space/New()
- ..()
- base_name = "[name]"
-
-//Some simple descriptors for breaches. Global because lazy, TODO: work out a better way to do this. | 6 years late, but atleast they are proper globals now
-
-GLOBAL_LIST_INIT(breach_brute_descriptors, list(
- "tiny puncture",
- "ragged tear",
- "large split",
- "huge tear",
- "gaping wound"
- ))
-
-GLOBAL_LIST_INIT(breach_burn_descriptors, list(
- "small burn",
- "melted patch",
- "sizable burn",
- "large scorched area",
- "huge scorched area"
- ))
-
-/datum/breach/proc/update_descriptor()
-
- //Sanity...
- class = max(1,min(class,5))
- //Apply the correct descriptor.
- if(damtype == BURN)
- descriptor = GLOB.breach_burn_descriptors[class]
- else if(damtype == BRUTE)
- descriptor = GLOB.breach_brute_descriptors[class]
-
-//Repair a certain amount of brute or burn damage to the suit.
-/obj/item/clothing/suit/space/proc/repair_breaches(damtype, amount, mob/user)
-
- if(!can_breach || !breaches || !breaches.len || !damage)
- to_chat(user, "There are no breaches to repair on \the [src].")
- return
-
- var/list/valid_breaches = list()
-
- for(var/datum/breach/B in breaches)
- if(B.damtype == damtype)
- valid_breaches += B
-
- if(!valid_breaches.len)
- to_chat(user, "There are no breaches to repair on \the [src].")
- return
-
- var/amount_left = amount
- for(var/datum/breach/B in valid_breaches)
- if(!amount_left) break
-
- if(B.class <= amount_left)
- amount_left -= B.class
- valid_breaches -= B
- breaches -= B
- else
- B.class -= amount_left
- amount_left = 0
- B.update_descriptor()
-
- user.visible_message("[user] patches some of the damage on \the [src].")
- calc_breach_damage()
-
-/obj/item/clothing/suit/space/proc/create_breaches(damtype, amount)
-
- if(!can_breach || !amount)
- return
-
- if(!breaches)
- breaches = list()
-
- if(damage >= 25) return //We don't need to keep tracking it when it's at 250% pressure loss, really.
-
- if(!loc) return
- var/turf/T = get_turf(src)
- if(!T) return
-
- amount = amount * src.resilience
-
- //Increase existing breaches.
- for(var/datum/breach/existing in breaches)
-
- if(existing.damtype != damtype)
- continue
-
- if(existing.class < 5)
- var/needs = 5 - existing.class
- if(amount < needs)
- existing.class += amount
- amount = 0
- else
- existing.class = 5
- amount -= needs
-
- if(existing.damtype == BRUTE)
- T.visible_message("\The [existing.descriptor] on [src] gapes wider!")
- else if(existing.damtype == BURN)
- T.visible_message("\The [existing.descriptor] on [src] widens!")
-
- if(amount)
- //Spawn a new breach.
- var/datum/breach/B = new()
- breaches += B
-
- B.class = min(amount,(5 - max(damage - 20,0))) //We cap the check at 25, this line could overshoot without the calculation if it gets enough dammage in one shot.
-
- B.damtype = damtype
- B.update_descriptor()
- B.holder = src
-
- if(B.damtype == BRUTE)
- T.visible_message("\A [B.descriptor] opens up on [src]!")
- else if(B.damtype == BURN)
- T.visible_message("\A [B.descriptor] marks the surface of [src]!")
-
- calc_breach_damage()
-
-//Calculates the current extent of the damage to the suit.
-/obj/item/clothing/suit/space/proc/calc_breach_damage()
-
- damage = 0
- brute_damage = 0
- burn_damage = 0
-
- if(!can_breach || !breaches || !breaches.len)
- name = base_name
- return 0
-
- for(var/datum/breach/B in breaches)
- if(!B.class)
- src.breaches -= B
- qdel(B)
- else
- damage += B.class
- if(B.damtype == BRUTE)
- brute_damage += B.class
- else if(B.damtype == BURN)
- burn_damage += B.class
-
- if(damage >= 3)
- if(brute_damage >= 3 && brute_damage > burn_damage)
- name = "punctured [base_name]"
- else if(burn_damage >= 3 && burn_damage > brute_damage)
- name = "scorched [base_name]"
- else
- name = "damaged [base_name]"
- else
- name = "[base_name]"
-
- return damage
-
-//Handles repairs (and also upgrades).
-
-/obj/item/clothing/suit/space/attackby(obj/item/W as obj, mob/user as mob, params)
- if(istype(W,/obj/item/stack/sheet/plastic) || istype(W,/obj/item/stack/sheet/metal))
-
- if(istype(src.loc,/mob/living))
- to_chat(user, "How do you intend to patch a hardsuit while someone is wearing it?")
- return
-
- if(!damage || !burn_damage)
- to_chat(user, "There is no surface damage on \the [src] to repair.")
- return
-
- var/obj/item/stack/sheet/P = W
- if(P.amount < 3)
- P.use(P.amount)
- repair_breaches(BURN, ( istype(P,/obj/item/stack/sheet/plastic) ? P.amount : (P.amount*2) ), user)
- else
- P.use(3)
- repair_breaches(BURN, ( istype(P,/obj/item/stack/sheet/plastic) ? 3 : 5), user)
- return
-
-
-/obj/item/clothing/suit/space/welder_act(mob/user, obj/item/I)
- . = TRUE
- if(istype(src.loc,/mob/living))
- to_chat(user, "How do you intend to patch a hardsuit while someone is wearing it?")
- return
- if(!damage || ! brute_damage)
- to_chat(user, "There is no structural damage on \the [src] to repair.")
- return
- if(!I.use_tool(src, user, amount = 5, volume = I.tool_volume))
- return
- repair_breaches(BRUTE, 3, user)
-
-/obj/item/clothing/suit/space/examine(mob/user)
- . = ..()
- if(can_breach && breaches && breaches.len)
- for(var/datum/breach/B in breaches)
- . += "It has \a [B.descriptor]."
diff --git a/code/modules/clothing/spacesuits/chronosuit.dm b/code/modules/clothing/spacesuits/chronosuit.dm
index 65d5b5dd00d..21d5f684454 100644
--- a/code/modules/clothing/spacesuits/chronosuit.dm
+++ b/code/modules/clothing/spacesuits/chronosuit.dm
@@ -28,10 +28,10 @@
resistance_flags = FIRE_PROOF | ACID_PROOF
var/obj/item/clothing/head/helmet/space/chronos/helmet = null
var/obj/effect/chronos_cam/camera = null
- var/activating = 0
- var/activated = 0
- var/cooldowntime = 50 //deciseconds
- var/teleporting = 0
+ var/activating = FALSE
+ var/activated = FALSE
+ var/cooldowntime = 5 SECONDS
+ var/teleporting = FALSE
/obj/item/clothing/suit/space/chronos/proc/new_camera(mob/user)
@@ -58,7 +58,7 @@
return ..()
/obj/item/clothing/suit/space/chronos/emp_act(severity)
- var/mob/living/carbon/human/user = src.loc
+ var/mob/living/carbon/human/user = loc
switch(severity)
if(1)
if(user && ishuman(user) && (user.wear_suit == src))
@@ -67,10 +67,10 @@
/obj/item/clothing/suit/space/chronos/proc/chronowalk(mob/living/carbon/human/user)
if(!teleporting && user && (user.stat == CONSCIOUS))
- teleporting = 1
+ teleporting = TRUE
var/turf/from_turf = get_turf(user)
if(!from_turf) //sanity, things happen
- teleporting = 0
+ teleporting = FALSE
return
var/turf/to_turf = from_turf
var/atom/movable/overlay/phaseanim = new(from_turf)
@@ -78,7 +78,7 @@
phaseanim.name = "phasing [user.name]"
phaseanim.icon = 'icons/mob/mob.dmi'
phaseanim.icon_state = "chronostuck"
- phaseanim.density = 1
+ phaseanim.density = TRUE
phaseanim.layer = FLY_LAYER
phaseanim.master = user
user.ExtinguishMob()
@@ -107,14 +107,14 @@
user.loc = from_turf
if(phaseanim)
qdel(phaseanim)
- teleporting = 0
+ teleporting = FALSE
if(user && !user.loc) //ubersanity
user.loc = locate(0,0,1)
user.gib()
/obj/item/clothing/suit/space/chronos/process()
if(activated)
- var/mob/living/carbon/human/user = src.loc
+ var/mob/living/carbon/human/user = loc
if(user && ishuman(user) && (user.wear_suit == src))
if(camera && (user.remote_control == camera))
if(!teleporting && !((camera.x == user.x) && (camera.y == user.y) && (camera.z == user.z))) //cheaper than a couple get_turf calls???
@@ -126,8 +126,8 @@
/obj/item/clothing/suit/space/chronos/proc/activate()
if(!activating && !activated && !teleporting)
- activating = 1
- var/mob/living/carbon/human/user = src.loc
+ activating = TRUE
+ var/mob/living/carbon/human/user = loc
if(user && ishuman(user))
if(user.wear_suit == src)
to_chat(user, "\nChronosuitMK4 login: root")
@@ -138,24 +138,24 @@
helmet = user.head
helmet.flags |= NODROP
helmet.suit = src
- src.flags |= NODROP
+ flags |= NODROP
to_chat(user, "\[ ok \] Starting brainwave scanner")
to_chat(user, "\[ ok \] Starting ui display driver")
to_chat(user, "\[ ok \] Initializing chronowalk4-view")
new_camera(user)
START_PROCESSING(SSobj, src)
- activated = 1
+ activated = TRUE
else
to_chat(user, "\[ fail \] Mounting /dev/helmet")
to_chat(user, "FATAL: Unable to locate /dev/helmet. Aborting...")
cooldown = world.time + cooldowntime
- activating = 0
+ activating = FALSE
return 0
/obj/item/clothing/suit/space/chronos/proc/deactivate()
if(activated)
- activating = 1
- var/mob/living/carbon/human/user = src.loc
+ activating = TRUE
+ var/mob/living/carbon/human/user = loc
if(user && ishuman(user))
if(user.wear_suit == src)
to_chat(user, "\nroot@ChronosuitMK4# chronowalk4 --stop\n")
@@ -171,18 +171,18 @@
helmet.suit = null
helmet = null
to_chat(user, "logout")
- src.flags &= ~NODROP
+ flags &= ~NODROP
cooldown = world.time + cooldowntime * 1.5
- activated = 0
- activating = 0
+ activated = FALSE
+ activating = FALSE
/obj/effect/chronos_cam
name = "chronosuit view"
- density = 0
- anchored = 1
+ density = FALSE
+ anchored = TRUE
invisibility = 101
- opacity = 0
+ opacity = FALSE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
var/mob/holder = null
@@ -196,15 +196,15 @@
if(holder)
if(user == holder)
if(user.client && user.client.eye != src)
- src.loc = get_turf(user)
+ loc = get_turf(user)
user.client.eye = src
var/step = get_step(src, direction)
if(step)
if(istype(step, /turf/space))
- if(!src.Move(step))
- src.loc = step
+ if(!Move(step))
+ loc = step
else
- src.loc = step
+ loc = step
else
qdel(src)
diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm
index d8ee7c5a3d1..de2f2263b98 100644
--- a/code/modules/clothing/spacesuits/hardsuit.dm
+++ b/code/modules/clothing/spacesuits/hardsuit.dm
@@ -335,7 +335,7 @@
item_state = "syndie_helm"
item_color = "syndi"
armor = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 15, BOMB = 35, BIO = 100, RAD = 50, FIRE = 50, ACID = 90)
- on = 1
+ on = TRUE
var/obj/item/clothing/suit/space/hardsuit/syndi/linkedsuit = null
actions_types = list(/datum/action/item_action/toggle_helmet_mode)
visor_flags_inv = HIDEMASK|HIDEEYES|HIDEFACE|HIDETAIL
@@ -410,7 +410,7 @@
item_state = "syndie_hardsuit"
item_color = "syndi"
w_class = WEIGHT_CLASS_NORMAL
- var/on = 1
+ var/on = TRUE
actions_types = list(/datum/action/item_action/toggle_hardsuit_mode)
armor = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 15, BOMB = 35, BIO = 100, RAD = 50, FIRE = 50, ACID = 90)
allowed = list(/obj/item/gun, /obj/item/ammo_box,/obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/melee/energy/sword, /obj/item/restraints/handcuffs, /obj/item/tank/internals)
@@ -482,7 +482,7 @@
icon_state = "hardsuit0-medical"
item_state = "medical_helm"
item_color = "medical"
- flash_protect = 0
+ flash_protect = FLASH_PROTECTION_NONE
armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 5, BOMB = 10, BIO = 100, RAD = 60, FIRE = 60, ACID = 75)
scan_reagents = 1 //Generally worn by the CMO, so they'd get utility off of seeing reagents
@@ -503,7 +503,7 @@
icon_state = "hardsuit0-rd"
item_state = "rd"
item_color = "rd"
- flash_protect = 0
+ flash_protect = FLASH_PROTECTION_NONE
scan_reagents = TRUE
armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 5, BOMB = 100, BIO = 100, RAD = 60, FIRE = 60, ACID = 80)
var/hud_active = FALSE
diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm
index abed3c94698..645f10a63a9 100644
--- a/code/modules/clothing/spacesuits/miscellaneous.dm
+++ b/code/modules/clothing/spacesuits/miscellaneous.dm
@@ -39,7 +39,7 @@
//Deathsquad space suit, not hardsuits because no flashlight!
/obj/item/clothing/head/helmet/space/deathsquad
- name = "deathsquad helmet"
+ name = "Deathsquad helmet"
desc = "That's not red paint. That's real blood."
icon_state = "deathsquad"
item_state = "deathsquad"
@@ -53,12 +53,13 @@
strip_delay = 130
/obj/item/clothing/suit/space/deathsquad
- name = "deathsquad suit"
+ name = "Deathsquad suit"
desc = "A heavily armored, advanced space suit that protects against most forms of damage."
icon_state = "deathsquad"
item_state = "swat_suit"
- allowed = list(/obj/item/gun,/obj/item/ammo_box,/obj/item/ammo_casing,/obj/item/melee/baton,/obj/item/restraints/handcuffs,/obj/item/tank/internals,/obj/item/kitchen/knife/combat)
+ allowed = list(/obj/item/gun,/obj/item/ammo_box,/obj/item/ammo_casing,/obj/item/melee/baton,/obj/item/restraints/handcuffs,/obj/item/tank/internals,/obj/item/kitchen/knife/combat,/obj/item/flashlight)
armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 50, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100)
+ flags_inv = HIDESHOES | HIDEJUMPSUIT | HIDETAIL
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF | ACID_PROOF
strip_delay = 130
@@ -238,7 +239,7 @@
desc = "A lightweight space helmet with the basic ability to protect the wearer from the vacuum of space during emergencies."
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 100, rad = 20, fire = 50, acid = 65)
- flash_protect = 0
+ flash_protect = FLASH_PROTECTION_NONE
species_restricted = list("exclude", "Wryn")
sprite_sheets = list(
"Tajaran" = 'icons/mob/clothing/species/tajaran/helmet.dmi',
diff --git a/code/modules/clothing/spacesuits/plasmamen.dm b/code/modules/clothing/spacesuits/plasmamen.dm
index d2ab5b97334..debdb7e5ffe 100644
--- a/code/modules/clothing/spacesuits/plasmamen.dm
+++ b/code/modules/clothing/spacesuits/plasmamen.dm
@@ -5,7 +5,7 @@
icon_state = "plasmaman-helm"
item_state = "plasmaman-helm"
strip_delay = 80
- flash_protect = 2
+ flash_protect = FLASH_PROTECTION_WELDER
tint = 2
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 0, FIRE = 100, ACID = 75)
resistance_flags = FIRE_PROOF
diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm
index dcefff109d5..f970d675eb5 100644
--- a/code/modules/clothing/suits/miscellaneous.dm
+++ b/code/modules/clothing/suits/miscellaneous.dm
@@ -940,20 +940,20 @@
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
slowdown = -10
siemens_coefficient = 0
- var/on = 0
+ var/on = FALSE
/obj/item/clothing/suit/advanced_protective_suit/Destroy()
if(on)
- on = 0
+ on = FALSE
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/clothing/suit/advanced_protective_suit/ui_action_click()
if(on)
- on = 0
+ on = FALSE
to_chat(usr, "You turn the suit's special processes off.")
else
- on = 1
+ on = TRUE
to_chat(usr, "You turn the suit's special processes on.")
START_PROCESSING(SSobj, src)
diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm
index 84b4d93558c..6da70fa990a 100644
--- a/code/modules/clothing/under/miscellaneous.dm
+++ b/code/modules/clothing/under/miscellaneous.dm
@@ -104,6 +104,15 @@
sensor_mode = SENSOR_COORDS
random_sensor = FALSE
+/obj/item/clothing/under/rank/deathsquad
+ name = "\improper Deathsquad jumpsuit"
+ desc = "It's decorative jumpsuit worn by the Deathsquad. A small tag at the bottom reads \"Not associated with Nanotrasen\". "
+ icon_state = "officer"
+ item_state = "g_suit"
+ item_color = "officer"
+ sensor_mode = SENSOR_OFF // You think the Deathsquad wants to be seen?
+ random_sensor = FALSE
+
/obj/item/clothing/under/rank/centcom_commander
name = "\improper CentComm commander's jumpsuit"
desc = "It's a jumpsuit worn by CentComm's highest-tier Commanders."
diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm
index 22675ca4ad9..0bf8de3e8b7 100644
--- a/code/modules/customitems/item_defines.dm
+++ b/code/modules/customitems/item_defines.dm
@@ -1376,6 +1376,7 @@
desc = "A well made satchel for military operations. Totally not made by an enemy corporation"
icon = 'icons/obj/custom_items.dmi'
icon_state = "rawk_satchel"
+ item_state = null
sprite_sheets = null
/obj/item/storage/backpack/fluff/krich_back //lizardzsi: Krichahka
@@ -1383,12 +1384,14 @@
desc = "Battered, Sol-made military radio backpack that had its speakers fried from playing Vox opera. The words 'Swift-Talon' are crudely scratched onto its side."
icon = 'icons/obj/custom_items.dmi'
icon_state = "voxcaster_fluff"
+ item_state = null
/obj/item/storage/backpack/fluff/ssscratches_back //Ssscratches: Lasshy-Bot
name = "CatPack"
desc = "It's a backpack, but it's also a cat."
icon = 'icons/obj/custom_items.dmi'
icon_state = "ssscratches_backpack"
+ item_state = null
/obj/item/storage/backpack/fluff/thebrew //Greey: Korala Ice
name = "The Brew"
diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm
index 987a9cf7950..b88c7012369 100644
--- a/code/modules/events/event_container.dm
+++ b/code/modules/events/event_container.dm
@@ -163,7 +163,6 @@ GLOBAL_LIST_EMPTY(event_last_fired)
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Radiation Storm", /datum/event/radiation_storm, 25, list(ASSIGNMENT_MEDICAL = 50), TRUE),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Spider Infestation", /datum/event/spider_infestation, 100, list(ASSIGNMENT_SECURITY = 30), TRUE),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Ion Storm", /datum/event/ion_storm, 0, list(ASSIGNMENT_AI = 50, ASSIGNMENT_CYBORG = 50, ASSIGNMENT_ENGINEER = 15, ASSIGNMENT_SCIENTIST = 5)),
- new /datum/event_meta(EVENT_LEVEL_MODERATE, "Borer Infestation", /datum/event/borer_infestation, 40, list(ASSIGNMENT_SECURITY = 30), TRUE),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Immovable Rod", /datum/event/immovable_rod, 0, list(ASSIGNMENT_ENGINEER = 30), TRUE),
//new /datum/event_meta/ninja(EVENT_LEVEL_MODERATE, "Space Ninja", /datum/event/space_ninja, 0, list(ASSIGNMENT_SECURITY = 15), TRUE),
// NON-BAY EVENTS
diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm
index 619a6a51977..b69b9d92622 100644
--- a/code/modules/events/spacevine.dm
+++ b/code/modules/events/spacevine.dm
@@ -137,7 +137,7 @@
if(prob(50))
ChangeTurf(baseturf)
-/turf/simulated/floor/vines/ChangeTurf(turf/simulated/floor/T, defer_change = FALSE, keep_icon = TRUE, ignore_air = FALSE)
+/turf/simulated/floor/vines/ChangeTurf(turf/simulated/floor/T, defer_change = FALSE, keep_icon = TRUE, ignore_air = FALSE, copy_existing_baseturf = TRUE)
. = ..()
//Do this *after* the turf has changed as qdel in spacevines will call changeturf again if it hasn't
for(var/obj/structure/spacevine/SV in src)
diff --git a/code/modules/food_and_drinks/drinks/bottler/bottler.dm b/code/modules/food_and_drinks/drinks/bottler/bottler.dm
index 503b7752a91..667c64be053 100644
--- a/code/modules/food_and_drinks/drinks/bottler/bottler.dm
+++ b/code/modules/food_and_drinks/drinks/bottler/bottler.dm
@@ -14,13 +14,13 @@
desc = "A machine that combines ingredients and bottles the resulting beverages."
icon = 'icons/obj/kitchen.dmi'
icon_state = "bottler_off"
- density = 1
- anchored = 1
+ density = TRUE
+ anchored = TRUE
var/list/slots[3]
var/list/datum/bottler_recipe/available_recipes
var/list/acceptable_items
var/list/containers = list("glass bottle" = 10, "plastic bottle" = 20, "metal can" = 25)
- var/bottling = 0
+ var/bottling = FALSE
/obj/machinery/bottler/Initialize(mapload)
. = ..()
@@ -270,7 +270,7 @@
containers[con_type]--
//select and process a recipe based on inserted ingredients
visible_message("[src] hums as it processes the ingredients...")
- bottling = 1
+ bottling = TRUE
var/datum/bottler_recipe/recipe_to_use = select_recipe()
if(!recipe_to_use)
//bad recipe, ruins the drink
@@ -288,7 +288,7 @@
flick("bottler_on", src)
spawn(45)
resetSlots()
- bottling = 0
+ bottling = FALSE
drink_container.forceMove(loc)
updateUsrDialog()
diff --git a/code/modules/food_and_drinks/drinks/drinks/bottle.dm b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
index 6811188cae2..0ebb8bcfd75 100644
--- a/code/modules/food_and_drinks/drinks/drinks/bottle.dm
+++ b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
@@ -99,8 +99,8 @@
head_attack_message = " on the head"
//Weaken the target for the duration that we calculated and divide it by 5.
if(armor_duration)
- var/stun_time = (min(armor_duration, 10)) STATUS_EFFECT_CONSTANT
- target.Weaken(stun_time)
+ var/knockdown_time = (min(armor_duration, 10)) STATUS_EFFECT_CONSTANT
+ target.KnockDown(knockdown_time)
//Display an attack message.
if(target != user)
@@ -152,7 +152,7 @@
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("stabbed", "slashed", "attacked")
var/icon/broken_outline = icon('icons/obj/drinks.dmi', "broken")
- sharp = 1
+ sharp = TRUE
/obj/item/broken_bottle/decompile_act(obj/item/matter_decompiler/C, mob/user)
C.stored_comms["glass"] += 3
@@ -332,7 +332,7 @@
list_reagents = list()
var/list/accelerants = list(/datum/reagent/consumable/ethanol,/datum/reagent/fuel,/datum/reagent/clf3,/datum/reagent/phlogiston,
/datum/reagent/napalm,/datum/reagent/hellwater,/datum/reagent/plasma,/datum/reagent/plasma_dust)
- var/active = 0
+ var/active = FALSE
/obj/item/reagent_containers/food/drinks/bottle/molotov/CheckParts(list/parts_list)
..()
@@ -358,7 +358,7 @@
/obj/item/reagent_containers/food/drinks/bottle/molotov/attackby(obj/item/I, mob/user, params)
if(is_hot(I) && !active)
- active = 1
+ active = TRUE
var/turf/bombturf = get_turf(src)
var/area/bombarea = get_area(bombturf)
message_admins("[key_name(user)][ADMIN_QUE(user,"?")] has primed a [name] for detonation at [bombarea] (JMP).")
@@ -388,4 +388,4 @@
return
to_chat(user, "You snuff out the flame on \the [src].")
overlays -= GLOB.fire_overlay
- active = 0
+ active = FALSE
diff --git a/code/modules/food_and_drinks/food/foods/pizza.dm b/code/modules/food_and_drinks/food/foods/pizza.dm
index 8272db8fe3b..cdd8dfe3e64 100644
--- a/code/modules/food_and_drinks/food/foods/pizza.dm
+++ b/code/modules/food_and_drinks/food/foods/pizza.dm
@@ -119,8 +119,8 @@
icon = 'icons/obj/food/pizza.dmi'
icon_state = "pizzabox1"
- var/open = 0 // Is the box open?
- var/ismessy = 0 // Fancy mess on the lid
+ var/open = FALSE // Is the box open?
+ var/ismessy = FALSE // Fancy mess on the lid
var/obj/item/reagent_containers/food/snacks/sliceable/pizza/pizza // Content pizza
var/list/boxes = list() // If the boxes are stacked, they come here
var/boxtag = ""
@@ -196,7 +196,7 @@
return
open = !open
if(open && pizza)
- ismessy = 1
+ ismessy = TRUE
update_icon()
/obj/item/pizzabox/attackby(obj/item/I, mob/user, params)
diff --git a/code/modules/food_and_drinks/food/snacks.dm b/code/modules/food_and_drinks/food/snacks.dm
index e5276f6c632..407f944f4a2 100644
--- a/code/modules/food_and_drinks/food/snacks.dm
+++ b/code/modules/food_and_drinks/food/snacks.dm
@@ -9,10 +9,8 @@
var/trash = null
var/slice_path
var/slices_num
- var/eatverb
- var/wrapped = 0
var/dried_type = null
- var/dry = 0
+ var/dry = FALSE
var/cooktype[0]
var/cooked_type = null //for microwave cooking. path of the resulting item after microwaving
var/total_w_class = 0 //for the total weight an item of food can carry
diff --git a/code/modules/food_and_drinks/kitchen_machinery/cooker.dm b/code/modules/food_and_drinks/kitchen_machinery/cooker.dm
index d950737b07d..263087f5910 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/cooker.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/cooker.dm
@@ -2,21 +2,24 @@
name = "cooker"
desc = "You shouldn't be seeing this!"
layer = 2.9
- density = 1
- anchored = 1
+ density = TRUE
+ anchored = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 5
- var/on = 0
+ var/on = FALSE
var/onicon = null
var/officon = null
var/openicon = null
var/thiscooktype = null
- var/burns = 0 // whether a machine burns something - if it does, you probably want to add the cooktype to /snacks/badrecipe
+ /// whether a machine burns something - if it does, you probably want to add the cooktype to /snacks/badrecipe
+ var/burns = FALSE
var/firechance = 0
var/cooktime = 0
var/foodcolor = null
- var/has_specials = 0 //Set to 1 if the machine has specials to check, otherwise leave it at 0
- var/upgradeable = 0 //Set to 1 if the machine supports upgrades / deconstruction, or else it will ignore stuff like screwdrivers and parts exchangers
+ ///Set to TRUE if the machine has specials to check, otherwise leave it at FALSE
+ var/has_specials = FALSE
+ ///Set to TRUE if the machine supports upgrades / deconstruction, or else it will ignore stuff like screwdrivers and parts exchangers
+ var/upgradeable = FALSE
// checks if the snack has been cooked in a certain way
/obj/machinery/cooker/proc/checkCooked(obj/item/reagent_containers/food/snacks/D)
@@ -57,12 +60,12 @@
/obj/machinery/cooker/proc/turnoff(obj/item/olditem)
icon_state = officon
playsound(loc, 'sound/machines/ding.ogg', 50, 1)
- on = 0
+ on = FALSE
qdel(olditem)
return
// Burns the food with a chance of starting a fire - for if you try cooking something that's already been cooked that way
-// if burns = 0 then it'll just tell you that the item is already that foodtype and it would do nothing
+// if burns = FALSE then it'll just tell you that the item is already that foodtype and it would do nothing
// if you wanted a different side effect set burns to 1 and override burn_food()
/obj/machinery/cooker/proc/burn_food(mob/user, obj/item/reagent_containers/props)
var/obj/item/reagent_containers/food/snacks/badrecipe/burnt = new(get_turf(src))
@@ -87,7 +90,7 @@
/obj/machinery/cooker/proc/putIn(obj/item/tocook, mob/chef)
icon_state = onicon
to_chat(chef, "You put [tocook] into [src].")
- on = 1
+ on = TRUE
chef.drop_item()
tocook.loc = src
diff --git a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
index 009f6da4a90..681ddb591a2 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
@@ -4,15 +4,15 @@
icon = 'icons/obj/cooking_machines.dmi'
icon_state = "fryer_off"
thiscooktype = "deep fried"
- burns = 1
+ burns = TRUE
firechance = 100
cooktime = 200
foodcolor = "#FFAD33"
officon = "fryer_off"
onicon = "fryer_on"
openicon = "fryer_open"
- has_specials = 1
- upgradeable = 1
+ has_specials = TRUE
+ upgradeable = TRUE
/obj/machinery/cooker/deepfryer/Initialize(mapload)
. = ..()
diff --git a/code/modules/food_and_drinks/kitchen_machinery/food_grill.dm b/code/modules/food_and_drinks/kitchen_machinery/food_grill.dm
index f68f8c31baf..2686931c625 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/food_grill.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/food_grill.dm
@@ -4,7 +4,7 @@
icon = 'icons/obj/cooking_machines.dmi'
icon_state = "grill_off"
thiscooktype = "grilled"
- burns = 1
+ burns = TRUE
firechance = 20
cooktime = 50
foodcolor = "#A34719"
diff --git a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
index 44ecf07aa02..8467bb05abd 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
@@ -4,12 +4,12 @@
desc = "The name isn't descriptive enough?"
icon = 'icons/obj/kitchen.dmi'
icon_state = "grinder"
- density = 1
- anchored = 1
- var/operating = 0 //Is it on?
- var/dirty = 0 // Does it need cleaning?
+ density = TRUE
+ anchored = TRUE
+ var/operating = FALSE //Is it on?
+ var/dirty = FALSE // Does it need cleaning?
var/mob/living/occupant // Mob who has been put inside
- var/locked = 0 //Used to prevent mobs from breaking the feedin anim
+ var/locked = FALSE //Used to prevent mobs from breaking the feedin anim
var/gib_throw_dir = WEST // Direction to spit meat and gibs in. Defaults to west.
@@ -186,7 +186,7 @@
if(!occupant)
return
- locked = 1 //lock gibber
+ locked = TRUE //lock gibber
var/image/gibberoverlay = new //used to simulate 3D effects
gibberoverlay.icon = icon
@@ -204,14 +204,14 @@
holder.pixel_x = 2
holder.loc = get_turf(src)
holder.layer = MOB_LAYER //simulate mob-like layering
- holder.anchored = 1
+ holder.anchored = TRUE
var/atom/movable/holder2 = new //holder for gibber overlay, used to simulate 3D effect
holder2.name = null
holder2.overlays += gibberoverlay
holder2.loc = get_turf(src)
holder2.layer = MOB_LAYER + 0.1 //3D, it's above the mob, rest of the gibber is behind
- holder2.anchored = 1
+ holder2.anchored = TRUE
animate(holder, pixel_y = 16, time = animation_delay) //animate going down
@@ -226,7 +226,7 @@
qdel(holder) //get rid of holder object
qdel(holder2) //get rid of holder object
- locked = 0 //unlock
+ locked = FALSE //unlock
/obj/machinery/gibber/proc/startgibbing(mob/user, UserOverride=0)
if(!istype(user) && !UserOverride)
@@ -247,7 +247,7 @@
use_power(1000)
visible_message("You hear a loud squelchy grinding sound.")
- operating = 1
+ operating = TRUE
update_icon()
var/offset = prob(50) ? -2 : 2
animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = gibtime * 5) //start shaking
@@ -309,7 +309,7 @@
sleep(1)
pixel_x = initial(pixel_x) //return to it's spot after shaking
- operating = 0
+ operating = FALSE
update_icon()
@@ -359,11 +359,11 @@
for(var/mob/living/carbon/H in victim_targets)
if(H.loc == lturf) //still standing there
if(force_move_into_gibber(H))
- locked = 1 // no escape
+ locked = TRUE // no escape
ejectclothes(occupant)
cleanbay()
startgibbing(null, 1)
- locked = 0
+ locked = FALSE
break
victim_targets.Cut()
diff --git a/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm b/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm
index 6fdd29213ef..373ec42e852 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/icecream_vat.dm
@@ -3,8 +3,8 @@
/obj/machinery/icemachine
name = "\improper Cream-Master Deluxe"
- density = 1
- anchored = 1
+ density = TRUE
+ anchored = TRUE
icon = 'icons/obj/cooking_machines.dmi'
icon_state = "icecream_vat"
use_power = IDLE_POWER_USE
diff --git a/code/modules/food_and_drinks/kitchen_machinery/juicer.dm b/code/modules/food_and_drinks/kitchen_machinery/juicer.dm
index 393687fce5a..b17b2cfe0f0 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/juicer.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/juicer.dm
@@ -4,8 +4,8 @@
icon = 'icons/obj/kitchen.dmi'
icon_state = "juicer1"
layer = 2.9
- density = 1
- anchored = 0
+ density = TRUE
+ anchored = FALSE
use_power = IDLE_POWER_USE
idle_power_usage = 5
active_power_usage = 100
diff --git a/code/modules/food_and_drinks/kitchen_machinery/kitchen_machine.dm b/code/modules/food_and_drinks/kitchen_machinery/kitchen_machine.dm
index 46c8311be98..4ee485302db 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/kitchen_machine.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/kitchen_machine.dm
@@ -3,13 +3,13 @@
name = "Base Kitchen Machine"
desc = "If you are seeing this, a coder/mapper messed up. Please report it."
layer = 2.9
- density = 1
- anchored = 1
+ density = TRUE
+ anchored = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 5
active_power_usage = 100
container_type = OPENCONTAINER
- var/operating = 0 // Is it on?
+ var/operating = FALSE // Is it on?
var/dirty = 0 // = {0..100} Does it need cleaning?
var/broken = 0 // ={0,1,2} How broken is it???
var/efficiency = 0
@@ -70,11 +70,11 @@
if(!broken && istype(O, /obj/item/wrench))
playsound(src, O.usesound, 50, 1)
if(anchored)
- anchored = 0
+ anchored = FALSE
to_chat(user, "\The [src] can now be moved.")
return
else if(!anchored)
- anchored = 1
+ anchored = TRUE
to_chat(user, "\The [src] is now secured.")
return
@@ -361,18 +361,18 @@
/obj/machinery/kitchen_machine/proc/start()
visible_message("\The [src] turns on.", "You hear \a [src].")
- operating = 1
+ operating = TRUE
icon_state = on_icon
updateUsrDialog()
/obj/machinery/kitchen_machine/proc/abort()
- operating = 0 // Turn it off again aferwards
+ operating = FALSE // Turn it off again aferwards
icon_state = off_icon
updateUsrDialog()
/obj/machinery/kitchen_machine/proc/stop()
playsound(loc, 'sound/machines/ding.ogg', 50, 1)
- operating = 0 // Turn it off again aferwards
+ operating = FALSE // Turn it off again aferwards
icon_state = off_icon
updateUsrDialog()
@@ -395,7 +395,7 @@
dirty = 100 // Make it dirty so it can't be used util cleaned
flags = null //So you can't add condiments
icon_state = dirty_icon // Make it look dirty too
- operating = 0 // Turn it off again aferwards
+ operating = FALSE // Turn it off again aferwards
updateUsrDialog()
/obj/machinery/kitchen_machine/proc/broke()
@@ -404,7 +404,7 @@
visible_message("[src] breaks!") //Let them know they're stupid
broken = 2 // Make it broken so it can't be used util fixed
flags = null //So you can't add condiments
- operating = 0 // Turn it off again aferwards
+ operating = FALSE // Turn it off again aferwards
updateUsrDialog()
/obj/machinery/kitchen_machine/proc/fail()
diff --git a/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm b/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm
index 746b7b75d2a..35a1d2e5c04 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm
@@ -6,8 +6,8 @@ GLOBAL_LIST_EMPTY(monkey_recyclers)
icon = 'icons/obj/kitchen.dmi'
icon_state = "grinder"
layer = 2.9
- density = 1
- anchored = 1
+ density = TRUE
+ anchored = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 5
active_power_usage = 50
diff --git a/code/modules/food_and_drinks/kitchen_machinery/oven.dm b/code/modules/food_and_drinks/kitchen_machinery/oven.dm
index 2b2b9cb1e5b..4d24f62288d 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/oven.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/oven.dm
@@ -4,10 +4,10 @@
icon = 'icons/obj/cooking_machines.dmi'
icon_state = "oven_off"
layer = 2.9
- density = 1
- anchored = 1
+ density = TRUE
+ anchored = TRUE
use_power = IDLE_POWER_USE
- var/candy = 0
+ var/candy = FALSE
idle_power_usage = 5
var/on = FALSE //Is it making food already?
var/list/food_choices = list()
@@ -69,7 +69,7 @@
desc = "Get yer box of deep fried deep fried deep fried deep fried cotton candy cereal sandwich cookies here!"
icon = 'icons/obj/cooking_machines.dmi'
icon_state = "mixer_off"
- candy = 1
+ candy = TRUE
/obj/machinery/cooking/candy/updatefood()
for(var/U in food_choices)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/processor.dm b/code/modules/food_and_drinks/kitchen_machinery/processor.dm
index e44a7588e68..a6324e8aaa8 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/processor.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/processor.dm
@@ -3,11 +3,11 @@
icon = 'icons/obj/kitchen.dmi'
icon_state = "processor"
layer = 2.9
- density = 1
- anchored = 1
+ density = TRUE
+ anchored = TRUE
var/broken = 0
- var/processing = 0
+ var/processing = FALSE
use_power = IDLE_POWER_USE
idle_power_usage = 5
@@ -208,7 +208,7 @@
if(contents.len == 0)
to_chat(user, "\the [src] is empty.")
return 1
- processing = 1
+ processing = TRUE
user.visible_message("[user] turns on [src].", \
"You turn on [src].", \
"You hear a food processor.")
@@ -229,7 +229,7 @@
log_debug("The [O] in processor([src]) does not have a suitable recipe, but it was somehow put inside of the processor anyways.")
continue
P.process_food(loc, O, src)
- processing = 0
+ processing = FALSE
visible_message("\the [src] has finished processing.", \
"\the [src] has finished processing.", \
diff --git a/code/modules/games/cards.dm b/code/modules/games/cards.dm
index e8b08ccb402..18b564e94b1 100644
--- a/code/modules/games/cards.dm
+++ b/code/modules/games/cards.dm
@@ -34,7 +34,7 @@
throwforce = 0
force = 0
/// Inherited card hit sound
- var/card_hitsound
+ var/card_hitsound
/// Inherited card force
var/card_force = 0
/// Inherited card throw force
@@ -313,7 +313,7 @@
var/concealed = FALSE
var/list/cards = list()
/// Tracked direction, which is used when updating the hand's appearance instead of messing with the local dir
- var/direction = NORTH
+ var/direction = NORTH
var/parentdeck = null
/// The player's picked card they want to take out. Stored in the hand so it can be passed onto the verb
var/pickedcard = null
@@ -567,7 +567,10 @@
/obj/item/cardhand/dropped(mob/user)
..()
- direction = user.dir
+ if(user)
+ direction = user.dir
+ else
+ direction = NORTH
update_icon()
/obj/item/cardhand/pickup(mob/user as mob)
diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm
index ae70c38f491..e3b74b34ce0 100644
--- a/code/modules/hydroponics/biogenerator.dm
+++ b/code/modules/hydroponics/biogenerator.dm
@@ -3,11 +3,11 @@
desc = "Converts plants into biomass, which can be used to construct useful items."
icon = 'icons/obj/biogenerator.dmi'
icon_state = "biogen-empty"
- density = 1
- anchored = 1
+ density = TRUE
+ anchored = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 40
- var/processing = 0
+ var/processing = FALSE
var/obj/item/reagent_containers/glass/beaker = null
var/points = 0
var/menustat = "menu"
@@ -149,11 +149,11 @@
user.visible_message("[user] begins to load [O] in [src]...",
"You begin to load a design from [O]...",
"You hear the chatter of a floppy drive.")
- processing = 1
+ processing = TRUE
var/obj/item/disk/design_disk/D = O
if(do_after(user, 10, target = src))
files.AddDesign2Known(D.blueprint)
- processing = 0
+ processing = FALSE
return 1
else
to_chat(user, "You cannot put this in [name]!")
@@ -235,13 +235,13 @@
points += (I.reagents.get_reagent_amount("nutriment")+I.reagents.get_reagent_amount("plantmatter"))*10*productivity
qdel(I)
if(S)
- processing = 1
+ processing = TRUE
update_icon()
updateUsrDialog()
playsound(loc, 'sound/machines/blender.ogg', 50, 1)
use_power(S*30)
sleep(S+15/productivity)
- processing = 0
+ processing = FALSE
update_icon()
else
menustat = "void"
diff --git a/code/modules/hydroponics/gene_modder.dm b/code/modules/hydroponics/gene_modder.dm
index 0bd392a73c0..664834d67dc 100644
--- a/code/modules/hydroponics/gene_modder.dm
+++ b/code/modules/hydroponics/gene_modder.dm
@@ -4,8 +4,8 @@
icon = 'icons/obj/hydroponics/equipment.dmi'
pass_flags = PASSTABLE
icon_state = "dnamod"
- density = 1
- anchored = 1
+ density = TRUE
+ anchored = TRUE
var/obj/item/seeds/seed
var/obj/item/disk/plantgene/disk
diff --git a/code/modules/hydroponics/hydroitemdefines.dm b/code/modules/hydroponics/hydroitemdefines.dm
index 2f323b426d4..2c6e24b6f75 100644
--- a/code/modules/hydroponics/hydroitemdefines.dm
+++ b/code/modules/hydroponics/hydroitemdefines.dm
@@ -95,7 +95,7 @@
origin_tech = "materials=2;combat=2"
attack_verb = list("chopped", "torn", "cut")
hitsound = 'sound/weapons/bladeslice.ogg'
- sharp = 1
+ sharp = TRUE
/obj/item/hatchet/suicide_act(mob/user)
user.visible_message("[user] is chopping at [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide.")
@@ -129,7 +129,7 @@
origin_tech = "materials=3;combat=2"
attack_verb = list("chopped", "sliced", "cut", "reaped")
hitsound = 'sound/weapons/bladeslice.ogg'
- sharp = 1
+ sharp = TRUE
var/extend = 1
var/swiping = FALSE
@@ -172,7 +172,7 @@
icon_state = "tscythe0"
item_state = null //no sprite for folded version, like a tele-baton
force = 3
- sharp = 0
+ sharp = FALSE
w_class = WEIGHT_CLASS_SMALL
extend = 0
slot_flags = SLOT_BELT
diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm
index 4ff8c6b7039..3895f27f6f9 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -2,8 +2,8 @@
name = "hydroponics tray"
icon = 'icons/obj/hydroponics/equipment.dmi'
icon_state = "hydrotray"
- density = 1
- anchored = 1
+ density = TRUE
+ anchored = TRUE
pixel_y = 8
var/waterlevel = 100 //The amount of water in the tray (max 100)
var/maxwater = 100 //The maximum amount of water in the tray
@@ -15,15 +15,15 @@
var/mutmod = 1 //Nutriment's effect on mutations
var/toxic = 0 //Toxicity in the tray?
var/age = 0 //Current age
- var/dead = 0 //Is it dead?
+ var/dead = FALSE //Is it dead?
var/plant_health //Its health
var/lastproduce = 0 //Last time it was harvested
var/lastcycle = 0 //Used for timing of cycles.
var/cycledelay = 200 //About 10 seconds / cycle
- var/harvest = 0 //Ready to harvest?
+ var/harvest = FALSE //Ready to harvest?
var/obj/item/seeds/myseed = null //The currently planted seed
var/rating = 1
- var/wrenchable = 1
+ var/wrenchable = TRUE
var/lid_state = 0
var/recent_bee_visit = FALSE //Have we been visited by a bee recently, so bees dont overpollinate one plant
var/using_irrigation = FALSE //If the tray is connected to other trays via irrigation hoses
@@ -234,7 +234,7 @@
if(age > myseed.production && (age - lastproduce) > myseed.production && (!harvest && !dead))
nutrimentMutation()
if(myseed && myseed.yield != -1) // Unharvestable shouldn't be harvested
- harvest = 1
+ harvest = TRUE
plant_hud_set_status()
else
lastproduce = age
@@ -374,7 +374,7 @@
/obj/machinery/hydroponics/proc/weedinvasion() // If a weed growth is sufficient, this happens.
- dead = 0
+ dead = FALSE
var/oldPlantName
if(myseed) // In case there's nothing in the tray beforehand
oldPlantName = myseed.plantname
@@ -401,7 +401,7 @@
age = 0
plant_health = myseed.endurance
lastcycle = world.time
- harvest = 0
+ harvest = FALSE
adjustWeeds(-10) // Reset
adjustPests(-10) // Reset
update_icon()
@@ -435,7 +435,7 @@
age = 0
plant_health = myseed.endurance
lastcycle = world.time
- harvest = 0
+ harvest = FALSE
plant_hud_set_health()
plant_hud_set_status()
adjustWeeds(-10) // Reset
@@ -450,12 +450,12 @@
QDEL_NULL(myseed)
var/newWeed = pick(/obj/item/seeds/liberty, /obj/item/seeds/angel, /obj/item/seeds/nettle/death, /obj/item/seeds/kudzu)
myseed = new newWeed
- dead = 0
+ dead = FALSE
hardmutate()
age = 0
plant_health = myseed.endurance
lastcycle = world.time
- harvest = 0
+ harvest = FALSE
plant_hud_set_health()
plant_hud_set_status()
adjustWeeds(-10) // Reset
@@ -469,11 +469,11 @@
/obj/machinery/hydroponics/proc/plantdies() // OH NOES!!!!! I put this all in one function to make things easier
plant_health = 0
- harvest = 0
+ harvest = FALSE
adjustPests(-10) // Pests die
if(!dead)
update_icon()
- dead = 1
+ dead = TRUE
plant_hud_set_health()
plant_hud_set_status()
@@ -813,7 +813,7 @@
investigate_log("had Kudzu planted in it by [key_name(user)] at ([x],[y],[z])","kudzu")
user.unEquip(O)
to_chat(user, "You plant [O].")
- dead = 0
+ dead = FALSE
myseed = O
age = 1
plant_health = myseed.endurance
@@ -930,7 +930,7 @@
if(harvest)
myseed.harvest(user)
else if(dead)
- dead = 0
+ dead = FALSE
to_chat(user, "You remove the dead plant from [src].")
QDEL_NULL(myseed)
update_icon()
@@ -940,7 +940,7 @@
examine(user)
/obj/machinery/hydroponics/proc/update_tray(mob/user = usr)
- harvest = 0
+ harvest = FALSE
lastproduce = age
if(istype(myseed,/obj/item/seeds/replicapod))
to_chat(user, "You harvest from the [myseed.plantname].")
@@ -950,7 +950,7 @@
to_chat(user, "You harvest [myseed.getYield()] items from the [myseed.plantname].")
if(!myseed.get_gene(/datum/plant_gene/trait/repeated_harvest))
QDEL_NULL(myseed)
- dead = 0
+ dead = FALSE
plant_hud_set_status()
plant_hud_set_health()
update_icon()
@@ -1024,9 +1024,9 @@
name = "soil"
icon = 'icons/obj/hydroponics/equipment.dmi'
icon_state = "soil"
- density = 0
+ density = FALSE
use_power = NO_POWER_USE
- wrenchable = 0
+ wrenchable = FALSE
/obj/machinery/hydroponics/soil/update_icon_hoses()
return // Has no hoses
diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm
index 777dbe08a6a..2611669b0f7 100644
--- a/code/modules/hydroponics/plant_genes.dm
+++ b/code/modules/hydroponics/plant_genes.dm
@@ -307,10 +307,12 @@
/datum/plant_gene/trait/teleport/on_squash(obj/item/reagent_containers/food/snacks/grown/G, atom/target)
if(isliving(target))
+ var/mob/living/L = target
var/teleport_radius = max(round(G.seed.potency / 10), 1)
- var/turf/T = get_turf(target)
+ var/turf/T = get_turf(L)
new /obj/effect/decal/cleanable/molten_object(T) //Leave a pile of goo behind for dramatic effect...
- do_teleport(target, T, teleport_radius)
+ do_teleport(L, T, teleport_radius)
+ L.apply_status_effect(STATUS_EFFECT_TELEPORTSICK)
/datum/plant_gene/trait/teleport/on_slip(obj/item/reagent_containers/food/snacks/grown/G, mob/living/carbon/C)
var/teleport_radius = max(round(G.seed.potency / 10), 1)
@@ -319,6 +321,7 @@
to_chat(C, "You slip through spacetime!")
if(prob(50))
do_teleport(G, T, teleport_radius)
+ C.apply_status_effect(STATUS_EFFECT_TELEPORTSICK)
else
new /obj/effect/decal/cleanable/molten_object(T) //Leave a pile of goo behind for dramatic effect...
qdel(G)
diff --git a/code/modules/hydroponics/seed_extractor.dm b/code/modules/hydroponics/seed_extractor.dm
index 6fa5c0cfb84..b0c92099985 100644
--- a/code/modules/hydroponics/seed_extractor.dm
+++ b/code/modules/hydroponics/seed_extractor.dm
@@ -42,8 +42,8 @@
desc = "Extracts and bags seeds from produce."
icon = 'icons/obj/hydroponics/equipment.dmi'
icon_state = "sextractor"
- density = 1
- anchored = 1
+ density = TRUE
+ anchored = TRUE
var/list/piles = list()
var/max_seeds = 1000
var/seed_multiplier = 1
diff --git a/code/modules/library/admin.dm b/code/modules/library/admin.dm
deleted file mode 100644
index 2f1c1e101fc..00000000000
--- a/code/modules/library/admin.dm
+++ /dev/null
@@ -1,64 +0,0 @@
-/client/proc/delbook()
- set name = "Delete Book"
- set desc = "Permamently deletes a book from the database."
- set category = "Admin"
-
- if(!check_rights(R_ADMIN))
- return
-
- var/isbn = input("ISBN number?", "Delete Book") as num | null
- if(!isbn)
- return
-
- var/datum/db_query/query_delbook = SSdbcore.NewQuery("DELETE FROM library WHERE id=:isbn", list(
- "isbn" = text2num(isbn) // just to be sure
- ))
- if(!query_delbook.warn_execute())
- qdel(query_delbook)
- return
-
- qdel(query_delbook)
- log_admin("[key_name(usr)] has deleted the book [isbn].")
- message_admins("[key_name_admin(usr)] has deleted the book [isbn].")
-
-/client/proc/view_flagged_books()
- set name = "View Flagged Books"
- set desc = "View books flagged for content."
- set category = "Admin"
-
- if(!check_rights(R_ADMIN))
- return
-
- holder.view_flagged_books()
-
-/datum/admins/proc/view_flagged_books()
- if(!usr.client.holder)
- return
-
- var/dat = "
ISBN
Title
Total Flags
Options
"
-
- var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, title, flagged FROM library WHERE flagged > 0 ORDER BY flagged DESC")
- if(!query.warn_execute())
- qdel(query)
- return
-
- var/books = 0
- while(query.NextRow())
- books++
- var/isbn = query.item[1]
- dat += "
"
-
- var/datum/browser/popup = new(usr, "admin_view_flagged_books", "Flagged Books", 700, 400)
- popup.set_content(dat)
- popup.open(0)
-
diff --git a/code/modules/library/book.dm b/code/modules/library/book.dm
new file mode 100644
index 00000000000..e92653d0e36
--- /dev/null
+++ b/code/modules/library/book.dm
@@ -0,0 +1,377 @@
+///Max Writeable Content Pages per book, players really don't need more than this
+#define MAX_PAGES 5
+
+/**
+ * # Standard Book
+ *
+ * Game Object which stores pages of text usually written by players, has other editable information such as the book's
+ * title, author, summary, and categories. Has other values that are generated when books are acquired through the library
+ * computer.
+ *
+ * Like other User Interfaces that heavily rely on player input, using newer tools such as TGUI presents sanitization issues
+ * so books will remain using BrowserUI until further notice.
+ */
+/obj/item/book
+ name = "book"
+ icon = 'icons/obj/library.dmi'
+ icon_state = "book"
+ throw_speed = 1
+ throw_range = 5
+ force = 2
+ w_class = WEIGHT_CLASS_NORMAL
+ attack_verb = list("bashed", "whacked")
+ resistance_flags = FLAMMABLE
+ drop_sound = 'sound/items/handling/book_drop.ogg'
+ pickup_sound = 'sound/items/handling/book_pickup.ogg'
+
+ ///Title & Real name of the book
+ var/title
+ ///Who wrote the book, can be changed by pen or PC
+ var/author
+ ///Short summary of the contents of the book, can be changed by pen or PC
+ var/summary
+ ///Book Rating - Assigned by library computer based on how many/how players have rated this book
+ var/rating
+ ///Book Categories - used for differentiating types of books, set by players upon upload, viewable upon examining book
+ var/categories = list()
+ ///The background color of the book, useful for themed programmatic books, must be in #FFFFFF hex color format
+ var/book_bgcolor = "#FFF2E5"
+ ///Content Pages of the books, this variable is a list of strings containting the HTML + Text of each page
+ var/pages = list()
+ ///What page is the book currently opened to? Page 0 - Intro Page | Page 1-5 - Content Pages
+ var/current_page = 0
+
+ ///Book UI Popup Height
+ var/book_height = 400
+ ///Book UI Popup Width
+ var/book_width = 400
+ ///Prevents book from being uploaded - For all printed books
+ var/copyright = FALSE
+ ///Prevents book contents from being edited
+ var/protected = FALSE
+ ///Book's id within the library system, unique to each book object, should not be declared manually
+ var/libraryid
+ ///Indicates whether or not a books pages have been carved out
+ var/carved = FALSE
+ ///Item that is stored inside the book
+ var/obj/item/store
+
+/obj/item/book/Initialize(mapload, datum/cachedbook/CB, _copyright = FALSE, _protected = FALSE)
+ . = ..()
+ if(!CB)
+ return
+ author = CB.author
+ title = CB.title
+ pages = CB.content
+ summary = CB.summary
+ categories = CB.categories
+ copyright = _copyright
+ protected = _protected
+ rating = CB.rating
+ name = "Book: [CB.title]"
+ icon_state = "book[rand(1,8)]"
+
+
+/obj/item/book/attack(mob/M, mob/living/user)
+ if(user.a_intent == INTENT_HELP)
+ force = 0
+ attack_verb = list("educated")
+ else
+ force = initial(force)
+ attack_verb = list("bashed", "whacked")
+ ..()
+
+/obj/item/book/attack_self(mob/user)
+ if(carved)
+ //Attempt to remove inserted object, if none found, remind user that someone vandalized their book (Bastards)!
+ if(!remove_stored_item(user, TRUE))
+ to_chat(user, "The pages of [title] have been cut out!")
+ return
+ user.visible_message("[user] opens a book titled \"[title]\" and begins reading intently.")
+ read_book(user)
+
+/obj/item/book/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/pen))
+ edit_book(user)
+ else if(istype(I, /obj/item/barcodescanner))
+ var/obj/item/barcodescanner/scanner = I
+ scanner.scanBook(src, user) //abstraction and proper scoping ftw | did you know barcode scanner code used to be here?
+ return
+ else if(I.sharp && !carved) //don't use sharp objects on your books if you don't want to carve out all of its pages kids!
+ carve_book(user, I)
+ else if(store_item(I, user))
+ return
+ else
+ ..()
+
+/obj/item/book/examine(mob/user)
+ . = ..()
+ if(isobserver(user))
+ read_book(user)
+
+/**
+ * Internal Checker Proc
+ *
+ * Gives free pass to observers to read, ensures that all other mobs attempting to read book are A) literated and
+ * B) are within range to actually read the book.
+ */
+/obj/item/book/proc/can_read(mob/user)
+ if(isobserver(user)) //We check this first because ghosts should be able to read any book they can see no matter what
+ return TRUE
+ if(!in_range(src, user))
+ return FALSE
+ if(!user.is_literate()) //this person was 2 cool 4 school and cannot READ
+ to_chat(user, "You attempt to the read the book but remember that you don't actually know how to read.")
+ return FALSE
+ return TRUE
+
+/**
+ * Read Book Proc
+ *
+ * Checks if players is able to read book and that book is readable before calling the neccesary procs to open up UI
+ */
+/obj/item/book/proc/read_book(mob/user)
+ if(!length(pages)) //You can't read a book with no pages in it
+ to_chat(user, "This book is completely blank!")
+ return
+ if(!can_read(user))
+ return
+
+ show_content(user) //where all the magic happens
+ onclose(user, "book")
+
+/**
+ * Show Content Proc
+ *
+ * Builds the browserUI html to show to the player then open up the User interface. It first build the header navigation
+ * buttons and then builds the rest of the UI based on what page the player is turned to.
+ */
+/obj/item/book/proc/show_content(mob/user)
+ var/dat = ""
+ //First, we're going to choose/generate our header buttons for switching pages and store it in var/dat
+ var/header_left = ""
+ var/header_right = ""
+ if(length(pages)) //No need to have page switching buttons if there's no pages
+ if(current_page < length(pages))
+ header_right = "
"
+
+ dat += header_left + header_right
+ //Now we're going to display the header buttons + the current page selected, if it's page 0, we display the cover_page instead
+ if(!current_page)
+ var/cover_page = {"
[title]
Written by: [author]
Summary: [summary]"}
+ user << browse("[dat] " + "[cover_page]", "window=book[UID()];size=400x400")
+ return
+ else
+ user << browse("[dat] " + "[pages[current_page]]", "window=book[UID()]")
+
+/obj/item/book/Topic(href, href_list)
+ if(..())
+ return
+ if(href_list["next_page"])
+ if(current_page > length(pages)) //should never be false, but just in-case
+ current_page = length(pages)
+ return
+ current_page++
+ playsound(loc, "pageturn", 50, 1)
+ read_book(usr) //scuffed but this is how you update the UI
+ updateUsrDialog()
+ if(href_list["prev_page"])
+ if(current_page < 0) //should never be false, but just in-case
+ current_page = 0
+ return
+ current_page--
+ playsound(loc, "pageturn", 50, 1)
+ read_book(usr) //scuffed but this is how you update the UI
+ updateUsrDialog()
+
+/**
+ * Edit Book Proc
+ *
+ * This is where a lot of the magic happens, upon interacting with the book with a pen, this proc will open up options
+ * for the player to edit the book. Most importantly, this is where we account for player stupidity and maliciousness
+ * any input must strip/reject bad text and HTML from user input, additionally we account for players trying to screw
+ * with the Database. This will also limit the max characters players can upload at one time to prevent spamming.
+ */
+/obj/item/book/proc/edit_book(mob/user)
+ if(protected) //we don't want people touching "special" books, especially ones that use iframes
+ to_chat(user, "These pages don't seem to take the ink well. Looks like you can't modify it.")
+ return
+ var/choice = input(user, "What would you like to edit?") as null|anything in list("Title", "Edit Current Page", "Author", "Summary", "Add Page", "Remove Page")
+ switch(choice)
+ if("Title")
+ var/newtitle = reject_bad_text(stripped_input(user, "Write a new title:"))
+ if(!newtitle)
+ to_chat(user, "You change your mind.")
+ return
+ //Like with paper, the name (not title) of the book should indicate that THIS IS A BOOK when actions are performed with it
+ //this is to prevent players from naming it "Nuclear Authentification Disk" or "Energy Sword" to fuck with security
+ name = "Book: " + newtitle
+ title = newtitle
+ if("Author")
+ var/newauthor = stripped_input(user, "Write the author's name:")
+ if(!newauthor)
+ to_chat(user, "You change your mind.")
+ return
+ author = newauthor
+ if("Summary")
+ var/newsummary = strip_html(input(user, "Write the new summary:") as message|null, MAX_SUMMARY_LEN)
+ if(!newsummary)
+ to_chat(user, "You change your mind.")
+ return
+ summary = newsummary
+ if("Edit Current Page")
+ if(carved)
+ to_chat(user, "The pages of [title] have been cut out!")
+ return
+ if(!current_page)
+ to_chat(user, "You need to turn to a page before writing in the book.")
+ return
+ var/character_space_remaining = MAX_CHARACTERS_PER_BOOKPAGE - length(pages[current_page])
+ if(character_space_remaining <= 0)
+ to_chat(user, "There's not enough space left on this page to write anything!")
+ return
+ var/content = strip_html(input(user, "Add Text to this page, you have [character_space_remaining] characters of space left:") as message|null, MAX_CHARACTERS_PER_BOOKPAGE)
+ if(!content)
+ to_chat(user, "You change your mind.")
+ return
+ //check if length of current text content + what player is adding is larger than our character limit
+ else if((length(content) + length(pages[current_page])) > MAX_CHARACTERS_PER_BOOKPAGE)
+ //if true, let's cut down the text to fit perfectly into our character limit, player is only half-pissed!
+ pages[current_page] += dd_limittext(content, (MAX_CHARACTERS_PER_BOOKPAGE - length(pages[current_page])))
+ else
+ pages[current_page] += content
+ if("Add Page")
+ if(carved)
+ to_chat(user, "You can't add anymore pages, the pages of [title] have been cut out and the book is ruined!")
+ return
+ if(length(pages) >= MAX_PAGES)
+ to_chat(user, "You can't fit anymore pages in this book!")
+ return
+ to_chat(user, "You add another page to the book!")
+ pages += " "
+ if("Remove Page")
+ if(!length(pages))
+ to_chat(user, "There aren't any pages in this book!")
+ return
+ var/page_choice = stripped_input(user, "There are [length(pages)] pages, which page number would you like to remove?")
+ if(!page_choice)
+ to_chat(user, "You change your mind.")
+ return
+ if(!isnum(page_choice) || page_choice <= 0 || page_choice > length(pages))
+ to_chat(user, "That is not an acceptable value.= MAX_PAGES)
+ return FALSE
+ pages += text
+ current_page = length(pages) //open to newely added page so player can edit it
+ return TRUE
+
+/obj/item/book/proc/remove_page(page_number)
+ if(length(pages) < page_number) //can't remove the page if it doesn't exist
+ return FALSE
+ pages -= pages[page_number]
+ page_number = length(pages) //if page_number is somehow at a value it shouldn't be we fix it here aswell
+ return TRUE //we want to make sure whatever is calling this proc knows the operation was succesful
+
+/obj/item/book/proc/carve_book(mob/user, obj/item/I)
+ if(carved)
+ to_chat(user, "[title] has already been carved out!")
+ return
+ if(!I.sharp)
+ to_chat(user, "You can't carve [title] using that!")
+ return
+ to_chat(user, "You begin to carve out [title].")
+ if(I.use_tool(src, user, 30, volume = I.tool_volume))
+ user.visible_message("[user] appears to carve out the pages inside of [title]!",\
+ "You carve out [title]!")
+ carved = TRUE
+ return TRUE
+
+/obj/item/book/proc/store_item(obj/item/I, mob/user)
+ if(!carved)
+ return
+ if(store)
+ to_chat(user, "There is already something in [src]!")
+ return
+
+ //does it exist, if so is it an abstract item?
+ if(!istype(I) || (I.flags & ABSTRACT))
+ return
+ if(I.flags & NODROP)
+ to_chat(user, "[I] stays stuck to your hand when you try and hide it in the book!.")
+ return
+ //Checking to make sure the item we're storing isn't larger than/equal to size of the book, prevents recursive storing aswell
+ if(I.w_class >= w_class)
+ to_chat(user, "[I] is to large to fit in [src].")
+ return
+
+ user.drop_item()
+ I.forceMove(src)
+ RegisterSignal(I, COMSIG_PARENT_QDELETING, .proc/clear_stored_item) //ensure proper GC'ing
+ store = I
+ to_chat(user, "You hide [I] in [name].")
+ return TRUE
+
+///needed for proper GC'ing
+/obj/item/book/proc/clear_stored_item()
+ store = null
+
+/obj/item/book/proc/remove_stored_item(mob/user, display_message = TRUE)
+ if(!store)
+ if(display_message) //we don't wanna display this message in certain cases if there's not a user removing it
+ to_chat(user, "You search [name] but there is nothing in it!")
+ return FALSE
+ if(display_message)
+ to_chat(user, "You carefully remove [store] from [name]!")
+ store.forceMove(get_turf(store.loc))
+ clear_stored_item()
+ UnregisterSignal(store, COMSIG_PARENT_QDELETING)
+
+ return TRUE
+
+ //* Book Spawners n'stuff *//
+/obj/item/book/random
+ icon_state = "random_book"
+ var/amount = 1
+
+/obj/item/book/random/Initialize()
+ ..()
+ var/list/books = GLOB.library_catalog.get_random_book(amount)
+ for(var/datum/cachedbook/book as anything in books)
+ new /obj/item/book(loc, book, TRUE, FALSE)
+ return INITIALIZE_HINT_QDEL
+
+/obj/item/book/random/triple
+ amount = 3
+
+ //* Codex Gigas *//
+ //This book used to have its own dm file, due to devil code removal, it is now only a cosmetic item for the time being
+ //this will be its resting place until it is used for something else eventually.
+/obj/item/book/codex_gigas
+ name = "\improper Codex Gigas"
+ desc = "A book documenting the nature of devils, it seems whatever magic that once possessed this codex is long gone."
+ icon_state = "demonomicon"
+ throw_speed = 1
+ throw_range = 10
+ resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
+ author = "Forces beyond your comprehension"
+ protected = TRUE
+ title = "The codex gigas"
+ copyright = TRUE
+
+#undef MAX_PAGES
diff --git a/code/modules/library/codex_gigas.dm b/code/modules/library/codex_gigas.dm
deleted file mode 100644
index c1d03f3aed3..00000000000
--- a/code/modules/library/codex_gigas.dm
+++ /dev/null
@@ -1,11 +0,0 @@
-/obj/item/book/codex_gigas
- name = "\improper Codex Gigas"
- desc = "A book documenting the nature of devils."
- icon_state ="demonomicon"
- throw_speed = 1
- throw_range = 10
- resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
- author = "Forces beyond your comprehension"
- unique = TRUE
- title = "The codex gigas"
- has_drm = TRUE
diff --git a/code/modules/library/computers/base.dm b/code/modules/library/computers/base.dm
deleted file mode 100644
index c0f2d473afa..00000000000
--- a/code/modules/library/computers/base.dm
+++ /dev/null
@@ -1,110 +0,0 @@
-#define MAX_BOOK_FLAGS 3 // maximum number of times a book can be flagged before being removed from results
-
-/obj/machinery/computer/library
- name = "visitor computer"
- anchored = 1
- density = 1
- icon_keyboard = ""
- icon_screen = "computer_on"
- var/screenstate = 0
- var/page_num = 1
- var/num_pages = 0
- var/num_results = 0
- var/datum/library_query/query = new()
-
- icon = 'icons/obj/library.dmi'
- icon_state = "computer"
-
-/obj/machinery/computer/library/proc/interact_check(mob/user)
- if(stat & (BROKEN | NOPOWER))
- return 1
-
- if(!Adjacent(user))
- if(!issilicon(user) && !isobserver(user))
- user.unset_machine()
- user << browse(null, "window=library")
- return 1
-
- user.set_machine(src)
- return 0
-
-/obj/machinery/computer/library/proc/get_page(page_num)
- var/searchquery = ""
- var/where = 0
- var/list/sql_params = list()
- if(query)
- if(query.title && query.title != "")
- searchquery += " WHERE title LIKE :title"
- sql_params["title"] = "%[query.title]%"
- where = 1
- if(query.author && query.author != "")
- searchquery += " [!where ? "WHERE" : "AND"] author LIKE :author"
- sql_params["author"] = "%[query.author]%"
- where = 1
- if(query.category && query.category != "")
- searchquery += " [!where ? "WHERE" : "AND"] category LIKE :cat"
- sql_params["cat"] = "%[query.category]%"
- if(query.category == "Fiction")
- searchquery += " AND category NOT LIKE '%Non-Fiction%'"
- where = 1
-
- // This one doesnt take player input directly, so it doesnt require params
- searchquery += " [!where ? "WHERE" : "AND"] flagged < [MAX_BOOK_FLAGS]"
- // This does though
- var/sql = "SELECT id, author, title, category, ckey, flagged FROM library [searchquery] LIMIT :lowerlimit, :upperlimit"
- sql_params["lowerlimit"] = text2num((page_num - 1) * LIBRARY_BOOKS_PER_PAGE)
- sql_params["upperlimit"] = LIBRARY_BOOKS_PER_PAGE
-
- // Pagination
- var/datum/db_query/select_query = SSdbcore.NewQuery(sql, sql_params)
-
- if(!select_query.warn_execute())
- qdel(select_query)
- return
-
- var/list/results = list()
- while(select_query.NextRow())
- var/datum/cachedbook/CB = new()
- CB.LoadFromRow(list(
- "id" =select_query.item[1],
- "author" =select_query.item[2],
- "title" =select_query.item[3],
- "category"=select_query.item[4],
- "ckey" =select_query.item[5],
- "flagged" =text2num(select_query.item[6])
- ))
- results += CB
- qdel(select_query)
- return results
-
-/obj/machinery/computer/library/proc/get_num_results()
- var/sql = "SELECT COUNT(id) FROM library"
-
- var/datum/db_query/count_query = SSdbcore.NewQuery(sql)
- if(!count_query.warn_execute())
- qdel(count_query)
- return
-
- while(count_query.NextRow())
- var/value = text2num(count_query.item[1])
- qdel(count_query)
- return value
- qdel(count_query)
- return 0
-
-/obj/machinery/computer/library/proc/get_pagelist()
- var/pagelist = "
"
- dat += ""
-
- if(src.arcanecheckout)
- new /obj/item/melee/cultblade/dagger(src.loc)
- to_chat(user, "Your sanity barely endures the seconds spent in the vault's browsing window. The only thing to remind you of this when you stop browsing is a strange looking dagger sitting on the desk. You don't really remember where it came from.")
- user.visible_message("[user] stares at the blank screen for a few moments, [user.p_their()] expression frozen in fear. When [user.p_they()] finally awaken[user.p_s()] from it, [user.p_they()] look[user.p_s()] a lot older.", 2)
- src.arcanecheckout = 0
- if(1)
- // Inventory
- dat += "
Inventory
"
- for(var/obj/item/book/b in inventory)
- dat += "[b.name] (Delete) "
- dat += "(Return to main menu) "
- if(2)
- // Checked Out
- dat += "
"
- if(!scanner)
- for(var/obj/machinery/libraryscanner/S in range(9))
- scanner = S
- break
- if(!scanner)
- dat += "No scanner found within wireless network range. "
- else if(!scanner.cache)
- dat += "No data found in scanner memory. "
- else
-
- dat += {"Data marked for upload...
- Title: [scanner.cache.name] "}
- if(!scanner.cache.author)
- scanner.cache.author = "Anonymous"
-
- dat += {"Author: [scanner.cache.author]
- Category: [upload_category]
- \[Upload\] "}
- dat += "(Return to main menu) "
- if(7)
- dat += "
Print a Manual
"
- dat += "
"
-
- var/list/forbidden = list(
- /obj/item/book/manual/random
- )
-
- if(!emagged)
- forbidden |= /obj/item/book/manual/nuclear
-
- var/manualcount = 1
- var/obj/item/book/manual/M = null
-
- for(var/manual_type in subtypesof(/obj/item/book/manual))
- if(!(manual_type in forbidden))
- M = new manual_type()
- dat += "
[pagelist]"
- dat += "\[Go Back\] "
- var/datum/browser/B = new /datum/browser(user, "library", "Library Visitor")
- B.set_content(dat)
- B.open()
-
-/obj/machinery/computer/library/public/Topic(href, href_list)
- if(..())
- usr << browse(null, "window=publiclibrary")
- onclose(usr, "publiclibrary")
- return
-
- if(href_list["pagenum"])
- if(!num_pages)
- page_num = 1
- else
- var/pn = text2num(href_list["pagenum"])
- if(!isnull(pn))
- page_num = clamp(pn, 1, num_pages)
-
- if(href_list["settitle"])
- var/newtitle = input("Enter a title to search for:") as text|null
- if(newtitle)
- query.title = sanitize(newtitle)
- else
- query.title = null
- if(href_list["setcategory"])
- var/newcategory = input("Choose a category to search for:") in (list("Any") + GLOB.library_section_names)
- if(newcategory == "Any")
- query.category = null
- else if(newcategory)
- query.category = sanitize(newcategory)
- if(href_list["setauthor"])
- var/newauthor = input("Enter an author to search for:") as text|null
- if(newauthor)
- query.author = sanitize(newauthor)
- else
- query.author = null
-
- if(href_list["page"])
- if(num_pages == 0)
- page_num = 1
- else
- page_num = clamp(text2num(href_list["page"]), 1, num_pages)
-
- if(href_list["search"])
- num_results = src.get_num_results()
- num_pages = CEILING(num_results/LIBRARY_BOOKS_PER_PAGE, 1)
- page_num = 1
-
- screenstate = 1
-
- if(href_list["back"])
- screenstate = 0
-
- if(href_list["flag"])
- if(!SSdbcore.IsConnected())
- alert("Connection to Archive has been severed. Aborting.")
- return
- var/id = href_list["flag"]
- if(id)
- var/datum/cachedbook/B = getBookByID(id)
- if(B)
- if((input(usr, "Are you sure you want to flag [B.title] as having inappropriate content?", "Flag Book #[B.id]") in list("Yes", "No")) == "Yes")
- GLOB.library_catalog.flag_book_by_id(usr, id)
-
- add_fingerprint(usr)
- updateUsrDialog()
- return
diff --git a/code/modules/library/lib_items.dm b/code/modules/library/lib_items.dm
deleted file mode 100644
index 61144eea859..00000000000
--- a/code/modules/library/lib_items.dm
+++ /dev/null
@@ -1,327 +0,0 @@
-/* Library Items
- *
- * Contains:
- * Bookcase
- * Book
- * Barcode Scanner
- */
-
-
-/*
- * Bookcase
- */
-
-/obj/structure/bookcase
- name = "bookcase"
- icon = 'icons/obj/library.dmi'
- icon_state = "book-0"
- anchored = 1
- density = 1
- opacity = 1
- resistance_flags = FLAMMABLE
- max_integrity = 200
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 0)
- var/tmp/busy = 0
- var/list/allowed_books = list(/obj/item/book, /obj/item/spellbook, /obj/item/storage/bible, /obj/item/tome) //Things allowed in the bookcase
-
-/obj/structure/bookcase/Initialize()
- ..()
- for(var/obj/item/I in loc)
- if(is_type_in_list(I, allowed_books))
- I.forceMove(src)
- update_icon()
-
-/obj/structure/bookcase/attackby(obj/item/O as obj, mob/user as mob, params)
- if(busy) //So that you can't mess with it while deconstructing
- return TRUE
- if(is_type_in_list(O, allowed_books))
- if(!user.drop_item())
- return
- O.forceMove(src)
- update_icon()
- return TRUE
- else if(istype(O, /obj/item/storage/bag/books))
- var/obj/item/storage/bag/books/B = O
- for(var/obj/item/T in B.contents)
- if(istype(T, /obj/item/book) || istype(T, /obj/item/spellbook) || istype(T, /obj/item/tome) || istype(T, /obj/item/storage/bible))
- B.remove_from_storage(T, src)
- to_chat(user, "You empty [O] into [src].")
- update_icon()
- return TRUE
- else if(istype(O, /obj/item/wrench))
- user.visible_message("[user] starts disassembling \the [src].", \
- "You start disassembling \the [src].")
- playsound(get_turf(src), O.usesound, 50, 1)
- busy = TRUE
-
- if(do_after(user, 50 * O.toolspeed, target = src))
- playsound(get_turf(src), O.usesound, 75, 1)
- user.visible_message("[user] disassembles \the [src].", \
- "You disassemble \the [src].")
- busy = FALSE
- density = 0
- deconstruct(TRUE)
- else
- busy = FALSE
- return TRUE
- else if(istype(O, /obj/item/pen))
- rename_interactive(user, O)
- return TRUE
- else
- return ..()
-
-/obj/structure/bookcase/attack_hand(mob/living/user)
- if(contents.len)
- var/obj/item/book/choice = input("Which book would you like to remove from [src]?") as null|anything in contents
- if(choice)
- if(user.incapacitated() || IS_HORIZONTAL(user) || !Adjacent(user))
- return
- if(!user.get_active_hand())
- user.put_in_hands(choice)
- else
- choice.forceMove(get_turf(src))
- update_icon()
-
-/obj/structure/bookcase/deconstruct(disassembled = TRUE)
- new /obj/item/stack/sheet/wood(loc, 5)
- for(var/obj/item/I in contents)
- if(is_type_in_list(I, allowed_books))
- I.forceMove(get_turf(src))
- qdel(src)
-
-/obj/structure/bookcase/update_icon()
- if(contents.len < 5)
- icon_state = "book-[contents.len]"
- else
- icon_state = "book-5"
-
-
-/obj/structure/bookcase/manuals/medical
- name = "Medical Manuals bookcase"
-
-/obj/structure/bookcase/manuals/medical/Initialize()
- . = ..()
- new /obj/item/book/manual/medical_cloning(src)
- update_icon()
-
-
-/obj/structure/bookcase/manuals/engineering
- name = "Engineering Manuals bookcase"
-
-/obj/structure/bookcase/manuals/engineering/Initialize()
- . = ..()
- new /obj/item/book/manual/engineering_construction(src)
- new /obj/item/book/manual/engineering_particle_accelerator(src)
- new /obj/item/book/manual/engineering_hacking(src)
- new /obj/item/book/manual/engineering_guide(src)
- new /obj/item/book/manual/engineering_singularity_safety(src)
- new /obj/item/book/manual/robotics_cyborgs(src)
- update_icon()
-
-/obj/structure/bookcase/manuals/research_and_development
- name = "R&D Manuals bookcase"
-
-/obj/structure/bookcase/manuals/research_and_development/Initialize()
- . = ..()
- new /obj/item/book/manual/research_and_development(src)
- update_icon()
-
-/obj/structure/bookcase/sop
- name = "bookcase (Standard Operating Procedures)"
-
-/obj/structure/bookcase/sop/Initialize()
- . = ..()
- new /obj/item/book/manual/sop_command(src)
- new /obj/item/book/manual/sop_engineering(src)
- new /obj/item/book/manual/sop_general(src)
- new /obj/item/book/manual/sop_legal(src)
- new /obj/item/book/manual/sop_medical(src)
- new /obj/item/book/manual/sop_science(src)
- new /obj/item/book/manual/sop_security(src)
- new /obj/item/book/manual/sop_service(src)
- new /obj/item/book/manual/sop_supply(src)
- update_icon()
-
-/*
- * Book
- */
-/obj/item/book
- name = "book"
- icon = 'icons/obj/library.dmi'
- icon_state ="book"
- throw_speed = 1
- throw_range = 5
- force = 2
- w_class = WEIGHT_CLASS_NORMAL //upped to three because books are, y'know, pretty big. (and you could hide them inside eachother recursively forever)
- attack_verb = list("bashed", "whacked")
- resistance_flags = FLAMMABLE
- drop_sound = 'sound/items/handling/book_drop.ogg'
- pickup_sound = 'sound/items/handling/book_pickup.ogg'
- var/dat // Actual page content
- var/due_date = 0 // Game time in 1/10th seconds
- var/author // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned
- var/unique = 0 // 0 - Normal book, 1 - Should not be treated as normal book, unable to be copied, unable to be modified
- var/title // The real name of the book.
- var/carved = 0 // Has the book been hollowed out for use as a secret storage item?
- var/forbidden = 0 // Prevent ordering of this book. (0=no, 1=yes, 2=emag only)
- var/obj/item/store // What's in the book?
- /// Book DRM. If this var is TRUE, it cannot be scanned and re-uploaded
- var/has_drm = FALSE
-
-/obj/item/book/attack_self(mob/user as mob)
- if(carved)
- if(store)
- to_chat(user, "[store] falls out of [title]!")
- store.forceMove(get_turf(loc))
- store = null
- return
- else
- to_chat(user, "The pages of [title] have been cut out!")
- return
- if(src.dat)
- user << browse("Penned by [author]. " + "[dat]", "window=book")
- if(!isobserver(user))
- user.visible_message("[user] opens a book titled \"[title]\" and begins reading intently.")
- onclose(user, "book")
- else
- to_chat(user, "This book is completely blank!")
-
-/obj/item/book/attackby(obj/item/W as obj, mob/user as mob, params)
- if(carved)
- if(!store)
- if(W.w_class < WEIGHT_CLASS_NORMAL)
- user.drop_item()
- W.forceMove(src)
- store = W
- to_chat(user, "You put [W] in [title].")
- return 1
- else
- to_chat(user, "[W] won't fit in [title].")
- return 1
- else
- to_chat(user, "There's already something in [title]!")
- return 1
- if(istype(W, /obj/item/pen))
- if(unique)
- to_chat(user, "These pages don't seem to take the ink well. Looks like you can't modify it.")
- return 1
- var/choice = input("What would you like to change?") in list("Title", "Contents", "Author", "Cancel")
- switch(choice)
- if("Title")
- var/newtitle = reject_bad_text(stripped_input(usr, "Write a new title:"))
- if(!newtitle)
- to_chat(usr, "The title is invalid.")
- return 1
- else
- src.name = newtitle
- src.title = newtitle
- if("Contents")
- var/content = strip_html(input(usr, "Write your book's contents (HTML NOT allowed):") as message|null, MAX_BOOK_MESSAGE_LEN)
- if(!content)
- to_chat(usr, "The content is invalid.")
- return 1
- else
- src.dat += content
- if("Author")
- var/newauthor = stripped_input(usr, "Write the author's name:")
- if(!newauthor)
- to_chat(usr, "The name is invalid.")
- return 1
- else
- src.author = newauthor
- return 1
- else if(istype(W, /obj/item/barcodescanner))
- var/obj/item/barcodescanner/scanner = W
- if(!scanner.computer)
- to_chat(user, "[W]'s screen flashes: 'No associated computer found!'")
- else
- switch(scanner.mode)
- if(0)
- scanner.book = src
- to_chat(user, "[W]'s screen flashes: 'Book stored in buffer.'")
- if(1)
- scanner.book = src
- scanner.computer.buffer_book = src.name
- to_chat(user, "[W]'s screen flashes: 'Book stored in buffer. Book title stored in associated computer buffer.'")
- if(2)
- scanner.book = src
- for(var/datum/borrowbook/b in scanner.computer.checkouts)
- if(b.bookname == src.name)
- scanner.computer.checkouts.Remove(b)
- to_chat(user, "[W]'s screen flashes: 'Book stored in buffer. Book has been checked in.'")
- return 1
- to_chat(user, "[W]'s screen flashes: 'Book stored in buffer. No active check-out record found for current title.'")
- if(3)
- scanner.book = src
- for(var/obj/item/book in scanner.computer.inventory)
- if(book == src)
- to_chat(user, "[W]'s screen flashes: 'Book stored in buffer. Title already present in inventory, aborting to avoid duplicate entry.'")
- return 1
- scanner.computer.inventory.Add(src)
- to_chat(user, "[W]'s screen flashes: 'Book stored in buffer. Title added to general inventory.'")
- return 1
- else if(istype(W, /obj/item/kitchen/knife) && !carved)
- carve_book(user, W)
- else
- return ..()
-
-/obj/item/book/wirecutter_act(mob/user, obj/item/I)
- return carve_book(user, I)
-
-/obj/item/book/attack(mob/M, mob/living/user)
- if(user.a_intent == INTENT_HELP)
- force = 0
- attack_verb = list("educated")
- else
- force = initial(force)
- attack_verb = list("bashed", "whacked")
- ..()
-
-/obj/item/book/proc/carve_book(mob/user, obj/item/I)
- if(!I.sharp && I.tool_behaviour != TOOL_WIRECUTTER) //Only sharp and wirecutter things can carve books
- to_chat(user, "")
- return
- if(carved)
- return
- to_chat(user, "You begin to carve out [title].")
- if(I.use_tool(src, user, 30, volume = I.tool_volume))
- to_chat(user, "You carve out the pages from [title]! You didn't want to read it anyway.")
- carved = TRUE
- return TRUE
-/*
- * Barcode Scanner
- */
-/obj/item/barcodescanner
- name = "barcode scanner"
- icon = 'icons/obj/library.dmi'
- icon_state ="scanner"
- throw_speed = 1
- throw_range = 5
- w_class = WEIGHT_CLASS_TINY
- var/obj/machinery/computer/library/checkout/computer // Associated computer - Modes 1 to 3 use this
- var/obj/item/book/book // Currently scanned book
- var/mode = 0 // 0 - Scan only, 1 - Scan and Set Buffer, 2 - Scan and Attempt to Check In, 3 - Scan and Attempt to Add to Inventory
-
-/obj/item/barcodescanner/attack_self(mob/user as mob)
- mode += 1
- if(mode > 3)
- mode = 0
- to_chat(user, "[src] Status Display:")
- var/modedesc
- switch(mode)
- if(0)
- modedesc = "Scan book to local buffer."
- if(1)
- modedesc = "Scan book to local buffer and set associated computer buffer to match."
- if(2)
- modedesc = "Scan book to local buffer, attempt to check in scanned book."
- if(3)
- modedesc = "Scan book to local buffer, attempt to add book to general inventory."
- else
- modedesc = "ERROR"
- to_chat(user, " - Mode [mode] : [modedesc]")
- if(src.computer)
- to_chat(user, "Computer has been associated with this unit.")
- else
- to_chat(user, "No associated computer found. Only local scans will function properly.")
- to_chat(user, "\n")
diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm
deleted file mode 100644
index d76c1f3ef1f..00000000000
--- a/code/modules/library/lib_machines.dm
+++ /dev/null
@@ -1,225 +0,0 @@
-#define LIBRARY_BOOKS_PER_PAGE 25
-
-GLOBAL_DATUM_INIT(library_catalog, /datum/library_catalog, new())
-GLOBAL_LIST_INIT(library_section_names, list("Any", "Fiction", "Non-Fiction", "Adult", "Reference", "Religion"))
-
-/*
- * Borrowbook datum
- */
-/datum/borrowbook // Datum used to keep track of who has borrowed what when and for how long.
- var/bookname
- var/mobname
- var/getdate
- var/duedate
-
-/*
- * Cachedbook datum
- */
-/datum/cachedbook // Datum used to cache the SQL DB books locally in order to achieve a performance gain.
- var/id
- var/title
- var/author
- var/ckey // ADDED 24/2/2015 - N3X
- var/category
- var/content
- var/programmatic=0 // Is the book programmatically added to the catalog?
- var/forbidden=0
- var/path = /obj/item/book // Type path of the book to generate
- var/flagged = 0
-
-/datum/cachedbook/proc/LoadFromRow(list/row)
- id = row["id"]
- author = row["author"]
- title = row["title"]
- category = row["category"]
- ckey = row["ckey"]
- flagged = row["flagged"]
- if("content" in row)
- content = row["content"]
- programmatic=0
-
-// Builds a SQL statement
-/datum/library_query
- var/author
- var/category
- var/title
-
-// So we can have catalogs of books that are programmatic, and ones that aren't.
-/datum/library_catalog
- var/list/cached_books = list()
-
-/datum/library_catalog/New()
- var/newid=1
- for(var/typepath in subtypesof(/obj/item/book/manual))
- var/obj/item/book/B = new typepath(null)
- var/datum/cachedbook/CB = new()
- CB.forbidden = B.forbidden
- CB.title = B.name
- CB.author = B.author
- CB.programmatic=1
- CB.path=typepath
- CB.id = "M[newid]"
- newid++
- cached_books["[CB.id]"]=CB
-
-/datum/library_catalog/proc/flag_book_by_id(mob/user, id)
- var/global/books_flagged_this_round[0]
-
- if("[id]" in cached_books)
- var/datum/cachedbook/CB = cached_books["[id]"]
- if(CB.programmatic)
- to_chat(user, "That book cannot be flagged in the system, as it does not actually exist in the database.")
- return
-
- if("[id]" in books_flagged_this_round)
- to_chat(user, "This book has already been flagged this shift.")
- return
-
- books_flagged_this_round["[id]"] = 1
- message_admins("[key_name_admin(user)] has flagged book #[id] as inappropriate.")
-
- var/datum/db_query/query = SSdbcore.NewQuery("UPDATE library SET flagged = flagged + 1 WHERE id=:id", list(
- "id" = text2num(id)
- ))
- if(!query.warn_execute())
- qdel(query)
- return
- qdel(query)
-
-/datum/library_catalog/proc/rmBookByID(mob/user, id)
- if("[id]" in cached_books)
- var/datum/cachedbook/CB = cached_books["[id]"]
- if(CB.programmatic)
- to_chat(user, "That book cannot be removed from the system, as it does not actually exist in the database.")
- return
-
- var/datum/db_query/query = SSdbcore.NewQuery("DELETE FROM library WHERE id=:id", list(
- "id" = text2num(id)
- ))
- if(!query.warn_execute())
- qdel(query)
- return
- qdel(query)
-
-/datum/library_catalog/proc/getBookByID(id)
- if("[id]" in cached_books)
- return cached_books["[id]"]
-
- var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, author, title, category, content, ckey, flagged FROM library WHERE id=:id", list(
- "id" = text2num(id)
- ))
- if(!query.warn_execute())
- qdel(query)
- return
-
- var/list/results=list()
- while(query.NextRow())
- var/datum/cachedbook/CB = new()
- CB.LoadFromRow(list(
- "id" =query.item[1],
- "author" =query.item[2],
- "title" =query.item[3],
- "category"=query.item[4],
- "content" =query.item[5],
- "ckey" =query.item[6],
- "flagged" =query.item[7]
- ))
- results += CB
- cached_books["[id]"]=CB
- qdel(query)
- return CB
- qdel(query)
- return results
-
-/** Scanner **/
-/obj/machinery/libraryscanner
- name = "scanner"
- icon = 'icons/obj/library.dmi'
- icon_state = "bigscanner"
- anchored = 1
- density = 1
- var/obj/item/book/cache // Last scanned book
-
-/obj/machinery/libraryscanner/attackby(obj/item/I, mob/user)
- if(default_unfasten_wrench(user, I))
- power_change()
- return
- if(istype(I, /obj/item/book))
- // NT with those pesky DRM schemes
- var/obj/item/book/B = I
- if(B.has_drm)
- atom_say("Copyrighted material detected. Scanner is unable to copy book to memory.")
- return FALSE
- user.drop_item()
- I.forceMove(src)
- return 1
- else
- return ..()
-
-/obj/machinery/libraryscanner/attack_hand(mob/user)
- if(istype(user,/mob/dead))
- to_chat(user, "Nope.")
- return
- usr.set_machine(src)
- var/dat = "Scanner Control Interface\n" //
- if(cache)
- dat += "Data stored in memory. "
- else
- dat += "No data stored in memory. "
- dat += "\[Scan\]"
- if(cache)
- dat += " \[Clear Memory\]
\[Remove Book\]"
- else
- dat += " "
- user << browse(dat, "window=scanner")
- onclose(user, "scanner")
-
-/obj/machinery/libraryscanner/Topic(href, href_list)
- if(..())
- usr << browse(null, "window=scanner")
- onclose(usr, "scanner")
- return
-
- if(href_list["scan"])
- for(var/obj/item/book/B in contents)
- cache = B
- break
- if(href_list["clear"])
- cache = null
- if(href_list["eject"])
- for(var/obj/item/book/B in contents)
- B.loc = src.loc
- src.add_fingerprint(usr)
- src.updateUsrDialog()
- return
-
-
-/*
- * Book binder
- */
-/obj/machinery/bookbinder
- name = "Book Binder"
- icon = 'icons/obj/library.dmi'
- icon_state = "binder"
- anchored = 1
- density = 1
-
-/obj/machinery/bookbinder/attackby(obj/item/I, mob/user)
- var/obj/item/paper/P = I
- if(default_unfasten_wrench(user, I))
- power_change()
- return
- if(istype(P))
- user.drop_item()
- user.visible_message("[user] loads some paper into [src].", "You load some paper into [src].")
- src.visible_message("[src] begins to hum as it warms up its printing drums.")
- sleep(rand(200,400))
- src.visible_message("[src] whirs as it prints and binds a new book.")
- var/obj/item/book/b = new(loc)
- b.dat = P.info
- b.name = "Print Job #[rand(100, 999)]"
- b.icon_state = "book[rand(1,16)]"
- qdel(P)
- return 1
- else
- return ..()
diff --git a/code/modules/library/lib_readme.dm b/code/modules/library/lib_readme.dm
deleted file mode 100644
index 0150ed6ba8a..00000000000
--- a/code/modules/library/lib_readme.dm
+++ /dev/null
@@ -1,61 +0,0 @@
-//*******************************
-//
-// Library SQL Configuration
-//
-//*******************************
-
-// Deprecated! See global.dm for new SQL config vars -- TLE
-/*
-#define SQL_ADDRESS ""
-#define SQL_DB ""
-#define SQL_PORT "3306"
-#define SQL_LOGIN ""
-#define SQL_PASS ""
-*/
-
-//*******************************
-// Requires Dantom.DB library ( http://www.byond.com/developer/Dantom/DB )
-
-
-/*
- The Library
- ------------
- A place for the crew to go, relax, and enjoy a good book.
- Aspiring authors can even self publish and, if they're lucky
- convince the on-staff Librarian to submit it to the Archives
- to be chronicled in history forever - some say even persisting
- through alternate dimensions.
-
-
- Written by TLE for /tg/station 13
- Feel free to use this as you like. Some credit would be cool.
- Check us out at http://nanotrasen.com/ if you're so inclined.
-*/
-
-// CONTAINS:
-
-// Objects:
-// - bookcase
-// - book
-// - barcode scanner
-// Machinery:
-// - library computer
-// - visitor's computer
-// - book binder
-// - book scanner
-// Datum:
-// - borrowbook
-
-
-// Ideas for the future
-// ---------------------
-// - Visitor's computer should be able to search the current in-round library inventory (that the Librarian has stocked and checked in)
-// -- Give computer other features like an Instant Messenger application, or the ability to edit, save, and print documents.
-// - Admin interface directly tied to the Archive DB. Right now there's no way to delete uploaded books in-game.
-// -- If this gets implemented, allow Librarians to "tag" or "suggest" books to be deleted. The DB ID of the tagged books gets saved to a text file (or another table in the DB maybe?).
-// The admin interface would automatically take these IDs and SELECT them all from the DB to be displayed along with a Delete link to drop the row from the table.
-// - When the game sets up and the round begins, have it automatically pick random books from the DB to populate the library with. Even if the Librarian is a useless fuck there are at least a few books around.
-// - Allow books to be "hollowed out" like the Chaplain's Bible, allowing you to store one pocket-sized item inside.
-// - Make books/book cases burn when exposed to flame.
-// - Make book binder hackable.
-// - Books shouldn't print straight from the library computer. Make it synch with a machine like the book binder to print instead. This should consume some sort of resource.
diff --git a/code/modules/library/library_admin.dm b/code/modules/library/library_admin.dm
new file mode 100644
index 00000000000..ce8c724edac
--- /dev/null
+++ b/code/modules/library/library_admin.dm
@@ -0,0 +1,206 @@
+#define LIBRARY_MENU_MAIN 1
+#define LIBRARY_MENU_CKEY 2
+#define LIBRARY_MENU_REPORTS 3
+
+/client/proc/library_manager()
+ set name = "Manage Library"
+ set category = "Admin"
+ set desc = "Manage Flagged Books and Perform Maintenance on the Library System"
+
+ if(!check_rights(R_ADMIN))
+ return
+
+ var/datum/ui_module/library_manager/L = new()
+ L.ui_interact(usr)
+
+/datum/ui_module/library_manager
+ name = "Library Manager"
+ ///Where we will store our cachedbook datums
+ var/list/cached_books = list()
+ ///list of assoc lists detailing each invidual reports, can contain multiple reports for same book
+ var/list/reports = list()
+
+ ///TGUI page we are currently on
+ var/page_state = LIBRARY_MENU_MAIN
+ ///Ckey's books we are viewing
+ var/selected_ckey
+
+ ///information for the book we are opening in browserui
+ var/datum/cachedbook/view_book
+ ///browserui helper variable for turning pages in book
+ var/view_book_page = 0
+
+/datum/ui_module/library_manager/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.admin_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "LibraryManager", name, 600, 600, master_ui, state)
+ ui.autoupdate = TRUE
+ ui.open()
+
+/datum/ui_module/library_manager/ui_data(mob/user)
+ var/list/data = list()
+ data["pagestate"] = page_state
+ data["booklist"] = cached_books
+ data["ckey"] = selected_ckey ? selected_ckey : "ERROR"
+ data["reports"] = reports
+
+ data["modal"] = ui_modal_data(src)
+ return data
+
+/datum/ui_module/library_manager/ui_act(action, params, datum/tgui/ui)
+ if(..())
+ return
+
+ if(ui_act_modal(action, params))
+ return
+
+ switch(action)
+ if("view_reported_books")
+ reports = list()
+ for(var/datum/cachedbook/CB in GLOB.library_catalog.get_flagged_books())
+ for(var/datum/flagged_book/report as anything in CB.reports)
+ if(!report)
+ continue
+ var/datum/library_category/report_category = GLOB.library_catalog.get_report_category_by_id(report.category_id)
+ var/report_info = list(
+ "reporter_ckey" = report.reporter,
+ "uploader_ckey" = CB.ckey,
+ "id" = CB.id,
+ "title" = CB.title,
+ "author" = CB.author,
+ "report_description" = report_category.description,
+ )
+ reports += list(report_info)
+ page_state = LIBRARY_MENU_REPORTS
+ if("delete_book")
+ if(text2num(params["bookid"])) //make sure this is actually a number
+ if(GLOB.library_catalog.remove_book_by_id(text2num(params["bookid"])))
+ log_and_message_admins("has deleted book [params["bookid"]].")
+ if("view_book")
+ if(params["bookid"])
+ view_book_by_id(text2num(params["bookid"]), ui.user)
+ if("unflag_book")
+ if(params["bookid"])
+ if(GLOB.library_catalog.unflag_book_by_id(text2num(params["bookid"])))
+ log_and_message_admins("has unflagged book [params["bookid"]].")
+ if("return")
+ page_state = LIBRARY_MENU_MAIN
+
+
+/datum/ui_module/library_manager/proc/ui_act_modal(action, list/params)
+ . = TRUE
+ var/id = params["id"] // The modal's ID
+ var/list/arguments = istext(params["arguments"]) ? json_decode(params["arguments"]) : params["arguments"]
+ switch(ui_modal_act(src, action, params))
+ if(UI_MODAL_OPEN)
+ switch(id)
+ if("specify_ssid_delete")
+ ui_modal_input(src, id, "Please input a book SSID:", null, arguments)
+ if("specify_ckey_search")
+ ui_modal_input(src, id, "Please input a CKEY:", null, arguments)
+ if("specify_ckey_delete")
+ ui_modal_input(src, id, "Please input a CKEY:", null, arguments)
+ else
+ return FALSE
+ if(UI_MODAL_ANSWER)
+ var/answer = params["answer"]
+ switch(id)
+ if("specify_ssid_delete")
+ if(!answer || !text2num(answer))
+ return
+ var/confirm = alert("You are about to delete book [text2num(answer)]", "Confirm Deletion", "Yes", "No")
+ if(confirm != "Yes")
+ return //we don't need to sanitize b/c removeBookyByID uses id=:id instead of like statemetns
+ if(GLOB.library_catalog.remove_book_by_id(text2num(answer)))
+ log_and_message_admins("has deleted the book [text2num(answer)].")
+ if("specify_ckey_search")
+ if(!answer)
+ return
+ var/datum/library_user_data/search_terms = new()
+ search_terms.search_ckey = paranoid_sanitize(answer)
+ selected_ckey = paranoid_sanitize(answer)
+ cached_books = list()
+ for(var/datum/cachedbook/CB in GLOB.library_catalog.get_book_by_range(1, 10, search_terms))
+ var/list/book_data = list(
+ "id" = CB.id,
+ "title" = CB.title,
+ "author" = CB.author,
+ "rating" = CB.rating,
+ "summary" = CB.summary,
+ "ckey" = CB.ckey,
+ "reports" = CB.reports,
+ )
+ cached_books += list(book_data)
+ page_state = LIBRARY_MENU_CKEY
+ if("specify_ckey_delete")
+ if(!answer)
+ return
+ var/sanitized_answer = paranoid_sanitize(answer) //the last thing we want happening is someone deleting every book with "%%"
+ var/confirm //We want to be absolutely certain an admin wants to do this
+ confirm = alert("You are about to mass delete potentially up to 10 books", "Confirm Deletion", "Yes", "No")
+ if(confirm != "Yes")
+ return
+ if(GLOB.library_catalog.remove_books_by_ckey(sanitized_answer))
+ log_and_message_admins("has deleted all books uploaded by [answer].")
+ else
+ return FALSE
+ else
+ return FALSE
+
+/datum/ui_module/library_manager/proc/view_book_by_id(bookid, mob/user)
+ if(!view_book || view_book.id != bookid)
+ view_book = GLOB.library_catalog.get_book_by_id(bookid)
+ view_book_page = 0
+ view_book(user)
+
+/*
+* #View Book
+*
+* Internal proc for viewing library books as an admin. This absolutely must stay as BrowserUI even though the rest of
+* the library manager is TGUI. This is because of TGUI sanitization issues.
+*/
+/datum/ui_module/library_manager/proc/view_book(mob/user)
+ if(!view_book || !length(view_book.content))
+ return
+
+ var/dat = ""
+ //First, we're going to choose/generate our header buttons for switching pages and store it in var/dat
+ var/header_left = ""
+ var/header_right = ""
+ if(length(view_book.content)) //No need to have page switching buttons if there's no pages
+ if(view_book_page < length(view_book.content))
+ header_right = "
"
+
+ dat += header_left + header_right
+ //Now we're going to display the header buttons + the current page selected, if it's page 0, we display the cover_page instead
+ if(!view_book_page)
+ var/cover_page = {"
[view_book.title]
Written by: [view_book.author]
Summary: [view_book.summary]"}
+ user << browse("[dat] " + "[cover_page]", "window=book[UID()];size=400x400")
+ return
+ else
+ user << browse("[dat] " + "[view_book.content[view_book_page]]", "window=book[UID()]")
+
+/datum/ui_module/library_manager/Topic(href, href_list)
+ ..()
+ if(!check_rights(R_ADMIN))
+ log_admin("[key_name(usr)] tried to use the library manager without authorization.")
+ message_admins("[key_name_admin(usr)] has attempted to override the library manager!")
+ return
+ if(href_list["next_page"])
+ if(view_book_page > length(view_book.content)) //should never be false, but just in-case
+ view_book_page = length(view_book.content)
+ return
+ view_book_page++
+ view_book(usr) //scuffed but this is how you update the UI
+ if(href_list["prev_page"])
+ if(view_book_page < 0) //should never be false, but just in-case
+ view_book_page = 0
+ return
+ view_book_page--
+ view_book(usr) //scuffed but this is how you update the UI
+
+#undef LIBRARY_MENU_MAIN
+#undef LIBRARY_MENU_CKEY
+#undef LIBRARY_MENU_REPORTS
diff --git a/code/modules/library/library_catalog.dm b/code/modules/library/library_catalog.dm
new file mode 100644
index 00000000000..8b1ecd43e8f
--- /dev/null
+++ b/code/modules/library/library_catalog.dm
@@ -0,0 +1,653 @@
+///library category datum constructor helper, used to make easier the process of defining new report/book categories
+#define DEFINE_CATEGORY(C, D) (new /datum/library_category(_category_id = C, _description = D))
+///Maximum number of books that can be uploaded by a single ckey
+#define MAX_PLAYER_UPLOADS 5
+
+/*
+ * # Library Catalog
+
+ This datum forms the basis for the entire library system, one is created at roundstart and stored to a global variable
+ It holds lists for all predefined report and book categories, books flagged during the round, and all programmatic
+ books.
+
+ Additionally, ALL library SQL queries are handled in this datum. This is intentional so that we do not have multiple SQL
+ queries trying to do the same thing but in 4-5 different dm files. This file is split/organized into a specific
+ structure:
+ TOP - Defining Library Lists
+ MIDDLE - Get Procs that get information from the catalog or DB
+ BOTTOM - Send/Update procs that perform changes to the Database. Don't mix their functionalities together.
+ */
+/datum/library_catalog
+ ///Lists of all reported books in the current round
+ var/list/flagged_books = list()
+ ///List of all programmatic books, automatically generated upon New()
+ var/list/books = list()
+ ///List of all report categories, automatically generated upon New()
+ var/list/report_types = list()
+ ///List of all book categories, automatically generated upon New()
+ var/list/categories = list()
+
+/datum/library_catalog/New()
+
+ //Building a list of all the reasons that players can report books, used for report menu + logging reports in DB
+ //Cat ID needs to be unique to category, description can be changed here without issues anywhere else
+ report_types = list(
+ DEFINE_CATEGORY(LIB_REPORT_HATESPEECH, "Hatespeech or Slur Usage"),
+ DEFINE_CATEGORY(LIB_REPORT_EROTICA, "Erotica or Sexual Content"),
+ DEFINE_CATEGORY(LIB_REPORT_OOC, "Out of Character Information"),
+ DEFINE_CATEGORY(LIB_REPORT_COPYPASTA, "Copypastas or Spam"),
+ DEFINE_CATEGORY(LIB_REPORT_BLANK , "Blank or No Content"),
+ DEFINE_CATEGORY(LIB_REPORT_NOEFFORT , "Very Low Effort Content"),
+ DEFINE_CATEGORY(LIB_REPORT_OTHER , "Other Reason not Specified"), //required
+ )
+
+ //building a list of all categories, used for searching, Cat ID needs to be unique to category
+ categories = list(
+ DEFINE_CATEGORY(LIB_CATEGORY_FICTION, "Fiction"),
+ DEFINE_CATEGORY(LIB_CATEGORY_NONFICTION, "Non-Fiction"),
+ DEFINE_CATEGORY(LIB_CATEGORY_RELIGION, "Religious"),
+ DEFINE_CATEGORY(LIB_CATEGORY_FANTASY, "Fantasy"),
+ DEFINE_CATEGORY(LIB_CATEGORY_HORROR, "Horror"),
+ DEFINE_CATEGORY(LIB_CATEGORY_ROMANCE, "Romance"),
+ DEFINE_CATEGORY(LIB_CATEGORY_MYSTERY, "Mystery"),
+ DEFINE_CATEGORY(LIB_CATEGORY_ADVENTURE, "Adventure"),
+ DEFINE_CATEGORY(LIB_CATEGORY_HISTORY, "History"),
+
+ DEFINE_CATEGORY(LIB_CATEGORY_PHILOSOPHY, "Philosophy"),
+ DEFINE_CATEGORY(LIB_CATEGORY_DRAMA, "Drama and Thriller"),
+ DEFINE_CATEGORY(LIB_CATEGORY_EXPERIMENT, "Experiment Notes"),
+ DEFINE_CATEGORY(LIB_CATEGORY_LEGAL, "Legal Document"),
+ DEFINE_CATEGORY(LIB_CATEGORY_BIOGRAPHY, "Biography"),
+ DEFINE_CATEGORY(LIB_CATEGORY_GUIDE, "Guides and References"),
+ DEFINE_CATEGORY(LIB_CATEGORY_PAPERWORK, "Paperwork"),
+ DEFINE_CATEGORY(LIB_CATEGORY_COOKING, "Culinary Arts"),
+ DEFINE_CATEGORY(LIB_CATEGORY_DESIGN, "Decor and Design"),
+ DEFINE_CATEGORY(LIB_CATEGORY_COMBAT, "Martial Arts and Combat"),
+ DEFINE_CATEGORY(LIB_CATEGORY_EXPLORATION, "Exploration"),
+ DEFINE_CATEGORY(LIB_CATEGORY_THEATRE, "Theatre"),
+ DEFINE_CATEGORY(LIB_CATEGORY_POETRY, "Poetry"),
+
+ DEFINE_CATEGORY(LIB_CATEGORY_LAW, "Law"),
+ DEFINE_CATEGORY(LIB_CATEGORY_SECURITY, "Security"),
+ DEFINE_CATEGORY(LIB_CATEGORY_SUPPLY, "Supply"),
+ DEFINE_CATEGORY(LIB_CATEGORY_ENGINEERING, "Engineering"),
+ DEFINE_CATEGORY(LIB_CATEGORY_SERVICE , "Service"),
+ DEFINE_CATEGORY(LIB_CATEGORY_MEDICAL, "Medical"),
+ DEFINE_CATEGORY(LIB_CATEGORY_RESEARCH, "Science"),
+ DEFINE_CATEGORY(LIB_CATEGORY_COMMAND , "Command"),
+ )
+
+ //Books that we don't want showing up in the programmatic book list
+ //Books should go here if they're non-functional, spawners, or are designed for off-station roles to consume
+ var/list/forbidden_books = list(
+ /obj/item/book/manual/random,
+ /obj/item/book/manual/nuclear,
+ /obj/item/book/manual/wiki,
+ /obj/item/book/manual/hydroponics_pod_people,
+ )
+
+ var/newid = 1
+ //building a list of all programmatic books
+ for(var/typepath in (subtypesof(/obj/item/book/manual) - forbidden_books))
+ var/obj/item/book/B = typepath
+ var/datum/programmatic_book/PB = new()
+ PB.title = initial(B.name)
+ PB.author = initial(B.author)
+ PB.id = "M[newid]"
+ PB.book_type = typepath
+ newid++
+ books += PB
+
+/*
+ * can_vv_delete override
+ * Admins should not be deleting this willy nilly, if they think it is neccesary,
+ * they can go through the effort of advanced proccall
+ */
+/datum/library_catalog/can_vv_delete()
+ message_admins("An admin attempted to VV delete the global library catalog, this will break the library system for the round, if you know what you are doing please use advanced proccal")
+ return FALSE
+
+/*
+ * Database Select and Get Procs
+ *
+ * Each of these procs facilitate finding, taking,
+ * and prepping information from the database for use elsewhere
+ */
+
+///External proc that Returns a report library_category datum that matches the provided cat_id
+/datum/library_catalog/proc/get_report_category_by_id(category_id)
+ for(var/datum/library_category/category in report_types)
+ if(category.category_id == category_id)
+ return category
+ //proc shouldn't get this far, but if there's an entry in the DB that we don't have added, just default to other cat
+ for(var/datum/library_category/category in report_types)
+ if(category.category_id == LIB_REPORT_OTHER)
+ return category
+
+///External proc that Returns a book library_category datum that matches the provided cat_id
+/datum/library_catalog/proc/get_book_category_by_id(category_id)
+ for(var/datum/library_category/category in categories)
+ if(category.category_id == category_id)
+ return category
+
+///External proc that Returns a report programmaticbook datum that matches the provided bookid
+/datum/library_catalog/proc/get_programmatic_book_by_id(id)
+ for(var/datum/programmatic_book/PB as anything in books)
+ if(PB.id == id)
+ return PB
+
+/*
+ * # get_book_by_id
+ *
+ * External proc that takes in an id number and searches the Database for a book with a matching SSID
+ * returns a cached book with the data from that row
+ *
+ * Arguments:
+ * * id - integer value that matches as a book SSID
+ */
+/datum/library_catalog/proc/get_book_by_id(id)
+ var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, author, title, content, summary, rating, raters, primary_category, secondary_category, tertiary_category, ckey, reports FROM library WHERE id=:id", list(
+ "id" = id
+ ))
+
+ if(!query.warn_execute())
+ qdel(query)
+ return
+
+ var/list/results = list()
+ while(query.NextRow())
+ var/datum/cachedbook/CB = new()
+ CB.LoadFromRow(list(
+ "id" = query.item[1],
+ "author" = query.item[2],
+ "title" = query.item[3],
+ "content" = query.item[4],
+ "summary" = query.item[5],
+ "rating" = query.item[6],
+ "raters" = query.item[7],
+ "primary_category" = query.item[8],
+ "secondary_category" = query.item[9],
+ "tertiary_category" = query.item[10],
+ "ckey" = query.item[11],
+ "reports" = query.item[12],
+ ))
+ results += CB
+ qdel(query)
+ return CB
+ qdel(query)
+ return results
+
+/*
+ * # build_search_query
+ *
+ * Internal proc that builds part of an SQL statement using a datum of search terms/parameters. It will then return
+ * a list of two objects: 1) the built SQL statement and 2) the assoc list of parameters that will accompany it in the query
+ * This should only ever be used to generate WHERE statements
+ *
+ * Arguments:
+ * * datum/library_user_data/search_terms - datum with parameters for what we want to query our DB for
+ */
+/datum/library_catalog/proc/build_search_query(datum/library_user_data/search_terms)
+ var/searchquery = ""
+ //We do not want to use WHERE more than once in our query, first usage makes this TRUE and defaults other WHERE's to AND
+ var/where = FALSE
+ var/list/sql_params = list()
+ if(search_terms)
+ if(search_terms.search_title)
+ searchquery += " WHERE title LIKE :title"
+ sql_params["title"] = "%[search_terms.search_title]%"
+ where = TRUE
+ if(search_terms.search_author)
+ searchquery += " [!where ? "WHERE" : "AND"] author LIKE :author"
+ sql_params["author"] = "%[search_terms.search_author]%"
+ where = TRUE
+ if(length(search_terms.search_categories))
+ //yes this sql is cursed, but this is how it must be done and we only ever use this once :)
+ var/category_vars = list()
+ var/category_count = 1
+ for(var/c in search_terms.search_categories)
+ sql_params["category[category_count]"] = c
+ category_vars += ":category[category_count]"
+ category_count++
+ var/query_insert = "([jointext(category_vars, ", ")])"
+ searchquery += " [!where ? "WHERE" : "AND"] (primary_category IN [query_insert] OR secondary_category IN [query_insert] OR tertiary_category IN [query_insert])"
+ where = TRUE
+ if(search_terms.search_rating["min"] && search_terms.search_rating["max"])
+ searchquery += " [!where ? "WHERE" : "AND"] (rating BETWEEN :ratingmin AND :ratingmax)"
+ sql_params["ratingmin"] = search_terms.search_rating["min"]
+ sql_params["ratingmax"] = search_terms.search_rating["max"]
+ where = TRUE
+ if(search_terms.search_ckey)
+ searchquery += " [!where ? "WHERE" : "AND"] ckey =:ckey"
+ sql_params["ckey"] = search_terms.search_ckey
+ where = TRUE
+
+ var/list/results = list(searchquery, sql_params)
+ return results
+
+/*
+ * # get_book_by_range
+ *
+ * External proc used to get a large amount of books from a specific part of the library DB. Has paremeters to
+ * specify range as well as what kind of books to look for. Will return a list of cachedbook datums.
+ *
+ * Arguments:
+ * * initial - Book we want to start grabbing rows at, THIS IS NOT SSID, based on number of rows in DB
+ * * range - Amount of books we want to grab at once
+ * * datum/library_user_data/search_terms - datum with parameters for what we want to query our DB for
+ */
+/datum/library_catalog/proc/get_book_by_range(initial = 1, range = 25, datum/library_user_data/search_terms, doAsync = TRUE)
+ var/list/search_query = build_search_query(search_terms)
+ var/sql = "SELECT id, author, title, content, summary, rating, raters, primary_category, secondary_category, tertiary_category, ckey, reports FROM library" + search_query[1] + " LIMIT :lowerlimit, :upperlimit"
+ var/list/sql_params = search_query[2]
+
+ sql_params["lowerlimit"] = initial
+ sql_params["upperlimit"] = range
+
+ var/datum/db_query/select_query = SSdbcore.NewQuery(sql, sql_params)
+
+ if(!select_query.warn_execute(async = doAsync))
+ qdel(select_query)
+ return
+
+ var/list/results = list()
+ while(select_query.NextRow())
+ var/datum/cachedbook/CB = new()
+ CB.LoadFromRow(list(
+ "id" = select_query.item[1],
+ "author" = select_query.item[2],
+ "title" = select_query.item[3],
+ "content" = select_query.item[4],
+ "summary" = select_query.item[5],
+ "rating" = select_query.item[6],
+ "raters" = select_query.item[7],
+ "primary_category" = select_query.item[8],
+ "secondary_category" = select_query.item[9],
+ "tertiary_category" = select_query.item[10],
+ "ckey" = select_query.item[11],
+ "reports" = select_query.item[12],
+ ))
+ results += CB
+ qdel(select_query)
+ return results
+
+/*
+ * # get_flagged_books
+ *
+ * External proc that finds all books that have reports marked in the Database. Returns these books as a list
+ * of cachedbook datums. This proc is not intended to actually handle reports or generate report_book datums
+ */
+/datum/library_catalog/proc/get_flagged_books()
+ var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, author, title, content, summary, ckey, reports FROM library WHERE LENGTH(reports) > 5")
+ if(!query.warn_execute())
+ qdel(query)
+ return
+
+ var/list/flagged_books = list()
+ while(query.NextRow())
+ var/datum/cachedbook/CB = new()
+ CB.LoadFromRow(list(
+ "id" = query.item[1],
+ "author" = query.item[2],
+ "title" = query.item[3],
+ "content" = query.item[4],
+ "summary" = query.item[5],
+ "ckey" = query.item[6],
+ "reports" = query.item[7],
+ ))
+ flagged_books += CB
+ qdel(query)
+ return flagged_books
+
+/*
+ * # get_total_books
+ *
+ * External proc that counts the number of books in the DB that match the provided search parameters
+ * calling this with no arguments will return the complete count of books in the DB, if the query fails
+ * this proc will return null, so usages of this proc will need to account for that
+ *
+ * Arguments:
+ * * datum/library_user_data/search_terms - datum with parameters for what we want to query our DB for
+ */
+/datum/library_catalog/proc/get_total_books(datum/library_user_data/search_terms)
+ var/list/search_query = build_search_query(search_terms)
+ var/sql = "SELECT COUNT(id) FROM library" + search_query[1]
+ var/list/sql_params = search_query[2]
+
+ var/datum/db_query/count_query = SSdbcore.NewQuery(sql, sql_params)
+ if(!count_query.warn_execute())
+ qdel(count_query)
+ return
+
+ while(count_query.NextRow())
+ var/value = text2num(count_query.item[1])
+ qdel(count_query)
+ return value
+ qdel(count_query)
+
+/*
+ * # get_book_ratings
+ *
+ * External proc that gets all of the book ratings for a book. Unless the requested SSID doesn't exist in the
+ * database, this proc will return (if the book has ratings) a list with the
+ * first element being the books avg ratings and a list of ratings by players ["ckey", rating_int]
+ *
+ * Arguments:
+ * * bookid - SSID of the book you wish to get ratings for
+ */
+/datum/library_catalog/proc/get_book_ratings(bookid)
+ var/list/sql_params = list()
+ sql_params["id"] = bookid
+
+ var/datum/db_query/query = SSdbcore.NewQuery("SELECT rating, raters FROM library WHERE id=:id", sql_params)
+
+ if(!query.warn_execute())
+ qdel(query)
+ return
+
+ var/list/book_ratings = list()
+ while(query.NextRow())
+ if(!query.item[2] || length(query.item[2]) < 5) //we don't want to decode something that is null or contains no values
+ book_ratings = list(query.item[1], list())
+ break
+ book_ratings = list(query.item[1], json_decode(query.item[2]))
+
+ qdel(query)
+ return book_ratings
+
+/*
+ * # get_random_books
+ *
+ * External proc that gets random books from the Database, used by spawners for the most part. RANT: whoever wrote the fucking
+ * old library code made this a global proc that accepted a loc and new'd/spawned in books from THIS PROC, take this as a
+ * lesson never to do this. Anywho, this proc returns a list of cached books.
+ *
+ * Arguments:
+ * * amount - amount of random books to get
+ */
+/datum/library_catalog/proc/get_random_book(amount = 1, doAsync = TRUE)
+ if(!amount)
+ return
+ if(!SSdbcore.IsConnected())
+ return
+ var/num_books = clamp(amount, 1, 50) //you don't need more than 50 random books <3
+ var/list/sql_params = list("amount" = num_books )
+ var/sql = "SELECT id, author, title, content, summary, rating, primary_category, secondary_category, tertiary_category, ckey, reports FROM library GROUP BY title ORDER BY rand() LIMIT :amount"
+ var/datum/db_query/query = SSdbcore.NewQuery(sql, sql_params)
+ if(!query.warn_execute(async = doAsync)) //this proc is used in initialize in some objects :)
+ qdel(query)
+ return
+
+ var/list/results = list()
+ while(query.NextRow())
+ var/datum/cachedbook/CB = new()
+ CB.LoadFromRow(list(
+ "id" = query.item[1],
+ "author" = query.item[2],
+ "title" = query.item[3],
+ "content" = query.item[4],
+ "summary" = query.item[5],
+ "rating" = query.item[6],
+ "primary_category" = query.item[7],
+ "secondary_category" = query.item[8],
+ "tertiary_category" = query.item[9],
+ "ckey" = query.item[10],
+ "reports" = query.item[11]
+ ))
+ results += CB
+ qdel(query)
+ return results
+/*
+ * Database Update Procs
+ *
+ * Each of these procs facilitate editing/updating the database
+ */
+
+/*
+ * # flag_book_by_id
+ *
+ * External proc that Handles reporting of books. Will first get the existing flags for the book from the DB, if the report is
+ * guchi, it will then add it to the list of reports for the book, encode to JSON, and update the DB
+ *
+ * Arguments:
+ * * ckey - ckey of the player who is making the report
+ * * bookid - SSID of the book being reported
+ * * category_id - ID of the report category that is being used in the report
+ */
+/datum/library_catalog/proc/flag_book_by_id(ckey, bookid, category_id)
+ //we should never flag a book in the DB without having the Book ID, Report Type, or Who reported it
+ if(!bookid || !category_id || !ckey)
+ return FALSE
+ var/datum/library_category/report_type = get_report_category_by_id(category_id) //lets pull our report category datum
+ if(!report_type) //is this an existing report type? If not somethings gone terribly wrong
+ message_admins("WARNING: a player has attempted to flag book #[bookid] as inappropriate for a reason that does not exist, please investigate further.")
+ return FALSE
+ var/datum/cachedbook/reportedbook = get_book_by_id(bookid) //and now lets get what's currently on the DB
+ if(!reportedbook) //does this book exist in the DB?
+ message_admins("WARNING: a player has attempted to flag book #[bookid] as inappropriate for [report_type.description] but it does not exist in the Database, please investigate further.")
+ return FALSE
+ if(!SSdbcore.IsConnected()) //check our connection to the DB
+ message_admins("WARNING: a player has attempted to flag book #[bookid] as inappropriate for [report_type.description] but the flag was not succesfully saved to the Database. Please investigate further.")
+ alert("Connection to Archive has been severed. Aborting.")
+ return FALSE
+
+ //Alright now that we've triple checked that we're ready to do this:
+ //Has this player reported this book already this round?
+ for(var/datum/flagged_book/book in flagged_books)
+ if (book.bookid == bookid && book.reporter == ckey)
+ return FALSE
+ //If not, have they report this book in a previous round?
+ for(var/datum/flagged_book/book in reportedbook.reports)
+ if(book.reporter == ckey)
+ return FALSE
+
+ //lets add this book to the reported_books list for the round
+ var/datum/flagged_book/f = new()
+ f.bookid = bookid
+ f.reporter = ckey
+ f.category_id = category_id
+ flagged_books += f //adding to global list
+ reportedbook.reports += f //adding to books var for tracking reports
+ //Now we will add the report to the DB, we will build the JSON we're going to upload from our books report list
+ var/list/flag_json = list()
+ //Flagged book json is stored as such: "[[reporter_ckey1, report_id1],[reporter_ckey2, report_id2]]""
+ for(var/datum/flagged_book/book in reportedbook.reports)
+ flag_json += list(list( //yes this is intentional
+ book.reporter,
+ book.category_id,
+ ))
+ //uploading our report to the library
+ var/datum/db_query/query = SSdbcore.NewQuery("UPDATE library SET reports=:report WHERE id=:id", list(
+ "id" = text2num(bookid),
+ "report" = json_encode(flag_json),
+ ))
+ if(!query.warn_execute())
+ message_admins("WARNING: a player has attempted to flag book #[bookid] as inappropriate for \"[report_type.description]\" but the flag was not succesfully saved to the Database. Please investigate further.")
+ qdel(query)
+ return FALSE
+ message_admins("[ckey] has flagged book #[bookid] as inappropriate for \"[report_type.description]\".")
+ qdel(query)
+ return TRUE
+
+/*
+ * # unflag_book_by_id
+ *
+ * External proc that removes all reports on a book.
+ *
+ * Arguments:
+ * * bookid - SSID of the book being reported
+ */
+/datum/library_catalog/proc/unflag_book_by_id(bookid)
+ //we should never flag a book in the DB without having the Book ID, Report Type, or Who reported it
+ if(!bookid)
+ return FALSE
+ var/datum/cachedbook/reportedbook = get_book_by_id(bookid)
+ if(!reportedbook)
+ return FALSE //it don't exist
+
+ if(!SSdbcore.IsConnected()) //check our connection to the DB
+ message_admins("WARNING: an admin has attempted to unflag book #[bookid] but it was not succesfully saved to the Database. Please investigate further.")
+ return FALSE
+
+ //uploading our report to the library
+ var/datum/db_query/query = SSdbcore.NewQuery("UPDATE library SET reports=:report WHERE id=:id", list(
+ "id" = text2num(bookid),
+ "report" = json_encode(list()),
+ ))
+ if(!query.warn_execute())
+ message_admins("WARNING: an admin has attempted to unflag book #[bookid] but it was not succesfully saved to the Database. Please investigate further.")
+ qdel(query)
+ return FALSE
+ qdel(query)
+ return TRUE
+/*
+ * # remove_book_by_id
+ *
+ * External proc that Handles the deletion of books by SSID
+ *
+ * Arguments:
+ * * bookid - SSID of the book being deleted
+ */
+/datum/library_catalog/proc/remove_book_by_id(bookid)
+ var/datum/db_query/query = SSdbcore.NewQuery("DELETE FROM library WHERE id=:id", list(
+ "id" = text2num(bookid)
+ ))
+ if(!query.warn_execute())
+ qdel(query)
+ return FALSE
+ qdel(query)
+ return TRUE
+
+/*
+ * # remove_books_by_ckey
+ *
+ * External proc that Handles the mass deletion of all books uploaded by a single ckey
+ *
+ * Arguments:
+ * * ckey - ckey we will use to get all the books we want for deletion
+ */
+/datum/library_catalog/proc/remove_books_by_ckey(ckey)
+ var/datum/db_query/query = SSdbcore.NewQuery("DELETE FROM library WHERE ckey=:ckey", list(
+ "ckey" = ckey
+ ))
+ if(!query.warn_execute())
+ qdel(query)
+ return FALSE
+ qdel(query)
+ return TRUE
+
+/*
+ * # upload_book
+ *
+ * External proc that handles creating new rows/uploading books to the DB
+ *
+ * Arguments:
+ * * ckey - author's ckey that will be tied to the book uploaded
+ * * datum/cachedbook/selected_book - cachedbook datum that contains all the book information to added to DB
+ */
+/datum/library_catalog/proc/upload_book(ckey, datum/cachedbook/selected_book)
+ if(!ckey)
+ return FALSE
+ if(!selected_book.title || !selected_book.author || !length(selected_book.categories) || !length(selected_book.content))
+ return FALSE
+
+ if(!SSdbcore.IsConnected())
+ return FALSE
+
+ var/datum/library_user_data/search_terms = new()
+ search_terms.search_ckey = ckey
+ if(length(get_total_books(search_terms)) >= MAX_PLAYER_UPLOADS)
+ return FALSE
+
+ var/sql = {"INSERT INTO library (author, title, content, summary, primary_category, secondary_category, tertiary_category, ckey, raters, reports)
+ VALUES (:author, :title, :content, :summary, :primarycategory, :secondarycategory, :tertiarycategory, :ckey, :raters, :reports)"}
+
+ var/sql_params = list(
+ "author" = selected_book.author,
+ "title" = selected_book.title,
+ "content" = json_encode(selected_book.content),
+ "summary" = selected_book.summary ? selected_book.summary : "No Summary",
+ "primarycategory" = length(selected_book.categories) >= 1 ? selected_book.categories[1] : 0,
+ "secondarycategory" = length(selected_book.categories) >= 2 ? selected_book.categories[2] : 0,
+ "tertiarycategory" = length(selected_book.categories) >= 3 ? selected_book.categories[3] : 0,
+ "ckey" = ckey,
+ "raters" = " ", //Entry for both of these columns are NOT NULL
+ "reports" = " ", //so we need to provide an empty string val
+ )
+
+ var/datum/db_query/query = SSdbcore.NewQuery(sql, sql_params)
+
+ if(!query.warn_execute())
+ qdel(query)
+ return FALSE
+
+ qdel(query)
+ log_admin("[ckey] has uploaded the book titled [selected_book.title], [length(selected_book.content)] pages in length")
+ message_admins("[ckey] has uploaded the book titled [selected_book.title], [length(selected_book.content)] pages in length")
+ return TRUE
+
+/*
+ * # rate_book
+ *
+ * External proc that handles adding ratings to books in the DB. Will first get the ratings for the book from the DB
+ * and then rebuild the list/JSON for the ratings. It will also calculate the new average rating for the book.
+ * This proc will automatically clean out duplicate entries (2 or more ratings from the same ckey on 1 book), additionally,
+ * watch out for any user inputs that are not whole numbers/integers
+ *
+ * Arguments:
+ * * ckey - reviewer's ckey
+ * * bookid - SSID of the book being rated
+ * * user_rating - integer from 1 to 10
+ */
+/datum/library_catalog/proc/rate_book(ckey, bookid, user_rating)
+ if(!ckey || !bookid || !user_rating || !isnum(user_rating))
+ return
+ if(!SSdbcore.IsConnected())
+ return
+
+ var/list/current_ratings = get_book_ratings(bookid) // = [ratingInt, [[ckey, rating],[ckey, rating],[ckey, rating]]]
+ var/list/new_raters_info = list()
+ var/new_rating_value = round(user_rating, 1) //should only ever be a whole number
+
+ if(length(current_ratings)) //did get_book_ratings actually return something?
+ for(var/rating in current_ratings[2])
+ if(rating[1] == ckey)
+ continue //if your ckey has an existing rating, throw it out to make room for new one
+ new_raters_info += list(rating)
+ new_rating_value += rating[2]
+ else
+ current_ratings = list()
+
+ new_raters_info += list(list(ckey, user_rating)) //intentional
+ var/list/sql_params = list()
+ sql_params["id"] = bookid
+ //aggregate of ratings divided by total ratings to get average
+ var/new_calculated_average = new_rating_value / length(new_raters_info)
+ new_calculated_average = round(new_calculated_average, 0.1)
+ sql_params["newrating"] = new_calculated_average
+ sql_params["raters"] = json_encode(new_raters_info)
+
+ var/datum/db_query/query = SSdbcore.NewQuery("UPDATE library SET rating=:newrating, raters=:raters WHERE id=:id", sql_params)
+
+ if(!query.warn_execute())
+ qdel(query)
+ return
+ qdel(query)
+ return TRUE
+
+#undef DEFINE_CATEGORY
+#undef MAX_PLAYER_UPLOADS
+
+/* here be dragons~~~
+ __ _
+ _/ \ _(\(o
+ / \ / _ ^^^o
+ / ! \/ ! '!!!v'
+ ! ! \ _' ( \____
+ ! . \ _!\ \===^\)
+ \ \_! / __!
+ \! / \
+ (\_ _/ _\ )
+ \ ^^--^^ __-^ /(__
+ ^^----^^ "^--v'
+*/
diff --git a/code/modules/library/library_computer.dm b/code/modules/library/library_computer.dm
new file mode 100644
index 00000000000..a5f4e130938
--- /dev/null
+++ b/code/modules/library/library_computer.dm
@@ -0,0 +1,583 @@
+///Defines how many player books appear on the player book archive TGUI tab
+#define LIBRARY_BOOKS_PER_PAGE 25
+///Login state for our computer, this state grants full access to functions
+#define LOGIN_FULL 1
+///Login state for our computer, this state grants basic access to functions
+#define LOGIN_PUBLIC 2
+///Wait time before printing another book, used to prevent spam
+#define PRINTING_COOLDOWN (5 SECONDS)
+
+/**
+ * # Library Computer
+ *
+ * This is the player facing machine that handles all library functions
+ *
+ * This holds all procs for handling book checkins/checkout, book fines, book obj creation/modification
+ * the object also holds static lists for book inventory and checkouts. NO SQL CALLS OR QUERIES ARE MADE HERE, all
+ * of those are handled by the global library catalog that we will reference, and it should stay that way :)
+ */
+/obj/machinery/computer/library
+ name = "Library Computer"
+ anchored = TRUE
+ density = TRUE
+ icon_keyboard = null
+ icon_screen = "computer_on"
+ icon = 'icons/obj/library.dmi'
+ icon_state = "computer"
+
+ //We define a required access only to lock library specific actions like ordering/managing books to librarian access+
+ req_one_access = list(ACCESS_LIBRARY)
+ ///Page Number for going through player book archives
+ var/archive_page_num = 1
+ ///report category_id we have selected
+ var/selected_report
+ ///Total number of pages for the parameters have set for our booklist
+ var/num_pages = 0
+ ///total inventoried books, used for setting book library IDs
+ var/total_books = 0
+ ///list for storing player inputs and selections, helpful for cutting down on single variable declarations
+ var/datum/library_user_data/user_data = new()
+ ///This list temporarily stores the player books we grab from the DB in datums, we only update it when we need to for performance reasons
+ var/list/cached_booklist = list()
+ ///Static List of borrowbook datums, used to track book checkouts acrossed the library system
+ var/static/list/checkouts = list()
+ ///Static List of book datums to track what books the librarian has added to the library inventory
+ var/static/list/inventory = list()
+ ///How Long a book is allowed to be checked out for
+ var/checkoutperiod = 15 MINUTES
+ ///Wait period for printing books
+ var/print_cooldown = 5 SECONDS
+
+
+/obj/machinery/computer/library/Initialize(mapload)
+ . = ..()
+ populate_booklist(async = FALSE)
+ //since ui_data screws up when SQL calls are made inside it,
+ //we must populate our booklist before ui_act is called for the first time
+
+/obj/machinery/computer/library/attack_ai(mob/user)
+ return attack_hand(user)
+
+/obj/machinery/computer/library/attack_hand(mob/user)
+ if(..())
+ return
+ ui_interact(user)
+
+/obj/machinery/computer/library/attack_ghost(mob/user)
+ ui_interact(user)
+
+/obj/machinery/computer/library/attackby(obj/item/O, mob/user, params)
+ if(istype(O, /obj/item/book))
+ select_book(O)
+ return
+ if(istype(O, /obj/item/barcodescanner))
+ var/obj/item/barcodescanner/B = O
+ if(!B.connect(src))
+ playsound(src, 'sound/machines/synth_no.ogg', 15, TRUE)
+ to_chat(user, "ERROR: No Connection Established!")
+ return
+ to_chat(user, "Barcode Scanner Succesfully Connected to Computer.")
+ audible_message("[src] lets out a low, short blip.", hearing_distance = 2)
+ playsound(B, 'sound/machines/terminal_select.ogg', 10, TRUE)
+ return
+ if(istype(O, /obj/item/card/id))
+ var/obj/item/card/id/ID = O //at some point, this should be moved over to its own proc (select_patron()???)
+ if(ID.registered_name)
+ user_data.patron_name = ID.registered_name
+ else
+ user_data.patron_name = null
+ user_data.patron_account = null //account number should reset every scan so we don't accidently have an account number but no name
+ playsound(src, 'sound/machines/synth_no.ogg', 15, TRUE)
+ to_chat(user, "ERROR: No name detected!")
+ return //no point in continuing if the ID card has no associated name!
+ playsound(src, 'sound/items/scannerbeep.ogg', 15, TRUE)
+ if(ID.associated_account_number)
+ user_data.patron_account = ID.associated_account_number
+ else
+ user_data.patron_account = null
+ to_chat(user, "[src]'s screen flashes: 'WARNING! Patron without associated account number Selected'")
+ return
+ return ..()
+
+/obj/machinery/computer/library/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "LibraryComputer", name, 1050, 600, master_ui, state)
+ ui.open()
+
+/*
+ * # UI Data for TGUI
+ *
+ * Hey friends, this proc is where we stuff our massive amounts of data into our data list to be sent to our TGUI
+ * a few things about the library UI in specific, under no circumstance can any proc be called in ui_data that causes
+ * our code to sleep or wait, this will crash our TGUI interface upon first opening. This means you cannot call any of our
+ * procs that call a library_catalog proc that makes an SQL Query.
+ */
+/obj/machinery/computer/library/ui_data(mob/user)
+ var/list/data = list()
+
+ data["archive_pagenumber"] = archive_page_num
+ data["num_pages"] = num_pages
+ var/selected_categories = list()
+ selected_categories = user_data.search_categories
+
+ data["login_state"] = allowed(user)
+
+ data["searchcontent"] = list(
+ "title" = user_data.search_title,
+ "author" = user_data.search_author,
+ "ratingmin" = user_data.search_rating["min"],
+ "ratingmax" = user_data.search_rating["max"],
+ "categories" = selected_categories,
+ "ckey" = user_data.search_ckey,
+ )
+
+ var/list/selected_book_data = list(
+ "title" = user_data.selected_book.title ? user_data.selected_book.title : "not specified",
+ "author" = user_data.selected_book.author ? user_data.selected_book.author : "not specified",
+ "summary" = user_data.selected_book.summary ? user_data.selected_book.summary : "no summary",
+ "copyright" = user_data.selected_book.copyright ? user_data.selected_book.copyright : FALSE,
+ "categories" = user_data.selected_book.categories ? user_data.selected_book.categories : list()
+ )
+
+ data["selectedbook"] = selected_book_data
+
+ //should only be generating the cached booklist when we absolutely need to
+ data["external_booklist"] = cached_booklist
+ data["checkout_data"] = list()
+
+ for(var/datum/borrowbook/b in checkouts)
+ var/remaining_time = (b.duedate - world.time) / 600
+ var/late = FALSE
+ if(remaining_time <= 0) //if remaining time is less than zero, you're late
+ late = TRUE
+ remaining_time = round(remaining_time)
+
+ var/list/checkout_data = list(
+ "timeleft" = remaining_time,
+ "islate" = late,
+ "title" = b.bookname,
+ "libraryid" = b.libraryid,
+ "patron_name" = b.patron_name
+ )
+ data["checkout_data"] += list(checkout_data)
+
+ data["inventory_list"] = list()
+ for(var/book in inventory)
+ var/checked_out = FALSE
+ var/datum/cachedbook/CB = book
+ for(var/datum/borrowbook/checkout in checkouts)
+ if(CB.libraryid == checkout.libraryid)
+ checked_out = TRUE
+ break
+ var/list/book_data = list(
+ "title" = CB.title ? CB.title : "not specified",
+ "author" = CB.author ? CB.author : "not specified",
+ "summary" = CB.summary ? CB.summary : "no summary",
+ "id" = CB.id,
+ "libraryid" = CB.libraryid,
+ "checked_out" = checked_out,
+ )
+ data["inventory_list"] += list(book_data)
+ data["user_ckey"] = user?.ckey
+ data["selected_report"] = selected_report
+ data["selected_rating"] = user_data.selected_rating
+ data["modal"] = ui_modal_data(src)
+
+ return data
+
+/obj/machinery/computer/library/ui_static_data(mob/user)
+ var/list/static_data = list()
+ //Book Categories will never change within a round so they don't need to sent more than once
+ static_data["book_categories"] = list()
+ for(var/datum/library_category/category in GLOB.library_catalog.categories)
+ var/category_info = list(
+ "category_id" = category.category_id,
+ "description" = category.description,
+ )
+ static_data["book_categories"] += list(category_info)
+
+ //Report Categories will never change within a round so they don't need to sent more than once
+ static_data["report_categories"] = list()
+ for(var/r in GLOB.library_catalog.report_types)
+ var/datum/library_category/report = r
+ var/report_info = list(
+ "category_id" = report.category_id,
+ "description" = report.description,
+ )
+ static_data["report_categories"] += list(report_info)
+
+ static_data["programmatic_booklist"] = list()
+ for(var/book in GLOB.library_catalog.books)
+ var/datum/programmatic_book/PB = book
+ var/list/book_data = list(
+ "title" = PB.title ? PB.title : "not specified",
+ "author "= PB.author ? PB.author : "Nanotrasen",
+ "id" = PB.id,
+ )
+ static_data["programmatic_booklist"] += list(book_data)
+
+ return static_data
+
+/obj/machinery/computer/library/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ if(..())
+ return
+
+ if(ui_act_modal(action, params))
+ return
+
+ add_fingerprint(usr)
+
+ switch(action)
+ //Page Switching
+ if("incrementpage")
+ archive_page_num = clamp(archive_page_num + 1, 1, num_pages)
+ populate_booklist()
+ if("incrementpagemax")
+ archive_page_num = num_pages
+ populate_booklist()
+ if("deincrementpage")
+ archive_page_num = clamp(archive_page_num - 1, 1, num_pages)
+ populate_booklist()
+ if("deincrementpagemax")
+ archive_page_num = 1
+ populate_booklist()
+ //Search Tools' Buttons
+ if("toggle_search_category")
+ var/category_id = text2num(params["category_id"])
+ if(category_id in user_data.search_categories)
+ user_data.search_categories -= category_id
+ populate_booklist()
+ else
+ user_data.search_categories += category_id
+ populate_booklist()
+ if("clear_search")
+ user_data.clear_search()
+ populate_booklist()
+ if("find_users_books")
+ user_data.clear_search() //we need to clear out other search params first
+ user_data.search_ckey = params["user_ckey"]
+ populate_booklist()
+ if("clear_ckey_search")
+ user_data.search_ckey = null
+ populate_booklist()
+
+ //Order Buttons
+ if("order_external_book")
+ var/datum/cachedbook/orderedbook = GLOB.library_catalog.get_book_by_id(params["bookid"])
+ if(orderedbook && print_cooldown <= world.time)
+ make_external_book(orderedbook)
+ print_cooldown = world.time + PRINTING_COOLDOWN
+ if("order_programmatic_book")
+ var/datum/programmatic_book/PB = GLOB.library_catalog.get_programmatic_book_by_id(params["bookid"])
+ if(PB && print_cooldown <= world.time)
+ make_programmatic_book(PB)
+ print_cooldown = world.time + PRINTING_COOLDOWN
+ //book author actions
+ if("delete_book")
+ if(params["bookid"])
+ var/datum/cachedbook/selectedbook = GLOB.library_catalog.get_book_by_id(params["bookid"])
+ if(!selectedbook)
+ playsound(src, 'sound/machines/synth_no.ogg', 15, TRUE)
+ atom_say("Deletion Failed!")
+ return
+ if(selectedbook.ckey != params["user_ckey"])
+ message_admins("[params["user_ckey"]] attempted to delete a book that wasn't theirs, this shouldn't happen, please investigate.")
+ return
+ if(GLOB.library_catalog.remove_book_by_id(params["bookid"])) //this doesn't need to be logged
+ playsound(loc, 'sound/machines/ping.ogg', 25, 0)
+ atom_say("Deletion Succesful!")
+ return
+ playsound(src, 'sound/machines/synth_no.ogg', 15, TRUE)
+ atom_say("Deletion Failed!")
+
+
+ //rating acts
+ if("set_rating")
+ if(params["rating_value"])
+ user_data.selected_rating = text2num(params["rating_value"])
+ if("rate_book")
+ if(GLOB.library_catalog.rate_book(params["user_ckey"], params["bookid"], user_data.selected_rating))
+ playsound(loc, 'sound/machines/ping.ogg', 25, 0)
+ atom_say("Rating Succesful!")
+ populate_booklist()
+ //Report Acts
+ if("submit_report")
+ if(GLOB.library_catalog.flag_book_by_id(params["user_ckey"], params["bookid"], selected_report))
+ playsound(loc, 'sound/machines/ping.ogg', 50, 0)
+ atom_say("Report Submitted!")
+ return
+ playsound(src, 'sound/machines/synth_no.ogg', 15, TRUE)
+ atom_say("Report Submission Failed!")
+ if("set_report")
+ selected_report = text2num(params["report_type"])
+ //Book Uploader
+ if("toggle_upload_category")
+ if(text2num(params["category_id"]) in user_data.selected_book.categories)
+ user_data.selected_book.categories -= text2num(params["category_id"])
+ populate_booklist()
+ else
+ if(length(user_data.selected_book.categories) >= 3)
+ playsound(src, 'sound/machines/synth_no.ogg', 15, TRUE)
+ return
+ user_data.selected_book.categories += text2num(params["category_id"])
+ populate_booklist()
+ if("uploadbook")
+ if(GLOB.library_catalog.upload_book(params["user_ckey"], user_data.selected_book))
+ playsound(src, 'sound/machines/ping.ogg', 50, 0)
+ atom_say("Book Uploaded!")
+ return
+ playsound(src, 'sound/machines/synth_no.ogg', 15, TRUE)
+ atom_say("Book Upload Failed!")
+ num_pages = getmaxpages()
+ if("reportlost")
+ inventoryRemove(text2num(params["libraryid"]))
+ for(var/datum/borrowbook/book in checkouts)
+ if(book.libraryid == text2num(params["libraryid"]))
+ checkouts -= book
+
+
+/obj/machinery/computer/library/proc/ui_act_modal(action, list/params)
+ . = TRUE
+ var/id = params["id"] // The modal's ID
+ var/list/arguments = istext(params["arguments"]) ? json_decode(params["arguments"]) : params["arguments"]
+ switch(ui_modal_act(src, action, params))
+ if(UI_MODAL_OPEN)
+ switch(id)
+ if("setpagenumber")
+ ui_modal_input(src, id, "Please input a page number:", null, arguments, archive_page_num)
+ //search inputs
+ if("edit_search_title")
+ ui_modal_input(src, id, "Please input the new title:", null, arguments, user_data.search_title)
+ if("edit_search_author")
+ ui_modal_input(src, id, "Please input the new author:", null, arguments, user_data.search_author)
+ if("edit_search_ratingmax")
+ ui_modal_input(src, id, "Please input the new upper rating bound:", null, arguments, user_data.search_rating["max"])
+ if("edit_search_ratingmin")
+ ui_modal_input(src, id, "Please input the new lower rating bound:", null, arguments, user_data.search_rating["min"])
+ //book uploader inputs
+ if("edit_selected_title")
+ ui_modal_input(src, id, "Please input the new title:", null, arguments, user_data.selected_book.title)
+ if("edit_selected_author")
+ ui_modal_input(src, id, "Please input the new author:", null, arguments, user_data.selected_book.author)
+ if("edit_selected_summary")
+ ui_modal_input(src, id, "Please input the new summary:", null, arguments, user_data.selected_book.summary)
+ //book list buttons
+ if("expand_info")
+ var/datum/programmatic_book/PB = GLOB.library_catalog.get_programmatic_book_by_id(arguments["bookid"])
+ if(PB)
+ ui_modal_message(src, id, "", arguments = list(
+ "isProgrammatic" = TRUE,
+ "title" = PB.title,
+ "author" = PB.author,
+ "summary" = PB.summary ? PB.summary : "No Summary Provided",
+ "rating" = "N for Nanotrasen",
+ ))
+
+ return //If we've succesfully opened the modal for our programmatic book, we don't need to do more logic
+ var/datum/cachedbook/CB = GLOB.library_catalog.get_book_by_id(arguments["bookid"])
+ if(CB)
+ var/category_names = list()
+ for(var/datum/library_category/category in CB.categories)
+ category_names += category.description
+ user_data.selected_report = null
+ user_data.selected_rating = 0
+
+ ui_modal_message(src, id, "", arguments = list(
+ "isProgrammatic" = FALSE,
+ "id" = CB.id,
+ "ckey" = CB.ckey,
+ "title" = CB.title,
+ "author" = CB.author,
+ "summary" = CB.summary ? CB.summary : "No Summary Provided",
+ "rating" = CB.rating ? CB.rating : 0,
+ "categories" = category_names,
+ ))
+ if("report_book")
+ var/datum/cachedbook/CB = GLOB.library_catalog.get_book_by_id(arguments["bookid"])
+ ui_modal_message(src, id, "", arguments = list(
+ id = CB.id,
+ title = CB.title,
+ ckey = CB.ckey,
+ ))
+ if("rate_info")
+ var/datum/cachedbook/CB = GLOB.library_catalog.get_book_by_id(arguments["bookid"])
+ var/list/book_ratings = GLOB.library_catalog.get_book_ratings(arguments["bookid"])
+ ui_modal_message(src, id, "", arguments = list(
+ "id" = CB.id,
+ "title" = CB.title,
+ "author" = CB.author,
+ "ckey" = CB.ckey,
+ "current_rating" = length(book_ratings) ? book_ratings[1] : 0,
+ "total_ratings" = length(book_ratings) ? length(book_ratings[2]) : 0,
+ ))
+ else
+ return FALSE
+ if(UI_MODAL_ANSWER)
+ var/answer = sanitize(params["answer"]) //xss attacks bad
+ switch(id)
+ if("edit_search_title")
+ if(!length(answer))
+ user_data.search_title = null
+ populate_booklist()
+ return
+ if(length(answer) >= MAX_NAME_LEN)
+ return
+ user_data.search_title = answer
+ populate_booklist()
+ if("edit_search_author")
+ if(!length(answer))
+ user_data.search_author = null
+ populate_booklist()
+ return
+ if(length(answer) >= MAX_NAME_LEN)
+ return
+ user_data.search_author = answer
+ populate_booklist()
+ if("edit_search_ratingmax")
+ if(!text2num(answer))
+ return
+ user_data.search_rating["max"] = clamp(text2num(answer), user_data.search_rating["min"], 10)
+ populate_booklist()
+ if("edit_search_ratingmin")
+ if(!text2num(answer))
+ return
+ user_data.search_rating["min"] = clamp(text2num(answer), 0, user_data.search_rating["max"])
+ populate_booklist()
+ if("edit_selected_title")
+ if(length(answer) >= MAX_NAME_LEN)
+ return
+ user_data.selected_book.title = answer
+ if("edit_selected_author")
+ if(length(answer) >= MAX_NAME_LEN)
+ return
+ user_data.selected_book.author = answer
+ if("edit_selected_summary")
+ if(length(answer) >= MAX_SUMMARY_LEN)
+ return
+ user_data.selected_book.summary = answer
+ if("setpagenumber")
+ if(!text2num(answer))
+ return
+ archive_page_num = clamp(text2num(answer), 1, getmaxpages())
+ populate_booklist()
+ else
+ return FALSE
+ else
+ return FALSE
+
+/obj/machinery/computer/library/proc/select_book(obj/item/book/B)
+ if(B.carved == TRUE)
+ return
+ user_data.selected_book.title = B.title ? B.title : "No Title"
+ user_data.selected_book.author = B.author ? B.author : "No Author"
+ user_data.selected_book.summary = B.summary ? B.summary : "No Summary"
+ user_data.selected_book.copyright = B.copyright ? B.copyright : FALSE
+ user_data.selected_book.content = B.pages ? B.pages : list()
+ user_data.selected_book.categories = B.categories ? B.categories : list()
+
+/obj/machinery/computer/library/proc/inventoryAdd(obj/item/book/B) //add book to library inventory
+ for(var/datum/cachedbook/I in inventory)
+ if(I.libraryid == B.libraryid)
+ return FALSE
+ if(!B.libraryid)
+ total_books++
+ B.libraryid = total_books
+ var/datum/cachedbook/CB = new()
+ CB.serialize_book(B)
+ if(!CB)
+ return
+ inventory.Add(CB)
+ return TRUE
+
+/obj/machinery/computer/library/proc/inventoryRemove(libraryID) //remove book from library inventory
+ for(var/datum/cachedbook/O in inventory)
+ if(O.libraryid == libraryID)
+ inventory.Remove(O)
+ return TRUE
+ return FALSE
+
+/obj/machinery/computer/library/proc/checkout(obj/item/book/B) //checkout book
+ if(!B.libraryid || !user_data.patron_name) //If book isn't a library book or there isn't a selected patron: return
+ return FALSE
+ for(var/datum/borrowbook/O in checkouts) //is this book already checked out?
+ if(O.libraryid == B.libraryid)
+ return FALSE
+ var/datum/borrowbook/P = new /datum/borrowbook
+ P.bookname = sanitize(B.title)
+ P.libraryid = B.libraryid
+ P.patron_name = sanitize(user_data.patron_name)
+ P.patron_account = sanitize(user_data.patron_account)
+ P.duedate = world.time + (checkoutperiod)
+ checkouts.Add(P)
+ return TRUE
+
+/obj/machinery/computer/library/proc/checkin(obj/item/book/B) //check back in a book
+ if(!B.libraryid)
+ return FALSE
+ for(var/datum/borrowbook/O in checkouts) //is this book checked out?
+ if(O.libraryid == B.libraryid)
+ checkouts.Remove(O)
+ return TRUE
+ return FALSE
+
+/*
+ * # populate_booklist
+ *
+ * internal proc that will refresh our cached booklist, it needs to be called everytime we are switching parameters
+ * that will affect what books will be displayed in our TGUI player book archive.
+ */
+/obj/machinery/computer/library/proc/populate_booklist(async = TRUE)
+ cached_booklist = list() //clear old list
+ var/starting_book = (archive_page_num - 1) * LIBRARY_BOOKS_PER_PAGE
+ var/range = LIBRARY_BOOKS_PER_PAGE
+ for(var/datum/cachedbook/CB in GLOB.library_catalog.get_book_by_range(starting_book, range, user_data, async))
+ //instead of just adding the datum to the cached_booklist, we want to make it an assoc list so we can just give it to the TGUI
+
+ var/list/book_data = list(
+ "id" = CB.id,
+ "title" = CB.title,
+ "author" = CB.author,
+ "rating" = CB.rating,
+ "summary" = CB.summary,
+ "ckey" = CB.ckey,
+ "reports" = CB.reports,
+ )
+ book_data["categories"] = list()
+ for(var/category in CB.categories)
+ var/datum/library_category/book_category = GLOB.library_catalog.get_book_category_by_id(category)
+ if(book_category)
+ book_data["categories"] += book_category.description //we're displaying the cats onlys, so we don't need the ids
+
+ cached_booklist += list(book_data)
+ num_pages = getmaxpages()
+ archive_page_num = clamp(archive_page_num, 1, num_pages)
+
+///Returns the amount of pages we will need to hold all the book our DB has found
+/obj/machinery/computer/library/proc/getmaxpages()
+ //if get_total_books doesn't return anything, just set pages to 1 so we don't break stuff
+ var/book_count = max(1, GLOB.library_catalog.get_total_books(user_data))
+ var/page_count = round(book_count / LIBRARY_BOOKS_PER_PAGE)
+ //Since 'round' gets the floor value it's likely there will be 1 page more than
+ //the page count amount (almost guaranteed), we check for a remainder because of this
+ if(book_count % LIBRARY_BOOKS_PER_PAGE)
+ page_count++
+ return page_count
+
+/obj/machinery/computer/library/proc/make_external_book(datum/cachedbook/newbook)
+ if(!newbook?.id)
+ return
+ new /obj/item/book(loc, newbook, TRUE, FALSE)
+ visible_message("[src]'s printer hums as it produces a completely bound book. How did it do that?")
+
+/obj/machinery/computer/library/proc/make_programmatic_book(datum/programmatic_book/newbook)
+ if(!newbook?.book_type)
+ return
+
+ new newbook.book_type(loc)
+ visible_message("[src]'s printer hums as it produces a completely bound book. How did it do that?")
+
+#undef LIBRARY_BOOKS_PER_PAGE
+#undef LOGIN_FULL
+#undef LOGIN_PUBLIC
+#undef PRINTING_COOLDOWN
diff --git a/code/modules/library/library_datums.dm b/code/modules/library/library_datums.dm
new file mode 100644
index 00000000000..8d191870b26
--- /dev/null
+++ b/code/modules/library/library_datums.dm
@@ -0,0 +1,134 @@
+
+/*
+ * # Library User Data Datum
+ *
+ * Because facilitating an entire library system that needs to be able to search a DB + move lots and lots of data
+ * the temporary data used for functions has been condensed into a single datum
+ */
+/datum/library_user_data
+ var/search_title
+ var/search_author
+ var/search_ckey
+ var/search_rating = list(
+ "min" = 0,
+ "max" = 10,
+ )
+ var/search_categories = list()
+ var/selected_rating = 0
+ var/patron_name
+ var/patron_account
+ var/datum/cachedbook/selected_book = new()
+ var/datum/library_category/selected_report
+
+/datum/library_user_data/proc/clear_search()
+ search_title = null
+ search_author = null
+ search_ckey = null
+ search_rating["min"] = 0
+ search_rating["max"] = 10
+ search_categories = list()
+
+/*
+ * # Borrowbook datum
+ *
+ * Used for tracking books that have been checked out from the library by players. Created and stored upon a book being
+ * checked out and deleted upon the book being succesfully checked back in or the librarian marking a book as "lost"
+ */
+/datum/borrowbook // Datum used to keep track of who has borrowed what when and for how long.
+ var/bookname
+ var/libraryid
+ var/patron_name
+ var/patron_account //Patron's Account ID, used for deducting $credits$ from their account
+ var/duedate
+
+/*
+ * # Cachedbook datum
+ *
+ * Used for holding book data sourced from the Database in limbo to be used whenever the library computer needs it, these
+ * are designed to only temporarily hold book data
+ * checked out and deleted upon the book being succesfully checked back in or the librarian marking a book as "lost"
+ */
+/datum/cachedbook // Datum used to cache the SQL DB books locally in order to achieve a performance gain.
+ var/id
+ var/libraryid
+ var/title
+ var/list/content = list()
+ var/summary
+ var/author
+ var/rating
+ var/copyright
+ var/ckey //administrative tracking/tooling purposes
+ var/list/categories = list()
+ var/reports = list()
+
+///helper proc to turn our returned query rows into a cachedbook datum
+/datum/cachedbook/proc/LoadFromRow(list/row)
+ id = row["id"]
+ author = row["author"]
+ title = row["title"]
+ content = json_decode(row["content"])
+ summary = row["summary"]
+ rating = row["rating"]
+ if(text2num(row["primary_category"]))
+ categories += text2num(row["primary_category"])
+ if(text2num(row["primary_category"]))
+ categories += text2num(row["secondary_category"])
+ if(text2num(row["primary_category"]))
+ categories += text2num(row["tertiary_category"])
+ ckey = row["ckey"]
+ var/list/reports_json = list()
+ if(length(row["reports"]) > 5) //do we actually have a string with content??
+ reports_json = json_decode(row["reports"])
+ for(var/r in reports_json)
+ var/datum/library_category/report_category = GLOB.library_catalog.get_report_category_by_id(r[2])
+ var/datum/flagged_book/report = new()
+ report.bookid = id
+ report.category_id = report_category.category_id
+ report.reporter = r[1]
+ reports += report
+
+/datum/cachedbook/proc/serialize_book(obj/item/book/B)
+ title = B.title ? B.title : "Unnamed"
+ author = B.author ? B.author : "Anonymous"
+ if(length(B.pages)) //just incase we run a book with no pages
+ content = B.pages
+ else
+ content = list()
+ summary = B.summary ? B.summary : "No summary provided"
+ rating = B.rating ? B.rating : 0
+ copyright = B.copyright ? B.copyright : FALSE
+ libraryid = B.libraryid
+
+/*
+ * # Programmaticbook datum
+ *
+ * Used for holding book data from books that have been "hardcoded" such as manuals.
+ */
+/datum/programmatic_book
+ var/id
+ var/title
+ var/author
+ var/book_type
+ var/summary
+
+/datum/flagged_book
+ ///book id of the book this flag is attached to
+ var/bookid
+ ///The ckey of the player who reported it
+ var/reporter
+ ///the id of the report category
+ var/category_id
+
+/*
+ * # library_category datum
+ *
+ * Used for storing information about library categories. This is used both for "book categories" like genre/purpose
+ * and also for defining OOC Report types to facilitate the reporting and deleting of bad books
+ */
+/datum/library_category
+ var/category_id
+ var/description //The front-facing text that the user sees
+
+/datum/library_category/New(_category_id, _description)
+ category_id = _category_id
+ description = _description
diff --git a/code/modules/library/library_equipment.dm b/code/modules/library/library_equipment.dm
new file mode 100644
index 00000000000..f1d8af05c65
--- /dev/null
+++ b/code/modules/library/library_equipment.dm
@@ -0,0 +1,424 @@
+#define BARCODE_MODE_SCAN_SELECT 1
+#define BARCODE_MODE_SCAN_INVENTORY 2
+#define BARCODE_MODE_CHECKOUT 3
+#define BARCODE_MODE_CHECKIN 4
+
+/*
+ * Bookcase
+ */
+
+/obj/structure/bookcase
+ name = "bookcase"
+ icon = 'icons/obj/library.dmi'
+ icon_state = "bookshelf-0"
+ anchored = TRUE
+ density = TRUE
+ opacity = TRUE
+ resistance_flags = FLAMMABLE
+ max_integrity = 200
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 0)
+ var/list/allowed_books = list(/obj/item/book, /obj/item/spellbook, /obj/item/storage/bible, /obj/item/tome) //Things allowed in the bookcase
+
+/obj/structure/bookcase/attackby(obj/item/O, mob/user)
+ if(is_type_in_list(O, allowed_books))
+ if(!user.drop_item())
+ return
+ O.forceMove(src)
+ update_icon()
+ return TRUE
+ if(istype(O, /obj/item/storage/bag/books))
+ var/obj/item/storage/bag/books/B = O
+ for(var/obj/item/T in B.contents)
+ if(is_type_in_list(T, allowed_books))
+ B.remove_from_storage(T, src)
+ to_chat(user, "You empty [O] into [src].")
+ update_icon()
+ return TRUE
+ if(istype(O, /obj/item/pen))
+ rename_interactive(user, O)
+ return TRUE
+
+ return ..()
+
+/obj/structure/bookcase/attack_hand(mob/user)
+ if(!length(contents))
+ return
+
+ var/obj/item/book/choice = input(user, "Which book would you like to remove from [src]?") as null|anything in contents
+ if(!choice)
+ return
+ if(user.incapacitated() || !Adjacent(user))
+ return
+ if(!user.get_active_hand())
+ user.put_in_hands(choice)
+ else
+ choice.forceMove(get_turf(src))
+ update_icon()
+
+/obj/structure/bookcase/deconstruct(disassembled = TRUE)
+ new /obj/item/stack/sheet/wood(loc, 5)
+ for(var/obj/item/I in contents)
+ if(is_type_in_list(I, allowed_books))
+ I.forceMove(get_turf(src))
+ ..()
+
+/obj/structure/bookcase/update_icon()
+ icon_state = "bookshelf-[min(length(contents), 5)]"
+
+
+/obj/structure/bookcase/screwdriver_act(mob/user, obj/item/I)
+ if(flags & NODECONSTRUCT)
+ return
+ . = TRUE
+ if(!I.tool_use_check(user, 0))
+ return
+ TOOL_ATTEMPT_DISMANTLE_MESSAGE
+ if(!I.use_tool(src, user, 20, volume = I.tool_volume))
+ return
+ TOOL_DISMANTLE_SUCCESS_MESSAGE
+ deconstruct(TRUE)
+
+/obj/structure/bookcase/wrench_act(mob/user, obj/item/I)
+ . = TRUE
+
+ default_unfasten_wrench(user, I, 0)
+
+/obj/structure/bookcase/manuals/medical
+ name = "Medical Manuals bookcase"
+
+/obj/structure/bookcase/manuals/medical/Initialize()
+ . = ..()
+ new /obj/item/book/manual/medical_cloning(src)
+ update_icon()
+
+
+/obj/structure/bookcase/manuals/engineering
+ name = "Engineering Manuals bookcase"
+
+/obj/structure/bookcase/manuals/engineering/Initialize()
+ . = ..()
+ new /obj/item/book/manual/wiki/engineering_construction(src)
+ new /obj/item/book/manual/engineering_particle_accelerator(src)
+ new /obj/item/book/manual/wiki/hacking(src)
+ new /obj/item/book/manual/wiki/engineering_guide(src)
+ new /obj/item/book/manual/engineering_singularity_safety(src)
+ new /obj/item/book/manual/wiki/robotics_cyborgs(src)
+ update_icon()
+
+/obj/structure/bookcase/manuals/research_and_development
+ name = "R&D Manuals bookcase"
+
+/obj/structure/bookcase/manuals/research_and_development/Initialize()
+ . = ..()
+ new /obj/item/book/manual/research_and_development(src)
+ update_icon()
+
+/obj/structure/bookcase/sop
+ name = "bookcase (Standard Operating Procedures)"
+
+/obj/structure/bookcase/sop/Initialize()
+ . = ..()
+ new /obj/item/book/manual/wiki/sop_command(src)
+ new /obj/item/book/manual/wiki/sop_engineering(src)
+ new /obj/item/book/manual/wiki/sop_general(src)
+ new /obj/item/book/manual/wiki/sop_legal(src)
+ new /obj/item/book/manual/wiki/sop_medical(src)
+ new /obj/item/book/manual/wiki/sop_science(src)
+ new /obj/item/book/manual/wiki/sop_security(src)
+ new /obj/item/book/manual/wiki/sop_service(src)
+ new /obj/item/book/manual/wiki/sop_supply(src)
+ update_icon()
+
+/obj/structure/bookcase/random
+ var/category = null
+ var/book_count = 5
+ icon_state = "random_bookcase"
+ anchored = TRUE
+
+/obj/structure/bookcase/random/Initialize(mapload)
+ . = ..()
+ var/list/books = GLOB.library_catalog.get_random_book(book_count, doAsync = FALSE)
+ for(var/datum/cachedbook/book as anything in books)
+ new /obj/item/book(src, book, TRUE, FALSE)
+ update_icon()
+
+/*
+ * Book binder
+ */
+/obj/machinery/bookbinder
+ name = "Book Binder"
+ icon = 'icons/obj/library.dmi'
+ icon_state = "binder"
+ anchored = TRUE
+ density = TRUE
+
+ var/datum/cachedbook/selected_content = new()
+ var/printing = FALSE
+
+/obj/machinery/bookbinder/attack_ai(mob/user)
+ return attack_hand(user)
+
+/obj/machinery/bookbinder/attack_hand(mob/user)
+ if(..())
+ return
+ ui_interact(user)
+
+/obj/machinery/bookbinder/attack_ghost(mob/user)
+ ui_interact(user)
+
+/obj/machinery/bookbinder/wrench_act(mob/living/user, obj/item/I)
+ . = ..()
+ if(default_unfasten_wrench(user, I))
+ power_change()
+
+/obj/machinery/bookbinder/attackby(obj/item/I, mob/user)
+ if(istype(I, /obj/item/paper))
+ select_paper(I)
+ if(istype(I, /obj/item/paper_bundle))
+ select_paper_stack(I)
+ if(istype(I, /obj/item/book))
+ select_book(I)
+ else
+ return ..()
+
+/obj/machinery/bookbinder/proc/select_paper(obj/item/paper/P)
+ selected_content.title = P.name
+ selected_content.author = null
+ selected_content.content = list(P.info)
+
+/obj/machinery/bookbinder/proc/select_paper_stack(obj/item/paper_bundle/P)
+ selected_content.title = P.name
+ selected_content.author = null
+ selected_content.content = list()
+ for(var/obj/item/paper/I in P.contents)
+ selected_content.content += I.info
+
+/obj/machinery/bookbinder/proc/select_book(obj/item/book/B)
+ if(!B || B.protected || B.carved)
+ return
+ selected_content.title = B.title
+ selected_content.author = B.author
+ selected_content.author = B.summary
+ selected_content.content = B.pages
+ for(var/c in B.categories)
+ if(c)
+ selected_content.categories += c
+
+/obj/machinery/bookbinder/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "BookBinder", name, 700, 400, master_ui, state)
+ ui.open()
+
+/obj/machinery/bookbinder/ui_data(mob/user)
+ var/list/data = list()
+
+ var/list/selected_book_data = list(
+ "title" = selected_content.title ? selected_content.title : "not specified",
+ "author" = selected_content.author ? selected_content.author : "not specified",
+ "summary" = selected_content.summary ? selected_content.summary : "no summary",
+ "copyright" = selected_content.copyright ? selected_content.copyright : FALSE,
+ "categories" = selected_content.categories ? selected_content.categories : list()
+ )
+ data["selectedbook"] = selected_book_data
+ data["modal"] = ui_modal_data(src)
+ return data
+
+/obj/machinery/bookbinder/ui_static_data(mob/user)
+ var/list/static_data = list()
+
+ static_data["book_categories"] = list()
+ for(var/datum/library_category/category in GLOB.library_catalog.categories)
+ var/category_info = list(
+ "category_id" = category.category_id,
+ "description" = category.description,
+ )
+ static_data["book_categories"] += list(category_info)
+
+ return static_data
+
+/obj/machinery/bookbinder/ui_act(action, list/params, datum/tgui/ui)
+ if(..())
+ return
+
+ if(ui_act_modal(action, params))
+ return
+
+ add_fingerprint(ui.user)
+
+ switch(action)
+ if("print_book")
+ if(!printing)
+ printing = TRUE
+ visible_message("[src] begins to hum as it warms up its printing drums.")
+ addtimer(CALLBACK(src, .proc/print_book), 5 SECONDS)
+ else
+ playsound(src, 'sound/machines/synth_no.ogg', 15, TRUE)
+ if("toggle_binder_category")
+ var/category_id = text2num(params["category_id"])
+ if(category_id in selected_content.categories)
+ selected_content.categories -= category_id
+ else
+ if(length(selected_content.categories) >= 3)
+ playsound(src, 'sound/machines/synth_no.ogg', 15, TRUE)
+ return
+ selected_content.categories += category_id
+
+/obj/machinery/bookbinder/proc/ui_act_modal(action, list/params)
+ . = TRUE
+ var/id = params["id"] // The modal's ID
+ var/list/arguments = istext(params["arguments"]) ? json_decode(params["arguments"]) : params["arguments"]
+ switch(ui_modal_act(src, action, params))
+ if(UI_MODAL_OPEN)
+ switch(id)
+ if("edit_selected_title")
+ ui_modal_input(src, id, "Please input the new title:", null, arguments, selected_content.title)
+ if("edit_selected_author")
+ ui_modal_input(src, id, "Please input the new author:", null, arguments, selected_content.author)
+ if("edit_selected_summary")
+ ui_modal_input(src, id, "Please input the new summary:", null, arguments, selected_content.summary)
+ else
+ return FALSE
+ if(UI_MODAL_ANSWER)
+ var/answer = params["answer"]
+ switch(id)
+ if("edit_selected_title")
+ if(length(answer) >= MAX_NAME_LEN)
+ return
+ selected_content.title = strip_html(answer)
+ if("edit_selected_author")
+ if(length(answer) >= MAX_NAME_LEN)
+ return
+ selected_content.author = strip_html(answer)
+ if("edit_selected_summary")
+ if(length(answer) >= MAX_SUMMARY_LEN)
+ return
+ selected_content.summary = strip_html(answer)
+ else
+ return FALSE
+ else
+ return FALSE
+
+/obj/machinery/bookbinder/proc/print_book()
+ visible_message("[src] whirs as it prints and binds a new book.")
+ new /obj/item/book(loc, selected_content, FALSE, FALSE)
+ printing = FALSE
+
+/*
+ * Barcode Scanner
+ */
+/obj/item/barcodescanner
+ name = "barcode scanner"
+ desc = "A scanner used for managing library books, one can connect it the library system by tapping on a computer with it in hand."
+ icon = 'icons/obj/library.dmi'
+ icon_state ="scanner"
+ throw_speed = 1
+ throw_range = 5
+ w_class = WEIGHT_CLASS_TINY
+ var/list/modes = list(BARCODE_MODE_SCAN_SELECT, BARCODE_MODE_SCAN_INVENTORY, BARCODE_MODE_CHECKOUT, BARCODE_MODE_CHECKIN)
+ /// Associated Library Computer, needed to perform actions
+ var/obj/machinery/computer/library/computer
+ var/mode = BARCODE_MODE_SCAN_SELECT
+
+/obj/item/barcodescanner/attack_self(mob/user)
+ if(!check_connection(user))
+ return
+ mode++
+ if(mode > length(modes))
+ mode = modes[1]
+ var/modedesc
+ switch(mode)
+ if(BARCODE_MODE_SCAN_SELECT)
+ modedesc = "Scan book to computer."
+ if(BARCODE_MODE_SCAN_INVENTORY)
+ modedesc = "Scan book into to general inventory."
+ if(BARCODE_MODE_CHECKOUT)
+ modedesc = "Checkout Book"
+ if(BARCODE_MODE_CHECKIN)
+ modedesc = "Checkin Book"
+ else
+ modedesc = "ERROR"
+ playsound(src, 'sound/machines/terminal_select.ogg', 15, TRUE)
+ to_chat(user, "[src] mode: [modedesc]")
+
+/obj/item/barcodescanner/proc/connect(obj/machinery/computer/library/library_computer)
+ if(!istype(library_computer))
+ return FALSE
+ if(computer == library_computer)
+ return TRUE //we're succesfully connected already, let player know it was a "succesful connection"
+
+ UnregisterSignal(computer, COMSIG_PARENT_QDELETING)
+ computer = library_computer
+ RegisterSignal(library_computer, COMSIG_PARENT_QDELETING, .proc/disconnect)
+ return TRUE
+
+/obj/item/barcodescanner/proc/disconnect()
+ computer = null
+
+/obj/item/barcodescanner/proc/scanID(obj/item/card/id/ID, mob/user)
+ if(!check_connection(user))
+ return
+
+ if(!ID.registered_name)
+ computer.user_data.patron_name = null
+ computer.user_data.patron_account = null //account number should reset every scan so we don't accidently have an account number but no name
+ playsound(src, 'sound/machines/synth_no.ogg', 15, TRUE)
+ to_chat(user, "[src]'s screen flashes: 'ERROR! No name associated with this ID Card'")
+ return //no point in continuing if the ID card has no associated name!
+
+ computer.user_data.patron_name = ID.registered_name
+ playsound(src, 'sound/items/scannerbeep.ogg', 15, TRUE)
+ if(!ID.associated_account_number)
+ computer.user_data.patron_account = null
+ to_chat(user, "[src]'s screen flashes: 'WARNING! Patron without associated account number Selected'")
+ return
+
+ computer.user_data.patron_account = ID.associated_account_number
+ to_chat(user, "[src]'s screen flashes: 'Patron Selected'")
+
+/obj/item/barcodescanner/proc/scanBook(obj/item/book/B, mob/user as mob)
+ if(!check_connection(user))
+ return
+
+ switch(mode)
+ if(BARCODE_MODE_SCAN_SELECT)
+ computer.select_book(B)
+ playsound(src, 'sound/machines/terminal_select.ogg', 15, TRUE)
+ to_chat(user, "[src]'s screen flashes: 'Book selected in library computer.'")
+ if(BARCODE_MODE_SCAN_INVENTORY)
+ if(computer.inventoryAdd(B))
+ playsound(src, 'sound/items/scannerbeep.ogg', 15, TRUE)
+ to_chat(user, "[src]'s screen flashes: 'Title added to general inventory.'")
+ else
+ playsound(src, 'sound/machines/synth_no.ogg', 15, TRUE)
+ to_chat(user, "[src]'s screen flashes: 'Title already in general inventory.'")
+ if(BARCODE_MODE_CHECKOUT)
+ var/confirm
+ if(!computer.user_data.patron_account)
+ confirm = alert("Warning: patron does not have an associated account number! Are you sure you want to checkout [B] to [computer.user_data.patron_name]?", "Confirm Checkout", "Yes", "No")
+ else
+ confirm = alert("Are you sure you want to checkout [B] to [computer.user_data.patron_name]?", "Confirm Checkout", "Yes", "No")
+
+ if(confirm == "No")
+ return
+ if(computer.checkout(B))
+ playsound(src, 'sound/items/scannerbeep.ogg', 15, TRUE)
+ to_chat(user, "[src]'s screen flashes: 'Title checked out to [computer.user_data.patron_name].'")
+ else
+ playsound(src, 'sound/machines/synth_no.ogg', 15, TRUE)
+ to_chat(user, "[src]'s screen flashes: 'ERROR! Book Checkout Unsuccesful.'")
+ if(BARCODE_MODE_CHECKIN)
+ if(computer.checkin(B))
+ playsound(src, 'sound/items/scannerbeep.ogg', 15, TRUE)
+ to_chat(user, "[src]'s screen flashes: 'Title checked back into general inventory.'")
+ else
+ playsound(src, 'sound/machines/synth_no.ogg', 15, TRUE)
+ to_chat(user, "[src]'s screen flashes: 'ERROR! Book Checkout Unsuccesful.'")
+
+/obj/item/barcodescanner/proc/check_connection(mob/user as mob) //fuck you null references!
+ if(computer)
+ return TRUE
+ else
+ playsound(src, 'sound/machines/synth_no.ogg', 15, TRUE)
+ to_chat(user, "Please reconnect [src] to a library computer.")
+ return FALSE
diff --git a/code/modules/library/library_readme.dm b/code/modules/library/library_readme.dm
new file mode 100644
index 00000000000..56eaf58170b
--- /dev/null
+++ b/code/modules/library/library_readme.dm
@@ -0,0 +1,40 @@
+//*******************************
+//
+// Library System Breakdown
+//
+//*******************************
+/*
+ The Library
+ ------------
+ A place for the crew to go, relax, and enjoy a good book.
+ Aspiring authors can even self publish and submit it to the Archives
+ to be chronicled in history forever - some say even persisting
+ through alternate dimensions.
+*/
+
+/* DB Notes:
+-We have three seperate categories columns because in a relation database you can either store things as a JSON list
+or you can be able to search them. You can't have both, which is why we have a primary, secondary, and tertiary column
+*/
+// CONTAINS:
+
+// Objects:
+// - bookcase
+// - book
+// - barcode scanner
+// Machinery:
+// - library computer
+// - book binder
+// Datum:
+// - borrowbook
+// - CachedBook
+// - Library Catalog
+
+
+// Ideas for the future
+// ---------------------
+// - Make library equipment emaggable
+// - Books shouldn't print straight from the library computer. Make it synch with a machine like the book binder to print instead. This should consume some sort of resource.
+// - Consider porting All wiki/iframe manuals to using MediaWiki API Calls and display using TGUI
+// - DB: put in checks to automatically prevent duplicate books from being uploaded to the Database
+// - Fully implement book fining system
diff --git a/code/modules/library/random_books.dm b/code/modules/library/random_books.dm
deleted file mode 100644
index a43f0cc4b18..00000000000
--- a/code/modules/library/random_books.dm
+++ /dev/null
@@ -1,96 +0,0 @@
-/obj/item/book/manual/random
- icon_state = "random_book"
-
-/obj/item/book/manual/random/New()
- ..()
- var/static/banned_books = list(/obj/item/book/manual/random, /obj/item/book/manual/nuclear)
- var/newtype = pick(subtypesof(/obj/item/book/manual) - banned_books)
- new newtype(loc)
- qdel(src)
-
-/obj/item/book/random
- icon_state = "random_book"
- var/amount = 1
- var/category = null
-
-/obj/item/book/random/Initialize()
- ..()
- create_random_books(amount, src.loc, TRUE, category)
- qdel(src)
-
-/obj/item/book/random/triple
- amount = 3
-
-/obj/structure/bookcase/random
- var/category = null
- var/book_count = 2
- icon_state = "random_bookcase"
- anchored = TRUE
-
-/obj/structure/bookcase/random/Initialize()
- . = ..()
- if(!book_count || !isnum(book_count))
- update_icon()
- return
- book_count += pick(-1,-1,0,1,1)
- create_random_books(book_count, src, FALSE, category)
- update_icon()
-
-// why is this a global proc
-/proc/create_random_books(amount = 2, location, fail_loud = FALSE, category = null)
- . = list()
- if(!isnum(amount) || amount<1)
- return
- if(!SSdbcore.IsConnected())
- if(fail_loud || prob(5))
- var/obj/item/paper/P = new(location)
- P.info = "There once was a book from Nantucket But the database failed us, so f*$! it. I tried to be good to you Now this is an I.O.U If you're feeling entitled, well, stuff it!
~"
- P.update_icon()
- return
- if(prob(25))
- category = null
- var/c = ""
- var/list/sql_params = list()
- if(category)
- c = " AND category=:category"
- sql_params["category"] = category
-
- sql_params["amount"] = amount
- var/datum/db_query/query_get_random_books = SSdbcore.NewQuery("SELECT author, title, content FROM library WHERE (isnull(flagged) OR flagged = 0)[c] GROUP BY title ORDER BY rand() LIMIT :amount", sql_params)
- if(!query_get_random_books.warn_execute())
- qdel(query_get_random_books)
- return
-
- while(query_get_random_books.NextRow())
- var/obj/item/book/B = new(location)
- . += B
- B.author = query_get_random_books.item[1]
- B.title = query_get_random_books.item[2]
- B.dat = query_get_random_books.item[3]
- B.name = "Book: [B.title]"
- B.icon_state= "book[rand(1,8)]"
- qdel(query_get_random_books)
-
-/obj/structure/bookcase/random/fiction
- name = "bookcase (Fiction)"
- category = "Fiction"
-/obj/structure/bookcase/random/nonfiction
- name = "bookcase (Non-Fiction)"
- category = "Non-fiction"
-/obj/structure/bookcase/random/religion
- name = "bookcase (Religion)"
- category = "Religion"
-/obj/structure/bookcase/random/adult
- name = "bookcase (Adult)"
- category = "Adult"
-
-/obj/structure/bookcase/random/reference
- name = "bookcase (Reference)"
- category = "Reference"
- var/ref_book_prob = 20
-
-/obj/structure/bookcase/random/reference/Initialize(mapload)
- . = ..()
- while(book_count > 0 && prob(ref_book_prob))
- book_count--
- new /obj/item/book/manual/random(src)
diff --git a/code/modules/martial_arts/combos/sleeping_carp/keelhaul.dm b/code/modules/martial_arts/combos/sleeping_carp/keelhaul.dm
index f381c014171..b0b22b3736a 100644
--- a/code/modules/martial_arts/combos/sleeping_carp/keelhaul.dm
+++ b/code/modules/martial_arts/combos/sleeping_carp/keelhaul.dm
@@ -6,13 +6,15 @@
/datum/martial_combo/sleeping_carp/keelhaul/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA)
user.do_attack_animation(target, ATTACK_EFFECT_KICK)
playsound(get_turf(target), 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
- if(!target.IsWeakened() && !IS_HORIZONTAL(target) && !target.stat)
+ if(!IS_HORIZONTAL(target))
target.apply_damage(10, BRUTE, BODY_ZONE_HEAD)
- target.Weaken(4 SECONDS)
+ target.KnockDown(6 SECONDS)
target.visible_message("[user] kicks [target] in the head, sending them face first into the floor!",
"You are kicked in the head by [user], sending you crashing to the floor!")
else
target.apply_damage(5, BRUTE, BODY_ZONE_HEAD)
+ target.drop_l_hand()
+ target.drop_r_hand()
target.visible_message("[user] kicks [target] in the head, leaving them reeling in pain!",
"You are kicked in the head by [user], and you reel in pain!")
target.apply_damage(40, STAMINA)
diff --git a/code/modules/martial_arts/sleeping_carp.dm b/code/modules/martial_arts/sleeping_carp.dm
index 9f7053f1757..9d9c64b9f4a 100644
--- a/code/modules/martial_arts/sleeping_carp.dm
+++ b/code/modules/martial_arts/sleeping_carp.dm
@@ -8,14 +8,6 @@
has_explaination_verb = TRUE
combos = list(/datum/martial_combo/sleeping_carp/crashing_kick, /datum/martial_combo/sleeping_carp/keelhaul, /datum/martial_combo/sleeping_carp/gnashing_teeth)
-/datum/martial_art/the_sleeping_carp/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
- MARTIAL_ARTS_ACT_CHECK
- var/obj/item/grab/G = D.grabbedby(A,1)
- if(G)
- G.state = GRAB_AGGRESSIVE //Instant aggressive grab
- add_attack_logs(A, D, "Melee attacked with martial-art [src] : Grabbed", ATKLOG_ALL)
- return TRUE
-
/datum/martial_art/the_sleeping_carp/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
MARTIAL_ARTS_ACT_CHECK
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
diff --git a/code/modules/mining/abandonedcrates.dm b/code/modules/mining/abandonedcrates.dm
index f289a2dc8e1..06d21232fed 100644
--- a/code/modules/mining/abandonedcrates.dm
+++ b/code/modules/mining/abandonedcrates.dm
@@ -157,7 +157,7 @@
if(in_range(src, user))
if(input == code)
to_chat(user, "The crate unlocks!")
- locked = 0
+ locked = FALSE
overlays.Cut()
overlays += "securecrateg"
else if(input == null || length(input) != codelen)
diff --git a/code/modules/mining/equipment/lazarus_injector.dm b/code/modules/mining/equipment/lazarus_injector.dm
index 2114570ebea..f1e06a9f203 100644
--- a/code/modules/mining/equipment/lazarus_injector.dm
+++ b/code/modules/mining/equipment/lazarus_injector.dm
@@ -26,17 +26,17 @@
if(M.stat == DEAD)
M.faction = list("neutral")
M.revive()
- M.can_collar = 1
+ M.can_collar = TRUE
if(istype(target, /mob/living/simple_animal/hostile))
var/mob/living/simple_animal/hostile/H = M
if(malfunctioning)
H.faction |= list("lazarus", "\ref[user]")
- H.robust_searching = 1
+ H.robust_searching = TRUE
H.friends += user
- H.attack_same = 1
+ H.attack_same = TRUE
log_game("[user] has revived hostile mob [target] with a malfunctioning lazarus injector")
else
- H.attack_same = 0
+ H.attack_same = FALSE
loaded = 0
user.visible_message("[user] injects [M] with [src], reviving it.")
playsound(src,'sound/effects/refill.ogg',50,1)
diff --git a/code/modules/mining/equipment/mining_tools.dm b/code/modules/mining/equipment/mining_tools.dm
index f5d5d9f68bd..5a56e898ca2 100644
--- a/code/modules/mining/equipment/mining_tools.dm
+++ b/code/modules/mining/equipment/mining_tools.dm
@@ -14,7 +14,7 @@
attack_verb = list("hit", "pierced", "sliced", "attacked")
var/list/digsound = list('sound/effects/picaxe1.ogg','sound/effects/picaxe2.ogg','sound/effects/picaxe3.ogg')
var/drill_verb = "picking"
- sharp = 1
+ sharp = TRUE
var/excavation_amount = 100
usesound = 'sound/effects/picaxe1.ogg'
toolspeed = 1
diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm
index d3d9e97b3b1..3c8122695bc 100644
--- a/code/modules/mining/equipment/survival_pod.dm
+++ b/code/modules/mining/equipment/survival_pod.dm
@@ -180,8 +180,8 @@
name = "pod computer"
icon_state = "pod_computer"
icon = 'icons/obj/lavaland/pod_computer.dmi'
- anchored = 1
- density = 1
+ anchored = TRUE
+ density = TRUE
pixel_y = -32
/obj/item/gps/computer/attackby(obj/item/W, mob/user, params)
@@ -252,8 +252,8 @@
icon_state = "fans"
name = "environmental regulation system"
desc = "A large machine releasing a constant gust of air."
- anchored = 1
- density = 1
+ anchored = TRUE
+ density = TRUE
var/arbitraryatmosblockingvar = 1
var/buildstacktype = /obj/item/stack/sheet/metal
var/buildstackamount = 5
@@ -289,7 +289,7 @@
name = "tiny fan"
desc = "A tiny fan, releasing a thin gust of air."
layer = TURF_LAYER+0.1
- density = 0
+ density = FALSE
icon_state = "fan_tiny"
buildstackamount = 2
@@ -315,9 +315,9 @@
icon_state = "tubes"
icon = 'icons/obj/lavaland/survival_pod.dmi'
name = "tubes"
- anchored = 1
+ anchored = TRUE
layer = MOB_LAYER - 0.2
- density = 0
+ density = FALSE
/obj/structure/tubes/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/wrench))
diff --git a/code/modules/mining/lavaland/loot/ashdragon_loot.dm b/code/modules/mining/lavaland/loot/ashdragon_loot.dm
index 04b3afdaf86..c5470f80660 100644
--- a/code/modules/mining/lavaland/loot/ashdragon_loot.dm
+++ b/code/modules/mining/lavaland/loot/ashdragon_loot.dm
@@ -31,7 +31,7 @@
icon_state = "spectral"
item_state = "spectral"
flags = CONDUCT
- sharp = 1
+ sharp = TRUE
w_class = WEIGHT_CLASS_BULKY
force = 1
throwforce = 1
diff --git a/code/modules/mining/lavaland/loot/colossus_loot.dm b/code/modules/mining/lavaland/loot/colossus_loot.dm
index fff82ae517e..7d67bfc2434 100644
--- a/code/modules/mining/lavaland/loot/colossus_loot.dm
+++ b/code/modules/mining/lavaland/loot/colossus_loot.dm
@@ -24,7 +24,7 @@
icon_state = "anomaly_crystal"
light_range = 8
use_power = NO_POWER_USE
- density = 1
+ density = TRUE
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
var/activation_method = "touch"
var/activation_damage_type = null
@@ -252,7 +252,7 @@
health = 2
harm_intent_damage = 1
friendly = "mends"
- density = 0
+ density = FALSE
flying = TRUE
obj_damage = 0
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
@@ -263,15 +263,15 @@
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
luminosity = 4
faction = list("neutral")
- universal_understand = 1
- del_on_death = 1
+ universal_understand = TRUE
+ del_on_death = TRUE
unsuitable_atmos_damage = 0
- flying = 1
+ flying = TRUE
minbodytemp = 0
maxbodytemp = 1500
environment_smash = 0
AIStatus = AI_OFF
- stop_automated_movement = 1
+ stop_automated_movement = TRUE
var/heal_power = 5
/mob/living/simple_animal/hostile/lightgeist/New()
@@ -341,8 +341,8 @@
name = "quantum entanglement stasis warp field"
desc = "You can hardly comprehend this thing... which is why you can't see it."
icon_state = null //This shouldn't even be visible, so if it DOES show up, at least nobody will notice
- density = 1
- anchored = 1
+ density = TRUE
+ anchored = TRUE
resistance_flags = FIRE_PROOF | ACID_PROOF | INDESTRUCTIBLE
var/mob/living/simple_animal/holder_animal
@@ -362,7 +362,7 @@
/obj/structure/closet/stasis/Entered(atom/A)
if(isliving(A) && holder_animal)
var/mob/living/L = A
- L.notransform = 1
+ L.notransform = TRUE
ADD_TRAIT(L, TRAIT_MUTE, STASIS_MUTE)
L.status_flags |= GODMODE
L.mind.transfer_to(holder_animal)
@@ -375,7 +375,7 @@
for(var/mob/living/L in src)
REMOVE_TRAIT(L, TRAIT_MUTE, STASIS_MUTE)
L.status_flags &= ~GODMODE
- L.notransform = 0
+ L.notransform = FALSE
if(holder_animal && !QDELETED(holder_animal))
holder_animal.mind.transfer_to(L)
L.mind.RemoveSpell(/obj/effect/proc_holder/spell/exit_possession)
@@ -393,7 +393,7 @@
name = "Exit Possession"
desc = "Exits the body you are possessing"
charge_max = 60
- clothes_req = 0
+ clothes_req = FALSE
invocation_type = "none"
action_icon_state = "exit_possession"
sound = null
diff --git a/code/modules/mining/lavaland/loot/tendril_loot.dm b/code/modules/mining/lavaland/loot/tendril_loot.dm
index 7215d031c4a..dfe9702adde 100644
--- a/code/modules/mining/lavaland/loot/tendril_loot.dm
+++ b/code/modules/mining/lavaland/loot/tendril_loot.dm
@@ -433,11 +433,11 @@
Z.desc = "It's shaped an awful lot like [user.name]."
Z.setDir(user.dir)
user.forceMove(Z)
- user.notransform = 1
+ user.notransform = TRUE
user.status_flags |= GODMODE
spawn(100)
user.status_flags &= ~GODMODE
- user.notransform = 0
+ user.notransform = FALSE
user.forceMove(get_turf(Z))
user.visible_message("[user] pops back into reality!")
Z.can_destroy = TRUE
diff --git a/code/modules/mining/machine_unloading.dm b/code/modules/mining/machine_unloading.dm
index 39feeb38a61..7279b0f115a 100644
--- a/code/modules/mining/machine_unloading.dm
+++ b/code/modules/mining/machine_unloading.dm
@@ -5,8 +5,8 @@
name = "unloading machine"
icon = 'icons/obj/machines/mining_machines.dmi'
icon_state = "unloader"
- density = 1
- anchored = 1.0
+ density = TRUE
+ anchored = TRUE
input_dir = WEST
output_dir = EAST
speed_process = 1
diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm
index 87937aa2169..3b0f195d5d8 100644
--- a/code/modules/mining/mine_items.dm
+++ b/code/modules/mining/mine_items.dm
@@ -83,6 +83,6 @@
desc = "A mining car. This one doesn't work on rails, but has to be dragged."
name = "mining car (not for rails)"
icon_state = "miningcar"
- density = 1
+ density = TRUE
icon_opened = "miningcar_open"
icon_closed = "miningcar"
diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm
index 0f11bd0e665..18a4eadbcda 100644
--- a/code/modules/mining/minebot.dm
+++ b/code/modules/mining/minebot.dm
@@ -32,11 +32,11 @@
/obj/item/stack/ore/plasma, /obj/item/stack/ore/uranium, /obj/item/stack/ore/iron,
/obj/item/stack/ore/bananium, /obj/item/stack/ore/tranquillite, /obj/item/stack/ore/glass,
/obj/item/stack/ore/titanium)
- healable = 0
+ healable = FALSE
loot = list(/obj/effect/decal/cleanable/robot_debris)
del_on_death = TRUE
var/mode = MINEDRONE_COLLECT
- var/light_on = 0
+ var/light_on = FALSE
var/mesons_active
var/obj/item/gun/energy/kinetic_accelerator/minebot/stored_gun
@@ -70,7 +70,7 @@
/mob/living/simple_animal/hostile/mining_drone/sentience_act()
..()
- check_friendly_fire = 0
+ check_friendly_fire = FALSE
/mob/living/simple_animal/hostile/mining_drone/examine(mob/user)
. = ..()
diff --git a/code/modules/mining/mint.dm b/code/modules/mining/mint.dm
index d8815d15329..96c940cd808 100644
--- a/code/modules/mining/mint.dm
+++ b/code/modules/mining/mint.dm
@@ -62,7 +62,7 @@
return
usr.set_machine(src)
add_fingerprint(usr)
- if(processing == 1)
+ if(processing)
to_chat(usr, "The machine is processing.")
return
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm
index abbfa5242a6..e1390799622 100644
--- a/code/modules/mining/ores_coins.dm
+++ b/code/modules/mining/ores_coins.dm
@@ -220,7 +220,7 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
item_state = "Gibtonite ore"
w_class = WEIGHT_CLASS_BULKY
throw_range = 0
- anchored = 1 //Forces people to carry it by hand, no pulling!
+ anchored = TRUE //Forces people to carry it by hand, no pulling!
var/primed = 0
var/det_time = 100
var/quality = GIBTONITE_QUALITY_LOW //How pure this gibtonite is, determines the explosion produced by it and is derived from the det_time of the rock wall it was taken from, higher value = better
diff --git a/code/modules/mob/hear_say.dm b/code/modules/mob/hear_say.dm
index e069bfe28cc..d8453a38f01 100644
--- a/code/modules/mob/hear_say.dm
+++ b/code/modules/mob/hear_say.dm
@@ -95,11 +95,12 @@
if(client.prefs.toggles & PREFTOGGLE_CHAT_GHOSTEARS && (speaker in view(src)))
message = "[message]"
- // Check if the language used is innate
- for(var/datum/multilingual_say_piece/SP in message_pieces)
- if(SP.speaking && SP.speaking.flags & INNATE)
- custom_emote(EMOTE_AUDIBLE, message_clean, TRUE)
- return
+ // Ensure only the speaker is forced to emote, and that the spoken language is inname
+ if(speaker == src)
+ for(var/datum/multilingual_say_piece/SP in message_pieces)
+ if(SP.speaking && SP.speaking.flags & INNATE)
+ custom_emote(EMOTE_AUDIBLE, message_clean, TRUE)
+ return
if(!can_hear())
// INNATE is the flag for audible-emote-language, so we don't want to show an "x talks but you cannot hear them" message if it's set
diff --git a/code/modules/mob/holder.dm b/code/modules/mob/holder.dm
index 864e48771a7..330ab4447da 100644
--- a/code/modules/mob/holder.dm
+++ b/code/modules/mob/holder.dm
@@ -54,7 +54,7 @@
if(istype(M))
for(var/atom/A in M.contents)
- if(istype(A,/mob/living/simple_animal/borer) || istype(A,/obj/item/holder))
+ if(istype(A, /obj/item/holder))
return
M.status_flags &= ~PASSEMOTES
diff --git a/code/modules/mob/language.dm b/code/modules/mob/language.dm
index f7d7bff0517..a1a6ea2aac8 100644
--- a/code/modules/mob/language.dm
+++ b/code/modules/mob/language.dm
@@ -568,30 +568,6 @@
/datum/language/abductor/golem/check_special_condition(mob/living/carbon/human/other, mob/living/carbon/human/speaker)
return TRUE
-/datum/language/corticalborer
- name = "Cortical Link"
- desc = "Cortical borers possess a strange link between their tiny minds."
- speech_verb = "sings"
- ask_verb = "sings"
- exclaim_verbs = list("sings")
- colour = "alien"
- key = "bo"
- flags = RESTRICTED | HIVEMIND | NOBABEL
- follow = TRUE
-
-/datum/language/corticalborer/broadcast(mob/living/speaker, message, speaker_mask)
- var/mob/living/simple_animal/borer/B
-
- if(iscarbon(speaker))
- var/mob/living/carbon/M = speaker
- B = M.has_brain_worms()
- else if(istype(speaker,/mob/living/simple_animal/borer))
- B = speaker
-
- if(B)
- speaker_mask = B.truename
- ..(speaker,message,speaker_mask)
-
/datum/language/binary
name = "Robot Talk"
desc = "Most human stations support free-use communications protocols and routing hubs for synthetic use."
diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm
index 99900183185..5219d3dbed0 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm
@@ -30,9 +30,6 @@
continue
no_queen = 0
- if(src.has_brain_worms())
- to_chat(src, "We cannot perform this ability at the present time!")
- return
if(no_queen)
adjustPlasma(-500)
to_chat(src, "You begin to evolve!")
diff --git a/code/modules/mob/living/carbon/brain/brain_item.dm b/code/modules/mob/living/carbon/brain/brain_item.dm
index 6ee93ced411..4622858409a 100644
--- a/code/modules/mob/living/carbon/brain/brain_item.dm
+++ b/code/modules/mob/living/carbon/brain/brain_item.dm
@@ -61,10 +61,6 @@
var/obj/item/organ/internal/brain/B = src
if(!special)
- var/mob/living/simple_animal/borer/borer = owner.has_brain_worms()
- if(borer)
- borer.leave_host() //Should remove borer if the brain is removed - RR
-
if(owner.mind && !non_primary)//don't transfer if the owner does not have a mind.
B.transfer_identity(user)
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index fdc2102f8e8..fb0b346fa3f 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -14,10 +14,6 @@
QDEL_LIST(internal_organs)
QDEL_LIST(stomach_contents)
QDEL_LIST(processing_patches)
- var/mob/living/simple_animal/borer/B = has_brain_worms()
- if(B)
- B.leave_host()
- qdel(B)
GLOB.carbon_list -= src
return ..()
@@ -518,10 +514,10 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, list(/obj/machinery/atmospherics/unary/ven
to_chat(src, "This ventilation duct is not connected to anything!")
-/mob/living/proc/add_ventcrawl(obj/machinery/atmospherics/starting_machine)
- if(!istype(starting_machine) || !starting_machine.returnPipenet() || !starting_machine.can_see_pipes())
+/mob/living/proc/add_ventcrawl(obj/machinery/atmospherics/starting_machine, obj/machinery/atmospherics/target_move)
+ if(!istype(starting_machine) || !starting_machine.returnPipenet(target_move) || !starting_machine.can_see_pipes())
return
- var/datum/pipeline/pipeline = starting_machine.returnPipenet()
+ var/datum/pipeline/pipeline = starting_machine.returnPipenet(target_move)
var/list/totalMembers = list()
totalMembers |= pipeline.members
totalMembers |= pipeline.other_atmosmch
@@ -543,13 +539,15 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, list(/obj/machinery/atmospherics/unary/ven
/atom/proc/update_pipe_vision()
return
-/mob/living/update_pipe_vision()
- if(pipes_shown.len)
+/mob/living/update_pipe_vision(obj/machinery/atmospherics/target_move)
+ if(pipes_shown.len && !(target_move))
if(!is_ventcrawling(src))
remove_ventcrawl()
else
if(is_ventcrawling(src))
- add_ventcrawl(loc)
+ if(target_move)
+ remove_ventcrawl()
+ add_ventcrawl(loc, target_move)
//Throwing stuff
@@ -979,6 +977,7 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, list(/obj/machinery/atmospherics/unary/ven
else
REMOVE_TRAIT(src, TRAIT_RESTRAINED, "handcuffed")
clear_alert("handcuffed")
+ changeNext_move(CLICK_CD_RAPID) //reset click cooldown from handcuffs
update_action_buttons_icon() //some of our action buttons might be unusable when we're handcuffed.
update_inv_handcuffed()
update_hud_handcuffed()
diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm
index 667fd86204e..a6c82a2f437 100644
--- a/code/modules/mob/living/carbon/carbon_defines.dm
+++ b/code/modules/mob/living/carbon/carbon_defines.dm
@@ -14,8 +14,6 @@
var/obj/item/head = null
var/obj/item/clothing/suit/wear_suit = null //TODO: necessary? Are they even used? ~Carn
- var/mob/living/simple_animal/borer/borer = null
-
//Active emote/pose
var/pose = null
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 07ff5d95257..8cd2177067b 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -203,9 +203,6 @@
stat("Distribution Pressure", internal.distribute_pressure)
// I REALLY need to split up status panel things into datums
- var/mob/living/simple_animal/borer/B = has_brain_worms()
- if(B && B.controlling)
- stat("Chemicals", B.chemicals)
if(mind)
var/datum/antagonist/changeling/cling = mind.has_antag_datum(/datum/antagonist/changeling)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 8a5b71a2135..fe354adf06c 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -489,7 +489,7 @@ emp_act
if(prob(I.force))
visible_message("[src] has been knocked down!", \
"[src] has been knocked down!")
- apply_effect(10 SECONDS, WEAKEN, armor)
+ KnockDown(10 SECONDS)
AdjustConfused(30 SECONDS)
if(prob(I.force + ((100 - health)/2)) && src != user && I.damtype == BRUTE)
SSticker.mode.remove_revolutionary(mind)
@@ -510,7 +510,7 @@ emp_act
if(stat == CONSCIOUS && I.force && prob(I.force + 10))
visible_message("[src] has been knocked down!", \
"[src] has been knocked down!")
- apply_effect(10 SECONDS, WEAKEN, armor)
+ KnockDown(8 SECONDS)
if(bloody)
if(wear_suit)
diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm
index bae8a2ab486..2ae2227561f 100644
--- a/code/modules/mob/living/carbon/human/say.dm
+++ b/code/modules/mob/living/carbon/human/say.dm
@@ -39,9 +39,6 @@
winset(client, "input", "text=[null]")
/mob/living/carbon/human/say_understands(mob/other, datum/language/speaking = null)
- if(has_brain_worms()) //Brain worms translate everything. Even mice and alien speak.
- return 1
-
if(dna.species.can_understand(other))
return 1
@@ -100,6 +97,8 @@
// how do species that don't breathe talk? magic, that's what.
var/breathes = (!HAS_TRAIT(src, TRAIT_NOBREATH))
var/obj/item/organ/internal/L = get_organ_slot("lungs")
+ if(HAS_TRAIT(src, TRAIT_MUTE))
+ return FALSE
if((breathes && !L) || breathes && L && (L.status & ORGAN_DEAD))
return FALSE
if(getOxyLoss() > 10 || AmountLoseBreath() >= 8 SECONDS)
diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm
index 5568d569dfa..68c24b0242c 100644
--- a/code/modules/mob/living/carbon/human/species/_species.dm
+++ b/code/modules/mob/living/carbon/human/species/_species.dm
@@ -504,9 +504,9 @@
target.visible_message("[user] [pick(attack.attack_verb)]ed [target]!")
target.apply_damage(damage, BRUTE, affecting, armor_block, sharp = attack.sharp) //moving this back here means Armalis are going to knock you down 70% of the time, but they're pure adminbus anyway.
if((target.stat != DEAD) && damage >= user.dna.species.punchstunthreshold)
- target.visible_message("[user] has weakened [target]!", \
- "[user] has weakened [target]!")
- target.apply_effect(8 SECONDS, WEAKEN, armor_block)
+ target.visible_message("[user] has knocked down [target]!", \
+ "[user] has knocked down [target]!")
+ target.KnockDown(4 SECONDS)
target.forcesay(GLOB.hit_appends)
else if(IS_HORIZONTAL(target))
target.forcesay(GLOB.hit_appends)
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index cd06156b763..8cf846303f7 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -772,7 +772,6 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
else
standing = mutable_appearance('icons/mob/clothing/feet.dmi', "[shoes.icon_state]", layer = -SHOES_LAYER)
-
if(shoes.blood_DNA)
var/image/bloodsies = image("icon" = dna.species.blood_mask, "icon_state" = "shoeblood")
bloodsies.color = shoes.blood_color
@@ -979,13 +978,16 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
remove_overlay(BACK_LAYER)
if(back)
//determine the icon to use
+ var/t_state = back.item_state
+ if(!t_state)
+ t_state = back.icon_state
var/mutable_appearance/standing
if(back.icon_override)
- standing = mutable_appearance(back.icon_override, "[back.icon_state]", layer = -BACK_LAYER)
+ standing = mutable_appearance(back.icon_override, "[t_state]", layer = -BACK_LAYER)
else if(back.sprite_sheets && back.sprite_sheets[dna.species.name])
- standing = mutable_appearance(back.sprite_sheets[dna.species.name], "[back.icon_state]", layer = -BACK_LAYER)
+ standing = mutable_appearance(back.sprite_sheets[dna.species.name], "[t_state]", layer = -BACK_LAYER)
else
- standing = mutable_appearance('icons/mob/clothing/back.dmi', "[back.icon_state]", layer = -BACK_LAYER)
+ standing = mutable_appearance('icons/mob/clothing/back.dmi', "[t_state]", layer = -BACK_LAYER)
//create the image
standing.alpha = back.alpha
diff --git a/code/modules/mob/living/living_emote.dm b/code/modules/mob/living/living_emote.dm
index 67e72854045..7270e45f6e4 100644
--- a/code/modules/mob/living/living_emote.dm
+++ b/code/modules/mob/living/living_emote.dm
@@ -2,7 +2,6 @@
mob_type_allowed_typecache = /mob/living
mob_type_blacklist_typecache = list(
/mob/living/carbon/brain, // nice try
- /mob/living/captive_brain,
/mob/living/silicon,
/mob/living/simple_animal/bot
)
@@ -83,7 +82,6 @@
mob_type_blacklist_typecache = list(
/mob/living/carbon/brain,
- /mob/living/captive_brain
)
/datum/emote/living/deathgasp/get_sound(mob/living/user)
@@ -346,7 +344,6 @@
mob_type_blacklist_typecache = list(
/mob/living/carbon/brain,
- /mob/living/captive_brain
)
/datum/emote/living/tilt
@@ -389,7 +386,6 @@
message = null
mob_type_blacklist_typecache = list(
/mob/living/carbon/brain, // nice try
- /mob/living/captive_brain
)
// Custom emotes should be able to be forced out regardless of context.
diff --git a/code/modules/mob/living/simple_animal/hostile/alien.dm b/code/modules/mob/living/simple_animal/hostile/alien.dm
index 22bea873162..8edabe284f9 100644
--- a/code/modules/mob/living/simple_animal/hostile/alien.dm
+++ b/code/modules/mob/living/simple_animal/hostile/alien.dm
@@ -74,7 +74,7 @@
maxHealth = 150
melee_damage_lower = 15
melee_damage_upper = 15
- ranged = 1
+ ranged = TRUE
retreat_distance = 5
minimum_distance = 5
projectiletype = /obj/item/projectile/neurotox
@@ -95,7 +95,7 @@
maxHealth = 250
melee_damage_lower = 15
melee_damage_upper = 15
- ranged = 1
+ ranged = TRUE
retreat_distance = 5
minimum_distance = 5
move_to_delay = 4
diff --git a/code/modules/mob/living/simple_animal/hostile/bat.dm b/code/modules/mob/living/simple_animal/hostile/bat.dm
index 455fa22f130..dd2529f3f69 100644
--- a/code/modules/mob/living/simple_animal/hostile/bat.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bat.dm
@@ -63,6 +63,6 @@
melee_damage_upper = 30
a_intent = INTENT_HARM
pass_flags = PASSTABLE
- universal_speak = 1
- universal_understand = 1
+ universal_speak = TRUE
+ universal_understand = TRUE
gold_core_spawnable = NO_SPAWN //badmin only
diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm
index e75a914b9df..55861669bcd 100644
--- a/code/modules/mob/living/simple_animal/hostile/bear.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bear.dm
@@ -18,7 +18,7 @@
response_help = "pets"
response_disarm = "gently pushes aside"
response_harm = "hits"
- stop_automated_movement_when_pulled = 0
+ stop_automated_movement_when_pulled = FALSE
maxHealth = 60
health = 60
obj_damage = 60
diff --git a/code/modules/mob/living/simple_animal/hostile/carp.dm b/code/modules/mob/living/simple_animal/hostile/carp.dm
index ec1baeb0bdf..9e4d64f5e4c 100644
--- a/code/modules/mob/living/simple_animal/hostile/carp.dm
+++ b/code/modules/mob/living/simple_animal/hostile/carp.dm
@@ -124,7 +124,7 @@
icon_living = "holocarp"
maxbodytemp = INFINITY
gold_core_spawnable = NO_SPAWN
- del_on_death = 1
+ del_on_death = TRUE
random_color = FALSE
/mob/living/simple_animal/hostile/carp/megacarp
diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
index 38e71362817..ca80102116c 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -90,10 +90,10 @@
if(AIStatus == AI_IDLE)
//1% chance to skitter madly away
if(!busy && prob(1))
- stop_automated_movement = 1
+ stop_automated_movement = TRUE
Goto(pick(urange(20, src, 1)), move_to_delay)
spawn(50)
- stop_automated_movement = 0
+ stop_automated_movement = FALSE
walk(src,0)
return 1
@@ -103,7 +103,7 @@
if(cocoon_target == C && get_dist(src,cocoon_target) > 1)
cocoon_target = null
busy = 0
- stop_automated_movement = 0
+ stop_automated_movement = FALSE
/mob/living/simple_animal/hostile/poison/giant_spider/nurse/handle_automated_movement() //Hacky and ugly.
if(..())
@@ -135,7 +135,7 @@
if(isitem(O) || isstructure(O) || ismachinery(O))
cocoon_target = O
busy = MOVING_TO_TARGET
- stop_automated_movement = 1
+ stop_automated_movement = TRUE
Goto(O, move_to_delay)
//give up if we can't reach them after 10 seconds
GiveUp(O)
@@ -146,7 +146,7 @@
else
busy = 0
- stop_automated_movement = 0
+ stop_automated_movement = FALSE
/mob/living/simple_animal/hostile/poison/giant_spider/verb/Web()
set name = "Lay Web"
@@ -158,12 +158,12 @@
if(busy != SPINNING_WEB)
busy = SPINNING_WEB
src.visible_message("\the [src] begins to secrete a sticky substance.")
- stop_automated_movement = 1
+ stop_automated_movement = TRUE
spawn(40)
if(busy == SPINNING_WEB && src.loc == T)
new /obj/structure/spider/stickyweb(T)
busy = 0
- stop_automated_movement = 0
+ stop_automated_movement = FALSE
/mob/living/simple_animal/hostile/poison/giant_spider/nurse/verb/Wrap()
@@ -198,7 +198,7 @@
if(cocoon_target && busy != SPINNING_COCOON)
busy = SPINNING_COCOON
src.visible_message("\the [src] begins to secrete a sticky substance around \the [cocoon_target].")
- stop_automated_movement = 1
+ stop_automated_movement = TRUE
walk(src,0)
spawn(50)
if(busy == SPINNING_COCOON)
@@ -234,7 +234,7 @@
C.icon_state = pick("cocoon_large1","cocoon_large2","cocoon_large3")
cocoon_target = null
busy = 0
- stop_automated_movement = 0
+ stop_automated_movement = FALSE
/mob/living/simple_animal/hostile/poison/giant_spider/nurse/verb/LayEggs()
set name = "Lay Eggs"
@@ -249,7 +249,7 @@
else if(busy != LAYING_EGGS)
busy = LAYING_EGGS
src.visible_message("\the [src] begins to lay a cluster of eggs.")
- stop_automated_movement = 1
+ stop_automated_movement = TRUE
spawn(50)
if(busy == LAYING_EGGS)
E = locate() in get_turf(src)
@@ -259,10 +259,10 @@
C.master_commander = master_commander
C.xenobiology_spawned = xenobiology_spawned
if(ckey)
- C.player_spiders = 1
+ C.player_spiders = TRUE
fed--
busy = 0
- stop_automated_movement = 0
+ stop_automated_movement = FALSE
#undef SPINNING_WEB
#undef LAYING_EGGS
diff --git a/code/modules/mob/living/simple_animal/hostile/headslug.dm b/code/modules/mob/living/simple_animal/hostile/headslug.dm
index cf08da3d050..ea321f84b47 100644
--- a/code/modules/mob/living/simple_animal/hostile/headslug.dm
+++ b/code/modules/mob/living/simple_animal/hostile/headslug.dm
@@ -14,7 +14,7 @@
attacktext = "chomps"
attack_sound = 'sound/weapons/bite.ogg'
faction = list("creature")
- robust_searching = 1
+ robust_searching = TRUE
stat_attack = DEAD
obj_damage = 0
environment_smash = 0
diff --git a/code/modules/mob/living/simple_animal/hostile/hellhound.dm b/code/modules/mob/living/simple_animal/hostile/hellhound.dm
index 10c772e53fe..d451c015fa9 100644
--- a/code/modules/mob/living/simple_animal/hostile/hellhound.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hellhound.dm
@@ -20,14 +20,14 @@
maxHealth = 250 // same as sgt araneus
health = 250
obj_damage = 50
- robust_searching = 1
+ robust_searching = TRUE
stat_attack = UNCONSCIOUS
attacktext = "savages"
attack_sound = 'sound/effects/bite.ogg'
speak_emote = list("growls")
see_in_dark = 9
- universal_understand = 1
- wander = 0
+ universal_understand = TRUE
+ wander = FALSE
var/life_regen_cycles = 0
var/life_regen_cycle_trigger = 10 // heal once for every X number of cycles spent resting
var/life_regen_amount = -10 // negative, because negative = healing
@@ -109,7 +109,7 @@
maxHealth = 400
health = 400
force_threshold = 5 // no punching
- universal_speak = 1
+ universal_speak = TRUE
smoke_freq = 200
life_regen_cycle_trigger = 5
melee_damage_lower = 20
diff --git a/code/modules/mob/living/simple_animal/hostile/hivebot.dm b/code/modules/mob/living/simple_animal/hostile/hivebot.dm
index 6402526be42..83607cb383c 100644
--- a/code/modules/mob/living/simple_animal/hostile/hivebot.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hivebot.dm
@@ -19,7 +19,7 @@
projectilesound = 'sound/weapons/gunshots/gunshot.ogg'
projectiletype = /obj/item/projectile/hivebotbullet
faction = list("hivebot")
- check_friendly_fire = 1
+ check_friendly_fire = TRUE
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
speak_emote = list("states")
@@ -27,18 +27,18 @@
loot = list(/obj/effect/decal/cleanable/blood/gibs/robot)
deathmessage = "blows apart!"
bubble_icon = "machine"
- del_on_death = 1
+ del_on_death = TRUE
footstep_type = FOOTSTEP_MOB_CLAW
/mob/living/simple_animal/hostile/hivebot/range
name = "Hivebot"
desc = "A smallish robot, this one is armed!"
- ranged = 1
+ ranged = TRUE
retreat_distance = 5
minimum_distance = 5
/mob/living/simple_animal/hostile/hivebot/rapid
- ranged = 1
+ ranged = TRUE
rapid = 3
retreat_distance = 5
minimum_distance = 5
@@ -48,7 +48,7 @@
desc = "A robot, this one is armed and looks tough!"
health = 80
maxHealth = 80
- ranged = 1
+ ranged = TRUE
/mob/living/simple_animal/hostile/hivebot/death(gibbed)
// Only execute the below if we successfully died
@@ -66,8 +66,8 @@
health = 200
maxHealth = 200
status_flags = 0
- anchored = 1
- stop_automated_movement = 1
+ anchored = TRUE
+ stop_automated_movement = TRUE
var/bot_type = "norm"
var/bot_amt = 10
var/spawn_delay = 600
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index a9efb013fc9..526053b3c15 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -1,6 +1,6 @@
/mob/living/simple_animal/hostile
faction = list("hostile")
- stop_automated_movement_when_pulled = 0
+ stop_automated_movement_when_pulled = FALSE
obj_damage = 40
environment_smash = ENVIRONMENT_SMASH_STRUCTURES //Bitflags. Set to ENVIRONMENT_SMASH_STRUCTURES to break closets,tables,racks, etc; ENVIRONMENT_SMASH_WALLS for walls; ENVIRONMENT_SMASH_RWALLS for rwalls
var/atom/target
@@ -29,13 +29,13 @@
var/ranged_cooldown = 0 //What the current cooldown on ranged attacks is, generally world.time + ranged_cooldown_time
var/ranged_cooldown_time = 30 //How long, in deciseconds, the cooldown of ranged attacks is
var/ranged_ignores_vision = FALSE //if it'll fire ranged attacks even if it lacks vision on its target, only works with environment smash
- var/check_friendly_fire = 0 // Should the ranged mob check for friendlies when shooting
+ var/check_friendly_fire = FALSE // Should the ranged mob check for friendlies when shooting
var/retreat_distance = null //If our mob runs from players when they're too close, set in tile distance. By default, mobs do not retreat.
var/minimum_distance = 1 //Minimum approach distance, so ranged mobs chase targets down, but still keep their distance set in tiles to the target, set higher to make mobs keep distance
//These vars are related to how mobs locate and target
- var/robust_searching = 0 //By default, mobs have a simple searching method, set this to 1 for the more scrutinous searching (stat_attack, stat_exclusive, etc), should be disabled on most mobs
+ var/robust_searching = FALSE //By default, mobs have a simple searching method, set this to TRUE for the more scrutinous searching (stat_attack, stat_exclusive, etc), should be disabled on most mobs
var/vision_range = 9 //How big of an area to search for targets in, a vision of 9 attempts to find targets as soon as they walk into screen view
var/aggro_vision_range = 9 //If a mob is aggro, we search in this radius. Defaults to 9 to keep in line with original simple mob aggro radius
var/search_objects = 0 //If we want to consider objects when searching around, set this to 1. If you want to search for objects while also ignoring mobs until hurt, set it to 2. To completely ignore mobs, even when attacked, set it to 3
@@ -44,7 +44,7 @@
var/list/wanted_objects = list() //A typecache of objects types that will be checked against to attack, should we have search_objects enabled
var/stat_attack = CONSCIOUS //Mobs with stat_attack to UNCONSCIOUS will attempt to attack things that are unconscious, Mobs with stat_attack set to DEAD will attempt to attack the dead.
var/stat_exclusive = FALSE //Mobs with this set to TRUE will exclusively attack things defined by stat_attack, stat_attack DEAD means they will only attack corpses
- var/attack_same = 0 //Set us to 1 to allow us to attack our own faction
+ var/attack_same = FALSE //Set to TRUE to allow us to attack our own faction
var/atom/targets_from = null //all range/attack/etc. calculations should be done from this atom, defaults to the mob itself, useful for Vehicles and such
var/attack_all_objects = FALSE //if true, equivalent to having a wanted_objects list containing ALL objects.
@@ -257,7 +257,7 @@
AttackingTarget()
/mob/living/simple_animal/hostile/proc/MoveToTarget(list/possible_targets)//Step 5, handle movement between us and our target
- stop_automated_movement = 1
+ stop_automated_movement = TRUE
if(!target || !CanAttack(target))
LoseTarget()
return 0
@@ -334,7 +334,7 @@
taunt_chance = max(taunt_chance-7,2)
/mob/living/simple_animal/hostile/proc/LoseAggro()
- stop_automated_movement = 0
+ stop_automated_movement = FALSE
vision_range = initial(vision_range)
taunt_chance = initial(taunt_chance)
diff --git a/code/modules/mob/living/simple_animal/hostile/illusion.dm b/code/modules/mob/living/simple_animal/hostile/illusion.dm
index f225bbe1342..a4064cc2dce 100644
--- a/code/modules/mob/living/simple_animal/hostile/illusion.dm
+++ b/code/modules/mob/living/simple_animal/hostile/illusion.dm
@@ -18,7 +18,7 @@
var/mob/living/parent_mob
var/multiply_chance = 0 //if we multiply on hit
deathmessage = "vanishes into thin air! It was a fake!"
- del_on_death = 1
+ del_on_death = TRUE
/mob/living/simple_animal/hostile/illusion/Life()
diff --git a/code/modules/mob/living/simple_animal/hostile/jungle_animals.dm b/code/modules/mob/living/simple_animal/hostile/jungle_animals.dm
index 2a56141b08d..212f2d48b6b 100644
--- a/code/modules/mob/living/simple_animal/hostile/jungle_animals.dm
+++ b/code/modules/mob/living/simple_animal/hostile/jungle_animals.dm
@@ -18,7 +18,7 @@
response_help = "pets the"
response_disarm = "gently pushes aside the"
response_harm = "hits the"
- stop_automated_movement_when_pulled = 0
+ stop_automated_movement_when_pulled = FALSE
maxHealth = 50
health = 50
pixel_x = -16
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
index 7af7f747a52..08a8819831d 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
@@ -463,7 +463,7 @@ Difficulty: Medium
icon = 'icons/effects/fire.dmi'
icon_state = "1"
anchored = TRUE
- opacity = 0
+ opacity = FALSE
density = TRUE
duration = 82
color = COLOR_DARK_ORANGE
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
index 352eae47ead..8cf1a35dff8 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
@@ -30,15 +30,15 @@ Difficulty: Medium
armour_penetration = 50
melee_damage_lower = 25
melee_damage_upper = 25
- wander = 0
+ wander = FALSE
speed = 2
- ranged = 1
- del_on_death = 1
+ ranged = TRUE
+ del_on_death = TRUE
retreat_distance = 5
minimum_distance = 5
ranged_cooldown_time = 20
var/size = 5
- var/charging = 0
+ var/charging = FALSE
internal_type = /obj/item/gps/internal/legion
medal_type = BOSS_MEDAL_LEGION
score_type = LEGION_SCORE
@@ -46,7 +46,7 @@ Difficulty: Medium
pixel_x = -75
loot = list(/obj/item/stack/sheet/bone = 3)
vision_range = 13
- elimination = 1
+ elimination = TRUE
appearance_flags = 0
mouse_opacity = MOUSE_OPACITY_ICON
stat_attack = UNCONSCIOUS // Overriden from /tg/ - otherwise Legion starts chasing its minions
@@ -70,20 +70,20 @@ Difficulty: Medium
else
visible_message("[src] charges!")
SpinAnimation(speed = 20, loops = 5, parallel = FALSE)
- ranged = 0
+ ranged = FALSE
retreat_distance = 0
minimum_distance = 0
speed = 0
- charging = 1
+ charging = TRUE
spawn(50)
reset_charge()
/mob/living/simple_animal/hostile/megafauna/legion/proc/reset_charge()
- ranged = 1
+ ranged = TRUE
retreat_distance = 5
minimum_distance = 5
speed = 2
- charging = 0
+ charging = FALSE
/mob/living/simple_animal/hostile/megafauna/legion/can_die()
return ..() && health <= 0
@@ -126,7 +126,7 @@ Difficulty: Medium
break
if(last_legion)
loot = list(/obj/item/staff/storm)
- elimination = 0
+ elimination = FALSE
else if(prob(5))
loot = list(/obj/structure/closet/crate/necropolis/tendril)
if(!true_spawn)
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 f4f011bac85..69b8098542b 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
@@ -30,7 +30,7 @@
var/list/crusher_loot
var/medal_type
var/score_type = BOSS_SCORE
- var/elimination = 0
+ var/elimination = FALSE
var/anger_modifier = 0
var/obj/item/gps/internal_gps
var/internal_type
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/swarmer.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/swarmer.dm
index 0812991bfb9..d90528d0ea9 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/swarmer.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/swarmer.dm
@@ -106,7 +106,7 @@ GLOBAL_LIST_INIT(AISwarmerCapsByType, list(/mob/living/simple_animal/hostile/swa
//AI versions of the swarmer mini-antag
//This is an Abstract Base, it re-enables AI, but does not give the swarmer any goals/targets
/mob/living/simple_animal/hostile/swarmer/ai
- wander = 1
+ wander = TRUE
faction = list("swarmer", "mining")
weather_immunities = list("ash") //wouldn't be fun otherwise
AIStatus = AI_ON
diff --git a/code/modules/mob/living/simple_animal/hostile/mimic.dm b/code/modules/mob/living/simple_animal/hostile/mimic.dm
index 078b11c8965..88d602d8d6f 100644
--- a/code/modules/mob/living/simple_animal/hostile/mimic.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mimic.dm
@@ -31,7 +31,7 @@
var/is_electronic = 0
gold_core_spawnable = HOSTILE_SPAWN
- del_on_death = 1
+ del_on_death = TRUE
/mob/living/simple_animal/hostile/mimic/emp_act(severity)
if(is_electronic)
@@ -45,9 +45,9 @@
// Aggro when you try to open them. Will also pickup loot when spawns and drop it when dies.
/mob/living/simple_animal/hostile/mimic/crate
attacktext = "bites"
- stop_automated_movement = 1
- wander = 0
- var/attempt_open = 0
+ stop_automated_movement = TRUE
+ wander = FALSE
+ var/attempt_open = FALSE
// Pickup loot
/mob/living/simple_animal/hostile/mimic/crate/Initialize(mapload)
@@ -84,7 +84,7 @@
/mob/living/simple_animal/hostile/mimic/crate/proc/trigger()
if(!attempt_open)
visible_message("[src] starts to move!")
- attempt_open = 1
+ attempt_open = TRUE
/mob/living/simple_animal/hostile/mimic/crate/adjustHealth(amount, updating_health = TRUE)
trigger()
@@ -221,7 +221,7 @@ GLOBAL_LIST_INIT(protected_objects, list(/obj/structure/table, /obj/structure/ca
emote_see = list("aims menacingly")
obj_damage = 0
environment_smash = 0 //needed? seems weird for them to do so
- ranged = 1
+ ranged = TRUE
retreat_distance = 1 //just enough to shoot
minimum_distance = 6
var/obj/item/gun/G = O
@@ -277,7 +277,7 @@ GLOBAL_LIST_INIT(protected_objects, list(/obj/structure/table, /obj/structure/ca
Pewgun.chambered.loc = Pewgun
visible_message("The [src] cocks itself!")
else
- ranged = 0 //BANZAIIII
+ ranged = FALSE //BANZAIIII
retreat_distance = 0
minimum_distance = 1
return
diff --git a/code/modules/mob/living/simple_animal/hostile/mining/basilisk.dm b/code/modules/mob/living/simple_animal/hostile/mining/basilisk.dm
index 581a1b3b02e..8dbcc6f95c5 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining/basilisk.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining/basilisk.dm
@@ -12,7 +12,7 @@
move_to_delay = 20
projectiletype = /obj/item/projectile/temp/basilisk
projectilesound = 'sound/weapons/pierce.ogg'
- ranged = 1
+ ranged = TRUE
ranged_message = "stares"
ranged_cooldown_time = 30
throw_message = "does nothing against the hard shell of"
@@ -77,7 +77,7 @@
attack_sound = 'sound/weapons/bladeslice.ogg'
stat_attack = UNCONSCIOUS
flying = TRUE
- robust_searching = 1
+ robust_searching = TRUE
crusher_loot = /obj/item/crusher_trophy/watcher_wing
loot = list()
butcher_results = list(/obj/item/stack/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/mining/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
index 819612d0f34..a6fefabc5c5 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
@@ -10,7 +10,7 @@
mob_biotypes = MOB_ORGANIC
mouse_opacity = MOUSE_OPACITY_OPAQUE
move_to_delay = 14
- ranged = 1
+ ranged = TRUE
vision_range = 5
aggro_vision_range = 9
speed = 3
@@ -86,7 +86,7 @@
environment_smash = ENVIRONMENT_SMASH_NONE
pass_flags = PASSTABLE | PASSMOB
density = FALSE
- del_on_death = 1
+ del_on_death = TRUE
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/Initialize(mapload)
. = ..()
@@ -173,9 +173,9 @@
crusher_loot = /obj/item/crusher_trophy/legion_skull
loot = list(/obj/item/organ/internal/regenerative_core/legion)
brood_type = /mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion
- del_on_death = 1
+ del_on_death = TRUE
stat_attack = UNCONSCIOUS
- robust_searching = 1
+ robust_searching = TRUE
var/dwarf_mob = FALSE
var/mob/living/carbon/human/stored_mob
@@ -239,7 +239,7 @@
throw_message = "is shrugged off by"
del_on_death = TRUE
stat_attack = UNCONSCIOUS
- robust_searching = 1
+ robust_searching = TRUE
var/can_infest_dead = FALSE
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/Life(seconds, times_fired)
diff --git a/code/modules/mob/living/simple_animal/hostile/mushroom.dm b/code/modules/mob/living/simple_animal/hostile/mushroom.dm
index ed22692ffac..228077c5c02 100644
--- a/code/modules/mob/living/simple_animal/hostile/mushroom.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mushroom.dm
@@ -17,7 +17,7 @@
obj_damage = 0
melee_damage_lower = 1
melee_damage_upper = 1
- attack_same = 2
+ attack_same = 2 // this is usually a bool, but mushrooms are a special case
attacktext = "chomps"
attack_sound = 'sound/weapons/bite.ogg'
faction = list("mushroom")
@@ -26,7 +26,7 @@
mouse_opacity = MOUSE_OPACITY_ICON
speed = 1
ventcrawler = 2
- robust_searching = 1
+ robust_searching = TRUE
speak_emote = list("squeaks")
deathmessage = "fainted"
var/powerlevel = 0 //Tracks our general strength level gained from eating other shrooms
diff --git a/code/modules/mob/living/simple_animal/hostile/pirate.dm b/code/modules/mob/living/simple_animal/hostile/pirate.dm
index 8f475f2251b..281167e5523 100644
--- a/code/modules/mob/living/simple_animal/hostile/pirate.dm
+++ b/code/modules/mob/living/simple_animal/hostile/pirate.dm
@@ -27,7 +27,7 @@
speak_emote = list("yarrs")
loot = list(/obj/effect/mob_spawn/human/corpse/pirate,
/obj/item/melee/energy/sword/pirate)
- del_on_death = 1
+ del_on_death = TRUE
faction = list("pirate")
sentience_type = SENTIENCE_OTHER
footstep_type = FOOTSTEP_MOB_SHOE
@@ -38,7 +38,7 @@
icon_living = "pirateranged"
icon_dead = "piratemelee_dead" // Does not actually exist. del_on_death.
projectilesound = 'sound/weapons/laser.ogg'
- ranged = 1
+ ranged = TRUE
rapid = 2
retreat_distance = 5
minimum_distance = 5
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm
index 223241426f9..18bbb0f390b 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm
@@ -7,7 +7,7 @@
icon_living = "drone3"
icon_dead = "drone_dead"
mob_biotypes = MOB_ROBOTIC
- ranged = 1
+ ranged = TRUE
rapid = 3
retreat_distance = 3
minimum_distance = 3
@@ -29,7 +29,7 @@
minbodytemp = 0
faction = list("malf_drone")
deathmessage = "suddenly breaks apart."
- del_on_death = 1
+ del_on_death = TRUE
var/passive_mode = TRUE // if true, don't target anything.
/mob/living/simple_animal/hostile/malf_drone/Initialize(mapload)
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/fish.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/fish.dm
index 0422b3ccc9b..c0fd9d23cec 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/fish.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/fish.dm
@@ -24,7 +24,7 @@
attack_sound = 'sound/weapons/bite.ogg'
speak_emote = list("gnashes")
faction = list("carp")
- flying = 1
+ flying = TRUE
var/carp_color = "carp" //holder for icon set
var/static/list/carp_colors = list(\
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/undead.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/undead.dm
index 18a2d878d7f..1d958b3e561 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/undead.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/undead.dm
@@ -23,7 +23,7 @@
icon_living = "ghost2"
icon_dead = "ghost"
mob_biotypes = MOB_SPIRIT
- density = 0 // ghost
+ density = FALSE // ghost
invisibility = 60 // no seriously ghost
speak_chance = 0 // fyi, ghost
@@ -52,7 +52,7 @@
gold_core_spawnable = NO_SPAWN //too spooky for science
faction = list("undead") // did I mention ghost
loot = list(/obj/item/reagent_containers/food/snacks/ectoplasm)
- del_on_death = 1
+ del_on_death = TRUE
/mob/living/simple_animal/hostile/retaliate/ghost/Process_Spacemove(check_drift = 0)
return 1
@@ -91,7 +91,7 @@
faction = list("undead")
loot = list(/obj/effect/decal/remains/human)
- del_on_death = 1
+ del_on_death = TRUE
footstep_type = FOOTSTEP_MOB_SHOE
/mob/living/simple_animal/hostile/retaliate/zombie
@@ -121,4 +121,4 @@
faction = list("undead")
loot = list(/obj/effect/decal/cleanable/blood/gibs)
- del_on_death = 1
+ del_on_death = TRUE
diff --git a/code/modules/mob/living/simple_animal/hostile/russian.dm b/code/modules/mob/living/simple_animal/hostile/russian.dm
index 034b855d116..02b6886b6ef 100644
--- a/code/modules/mob/living/simple_animal/hostile/russian.dm
+++ b/code/modules/mob/living/simple_animal/hostile/russian.dm
@@ -26,14 +26,14 @@
status_flags = CANPUSH
loot = list(/obj/effect/mob_spawn/human/corpse/russian,
/obj/item/kitchen/knife)
- del_on_death = 1
+ del_on_death = TRUE
sentience_type = SENTIENCE_OTHER
footstep_type = FOOTSTEP_MOB_SHOE
/mob/living/simple_animal/hostile/russian/ranged
icon_state = "russianranged"
icon_living = "russianranged"
- ranged = 1
+ ranged = TRUE
retreat_distance = 5
minimum_distance = 5
projectilesound = 'sound/weapons/gunshots/gunshot.ogg'
diff --git a/code/modules/mob/living/simple_animal/hostile/skeleton.dm b/code/modules/mob/living/simple_animal/hostile/skeleton.dm
index ad736bce4d0..128a3cfab25 100644
--- a/code/modules/mob/living/simple_animal/hostile/skeleton.dm
+++ b/code/modules/mob/living/simple_animal/hostile/skeleton.dm
@@ -22,7 +22,7 @@
attack_sound = 'sound/hallucinations/growl1.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)
unsuitable_atmos_damage = 10
- robust_searching = 1
+ robust_searching = TRUE
stat_attack = UNCONSCIOUS
gold_core_spawnable = HOSTILE_SPAWN
faction = list("skeleton")
diff --git a/code/modules/mob/living/simple_animal/hostile/spaceworms.dm b/code/modules/mob/living/simple_animal/hostile/spaceworms.dm
index 6ab198a5611..082cee74232 100644
--- a/code/modules/mob/living/simple_animal/hostile/spaceworms.dm
+++ b/code/modules/mob/living/simple_animal/hostile/spaceworms.dm
@@ -21,7 +21,7 @@
maxHealth = 50
health = 50
- stop_automated_movement = 1
+ stop_automated_movement = TRUE
animate_movement = SYNC_STEPS
minbodytemp = 0
@@ -73,7 +73,7 @@
animate_movement = SLIDE_STEPS
AIStatus = AI_ON//The head is conscious
- stop_automated_movement = 0 //Ditto ^
+ stop_automated_movement = FALSE //Ditto ^
faction = list("spaceworms") //head and body both have this faction JIC
diff --git a/code/modules/mob/living/simple_animal/hostile/statue.dm b/code/modules/mob/living/simple_animal/hostile/statue.dm
index 7e3c0994507..a72dad6f6e6 100644
--- a/code/modules/mob/living/simple_animal/hostile/statue.dm
+++ b/code/modules/mob/living/simple_animal/hostile/statue.dm
@@ -17,7 +17,7 @@
speed = -1
maxHealth = 50000
health = 50000
- healable = 0
+ healable = FALSE
harm_intent_damage = 35
obj_damage = 100
@@ -47,7 +47,7 @@
pull_force = MOVE_FORCE_EXTREMELY_STRONG
status_flags = GODMODE // Cannot push also
- var/cannot_be_seen = 1
+ var/cannot_be_seen = TRUE
var/mob/living/creator = null
@@ -161,7 +161,7 @@
desc = "You will trigger a large amount of lights around you to flicker."
charge_max = 300
- clothes_req = 0
+ clothes_req = FALSE
/obj/effect/proc_holder/spell/aoe_turf/flicker_lights/create_new_targeting()
var/datum/spell_targeting/aoe/turf/T = new()
@@ -181,7 +181,7 @@
message = "You glare your eyes."
charge_max = 600
- clothes_req = 0
+ clothes_req = FALSE
/obj/effect/proc_holder/spell/aoe_turf/blindness/create_new_targeting()
var/datum/spell_targeting/aoe/turf/T = new()
diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
index 18dcacdfbb8..1e611ff7bdf 100644
--- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm
+++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
@@ -23,10 +23,10 @@
a_intent = INTENT_HARM
unsuitable_atmos_damage = 15
faction = list("syndicate")
- check_friendly_fire = 1
+ check_friendly_fire = TRUE
status_flags = CANPUSH
loot = list(/obj/effect/mob_spawn/human/corpse/syndicatesoldier)
- del_on_death = 1
+ del_on_death = TRUE
sentience_type = SENTIENCE_OTHER
footstep_type = FOOTSTEP_MOB_SHOE
@@ -82,14 +82,14 @@
/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot
name = "Syndicate Operative"
force_threshold = 6 // Prevents people using punches to bypass eshield
- robust_searching = 1 // Together with stat_attack, ensures dionae/etc that regen are killed properly
+ robust_searching = TRUE // Together with stat_attack, ensures dionae/etc that regen are killed properly
stat_attack = UNCONSCIOUS
- universal_speak = 1
+ universal_speak = TRUE
icon_state = "syndicate_swordonly"
icon_living = "syndicate_swordonly"
melee_block_chance = 0
ranged_block_chance = 0
- del_on_death = 1
+ del_on_death = TRUE
var/area/syndicate_depot/core/depotarea
var/raised_alert = FALSE
var/alert_on_death = FALSE
@@ -236,7 +236,7 @@
melee_damage_upper = 10
attacktext = "punches"
attack_sound = 'sound/weapons/punch1.ogg'
- ranged = 1
+ ranged = TRUE
rapid = 3
retreat_distance = 3
minimum_distance = 3
@@ -266,7 +266,7 @@
melee_damage_upper = 10
attacktext = "punches"
attack_sound = 'sound/weapons/punch1.ogg'
- ranged = 1
+ ranged = TRUE
retreat_distance = 3
minimum_distance = 3
melee_block_chance = 0
@@ -295,7 +295,7 @@
icon_state = "syndicate_space_sword"
icon_living = "syndicate_space_sword"
speed = 1
- wander = 0
+ wander = FALSE
alert_on_spacing = FALSE
/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/space/Process_Spacemove(movement_dir = 0)
@@ -317,7 +317,7 @@
/mob/living/simple_animal/hostile/syndicate/ranged
- ranged = 1
+ ranged = TRUE
rapid = 2
retreat_distance = 5
minimum_distance = 5
@@ -365,7 +365,7 @@
flying = TRUE
bubble_icon = "syndibot"
gold_core_spawnable = HOSTILE_SPAWN
- del_on_death = 1
+ del_on_death = TRUE
deathmessage = "is smashed into pieces!"
/mob/living/simple_animal/hostile/viscerator/Initialize(mapload)
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm
index f087e7b6f57..0f8979b7f99 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm
@@ -159,8 +159,8 @@
name = "terror web"
desc = "it's stringy and sticky"
icon = 'icons/effects/effects.dmi'
- anchored = 1 // prevents people dragging it
- density = 0 // prevents it blocking all movement
+ anchored = TRUE // prevents people dragging it
+ density = FALSE // prevents it blocking all movement
max_integrity = 20 // two welders, or one laser shot (15 for the normal spider webs)
icon_state = "stickyweb1"
var/creator_ckey = null
@@ -252,7 +252,7 @@
return
busy = SPINNING_COCOON
visible_message("[src] begins to secrete a sticky substance around [cocoon_target].")
- stop_automated_movement = 1
+ stop_automated_movement = TRUE
walk(src,0)
if(do_after(src, 40, target = cocoon_target.loc))
if(busy == SPINNING_COCOON)
@@ -291,7 +291,7 @@
C.icon_state = pick("cocoon_large1","cocoon_large2","cocoon_large3")
cocoon_target = null
busy = 0
- stop_automated_movement = 0
+ stop_automated_movement = FALSE
/mob/living/simple_animal/hostile/poison/terror_spider/proc/DoVentSmash()
var/valid_target = FALSE
@@ -308,7 +308,7 @@
if(do_after(src, 40, target = loc))
for(var/obj/machinery/atmospherics/unary/vent_pump/P in range(1, get_turf(src)))
if(P.welded)
- P.welded = 0
+ P.welded = FALSE
P.update_icon()
P.update_pipe_image()
forceMove(P.loc)
@@ -316,7 +316,7 @@
return
for(var/obj/machinery/atmospherics/unary/vent_scrubber/C in range(1, get_turf(src)))
if(C.welded)
- C.welded = 0
+ C.welded = FALSE
C.update_icon()
C.update_pipe_image()
forceMove(C.loc)
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/brown.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/brown.dm
index 389397da95c..4dd64209344 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/brown.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/brown.dm
@@ -23,7 +23,7 @@
spider_opens_doors = 2 // Breach specialist.
environment_smash = ENVIRONMENT_SMASH_RWALLS // Breaks anything.
spider_tier = TS_TIER_2
- ai_ventbreaker = 1
+ ai_ventbreaker = TRUE
freq_ventcrawl_combat = 600 // Ventcrawls very frequently, breaking open vents as it goes.
freq_ventcrawl_idle = 1800
web_type = null
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/gray.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/gray.dm
index 316dd65de61..06ccd8fbc0d 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/gray.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/gray.dm
@@ -55,7 +55,7 @@
/mob/living/simple_animal/hostile/poison/terror_spider/gray/spider_special_action()
if(prob(prob_ai_massweb))
for(var/turf/simulated/T in oview(2,get_turf(src)))
- if(T.density == 0)
+ if(!T.density)
var/obj/structure/spider/terrorweb/W = locate() in T
if(!W)
new web_type(T)
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/princess.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/princess.dm
index 787d89b722f..ca22e8c2750 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/princess.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/princess.dm
@@ -21,7 +21,7 @@
spider_tier = TS_TIER_3
// Unlike queens, no ranged attack.
- ranged = 0
+ ranged = FALSE
retreat_distance = 0
minimum_distance = 0
projectilesound = null
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/purple.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/purple.dm
index eb55ff2a9b3..b82a2ac5765 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/purple.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/purple.dm
@@ -111,5 +111,5 @@
/obj/structure/spider/terrorweb/purple
name = "thick web"
desc = "This web is so thick, most cannot see beyond it."
- opacity = 1
+ opacity = TRUE
max_integrity = 40
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm
index cd0a0646bc5..fae0239c272 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm
@@ -27,7 +27,7 @@
ai_ventcrawls = FALSE
idle_ventcrawl_chance = 0
force_threshold = 18 // outright immune to anything of force under 18, this means welders can't hurt it, only guns can
- ranged = 1
+ ranged = TRUE
retreat_distance = 5
minimum_distance = 5
projectilesound = 'sound/weapons/pierce.ogg'
@@ -172,7 +172,7 @@
else if(entry_vent)
if(!path_to_vent)
visible_message("\The [src] looks around warily - then seeks a better nesting ground.")
- path_to_vent = 1
+ path_to_vent = TRUE
else
neststep = -1
message_admins("Warning: [key_name_admin(src)] was spawned in an area without a vent! This is likely a mapping/spawn mistake. This mob's AI has been permanently deactivated.")
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/reproduction.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/reproduction.dm
index 28e67d9912d..fc4269a7e0e 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/reproduction.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/reproduction.dm
@@ -7,7 +7,7 @@
name = "spiderling"
desc = "A fast-moving tiny spider, prone to making aggressive hissing sounds. Hope it doesn't grow up."
icon_state = "spiderling"
- anchored = 0
+ anchored = FALSE
layer = 2.75
max_integrity = 3
var/stillborn = FALSE
@@ -101,7 +101,7 @@
return
if(travelling_in_vent)
if(isturf(loc))
- travelling_in_vent = 0
+ travelling_in_vent = FALSE
entry_vent = null
else if(entry_vent)
if(get_dist(src, entry_vent) <= 1)
@@ -179,7 +179,7 @@
// --------------------------------------------------------------------------------
/mob/living/simple_animal/hostile/poison/terror_spider/proc/DoLayTerrorEggs(lay_type, lay_number)
- stop_automated_movement = 1
+ stop_automated_movement = TRUE
var/obj/structure/spider/eggcluster/terror_eggcluster/C = new /obj/structure/spider/eggcluster/terror_eggcluster(get_turf(src), lay_type)
C.spiderling_number = lay_number
C.spider_myqueen = spider_myqueen
@@ -189,7 +189,7 @@
C.amount_grown = 250
C.spider_growinstantly = TRUE
spawn(10)
- stop_automated_movement = 0
+ stop_automated_movement = FALSE
/obj/structure/spider/eggcluster/terror_eggcluster
name = "terror egg cluster"
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_ai.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_ai.dm
index 03f13469ae0..f2b1a0fe728 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_ai.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_ai.dm
@@ -108,17 +108,17 @@
if(path_to_vent)
if(entry_vent)
if(spider_steps_taken > spider_max_steps)
- path_to_vent = 0
- stop_automated_movement = 0
+ path_to_vent = FALSE
+ stop_automated_movement = FALSE
spider_steps_taken = 0
- path_to_vent = 0
+ path_to_vent = FALSE
entry_vent = null
else if(get_dist(src, entry_vent) <= 1)
- path_to_vent = 0
- stop_automated_movement = 1
+ path_to_vent = FALSE
+ stop_automated_movement = TRUE
spider_steps_taken = 0
spawn(50)
- stop_automated_movement = 0
+ stop_automated_movement = FALSE
TSVentCrawlRandom(entry_vent)
else
spider_steps_taken++
@@ -127,13 +127,13 @@
if(spider_debug)
visible_message("[src] moves towards the vent [entry_vent].")
else
- path_to_vent = 0
+ path_to_vent = FALSE
else if(ai_break_lights && world.time > (last_break_light + freq_break_light))
last_break_light = world.time
for(var/obj/machinery/light/L in range(1, src))
if(!L.status)
step_to(src,L)
- L.on = 1
+ L.on = TRUE
L.break_light_tube()
do_attack_animation(L)
visible_message("[src] smashes the [L.name].")
@@ -154,7 +154,7 @@
entry_vent = v
vdistance = get_dist(src,v)
if(entry_vent)
- path_to_vent = 1
+ path_to_vent = TRUE
else
// If none of the general actions apply, check for class-specific actions.
spider_special_action()
@@ -206,7 +206,7 @@
spider_steps_taken = 0
cocoon_target = null
busy = 0
- stop_automated_movement = 0
+ stop_automated_movement = FALSE
else
spider_steps_taken++
CreatePath(cocoon_target)
@@ -228,7 +228,7 @@
if(istype(O, /obj/item) || istype(O, /obj/structure) || istype(O, /obj/machinery))
if(!istype(O, /obj/item/paper))
cocoon_target = O
- stop_automated_movement = 1
+ stop_automated_movement = TRUE
spider_steps_taken = 0
return
@@ -250,7 +250,7 @@
spawn(0)
try_open_airlock(A)
for(var/obj/machinery/door/firedoor/F in view(1, src))
- if(tgt_dir == get_dir(src,F) && F.density && !F.welded)
+ if(tgt_dir == get_dir(src, F) && F.density && !F.welded)
visible_message("[src] pries open the firedoor!")
F.open()
@@ -269,7 +269,7 @@
if(entry_vent)
if(get_dist(src, entry_vent) <= 2)
if(ai_ventbreaker && entry_vent.welded)
- entry_vent.welded = 0
+ entry_vent.welded = FALSE
entry_vent.update_icon()
entry_vent.visible_message("[src] smashes the welded cover off [entry_vent]!")
var/list/vents = list()
@@ -297,7 +297,7 @@
entry_vent = null
return
if(ai_ventbreaker && exit_vent.welded)
- exit_vent.welded = 0
+ exit_vent.welded = FALSE
exit_vent.update_icon()
exit_vent.update_pipe_image()
exit_vent.visible_message("[src] smashes the welded cover off [exit_vent]!")
@@ -315,7 +315,7 @@
/mob/living/simple_animal/hostile/poison/terror_spider/proc/ListValidTurfs()
var/list/potentials = list()
for(var/turf/simulated/T in oview(3,get_turf(src)))
- if(T.density == 0 && get_dist(get_turf(src),T) == 3)
+ if(!T.density && get_dist(get_turf(src), T) == 3)
var/obj/structure/spider/terrorweb/W = locate() in T
if(!W)
var/obj/structure/grille/G = locate() in T
@@ -328,7 +328,7 @@
/mob/living/simple_animal/hostile/poison/terror_spider/proc/ListWebbedTurfs()
var/list/webbed = list()
for(var/turf/simulated/T in oview(3,get_turf(src)))
- if(T.density == 0 && get_dist(get_turf(src),T) == 3)
+ if(!T.density && get_dist(get_turf(src), T) == 3)
var/obj/structure/spider/terrorweb/W = locate() in T
if(W)
webbed += T
@@ -337,7 +337,7 @@
/mob/living/simple_animal/hostile/poison/terror_spider/proc/ListVisibleTurfs()
var/list/vturfs = list()
for(var/turf/simulated/T in oview(7,get_turf(src)))
- if(T.density == 0)
+ if(!T.density)
vturfs += T
return vturfs
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm
index 8d6980114e0..53ab3c23334 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm
@@ -60,7 +60,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
var/freq_ventcrawl_combat = 1800 // 3 minutes
var/freq_ventcrawl_idle = 9000 // 15 minutes
var/last_ventcrawl_time = -9000 // Last time the spider crawled. Used to prevent excessive crawling. Setting to freq*-1 ensures they can crawl once on spawn.
- var/ai_ventbreaker = 0
+ var/ai_ventbreaker = FALSE
// AI movement tracking
var/spider_steps_taken = 0 // leave at 0, its a counter for ai steps taken.
@@ -119,11 +119,11 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
var/spider_opens_doors = 1 // all spiders can open firedoors (they have no security). 1 = can open depowered doors. 2 = can open powered doors
faction = list("terrorspiders")
- var/spider_awaymission = 0 // if 1, limits certain behavior in away missions
- var/spider_uo71 = 0 // if 1, spider is in the UO71 away mission
+ var/spider_awaymission = FALSE // if TRUE, limits certain behavior in away missions
+ var/spider_uo71 = FALSE // if TRUE, spider is in the UO71 away mission
var/spider_unlock_id_tag = "" // if defined, unlock awaymission blast doors with this tag on death
var/spider_role_summary = "UNDEFINED"
- var/spider_placed = 0
+ var/spider_placed = FALSE
// AI variables designed for use in procs
var/atom/movable/cocoon_target // for queen and nurse
@@ -131,15 +131,15 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
var/obj/machinery/atmospherics/unary/vent_pump/exit_vent // remote vent they intend to come out of
var/obj/machinery/atmospherics/unary/vent_pump/nest_vent // home vent, usually used by queens
var/fed = 0
- var/travelling_in_vent = 0
+ var/travelling_in_vent = FALSE
var/list/enemies = list()
- var/path_to_vent = 0
+ var/path_to_vent = FALSE
var/killcount = 0
var/busy = 0 // leave this alone!
var/spider_tier = TS_TIER_1 // 1 for red,gray,green. 2 for purple,black,white, 3 for prince, mother. 4 for queen
/// Does this terror speak loudly on the terror hivemind?
var/loudspeaker = FALSE
- var/hasdied = 0
+ var/hasdied = FALSE
var/list/spider_special_drops = list()
var/attackstep = 0
var/attackcycles = 0
@@ -282,16 +282,16 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
real_name = name
msg_terrorspiders("[src] has grown in [get_area(src)].")
if(is_away_level(z))
- spider_awaymission = 1
+ spider_awaymission = TRUE
GLOB.ts_count_alive_awaymission++
if(spider_tier >= 3)
ai_ventcrawls = FALSE // means that pre-spawned bosses on away maps won't ventcrawl. Necessary to keep prince/mother in one place.
if(istype(get_area(src), /area/awaymission/UO71)) // if we are playing the away mission with our special spiders...
- spider_uo71 = 1
+ spider_uo71 = TRUE
if(world.time < 600)
// these are static spiders, specifically for the UO71 away mission, make them stay in place
ai_ventcrawls = FALSE
- spider_placed = 1
+ spider_placed = TRUE
else
GLOB.ts_count_alive_station++
// after 3 seconds, assuming nobody took control of it yet, offer it to ghosts.
@@ -344,7 +344,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
/mob/living/simple_animal/hostile/poison/terror_spider/proc/handle_dying()
if(!hasdied)
- hasdied = 1
+ hasdied = TRUE
GLOB.ts_count_dead++
GLOB.ts_death_last = world.time
if(spider_awaymission)
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/white.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/white.dm
index 114ff403a23..4248ebb5e5c 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/white.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/white.dm
@@ -25,7 +25,7 @@
/mob/living/simple_animal/hostile/poison/terror_spider/white/LoseTarget()
- stop_automated_movement = 0
+ stop_automated_movement = FALSE
attackstep = 0
attackcycles = 0
..()
diff --git a/code/modules/mob/living/simple_animal/hostile/tree.dm b/code/modules/mob/living/simple_animal/hostile/tree.dm
index a659acd074b..9bec14512ef 100644
--- a/code/modules/mob/living/simple_animal/hostile/tree.dm
+++ b/code/modules/mob/living/simple_animal/hostile/tree.dm
@@ -35,7 +35,7 @@
loot = list(/obj/item/stack/sheet/wood)
gold_core_spawnable = HOSTILE_SPAWN
deathmessage = "is hacked into pieces!"
- del_on_death = 1
+ del_on_death = TRUE
/mob/living/simple_animal/hostile/tree/AttackingTarget()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm b/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm
index 7047d561f1e..3d8ab9d3e66 100644
--- a/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm
+++ b/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm
@@ -54,7 +54,7 @@
layer = MOB_LAYER + 0.9
health = 50
maxHealth = 50
- ranged = 1
+ ranged = TRUE
harm_intent_damage = 5
obj_damage = 60
melee_damage_lower = 25
@@ -69,7 +69,7 @@
var/grasp_chance = 20
var/grasp_pull_chance = 85
var/grasp_range = 4
- del_on_death = 1
+ del_on_death = TRUE
/mob/living/simple_animal/hostile/venus_human_trap/handle_automated_action()
if(..())
diff --git a/code/modules/mob/living/simple_animal/hostile/winter_mobs.dm b/code/modules/mob/living/simple_animal/hostile/winter_mobs.dm
index 1daf449af24..260d3d8f2b0 100644
--- a/code/modules/mob/living/simple_animal/hostile/winter_mobs.dm
+++ b/code/modules/mob/living/simple_animal/hostile/winter_mobs.dm
@@ -42,13 +42,13 @@
if(prob(20)) //chance to become a stationary snowman structure instead of a corpse
loot.Add(/obj/structure/snowman)
deathmessage = "shimmers as its animating magic fades away!"
- del_on_death = 1
+ del_on_death = TRUE
return ..()
/mob/living/simple_animal/hostile/winter/snowman/ranged
maxHealth = 50
health = 50
- ranged = 1
+ ranged = TRUE
retreat_distance = 5
minimum_distance = 5
projectiletype = /obj/item/projectile/snowball
@@ -105,7 +105,7 @@
death_message = "YOU'VE BEEN VERY NAUGHTY! PREPARE TO DIE!"
maxHealth = 200 //DID YOU REALLY BELIEVE IT WOULD BE THIS EASY!??!!
health = 200
- ranged = 1
+ ranged = TRUE
projectiletype = /obj/item/projectile/ornament
retreat_distance = 5
minimum_distance = 5
@@ -116,7 +116,7 @@
death_message = "FACE MY FINAL FORM AND KNOW DESPAIR!"
maxHealth = 250
health = 250
- ranged = 1
+ ranged = TRUE
rapid = 3
speed = 0 //he's lost some weight from the fighting
projectiletype = /obj/item/projectile/ornament
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 796bb5b7dbf..48184d06b4c 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -164,7 +164,7 @@
health = clamp(health, 0, maxHealth)
med_hud_set_health()
-/mob/living/simple_animal/lay_down()
+/mob/living/simple_animal/on_lying_down(new_lying_angle)
..()
if(icon_resting && stat != DEAD)
icon_state = icon_resting
@@ -173,7 +173,7 @@
regenerate_icons()
ADD_TRAIT(src, TRAIT_IMMOBILIZED, LYING_DOWN_TRAIT) //simple mobs cannot crawl
-/mob/living/simple_animal/stand_up()
+/mob/living/simple_animal/on_standing_up()
..()
if(icon_resting && stat != DEAD)
icon_state = icon_living
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index e421fda4303..5c885a06add 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -923,7 +923,7 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
if(isliving(M))
var/mob/living/L = M
if(L.mob_size <= MOB_SIZE_SMALL)
- return // Stops pAI drones and small mobs (borers, parrots, crabs) from stripping people. --DZD
+ return // Stops pAI drones and small mobs (parrots, crabs) from stripping people. --DZD
if(!M.can_strip)
return
if(usr == src)
diff --git a/code/modules/mob/new_player/sprite_accessories/vulpkanin/vulpkanin_hair.dm b/code/modules/mob/new_player/sprite_accessories/vulpkanin/vulpkanin_hair.dm
index a3e3339b1eb..fba5078f1e4 100644
--- a/code/modules/mob/new_player/sprite_accessories/vulpkanin/vulpkanin_hair.dm
+++ b/code/modules/mob/new_player/sprite_accessories/vulpkanin/vulpkanin_hair.dm
@@ -85,3 +85,7 @@
name = "Raine"
icon_state = "raine"
gender = FEMALE
+
+/datum/sprite_accessory/hair/vulpkanin/vulp_hair_jeremy
+ name = "Jeremy"
+ icon_state = "jeremy"
diff --git a/code/modules/pda/PDA.dm b/code/modules/pda/PDA.dm
index d6073d3d271..0ac05d5209c 100755
--- a/code/modules/pda/PDA.dm
+++ b/code/modules/pda/PDA.dm
@@ -34,7 +34,7 @@ GLOBAL_LIST_EMPTY(PDAs)
var/silent = FALSE //To beep or not to beep, that is the question
var/honkamt = 0 //How many honks left when infected with honk.exe
var/mimeamt = 0 //How many silence left when infected with mime.exe
- var/detonate = 1 // Can the PDA be blown up?
+ var/detonate = TRUE // Can the PDA be blown up?
var/ttone = "beep" //The ringtone!
var/list/ttone_sound = list("beep" = 'sound/machines/twobeep.ogg',
"boom" = 'sound/effects/explosionfar.ogg',
diff --git a/code/modules/pda/ai.dm b/code/modules/pda/ai.dm
index bfbecad1b5b..caebaa35e91 100644
--- a/code/modules/pda/ai.dm
+++ b/code/modules/pda/ai.dm
@@ -1,7 +1,7 @@
// Special AI/pAI PDAs that cannot explode.
/obj/item/pda/silicon
icon_state = "NONE"
- detonate = 0
+ detonate = FALSE
ttone = "data"
/obj/item/pda/silicon/proc/set_name_and_job(newname as text, newjob as text, newrank as null|text)
diff --git a/code/modules/pda/pdas.dm b/code/modules/pda/pdas.dm
index 3c961103b20..f39bea4200d 100644
--- a/code/modules/pda/pdas.dm
+++ b/code/modules/pda/pdas.dm
@@ -74,7 +74,7 @@
/obj/item/pda/captain
default_cartridge = /obj/item/cartridge/captain
icon_state = "pda-captain"
- detonate = 0
+ detonate = FALSE
//toff = 1
/obj/item/pda/heads/ntrep
@@ -90,6 +90,8 @@
icon_state = "pda-h"
/obj/item/pda/heads/ert
+ default_cartridge = /obj/item/cartridge/centcom
+ detonate = FALSE
/obj/item/pda/heads/ert/engineering
icon_state = "pda-engineer"
diff --git a/code/modules/power/generator.dm b/code/modules/power/generator.dm
index fb29993543b..6b43ffd907d 100644
--- a/code/modules/power/generator.dm
+++ b/code/modules/power/generator.dm
@@ -16,6 +16,9 @@
var/lastgenlev = -1
var/lastcirc = "00"
+ var/light_range_on = 1
+ var/light_power_on = 0.1 //just dont want it to be culled by byond.
+
/obj/machinery/power/generator/Initialize(mapload)
. = ..()
update_desc()
@@ -36,6 +39,10 @@
if(powernet)
disconnect_from_network()
+/obj/machinery/power/generator/Initialize()
+ . = ..()
+ connect()
+
/obj/machinery/power/generator/proc/connect()
connect_to_network()
@@ -60,21 +67,29 @@
updateDialog()
/obj/machinery/power/generator/power_change()
+ . = ..()
if(!anchored)
stat |= NOPOWER
+ if((stat & (BROKEN|NOPOWER)))
+ set_light(0)
else
- ..()
+ set_light(light_range_on, light_power_on)
+ update_icon()
+
/obj/machinery/power/generator/update_icon()
if(stat & (NOPOWER|BROKEN))
- overlays.Cut()
+ cut_overlays()
+ underlays.Cut()
+ return
else
- overlays.Cut()
-
+ cut_overlays()
if(lastgenlev != 0)
- overlays += image('icons/obj/power.dmi', "teg-op[lastgenlev]")
+ add_overlay(mutable_appearance('icons/obj/power.dmi', "teg-op[lastgenlev]"))
+ underlays += emissive_appearance(icon, "teg-op[lastgenlev]")
- overlays += image('icons/obj/power.dmi', "teg-oc[lastcirc]")
+ add_overlay(mutable_appearance('icons/obj/power.dmi', "teg-oc[lastcirc]"))
+ underlays += emissive_appearance(icon, "teg-oc[lastcirc]")
/obj/machinery/power/generator/process()
if(stat & (NOPOWER|BROKEN))
@@ -230,7 +245,3 @@
if(!powernet || !cold_circ || !hot_circ)
connect()
return TRUE
-
-/obj/machinery/power/generator/power_change()
- ..()
- update_icon()
diff --git a/code/modules/projectiles/ammunition/energy.dm b/code/modules/projectiles/ammunition/energy.dm
index c1e40323915..e8c2bf7ef55 100644
--- a/code/modules/projectiles/ammunition/energy.dm
+++ b/code/modules/projectiles/ammunition/energy.dm
@@ -316,16 +316,16 @@
..(mimic_type)
/obj/item/ammo_casing/energy/detective
- projectile_type = /obj/item/projectile/energy/detective
+ projectile_type = /obj/item/projectile/beam/laser/detective
fire_sound = 'sound/weapons/gunshots/gunshot_det_energy.ogg'
select_name = "disabler"
/obj/item/ammo_casing/energy/detective/tracker_warrant
- projectile_type = /obj/item/projectile/energy/detective/tracker_warrant_shot
+ projectile_type = /obj/item/projectile/beam/laser/detective/tracker_warrant_shot
e_cost = 50
select_name = "tracker and warrant generator"
/obj/item/ammo_casing/energy/detective/overcharge
- projectile_type = /obj/item/projectile/energy/detective/overcharged
+ projectile_type = /obj/item/projectile/beam/laser/detective/overcharged
e_cost = 200
select_name = "overcharged"
diff --git a/code/modules/projectiles/ammunition/magazines.dm b/code/modules/projectiles/ammunition/magazines.dm
index 9066d4844c8..af6ec80673d 100644
--- a/code/modules/projectiles/ammunition/magazines.dm
+++ b/code/modules/projectiles/ammunition/magazines.dm
@@ -263,14 +263,17 @@
/obj/item/ammo_box/magazine/wt550m9/wtap
name = "wt550 magazine (Armour Piercing 4.6x30mm)"
+ icon_state = "46x30mmtA"
ammo_type = /obj/item/ammo_casing/c46x30mm/ap
/obj/item/ammo_box/magazine/wt550m9/wttx
name = "wt550 magazine (Toxin Tipped 4.6x30mm)"
+ icon_state = "46x30mmtT"
ammo_type = /obj/item/ammo_casing/c46x30mm/tox
/obj/item/ammo_box/magazine/wt550m9/wtic
name = "wt550 magazine (Incendiary 4.6x30mm)"
+ icon_state = "46x30mmtI"
ammo_type = /obj/item/ammo_casing/c46x30mm/inc
/obj/item/ammo_box/magazine/uzim9mm
@@ -305,13 +308,13 @@
ammo_type = /obj/item/ammo_casing/c9mm/inc
materials = list(MAT_METAL = 3000)
-/obj/item/ammo_box/magazine/pistolm9mm
- name = "pistol magazine (9mm)"
- icon_state = "9x19p"
+/obj/item/ammo_box/magazine/apsm9mm
+ name = "stechkin aps magazine (9mm)"
+ icon_state = "9mmaps"
ammo_type = /obj/item/ammo_casing/c9mm
caliber = "9mm"
max_ammo = 15
- multi_sprite_step = AMMO_MULTI_SPRITE_STEP_ON_OFF
+ multi_sprite_step = 5
/obj/item/ammo_box/magazine/smgm45
name = "\improper SMG magazine (.45)"
@@ -362,7 +365,7 @@
/obj/item/ammo_box/magazine/m12g
name = "shotgun magazine (12g slugs)"
desc = "A drum magazine."
- icon_state = "m12gb"
+ icon_state = "m12gsl"
ammo_type = /obj/item/ammo_casing/shotgun
origin_tech = "combat=3;syndicate=1"
caliber = "shotgun"
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index ffdbe489a29..4d27dec5122 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -13,18 +13,18 @@
throw_range = 5
force = 5
origin_tech = "combat=1"
- needs_permit = 1
+ needs_permit = TRUE
attack_verb = list("struck", "hit", "bashed")
var/fire_sound = "gunshot"
var/magin_sound = 'sound/weapons/gun_interactions/smg_magin.ogg'
var/magout_sound = 'sound/weapons/gun_interactions/smg_magout.ogg'
var/fire_sound_text = "gunshot" //the fire sound that shows in chat messages: laser blast, gunshot, etc.
- var/suppressed = 0 //whether or not a message is displayed when fired
- var/can_suppress = 0
- var/can_unsuppress = 1
+ var/suppressed = FALSE //whether or not a message is displayed when fired
+ var/can_suppress = FALSE
+ var/can_unsuppress = TRUE
var/recoil = 0 //boom boom shake the room
- var/clumsy_check = 1
+ var/clumsy_check = TRUE
var/obj/item/ammo_casing/chambered = null
var/trigger_guard = TRIGGER_GUARD_NORMAL //trigger guard on the weapon, hulks can't fire them with their big meaty fingers
var/sawn_desc = null //description change if weapon is sawn-off
@@ -47,7 +47,7 @@
righthand_file = 'icons/mob/inhands/guns_righthand.dmi'
var/obj/item/flashlight/gun_light = null
- var/can_flashlight = 0
+ var/can_flashlight = FALSE
var/can_bayonet = FALSE //if a bayonet can be added or removed if it already has one.
var/obj/item/kitchen/knife/bayonet
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index 28a1f199950..94e846e86ad 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -10,12 +10,12 @@
var/modifystate = 0
var/list/ammo_type = list(/obj/item/ammo_casing/energy)
var/select = 1 //The state of the select fire switch. Determines from the ammo_type list what kind of shot is fired next.
- var/can_charge = 1
+ var/can_charge = TRUE
var/charge_sections = 4
var/inhand_charge_sections = 4
ammo_x_offset = 2
- var/shaded_charge = 0 //if this gun uses a stateful charge bar for more detail
- var/selfcharge = 0
+ var/shaded_charge = FALSE //if this gun uses a stateful charge bar for more detail
+ var/selfcharge = FALSE
var/charge_tick = 0
var/charge_delay = 4
/// Do you want the gun to fit into a turret, defaults to true, used for if a energy gun is too strong to be in a turret, or does not make sense to be in one.
diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
index fc19c2e12ed..ec3e0bd05f8 100644
--- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
+++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
@@ -5,10 +5,10 @@
item_state = "kineticgun"
ammo_type = list(/obj/item/ammo_casing/energy/kinetic)
cell_type = /obj/item/stock_parts/cell/emproof
- needs_permit = 0
+ needs_permit = FALSE
origin_tech = "combat=3;powerstorage=3;engineering=3"
weapon_weight = WEAPON_LIGHT
- can_flashlight = 1
+ can_flashlight = TRUE
flight_x_offset = 15
flight_y_offset = 9
var/overheat_time = 16
diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm
index c76b38350d1..723e56608e0 100644
--- a/code/modules/projectiles/guns/energy/laser.dm
+++ b/code/modules/projectiles/guns/energy/laser.dm
@@ -15,8 +15,8 @@
desc = "A modified version of the basic laser gun, this one fires less concentrated energy bolts designed for target practice."
origin_tech = "combat=2;magnets=2"
ammo_type = list(/obj/item/ammo_casing/energy/laser/practice)
- clumsy_check = 0
- needs_permit = 0
+ clumsy_check = FALSE
+ needs_permit = FALSE
/obj/item/gun/energy/laser/retro
name ="retro laser gun"
@@ -27,12 +27,12 @@
/obj/item/gun/energy/laser/captain
name = "antique laser gun"
icon_state = "caplaser"
- item_state = "caplaser"
+ item_state = null
desc = "This is an antique laser gun. All craftsmanship is of the highest quality. It is decorated with assistant leather and chrome. The object menaces with spikes of energy. On the item is an image of Space Station 13. The station is exploding."
force = 10
origin_tech = null
ammo_x_offset = 3
- selfcharge = 1
+ selfcharge = TRUE
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
/obj/item/gun/energy/laser/captain/detailed_examine()
@@ -45,10 +45,10 @@
desc = "An industrial-grade heavy-duty laser rifle with a modified laser lense to scatter its shot into multiple smaller lasers. The inner-core can self-charge for theorically infinite use."
origin_tech = "combat=5;materials=4;powerstorage=4"
ammo_type = list(/obj/item/ammo_casing/energy/laser/scatter, /obj/item/ammo_casing/energy/laser)
- shaded_charge = 0
+ shaded_charge = FALSE
/obj/item/gun/energy/laser/cyborg
- can_charge = 0
+ can_charge = FALSE
desc = "An energy-based laser gun that draws power from the cyborg's internal energy cell directly. So this is what freedom looks like?"
ammo_type = list(/obj/item/ammo_casing/energy/laser/cyborg)
origin_tech = null
@@ -71,7 +71,7 @@
name = "accelerator laser cannon"
desc = "An advanced laser cannon that does more damage the farther away the target is."
icon_state = "lasercannon"
- item_state = "laser"
+ item_state = null
w_class = WEIGHT_CLASS_BULKY
force = 10
flags = CONDUCT
@@ -121,7 +121,7 @@
item_state = "laser"
ammo_type = list(/obj/item/ammo_casing/energy/immolator)
origin_tech = "combat=4;magnets=4;powerstorage=3"
- shaded_charge = 1
+ shaded_charge = TRUE
/obj/item/gun/energy/immolator/multi
name = "multi lens immolator cannon"
@@ -171,10 +171,10 @@
name = "laser tag gun"
desc = "Standard issue weapon of the Imperial Guard"
origin_tech = "combat=2;magnets=2"
- clumsy_check = 0
- needs_permit = 0
+ clumsy_check = FALSE
+ needs_permit = FALSE
ammo_x_offset = 2
- selfcharge = 1
+ selfcharge = TRUE
/obj/item/gun/energy/laser/tag/blue
icon_state = "bluetag"
diff --git a/code/modules/projectiles/guns/energy/nuclear.dm b/code/modules/projectiles/guns/energy/nuclear.dm
index a4686389335..8ef30631949 100644
--- a/code/modules/projectiles/guns/energy/nuclear.dm
+++ b/code/modules/projectiles/guns/energy/nuclear.dm
@@ -6,7 +6,7 @@
ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser)
origin_tech = "combat=4;magnets=3"
modifystate = 2
- can_flashlight = 1
+ can_flashlight = TRUE
flight_x_offset = 20
flight_y_offset = 10
shaded_charge = TRUE
@@ -33,7 +33,7 @@
ammo_x_offset = 2
charge_sections = 3
inhand_charge_sections = 3
- can_flashlight = 0 // Can't attach or detach the flashlight, and override it's icon update
+ can_flashlight = FALSE // Can't attach or detach the flashlight, and override it's icon update
actions_types = list(/datum/action/item_action/toggle_gunlight)
shaded_charge = FALSE
can_holster = TRUE // Pistol sized, so it should fit into a holster
@@ -67,7 +67,7 @@
desc = "An advanced energy revolver with the capacity to shoot both disablers and lasers."
cell_type = /obj/item/stock_parts/cell/hos_gun
icon_state = "bsgun"
- item_state = "gun"
+ item_state = null
force = 7
ammo_type = list(/obj/item/ammo_casing/energy/disabler/hos, /obj/item/ammo_casing/energy/laser/hos)
ammo_x_offset = 1
@@ -78,6 +78,7 @@
name = "\improper PDW-9 taser pistol"
desc = "A military grade sidearm, used by many militia forces throughout the local sector."
icon_state = "pdw9pistol"
+ item_state = "gun"
/obj/item/gun/energy/gun/turret
name = "hybrid turret gun"
@@ -88,7 +89,7 @@
w_class = WEIGHT_CLASS_HUGE
ammo_type = list(/obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/laser)
weapon_weight = WEAPON_HEAVY
- can_flashlight = 0
+ can_flashlight = FALSE
trigger_guard = TRIGGER_GUARD_NONE
ammo_x_offset = 2
shaded_charge = FALSE
@@ -97,16 +98,16 @@
name = "advanced energy gun"
desc = "An energy gun with an experimental miniaturized nuclear reactor that automatically charges the internal power cell."
icon_state = "nucgun"
- item_state = "nucgun"
+ item_state = null
origin_tech = "combat=4;magnets=4;powerstorage=4"
var/fail_tick = 0
charge_delay = 5
- can_charge = 0
+ can_charge = FALSE
ammo_x_offset = 1
ammo_type = list(/obj/item/ammo_casing/energy/laser, /obj/item/ammo_casing/energy/disabler)
- selfcharge = 1
+ selfcharge = TRUE
shaded_charge = FALSE
/obj/item/gun/energy/gun/nuclear/detailed_examine()
- return "This is an energy weapon. Most energy weapons can fire through windows harmlessly. To switch between stun and lethal, click the weapon \
+ return "This is an energy weapon. Most energy weapons can fire through windows harmlessly. To switch between disable and lethal, click the weapon \
in your hand. Unlike most weapons, this weapon recharges itself."
diff --git a/code/modules/projectiles/guns/energy/pulse.dm b/code/modules/projectiles/guns/energy/pulse.dm
index 7b2adb6cddd..41e944159db 100644
--- a/code/modules/projectiles/guns/energy/pulse.dm
+++ b/code/modules/projectiles/guns/energy/pulse.dm
@@ -6,6 +6,7 @@
w_class = WEIGHT_CLASS_BULKY
can_holster = FALSE
force = 10
+ modifystate = TRUE
flags = CONDUCT
slot_flags = SLOT_BACK
ammo_type = list(/obj/item/ammo_casing/energy/laser/pulse, /obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/laser)
@@ -26,9 +27,9 @@
w_class = WEIGHT_CLASS_NORMAL
slot_flags = SLOT_BELT
icon_state = "pulse_carbine"
- item_state = "pulse"
+ item_state = null
cell_type = /obj/item/stock_parts/cell/pulse/carbine
- can_flashlight = 1
+ can_flashlight = TRUE
flight_x_offset = 18
flight_y_offset = 12
@@ -38,10 +39,9 @@
w_class = WEIGHT_CLASS_SMALL
slot_flags = SLOT_BELT
icon_state = "pulse_pistol"
- item_state = "gun"
+ item_state = null
can_holster = TRUE
cell_type = /obj/item/stock_parts/cell/pulse/pistol
- can_charge = 0
/obj/item/gun/energy/pulse/destroyer
name = "pulse destroyer"
@@ -74,6 +74,6 @@
w_class = WEIGHT_CLASS_HUGE
ammo_type = list(/obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/laser/pulse)
weapon_weight = WEAPON_MEDIUM
- can_flashlight = 0
+ can_flashlight = FALSE
trigger_guard = TRIGGER_GUARD_NONE
ammo_x_offset = 2
diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm
index 619e9904e97..b15dadd7e27 100644
--- a/code/modules/projectiles/guns/energy/special.dm
+++ b/code/modules/projectiles/guns/energy/special.dm
@@ -13,6 +13,7 @@
can_holster = FALSE
flags = CONDUCT
slot_flags = SLOT_BACK
+ shaded_charge = TRUE
ammo_type = list(/obj/item/ammo_casing/energy/ion)
ammo_x_offset = 3
flight_x_offset = 17
@@ -59,7 +60,7 @@
origin_tech = "materials=2;biotech=4"
modifystate = 1
ammo_x_offset = 1
- selfcharge = 1
+ selfcharge = TRUE
can_holster = TRUE
// Meteor Gun //
@@ -73,8 +74,8 @@
w_class = WEIGHT_CLASS_BULKY
ammo_type = list(/obj/item/ammo_casing/energy/meteor)
cell_type = /obj/item/stock_parts/cell/potato
- clumsy_check = 0 //Admin spawn only, might as well let clowns use it.
- selfcharge = 1
+ clumsy_check = FALSE //Admin spawn only, might as well let clowns use it.
+ selfcharge = TRUE
/obj/item/gun/energy/meteorgun/pen
name = "meteor pen"
@@ -104,16 +105,16 @@
w_class = WEIGHT_CLASS_SMALL
materials = list(MAT_METAL=2000)
origin_tech = "combat=4;magnets=4;syndicate=5"
- suppressed = 1
+ suppressed = TRUE
ammo_type = list(/obj/item/ammo_casing/energy/bolt)
weapon_weight = WEAPON_LIGHT
unique_rename = FALSE
overheat_time = 20
holds_charge = TRUE
unique_frequency = TRUE
- can_flashlight = 0
+ can_flashlight = FALSE
max_mod_capacity = 0
- empty_state = null
+ empty_state = "crossbow_empty"
can_holster = TRUE
/obj/item/gun/energy/kinetic_accelerator/crossbow/detailed_examine()
@@ -131,8 +132,9 @@
w_class = WEIGHT_CLASS_NORMAL
materials = list(MAT_METAL=4000)
origin_tech = "combat=4;magnets=4;syndicate=2"
- suppressed = 0
+ suppressed = FALSE
ammo_type = list(/obj/item/ammo_casing/energy/bolt/large)
+ empty_state = "crossbowlarge_empty"
/obj/item/gun/energy/kinetic_accelerator/crossbow/large/cyborg
desc = "One and done!"
@@ -163,8 +165,8 @@
flags = CONDUCT
attack_verb = list("attacked", "slashed", "cut", "sliced")
force = 12
- sharp = 1
- can_charge = 0
+ sharp = TRUE
+ can_charge = FALSE
can_holster = TRUE
/obj/item/gun/energy/plasmacutter/attackby(obj/item/A, mob/user)
@@ -258,7 +260,7 @@
icon = 'icons/obj/guns/projectile.dmi'
cell_type = /obj/item/stock_parts/cell/secborg
ammo_type = list(/obj/item/ammo_casing/energy/c3dbullet)
- can_charge = 0
+ can_charge = FALSE
/obj/item/gun/energy/printer/update_icon()
return
@@ -297,8 +299,8 @@
desc = "Clown Planet's finest."
icon_state = "disabler"
ammo_type = list(/obj/item/ammo_casing/energy/clown)
- clumsy_check = 0
- selfcharge = 1
+ clumsy_check = FALSE
+ selfcharge = TRUE
ammo_x_offset = 3
can_holster = TRUE // you'll never see it coming
@@ -311,7 +313,7 @@
w_class = WEIGHT_CLASS_NORMAL
origin_tech = "combat=4;magnets=4;powerstorage=3"
ammo_type = list(/obj/item/ammo_casing/energy/weak_plasma, /obj/item/ammo_casing/energy/charged_plasma)
- shaded_charge = 1
+ shaded_charge = TRUE
can_holster = TRUE
atom_say_verb = "beeps"
bubble_icon = "swarmer"
@@ -571,7 +573,7 @@
origin_tech = "combat=4;materials=4;powerstorage=3;magnets=2"
ammo_type = list(/obj/item/ammo_casing/energy/temp)
- selfcharge = 1
+ selfcharge = TRUE
var/powercost = ""
var/powercostcolor = ""
@@ -744,8 +746,8 @@
desc = "A self-defense weapon that exhausts organic targets, weakening them until they collapse. Why does this one have teeth?"
icon_state = "disabler"
ammo_type = list(/obj/item/ammo_casing/energy/mimic)
- clumsy_check = 0 //Admin spawn only, might as well let clowns use it.
- selfcharge = 1
+ clumsy_check = FALSE //Admin spawn only, might as well let clowns use it.
+ selfcharge = TRUE
ammo_x_offset = 3
var/mimic_type = /obj/item/gun/projectile/automatic/pistol //Setting this to the mimicgun type does exactly what you think it will.
can_holster = TRUE
diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm
index 555781b34aa..4574adffe8f 100644
--- a/code/modules/projectiles/guns/energy/stun.dm
+++ b/code/modules/projectiles/guns/energy/stun.dm
@@ -15,7 +15,7 @@
item_state = "gun"
origin_tech = "combat=4;materials=4;powerstorage=4"
ammo_type = list(/obj/item/ammo_casing/energy/shock_revolver)
- can_flashlight = 0
+ can_flashlight = FALSE
shaded_charge = FALSE
can_holster = TRUE
@@ -38,8 +38,8 @@
/obj/item/gun/energy/gun/advtaser/cyborg
name = "cyborg taser"
desc = "An integrated hybrid taser that draws directly from a cyborg's power cell. The weapon contains a limiter to prevent the cyborg's power cell from overheating."
- can_flashlight = 0
- can_charge = 0
+ can_flashlight = FALSE
+ can_charge = FALSE
/obj/item/gun/energy/gun/advtaser/cyborg/newshot()
..()
@@ -62,7 +62,7 @@
name = "cyborg disabler"
desc = "An integrated disabler that draws from a cyborg's power cell. This weapon contains a limiter to prevent the cyborg's power cell from overheating."
ammo_type = list(/obj/item/ammo_casing/energy/disabler/cyborg)
- can_charge = 0
+ can_charge = FALSE
/obj/item/gun/energy/disabler/cyborg/newshot()
..()
diff --git a/code/modules/projectiles/guns/energy/telegun.dm b/code/modules/projectiles/guns/energy/telegun.dm
index 705254adef4..17b1aca227b 100644
--- a/code/modules/projectiles/guns/energy/telegun.dm
+++ b/code/modules/projectiles/guns/energy/telegun.dm
@@ -7,7 +7,7 @@
item_state = "ionrifle"
origin_tech = "combat=6;materials=7;powerstorage=5;bluespace=5;syndicate=4"
ammo_type = list(/obj/item/ammo_casing/energy/teleport)
- shaded_charge = 1
+ shaded_charge = TRUE
var/teleport_target = null
/obj/item/gun/energy/telegun/Destroy()
@@ -24,7 +24,7 @@
continue
if(!is_teleport_allowed(T.z))
continue
- if(R.syndicate == 1)
+ if(R.syndicate)
continue
var/tmpname = T.loc.name
if(areaindex[tmpname])
diff --git a/code/modules/projectiles/guns/grenade_launcher.dm b/code/modules/projectiles/guns/grenade_launcher.dm
index 1b88098ed15..a2c4e3bd46d 100644
--- a/code/modules/projectiles/guns/grenade_launcher.dm
+++ b/code/modules/projectiles/guns/grenade_launcher.dm
@@ -50,7 +50,7 @@
F.throw_at(target, 30, 2, user)
message_admins("[key_name_admin(user)] fired a grenade ([F.name]) from a grenade launcher ([name]).")
log_game("[key_name(user)] fired a grenade ([F.name]) from a grenade launcher ([name]).")
- F.active = 1
+ F.active = TRUE
F.icon_state = initial(icon_state) + "_active"
playsound(user.loc, 'sound/weapons/armbomb.ogg', 75, 1, -3)
spawn(15)
diff --git a/code/modules/projectiles/guns/magic.dm b/code/modules/projectiles/guns/magic.dm
index b03bd121615..330dd8864ec 100644
--- a/code/modules/projectiles/guns/magic.dm
+++ b/code/modules/projectiles/guns/magic.dm
@@ -12,11 +12,11 @@
var/charges = 0
var/recharge_rate = 4
var/charge_tick = 0
- var/can_charge = 1
+ var/can_charge = TRUE
var/ammo_type
var/no_den_usage
origin_tech = null
- clumsy_check = 0
+ clumsy_check = FALSE
trigger_guard = TRIGGER_GUARD_ALLOW_ALL // Has no trigger at all, uses magic instead
can_holster = FALSE // Nothing here is a gun, and therefore shouldn't really fit into a holster
diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm
index 408c86a2d3f..3fa985e1b0d 100644
--- a/code/modules/projectiles/guns/magic/wand.dm
+++ b/code/modules/projectiles/guns/magic/wand.dm
@@ -6,7 +6,7 @@
item_state = "wand"
belt_icon = "wand_nothing"
w_class = WEIGHT_CLASS_SMALL
- can_charge = 0
+ can_charge = FALSE
max_charges = 100 //100, 50, 50, 34 (max charge distribution by 25%ths)
var/variable_charges = 1
diff --git a/code/modules/projectiles/guns/mounted.dm b/code/modules/projectiles/guns/mounted.dm
index 162cc541fd2..8c7b9103549 100644
--- a/code/modules/projectiles/guns/mounted.dm
+++ b/code/modules/projectiles/guns/mounted.dm
@@ -5,8 +5,8 @@
icon_state = "taser"
item_state = "armcannonstun4"
force = 5
- selfcharge = 1
- can_flashlight = 0
+ selfcharge = TRUE
+ can_flashlight = FALSE
trigger_guard = TRIGGER_GUARD_ALLOW_ALL // Has no trigger at all, uses neural signals instead
/obj/item/gun/energy/laser/mounted
@@ -16,5 +16,5 @@
icon_state = "laser"
item_state = "armcannonlase"
force = 5
- selfcharge = 1
+ selfcharge = TRUE
trigger_guard = TRIGGER_GUARD_ALLOW_ALL
diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm
index ef0f30e1b25..7c0dc177b84 100644
--- a/code/modules/projectiles/guns/projectile.dm
+++ b/code/modules/projectiles/guns/projectile.dm
@@ -25,9 +25,9 @@
/obj/item/gun/projectile/update_icon()
..()
if(current_skin)
- icon_state = "[current_skin][suppressed ? "-suppressed" : ""][sawn_state ? "-sawn" : ""]"
+ icon_state = "[current_skin][suppressed ? "-suppressed" : ""][sawn_state ? "_sawn" : ""]"
else
- icon_state = "[initial(icon_state)][suppressed ? "-suppressed" : ""][sawn_state ? "-sawn" : ""]"
+ icon_state = "[initial(icon_state)][suppressed ? "-suppressed" : ""][sawn_state ? "_sawn" : ""]"
if(bayonet && can_bayonet)
overlays += knife_overlay
@@ -129,7 +129,7 @@
user.put_in_hands(suppressed)
fire_sound = S.oldsound
w_class = S.initial_w_class
- suppressed = 0
+ suppressed = FALSE
update_icon()
return
..()
diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm
index ff15b033b31..9c763b65ead 100644
--- a/code/modules/projectiles/guns/projectile/automatic.dm
+++ b/code/modules/projectiles/guns/projectile/automatic.dm
@@ -3,7 +3,7 @@
var/alarmed = 0
var/select = 1
can_tactical = TRUE
- can_suppress = 1
+ can_suppress = TRUE
burst_size = 3
fire_delay = 2
actions_types = list(/datum/action/item_action/toggle_firemode)
@@ -80,6 +80,7 @@
name = "\improper Nanotrasen Saber SMG"
desc = "A rejected prototype three-round burst 9mm submachine gun, designated 'SABR'. Surplus of this model are bouncing around armories of Nanotrasen Space Stations. Has a threaded barrel for suppressors."
icon_state = "saber"
+ item_state = "saber"
mag_type = /obj/item/ammo_box/magazine/smgm9mm
origin_tech = "combat=4;materials=2"
fire_sound = 'sound/weapons/gunshots/gunshot_pistol.ogg'
@@ -116,13 +117,13 @@
name = "security auto rifle"
desc = "An outdated personal defense weapon utilized by law enforcement. The WT-550 Automatic Rifle fires 4.6x30mm rounds."
icon_state = "wt550"
- item_state = "arg"
+ item_state = "wt550"
mag_type = /obj/item/ammo_box/magazine/wt550m9
fire_sound = 'sound/weapons/gunshots/gunshot_rifle.ogg'
magin_sound = 'sound/weapons/gun_interactions/batrifle_magin.ogg'
magout_sound = 'sound/weapons/gun_interactions/batrifle_magout.ogg'
fire_delay = 2
- can_suppress = 0
+ can_suppress = FALSE
burst_size = 1
actions_types = list()
can_bayonet = TRUE
@@ -155,7 +156,7 @@
fire_sound = 'sound/weapons/gunshots/gunshot_rifle.ogg'
magin_sound = 'sound/weapons/gun_interactions/batrifle_magin.ogg'
magout_sound = 'sound/weapons/gun_interactions/batrifle_magout.ogg'
- can_suppress = 0
+ can_suppress = FALSE
var/obj/item/gun/projectile/revolver/grenadelauncher/underbarrel
burst_size = 3
fire_delay = 2
@@ -228,7 +229,7 @@
origin_tech = "combat=5;materials=1;syndicate=3"
mag_type = /obj/item/ammo_box/magazine/tommygunm45
fire_sound = 'sound/weapons/gunshots/gunshot_smg.ogg'
- can_suppress = 0
+ can_suppress = FALSE
burst_size = 4
fire_delay = 1
@@ -244,7 +245,7 @@
fire_sound = 'sound/weapons/gunshots/gunshot_mg.ogg'
magin_sound = 'sound/weapons/gun_interactions/batrifle_magin.ogg'
magout_sound = 'sound/weapons/gun_interactions/batrifle_magout.ogg'
- can_suppress = 0
+ can_suppress = FALSE
burst_size = 3
fire_delay = 1
@@ -260,7 +261,7 @@
fire_sound = 'sound/weapons/gunshots/gunshot_shotgun.ogg'
magin_sound = 'sound/weapons/gun_interactions/batrifle_magin.ogg'
magout_sound = 'sound/weapons/gun_interactions/batrifle_magout.ogg'
- can_suppress = 0
+ can_suppress = FALSE
burst_size = 1
fire_delay = 0
actions_types = list()
@@ -310,7 +311,7 @@
fire_sound = 'sound/weapons/gunshots/gunshot_lascarbine.ogg'
magin_sound = 'sound/weapons/gun_interactions/batrifle_magin.ogg'
magout_sound = 'sound/weapons/gun_interactions/batrifle_magout.ogg'
- can_suppress = 0
+ can_suppress = FALSE
burst_size = 2
/obj/item/gun/projectile/automatic/lasercarbine/update_icon()
diff --git a/code/modules/projectiles/guns/projectile/launchers.dm b/code/modules/projectiles/guns/projectile/launchers.dm
index 37ba272a67e..8f04c5c58fd 100644
--- a/code/modules/projectiles/guns/projectile/launchers.dm
+++ b/code/modules/projectiles/guns/projectile/launchers.dm
@@ -4,7 +4,7 @@
/obj/item/gun/projectile/revolver/grenadelauncher//this is only used for underbarrel grenade launchers at the moment, but admins can still spawn it if they feel like being assholes
desc = "A break-operated grenade launcher."
name = "grenade launcher"
- icon_state = "dshotgun-sawn"
+ icon_state = "dbshotgun_sawn"
item_state = "gun"
mag_type = /obj/item/ammo_box/magazine/internal/grenadelauncher
fire_sound = 'sound/weapons/grenadelaunch.ogg'
@@ -58,9 +58,10 @@
icon_state = "speargun"
item_state = "speargun"
w_class = WEIGHT_CLASS_BULKY
+ slot_flags = SLOT_BACK
origin_tech = "combat=4;engineering=4"
force = 10
- can_suppress = 0
+ can_suppress = FALSE
mag_type = /obj/item/ammo_box/magazine/internal/speargun
fire_sound = 'sound/weapons/grenadelaunch.ogg'
burst_size = 1
diff --git a/code/modules/projectiles/guns/projectile/pistol.dm b/code/modules/projectiles/guns/projectile/pistol.dm
index 9bcbc8e9741..5c1f15677bb 100644
--- a/code/modules/projectiles/guns/projectile/pistol.dm
+++ b/code/modules/projectiles/guns/projectile/pistol.dm
@@ -10,14 +10,14 @@
fire_sound = 'sound/weapons/gunshots/gunshot_pistol.ogg'
magin_sound = 'sound/weapons/gun_interactions/pistol_magin.ogg'
magout_sound = 'sound/weapons/gun_interactions/pistol_magout.ogg'
- can_suppress = 1
+ can_suppress = TRUE
burst_size = 1
fire_delay = 0
actions_types = list()
/obj/item/gun/projectile/automatic/pistol/update_icon()
..()
- icon_state = "[initial(icon_state)][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]"
+ icon_state = "[initial(icon_state)][magazine ? "-[magazine.max_ammo]" : ""][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]"
return
//M1911//
@@ -27,7 +27,7 @@
icon_state = "m1911"
w_class = WEIGHT_CLASS_NORMAL
mag_type = /obj/item/ammo_box/magazine/m45
- can_suppress = 0
+ can_suppress = FALSE
//Enforcer//
/obj/item/gun/projectile/automatic/pistol/enforcer
@@ -86,11 +86,7 @@
fire_sound = 'sound/weapons/gunshots/gunshot_pistolH.ogg'
magin_sound = 'sound/weapons/gun_interactions/hpistol_magin.ogg'
magout_sound = 'sound/weapons/gun_interactions/hpistol_magout.ogg'
- can_suppress = 0
-
-/obj/item/gun/projectile/automatic/pistol/deagle/update_icon()
- ..()
- icon_state = "[initial(icon_state)][magazine ? "" : "-e"]"
+ can_suppress = FALSE
/obj/item/gun/projectile/automatic/pistol/deagle/gold
desc = "A gold plated Desert Eagle folded over a million times by superior martian gunsmiths. Uses .50 AE ammo."
@@ -109,8 +105,8 @@
icon_state = "aps"
w_class = WEIGHT_CLASS_NORMAL
origin_tech = "combat=3;materials=2;syndicate=3"
- mag_type = /obj/item/ammo_box/magazine/pistolm9mm
- can_suppress = 0
+ mag_type = /obj/item/ammo_box/magazine/apsm9mm
+ can_suppress = FALSE
burst_size = 3
fire_delay = 2
actions_types = list(/datum/action/item_action/toggle_firemode)
diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm
index 183de503023..cd7f3b9e5f6 100644
--- a/code/modules/projectiles/guns/projectile/revolver.dm
+++ b/code/modules/projectiles/guns/projectile/revolver.dm
@@ -103,8 +103,8 @@
righthand_file = null
can_holster = FALSE // Get your fingers out of there!
trigger_guard = TRIGGER_GUARD_ALLOW_ALL
- clumsy_check = 0 //Stole your uplink! Honk!
- needs_permit = 0 //go away beepsky
+ clumsy_check = FALSE //Stole your uplink! Honk!
+ needs_permit = FALSE //go away beepsky
/obj/item/gun/projectile/revolver/fingergun/fake
desc = "Pew pew pew!"
@@ -150,7 +150,7 @@
desc = "An old model of revolver that originated in Russia. Able to be suppressed. Uses 7.62x38mmR ammo."
icon_state = "nagant"
origin_tech = "combat=3"
- can_suppress = 1
+ can_suppress = TRUE
mag_type = /obj/item/ammo_box/magazine/internal/cylinder/rev762
// A gun to play Russian Roulette!
@@ -159,6 +159,7 @@
/obj/item/gun/projectile/revolver/russian
name = "\improper Russian Revolver"
desc = "A Russian-made revolver for drinking games. Uses .357 ammo, and has a mechanism that spins the chamber before each trigger pull."
+ icon_state = "russian_revolver"
origin_tech = "combat=2;materials=2"
mag_type = /obj/item/ammo_box/magazine/internal/rus357
var/spun = 0
@@ -271,8 +272,8 @@
/obj/item/gun/projectile/revolver/doublebarrel
name = "double-barreled shotgun"
desc = "A true classic."
- icon_state = "dshotgun"
- item_state = "shotgun_db"
+ icon_state = "dbshotgun"
+ item_state = null
lefthand_file = 'icons/mob/inhands/64x64_guns_lefthand.dmi'
righthand_file = 'icons/mob/inhands/64x64_guns_righthand.dmi'
inhand_x_dimension = 64
@@ -290,12 +291,12 @@
/obj/item/gun/projectile/revolver/doublebarrel/New()
..()
- options["Default"] = "dshotgun"
- options["Dark Red Finish"] = "dshotgun-d"
- options["Ash"] = "dshotgun-f"
- options["Faded Grey"] = "dshotgun-g"
- options["Maple"] = "dshotgun-l"
- options["Rosewood"] = "dshotgun-p"
+ options["Default"] = "dbshotgun"
+ options["Dark Red Finish"] = "dbshotgun_d"
+ options["Ash"] = "dbshotgun_f"
+ options["Faded Grey"] = "dbshotgun_g"
+ options["Maple"] = "dbshotgun_l"
+ options["Rosewood"] = "dbshotgun_p"
options["Cancel"] = null
/obj/item/gun/projectile/revolver/doublebarrel/attackby(obj/item/A, mob/user, params)
@@ -305,10 +306,10 @@
var/obj/item/melee/energy/W = A
if(W.active)
sawoff(user)
- item_state = "ishotgun_sawn"
+ item_state = icon_state
if(istype(A, /obj/item/circular_saw) || istype(A, /obj/item/gun/energy/plasmacutter))
sawoff(user)
- item_state = "ishotgun_sawn"
+ item_state = icon_state
else
return ..()
@@ -350,36 +351,33 @@
fire_sound = 'sound/weapons/gunshots/gunshot_shotgun.ogg'
sawn_desc = "I'm just here for the gasoline."
unique_reskin = FALSE
- var/slung = 0
+ var/sling = FALSE
/obj/item/gun/projectile/revolver/doublebarrel/improvised/attackby(obj/item/A, mob/user, params)
+ ..()
if(istype(A, /obj/item/stack/cable_coil) && !sawn_state)
var/obj/item/stack/cable_coil/C = A
- if(C.use(10))
+ if(sling)
+ to_chat(user, "The shotgun already has a sling!")
+ else if(C.use(10))
slot_flags = SLOT_BACK
- icon_state = "ishotgunsling"
- item_state = "ishotgunsling"
to_chat(user, "You tie the lengths of cable to the shotgun, making a sling.")
- slung = 1
+ sling = TRUE
update_icon()
else
- to_chat(user, "You need at least ten lengths of cable if you want to make a sling.")
- return
- else
- return ..()
+ to_chat(user, "You need at least ten lengths of cable if you want to make a sling!")
/obj/item/gun/projectile/revolver/doublebarrel/improvised/update_icon()
..()
- if(slung && (slot_flags & SLOT_BELT) )
- slung = 0
- icon_state = "ishotgun-sawn"
- item_state = "ishotgun_sawn"
+ if(sling)
+ icon_state = "ishotgun_sling"
+ item_state = "ishotgun_sling"
/obj/item/gun/projectile/revolver/doublebarrel/improvised/sawoff(mob/user)
. = ..()
- if(. && slung) //sawing off the gun removes the sling
+ if(. && sling) //sawing off the gun removes the sling
new /obj/item/stack/cable_coil(get_turf(src), 10)
- slung = 0
+ sling = FALSE
update_icon()
//caneshotgun
@@ -397,15 +395,15 @@
sawn_state = SAWN_OFF
w_class = WEIGHT_CLASS_SMALL
force = 10
- can_unsuppress = 0
+ can_unsuppress = FALSE
slot_flags = null
origin_tech = "" // NO GIVAWAYS
mag_type = /obj/item/ammo_box/magazine/internal/shot/improvised/cane
sawn_desc = "I'm sorry, but why did you saw your cane in the first place?"
attack_verb = list("bludgeoned", "whacked", "disciplined", "thrashed")
fire_sound = 'sound/weapons/gunshots/gunshot_silenced.ogg'
- suppressed = 1
- needs_permit = 0 //its just a cane beepsky.....
+ suppressed = TRUE
+ needs_permit = FALSE //its just a cane beepsky.....
/obj/item/gun/projectile/revolver/doublebarrel/improvised/cane/is_crutch()
return 1
diff --git a/code/modules/projectiles/guns/projectile/saw.dm b/code/modules/projectiles/guns/projectile/saw.dm
index f2e3a41b6b1..37d173e09a1 100644
--- a/code/modules/projectiles/guns/projectile/saw.dm
+++ b/code/modules/projectiles/guns/projectile/saw.dm
@@ -11,8 +11,8 @@
fire_sound = 'sound/weapons/gunshots/gunshot_mg.ogg'
magin_sound = 'sound/weapons/gun_interactions/lmg_magin.ogg'
magout_sound = 'sound/weapons/gun_interactions/lmg_magout.ogg'
- var/cover_open = 0
- can_suppress = 0
+ var/cover_open = FALSE
+ can_suppress = FALSE
burst_size = 3
fire_delay = 1
diff --git a/code/modules/projectiles/guns/projectile/shotgun.dm b/code/modules/projectiles/guns/projectile/shotgun.dm
index c32ca8cb26e..8fbfcfd1186 100644
--- a/code/modules/projectiles/guns/projectile/shotgun.dm
+++ b/code/modules/projectiles/guns/projectile/shotgun.dm
@@ -88,7 +88,7 @@
name = "riot shotgun"
desc = "A sturdy shotgun with a longer magazine and a fixed tactical stock designed for non-lethal riot control."
icon_state = "riotshotgun"
- item_state = "shotgun_riot"
+ item_state = "riotshotgun"
mag_type = /obj/item/ammo_box/magazine/internal/shot/riot
sawn_desc = "Come with me if you want to live."
sawn_state = SAWN_INTACT
@@ -136,11 +136,11 @@
/obj/item/gun/projectile/shotgun/riot/proc/post_sawoff()
- name = "assault shotgun"
+ name = "sawn-off riot shotgun"
desc = sawn_desc
w_class = WEIGHT_CLASS_NORMAL
- current_skin = "riotshotgun-short"
- item_state = "shotgun_assault" //phil235 is it different with different skin?
+ current_skin = "riotshotgun_sawn"
+ item_state = "riotshotgun_sawn" //phil235 is it different with different skin?
slot_flags &= ~SLOT_BACK //you can't sling it on your back
slot_flags |= SLOT_BELT //but you can wear it on your belt (poorly concealed under a trenchcoat, ideally)
sawn_state = SAWN_OFF
@@ -217,7 +217,6 @@
righthand_file = 'icons/mob/inhands/guns_righthand.dmi'
inhand_x_dimension = 32
inhand_y_dimension = 32
- slot_flags = 0 //no SLOT_BACK sprite, alas
mag_type = /obj/item/ammo_box/magazine/internal/boltaction
fire_sound = 'sound/weapons/gunshots/gunshot_rifle.ogg'
var/bolt_open = 0
diff --git a/code/modules/projectiles/guns/projectile/sniper.dm b/code/modules/projectiles/guns/projectile/sniper.dm
index 95f1b03574c..26ad0dab6fa 100644
--- a/code/modules/projectiles/guns/projectile/sniper.dm
+++ b/code/modules/projectiles/guns/projectile/sniper.dm
@@ -12,8 +12,8 @@
fire_delay = 40
burst_size = 1
origin_tech = "combat=7"
- can_unsuppress = 1
- can_suppress = 1
+ can_unsuppress = TRUE
+ can_suppress = TRUE
w_class = WEIGHT_CLASS_NORMAL
zoomable = TRUE
zoom_amt = 7 //Long range, enough to see in front of you, but no tiles behind you.
diff --git a/code/modules/projectiles/guns/projectile/toy.dm b/code/modules/projectiles/guns/projectile/toy.dm
index c24ce64fc36..4fe035d9a66 100644
--- a/code/modules/projectiles/guns/projectile/toy.dm
+++ b/code/modules/projectiles/guns/projectile/toy.dm
@@ -3,15 +3,15 @@
desc = "A prototype three-round burst toy submachine gun. Ages 8 and up."
icon = 'icons/obj/guns/toy.dmi'
icon_state = "saber"
- item_state = "gun"
+ item_state = "saber"
mag_type = /obj/item/ammo_box/magazine/toy/smg
fire_sound = 'sound/weapons/gunshots/gunshot_smg.ogg'
force = 0
throwforce = 0
burst_size = 3
- can_suppress = 0
- clumsy_check = 0
- needs_permit = 0
+ can_suppress = FALSE
+ clumsy_check = FALSE
+ needs_permit = FALSE
/obj/item/gun/projectile/automatic/toy/process_chamber(eject_casing = 0, empty_chamber = 1)
..()
@@ -20,10 +20,11 @@
name = "foam force pistol"
desc = "A small, easily concealable toy handgun. Ages 8 and up."
icon_state = "pistol"
+ item_state = "gun"
w_class = WEIGHT_CLASS_SMALL
mag_type = /obj/item/ammo_box/magazine/toy/pistol
fire_sound = 'sound/weapons/gunshots/gunshot.ogg'
- can_suppress = 0
+ can_suppress = FALSE
burst_size = 1
fire_delay = 0
can_holster = TRUE
@@ -31,7 +32,7 @@
/obj/item/gun/projectile/automatic/toy/pistol/update_icon()
..()
- icon_state = "[initial(icon_state)][chambered ? "" : "-e"]"
+ icon_state = "[initial(icon_state)][magazine ? "-[magazine.max_ammo]" : ""][chambered ? "" : "-e"]"
/obj/item/gun/projectile/automatic/toy/pistol/riot
name = "foam force riot pistol"
@@ -49,6 +50,10 @@
mag_type = /obj/item/ammo_box/magazine/toy/enforcer
can_flashlight = TRUE
+/obj/item/gun/projectile/automatic/toy/pistol/enforcer/update_icon()
+ ..()
+ icon_state = "[initial(icon_state)][chambered ? "" : "-e"]"
+
/obj/item/gun/projectile/automatic/toy/pistol/enforcer/update_icon()
..()
overlays.Cut()
@@ -69,8 +74,8 @@
throwforce = 0
origin_tech = null
mag_type = /obj/item/ammo_box/magazine/internal/shot/toy
- clumsy_check = 0
- needs_permit = 0
+ clumsy_check = FALSE
+ needs_permit = FALSE
/obj/item/gun/projectile/shotgun/toy/process_chamber()
..()
@@ -81,7 +86,11 @@
name = "foam force crossbow"
desc = "A weapon favored by many overactive children. Ages 8 and up."
icon_state = "crossbow"
- item_state = "crossbow"
+ item_state = "foamcrossbow"
+ lefthand_file = 'icons/mob/inhands/guns_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/guns_righthand.dmi'
+ inhand_x_dimension = 32
+ inhand_y_dimension = 32
mag_type = /obj/item/ammo_box/magazine/internal/shot/toy/crossbow
fire_sound = 'sound/items/syringeproj.ogg'
slot_flags = SLOT_BELT
@@ -91,8 +100,8 @@
name = "donksoft SMG"
desc = "A bullpup two-round burst toy SMG, designated 'C-20r'. Ages 8 and up."
icon = 'icons/obj/guns/toy.dmi'
- can_suppress = 0
- needs_permit = 0
+ can_suppress = FALSE
+ needs_permit = FALSE
mag_type = /obj/item/ammo_box/magazine/toy/smgm45
/obj/item/gun/projectile/automatic/c20r/toy/riot
@@ -105,8 +114,8 @@
name = "donksoft LMG"
desc = "A heavily modified toy light machine gun, designated 'L6 SAW'. Ages 8 and up."
icon = 'icons/obj/guns/toy.dmi'
- can_suppress = 0
- needs_permit = 0
+ can_suppress = FALSE
+ needs_permit = FALSE
mag_type = /obj/item/ammo_box/magazine/toy/m762
/obj/item/gun/projectile/automatic/l6_saw/toy/riot
@@ -121,6 +130,10 @@
icon = 'icons/obj/guns/toy.dmi'
icon_state = "tommygun"
item_state = "shotgun"
+ lefthand_file = 'icons/mob/inhands/guns_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/guns_righthand.dmi'
+ inhand_x_dimension = 32
+ inhand_y_dimension = 32
mag_type = /obj/item/ammo_box/magazine/internal/shot/toy/tommygun
w_class = WEIGHT_CLASS_SMALL
diff --git a/code/modules/projectiles/guns/syringe_gun.dm b/code/modules/projectiles/guns/syringe_gun.dm
index 19e5bfc5852..c48b58528cc 100644
--- a/code/modules/projectiles/guns/syringe_gun.dm
+++ b/code/modules/projectiles/guns/syringe_gun.dm
@@ -9,7 +9,7 @@
throw_range = 7
force = 4
materials = list(MAT_METAL=2000)
- clumsy_check = 0
+ clumsy_check = FALSE
fire_sound = 'sound/items/syringeproj.ogg'
var/list/syringes = list()
var/max_syringes = 1
@@ -93,8 +93,8 @@
w_class = WEIGHT_CLASS_SMALL
origin_tech = "combat=2;syndicate=2;biotech=3"
force = 2 //Also very weak because it's smaller
- suppressed = 1 //Softer fire sound
- can_unsuppress = 0 //Permanently silenced
+ suppressed = TRUE //Softer fire sound
+ can_unsuppress = FALSE //Permanently silenced
// Not quite a syringe gun, but also not completely unlike one either.
// Uses an internal reservoir instead of separately filled syringes, and can unload them
diff --git a/code/modules/projectiles/guns/throw/crossbow.dm b/code/modules/projectiles/guns/throw/crossbow.dm
index 7613c335141..156c5b60625 100644
--- a/code/modules/projectiles/guns/throw/crossbow.dm
+++ b/code/modules/projectiles/guns/throw/crossbow.dm
@@ -161,7 +161,7 @@
item_state = "bolt"
throwforce = 20
w_class = WEIGHT_CLASS_NORMAL
- sharp = 1
+ sharp = TRUE
/obj/item/arrow/proc/removed() //Helper for metal rods falling apart.
return
diff --git a/code/modules/projectiles/guns/throw/pielauncher.dm b/code/modules/projectiles/guns/throw/pielauncher.dm
index 69dcc166aae..6df067f45d6 100644
--- a/code/modules/projectiles/guns/throw/pielauncher.dm
+++ b/code/modules/projectiles/guns/throw/pielauncher.dm
@@ -7,7 +7,7 @@
throw_range = 3
force = 5
- clumsy_check = 0
+ clumsy_check = FALSE
valid_projectile_type = /obj/item/reagent_containers/food/snacks/pie
max_capacity = 5
projectile_speed = 2
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 2840b3c9412..398db8ba83f 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -2,9 +2,9 @@
name = "projectile"
icon = 'icons/obj/projectiles.dmi'
icon_state = "bullet"
- density = 0
+ density = FALSE
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
- anchored = 1 //There's a reason this is here, Mport. God fucking damn it -Agouri. Find&Fix by Pete. The reason this is here is to stop the curving of emitter shots.
+ anchored = TRUE //There's a reason this is here, Mport. God fucking damn it -Agouri. Find&Fix by Pete. The reason this is here is to stop the curving of emitter shots.
flags = ABSTRACT
pass_flags = PASSTABLE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
@@ -14,7 +14,7 @@
var/mob/firer = null//Who shot it
var/atom/firer_source_atom = null //the gun or object this came from
var/obj/item/ammo_casing/ammo_casing = null
- var/suppressed = 0 //Attack message
+ var/suppressed = FALSE //Attack message
var/yo = null
var/xo = null
var/current = null
diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm
index c4743e80fcb..2f4a2171637 100644
--- a/code/modules/projectiles/projectile/beams.dm
+++ b/code/modules/projectiles/projectile/beams.dm
@@ -161,3 +161,69 @@
var/mob/living/L = target
L.visible_message("[L] explodes!")
L.gib()
+
+/obj/item/projectile/beam/laser/detective
+ name = "energy revolver shot"
+ icon_state = "omnilaser"
+ light_color = LIGHT_COLOR_CYAN
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser
+ damage = 5
+ stamina = 25
+ eyeblur = 2 SECONDS
+
+/obj/item/projectile/beam/laser/detective/overcharged
+ name = "overcharged shot"
+ icon_state = "spark"
+ light_color = LIGHT_COLOR_DARKRED
+ color = LIGHT_COLOR_DARKRED
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/red_laser
+ damage = 45
+ stamina = 15
+ eyeblur = 4 SECONDS
+
+/obj/item/projectile/beam/laser/detective/tracker_warrant_shot
+ name = "tracker shot"
+ icon_state = "yellow_laser"
+ light_color = LIGHT_COLOR_YELLOW
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/yellow_laser
+ stamina = 0
+ reflectability = REFLECTABILITY_PHYSICAL //No mr cult juggernaught, please don't set me to search!
+
+/obj/item/projectile/beam/laser/detective/tracker_warrant_shot/on_hit(atom/target)
+ . = ..()
+ if(!ishuman(target))
+ no_worky(target)
+ return
+ start_tracking(target)
+ set_warrant(target)
+
+/obj/item/projectile/beam/laser/detective/tracker_warrant_shot/proc/start_tracking(atom/target)
+ var/obj/item/gun/energy/detective/D = firer_source_atom
+ if(!D)
+ no_worky(target)
+ return
+ if(D.tracking_target_UID)
+ no_worky(tracking_already = TRUE)
+ return
+ D.start_pointing(target.UID())
+
+/obj/item/projectile/beam/laser/detective/tracker_warrant_shot/proc/set_warrant(atom/target)
+ var/mob/living/carbon/human/target_to_mark = target
+ var/perpname = target_to_mark.get_visible_name(TRUE)
+ if(!perpname || perpname == "Unknown")
+ no_worky(target, warrant_fail = TRUE)
+ return
+ var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security)
+ if(!R || (R.fields["criminal"] in list(SEC_RECORD_STATUS_EXECUTE, SEC_RECORD_STATUS_ARREST)))
+ no_worky(target, warrant_fail = TRUE)
+ return
+ set_criminal_status(firer, R, SEC_RECORD_STATUS_SEARCH, "Target tagged by Detective Revolver", "Detective Revolver")
+
+/obj/item/projectile/beam/laser/detective/tracker_warrant_shot/proc/no_worky(atom/target, tracking_already, warrant_fail)
+ if(tracking_already)
+ to_chat(firer, "Weapon Alert: You are already tracking a target!")
+ return
+ if(warrant_fail)
+ to_chat(firer, "Weapon Alert: unable to generate warrant on [target]!")
+ return
+ to_chat(firer, "Weapon Alert: unable to track [target]!")
diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm
index 2600942c342..d9ed934b1c1 100644
--- a/code/modules/projectiles/projectile/energy.dm
+++ b/code/modules/projectiles/projectile/energy.dm
@@ -147,66 +147,3 @@
armour_penetration = 10 // It can have a little armor pen, as a treat. Bigger than it looks, energy armor is often low.
shield_buster = TRUE
reflectability = REFLECTABILITY_PHYSICAL //I will let eswords block it like a normal projectile, but it's not getting reflected, and eshields will take the hit hard. Carp still can reflect though, screw you.
-
-/obj/item/projectile/energy/detective
- name = "energy revolver shot"
- icon_state = "omnilaser"
- light_color = LIGHT_COLOR_CYAN
- damage = 5
- stamina = 25
- eyeblur = 2 SECONDS
-
-/obj/item/projectile/energy/detective/overcharged
- name = "overcharged shot"
- icon_state = "spark"
- light_color = LIGHT_COLOR_DARKRED
- color = LIGHT_COLOR_DARKRED
- damage = 45
- stamina = 15
- eyeblur = 4 SECONDS
-
-/obj/item/projectile/energy/detective/tracker_warrant_shot
- name = "tracker shot"
- icon_state = "yellow_laser"
- light_color = LIGHT_COLOR_YELLOW
- stamina = 0
- reflectability = REFLECTABILITY_PHYSICAL //No mr cult juggernaught, please don't set me to search!
-
-/obj/item/projectile/energy/detective/tracker_warrant_shot/on_hit(atom/target)
- . = ..()
- if(!ishuman(target))
- no_worky(target)
- return
- start_tracking(target)
- set_warrant(target)
-
-/obj/item/projectile/energy/detective/tracker_warrant_shot/proc/start_tracking(atom/target)
- var/obj/item/gun/energy/detective/D = firer_source_atom
- if(!D)
- no_worky(target)
- return
- if(D.tracking_target_UID)
- no_worky(tracking_already = TRUE)
- return
- D.start_pointing(target.UID())
-
-/obj/item/projectile/energy/detective/tracker_warrant_shot/proc/set_warrant(atom/target)
- var/mob/living/carbon/human/target_to_mark = target
- var/perpname = target_to_mark.get_visible_name(TRUE)
- if(!perpname || perpname == "Unknown")
- no_worky(target, warrant_fail = TRUE)
- return
- var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security)
- if(!R || (R.fields["criminal"] in list(SEC_RECORD_STATUS_EXECUTE, SEC_RECORD_STATUS_ARREST)))
- no_worky(target, warrant_fail = TRUE)
- return
- set_criminal_status(firer, R, SEC_RECORD_STATUS_SEARCH, "Target tagged by Detective Revolver", "Detective Revolver")
-
-/obj/item/projectile/energy/detective/tracker_warrant_shot/proc/no_worky(atom/target, tracking_already, warrant_fail)
- if(tracking_already)
- to_chat(firer, "Weapon Alert: You are already tracking a target!")
- return
- if(warrant_fail)
- to_chat(firer, "Weapon Alert: unable to generate warrant on [target]!")
- return
- to_chat(firer, "Weapon Alert: unable to track [target]!")
diff --git a/code/modules/reagents/chemistry/reagents/alcohol.dm b/code/modules/reagents/chemistry/reagents/alcohol.dm
index 19b1a14087f..bbaa9baf0ed 100644
--- a/code/modules/reagents/chemistry/reagents/alcohol.dm
+++ b/code/modules/reagents/chemistry/reagents/alcohol.dm
@@ -23,7 +23,8 @@
if(istype(O,/obj/item/book))
if(volume >= 5)
var/obj/item/book/affectedbook = O
- affectedbook.dat = null
+ for(var/page in affectedbook.pages)
+ affectedbook.pages[page] = " " //we're blanking the pages not making em null
affectedbook.visible_message("The solution melts away the ink on the book.")
else
O.visible_message("It wasn't enough...")
@@ -1044,7 +1045,7 @@
color = "#2E6671" // rgb: 46, 102, 113
alcohol_perc = 0.2
drink_icon = "erikasurprise"
- name = "Erika Surprise"
+ drink_name = "Erika Surprise"
drink_desc = "The surprise is, it's green!"
taste_description = "disappointment"
diff --git a/code/modules/reagents/chemistry/reagents/paradise_pop.dm b/code/modules/reagents/chemistry/reagents/paradise_pop.dm
index c7b8dd6f5c5..39792ec0083 100644
--- a/code/modules/reagents/chemistry/reagents/paradise_pop.dm
+++ b/code/modules/reagents/chemistry/reagents/paradise_pop.dm
@@ -99,6 +99,7 @@
"SECRET TECHNIQUE: TOOLBOX TO THE FACE!",
"SECRET TECHNIQUE: PLASMA CANISTER FIRE!",
"SECRET TECHNIQUE: TABLE AND DISPOSAL!",
+ // Borers got removed but the below reference stays because its hilarious
"[pick("MY BROTHER", " MY DOG", "MY BEST FRIEND", "THE BORER", "GEORGE MELONS", "BADMINS")] DID IT!",
";s WHATS SPACE LAW?!",
"I BOUGHT THESE GLOVES, NOT STEAL THEM",
diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm
index 23aa7e2d5f5..019d025f997 100755
--- a/code/modules/recycling/sortingmachinery.dm
+++ b/code/modules/recycling/sortingmachinery.dm
@@ -23,7 +23,7 @@
..()
/obj/structure/bigDelivery/attack_hand(mob/user as mob)
- playsound(src.loc, 'sound/items/poster_ripped.ogg', 50, 1)
+ playsound(loc, 'sound/items/poster_ripped.ogg', 50, 1)
if(wrapped)
wrapped.forceMove(get_turf(src))
if(istype(wrapped, /obj/structure/closet))
@@ -230,45 +230,56 @@
desc = "Used to set the destination of properly wrapped packages."
icon = 'icons/obj/device.dmi'
icon_state = "dest_tagger"
- var/currTag = 0
- //The whole system for the sorttype var is determined based on the order of this list,
- //disposals must always be 1, since anything that's untagged will automatically go to disposals, or sorttype = 1 --Superxpdude
w_class = WEIGHT_CLASS_TINY
item_state = "electronic"
flags = CONDUCT
slot_flags = SLOT_BELT
+ ///Value of the tag
+ var/currTag = 1
+ //The whole system for the sorttype var is determined based on the order of this list,
+ //disposals must always be 1, since anything that's untagged will automatically go to disposals, or sorttype = 1 --Superxpdude
-/obj/item/destTagger/proc/openwindow(mob/user as mob)
- var/dat = "
TagMaster 2.2
"
+/obj/item/destTagger/attack_self(mob/user)
+ ui_interact(user)
- dat += "
"
- for(var/i = 1, i <= GLOB.TAGGERLOCATIONS.len, i++)
- dat += "