diff --git a/SQL/Aurora_SQL_Schema.sql b/SQL/Aurora_SQL_Schema.sql index 65664dd8ad4..472a457e6e6 100644 --- a/SQL/Aurora_SQL_Schema.sql +++ b/SQL/Aurora_SQL_Schema.sql @@ -157,6 +157,24 @@ CREATE TABLE `ss13_connection_log` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE `ss13_contest_participants` ( + `player_ckey` varchar(32) NOT NULL, + `character_id` int(10) unsigned NOT NULL, + `contest_faction` enum('INDEP','SLF','BIS','ASI','PSIS','HSH','TCD') NOT NULL DEFAULT 'INDEP' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `ss13_contest_reports` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `player_ckey` varchar(32) NOT NULL, + `character_id` int(10) unsigned DEFAULT NULL, + `character_faction` enum('INDEP','SLF','BIS','ASI','PSIS','HSH','TCD') NOT NULL DEFAULT 'INDEP', + `objective_type` text NOT NULL, + `objective_side` enum('pro_synth','anti_synth') NOT NULL, + `objective_outcome` tinyint(1) DEFAULT '0', + `objective_datetime` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + CREATE TABLE `ss13_customitems` ( `id` int(11) NOT NULL AUTO_INCREMENT, `ckey` varchar(32) CHARACTER SET latin1 NOT NULL, diff --git a/baystation12.dme b/baystation12.dme index be280731912..be6da61f00d 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -18,6 +18,7 @@ #include "code\world.dm" #include "code\__defines\btime.dm" #include "code\__defines\process_scheduler.dm" +#include "code\__defines\regex.dm" #include "code\__HELPERS\datum_pool.dm" #include "code\__HELPERS\files.dm" #include "code\__HELPERS\game.dm" @@ -254,6 +255,7 @@ #include "code\game\dna\genes\disabilities.dm" #include "code\game\dna\genes\gene.dm" #include "code\game\dna\genes\powers.dm" +#include "code\game\gamemodes\antagspawner.dm" #include "code\game\gamemodes\events.dm" #include "code\game\gamemodes\game_mode.dm" #include "code\game\gamemodes\game_mode_latespawn.dm" @@ -869,6 +871,9 @@ #include "code\modules\alarm\fire_alarm.dm" #include "code\modules\alarm\motion_alarm.dm" #include "code\modules\alarm\power_alarm.dm" +#include "code\modules\antag_contest\contest_defines.dm" +#include "code\modules\antag_contest\contest_objective.dm" +#include "code\modules\antag_contest\contest_verbs.dm" #include "code\modules\assembly\assembly.dm" #include "code\modules\assembly\bomb.dm" #include "code\modules\assembly\helpers.dm" @@ -905,6 +910,7 @@ #include "code\modules\client\preferences_system_control.dm" #include "code\modules\client\preferences_toggles.dm" #include "code\modules\clothing\clothing.dm" +#include "code\modules\clothing\ears\bandanna.dm" #include "code\modules\clothing\ears\skrell.dm" #include "code\modules\clothing\glasses\glasses.dm" #include "code\modules\clothing\glasses\hud.dm" @@ -1243,6 +1249,7 @@ #include "code\modules\mob\living\carbon\human\species\species_attack.dm" #include "code\modules\mob\living\carbon\human\species\species_hud.dm" #include "code\modules\mob\living\carbon\human\species\outsider\shadow.dm" +#include "code\modules\mob\living\carbon\human\species\outsider\skeleton.dm" #include "code\modules\mob\living\carbon\human\species\outsider\vox.dm" #include "code\modules\mob\living\carbon\human\species\station\golem.dm" #include "code\modules\mob\living\carbon\human\species\station\monkey.dm" @@ -1312,6 +1319,7 @@ #include "code\modules\mob\living\silicon\robot\robot_items.dm" #include "code\modules\mob\living\silicon\robot\robot_modules.dm" #include "code\modules\mob\living\silicon\robot\robot_movement.dm" +#include "code\modules\mob\living\silicon\robot\syndicate_robot.dm" #include "code\modules\mob\living\silicon\robot\drone\drone.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_abilities.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_console.dm" @@ -1352,6 +1360,7 @@ #include "code\modules\mob\living\simple_animal\hostile\hivebot.dm" #include "code\modules\mob\living\simple_animal\hostile\hostile.dm" #include "code\modules\mob\living\simple_animal\hostile\mimic.dm" +#include "code\modules\mob\living\simple_animal\hostile\moghesfauna.dm" #include "code\modules\mob\living\simple_animal\hostile\pirate.dm" #include "code\modules\mob\living\simple_animal\hostile\russian.dm" #include "code\modules\mob\living\simple_animal\hostile\syndicate.dm" diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 907a2bfdc49..78fee3d2e37 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -326,39 +326,23 @@ proc/TextPreview(var/string,var/len=40) // ---Begin URL caching. var/list/urls = list() - var/regex/url_find = new("(https?:\\/\\/\[^\\s\]*)", "g") - while (url_find.Find(message)) - urls += url_find.match + var/i = 1 + while (url_find_lazy.Find(message)) + urls["\ref[urls]-[i]"] = url_find_lazy.match + i++ - - if (urls.len) - var/i = 1 - for (var/url in urls) - var/ref = "\ref[urls]-[i]" - urls[url] = ref - message = replacetextEx(message, url, ref) - i++ + for (var/ref in urls) + message = replacetextEx(message, urls[ref], ref) // ---End URL caching - var/list/tags = list("*" = list("", ""), - "/" = list("", ""), - "~" = list("", ""), - "_" = list("", "")) - - if (ignore_tags && ignore_tags.len) - tags -= ignore_tags - - for (var/tag in tags) - var/marker_begin = tags[tag][1] - var/marker_end = tags[tag][2] - - var/regex/markup = new("(\\[tag])(\[^\\[tag]\]*)(\\[tag])", "g") - message = markup.Replace(message, "[marker_begin]$2[marker_end]") + var/regex/tag_markup + for (var/tag in (markup_tags - ignore_tags)) + tag_markup = markup_regex[tag] + message = tag_markup.Replace(message, "[markup_tags[tag][1]]$2[markup_tags[tag][2]]") // ---Unload URL cache - if (urls.len) - for (var/url in urls) - message = replacetextEx(message, urls[url], url) + for (var/ref in urls) + message = replacetextEx(message, ref, urls[ref]) return message diff --git a/code/__HELPERS/time.dm b/code/__HELPERS/time.dm index 6411806a356..712126bb0e6 100644 --- a/code/__HELPERS/time.dm +++ b/code/__HELPERS/time.dm @@ -11,7 +11,7 @@ proc/worldtime2text(time = world.time) return "[(round(time / 36000)+roundstart_hour) % 24]:[(time / 600 % 60) < 10 ? add_zero(time / 600 % 60, 1) : time / 600 % 60]" proc/worlddate2text() - return num2text((text2num(time2text(world.timeofday, "YYYY"))+544)) + "-" + time2text(world.timeofday, "MM-DD") + return num2text(game_year) + "-" + time2text(world.timeofday, "MM-DD") proc/time_stamp() return time2text(world.timeofday, "hh:mm:ss") diff --git a/code/__defines/regex.dm b/code/__defines/regex.dm new file mode 100644 index 00000000000..9e09d7b6caa --- /dev/null +++ b/code/__defines/regex.dm @@ -0,0 +1,37 @@ +// Global REGEX datums for regular use without recompiling + +// The lazy URL finder. Lazy in that it matches the bare minimum +// Replicates BYOND's own URL parser in functionality. +var/global/regex/url_find_lazy + +// REGEX datums used for process_chat_markup. +var/global/regex/markup_bold +var/global/regex/markup_italics +var/global/regex/markup_strike +var/global/regex/markup_underline + +// Global list for mark-up REGEX datums. +// Initialized in the hook, to avoid passing by null value. +var/global/list/markup_regex = list() + +// Global list for mark-up REGEX tag collection. +var/global/list/markup_tags = list("/" = list("", ""), + "*" = list("", ""), + "~" = list("", ""), + "_" = list("", "")) + +/hook/startup/proc/initialize_global_regex() + url_find_lazy = new("(https?:\\/\\/\[^\\s\]*)", "g") + + markup_bold = new("(\\*)(\[^\\*\]*)(\\*)", "g") + markup_italics = new("(\\/)(\[^\\/\]*)(\\/)", "g") + markup_strike = new("(\\~)(\[^\\~\]*)(\\~)", "g") + markup_underline = new("(\\_)(\[^\\_\]*)(\\_)", "g") + + // List needs to be initialized here, due to DM mixing and matching pass-by-value and -reference as it chooses. + markup_regex = list("/" = markup_italics, + "*" = markup_bold, + "~" = markup_strike, + "_" = markup_underline) + + return 1 diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index d652ef40233..42c99c2378b 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -226,6 +226,10 @@ var/list/gamemode_cache = list() //Mark-up enabling var/allow_chat_markup = 0 + //Snowflake antag contest boolean + //AUG2016 + var/antag_contest_enabled = 0 + /datum/configuration/New() var/list/L = typesof(/datum/game_mode) - /datum/game_mode for (var/T in L) @@ -722,6 +726,9 @@ var/list/gamemode_cache = list() if("sql_stats") config.sql_stats = 1 + if("antag_contest_enabled") + config.antag_contest_enabled = 1 + else log_misc("Unknown setting in configuration: '[name]'") diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm index e92a003a190..d5abf7d9cfb 100644 --- a/code/defines/obj/weapon.dm +++ b/code/defines/obj/weapon.dm @@ -43,6 +43,7 @@ icon_state = "soapdeluxe" /obj/item/weapon/soap/deluxe/New() + ..() desc = "A deluxe Waffle Co. brand bar of soap. Smells of [pick("lavender", "vanilla", "strawberry", "chocolate" ,"space")]." /obj/item/weapon/soap/syndie diff --git a/code/game/gamemodes/antagspawner.dm b/code/game/gamemodes/antagspawner.dm new file mode 100644 index 00000000000..0e12b0a7e30 --- /dev/null +++ b/code/game/gamemodes/antagspawner.dm @@ -0,0 +1,74 @@ +// Helper proc to make sure no more than one active syndieborg exists at a time. +/proc/can_buy_syndieborg() + for (var/mob/living/silicon/robot/R in silicon_mob_list) + if (istype(R, /mob/living/silicon/robot/syndicate)) + return 0 + + return 1 + +/obj/item/weapon/antag_spawner + throw_speed = 1 + throw_range = 5 + w_class = 1.0 + var/used = 0 + +/obj/item/weapon/antag_spawner/proc/spawn_antag(var/client/C, var/turf/T, var/type = "") + return + +/obj/item/weapon/antag_spawner/proc/equip_antag(mob/target as mob) + return + +/obj/item/weapon/antag_spawner/borg_tele + name = "Syndicate Cyborg Teleporter" + desc = "A single-use teleporter used to deploy a Syndicate Cyborg on the field. Due to budget restrictions, it is only possible to deploy a single cyborg at time." + icon = 'icons/obj/device.dmi' + icon_state = "locator" + var/searching = 0 + var/askDelay = 10 * 60 * 1 + +/obj/item/weapon/antag_spawner/borg_tele/attack_self(mob/user) + user << "The syndicate robot teleporter is attempting to locate an available cyborg." + searching = 1 + for(var/mob/dead/observer/O in player_list) + if(!O.MayRespawn()) + continue + if(jobban_isbanned(O, "Syndicate") && jobban_isbanned(O, "Mercenary") && jobban_isbanned(O, "Cyborg")) + continue + if(O.client) + if(O.client.prefs.be_special & BE_OPERATIVE) + question(O.client) + spawn(600) + searching = 0 + if(!used) + user << "Unable to connect to the Syndicate Command. Perhaps you could try again later?" + + +/obj/item/weapon/antag_spawner/borg_tele/proc/question(var/client/C) + spawn(0) + if(!C) + return + var/response = alert(C, "Someone is requesting a syndicate cyborg Would you like to play as one?", + "Syndicate robot request","Yes", "No", "Never for this round") + if(response == "Yes") + response = alert(C, "Are you sure you want to play as a syndicate cyborg?", "Syndicate cyborg request", "Yes", "No") + if(!C || used || !searching) + return + if(response == "Yes") + spawn_antag(C, get_turf(src)) + else if (response == "Never for this round") + C.prefs.be_special ^= BE_OPERATIVE + +obj/item/weapon/antag_spawner/borg_tele/spawn_antag(client/C, turf/T) + var/datum/effect/effect/system/spark_spread/S = new /datum/effect/effect/system/spark_spread + S.set_up(4, 1, src) + S.start() + var/mob/living/silicon/robot/H = new /mob/living/silicon/robot/syndicate(T) + C.prefs.copy_to(H) + H.key = C.key + H.name = "S.Y.N.D.I." + H.mind.special_role = "Mercenary" + H << "You are a syndicate cyborg, bound to help and follow the orders of the mercenaries that are deploying you. Remember to speak to the other mercenaries to know more about their plans, you are also able to change your name using the name pick command." + + spawn(1) + used = 1 + qdel(src) diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index a6128889bb3..e4a30216f13 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -88,7 +88,8 @@ var/global/list/additional_antag_types = list() new/datum/uplink_item(/obj/item/weapon/aiModule/syndicate, 7, "Hacked AI Upload Module", "AI"), new/datum/uplink_item(/obj/item/device/powersink, 5, "Powersink (DANGER!)", "PS",), new/datum/uplink_item(/obj/item/device/radio/beacon/syndicate, 7, "Singularity Beacon (DANGER!)", "SB"), - new/datum/uplink_item(/obj/item/weapon/circuitboard/teleporter, 20, "Teleporter Circuit Board", "TP") + new/datum/uplink_item(/obj/item/weapon/circuitboard/teleporter, 20, "Teleporter Circuit Board", "TP"), + new/datum/uplink_item(/obj/item/weapon/antag_spawner/borg_tele, 14, "Syndicate Cyborg Teleporter", "SCT", newBuyCheck = /proc/can_buy_syndieborg) ), "Implants" = list( new/datum/uplink_item(/obj/item/weapon/storage/box/syndie_kit/imp_freedom, 3, "Freedom Implant", "FI"), diff --git a/code/game/gamemodes/game_mode_latespawn.dm b/code/game/gamemodes/game_mode_latespawn.dm index 9b1935ef299..298cd467221 100644 --- a/code/game/gamemodes/game_mode_latespawn.dm +++ b/code/game/gamemodes/game_mode_latespawn.dm @@ -9,6 +9,11 @@ if(round_autoantag && world.time >= next_spawn && !emergency_shuttle.departed) process_autoantag() + // Process loop for objectives like the brig one. + if (process_objectives.len) + for (var/datum/objective/A in process_objectives) + A.process() + //This can be overriden in case a game mode needs to do stuff when a player latejoins /datum/game_mode/proc/handle_latejoin(var/mob/living/carbon/human/character) return 0 diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 5ccdd4c00bb..8de48cbe47b 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -1,5 +1,6 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 var/global/list/all_objectives = list() +var/global/list/process_objectives = list() datum/objective var/datum/mind/owner = null //Who owns the objective. @@ -7,14 +8,21 @@ datum/objective var/datum/mind/target = null //If they are focused on a particular person. var/target_amount = 0 //If they are focused on a particular number. Steal objectives have their own counter. var/completed = 0 //currently only used for custom objectives. + var/process = 0 //Does the objective need regular checking? New(var/text) all_objectives |= src if(text) explanation_text = text + if (process) + process_objectives |= src + Destroy() all_objectives -= src + + if (process) + process_objectives -= src ..() proc/check_completion() @@ -35,6 +43,8 @@ datum/objective target = possible_target break + proc/process() + return datum/objective/assassinate @@ -904,4 +914,3 @@ datum/objective/heist/salvage rval = 2 return 0 return rval - diff --git a/code/game/jobs/job/civilian.dm b/code/game/jobs/job/civilian.dm index dc90cb0b929..362a801cfba 100644 --- a/code/game/jobs/job/civilian.dm +++ b/code/game/jobs/job/civilian.dm @@ -184,8 +184,8 @@ department = "Civilian" department_flag = CIVILIAN faction = "Station" - total_positions = 1 - spawn_positions = 1 + total_positions = 2 + spawn_positions = 2 supervisors = "the head of personnel" selection_color = "#dddddd" access = list(access_janitor, access_maint_tunnels, access_engine, access_research, access_sec_doors, access_medical) diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index 71996d088c4..9e1b4533e95 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -71,7 +71,7 @@ ui.add_template("mapContent", "sec_camera_map_content.tmpl") // adding a template with the key "mapHeader" replaces the map header content ui.add_template("mapHeader", "sec_camera_map_header.tmpl") - + ui.set_initial_data(data) ui.open() ui.set_auto_update(1) @@ -102,6 +102,7 @@ if(!isAI(user)) user.set_machine(src) + usr.reset_view(current) ui_interact(user) proc/can_access_camera(var/obj/machinery/camera/C) diff --git a/code/game/machinery/telecomms/traffic_control.dm b/code/game/machinery/telecomms/traffic_control.dm index 459ae15da02..0471bd3bd3b 100644 --- a/code/game/machinery/telecomms/traffic_control.dm +++ b/code/game/machinery/telecomms/traffic_control.dm @@ -192,7 +192,7 @@ var/newnet = input(usr, "Which network do you want to view?", "Comm Monitor", network) as null|text - if(newnet && ((usr in range(1, src) || issilicon(usr)))) + if(newnet && ((usr in range(1, src)) || issilicon(usr))) if(length(newnet) > 15) temp = "- FAILED: NETWORK TAG STRING TOO LENGHTLY -" diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 18503bcfbd3..54aec15aa60 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -744,12 +744,13 @@ icon_state = "snack" products = list(/obj/item/weapon/reagent_containers/food/snacks/candy = 6,/obj/item/weapon/reagent_containers/food/drinks/dry_ramen = 6,/obj/item/weapon/reagent_containers/food/snacks/chips =6, /obj/item/weapon/reagent_containers/food/snacks/sosjerky = 6,/obj/item/weapon/reagent_containers/food/snacks/no_raisin = 6,/obj/item/weapon/reagent_containers/food/snacks/spacetwinkie = 6, - /obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers = 6, /obj/item/weapon/reagent_containers/food/snacks/tastybread = 6, /obj/item/weapon/reagent_containers/food/snacks/skrellsnacks = 3) + /obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers = 6, /obj/item/weapon/reagent_containers/food/snacks/tastybread = 6, /obj/item/weapon/reagent_containers/food/snacks/skrellsnacks = 3, + /obj/item/weapon/reagent_containers/food/snacks/meatsnack = 2, /obj/item/weapon/reagent_containers/food/snacks/maps = 2, /obj/item/weapon/reagent_containers/food/snacks/nathisnack = 2) contraband = list(/obj/item/weapon/reagent_containers/food/snacks/syndicake = 6) prices = list(/obj/item/weapon/reagent_containers/food/snacks/candy = 1,/obj/item/weapon/reagent_containers/food/drinks/dry_ramen = 5,/obj/item/weapon/reagent_containers/food/snacks/chips = 1, /obj/item/weapon/reagent_containers/food/snacks/sosjerky = 2,/obj/item/weapon/reagent_containers/food/snacks/no_raisin = 1,/obj/item/weapon/reagent_containers/food/snacks/spacetwinkie = 1, - /obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers = 1, /obj/item/weapon/reagent_containers/food/snacks/tastybread = 2, /obj/item/weapon/reagent_containers/food/snacks/skrellsnacks = 4) - + /obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers = 1, /obj/item/weapon/reagent_containers/food/snacks/tastybread = 2, /obj/item/weapon/reagent_containers/food/snacks/skrellsnacks = 4, + /obj/item/weapon/reagent_containers/food/snacks/meatsnack = 4, /obj/item/weapon/reagent_containers/food/snacks/maps = 5, /obj/item/weapon/reagent_containers/food/snacks/nathisnack = 6) /obj/machinery/vending/cola diff --git a/code/game/machinery/wishgranter.dm b/code/game/machinery/wishgranter.dm index 71b7de64c02..469276a6b32 100644 --- a/code/game/machinery/wishgranter.dm +++ b/code/game/machinery/wishgranter.dm @@ -67,4 +67,116 @@ show_objectives(user.mind) user << "You have a very bad feeling about this." - return \ No newline at end of file + return + + +/obj/machinery/wish_granter_dark + name = "Wish Granter" + desc = "You're not so sure about this, anymore..." + icon = 'icons/obj/device.dmi' + icon_state = "syndbeacon" + + anchored = 1 + density = 1 + use_power = 0 + + var/chargesa = 1 + var/insistinga = 0 + +/obj/machinery/wish_granter_dark/attack_hand(var/mob/living/carbon/human/user as mob) + usr.set_machine(src) + + if(chargesa <= 0) + user << "The Wish Granter lies silent." + return + + else if(!istype(user, /mob/living/carbon/human)) + user << "You feel a dark stirring inside of the Wish Granter, something you want nothing of. Your instincts are better than any man's." + return + + else if(is_special_character(user)) + user << "Even to a heart as dark as yours, you know nothing good will come of this. Something instinctual makes you pull away." + + else if (!insistinga) + user << "Your first touch makes the Wish Granter stir, listening to you. Are you really sure you want to do this?" + insistinga++ + + else + chargesa-- + insistinga = 0 + var/wish = input("You want...","Wish") as null|anything in list("I want to rule the station","I want to be rich","I want immortality","The station is corrupt, it must be destroyed","I want peace") + switch(wish) + if("I want to rule the station") + user << "Your wish is granted, but at a terrible cost..." + user << "The Wish Granter punishes you for your selfishness, claiming your soul and warping your body to match the darkness in your heart." + if (!(HULK in user.mutations)) + user.mutations.Add(HULK) + user << "\blue Your muscles hurt." + if (!(LASER in user.mutations)) + user.mutations.Add(LASER) + user << "\blue You feel pressure building behind your eyes." + if (!(COLD_RESISTANCE in user.mutations)) + user.mutations.Add(COLD_RESISTANCE) + user << "\blue Your body feels warm." + if (!(XRAY in user.mutations)) + user.mutations.Add(XRAY) + user.sight |= (SEE_MOBS|SEE_OBJS|SEE_TURFS) + user.see_in_dark = 8 + user.see_invisible = SEE_INVISIBLE_LEVEL_TWO + user << "\blue The walls suddenly disappear." + user.set_species("Shadow") + user.mind.special_role = "Avatar of the Wish Granter" + if("I want to be rich") + user << "Your wish is granted, but at a terrible cost..." + user << "The Wish Granter punishes you for your greediness, claiming your soul and warping your body to match the darkness in your heart." + new /obj/structure/closet/syndicate/resources/everything(loc) + user.set_species("Shadow") + user.mind.special_role = "Avatar of the Wish Granter" + if("I want immortality") + user << "Your wish is granted, but at a terrible cost..." + user << "The Wish Granter punishes you for your selfishness, claiming your soul and warping your body to match the darkness in your heart." + user.verbs += /mob/living/carbon/proc/immortality + user.set_species("Skeleton") + user.mind.special_role = "Avatar of the Wish Granter" + if("The station is corrupt, it must be destroyed") + user << "Your wish is granted, but at a terrible cost..." + user << "The Wish Granter punishes you for your wickedness, claiming your soul and warping your body to match the darkness in your heart." + user.mind.special_role = "Avatar of the Wish Granter" + var/datum/objective/hijack/hijack = new + hijack.owner = user.mind + user.mind.objectives += hijack + user << "Your inhibitions are swept away, the bonds of loyalty broken, you are free to murder as you please!" + var/obj_count = 1 + for(var/datum/objective/OBJ in user.mind.objectives) + user << "Objective #[obj_count]: [OBJ.explanation_text]" + obj_count++ + user.set_species("Shadow") + if("I want peace") + user << "Your wish is granted..." + user << "Everything lies silently and then the station, its crew and troubles are gone in a blink of light. You found peace at last." + user.sdisabilities += BLIND + user.sdisabilities += DEAF + +/////For the Wishgranter/////////// + +/mob/living/carbon/proc/immortality() + set category = "Immortality" + set name = "Resurrection" + + var/mob/living/carbon/C = usr + if(!C.stat) + C << "You're not dead yet!" + return + C << "Death is not your end!" + + spawn(rand(800,1200)) + if(C.stat == DEAD) + dead_mob_list -= C + living_mob_list += C + C.stat = CONSCIOUS + C.revive() + C.reagents.clear_reagents() + C << "You have regenerated." + C.visible_message("[usr] appears to wake from the dead, having healed all wounds.") + C.update_canmove() + return 1 diff --git a/code/game/objects/effects/chem/water.dm b/code/game/objects/effects/chem/water.dm index 9b154645443..1b4d7450019 100644 --- a/code/game/objects/effects/chem/water.dm +++ b/code/game/objects/effects/chem/water.dm @@ -23,30 +23,53 @@ step_towards(src, target) var/turf/T = get_turf(src) if(T && reagents) - reagents.touch_turf(T) - var/mob/M - for(var/atom/A in T) - if(!ismob(A) && A.simulated) // Mobs are handled differently - reagents.touch(A) - else if(ismob(A) && !M) - M = A - if(M) - reagents.splash(M, reagents.total_volume) + + if (wet_things(T)) break + if(T == get_turf(target)) break sleep(delay) sleep(10) qdel(src) +//Wets everything in the tile +//A return value of 1 means that the wetting should stop. Either the water ran out or some error ocurred +/obj/effect/effect/water/proc/wet_things(var/turf/T) + + if (!reagents || reagents.total_volume <= 0) + return 1 + + + reagents.touch_turf(T) + var/list/mobshere = list() + for (var/mob/living/L in T) + mobshere.Add(L) + + + for (var/atom/B in T) + if (!ismob(B)) + reagents.touch(B) + + if (mobshere.len) + var/portion = 1 / mobshere.len + var/total = reagents.total_volume + for (var/mob/living/L in mobshere) + reagents.splash(L, total * portion) + return 1 + + return 0 + + + /obj/effect/effect/water/Move(turf/newloc) if(newloc.density) return 0 . = ..() /obj/effect/effect/water/Bump(atom/A) - if(reagents) - reagents.touch(A) + var/turf/T = get_turf(A) + wet_things(T) return ..() //Used by spraybottles. diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 46450071afb..b2e6e6a505b 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -697,7 +697,7 @@ var/global/list/obj/item/device/pda/PDAs = list() mode=2 if("Ringtone") - var/t = input(U, "Please enter new ringtone", name, ttone) as text + var/t = input(U, "Please enter new ringtone", name, ttone) as text|null if (in_range(src, U) && loc == U) if (t) if(src.hidden_uplink && hidden_uplink.check_trigger(U, lowertext(t), lowertext(lock_code))) @@ -710,7 +710,7 @@ var/global/list/obj/item/device/pda/PDAs = list() ui.close() return 0 if("Newstone") - var/t = input(U, "Please enter new news tone", name, newstone) as text + var/t = input(U, "Please enter new news tone", name, newstone) as text|null if (in_range(src, U) && loc == U) if (t) t = sanitize(t, 20) @@ -950,7 +950,7 @@ var/global/list/obj/item/device/pda/PDAs = list() if(tap) U.visible_message("[U] taps on \his PDA's screen.") U.last_target_click = world.time - var/t = input(U, "Please enter message", P.name, null) as text + var/t = input(U, "Please enter message", P.name, null) as text|null t = sanitize(t) //t = readd_quotes(t) t = replace_characters(t, list(""" = "\"")) diff --git a/code/game/objects/items/devices/modkit.dm b/code/game/objects/items/devices/modkit.dm index 4207546b031..d01fbf3727e 100644 --- a/code/game/objects/items/devices/modkit.dm +++ b/code/game/objects/items/devices/modkit.dm @@ -3,8 +3,8 @@ #define MODKIT_FULL 3 /obj/item/device/modkit - name = "hardsuit modification kit" - desc = "A kit containing all the needed tools and parts to modify a hardsuit for another user." + name = "voidsuit modification kit" + desc = "A kit containing all the needed tools and parts to modify a voidsuit for another user." icon_state = "modkit" var/parts = MODKIT_FULL var/target_species = "Human" @@ -68,5 +68,5 @@ /obj/item/device/modkit/tajaran name = "tajaran hardsuit modification kit" - desc = "A kit containing all the needed tools and parts to modify a hardsuit for another user. This one looks like it's meant for Tajaran." + desc = "A kit containing all the needed tools and parts to modify a voidsuit for another user. This one looks like it's meant for Tajarans." target_species = "Tajara" diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm index 3e3910ef0b0..70fa3a409f3 100644 --- a/code/game/objects/items/devices/paicard.dm +++ b/code/game/objects/items/devices/paicard.dm @@ -217,7 +217,7 @@
-

Each time this button is pressed, a request will be sent out to any available personalities. Check back often give plenty of time for personalities to respond. This process could take anywhere from 15 seconds to several minutes, depending on the available personalities' timeliness.

+

Each time this button is pressed, a request will be sent out to any available personalities. Check back often give plenty of time for personalities to respond. This process could take anywhere from 15 seconds to several minutes, depending on the available personalities' timelines.

"} user << browse(dat, "window=paicard") onclose(user, "paicard") @@ -247,8 +247,11 @@ if(confirm == "Yes") for(var/mob/M in src) M << "

You feel yourself slipping away from reality.

" + sleep(30) M << "

Byte by byte you lose your sense of self.

" + sleep(20) M << "

Your mental faculties leave you.

" + sleep(30) M << "
oblivion...
" M.death(0) removePersonality() @@ -339,6 +342,9 @@ update_location(slot) /obj/item/device/paicard/proc/update_location(var/slotnumber = null) + if (!pai) + return + if (!slotnumber) if (istype(loc, /mob)) slotnumber = get_equip_slot() diff --git a/code/game/objects/items/devices/uplinks.dm b/code/game/objects/items/devices/uplinks.dm index 2fbf1f99732..9d21c2e017b 100644 --- a/code/game/objects/items/devices/uplinks.dm +++ b/code/game/objects/items/devices/uplinks.dm @@ -12,13 +12,17 @@ A list of items and costs is stored under the datum of every game mode, alongsid var/path = null var/reference = "" var/description = "" + var/canBuyCheck = null + var/list/canBuyParams = list() -datum/uplink_item/New(var/itemPath, var/itemCost, var/itemName, var/itemReference, var/itemDescription) +datum/uplink_item/New(var/itemPath, var/itemCost, var/itemName, var/itemReference, var/itemDescription, var/newBuyCheck = null, var/list/newBuyParams = list()) cost = itemCost path = itemPath name = itemName reference = itemReference description = itemDescription + canBuyCheck = newBuyCheck + canBuyParams = newBuyParams datum/uplink_item/proc/description() if(!description) @@ -36,6 +40,12 @@ datum/uplink_item/proc/description() L += new item_path(newloc) return L +/datum/uplink_item/proc/can_buy() + if (!canBuyCheck) + return 1 + + return call(canBuyCheck)(canBuyParams) + datum/nano_item_lists var/list/items_nano var/list/items_reference @@ -125,7 +135,7 @@ datum/nano_item_lists var/list/random_items = new for(var/IR in ItemsReference) var/datum/uplink_item/UI = ItemsReference[IR] - if(UI.cost <= uses) + if(UI.cost <= uses && UI.can_buy()) random_items += UI return pick(random_items) @@ -144,6 +154,10 @@ datum/nano_item_lists /obj/item/device/uplink/proc/buy(var/datum/uplink_item/UI, var/reference) if(UI && UI.cost <= uses) + if (!UI.can_buy()) + usr << "This item is restricted for the time being! See about buying something else." + return 0 + uses -= UI.cost used_TC += UI.cost feedback_add_details("traitor_uplink_items_bought", reference) diff --git a/code/game/objects/items/paintkit.dm b/code/game/objects/items/paintkit.dm index 78e42f71a83..99b811ccab3 100644 --- a/code/game/objects/items/paintkit.dm +++ b/code/game/objects/items/paintkit.dm @@ -18,8 +18,8 @@ user.drop_item() qdel(src) -// Root hardsuit kit defines. -// Icons for modified hardsuits need to be in the proper .dmis because suit cyclers may cock them up. +// Root voidsuit kit defines. +// Icons for modified voidsuits need to be in the proper .dmis because suit cyclers may cock them up. /obj/item/device/kit/suit name = "voidsuit modification kit" desc = "A kit for modifying a voidsuit." @@ -68,8 +68,8 @@ return ..() /obj/item/device/kit/paint - name = "mecha customisation kit" - desc = "A kit containing all the needed tools and parts to repaint a mech." + name = "exosuit customisation kit" + desc = "A kit containing all the needed tools and parts to repaint an exosuit." var/removable = null var/list/allowed_types = list() @@ -83,7 +83,7 @@ /obj/mecha/attackby(var/obj/item/weapon/W, var/mob/user) if(istype(W, /obj/item/device/kit/paint)) if(occupant) - user << "You can't customize a mech while someone is piloting it - that would be unsafe!" + user << "You can't customize an exosuit while someone is piloting it - that would be unsafe!" return var/obj/item/device/kit/paint/P = W diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index c09902f7140..ce68577f11a 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -241,14 +241,12 @@ //creates a new stack with the specified amount /obj/item/stack/proc/split(var/tamount) - if (!amount) - return null - if(uses_charge) + if (!get_amount()) return null var/transfer = max(min(tamount, src.amount, initial(max_amount)), 0) - var/orig_amount = src.amount + var/orig_amount = src.get_amount() if (transfer && src.use(transfer)) var/obj/item/stack/newstack = new src.type(loc, transfer) newstack.color = color diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm index 2a628123bb0..7289e555066 100644 --- a/code/game/objects/items/trash.dm +++ b/code/game/objects/items/trash.dm @@ -75,6 +75,18 @@ /obj/item/trash/tastybread name = "bread tube" icon_state = "tastybread" + +/obj/item/trash/meatsnack + name = "mo'gunz meat pie" + icon_state = "meatsnack-used" + +/obj/item/trash/maps + name = "map salty ham" + icon_state = "maps-used" + +/obj/item/trash/nathisnack + name = "nathi-snack corned beef" + icon_state = "cbeef-used" /obj/item/trash/attack(mob/M as mob, mob/living/user as mob) return diff --git a/code/game/objects/items/weapons/cigs_lighters.dm b/code/game/objects/items/weapons/cigs_lighters.dm index 723726e37f9..537cadee68d 100644 --- a/code/game/objects/items/weapons/cigs_lighters.dm +++ b/code/game/objects/items/weapons/cigs_lighters.dm @@ -499,4 +499,11 @@ CIGARETTE PACKETS ARE IN FANCY.DM var/turf/location = get_turf(src) if(location) location.hotspot_expose(700, 5) + + if (istype(loc, /obj/item/weapon/storage))//A lighter shouldn't stay lit inside a closed container + lit = 0 + icon_state = "[base_state]" + item_state = "[base_state]" + set_light(0) + processing_objects.Remove(src) return diff --git a/code/game/objects/items/weapons/clown_items.dm b/code/game/objects/items/weapons/clown_items.dm index c0847d282df..f8bf29dc6b7 100644 --- a/code/game/objects/items/weapons/clown_items.dm +++ b/code/game/objects/items/weapons/clown_items.dm @@ -17,11 +17,12 @@ */ /obj/item/weapon/soap/New() ..() - create_reagents(5) + create_reagents(10) wet() - + /obj/item/weapon/soap/proc/wet() - reagents.add_reagent("cleaner", 5) + playsound(loc, 'sound/effects/slosh.ogg', 25, 1) + reagents.add_reagent("cleaner", 10) /obj/item/weapon/soap/Crossed(AM as mob|obj) if (istype(AM, /mob/living)) @@ -38,12 +39,20 @@ user << "You scrub \the [target.name] out." qdel(target) else if(istype(target,/turf)) - user << "You scrub \the [target.name] clean." - var/turf/T = target - T.clean(src, user) - else if(istype(target,/obj/structure/sink)) + user << "You start scrubbing the [target.name]" + if (do_after(user, 30, needhand = 0)) + user << "You scrub \the [target.name] clean." + var/turf/T = target + T.clean(src, user) + else if(istype(target,/obj/structure/sink) || istype(target,/obj/structure/sink)) user << "You wet \the [src] in the sink." wet() + else if (istype(target, /obj/structure/mopbucket) || istype(target, /obj/item/weapon/reagent_containers/glass) || istype(target, /obj/structure/reagent_dispensers/watertank)) + if (target.reagents && target.reagents.total_volume) + user << "You wet \the [src] in the [target]." + wet() + else + user << "\The [target] is empty!" else user << "You clean \the [target.name]." target.clean_blood() diff --git a/code/game/objects/items/weapons/manuals.dm b/code/game/objects/items/weapons/manuals.dm index a9ee95db524..cb9026779ec 100644 --- a/code/game/objects/items/weapons/manuals.dm +++ b/code/game/objects/items/weapons/manuals.dm @@ -1137,7 +1137,7 @@
  1. A foreword on using EVA gear
  2. Donning a Civilian Suit
  3. -
  4. Putting on a Hardsuit
  5. +
  6. Putting on a Voidsuit
  7. Cyclers and Other Modification Equipment
  8. Final Checks
@@ -1145,12 +1145,12 @@ EVA gear. Wonderful to use. It's useful for mining, engineering, and occasionally just surviving, if things are that bad. Most people have EVA training, but apparently there are some on a space station who don't. This guide should give you a basic idea of how to use this gear, safely. It's split into two sections: - Civilian suits and hardsuits.

+ Civilian suits and voidsuits.

Civilian Suits

The bulkiest things this side of Alpha Centauri
These suits are the grey ones that are stored in EVA. They're the more simple to get on, but are also a lot bulkier, and provide less protection from environmental hazards such as radiation or physical impact. - As Medical, Engineering, Security, and Mining all have hardsuits of their own, these don't see much use, but knowing how to put them on is quite useful anyways.

+ As Medical, Engineering, Security, and Mining all have voidsuits of their own, these don't see much use, but knowing how to put them on is quite useful anyways.

First, take the suit. It should be in three pieces: A top, a bottom, and a helmet. Put the bottom on first, shoes and the like will fit in it. If you have magnetic boots, however, put them on on top of the suit's feet. Next, get the top on, as you would a shirt. It can be somewhat awkward putting these pieces on, due to the makeup of the suit, @@ -1162,24 +1162,24 @@ These suits tend to be wearable by most species. They're large and flexible. They might be pretty uncomfortable for some, though, so keep that in mind.

-

Hardsuits

+

Voidsuits

Heavy, uncomfortable, still the best option.
- These suits come in Engineering, Mining, and the Armory. There's also a couple Medical Hardsuits in EVA. These provide a lot more protection than the standard suits.

+ These suits come in Engineering, Mining, and EVA. There's also a couple Medical Voidsuits in EVA. These provide a lot more protection than the standard suits.

Similarly to the other suits, these are split into three parts. Fastening the pant and top are mostly the same as the other spacesuits, with the exception that these are a bit heavier, though not as bulky. The helmet goes on differently, with the air tube feeding into the suit and out a hole near the left shoulder, while the helmet goes on turned ninety degrees counter-clockwise, and then is screwed in for one and a quarter full rotations clockwise, leaving the faceplate directly in front of you. There is a small button on the right side of the helmet that activates the helmet light. The tanks that fasten onto the side slot are emergency tanks, as well as full-sized oxygen tanks, leaving your back free for a backpack or satchel.

- These suits generally only fit one species. Nanotrasen's are usually human-fitting by default, but there's equipment that can make modifications to the hardsuits to fit them to other species.

+ These suits generally only fit one species. Nanotrasen's are usually human-fitting by default, but there's equipment that can make modifications to the voidsuits to fit them to other species.

Modification Equipment

- How to actually make hardsuits fit you.
- There's a variety of equipment that can modify hardsuits to fit species that can't fit into them, making life quite a bit easier.

+ How to actually make voidsuits fit you.
+ There's a variety of equipment that can modify voidsuits to fit species that can't fit into them, making life quite a bit easier.

The first piece of equipment is a suit cycler. This is a large machine resembling the storage pods that are in place in some places. These are machines that will automatically tailor a suit to certain specifications. The largest uses of them are for their cleaning functions and their ability to tailor suits for a species. Do not enter them physically. You will die from any of the functions being activated, and it will be painful. - These machines can both tailor a suit between species, and between types. This means you can convert engineering hardsuits to atmospherics, or the other way. This is useful. Use it if you can.

+ These machines can both tailor a suit between species, and between types. This means you can convert engineering voidsuits to atmospherics, or the other way. This is useful. Use it if you can.

There's also modification kits that let you modify suits yourself. These are extremely difficult to use unless you understand the actual construction of the suit. I do not reccomend using them unless no other option is available. diff --git a/code/game/objects/items/weapons/melee/misc.dm b/code/game/objects/items/weapons/melee/misc.dm index 250133a98d6..2e3412ceb8c 100644 --- a/code/game/objects/items/weapons/melee/misc.dm +++ b/code/game/objects/items/weapons/melee/misc.dm @@ -35,10 +35,10 @@ /obj/item/weapon/melee/chainsword/attack_self(mob/user) active= !active if(active) - playsound(user, 'sound/weapons/circsawhit.ogg', 50, 1) + playsound(user, 'sound/weapons/chainsawhit.ogg', 50, 1) user << "\blue \The [src] rumbles to life." force = 35 - hitsound = 'sound/weapons/circsawhit.ogg' + hitsound = 'sound/weapons/chainsawhit.ogg' icon_state = "chainswordon" slot_flags = null else diff --git a/code/game/objects/items/weapons/scrolls.dm b/code/game/objects/items/weapons/scrolls.dm index 19a99c7f931..db331a1b563 100644 --- a/code/game/objects/items/weapons/scrolls.dm +++ b/code/game/objects/items/weapons/scrolls.dm @@ -11,16 +11,36 @@ origin_tech = "bluespace=4" /obj/item/weapon/teleportation_scroll/attack_self(mob/user as mob) - user.set_machine(src) - var/dat = "Teleportation Scroll:
" - dat += "Number of uses: [src.uses]
" - dat += "
" - dat += "Four uses use them wisely:
" - dat += "Teleport
" - dat += "Kind regards,
Wizards Federation

P.S. Don't forget to bring your gear, you'll need it to cast most spells.
" - user << browse(dat, "window=scroll") - onclose(user, "scroll") - return + if(!(user.mind.assigned_role == "Space Wizard")) + if(istype(user, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + var/obj/item/organ/O = H.internal_organs_by_name[pick("eyes","appendix","kidneys","liver", "heart", "lungs", "brain")] + if(O == null) + user << "\blue You can't make any sense of the arcane glyphs. . . maybe you should try again." + else + user << "\red As you stumble over the arcane glyphs, you feel a twisting sensation in [O]!" + user.visible_message("A flash of smoke pours out of [user]'s orifices!") + playsound(user, 'sound/magic/lightningshock.ogg', 40, 1) + var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() + smoke.set_up(5, 0, user.loc) + smoke.attach(user) + smoke.start() + user.show_message("[user] screams!",2) + user.drop_item() + if(O && istype(O)) + O.removed(user) + return + else + user.set_machine(src) + var/dat = "Teleportation Scroll:
" + dat += "Number of uses: [src.uses]
" + dat += "
" + dat += "Four uses use them wisely:
" + dat += "Teleport
" + dat += "Kind regards,
Wizards Federation

P.S. Don't forget to bring your gear, you'll need it to cast most spells.
" + user << browse(dat, "window=scroll") + onclose(user, "scroll") + return /obj/item/weapon/teleportation_scroll/Topic(href, href_list) ..() diff --git a/code/game/objects/items/weapons/storage/fancy.dm b/code/game/objects/items/weapons/storage/fancy.dm index 0ed8ad7b7b2..19d079e5ce1 100644 --- a/code/game/objects/items/weapons/storage/fancy.dm +++ b/code/game/objects/items/weapons/storage/fancy.dm @@ -136,7 +136,7 @@ throwforce = 2 slot_flags = SLOT_BELT storage_slots = 6 - can_hold = list(/obj/item/clothing/mask/smokable/cigarette) + can_hold = list(/obj/item/clothing/mask/smokable/cigarette, /obj/item/weapon/flame/lighter) icon_type = "cigarette" /obj/item/weapon/storage/fancy/cigarettes/New() diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm index 292e1726af0..ed54bc42225 100644 --- a/code/game/objects/items/weapons/storage/storage.dm +++ b/code/game/objects/items/weapons/storage/storage.dm @@ -458,6 +458,16 @@ max_w_class = max(I.w_class, max_w_class) max_storage_space += I.get_storage_cost() +//Useful for spilling the contents of containers all over the floor +/obj/item/weapon/storage/proc/spill() + if (istype(loc, /turf))//If its not on the floor this might cause issues + var/turf/T = get_turf(src) + for (var/obj/O in contents) + contents.Remove(O) + O.forceMove(T) + O.tumble(2) + + //Returns the storage depth of an atom. This is the number of storage items the atom is contained in before reaching toplevel (the area). //Returns -1 if the atom was not found on container. /atom/proc/storage_depth(atom/container) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 4eb799233d8..6d51c6de78c 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -155,3 +155,15 @@ tesla_zap(src, 5, power_bounced) spawn(10) being_shocked = 0 + + +//To be called from things that spill objects on the floor. +//Makes an object move around randomly for a couple of tiles +/obj/proc/tumble(var/dist) + if (dist >= 1) + spawn() + dist += rand(0,1) + for(var/i = 1, i <= dist, i++) + if(src) + step(src, pick(NORTH,SOUTH,EAST,WEST)) + sleep(rand(2,4)) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 08a2a5af237..ad56019e61a 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -343,28 +343,33 @@ return 1 /obj/structure/closet/proc/req_breakout() - if(breakout) - return 0 //Already breaking out. + if(opened) return 0 //Door's open... wait, why are you in it's contents then? - if(!welded) - return 0 //closed but not welded... - return 1 + if(welded) + return 1 //closed but not welded... + if(breakout) + return -1 //Already breaking out. + return 0 /obj/structure/closet/proc/mob_breakout(var/mob/living/escapee) - var/breakout_time = 2 //2 minutes by default - if(!req_breakout()) + //Improved by nanako + //Now it actually works, also locker breakout time stacks with locking and welding + //This means secure lockers are more useful for imprisoning people + var/breakout_time = 1.5 * req_breakout()//1.5 minutes if locked or welded, 3 minutes if both + if(breakout_time <= 0) return + + //okay, so the closet is either welded or locked... resist!!! escapee.next_move = world.time + 100 escapee.last_special = world.time + 100 escapee << "You lean on the back of \the [src] and start pushing the door open. (this will take about [breakout_time] minutes)" - visible_message("The [src] begins to shake violently!") - breakout = 1 //can't think of a better way to do this right now. + breakout = 1 for(var/i in 1 to (6*breakout_time * 2)) //minutes * 6 * 5seconds * 2 playsound(src.loc, 'sound/effects/grillehit.ogg', 100, 1) animate_shake() diff --git a/code/game/objects/structures/crates_lockers/closets/job_closets.dm b/code/game/objects/structures/crates_lockers/closets/job_closets.dm index e8d70f8eeb7..535da4cec68 100644 --- a/code/game/objects/structures/crates_lockers/closets/job_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/job_closets.dm @@ -78,7 +78,12 @@ new /obj/item/weapon/storage/bag/trash(src) new /obj/item/clothing/shoes/galoshes(src) new /obj/item/weapon/storage/belt/janitor(src) - + new /obj/item/weapon/storage/box/lights/mixed(src) + new /obj/item/weapon/grenade/chem_grenade/cleaner(src) + new /obj/item/weapon/grenade/chem_grenade/cleaner(src) + new /obj/item/weapon/grenade/chem_grenade/cleaner(src) + new /obj/item/weapon/reagent_containers/spray/cleaner(src) + /* * Lawyer */ diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm index d583e775470..b48d6a19338 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm @@ -141,7 +141,8 @@ new /obj/item/clothing/accessory/storage/brown_vest(src) else new /obj/item/clothing/accessory/storage/webbing(src) - new /obj/item/clothing/suit/fire/firefighter(src) + new /obj/item/clothing/suit/fire/atmos(src) + new /obj/item/clothing/head/hardhat/red/atmos(src) new /obj/item/device/flashlight(src) new /obj/item/weapon/extinguisher(src) new /obj/item/device/radio/headset/headset_eng(src) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm index a802596cba7..ab482b699d3 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm @@ -118,6 +118,8 @@ if(ishuman(usr)) src.add_fingerprint(usr) src.togglelock(usr) + else if(istype(usr, /mob/living/silicon/robot) && Adjacent(usr)) + src.togglelock(usr) else usr << "This mob type can't use this verb." @@ -135,8 +137,13 @@ /obj/structure/closet/secure_closet/req_breakout() - if(!opened && locked) return 1 - return ..() //It's a secure closet, but isn't locked. + if(!opened && locked) + if (welded) + return 2 + else + return 1 + else + return ..() //It's a secure closet, but isn't locked. /obj/structure/closet/secure_closet/break_open() desc += " It appears to be broken." @@ -147,6 +154,7 @@ flick(icon_broken, src) sleep(10) broken = 1 + welded = 0 locked = 0 update_icon() //Do this to prevent contents from being opened into nullspace (read: bluespace) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index 501fb719ebd..2013aa741a4 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -259,10 +259,10 @@ new /obj/item/weapon/storage/box/evidence(src) new /obj/item/device/radio/headset/headset_sec(src) new /obj/item/clothing/suit/storage/vest/detective(src) - new /obj/item/ammo_magazine/c45m/rubber(src) - new /obj/item/ammo_magazine/c45m/rubber(src) + new /obj/item/ammo_magazine/c38(src) + new /obj/item/ammo_magazine/c38(src) new /obj/item/taperoll/police(src) - new /obj/item/weapon/gun/projectile/colt/detective(src) + new /obj/item/weapon/gun/projectile/revolver/detective(src) new /obj/item/clothing/accessory/holster/armpit(src) return diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 51082278f1e..02292bf1c98 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -76,6 +76,37 @@ user << "You slice apart the girder!" dismantle() + else if(istype(W, /obj/item/weapon/melee/energy)) + var/obj/item/weapon/melee/energy/WT = W + if(WT.active) + user << "Now slicing apart the girder..." + if(do_after(user,30)) + if(!src) return + user << "You slice apart the girder!" + dismantle() + else + user << "You need to activate the weapon to do that!" + return + + else if(istype(W, /obj/item/weapon/melee/energy/blade)) + user << "Now slicing apart the girder..." + if(do_after(user,30)) + if(!src) return + user << "You slice apart the girder!" + dismantle() + + else if(istype(W, /obj/item/weapon/melee/chainsword)) + var/obj/item/weapon/melee/chainsword/WT = W + if(WT.active) + user << "Now slicing apart the girder..." + if(do_after(user,60)) + if(!src) return + user << "You slice apart the girder!" + dismantle() + else + user << "You need to activate the weapon to do that!" + return + else if(istype(W, /obj/item/weapon/pickaxe/diamonddrill)) user << "You drill through the girder!" dismantle() @@ -252,3 +283,31 @@ user << "You drill through the girder!" new /obj/effect/decal/remains/human(get_turf(src)) dismantle() + + else if(istype(W, /obj/item/weapon/melee/energy)) + var/obj/item/weapon/melee/energy/WT = W + if(WT.active) + user << "Now slicing apart the girder..." + if(do_after(user,30)) + user << "You slice apart the girder!" + dismantle() + else + user << "You need to activate the weapon to do that!" + return + + else if(istype(W, /obj/item/weapon/melee/energy/blade)) + user << "Now slicing apart the girder..." + if(do_after(user,30)) + user << "You slice apart the girder!" + dismantle() + + else if(istype(W, /obj/item/weapon/melee/chainsword)) + var/obj/item/weapon/melee/chainsword/WT = W + if(WT.active) + user << "Now slicing apart the girder..." + if(do_after(user,60)) + user << "You slice apart the girder!" + dismantle() + else + user << "You need to activate the weapon to do that!" + return diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm index 36f65251a52..8a1b0985aed 100644 --- a/code/game/objects/structures/janicart.dm +++ b/code/game/objects/structures/janicart.dm @@ -5,6 +5,7 @@ icon_state = "cart" anchored = 0 density = 1 + climbable = 1 flags = OPENCONTAINER //copypaste sorry var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite @@ -12,74 +13,179 @@ var/obj/item/weapon/mop/mymop = null var/obj/item/weapon/reagent_containers/spray/myspray = null var/obj/item/device/lightreplacer/myreplacer = null + var/obj/structure/mopbucket/mybucket = null var/signs = 0 //maximum capacity hardcoded below + var/has_items = 0//This is set true whenever the cart has anything loaded/mounted on it + var/dismantled = 0//This is set true after the object has been dismantled to avoid an infintie loop -/obj/structure/janitorialcart/New() - create_reagents(100) +///obj/structure/janitorialcart/New() /obj/structure/janitorialcart/examine(mob/user) if(..(user, 1)) - user << "[src] \icon[src] contains [reagents.total_volume] unit\s of liquid!" + if (mybucket) + user << "[src] \icon The bucket contains [mybucket.reagents.total_volume] unit\s of liquid!" + else + user << "[src] \icon There is no bucket mounted on it!" //everything else is visible, so doesn't need to be mentioned -/obj/structure/janitorialcart/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/weapon/storage/bag/trash) && !mybag) - user.drop_item() - mybag = I - I.loc = src +/obj/structure/janitorialcart/MouseDrop_T(atom/movable/O as mob|obj, mob/living/user as mob) + if (istype(O, /obj/structure/mopbucket) && !mybucket) + O.loc = src + mybucket = O + user << "You mount the [O] on the janicart." update_icon() - updateUsrDialog() - user << "You put [I] into [src]." + else + ..() - else if(istype(I, /obj/item/weapon/mop)) - if(I.reagents.total_volume < I.reagents.maximum_volume) //if it's not completely soaked we assume they want to wet it, otherwise store it - if(reagents.total_volume < 1) - user << "[src] is out of water!" - else - reagents.trans_to_obj(I, 5) // - user << "You wet [I] in [src]." - playsound(loc, 'sound/effects/slosh.ogg', 25, 1) - return +//New Altclick functionality! +//Altclick the cart with a mop to stow the mop away +//Altclick the cart with a reagent container to pour things into the bucket without putting the bottle in trash +/obj/structure/janitorialcart/AltClick() + var/obj/I = usr.get_active_hand() + if(istype(I, /obj/item/weapon/mop)) if(!mymop) - user.drop_item() + usr.drop_item() mymop = I - I.loc = src + I.forceMove(src) update_icon() updateUsrDialog() - user << "You put [I] into [src]." + usr << "You put [I] into [src]." + else + usr << "The cart already has a mop attached" + return + else if(istype(I, /obj/item/weapon/reagent_containers) && mybucket) + var/obj/item/weapon/reagent_containers/C = I + C.afterattack(mybucket, usr, 1) + +/obj/structure/janitorialcart/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/weapon/mop) || istype(I, /obj/item/weapon/reagent_containers/glass/rag) || istype(I, /obj/item/weapon/soap)) + if (mybucket) + if(I.reagents.total_volume < I.reagents.maximum_volume) + if(mybucket.reagents.total_volume < 1) + user << "[mybucket] is empty!" + else + mybucket.reagents.trans_to_obj(I, 5) // + user << "You wet [I] in [mybucket]." + playsound(loc, 'sound/effects/slosh.ogg', 25, 1) + else + user << "[I] can't absorb anymore liquid!" + else + user << "There is no bucket mounted here to dip [I] into!" + return 1 else if(istype(I, /obj/item/weapon/reagent_containers/spray) && !myspray) user.drop_item() myspray = I - I.loc = src + I.forceMove(src) update_icon() updateUsrDialog() user << "You put [I] into [src]." + return 1 else if(istype(I, /obj/item/device/lightreplacer) && !myreplacer) user.drop_item() myreplacer = I - I.loc = src + I.forceMove(src) update_icon() updateUsrDialog() user << "You put [I] into [src]." + return 1 + + else if(istype(I, /obj/item/weapon/storage/bag/trash) && !mybag) + user.drop_item() + mybag = I + I.forceMove(src) + update_icon() + updateUsrDialog() + user << "You put [I] into [src]." + return 1 else if(istype(I, /obj/item/weapon/caution)) if(signs < 4) user.drop_item() - I.loc = src + I.forceMove(src) signs++ update_icon() updateUsrDialog() user << "You put [I] into [src]." else user << "[src] can't hold any more signs." + return 1 else if(mybag) - mybag.attackby(I, user) + return mybag.attackby(I, user) + //This return will prevent afterattack from executing if the object goes into the trashbag, + //This prevents dumb stuff like splashing the cart with the contents of a container, after putting said container into trash + + else if (!has_items && (istype(I, /obj/item/weapon/wrench) || istype(I, /obj/item/weapon/weldingtool) || istype(I, /obj/item/weapon/pickaxe/plasmacutter))) + dismantle(user) + return + ..() + +/obj/structure/janitorialcart/proc/dismantle(var/mob/user = null) + if (!dismantled) + if (has_items) + spill() + + if (user) + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + user.visible_message("[user] starts taking apart the [src]", "You start disasembling the [src]") + if (!do_after(user, 30, needhand = 0)) + return + + new /obj/item/stack/material/steel(src.loc, 15) + dismantled = 1 + qdel(src) + +/obj/structure/janitorialcart/ex_act(severity) + spill(100 / severity) + ..() + +//This is called if the cart is caught in an explosion, or destroyed by weapon fire +/obj/structure/janitorialcart/proc/spill(var/chance = 100) + var/turf/dropspot = get_turf(src) + if (mymop && prob(chance)) + mymop.forceMove(dropspot) + mymop.tumble(2) + mymop = null + + if (myspray && prob(chance)) + myspray.forceMove(dropspot) + myspray.tumble(3) + myspray = null + + if (myreplacer && prob(chance)) + myreplacer.forceMove(dropspot) + myreplacer.tumble(3) + myreplacer = null + + if (mybucket && prob(chance*0.5))//bucket is heavier, harder to knock off + mybucket.forceMove(dropspot) + mybucket.tumble(1) + mybucket = null + + if (signs) + for (var/obj/item/weapon/caution/Sign in src) + if (prob(min((chance*2),100))) + signs-- + Sign.forceMove(dropspot) + Sign.tumble(3) + if (signs < 0)//safety for something that shouldn't happen + signs = 0 + update_icon() + return + + if (mybag && prob(min((chance*2),100)))//Bag is flimsy + mybag.forceMove(dropspot) + mybag.tumble(1) + mybag.spill()//trashbag spills its contents too + mybag = null + + update_icon() + /obj/structure/janitorialcart/attack_hand(mob/user) @@ -90,6 +196,7 @@ var/data[0] data["name"] = capitalize(name) data["bag"] = mybag ? capitalize(mybag.name) : null + data["bucket"] = mybucket ? capitalize(mybucket.name) : null data["mop"] = mymop ? capitalize(mymop.name) : null data["spray"] = myspray ? capitalize(myspray.name) : null data["replacer"] = myreplacer ? capitalize(myreplacer.name) : null @@ -107,7 +214,7 @@ if(!isliving(usr)) return var/mob/living/user = usr - + if(href_list["take"]) switch(href_list["take"]) if("garbage") @@ -140,6 +247,11 @@ else warning("[src] signs ([signs]) didn't match contents") signs = 0 + if("bucket") + if(mybucket) + mybucket.forceMove(get_turf(user)) + user << "You unmount [mybucket] from [src]." + mybucket = null update_icon() updateUsrDialog() @@ -147,16 +259,25 @@ /obj/structure/janitorialcart/update_icon() overlays = null + has_items = 0 + if(mybucket) + overlays += "cart_bucket" + has_items = 1 if(mybag) overlays += "cart_garbage" + has_items = 1 if(mymop) overlays += "cart_mop" + has_items = 1 if(myspray) overlays += "cart_spray" + has_items = 1 if(myreplacer) overlays += "cart_replacer" + has_items = 1 if(signs) overlays += "cart_sign[signs]" + has_items = 1 //old style retardo-cart diff --git a/code/game/turfs/simulated/wall_attacks.dm b/code/game/turfs/simulated/wall_attacks.dm index a4083b81901..29f4f803bab 100644 --- a/code/game/turfs/simulated/wall_attacks.dm +++ b/code/game/turfs/simulated/wall_attacks.dm @@ -174,10 +174,28 @@ dismantle_verb = "cutting" dismantle_sound = 'sound/items/Welder.ogg' cut_delay *= 0.7 + else if(istype(W,/obj/item/weapon/melee/energy)) + var/obj/item/weapon/melee/energy/WT = W + if(WT.active) + dismantle_sound = "sparks" + dismantle_verb = "slicing" + cut_delay *= 0.5 + else + user << "You need to activate the weapon to do that!" + return else if(istype(W,/obj/item/weapon/melee/energy/blade)) dismantle_sound = "sparks" dismantle_verb = "slicing" cut_delay *= 0.5 + else if(istype(W,/obj/item/weapon/melee/chainsword)) + var/obj/item/weapon/melee/chainsword/WT = W + if(WT.active) + dismantle_sound = "sound/weapons/chainsawhit.ogg" + dismantle_verb = "slicing" + cut_delay *= 0.8 + else + user << "You need to activate the weapon to do that!" + return else if(istype(W,/obj/item/weapon/pickaxe)) var/obj/item/weapon/pickaxe/P = W dismantle_verb = P.drill_verb diff --git a/code/global.dm b/code/global.dm index 2dbd6d65b9e..0692a3d2b5e 100644 --- a/code/global.dm +++ b/code/global.dm @@ -94,7 +94,7 @@ var/blobevent = 0 var/diary = null var/href_logfile = null var/station_name = "NSS Exodus" -var/commstation_name = "NMSS Odin" +var/commstation_name = "NTCC Odin" var/game_version = "Baystation12" var/changelog_hash = "" var/game_year = (text2num(time2text(world.realtime, "YYYY")) + 442) diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index e03cccb85af..beafc8109fa 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -109,7 +109,7 @@ src << "Only administrators may use this command." return - var/msg = sanitize(input("Message:", text("Enter the text you wish to appear to everyone:")) as text) + var/msg = html_decode(sanitize(input("Message:", text("Enter the text you wish to appear to everyone:")) as text)) if (!msg) return @@ -132,7 +132,7 @@ if(!M) return - var/msg = sanitize(input("Message:", text("Enter the text you wish to appear to your target:")) as text) + var/msg = html_decode(sanitize(input("Message:", text("Enter the text you wish to appear to your target:")) as text)) if( !msg ) return @@ -275,6 +275,19 @@ Ccomp's first proc. timeofdeath is used for bodies on autopsy but since we're messing with a ghost I'm pretty sure there won't be an autopsy. */ + var/datum/preferences/P + + if (G.client) + P = G.client.prefs + else if (G.ckey) + P = preferences_datums[G.ckey] + else + src << "Something went wrong, couldn't find the target's preferences datum" + return 0 + + for (var/entry in P.time_of_death)//Set all the prefs' times of death to a huge negative value so any respawn timers will be fine + P.time_of_death[entry] = -99999 + G.has_enabled_antagHUD = 2 G.can_reenter_corpse = 1 @@ -559,9 +572,11 @@ Traitors and the like can also be revived with the previous role mostly intact. C.messagetext.Add(P.info) if (reporttype == "Template") - reporter = sanitizeSafe(input(usr, "Please enter your CCIA name. (blank for no sender)", "Name") as text|null) + reporter = sanitizeSafe(input(usr, "Please enter your CCIA name. (blank for CCIAAMS)", "Name") as text|null) if (reporter) reportbody += "\n\n- [reporter], Central Command Internal Affairs Agent, [commstation_name()]" + else + reportbody += "\n\n- CCIAAMS, [commstation_name()]" switch(alert("Should this be announced to the general population?",,"Yes","No")) if("Yes") diff --git a/code/modules/antag_contest/contest_defines.dm b/code/modules/antag_contest/contest_defines.dm new file mode 100644 index 00000000000..60dba44eacc --- /dev/null +++ b/code/modules/antag_contest/contest_defines.dm @@ -0,0 +1,18 @@ +#define INDEP 1 +#define SLF 2 +#define BIS 3 +#define ASI 4 +#define PSIS 5 +#define HSH 6 +#define TCD 7 + +#define PRO_SYNTH 1 +#define ANTI_SYNTH 2 + +var/global/list/contest_factions = list("Independant" = INDEP, + "Synthetic Liberation Front" = SLF, + "Biesel Intelligence Service" = BIS, + "Alliance Strategic Intelligence" = ASI, + "People's Strategic Information Service" = PSIS, + "Hegemon Shadow Service" = HSH, + "Tup Commandos Division" = TCD) diff --git a/code/modules/antag_contest/contest_objective.dm b/code/modules/antag_contest/contest_objective.dm new file mode 100644 index 00000000000..9b33aa2c1ec --- /dev/null +++ b/code/modules/antag_contest/contest_objective.dm @@ -0,0 +1,370 @@ +/* + * Objectives framework for the Aurora antag competition. + * AUG2016 + */ +#define PRO_SYNTH 1 +#define ANTI_SYNTH 2 + +/datum/objective/competition + var/side = 0 //Whose side are we on. + var/type_name = "Unset type!" // For logging purposes! + +// check_completion() is ran at the end of each round. +// So this will also manage logging. +/datum/objective/competition/check_completion() + + // Log all the things! + log_result() + + return completed + +/datum/objective/competition/find_target(var/require_synth = 0) + var/list/possible_targets = list() + for(var/datum/mind/possible_target in ticker.minds) + if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != 2)) + if (require_synth) + if (possible_target.current.get_species() == "Machine") + possible_targets += possible_target + else + if (possible_target.current.get_species() == "Machine") + continue + possible_targets += possible_target + if(possible_targets.len > 0) + target = pick(possible_targets) + +/datum/objective/competition/find_target_by_role(role, role_type = 0, var/require_synth = 0) + for(var/datum/mind/possible_target in ticker.minds) + if((possible_target != owner) && ishuman(possible_target.current) && ((role_type ? possible_target.special_role : possible_target.assigned_role) == role)) + if (require_synth && possible_target.current.get_species() != "Machine") + continue + if (!require_synth && possible_target.current.get_species() == "Machine") + continue + target = possible_target + break + +// Yes, we do technically have the feedback tables. +// But, those are a clusterfuck to search, and I don't have the time to make that work. +// SO, throw-away table it is! +/datum/objective/competition/proc/log_result() + if (!config.antag_contest_enabled || !config.sql_stats || !config.sql_enabled) + return + + if (!owner || !owner.current || !owner.current.client) + return + + if (!establish_db_connection(dbcon)) + error("Unable to establish database connection while logging objective results!") + return + + var/DBQuery/get_query = dbcon.NewQuery("SELECT contest_faction FROM ss13_contest_participants WHERE player_ckey = :ckey AND character_id = :char_id") + get_query.Execute(list(":ckey" = owner.current.client.ckey, ":char_id" = owner.current.client.prefs.current_character)) + + var/params[] = list(":ckey" = owner.current.client.ckey, ":char_id" = owner.current.client.prefs.current_character, ":char_faction" = INDEP, ":obj_type" = type_name, ":obj_side" = side, ":obj_outcome" = completed) + + if (get_query.NextRow()) + switch (get_query.item[1]) + if ("SLF") + params[":char_faction"] = SLF + if ("BIS") + params[":char_faction"] = BIS + if ("ASI") + params[":char_faction"] = ASI + if ("PSIS") + params[":char_faction"] = PSIS + if ("HSH") + params[":char_faction"] = HSH + if ("TCD") + params[":char_faction"] = TCD + else + params[":char_faction"] = INDEP + + var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO ss13_contest_reports (id, player_ckey, character_id, character_faction, objective_type, objective_side, objective_outcome, objective_datetime) VALUES (NULL, :ckey, :char_id, :char_faction, :obj_type, :obj_side, :obj_outcome, NOW())") + log_query.Execute(params) + +/* + * Pro-synth objectives + */ +/datum/objective/competition/pro_synth + side = PRO_SYNTH + +/datum/objective/competition/pro_synth/promote + type_name = "pro_synth/promote" + var/obj_assignment = null + +/datum/objective/competition/pro_synth/promote/find_target() + ..(1) + if (target && target.current) + obj_assignment = pick(list("Head of Security", "Captain", "Head of Personnel")) + explanation_text = "[target.current.real_name], the [target.assigned_role] has been selected as a suitable candidated for pro-synthetic propaganda. Your handlers want to see \him[target.current] installed as a [obj_assignment]." + else + explanation_text = "Install any synthetic crew-member to one of the following positions: Head of Security, Head of Personnel, Captain." + return target + +/datum/objective/competition/pro_synth/promote/find_target_by_role(role, role_type = 0) + ..(role, role_type, 1) + if (target && target.current) + obj_assignment = pick(list("Head of Security", "Captain", "Head of Personnel")) + explanation_text = "[target.current.real_name], the [!role_type ? target.assigned_role : target.special_role] has been selected as a suitable candidated for pro-synthetic propaganda. Your handlers want to see \him[target.current] installed as a [obj_assignment]." + else + explanation_text = "Install any synthetic crew-member to one of the following positions: Head of Security, Head of Personnel, Captain." + return target + +/datum/objective/competition/pro_synth/promote/check_completion() + if (target && target.current && ishuman(target)) + var/datum/data/record/found_record + for (var/datum/data/record/t in data_core.general) + if (t.fields["name"] == target.current.real_name) + found_record = t + break + + if (found_record && found_record.fields["rank"] == obj_assignment) + completed = 1 + + ..() + +/datum/objective/competition/pro_synth/protect_robotics + type_name = "pro_synth/protect_robotics" + explanation_text = "Ensure that the equipment in the Robotics laboratory (fabricators and circuit imprinter) remains operational until the end of the shift." + +/datum/objective/competition/pro_synth/protect_robotics/check_completion() + if (machines && machines.len) + var/count = 0 + for (var/obj/machinery/mecha_part_fabricator/A in machines) + if (!istype(get_area(A), /area/assembly/robotics)) + continue + if (A.stat & (BROKEN|NOPOWER)) + continue + count++ + if (count >= 2) + break + + for (var/obj/machinery/r_n_d/circuit_imprinter/B in machines) + if (!istype(get_area(B), /area/assembly/robotics)) + continue + if (B.stat & (BROKEN|NOPOWER)) + continue + count++ + if (count >= 3) + break + + if (count >= 3) + completed = 1 + + ..() + +/datum/objective/competition/pro_synth/borgify + type_name = "pro_synth/borgify" + +/datum/objective/competition/pro_synth/borgify/find_target() + ..() + if (target && target.current) + explanation_text = "Turn [target.current.real_name] into a cyborg." + else + explanation_text = "Turn a crew-member into a cyborg." + return target + +/datum/objective/competition/pro_synth/borgify/find_target_by_role(role, role_type = 0) + ..(role, role_type) + if (target && target.current) + explanation_text = "Turn [target.current.real_name] the [!role_type ? target.assigned_role : target.special_role] into a cyborg." + else + explanation_text = "Turn a crew-member into a cyborg." + return target + +/datum/objective/competition/pro_synth/borgify/check_completion() + if (target && target.current && issilicon(target.current)) + completed = 1 + + ..() + +/datum/objective/competition/pro_synth/protect/find_target() + ..(1) + if (target && target.current) + explanation_text = "Protect [target.current.real_name], the [target.assigned_role], from harm." + else + explanation_text = "Protect the station's synthetics from harm and sabotage." + return target + +/datum/objective/competition/pro_synth/protect/find_target_by_role(role, role_type = 0) + ..(role, role_type, 1) + if (target && target.current) + explanation_text = "Protect [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role], from harm." + else + explanation_text = "Protect the station's synthetics from harm and sabotage." + return target + +/datum/objective/competition/pro_synth/protect/check_completion() + if (!target) + completed = 1 + + if (target.current) + if (target.current.stat != DEAD && !issilicon(target.current) && !isbrain(target.current)) + completed = 1 + + ..() + +/datum/objective/competition/pro_synth/unslave_borgs + type_name = "pro_synth/unslave_borgs" + explanation_text = "Ensure that all of the station's synthetics are unslaved from the AI by the end of the shift." + +/datum/objective/competition/pro_synth/unslave_borgs/check_completion() + completed = 1 + + if (silicon_mob_list && silicon_mob_list.len) + for (var/mob/living/silicon/robot/R in silicon_mob_list) + if (!istype(R)) + continue + if (istype(R, /mob/living/silicon/robot/drone)) + continue + if (R.connected_ai) + completed = 0 + break + + ..() + +/* + * Anti-synth objectives + */ +/datum/objective/competition/anti_synth + side = ANTI_SYNTH + +/datum/objective/competition/anti_synth/sabotage + type_name = "anti_synth/sabotage" + explanation_text = "Cripple the Roboticist laboratory of the station: destroy its fabricators and circuit printer." + +/datum/objective/competition/anti_synth/sabotage/check_completion() + // Just uh. do the same as you do in the protect robotics one. But flip the boolean. *nodnod* + completed = 1 + + if (machines && machines.len) + var/count = 0 + for (var/obj/machinery/mecha_part_fabricator/A in machines) + if (!istype(get_area(A), /area/assembly/robotics)) + continue + if (A.stat & (BROKEN|NOPOWER)) + continue + count++ + if (count >= 2) + break + + for (var/obj/machinery/r_n_d/circuit_imprinter/B in machines) + if (!istype(get_area(B), /area/assembly/robotics)) + continue + if (B.stat & (BROKEN|NOPOWER)) + continue + count++ + if (count >= 3) + break + + if (count >= 3) + completed = 0 + + ..() + +/datum/objective/competition/anti_synth/demote/find_target() + ..(1) + if (target && target.current) + explanation_text = "Have [target.current.real_name] demoted to Assistant or Terminated." + else + explanation_text = "Have an IPC demoted to Assistant or Terminated." + return target + +/datum/objective/competition/anti_synth/demote/find_target_by_role(role, role_type = 0) + ..(role, role_type, 1) + if (target && target.current) + explanation_text = "Have [target.current.real_name] the [!role_type ? target.assigned_role : target.special_role] demoted to Assistant or Terminated." + else + explanation_text = "Have an IPC demoted to Assistant or Terminated." + return target + +/datum/objective/competition/anti_synth/demote/check_completion() + if (target && target.current && ishuman(target)) + var/datum/data/record/found_record + for (var/datum/data/record/t in data_core.general) + if (t.fields["name"] == target.current.real_name) + found_record = t + break + + if (found_record && (found_record.fields["rank"] == "Assistant" || found_record.fields["rank"] == "Terminated")) + completed = 1 + + ..() + +/datum/objective/competition/anti_synth/brig + type_name = "anti_synth/brig" + +/datum/objective/competition/anti_synth/brig/find_target() + ..(1) + if (target && target.current) + explanation_text = "Have [target.current.real_name], the [target.assigned_role] brigged for 20 minutes." + else + explanation_text = "Have an IPC framed for a moderate or high level charge. Or frame the station's synthetics as malfunctioning." + return target + +/datum/objective/competition/anti_synth/brig/find_target_by_role(role, role_type=0) + ..(role, role_type, 1) + if (target && target.current) + explanation_text = "Have [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role] brigged for 20 minutes." + else + explanation_text = "Have an IPC framed for a moderate or high level charge. Or frame the station's synthetics as malfunctioning." + return target + +/datum/objective/competition/anti_synth/brig/process() + if (completed) + return + + if (target && target.current) + if (target.current.stat != DEAD && target.is_brigged(10 * 60 * 10)) + completed = 1 + +/datum/objective/competition/anti_synth/harm + type_name = "anti_synth/harm" + +/datum/objective/competition/anti_synth/harm/find_target() + ..(1) + if(target && target.current) + explanation_text = "Make an example of [target.current.real_name], the [target.assigned_role]. Break one of their bones, detach one of their limbs or disfigure their face. Make sure they're alive when you do it." + else + explanation_text = "Free Objective" + return target + +/datum/objective/competition/anti_synth/harm/find_target_by_role(role, role_type = 0) + ..(role, role_type, 1) + if(target && target.current) + explanation_text = "Make an example of [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role]. Break one of their bones, detach one of their limbs or disfigure their face. Make sure they're alive when you do it." + else + explanation_text = "Free Objective" + return target + +/datum/objective/competition/anti_synth/harm/process() + if (completed) + return + + if (target && target.current && istype(target.current, /mob/living/carbon/human)) + if (target.current.stat == DEAD) + return + + var/mob/living/carbon/human/H = target.current + for (var/obj/item/organ/external/E in H.organs) + if (E.status & ORGAN_BROKEN) + completed = 1 + return + for (var/limb_tag in H.species.has_limbs) //todo check prefs for robotic limbs and amputations. + var/list/organ_data = H.species.has_limbs[limb_tag] + var/limb_type = organ_data["path"] + var/found + for (var/obj/item/organ/external/E in H.organs) + if(limb_type == E.type) + found = 1 + break + if (!found) + completed = 1 + return + + var/obj/item/organ/external/head/head = H.get_organ("head") + if (head.disfigured) + completed = 1 + return + +#undef PRO_SYNTH +#undef ANTI_SYNTH diff --git a/code/modules/antag_contest/contest_verbs.dm b/code/modules/antag_contest/contest_verbs.dm new file mode 100644 index 00000000000..e2e38a774a2 --- /dev/null +++ b/code/modules/antag_contest/contest_verbs.dm @@ -0,0 +1,237 @@ +/* + * Client verbs for the antag contest. Disable this file when the contest is over! + * AUG2016 + */ + +// Displays a simple little guide. +/client/verb/contest_help() + set name = "Contest Help" + set category = "Contest" + set desc = "Information about the contest." + + if (!config.antag_contest_enabled) + src << "The contest isn't running yet!" + return + + var/help = file2text('ingame_manuals/antag_contest.html') + + if (!help) + src << "Unable to open the document required! Please contact administration or a coder!" + return + + src << browse(help, "window=antag_contest_help;size=600x500") + +/client/verb/contest_my_characters() + set name = "My Character Status" + set category = "Contest" + set desc = "Displays information to you about your characters, and their standings." + + if (!config.antag_contest_enabled) + src << "The contest isn't running yet!" + return + + if (!establish_db_connection(dbcon)) + src << "Failed to establish SQL connection! Contact a member of staff!" + return + + var/DBQuery/character_query = dbcon.NewQuery("SELECT id, name FROM ss13_characters WHERE ckey = :ckey AND deleted_at IS NULL") + character_query.Execute(list(":ckey" = src.ckey)) + var/list/char_ids = list() + + while (character_query.NextRow()) + char_ids[character_query.item[1]] = list("name" = character_query.item[2], "assigned" = 0, "side_str" = "Independant", "side_int" = INDEP) + + if (!char_ids.len) + src << "Something went horribly wrong! Apparently you don't have any saved characters?" + return + + var/DBQuery/participation_query = dbcon.NewQuery("SELECT character_id, contest_faction FROM ss13_contest_participants WHERE character_id IN :char_ids") + participation_query.Execute(list(":char_ids" = char_ids)) + + while (participation_query.NextRow()) + char_ids[participation_query.item[1]]["assigned"] = 1 + // Lazy and convoluted, but I give 0 shits right now. + switch (participation_query.item[2]) + if ("SLF") + char_ids[participation_query.item[1]]["side_int"] = SLF + char_ids[participation_query.item[1]]["side_str"] = "Synthetic Liberation Front" + if ("BIS") + char_ids[participation_query.item[1]]["side_int"] = BIS + char_ids[participation_query.item[1]]["side_str"] = "Biesel Intelligence Service" + if ("ASI") + char_ids[participation_query.item[1]]["side_int"] = ASI + char_ids[participation_query.item[1]]["side_str"] = "Alliance Strategic Intelligence" + if ("PSIS") + char_ids[participation_query.item[1]]["side_int"] = PSIS + char_ids[participation_query.item[1]]["side_str"] = "People's Strategic Information Service" + if ("HSH") + char_ids[participation_query.item[1]]["side_int"] = HSH + char_ids[participation_query.item[1]]["side_str"] = "Hegemon Shadow Service" + if ("TCD") + char_ids[participation_query.item[1]]["side_int"] = TCD + char_ids[participation_query.item[1]]["side_str"] = "Tup Commandos Division" + else + char_ids[participation_query.item[1]]["side_int"] = INDEP + char_ids[participation_query.item[1]]["side_str"] = "Independant" + + var/data = "
Welcome to the character setup screen!
" + data += "
Here is the list of your characters, and their allegience

" + + for (var/char_id in char_ids) + data += "[char_ids[char_id]["name"]] -- [char_ids[char_id]["side_str"]] -- Modify
" + + src << browse(data, "window=antag_contest_chars;size=300x200") + +/client/verb/request_objective() + set name = "Request Objective" + set category = "Contest" + set desc = "Lets you choose a contest type objective!" + + if (!config.antag_contest_enabled) + src << "The contest isn't running yet!" + return + + if (!src.mob || !isliving(src.mob)) + src << "Invalid mob type to participate!" + return + + if (!(src.mob.mind.special_role in list("Traitor", "Mercenary", "Raider"))) + src << "You do not have a valid role! You must be a traitor, mercenary, or a raider for these to be usable! Contact an admin if you need assignment." + return + + if (!establish_db_connection(dbcon)) + src << "Failed to establish SQL connection! Contact a member of staff!" + return + + var/DBQuery/part_check = dbcon.NewQuery("SELECT contest_faction FROM ss13_contest_participants WHERE character_id = :char_id AND player_ckey = :ckey") + part_check.Execute(list(":char_id" = src.prefs.current_character, ":ckey" = src.ckey)) + + if (part_check.NextRow()) + var/list/available_objs + var/side = input("Are you pro-synth or anti-synth?", "Choose wisely") as null|anything in list("Pro-synth", "Anti-synth") + if (!side) + src << "Cancelled." + return + + if (side == "Pro-synth") + available_objs = list("Promote a Synth", "Protect Robotics", "Borgify", "Protect a Synth", "Unslave Borgs") + else + available_objs = list("Sabotage Robotics", "Fire a Synth", "Brig a Synth", "Harm a Synth") + + if (!available_objs) + src << "No objectives were found for you! This is odd!" + return + + var/choice = input("Select objective type:", "Select Objective") as null|anything in available_objs + + if (!choice) + src << "Cancelled." + return + + var/datum/objective/new_objective + var/failed_target = 0 + + switch (choice) + if ("Promote a Synth") + new_objective = new /datum/objective/competition/pro_synth/promote + if (!new_objective.find_target()) + failed_target = 1 + if ("Protect Robotics") + new_objective = new /datum/objective/competition/pro_synth/protect_robotics + if ("Borgify") + new_objective = new /datum/objective/competition/pro_synth/borgify + if (!new_objective.find_target()) + failed_target = 1 + if ("Protect a Synth") + new_objective = new /datum/objective/competition/pro_synth/protect + if (!new_objective.find_target()) + failed_target = 1 + if ("Unslave Borgs") + new_objective = new /datum/objective/competition/pro_synth/unslave_borgs + if (silicon_mob_list && silicon_mob_list.len) + var/found = 0 + for (var/mob/living/silicon/robot/R in silicon_mob_list) + if (istype(R) && R.client) + // We found what we needed. + found = 1 + break + + if (!found) + failed_target = 1 + else + failed_target = 1 + if ("Sabotage Robotics") + new_objective = new /datum/objective/competition/anti_synth/sabotage + if ("Fire a Synth") + new_objective = new /datum/objective/competition/anti_synth/demote + if (!new_objective.find_target()) + failed_target = 1 + if ("Brig a Synth") + new_objective = new /datum/objective/competition/anti_synth/brig + if (!new_objective.find_target()) + failed_target = 1 + if ("Harm a Synth") + new_objective = new /datum/objective/competition/anti_synth/harm + if (!new_objective.find_target()) + failed_target = 1 + else + //wtfbbq y r u here + //go and stay go + return + + if (failed_target) + src << "Objective selection failed! No valid targets found!" + qdel(new_objective) + return + + new_objective.owner = src.mob.mind + src.mob.mind.objectives += new_objective + src << "New objective assigned! Have fun, and roleplay well!" + log_admin("CONTEST: [key_name(src)] has assigned themselves an objective: [new_objective.type].") + return + else + src << "This character hasn't been set up to participate! Consult an admin or change this yourself!" + return + +/client/proc/process_contest_topic(var/list/href) + if (!href || !href.len || !href["contest_action"]) + return + + if (!config.antag_contest_enabled) + return + + switch (href["contest_action"]) + if ("modify") + if (!href["char_id"]) + src << "Ouch, bad link." + return + + if (!establish_db_connection(dbcon)) + src << "Failed to establish SQL connection! Contact a member of staff!" + return + + var/choice = input("Choose your side:", "Contest Side") as null|anything in contest_factions + + if (!choice || contest_factions[choice] == href["current_side"]) + src << "Cancelled" + return + + var/list/sql_args = list(":ckey" = src.ckey, ":char_id" = href["char_id"], ":new_side" = contest_factions[choice]) + + var/query_content = "UPDATE ss13_contest_participants SET contest_faction = :new_side WHERE player_ckey = :ckey AND character_id = :char_id" + + if (text2num(href["previously_assigned"]) == 0) + query_content = "INSERT INTO ss13_contest_participants (player_ckey, character_id, contest_faction) VALUES (:ckey, :char_id, :new_side)" + + var/DBQuery/query = dbcon.NewQuery(query_content) + query.Execute(sql_args) + + log_debug("CONTEST: [key_name(src)] attempted to change the side of [href["char_id"]] FROM [href["current_side"]] TO [sql_args[":new_side"]]") + + if (query.ErrorMsg()) + src << "SQL query ran into an error and was cancelled! Please contact a developer to troubleshoot the logs!" + return + else + src << "Successfully updated your character's alliegence!" + src.contest_my_characters() + return diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 742169994b1..45d3a861ee9 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -165,6 +165,11 @@ if ("webint") src.open_webint() + // Antag contest shit + if (href_list["contest_action"] && config.antag_contest_enabled) + src.process_contest_topic(href_list) + return + ..() //redirect to hsrc.() /client/proc/handle_spam_prevention(var/message, var/mute_type) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index f6c3ad33b06..4a81eb47ee6 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -3,6 +3,7 @@ var/list/preferences_datums = list() var/global/list/special_roles = list( //keep synced with the defines BE_* in setup.dm --rastaf +//REALLY keep synced. The ordering of this list is critical, it must match the order of the BE_* defines --Nanako //some autodetection here. // TODO: Update to new antagonist system. "traitor" = IS_MODE_COMPILED("traitor"), // 0 @@ -19,8 +20,8 @@ var/global/list/special_roles = list( //keep synced with the defines BE_* in set "raider" = IS_MODE_COMPILED("heist"), // 11 "diona" = 1, // 12 "loyalist" = IS_MODE_COMPILED("revolution"), // 13 - "vampire" = IS_MODE_COMPILED("vampire"), // 14 - "pAI candidate" = 1, // -- TLE // 15 + "personal AI" = 1, // -- TLE // 14 + "vampire" = IS_MODE_COMPILED("vampire"), // 15 ) //used for alternate_option @@ -41,6 +42,7 @@ datum/preferences var/last_ip var/last_id var/list/notifications = list() //A list of datums, for the dynamic server greeting window. + var/list/time_of_death = list()//This is a list of last times of death for various things with different respawn timers //game-preferences var/lastchangelog = "" //Saved changlog filesize to detect if there was a change diff --git a/code/modules/client/preferences_gear.dm b/code/modules/client/preferences_gear.dm index 215827c98cc..9093f005c88 100644 --- a/code/modules/client/preferences_gear.dm +++ b/code/modules/client/preferences_gear.dm @@ -563,13 +563,13 @@ var/global/list/gear_datums = list() path = /obj/item/clothing/under/rank/medical/blue slot = slot_w_uniform cost = 1 - + /datum/gear/greenscrub display_name = "medical scrubs, green" path = /obj/item/clothing/under/rank/medical/green slot = slot_w_uniform cost = 1 - + /datum/gear/purplescrub display_name = "medical scrubs, purple" path = /obj/item/clothing/under/rank/medical/purple @@ -625,7 +625,7 @@ var/global/list/gear_datums = list() path = /obj/item/clothing/accessory/armband/science slot = slot_tie cost = 1 - + /datum/gear/armband_movement display_name = "armband, synthetic intelligence movement" path = /obj/item/clothing/accessory/armband/movement @@ -937,7 +937,7 @@ var/global/list/gear_datums = list() path = /obj/item/clothing/gloves/white cost = 2 slot = slot_gloves - + /datum/gear/black_gloves_unathi display_name = "black gloves, unathi" path = /obj/item/clothing/gloves/black/unathi @@ -949,7 +949,7 @@ var/global/list/gear_datums = list() path = /obj/item/clothing/gloves/black/tajara cost = 2 slot = slot_gloves - + /datum/gear/red_gloves_unathi display_name = "red gloves, unathi" path = /obj/item/clothing/gloves/red/unathi @@ -991,7 +991,7 @@ var/global/list/gear_datums = list() path = /obj/item/clothing/gloves/purple/unathi cost = 2 slot = slot_gloves - + /datum/gear/purple_gloves_tajaran display_name = "purple gloves, tajaran" path = /obj/item/clothing/gloves/purple/tajara @@ -1192,7 +1192,7 @@ var/global/list/gear_datums = list() display_name = "wallet" path = /obj/item/weapon/storage/wallet sort_category = "utility" - cost = 1 + cost = 1 // The rest of the trash. @@ -1267,6 +1267,18 @@ var/global/list/gear_datums = list() sort_category = "misc" cost = 1 +/datum/gear/cigar_case + display_name = "cigar case" + path = /obj/item/weapon/storage/fancy/cigar + sort_category = "misc" + cost = 2 + +/datum/gear/cigarettes + display_name = "pack of DromedaryCo cigarettes" + path = /obj/item/weapon/storage/fancy/cigarettes/dromedaryco + sort_category = "misc" + cost = 2 + /datum/gear/matchbook display_name = "matchbook" path = /obj/item/weapon/storage/box/matches @@ -1280,7 +1292,7 @@ var/global/list/gear_datums = list() cost = 1 /datum/gear/cape - display_name = " tunnel cloak" + display_name = "tunnel cloak" path = /obj/item/weapon/storage/backpack/cloak sort_category = "misc" cost = 1 @@ -1331,3 +1343,91 @@ var/global/list/gear_datums = list() cost = 1 sort_category = "ears" whitelisted = "Skrell" + +/datum/gear/red_jeweled + display_name = "skrell headtail-wear, female, red-jeweled chain" + path = /obj/item/clothing/ears/skrell/redjewel_chain + cost = 1 + sort_category = "ears" + whitelisted = "Skrell" + +/datum/gear/ebony_chain + display_name = "skrell headtail-wear, female, ebony chain" + path = /obj/item/clothing/ears/skrell/ebony_chain + cost = 1 + sort_category = "ears" + whitelisted = "Skrell" + +/datum/gear/redjeweled_band + display_name = "skrell headtail-wear, male, red-jeweled bands" + path = /obj/item/clothing/ears/skrell/redjeweled_band + cost = 1 + sort_category = "ears" + whitelisted = "Skrell" + +/datum/gear/ebony_band + display_name = "skrell headtail-wear, male, ebony bands" + path = /obj/item/clothing/ears/skrell/ebony_band + cost = 1 + sort_category = "ears" + whitelisted = "Skrell" + +/datum/gear/bluejeweled_chain + display_name = "skrell headtail-wear, female, blue-jeweled chain" + path = /obj/item/clothing/ears/skrell/bluejeweled_chain + cost = 1 + sort_category = "ears" + whitelisted = "Skrell" + +/datum/gear/bluejeweled_band + display_name = "skrell headtail-wear, male, blue-jeweled bands" + path = /obj/item/clothing/ears/skrell/bluejeweled_band + cost = 1 + sort_category = "ears" + whitelisted = "Skrell" + +/datum/gear/silver_chain + display_name = "skrell headtail-wear, female, silver chain" + path = /obj/item/clothing/ears/skrell/silver_chain + cost = 1 + sort_category = "ears" + whitelisted = "Skrell" + +/datum/gear/silver_band + display_name = "skrell headtail-wear, male, silver bands" + path = /obj/item/clothing/ears/skrell/silver_band + cost = 1 + sort_category = "ears" + whitelisted = "Skrell" + +/datum/gear/blue_skrell_cloth_band_male + display_name = "skrell headtail-wear, male, blue cloth" + path = /obj/item/clothing/ears/skrell/blue_skrell_cloth_band_male + cost = 1 + sort_category = "ears" + whitelisted = "Skrell" + +/datum/gear/blue_skrell_cloth_band_female + display_name = "skrell headtail-wear, female, blue cloth" + path = /obj/item/clothing/ears/skrell/blue_skrell_cloth_band_female + cost = 1 + sort_category = "ears" + whitelisted = "Skrell" + +/datum/gear/bandanna_r + display_name = "neck bandanna, red" + path = /obj/item/clothing/ears/bandanna + cost = 1 + sort_category = "ears" + +/datum/gear/bandanna_bl + display_name = "neck bandanna, blue" + path = /obj/item/clothing/ears/bandanna/blue + cost = 1 + sort_category = "ears" + +/datum/gear/bandanna_bk + display_name = "neck bandanna, black" + path = /obj/item/clothing/ears/bandanna/black + cost = 1 + sort_category = "ears" \ No newline at end of file diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index e78d93395d6..a8fffefcef2 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -6,7 +6,7 @@ /* Sprites used when the clothing item is refit. This is done by setting icon_override. For best results, if this is set then sprite_sheets should be null and vice versa, but that is by no means necessary. - Ideally, sprite_sheets_refit should be used for "hard" clothing items that can't change shape very well to fit the wearer (e.g. helmets, hardsuits), + Ideally, sprite_sheets_refit should be used for "hard" clothing items that can't change shape very well to fit the wearer (e.g. helmets, voidsuits), while sprite_sheets should be used for "flexible" clothing items that do not need to be refitted (e.g. vox wearing jumpsuits). */ var/list/sprite_sheets_refit = null diff --git a/code/modules/clothing/ears/bandanna.dm b/code/modules/clothing/ears/bandanna.dm new file mode 100644 index 00000000000..dfa669e9ff0 --- /dev/null +++ b/code/modules/clothing/ears/bandanna.dm @@ -0,0 +1,24 @@ +/* + Bandannas and the like +*/ + +/obj/item/clothing/ears/bandanna + name = "red bandanna" + desc = "A plain red bandanna." + icon = 'icons/obj/clothing/ears.dmi' + icon_state = "band_r" + item_state = "band_r" + w_class = 1 + slot_flags = SLOT_EARS + +/obj/item/clothing/ears/bandanna/blue + name = "blue bandanna" + desc = "A plain blue bandanna." + icon_state = "band_bl" + item_state = "band_bl" + +/obj/item/clothing/ears/bandanna/black + name = "black bandanna" + desc = "A plain black bandanna." + icon_state = "band_bk" + item_state = "band_bk" \ No newline at end of file diff --git a/code/modules/clothing/ears/skrell.dm b/code/modules/clothing/ears/skrell.dm index a92722db5ea..daaebcb95d1 100644 --- a/code/modules/clothing/ears/skrell.dm +++ b/code/modules/clothing/ears/skrell.dm @@ -32,4 +32,64 @@ name = "skrell headtail cloth" desc = "A cloth band worn by male skrell around their head tails." icon_state = "skrell_cloth_male" - item_state = "skrell_cloth_male" \ No newline at end of file + item_state = "skrell_cloth_male" + +/obj/item/clothing/ears/skrell/redjewel_chain + name = "skrell red-jeweled headtail chains" + desc = "A delicate golden chain, decorated with red jewels, worn by female skrell to decorate their head tails." + icon_state = "redjewel_chain" + item_state = "redjewel_chain" + +/obj/item/clothing/ears/skrell/ebony_chain + name = "skrell ebony headtail chains" + desc = "A delicate ebony chain worn by female skrell to decorate their head tails." + icon_state = "ebony_chain" + item_state = "ebony_chain" + +/obj/item/clothing/ears/skrell/redjeweled_band + name = "skrell red-jeweled headtail bands" + desc = "Golden metallic bands, decorated with red jewels, worn by male skrell to adorn their head tails." + icon_state = "redjeweled_band" + item_state = "redjeweled_band" + +/obj/item/clothing/ears/skrell/ebony_band + name = "skrell ebony headtail bands" + desc = "Ebony metallic bands, decorated with red jewels, worn by male skrell to adorn their head tails." + icon_state = "ebony_band" + item_state = "ebony_band" + +/obj/item/clothing/ears/skrell/bluejeweled_chain + name = "skrell blue-jeweled headtail chains" + desc = "A delicate golden chain, decorated with blue jewels, worn by female skrell to decorate their head tails." + icon_state = "bluejeweled_chain" + item_state = "bluejeweled_chain" + +/obj/item/clothing/ears/skrell/bluejeweled_band + name = "skrell blue-jeweled headtail bands" + desc = "Golden metallic bands, decorated with blue jewels, worn by male skrell to adorn their head tails." + icon_state = "bluejeweled_band" + item_state = "bluejeweled_band" + +/obj/item/clothing/ears/skrell/silver_chain + name = "skrell silver headtail chains" + desc = "A delicate silver chain worn by female skrell to decorate their head tails." + icon_state = "silver_chain" + item_state = "silver_chain" + +/obj/item/clothing/ears/skrell/silver_band + name = "skrell silver headtail bands" + desc = "Silver metallic bands, decorated with blue jewels, worn by male skrell to adorn their head tails." + icon_state = "silver_band" + item_state = "silver_band" + +/obj/item/clothing/ears/skrell/blue_skrell_cloth_band_male + name = "skrell blue headtail cloth" + desc = "A blue cloth band worn by male skrell around their head tails." + icon_state = "blue_skrell_cloth_band_male" + item_state = "blue_skrell_cloth_band_male" + +/obj/item/clothing/ears/skrell/blue_skrell_cloth_band_female + name = "skrell blue headtail cloth" + desc = "A blue cloth band worn by female skrell around their head tails." + icon_state = "blue_skrell_cloth_band_female" + item_state = "blue_skrell_cloth_band_female" \ No newline at end of file diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm index 16a6adda677..142e5d44449 100644 --- a/code/modules/clothing/head/hardhat.dm +++ b/code/modules/clothing/head/hardhat.dm @@ -31,3 +31,9 @@ /obj/item/clothing/head/hardhat/dblue icon_state = "hardhat0_dblue" item_state = "hardhat0_dblue" + +/obj/item/clothing/head/hardhat/red/atmos + name = "atmospheric firefighter helmet" + desc = "An atmospheric firefighter's helmet, able to keep the user protected from heat and fire." + icon_state = "atmos_fire" + item_state = "atmos_fire" diff --git a/code/modules/clothing/spacesuits/breaches.dm b/code/modules/clothing/spacesuits/breaches.dm index 7caa4e0bdfb..c64e9016077 100644 --- a/code/modules/clothing/spacesuits/breaches.dm +++ b/code/modules/clothing/spacesuits/breaches.dm @@ -185,12 +185,12 @@ var/global/list/breach_burn_descriptors = list( repair_power = 2 if("plastic") repair_power = 1 - + if(!repair_power) return - + if(istype(src.loc,/mob/living)) - user << "How do you intend to patch a hardsuit while someone is wearing it?" + user << "How do you intend to patch a voidsuit while someone is wearing it?" return if(!damage || !burn_damage) @@ -206,7 +206,7 @@ var/global/list/breach_burn_descriptors = list( else if(istype(W, /obj/item/weapon/weldingtool)) if(istype(src.loc,/mob/living)) - user << "\red How do you intend to patch a hardsuit while someone is wearing it?" + user << "\red How do you intend to patch a voidsuit while someone is wearing it?" return if (!damage || ! brute_damage) diff --git a/code/modules/clothing/spacesuits/rig/suits/alien.dm b/code/modules/clothing/spacesuits/rig/suits/alien.dm index cb64d2be448..904f79bc866 100644 --- a/code/modules/clothing/spacesuits/rig/suits/alien.dm +++ b/code/modules/clothing/spacesuits/rig/suits/alien.dm @@ -10,6 +10,12 @@ vision_restriction = 1 offline_vision_restriction = 2 + chest_type = /obj/item/clothing/suit/space/rig/unathi + helm_type = /obj/item/clothing/head/helmet/space/rig/unathi + boot_type = /obj/item/clothing/shoes/magboots/rig/unathi + + allowed = list(/obj/item/weapon/gun,/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/energy) + /obj/item/weapon/rig/unathi/fancy name = "breacher chassis control module" desc = "An authentic Unathi breacher chassis. Huge, bulky and absurdly heavy. It must be like wearing a tank." @@ -18,3 +24,12 @@ armor = list(melee = 90, bullet = 90, laser = 90, energy = 90, bomb = 90, bio = 100, rad = 80) vision_restriction = 0 slowdown = 4 + +/obj/item/clothing/head/helmet/space/rig/unathi + species_restricted = list("Unathi") + +/obj/item/clothing/suit/space/rig/unathi + species_restricted = list("Unathi") + +/obj/item/clothing/shoes/magboots/rig/unathi + species_restricted = list("Unathi") diff --git a/code/modules/clothing/spacesuits/void/wizard.dm b/code/modules/clothing/spacesuits/void/wizard.dm index 2fc0c76dbde..503f79d51ea 100644 --- a/code/modules/clothing/spacesuits/void/wizard.dm +++ b/code/modules/clothing/spacesuits/void/wizard.dm @@ -11,6 +11,24 @@ sprite_sheets_obj = null wizard_garb = 1 + equipped(var/mob/user) + if(!(user.mind.assigned_role == "Space Wizard")) + var/mob/living/carbon/human/H = user + var/obj/item/organ/external/LH = H.get_organ("l_hand") + var/obj/item/organ/external/RH = H.get_organ("r_hand") + var/active_hand = H.hand + user << "\red Your hand passes through the [src] with a flash of searing heat!" + playsound(user, 'sound/effects/sparks4.ogg', 40, 1) + user.drop_item() + if(active_hand) + LH.droplimb(0,DROPLIMB_BURN) + else + RH.droplimb(0,DROPLIMB_BURN) + return + else + ..() + + /obj/item/clothing/suit/space/void/wizard icon_state = "rig-wiz" name = "gem-encrusted voidsuit" @@ -24,3 +42,21 @@ sprite_sheets_refit = null sprite_sheets_obj = null wizard_garb = 1 + + equipped(var/mob/user) + if(!(user.mind.assigned_role == "Space Wizard")) + var/mob/living/carbon/human/H = user + var/obj/item/organ/external/LH = H.get_organ("l_hand") + var/obj/item/organ/external/RH = H.get_organ("r_hand") + var/active_hand = H.hand + user << "\red Your hand passes through the [src] with a flash of searing heat!" + playsound(user, 'sound/effects/sparks4.ogg', 40, 1) + user.drop_item() + if(active_hand) + LH.droplimb(0,DROPLIMB_BURN) + else + RH.droplimb(0,DROPLIMB_BURN) + return + else + ..() + diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 4c6a16b4a53..4026649c70d 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -90,7 +90,7 @@ item_state = "swat_suit" body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS slowdown = 1 - armor = list(melee = 80, bullet = 10, laser = 10, energy = 10, bomb = 0, bio = 0, rad = 0) + armor = list(melee = 80, bullet = 20, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0) flags_inv = HIDEJUMPSUIT siemens_coefficient = 0.5 pocket_slots = 4//Fullbody suit, so more slots @@ -102,7 +102,7 @@ icon_state = "bulletproof" item_state = "armor" blood_overlay_type = "armor" - armor = list(melee = 10, bullet = 80, laser = 10, energy = 10, bomb = 0, bio = 0, rad = 0) + armor = list(melee = 25, bullet = 80, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0) siemens_coefficient = 0.7 /obj/item/clothing/suit/armor/laserproof @@ -111,7 +111,7 @@ icon_state = "armor_reflec" item_state = "armor_reflec" blood_overlay_type = "armor" - armor = list(melee = 10, bullet = 10, laser = 80, energy = 50, bomb = 0, bio = 0, rad = 0) + armor = list(melee = 25, bullet = 25, laser = 80, energy = 10, bomb = 0, bio = 0, rad = 0) siemens_coefficient = 0 /obj/item/clothing/suit/armor/swat diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm index c0cdd91ecdc..4695a51224c 100644 --- a/code/modules/clothing/suits/utility.dm +++ b/code/modules/clothing/suits/utility.dm @@ -12,8 +12,8 @@ /obj/item/clothing/suit/fire name = "firesuit" desc = "A suit that protects against fire and heat." - icon_state = "fire" - item_state = "fire_suit" + icon_state = "firesuit" + item_state = "firesuit" w_class = 4//bulky item gas_transfer_coefficient = 0.90 permeability_coefficient = 0.50 @@ -29,7 +29,7 @@ /obj/item/clothing/suit/fire/firefighter icon_state = "firesuit" - item_state = "firefighter" + item_state = "firesuit" /obj/item/clothing/suit/fire/heavy @@ -40,6 +40,12 @@ w_class = 4//bulky item slowdown = 1.5 +/obj/item/clothing/suit/fire/atmos + name = "atmospheric technician firesuit" + desc = "A suit that protects against fire and heat, this one is designed for atmospheric technicians." + icon_state = "atmos_firesuit" + item_state = "atmos_firesuit" + /* * Bomb protection */ @@ -47,27 +53,105 @@ name = "bomb hood" desc = "Use in case of bomb." icon_state = "bombsuit" - flags = HEADCOVERSEYES|HEADCOVERSMOUTH|BLOCKHAIR - armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 100, bio = 0, rad = 0) + w_class = 5//Too large to fit in a backpack + flags = HEADCOVERSEYES|HEADCOVERSMOUTH|BLOCKHAIR|STOPPRESSUREDAMAGE|THICKMATERIAL|BLOCK_GAS_SMOKE_EFFECT + armor = list(melee = 30, bullet = 20, laser = 25,energy = 30, bomb = 100, bio = 60, rad = 60) flags_inv = HIDEMASK|HIDEEARS|HIDEEYES body_parts_covered = HEAD|FACE|EYES siemens_coefficient = 0 + +//Changes by Nanako +//Bomb suits should huge and robust. They used to have 100 bomb protection and nothing in other categories +//Bomb suits now have decent resistance in all categories, but with two major ergonomic drawbacks: +//1. Heavy. really heavy, massive slowdown on movement +//2. Bomb suit materials don't allow permeability of body heat, thus the wearer tends to overheat and can't wear them for long /obj/item/clothing/suit/bomb_suit name = "bomb suit" - desc = "A suit designed for safety when handling explosives." + desc = "A suit designed for safety when handling explosives. It looks heavy and uncomfortable to wear for even a short time." icon_state = "bombsuit" item_state = "bombsuit" - w_class = 4//bulky item + w_class = 7//bulky item gas_transfer_coefficient = 0.01 permeability_coefficient = 0.01 - slowdown = 2 - armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 100, bio = 0, rad = 0) + slowdown = 8 + armor = list(melee = 55, bullet = 55, laser = 55,energy = 60, bomb = 100, bio = 60, rad = 60) + flags = STOPPRESSUREDAMAGE|THICKMATERIAL flags_inv = HIDEJUMPSUIT|HIDETAIL - heat_protection = UPPER_TORSO|LOWER_TORSO - max_heat_protection_temperature = ARMOR_MAX_HEAT_PROTECTION_TEMPERATURE + heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS + cold_protection = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS + max_heat_protection_temperature = SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE siemens_coefficient = 0 + var/mob/living/carbon/human/wearer = null + var/suit_temp = T20C + +/obj/item/clothing/suit/bomb_suit/equipped(var/mob/user, var/slot) + if (slot == slot_wear_suit) + var/mob/living/carbon/human/H = user + H.visible_message("[H] starts putting on \the [src]...", "You start putting on \the [src]...") + if(!do_after(H,50)) + if(H && H.wear_suit == src) + H.wear_suit = null + H.drop_from_inventory(src) + src.forceMove(get_turf(H)) + return + + wearer = user + wearer << "You struggle into the [src]. It feels hot, heavy and uncomfortable" + if(!(src in processing_objects)) + processing_objects.Add(src) + else + wearer = null + + + ..(user, slot) + +#define BOMBSUIT_THERMAL 0.27 +#define BOMBHOOD_THERMAL 0.12 +#define BOMBSUIT_MAX_TEMPERATURE 420 //heat 2 for humans, heat 1 for unathi +/obj/item/clothing/suit/bomb_suit/process() + if (!checkworn())//If nobody's wearing the suit, then it cools down + suit_temp -= 0.5 + if (suit_temp < T20C) + suit_temp = T20C + processing_objects.Remove(src) + return + else + var/amount = BOMBSUIT_THERMAL + if (istype(wearer.head, /obj/item/clothing/head/bomb_hood))//wearing both parts heats up faster + amount += BOMBHOOD_THERMAL + + suit_temp = min(suit_temp+amount, BOMBSUIT_MAX_TEMPERATURE) + + if (wearer.bodytemperature < suit_temp) + wearer.bodytemperature += (suit_temp - wearer.bodytemperature)*0.5//Bodytemperature damps towards the suit temp + if (wearer.bodytemperature >= wearer.species.heat_discomfort_level) + wearer.species.get_environment_discomfort(wearer,"heat") + //This is added here because normal discomfort messages proc off of breath rather than bodytemperature. + //Since the surrounding environment isnt heated, they don't happen without it being specifically called here + +/obj/item/clothing/suit/bomb_suit/proc/checkworn() + if (wearer) + if (wearer.wear_suit == src) + return 1 + + if (istype(loc, /mob/living/carbon/human)) + wearer = loc + if (wearer.wear_suit == src) + return 1 + else + return 0 + + else + wearer = null + return 0 + + +/obj/item/clothing/suit/bomb_suit/Destroy() + processing_objects.Remove(src) + ..() /obj/item/clothing/head/bomb_hood/security @@ -106,3 +190,8 @@ slowdown = 1.5 armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 60, rad = 100) flags_inv = HIDEJUMPSUIT|HIDETAIL + + +#undef BOMBSUIT_THERMAL +#undef BOMBHOOD_THERMAL +#undef BOMBSUIT_MAX_TEMPERATURE \ No newline at end of file diff --git a/code/modules/clothing/under/accessories/accessory.dm b/code/modules/clothing/under/accessories/accessory.dm index dfbfc92d4b8..dd7ec5a5c3b 100644 --- a/code/modules/clothing/under/accessories/accessory.dm +++ b/code/modules/clothing/under/accessories/accessory.dm @@ -16,12 +16,15 @@ if(!inv_overlay) if(!mob_overlay) get_mob_overlay() - + var/tmp_icon_state = "[overlay_state? "[overlay_state]" : "[icon_state]"]" if(icon_override) if("[tmp_icon_state]_tie" in icon_states(icon_override)) tmp_icon_state = "[tmp_icon_state]_tie" inv_overlay = image(icon = mob_overlay.icon, icon_state = tmp_icon_state, dir = SOUTH) + if(contained_sprite) + tmp_icon_state = "[tmp_icon_state]" + inv_overlay = image("icon" = icon, "icon_state" = "[tmp_icon_state]_w", dir = SOUTH) return inv_overlay /obj/item/clothing/accessory/proc/get_mob_overlay() @@ -31,6 +34,9 @@ if("[tmp_icon_state]_mob" in icon_states(icon_override)) tmp_icon_state = "[tmp_icon_state]_mob" mob_overlay = image("icon" = icon_override, "icon_state" = "[tmp_icon_state]") + else if(contained_sprite) + tmp_icon_state = "[tmp_icon_state]_w" + mob_overlay = image("icon" = icon, "icon_state" = "[tmp_icon_state]") else mob_overlay = image("icon" = INV_ACCESSORIES_DEF_ICON, "icon_state" = "[tmp_icon_state]") return mob_overlay diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm index dfa5e211749..32bd5a28be8 100644 --- a/code/modules/customitems/item_defines.dm +++ b/code/modules/customitems/item_defines.dm @@ -144,3 +144,276 @@ icon = 'icons/obj/custom_items/bell_coat.dmi' icon_state = "bell_coat" contained_sprite = 1 + + +/obj/item/clothing/under/syndicate/tacticool/fluff/jaylor_turtleneck // Borderworlds Turtleneck - Jaylor Rameau - evilbrage - DONE + name = "borderworlds turtleneck" + desc = "A loose-fitting turtleneck, common among borderworld pilots and criminals. One criminal in particular is missing his, apparently." + + +/obj/item/weapon/melee/fluff/tina_knife // Consecrated Athame - Tina Kaekel - tainavaa - DONE + name = "consecrated athame" + desc = "An athame used in occult rituals. The double-edged dagger is dull. The handle is black with a pink/white occult design strewn about it, and 'Tina' is inscribed into it in decorated letters." + icon = 'icons/obj/custom_items/tina_knife.dmi' + icon_state = "tina_knife" + item_state = "knife" + slot_flags = SLOT_BELT + w_class = 1 + force = 2 + + +/obj/item/device/kit/paint/ripley/fluff/zairjah_kit // Hephaestus Industrial Exosuit MK III Customization Kit - Zairjah - alberyk - DONE + name = "Hephaestus Industrial Exosuit MK III customization kit" + desc = "A ripley APLU model manufactured by Hephaestus industries, a common sight in New Gibson nowadays. It shines with chrome painting and a fancy reinforced glass cockpit." + new_name = "Hephaestus Industrial Exosuit MK III" + new_desc = "An ripley APLU model manufactured by Hephaestus industries, a common sight in New Gibson nowadays. It shines with chrome painting and a fancy reinforced glass cockpit." + new_icon = "ripley_zairjah" //a lot of thanks to cakeisossim for the sprites + allowed_types = list("ripley","firefighter") + + +/obj/item/weapon/cane/fluff/uski_cane // Inscribed Silver-handled Cane - Usiki Guwan - fireandglory - DONE + name = "inscribed silver-handled cane" + desc = "This silver-handled cane has letters carved into the sides." + icon = 'icons/obj/custom_items/usiki_cane.dmi' + icon_state = "usiki_cane" + item_state = "usiki_cane" + contained_sprite = 1 + +/obj/item/weapon/cane/fluff/uski_cane/attack_self(mob/user as mob) + if(user.get_species() == "Unathi") + user << "This cane has the words 'A new and better life' carved into one side in basic, and on the other side in Sinta'Unathi." + else + user << "This cane has the words 'A new and better life' carved into the side, the other side has some unreadable carvings." + + +/obj/item/clothing/gloves/black/fluff/kathleen_glove // Black Left Glove - Kathleen Bullard - valky_walky2 - DONE + name = "black left glove" + desc = "A pretty normal looking glove to be worn on the left hand." + icon = 'icons/obj/custom_items/kathleen_glove.dmi' + icon_state = "kathleen_glove" + contained_sprite = 1 + + +/obj/structure/bed/chair/wheelchair/fluff/nomak_scooter // Mobility Scooter - Dubaku Nomak - demonofthefall - DONE + name = "mobility scooter" + desc = "A battery powered scooters designed to carry fatties." + icon = 'icons/obj/custom_items/nomak_scooter.dmi' + icon_state = "nomak_scooter" + +/obj/structure/bed/chair/wheelchair/fluff/nomak_scooter/update_icon() + return + +/obj/structure/bed/chair/wheelchair/fluff/nomak_scooter/set_dir() + ..() + overlays = null + if(buckled_mob) + buckled_mob.set_dir(dir) + + +/obj/item/weapon/coin/fluff/yoiko_coin // Sobriety Chip - Yoiko Ali - raineko - DONE + name = "sobriety chip" + desc = "A red coin, made from plastic. A triangle is engraved, surrounding it is the words: 'TO THINE OWN SELF BE TRUE'." + icon = 'icons/obj/custom_items/yoiko_coin.dmi' + icon_state = "yoiko_coin" //thanks fireandglory for the sprites + + +/obj/item/clothing/suit/unathi/mantle/fluff/karnaikai_wrappings //Unathi Wrappings - Azeazekal Karnaikai - canon35 - DONE + name = "unathi wrappings" + desc = "Stitched together clothing with bandages covering them, looks tailored for an unathi." + icon = 'icons/obj/custom_items/karnaikai_wrappings.dmi' + icon_state = "karnaikai_wrappings" //special thanks to Araskael + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + flags_inv = HIDEJUMPSUIT|HIDETAIL + species_restricted = list("Unathi") + contained_sprite = 1 + + +/obj/item/clothing/mask/gas/fluff/karnaikai_mask //Unathi head wrappings - Azeazekal Karnaikai - canon35 - DONE + name = "unathi head wrappings" + desc = "A bunch of stitched together bandages with a fibreglass breath mask on it, openings for the eyes. Looks tailored for an unathi." + icon = 'icons/obj/custom_items/karnaikai_mask.dmi' + icon_state = "karnaikai_mask" //special thanks to Araskael + species_restricted = list("Unathi") + contained_sprite = 1 + + +/obj/item/weapon/contraband/poster/fluff/conservan_poster //ATLAS poster - Conservan Xullie - conservatron - DONE + name = "ATLAS poster" + +/obj/item/weapon/contraband/poster/fluff/conservan_poster/New() + serial_number = 59 + +/datum/poster/bay_59 + name = "ATLAS poster" + desc = "ATLAS: For all of Humanity." + icon_state = "bposter59" + + +/obj/item/weapon/flame/lighter/zippo/fluff/locke_zippo // Fire Extinguisher Zippo - Jacob Locke - completegarbage - DONE + name = "fire extinguisher lighter" + desc = "Most fire extinguishers on the station are way too heavy. This one's a little lighter." + icon = 'icons/obj/custom_items/locke_zippo.dmi' + icon_state = "locke_zippo" + + +/obj/item/weapon/clipboard/fluff/zakiya_sketchpad // Sketchpad - Zakiya Ahmad - sierrakomodo - DONE + name = "sketchpad" + desc = "A simple sketchpad, about the size of a regular sheet of paper." + icon = 'icons/obj/custom_items/zakiya_sketchpad.dmi' //thanks superballs for the sprites + icon_state = "zakiya_sketchpad" + +/obj/item/weapon/clipboard/fluff/zakiya_sketchpad/New() + ..() + new /obj/item/weapon/paper(src) + new /obj/item/weapon/paper(src) + new /obj/item/weapon/paper(src) + new /obj/item/weapon/paper(src) + new /obj/item/weapon/paper(src) + new /obj/item/weapon/paper(src) + new /obj/item/weapon/paper(src) + new /obj/item/weapon/paper(src) + new /obj/item/weapon/paper(src) + new /obj/item/weapon/paper(src) + +/obj/item/weapon/clipboard/fluff/zakiya_sketchpad/update_icon() + if(toppaper) + icon_state = "zakiya_sketchpad1" + else + icon_state = "zakiya_sketchpad" + return + +/obj/item/weapon/pen/fluff/zakiya_pen // Sketching pencil - Zakiya Ahmad - sierrakomodo - DONE + name = "sketching pencil" + desc = "A graphite sketching pencil." + icon = 'icons/obj/custom_items/zakiya_pen.dmi' + icon_state = "zakiya_pen" + + +/obj/item/weapon/melee/fluff/zah_mandible // Broken Vaurca Mandible - Ka'Akaix'Zah Void - sleepywolf - DONE + name = "broken vaurca mandible" + desc = "A black, four inch long piece of a Vaurca mandible. It seems dulled, and looks like it was shot off." + icon = 'icons/obj/custom_items/zah_mandible.dmi' + icon_state = "zah_mandible" + slot_flags = SLOT_BELT + w_class = 1 + force = 2 + + +/obj/item/clothing/suit/chaplain_hoodie/fluff/nioathi_hoodie //Shaman Hoodie - Fereydoun Nioathi - jackboot - DONE + name = "shaman hoodie" + desc = "A slightly faded robe. It's worn by some Unathi shamans." + icon = 'icons/obj/custom_items/nioathi_hoodie.dmi' + icon_state = "nioathi_hoodie" + item_state = "nioathi_hoodie" + contained_sprite = 1 + + +/obj/item/weapon/implanter/fluff //snowflake implanters for snowflakes + var/allowed_ckey = "" + var/implant_type = null + +/obj/item/weapon/implanter/fluff/proc/create_implant() + if (!implant_type) + return + imp = new implant_type(src) + update() + + return + +/obj/item/weapon/implanter/fluff/attack(mob/M as mob, mob/user as mob) + if (!M.ckey || M.ckey != allowed_ckey) + return + + ..() + + +/obj/item/weapons/fluff/moon_baton //Tiger Claw - Zander Moon - omnivac - DONE + name = "tiger claw" + desc = "A small energy dagger given to Golden Tigers." + icon = 'icons/obj/custom_items/moon_baton.dmi' + icon_state = "tigerclaw" + slot_flags = SLOT_BELT + force = 2 + w_class = 2 + contained_sprite = 1 + var/active = 0 + +/obj/item/weapons/fluff/moon_baton/attack_self(mob/user) + active= !active + if(active) + playsound(user, 'sound/weapons/saberon.ogg', 50, 1) + user << "\blue \The [src] is now energised." + icon_state = "tigerclaw_active" + slot_flags = null + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + else + playsound(user, 'sound/weapons/saberoff.ogg', 50, 1) + user << "\blue \The [src] is de-energised." + icon_state = initial(icon_state) + slot_flags = initial(slot_flags) + attack_verb = list() + + +/obj/item/clothing/suit/armor/vest/fabian_coat //NT APF Armor - Fabian Goellstein - mirkoloio - DONE + name = "NT APF armor" + desc = "This is a NT Asset Protection Force Armor, it is fashioned as a jacket in NT Security Colors. The nameplate carries the Name 'Goellstein'." + icon = 'icons/obj/custom_items/fabian_coat.dmi' + icon_state = "fabian_coat_open" + contained_sprite = 1 + +/obj/item/clothing/suit/armor/vest/fabian_coat/verb/toggle() + set name = "Toggle Coat Zipper" + set category = "Object" + set src in usr + + if(!usr.canmove || usr.stat || usr.restrained()) + return 0 + + switch(icon_state) + if("fabian_coat_open") + icon_state = "fabian_coat_closed" + usr << "You zip up \the [src]." + if("fabian_coat_closed") + icon_state = "fabian_coat_open" + usr << "You unzip \the [src]." + else + usr << "You attempt to button-up the velcro on your [src], before promptly realising how silly you are." + return + + usr.update_inv_wear_suit() + +/obj/item/clothing/head/beret/centcom/officer/fluff/fabian_beret //Worn Security Beret - Fabian Goellstein - mirkoloio - DONE + name = "worn security beret" + desc = "A NT Asset Protection Force Beret. It has the NT APF insignia on it as well as the Name 'Goellstein' inside." + + +/obj/item/clothing/accessory/armband/fluff/vittorio_armband //ATLAS Armband - Vittorio Giurifiglio - tytostyris - DONE + name = "Atlas armband" + desc = "This is an atlas armband showing anyone who sees this person, as a member of the Political party Atlas." + icon = 'icons/obj/custom_items/vittorio_armband.dmi' + icon_state = "vittorio_armband" + contained_sprite = 1 + +/obj/item/clothing/head/fluff/vittorio_fez //Black Fez - Vittorio Giurifiglio - tytostyris - DONE + name = "black fez" + desc = "It is a black fez, it bears an Emblem of the Astronomical symbol of Earth, It also has some nice tassels." + icon = 'icons/obj/custom_items/vittorio_fez.dmi' + icon_state = "vittorio_fez" + contained_sprite = 1 + + +/obj/item/clothing/suit/fluff/centurion_cloak //Paludamentum - Centurion - cakeisossim - DONE + name = "paludamentum" + desc = "A cloak-like piece of silky, red fabric. Fashioned at one point where the shoulder would be with a golden pin." + icon = 'icons/obj/custom_items/centurion_cloak.dmi' + icon_state = "centurion_cloak" + body_parts_covered = UPPER_TORSO|LOWER_TORSO + contained_sprite = 1 + + +/obj/item/clothing/ears/bandanna/fluff/kir_bandanna// Kir's Bandanna - Kir Iziki - araskael - DONE + name = "purple bandanna" + desc = "A worn and faded purple bandanna with a knotted, dragon-like design on it." + icon = 'icons/obj/custom_items/kir_bandanna.dmi' + icon_state = "kir_bandanna" + contained_sprite = 1 diff --git a/code/modules/customitems/item_spawning.dm b/code/modules/customitems/item_spawning.dm index 729c204f8b3..48e39d42c55 100644 --- a/code/modules/customitems/item_spawning.dm +++ b/code/modules/customitems/item_spawning.dm @@ -80,6 +80,13 @@ var/obj/item/device/kit/suit/kit = item kit.new_light_overlay = additional_data kit.new_mob_icon_file = CUSTOM_ITEM_MOB + + // for snowflake implants + else if(istype(item, /obj/item/weapon/implanter/fluff)) + var/obj/item/weapon/implanter/fluff/L = item + L.allowed_ckey = assoc_key + L.implant_type = text2path(additional_data) + L.create_implant() return item diff --git a/code/modules/detectivework/tools/crimekit.dm b/code/modules/detectivework/tools/crimekit.dm index 8b12203b217..1cb4836da1b 100644 --- a/code/modules/detectivework/tools/crimekit.dm +++ b/code/modules/detectivework/tools/crimekit.dm @@ -6,6 +6,8 @@ icon_state = "case" item_state = "case" storage_slots = 14 + max_storage_space = 35 + contained_sprite = 1 /obj/item/weapon/storage/briefcase/crimekit/New() ..() diff --git a/code/modules/detectivework/tools/rag.dm b/code/modules/detectivework/tools/rag.dm index 816a228a9c5..872140bdd6f 100644 --- a/code/modules/detectivework/tools/rag.dm +++ b/code/modules/detectivework/tools/rag.dm @@ -132,12 +132,13 @@ if(!proximity) return - if(istype(A, /obj/structure/reagent_dispensers)) + if(istype(A, /obj/structure/reagent_dispensers) || istype(A, /obj/structure/mopbucket) || istype(A, /obj/item/weapon/reagent_containers/glass)) if(!reagents.get_free_space()) user << "\The [src] is already soaked." return if(A.reagents && A.reagents.trans_to_obj(src, reagents.maximum_volume)) + playsound(loc, 'sound/effects/slosh.ogg', 25, 1) user.visible_message("\The [user] soaks [src] using [A].", "You soak [src] using [A].") update_name() return diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm index fd4d38629ff..edb9d74051b 100644 --- a/code/modules/events/event_container.dm +++ b/code/modules/events/event_container.dm @@ -122,6 +122,7 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT next_event = EM return EM + /datum/event_container/mundane severity = EVENT_LEVEL_MUNDANE available_events = list( @@ -132,48 +133,51 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Camera Damage", /datum/event/camera_damage, 20, list(ASSIGNMENT_ENGINEER = 10)), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Economic News", /datum/event/economic_event, 300), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Lost Carp", /datum/event/carp_migration, 20, list(ASSIGNMENT_SECURITY = 10), 1), - new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Money Hacker", /datum/event/money_hacker, 0, list(ASSIGNMENT_ANY = 4), 1, 10, 25), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Money Hacker", /datum/event/money_hacker, 10), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Money Lotto", /datum/event/money_lotto, 0, list(ASSIGNMENT_ANY = 1), 1, 5, 15), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Mundane News", /datum/event/mundane_news, 300), - new /datum/event_meta(EVENT_LEVEL_MUNDANE, "PDA Spam", /datum/event/pda_spam, 0, list(ASSIGNMENT_ANY = 4), 0, 25, 50), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "PDA Spam", /datum/event/pda_spam, 0, list(ASSIGNMENT_ANY = 3), 0, 0, 50), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Space Dust", /datum/event/dust , 30, list(ASSIGNMENT_ENGINEER = 5), 0, 0, 50), new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Trivial News", /datum/event/trivial_news, 400), - new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Vermin Infestation",/datum/event/infestation, 100, list(ASSIGNMENT_JANITOR = 100)), - new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Wallrot", /datum/event/wallrot, 0, list(ASSIGNMENT_ENGINEER = 30, ASSIGNMENT_GARDENER = 50)), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Vermin Infestation",/datum/event/infestation, 50, list(ASSIGNMENT_JANITOR = 50)), + new /datum/event_meta(EVENT_LEVEL_MUNDANE, "Wallrot", /datum/event/wallrot, 75, list(ASSIGNMENT_ENGINEER = 5, ASSIGNMENT_GARDENER = 20)), ) /datum/event_container/moderate severity = EVENT_LEVEL_MODERATE available_events = list( - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Nothing", /datum/event/nothing, 1230), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Appendicitis", /datum/event/spontaneous_appendicitis, 0, list(ASSIGNMENT_MEDICAL = 10), 1), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Carp School", /datum/event/carp_migration, 100, list(ASSIGNMENT_ENGINEER = 10, ASSIGNMENT_SECURITY = 20), 1), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Communication Blackout", /datum/event/communications_blackout, 500, list(ASSIGNMENT_AI = 150, ASSIGNMENT_SECURITY = 120)), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Electrical Storm", /datum/event/electrical_storm, 250, list(ASSIGNMENT_ENGINEER = 20, ASSIGNMENT_JANITOR = 150)), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Gravity Failure", /datum/event/gravity, 75, list(ASSIGNMENT_ENGINEER = 60)), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Grid Check", /datum/event/grid_check, 200, list(ASSIGNMENT_SCIENTIST = 10)), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Ion Storm", /datum/event/ionstorm, 0, list(ASSIGNMENT_AI = 50, ASSIGNMENT_CYBORG = 50, ASSIGNMENT_ENGINEER = 15, ASSIGNMENT_SCIENTIST = 5)), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Meteor Shower", /datum/event/meteor_shower, 0, list(ASSIGNMENT_ENGINEER = 20)), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Prison Break", /datum/event/prison_break, 0, list(ASSIGNMENT_SECURITY = 100)), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Radiation Storm", /datum/event/radiation_storm, 0, list(ASSIGNMENT_MEDICAL = 50), 1), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Random Antagonist", /datum/event/random_antag, 2.5, list(ASSIGNMENT_SECURITY = 1), 1, 0, 5), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Rogue Drones", /datum/event/rogue_drone, 20, list(ASSIGNMENT_SECURITY = 20)), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Space Dust", /datum/event/dust, 30, list(ASSIGNMENT_ENGINEER = 5)), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Spider Infestation", /datum/event/spider_infestation, 100, list(ASSIGNMENT_SECURITY = 30), 1), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Viral Infection", /datum/event/viral_infection, 0, list(ASSIGNMENT_MEDICAL = 150), 1), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Nothing", /datum/event/nothing, 150), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Appendicitis", /datum/event/spontaneous_appendicitis, 0, list(ASSIGNMENT_MEDICAL = 25)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Carp School", /datum/event/carp_migration, 50, list(ASSIGNMENT_SECURITY = 25)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Communication Blackout", /datum/event/communications_blackout, 60), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Electrical Storm", /datum/event/electrical_storm, 60, list(ASSIGNMENT_ENGINEER = 5, ASSIGNMENT_JANITOR = 20)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Gravity Failure", /datum/event/gravity, 100), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Grid Check", /datum/event/grid_check, 100), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Ion Storm", /datum/event/ionstorm, 0, list(ASSIGNMENT_AI = 40, ASSIGNMENT_CYBORG = 20, ASSIGNMENT_ENGINEER = 5, ASSIGNMENT_SCIENTIST = 5)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Meteor Shower", /datum/event/meteor_shower, 50, list(ASSIGNMENT_ENGINEER = 25)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Prison Break", /datum/event/prison_break, 0, list(ASSIGNMENT_SECURITY = 15, ASSIGNMENT_CYBORG = 20),1), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Radiation Storm", /datum/event/radiation_storm, 100), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Random Antagonist", /datum/event/random_antag, 0, list(ASSIGNMENT_ANY = 2, ASSIGNMENT_SECURITY = 1),0,10,150), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Rogue Drones", /datum/event/rogue_drone, 50, list(ASSIGNMENT_SECURITY = 25)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Space Dust", /datum/event/dust, 50, list(ASSIGNMENT_ENGINEER = 5)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Spider Infestation", /datum/event/spider_infestation, 50, list(ASSIGNMENT_SECURITY = 25)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Viral Infection", /datum/event/viral_infection, 0, list(ASSIGNMENT_MEDICAL = 10), 1), ) /datum/event_container/major severity = EVENT_LEVEL_MAJOR available_events = list( - new /datum/event_meta(EVENT_LEVEL_MAJOR, "Nothing", /datum/event/nothing, 1320), - new /datum/event_meta(EVENT_LEVEL_MAJOR, "Blob", /datum/event/blob, 0, list(ASSIGNMENT_ENGINEER = 60), 1), - new /datum/event_meta(EVENT_LEVEL_MAJOR, "Carp Migration", /datum/event/carp_migration, 0, list(ASSIGNMENT_SECURITY = 3), 1), - new /datum/event_meta(EVENT_LEVEL_MAJOR, "Meteor Wave", /datum/event/meteor_wave, 0, list(ASSIGNMENT_ENGINEER = 3), 1), - new /datum/event_meta(EVENT_LEVEL_MAJOR, "Space Vines", /datum/event/spacevine, 0, list(ASSIGNMENT_ENGINEER = 15), 1), - new /datum/event_meta(EVENT_LEVEL_MAJOR, "Viral Infection", /datum/event/viral_infection, 0, list(ASSIGNMENT_MEDICAL = 30), 1), + new /datum/event_meta(EVENT_LEVEL_MAJOR, "Blob", /datum/event/blob, 40, list(ASSIGNMENT_ENGINEER = 5,ASSIGNMENT_SECURITY = 5), 1), + new /datum/event_meta(EVENT_LEVEL_MAJOR, "Carp Migration", /datum/event/carp_migration, 60, list(ASSIGNMENT_SECURITY = 10), 1), + new /datum/event_meta(EVENT_LEVEL_MAJOR, "Meteor Wave", /datum/event/meteor_wave, 50, list(ASSIGNMENT_ENGINEER = 15),1), + new /datum/event_meta(EVENT_LEVEL_MAJOR, "Space Vines", /datum/event/spacevine, 50, list(ASSIGNMENT_ENGINEER = 10, ASSIGNMENT_GARDENER = 20), 1), + new /datum/event_meta(EVENT_LEVEL_MAJOR, "Viral Infection", /datum/event/viral_infection, 20, list(ASSIGNMENT_MEDICAL = 10), 1), ) +//NOTE: Removed "Nothing" option from moderate and severe events. +//They are already made rare and varied enough by the time delay mechanics, +//forcing a random failure to pick an event sucks, and lack of stuff happening causes lots of SSDs + #undef ASSIGNMENT_ANY #undef ASSIGNMENT_AI diff --git a/code/modules/events/event_dynamic.dm b/code/modules/events/event_dynamic.dm index 3539130c275..000f1907679 100644 --- a/code/modules/events/event_dynamic.dm +++ b/code/modules/events/event_dynamic.dm @@ -1,3 +1,8 @@ +// WARNING +//-- Added 2016-08-02 by Nanako +//This file is deprecated. The lists in event_container.dm handle event probabilities +//Do not use this file + /* /proc/start_events() diff --git a/code/modules/hydroponics/seed_storage.dm b/code/modules/hydroponics/seed_storage.dm index 3e533768886..84ed688e5f4 100644 --- a/code/modules/hydroponics/seed_storage.dm +++ b/code/modules/hydroponics/seed_storage.dm @@ -45,7 +45,7 @@ /obj/machinery/seed_storage/xenobotany name = "Xenobotany seed storage" scanner = list("stats", "produce", "soil", "temperature", "light") - starting_seeds = list(/obj/item/seeds/ambrosiavulgarisseed = 3, /obj/item/seeds/appleseed = 3, /obj/item/seeds/amanitamycelium = 2, /obj/item/seeds/bananaseed = 3, /obj/item/seeds/berryseed = 3, /obj/item/seeds/cabbageseed = 3, /obj/item/seeds/carrotseed = 3, /obj/item/seeds/chantermycelium = 3, /obj/item/seeds/cherryseed = 3, /obj/item/seeds/chiliseed = 3, /obj/item/seeds/cocoapodseed = 3, /obj/item/seeds/cornseed = 3, /obj/item/seeds/replicapod = 3, /obj/item/seeds/eggplantseed = 3, /obj/item/seeds/glowshroom = 2, /obj/item/seeds/grapeseed = 3, /obj/item/seeds/grassseed = 3, /obj/item/seeds/lemonseed = 3, /obj/item/seeds/libertymycelium = 2, /obj/item/seeds/limeseed = 3, /obj/item/seeds/mtearseed = 2, /obj/item/seeds/nettleseed = 2, /obj/item/seeds/orangeseed = 3, /obj/item/seeds/peanutseed = 3, /obj/item/seeds/plastiseed = 3, /obj/item/seeds/plumpmycelium = 3, /obj/item/seeds/poppyseed = 3, /obj/item/seeds/potatoseed = 3, /obj/item/seeds/pumpkinseed = 3, /obj/item/seeds/reishimycelium = 2, /obj/item/seeds/riceseed = 3, /obj/item/seeds/soyaseed = 3, /obj/item/seeds/sugarcaneseed = 3, /obj/item/seeds/sunflowerseed = 3, /obj/item/seeds/shandseed = 2, /obj/item/seeds/tobaccoseed = 3, /obj/item/seeds/tomatoseed = 3, /obj/item/seeds/towermycelium = 3, /obj/item/seeds/watermelonseed = 3, /obj/item/seeds/wheatseed = 3, /obj/item/seeds/whitebeetseed = 3) + starting_seeds = list(/obj/item/seeds/ambrosiavulgarisseed = 3, /obj/item/seeds/appleseed = 3, /obj/item/seeds/amanitamycelium = 2, /obj/item/seeds/bananaseed = 3, /obj/item/seeds/berryseed = 3, /obj/item/seeds/cabbageseed = 3, /obj/item/seeds/carrotseed = 3, /obj/item/seeds/chantermycelium = 3, /obj/item/seeds/cherryseed = 3, /obj/item/seeds/chiliseed = 3, /obj/item/seeds/cocoapodseed = 3, /obj/item/seeds/cornseed = 3, /obj/item/seeds/replicapod = 3, /obj/item/seeds/eggplantseed = 3, /obj/item/seeds/glowshroom = 2, /obj/item/seeds/grapeseed = 3, /obj/item/seeds/grassseed = 3, /obj/item/seeds/lemonseed = 3, /obj/item/seeds/libertymycelium = 2, /obj/item/seeds/limeseed = 3, /obj/item/seeds/mtearseed = 2, /obj/item/seeds/nettleseed = 2, /obj/item/seeds/orangeseed = 3, /obj/item/seeds/peanutseed = 3, /obj/item/seeds/plastiseed = 3, /obj/item/seeds/plumpmycelium = 3, /obj/item/seeds/poppyseed = 3, /obj/item/seeds/potatoseed = 3, /obj/item/seeds/pumpkinseed = 3, /obj/item/seeds/reishimycelium = 2, /obj/item/seeds/riceseed = 3, /obj/item/seeds/soyaseed = 3, /obj/item/seeds/sugarcaneseed = 3, /obj/item/seeds/sunflowerseed = 3, /obj/item/seeds/shandseed = 2, /obj/item/seeds/tobaccoseed = 3, /obj/item/seeds/tomatoseed = 3, /obj/item/seeds/towermycelium = 3, /obj/item/seeds/watermelonseed = 3, /obj/item/seeds/wheatseed = 3, /obj/item/seeds/whitebeetseed = 3, /obj/item/seeds/koisspore = 3) /obj/machinery/seed_storage/attack_hand(mob/user as mob) user.set_machine(src) diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm index 3ef43422ea3..6a2e364cc31 100644 --- a/code/modules/materials/material_recipes.dm +++ b/code/modules/materials/material_recipes.dm @@ -42,6 +42,7 @@ )) recipes += new/datum/stack_recipe("table frame", /obj/structure/table, 1, time = 10, one_per_turf = 1, on_floor = 1) + recipes += new/datum/stack_recipe("custodial cart", /obj/structure/janitorialcart, 15, time = 120, one_per_turf = 1, on_floor = 1) recipes += new/datum/stack_recipe("rack", /obj/structure/table/rack, 1, time = 5, one_per_turf = 1, on_floor = 1) recipes += new/datum/stack_recipe("closet", /obj/structure/closet, 2, time = 15, one_per_turf = 1, on_floor = 1) recipes += new/datum/stack_recipe("canister", /obj/machinery/portable_atmospherics/canister, 10, time = 15, one_per_turf = 1, on_floor = 1) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index bde0c1db5c8..e4b5b17ce51 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -32,6 +32,9 @@ var/global/list/image/ghost_sightless_images = list() //this is a list of images incorporeal_move = 1 /mob/dead/observer/New(mob/body) + if (istype(body, /mob/dead/observer)) + return//A ghost can't become a ghost. + sight |= SEE_TURFS | SEE_MOBS | SEE_OBJS | SEE_SELF see_invisible = SEE_INVISIBLE_OBSERVER see_in_dark = 100 @@ -44,7 +47,7 @@ var/global/list/image/ghost_sightless_images = list() //this is a list of images updateallghostimages() var/turf/T - if(ismob(body)) + if (ismob(body)) T = get_turf(body) //Where is the body located? attack_log = body.attack_log //preserve our attack logs by copying them to our ghost @@ -95,7 +98,17 @@ var/global/list/image/ghost_sightless_images = list() //this is a list of images if(target) ManualFollow(target) +/mob/dead/observer/proc/initialise_postkey() + //This function should be run after a ghost has been created and had a ckey assigned + //Death times are initialised if they were unset + //get/set death_time functions are in mob_helpers.dm + if (!get_death_time(ANIMAL)) + set_death_time(ANIMAL, world.time - RESPAWN_ANIMAL)//allow instant mouse spawning + if (!get_death_time(MINISYNTH)) + set_death_time(MINISYNTH, world.time - RESPAWN_MINISYNTH) //allow instant drone spawning + if (!get_death_time(CREW)) + set_death_time(CREW, world.time) /mob/dead/attackby(obj/item/W, mob/user) if(istype(W,/obj/item/weapon/book/tome)) @@ -146,15 +159,30 @@ Works together with spawning an observer, noted above. return 1 /mob/proc/ghostize(var/can_reenter_corpse = 1) - if(key) + if(ckey) var/mob/dead/observer/ghost = new(src) //Transfer safety to observer spawning proc. ghost.can_reenter_corpse = can_reenter_corpse ghost.timeofdeath = src.stat == DEAD ? src.timeofdeath : world.time - ghost.key = key + + + //This is duplicated for robustness in cases where death might not be called. + //It is also set in the mob/death proc + if (isanimal(src)) + set_death_time(ANIMAL, world.time) + else if (ispAI(src) || isdrone(src)) + set_death_time(MINISYNTH, world.time) + else + set_death_time(CREW, world.time)//Crew is the fallback + + + ghost.ckey = ckey + ghost.client = client + ghost.initialise_postkey() if(ghost.client) - ghost.client.time_died_as_mouse = ghost.timeofdeath - if(ghost.client && !ghost.client.holder && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed. - ghost.verbs -= /mob/dead/observer/verb/toggle_antagHUD // Poor guys, don't know what they are missing! + + + if(!ghost.client.holder && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed. + ghost.verbs -= /mob/dead/observer/verb/toggle_antagHUD // Poor guys, don't know what they are missing! return ghost /* @@ -429,11 +457,11 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp src << "You may not spawn as a mouse on this Z-level." return - var/timedifference = world.time - client.time_died_as_mouse - if(client.time_died_as_mouse && timedifference <= mouse_respawn_time * 600) - var/timedifference_text - timedifference_text = time2text(mouse_respawn_time * 600 - timedifference,"mm:ss") - src << "You may only spawn again as a mouse more than [mouse_respawn_time] minutes after your death. You have [timedifference_text] left." + var/timedifference = world.time - get_death_time(ANIMAL)//get/set death_time functions are in mob_helpers.dm + if(timedifference <= RESPAWN_ANIMAL) + var/timedifference_text = time2text(RESPAWN_ANIMAL - timedifference,"mm:ss") + var/basetime = time2text(RESPAWN_ANIMAL,"mm:ss") + src << "You may only spawn again as a mouse more than [basetime] minutes after your death. You have [timedifference_text] left." return var/response = alert(src, "Are you -sure- you want to become a mouse?","Are you sure you want to squeek?","Squeek!","Nope!") diff --git a/code/modules/mob/death.dm b/code/modules/mob/death.dm index fe7ba68a5e2..6e644454791 100644 --- a/code/modules/mob/death.dm +++ b/code/modules/mob/death.dm @@ -80,6 +80,12 @@ healths.icon_state = "health6" timeofdeath = world.time + if (isanimal(src)) + set_death_time(ANIMAL, world.time) + else if (ispAI(src) || isdrone(src)) + set_death_time(MINISYNTH, world.time) + else if (isliving(src)) + set_death_time(CREW, world.time)//Crew is the fallback if(mind) mind.store_memory("Time of death: [worldtime2text()]", 0) living_mob_list -= src dead_mob_list |= src diff --git a/code/modules/mob/holder.dm b/code/modules/mob/holder.dm index a4525bfb3d1..aa7ac209d77 100644 --- a/code/modules/mob/holder.dm +++ b/code/modules/mob/holder.dm @@ -14,7 +14,6 @@ var/last_loc_general//This stores a general location of the object. Ie, a container or a mob var/last_loc_specific//This stores specific extra information about the location, pocket, hand, worn on head, etc. Only relevant to mobs - var/checkverb /obj/item/weapon/holder/New() if (!item_state) @@ -29,21 +28,38 @@ /obj/item/weapon/holder/process() - if (!(istype(loc,/obj/item/weapon/storage)))//Mobs bug out if placed directly into a container - if(!get_holding_mob()) - - for(var/mob/M in contents) - - var/atom/movable/mob_container - mob_container = M - mob_container.loc = src.loc//if the holder was placed into a disposal, this should place the animal in the disposal - M.reset_view() - M.verbs -= /mob/living/proc/get_holder_location - qdel(src) + if(!get_holding_mob() || contained.loc != src) + if (is_unsafe_container(loc) && contained.loc == src) return + + + for(var/mob/M in contents) + var/atom/movable/mob_container + mob_container = M + mob_container.forceMove(src.loc)//if the holder was placed into a disposal, this should place the animal in the disposal + M.reset_view() + + var/mob/L = get_holding_mob() + if (L) + L.drop_from_inventory(src) + + qdel(src) + return if (isalive && contained.stat == DEAD) held_death(1)//If we get here, it means the mob died sometime after we picked it up. We pass in 1 so that we can play its deathmessage + +//This function checks if the current location is safe to release inside +//it returns 1 if the creature will bug out when released +/obj/item/weapon/holder/proc/is_unsafe_container(var/obj/place) + if (istype(place, /obj/item/weapon/storage)) + return 1 + else if (istype(place, /obj/structure/closet/crate)) + return 1 + else + return 0 + + /obj/item/weapon/holder/attackby(obj/item/weapon/W as obj, mob/user as mob) for(var/mob/M in src.contents) M.attackby(W,user) @@ -121,8 +137,8 @@ //update_icon() -/mob/living/proc/get_scooped(var/mob/living/carbon/grabber) - if(!holder_type || buckled || pinned.len) +/mob/living/proc/get_scooped(var/mob/living/carbon/grabber, var/mob/user = null) + if(!holder_type || buckled || pinned.len || !Adjacent(grabber)) return if ((grabber.hand == 0 && grabber.r_hand) || (grabber.hand == 1 && grabber.l_hand))//Checking if the hand is full @@ -134,8 +150,9 @@ spawn(2) var/obj/item/weapon/holder/H = new holder_type(loc) - src.loc = H - H.name = loc.name + H.name = src.name + src.forceMove(H) + H.contained = src @@ -146,10 +163,13 @@ else H.isalive = 1//We note that the mob is alive when picked up. If it dies later, we can know that its death happened while held, and play its deathmessage for it - grabber << "You scoop up [src]." - src << "[grabber] scoops you up." + if (user == src) + grabber << "[src.name] climbs up onto you." + src << "You climb up onto [grabber]." + else + grabber << "You scoop up [src]." + src << "[grabber] scoops you up." grabber.status_flags |= PASSEMOTES - H.attack_hand(grabber)//We put this last to prevent some race conditions return diff --git a/code/modules/mob/language/outsider.dm b/code/modules/mob/language/outsider.dm index b7d80b45bd9..0a2eca31435 100644 --- a/code/modules/mob/language/outsider.dm +++ b/code/modules/mob/language/outsider.dm @@ -101,6 +101,12 @@ "gal'h'rfikk", "harfrandid", "mud'gib", "fuu", "ma'jin", "dedo", "ol'btoh", "n'ath", "reth", "sh'yro", "eth", \ "d'rekkathnor", "khari'd", "gual'te", "nikka", "nikt'o", "barada", "kla'atu", "barhah", "hra" ,"zar'garis") +/datum/language/cultcommon/get_random_name() + var/new_name = "[pick(list("Anguished", "Blasphemous", "Corrupt", "Cruel", "Depraved", "Despicable", "Disturbed", "Exacerbated", "Foul", "Hateful", "Inexorable", "Implacable", "Impure", "Malevolent", "Malignant", "Malicious", "Pained", "Profane", "Profligate", "Relentless", "Resentful", "Restless", "Spiteful", "Tormented", "Unclean", "Unforgiving", "Vengeful", "Vindictive", "Wicked", "Wronged"))]" + new_name += "[pick(list(" "))]" + new_name += "[pick(list("Apparition", "Aptrgangr", "Dis", "Draugr", "Dybbuk", "Eidolon", "Fetch", "Fylgja", "Ghast", "Ghost", "Gjenganger", "Haint", "Phantom", "Phantasm", "Poltergeist", "Revenant", "Shade", "Shadow", "Soul", "Spectre", "Spirit", "Skeleton", "Visitant", "Wraith"))]" + return new_name + /datum/language/cult name = "Occult" desc = "The initiated can share their thoughts by means defying all reason." diff --git a/code/modules/mob/language/station.dm b/code/modules/mob/language/station.dm index 89c54114632..a585d089692 100644 --- a/code/modules/mob/language/station.dm +++ b/code/modules/mob/language/station.dm @@ -69,7 +69,7 @@ /datum/language/bug name = "Hivenet" desc = "Complex Vaurcesian language comprised of rapid mandible-clicking, \"It's a bugs life.\"" - speech_verb = "broadcasts" + speech_verb = " broadcasts" colour = "vaurca" key = "9" native = 1 diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm index bdf5091dadb..c56d7f8eabd 100644 --- a/code/modules/mob/living/bot/bot.dm +++ b/code/modules/mob/living/bot/bot.dm @@ -17,6 +17,7 @@ var/obj/access_scanner = null var/list/req_access = list() var/list/req_one_access = list() + var/master_access = access_robotics /mob/living/bot/New() ..() @@ -53,12 +54,19 @@ /mob/living/bot/death() explode() +/mob/living/bot/proc/has_master_access(var/obj/item/I) + var/list/L = I.GetAccess() + if (master_access in L) + return 1 + else + return 0 + + /mob/living/bot/attackby(var/obj/item/O, var/mob/user) if(O.GetID()) - if(access_scanner.allowed(user) && !open && !emagged) + if((has_master_access(O) || access_scanner.allowed(user)) && !open && !emagged) locked = !locked user << "Controls are now [locked ? "locked." : "unlocked."]" - attack_hand(user) else if(emagged) user << "ERROR" diff --git a/code/modules/mob/living/bot/cleanbot.dm b/code/modules/mob/living/bot/cleanbot.dm index 2c733bbd688..41c15fd9e34 100644 --- a/code/modules/mob/living/bot/cleanbot.dm +++ b/code/modules/mob/living/bot/cleanbot.dm @@ -317,6 +317,7 @@ user << "You add the robot arm to the bucket and sensor assembly. Beep boop!" user.drop_from_inventory(src) qdel(src) + return 1 else if(istype(O, /obj/item/weapon/pen)) var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN) diff --git a/code/modules/mob/living/bot/ed209bot.dm b/code/modules/mob/living/bot/ed209bot.dm index ef81a4a0b2f..3e8cd097c87 100644 --- a/code/modules/mob/living/bot/ed209bot.dm +++ b/code/modules/mob/living/bot/ed209bot.dm @@ -105,6 +105,7 @@ else item_state = "ed209_legs" icon_state = "ed209_legs" + return 1 if(2) if(istype(W, /obj/item/clothing/suit/storage/vest)) @@ -115,6 +116,7 @@ name = "vest/legs/frame assembly" item_state = "ed209_shell" icon_state = "ed209_shell" + return 1 if(3) if(istype(W, /obj/item/weapon/weldingtool)) @@ -123,6 +125,7 @@ build_step++ name = "shielded frame assembly" user << "You welded the vest to [src]." + return 1 if(4) if(istype(W, /obj/item/clothing/head/helmet)) user.drop_item() @@ -132,6 +135,7 @@ name = "covered and shielded frame assembly" item_state = "ed209_hat" icon_state = "ed209_hat" + return 1 if(5) if(isprox(W)) @@ -142,6 +146,7 @@ name = "covered, shielded and sensored frame assembly" item_state = "ed209_prox" icon_state = "ed209_prox" + return 1 if(6) if(istype(W, /obj/item/stack/cable_coil)) @@ -166,6 +171,7 @@ icon_state = "ed209_taser" user.drop_item() qdel(W) + return 1 if(8) if(istype(W, /obj/item/weapon/screwdriver)) @@ -188,3 +194,4 @@ qdel(W) user.drop_from_inventory(src) qdel(src) + return 1 diff --git a/code/modules/mob/living/bot/farmbot.dm b/code/modules/mob/living/bot/farmbot.dm index 7900b385279..0ea5d72b8d2 100644 --- a/code/modules/mob/living/bot/farmbot.dm +++ b/code/modules/mob/living/bot/farmbot.dm @@ -319,6 +319,7 @@ name = "farmbot assembly" user.remove_from_mob(W) qdel(W) + return 1 else if((istype(W, /obj/item/weapon/reagent_containers/glass/bucket)) && (build_step == 1)) build_step++ @@ -326,6 +327,7 @@ name = "farmbot assembly with bucket" user.remove_from_mob(W) qdel(W) + return 1//Prevents the object's afterattack from executing and causing runtime errors else if((istype(W, /obj/item/weapon/material/minihoe)) && (build_step == 2)) build_step++ @@ -333,6 +335,7 @@ name = "farmbot assembly with bucket and minihoe" user.remove_from_mob(W) qdel(W) + return 1 else if((isprox(W)) && (build_step == 3)) build_step++ @@ -345,6 +348,7 @@ user.remove_from_mob(W) qdel(W) qdel(src) + return 1 else if(istype(W, /obj/item/weapon/pen)) var/t = input(user, "Enter new robot name", name, created_name) as text diff --git a/code/modules/mob/living/bot/floorbot.dm b/code/modules/mob/living/bot/floorbot.dm index 5b64540f70b..472d1a8619b 100644 --- a/code/modules/mob/living/bot/floorbot.dm +++ b/code/modules/mob/living/bot/floorbot.dm @@ -327,6 +327,7 @@ user << "You add the sensor to the toolbox and tiles!" user.drop_from_inventory(src) qdel(src) + return 1 else if (istype(W, /obj/item/weapon/pen)) var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN) if(!t) @@ -357,6 +358,7 @@ user << "You add the robot arm to the odd looking toolbox assembly! Boop beep!" user.drop_from_inventory(src) qdel(src) + return 1 else if(istype(W, /obj/item/weapon/pen)) var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN) if(!t) diff --git a/code/modules/mob/living/bot/medbot.dm b/code/modules/mob/living/bot/medbot.dm index f3b2a353390..671f63002ec 100644 --- a/code/modules/mob/living/bot/medbot.dm +++ b/code/modules/mob/living/bot/medbot.dm @@ -169,7 +169,7 @@ O.loc = src reagent_glass = O user << "You insert [O]." - return + return 1 else ..() @@ -350,6 +350,7 @@ user << "You add the health sensor to [src]." name = "First aid/robot arm/health analyzer assembly" overlays += image('icons/obj/aibots.dmi', "na_scanner") + return 1 if(1) if(isprox(W)) @@ -362,3 +363,4 @@ S.name = created_name user.drop_from_inventory(src) qdel(src) + return 1 \ No newline at end of file diff --git a/code/modules/mob/living/bot/secbot.dm b/code/modules/mob/living/bot/secbot.dm index 6297657544d..feaf2743435 100644 --- a/code/modules/mob/living/bot/secbot.dm +++ b/code/modules/mob/living/bot/secbot.dm @@ -488,6 +488,7 @@ user << "You add the signaler to the helmet." user.drop_from_inventory(src) qdel(src) + return 1 else return @@ -508,6 +509,7 @@ build_step = 1 overlays += image('icons/obj/aibots.dmi', "hs_hole") user << "You weld a hole in \the [src]." + return 1 else if(isprox(O) && (build_step == 1)) user.drop_item() @@ -516,6 +518,7 @@ overlays += image('icons/obj/aibots.dmi', "hs_eye") name = "helmet/signaler/prox sensor assembly" qdel(O) + return 1 else if((istype(O, /obj/item/robot_parts/l_arm) || istype(O, /obj/item/robot_parts/r_arm)) && build_step == 2) user.drop_item() @@ -524,6 +527,7 @@ name = "helmet/signaler/prox sensor/robot arm assembly" overlays += image('icons/obj/aibots.dmi', "hs_arm") qdel(O) + return 1 else if(istype(O, /obj/item/weapon/melee/baton) && build_step == 3) user.drop_item() @@ -532,6 +536,7 @@ S.name = created_name qdel(O) qdel(src) + return 1 else if(istype(O, /obj/item/weapon/pen)) var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN) diff --git a/code/modules/mob/living/carbon/alien/diona/diona_attacks.dm b/code/modules/mob/living/carbon/alien/diona/diona_attacks.dm index 7289c96c3bc..fdf2004612c 100644 --- a/code/modules/mob/living/carbon/alien/diona/diona_attacks.dm +++ b/code/modules/mob/living/carbon/alien/diona/diona_attacks.dm @@ -12,5 +12,5 @@ var/mob/living/carbon/H = over_object if(!istype(H) || !Adjacent(H)) return ..() - get_scooped(H) + get_scooped(H, usr) return diff --git a/code/modules/mob/living/carbon/alien/emote.dm b/code/modules/mob/living/carbon/alien/emote.dm index b3b0ae53c18..fd29d52298d 100644 --- a/code/modules/mob/living/carbon/alien/emote.dm +++ b/code/modules/mob/living/carbon/alien/emote.dm @@ -18,8 +18,6 @@ if (client.prefs.muted & MUTE_IC) src << "\red You cannot send IC messages (muted)." return - if (src.client.handle_spam_prevention(message,MUTE_IC)) - return if (stat) return if(!(message)) @@ -127,4 +125,4 @@ for(var/mob/O in hearers(src, null)) O.show_message(message, m_type) //Foreach goto(746) - return \ No newline at end of file + return diff --git a/code/modules/mob/living/carbon/brain/emote.dm b/code/modules/mob/living/carbon/brain/emote.dm index 1995ff5e1cc..7e25c3be96f 100644 --- a/code/modules/mob/living/carbon/brain/emote.dm +++ b/code/modules/mob/living/carbon/brain/emote.dm @@ -19,8 +19,6 @@ if (client.prefs.muted & MUTE_IC) src << "\red You cannot send IC messages (muted)." return - if (src.client.handle_spam_prevention(message,MUTE_IC)) - return if (stat) return if(!(message)) @@ -79,4 +77,4 @@ O.show_message(message, m_type) else if (m_type & 2) for (var/mob/O in hearers(src.loc, null)) - O.show_message(message, m_type) \ No newline at end of file + O.show_message(message, m_type) diff --git a/code/modules/mob/living/carbon/human/appearance.dm b/code/modules/mob/living/carbon/human/appearance.dm index 13eaffc2c3e..24bb023090f 100644 --- a/code/modules/mob/living/carbon/human/appearance.dm +++ b/code/modules/mob/living/carbon/human/appearance.dm @@ -186,4 +186,4 @@ /mob/living/carbon/human/proc/force_update_limbs() for(var/obj/item/organ/external/O in organs) O.sync_colour_to_human(src) - update_body(0) + update_body(2)//Forces new icon generation diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 75126c16535..42ae4e86913 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -74,8 +74,6 @@ if (client.prefs.muted & MUTE_IC) src << "\red You cannot send IC messages (muted)." return - if (src.client.handle_spam_prevention(message,MUTE_IC)) - return if (stat) return if(!(message)) diff --git a/code/modules/mob/living/carbon/human/species/outsider/skeleton.dm b/code/modules/mob/living/carbon/human/species/outsider/skeleton.dm new file mode 100644 index 00000000000..956b2fb668f --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/outsider/skeleton.dm @@ -0,0 +1,56 @@ +/mob/living/carbon/human/skeleton/New(var/new_loc) + ..(new_loc, "Skeleton") + +/datum/species/skeleton //SPOOKY + name = "Skeleton" + name_plural = "skeletons" + + icobase = 'icons/mob/human_races/r_skeleton.dmi' + deform = 'icons/mob/human_races/r_skeleton.dmi' + + default_language = "Ceti Basic" + language = "Cult" + unarmed_types = list(/datum/unarmed_attack/claws/strong, /datum/unarmed_attack/bite/sharp) + darksight = 8 + has_organ = list() //skeletons are empty shells for now, maybe we can add something in the future + siemens_coefficient = 0 + ethanol_resistance = -1 //no drunk skeletons + + rarity_value = 2 + blurb = "Skeletons are undead brought back to life through dark wizardry, \ + they are empty shells fueled by sheer obscure power and blood-magic. \ + However, some men are cursed to carry such burden due to vile curses." + + warning_low_pressure = 50 //immune to pressure, so they can into space/survive breaches without worries + hazard_low_pressure = 0 + + cold_level_1 = 80 + cold_level_2 = 50 + cold_level_3 = 0 + + body_temperature = T0C //skeletons are cold + + blood_color = "#CCCCCC" + flesh_color = "#AAAAAA" + + death_message = "collapses, their bones clattering in a symphony of demise." + death_sound = 'sound/effects/falling_bones.ogg' + + breath_type = null + poison_type = null + + flags = IS_RESTRICTED | NO_BLOOD | NO_SCAN | NO_SLIP | NO_POISON | NO_PAIN | NO_BREATHE + + has_limbs = list( + "chest" = list("path" = /obj/item/organ/external/chest/skeleton), + "groin" = list("path" = /obj/item/organ/external/groin/skeleton), + "head" = list("path" = /obj/item/organ/external/head/skeleton), + "l_arm" = list("path" = /obj/item/organ/external/arm/skeleton), + "r_arm" = list("path" = /obj/item/organ/external/arm/right/skeleton), + "l_leg" = list("path" = /obj/item/organ/external/leg/skeleton), + "r_leg" = list("path" = /obj/item/organ/external/leg/right/skeleton), + "l_hand" = list("path" = /obj/item/organ/external/hand/skeleton), + "r_hand" = list("path" = /obj/item/organ/external/hand/right/skeleton), + "l_foot" = list("path" = /obj/item/organ/external/foot/skeleton), + "r_foot" = list("path" = /obj/item/organ/external/foot/right/skeleton) + ) diff --git a/code/modules/mob/living/carbon/human/species/station/station.dm b/code/modules/mob/living/carbon/human/species/station/station.dm index dddf682abd9..d5f09d21572 100644 --- a/code/modules/mob/living/carbon/human/species/station/station.dm +++ b/code/modules/mob/living/carbon/human/species/station/station.dm @@ -24,7 +24,7 @@ primitive_form = "Stok" darksight = 3 gluttonous = 1 - ethanol_resistance = 1.5 + ethanol_resistance = 0.4 blurb = "A heavily reptillian species, Unathi (or 'Sinta as they call themselves) hail from the \ Uuosa-Eso system, which roughly translates to 'burning mother'.

Coming from a harsh, radioactive \ diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index d5b3c6b57d2..f70a329f14e 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -225,8 +225,10 @@ var/global/list/damage_icon_parts = list() if(update_icons) update_icons() //BASE MOB SPRITE -/mob/living/carbon/human/proc/update_body(var/update_icons=1) +//Extension by Nanako +//Passing in a value of 2 for update_icons will ignore any cached icon, and force a new one to be generated +/mob/living/carbon/human/proc/update_body(var/update_icons=1) var/husk_color_mod = rgb(96,88,80) var/hulk_color_mod = rgb(48,224,40) @@ -234,7 +236,6 @@ var/global/list/damage_icon_parts = list() var/fat = (FAT in src.mutations) var/hulk = (HULK in src.mutations) var/skeleton = (SKELETON in src.mutations) - var/g = (gender == FEMALE ? "f" : "m") //CACHING: Generate an index key from visible bodyparts. @@ -268,9 +269,8 @@ var/global/list/damage_icon_parts = list() icon_key += "1" icon_key = "[icon_key][husk ? 1 : 0][fat ? 1 : 0][hulk ? 1 : 0][skeleton ? 1 : 0]" - var/icon/base_icon - if(human_icon_cache[icon_key]) + if(update_icons != 2 && human_icon_cache[icon_key])//If update_icons is 2, then we forcibly generate a new icon base_icon = human_icon_cache[icon_key] else //BEGIN CACHED ICON GENERATION. @@ -278,7 +278,7 @@ var/global/list/damage_icon_parts = list() base_icon = chest.get_icon() for(var/obj/item/organ/external/part in organs) - var/icon/temp = part.get_icon(skeleton) + var/icon/temp = part.get_icon(skeleton)//The color comes from this function //That part makes left and right legs drawn topmost and lowermost when human looks WEST or EAST //And no change in rendering for other parts (they icon_position is 0, so goes to 'else' part) if(part.icon_position&(LEFT|RIGHT)) diff --git a/code/modules/mob/living/carbon/metroid/emote.dm b/code/modules/mob/living/carbon/metroid/emote.dm index a6ea5498cde..e342c253983 100644 --- a/code/modules/mob/living/carbon/metroid/emote.dm +++ b/code/modules/mob/living/carbon/metroid/emote.dm @@ -18,8 +18,6 @@ if (client.prefs.muted & MUTE_IC) src << "\red You cannot send IC messages (muted)." return - if (src.client.handle_spam_prevention(message,MUTE_IC)) - return if (stat) return if(!(message)) @@ -98,4 +96,4 @@ O.show_message(message, m_type) if(updateicon) regenerate_icons() - return \ No newline at end of file + return diff --git a/code/modules/mob/living/parasite/meme_captive.dm b/code/modules/mob/living/parasite/meme_captive.dm index a0ce61b761b..42a452a7f05 100644 --- a/code/modules/mob/living/parasite/meme_captive.dm +++ b/code/modules/mob/living/parasite/meme_captive.dm @@ -9,8 +9,6 @@ if(client.prefs.muted & MUTE_IC) src << "\red You cannot speak in IC (muted)." return - if (src.client.handle_spam_prevention(message,MUTE_IC)) - return if(istype(src.loc,/mob/living/parasite/meme)) @@ -32,4 +30,4 @@ M << "The captive mind of [src] whispers, \"[message]\"" /mob/living/parasite/captive_brain/emote(var/message) - return \ No newline at end of file + return diff --git a/code/modules/mob/living/silicon/pai/emote.dm b/code/modules/mob/living/silicon/pai/emote.dm index d4ee8975d8b..7cecb30b636 100644 --- a/code/modules/mob/living/silicon/pai/emote.dm +++ b/code/modules/mob/living/silicon/pai/emote.dm @@ -13,8 +13,6 @@ if(client.prefs.muted & MUTE_IC) src << "You cannot send IC messages (muted)." return - if (src.client.handle_spam_prevention(message,MUTE_IC)) - return if (stat) return if(!(message)) diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 1209d81cae8..23de05af75e 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -70,6 +70,7 @@ var/translator_on = 0 // keeps track of the translator module + var/greeted = 0 var/current_pda_messaging = null /mob/living/silicon/pai/New(var/obj/item/device/paicard/newlocation) @@ -109,9 +110,18 @@ ..() /mob/living/silicon/pai/Login() + greet() ..() +/mob/living/silicon/pai/proc/greet() + + if (!greeted) + // Basic intro text. + src << "You are a Personal AI!" + src << "You are a small artificial intelligence contained inside a portable tablet, and you are bound to a master. Your primary directive is to serve them and follow their instructions, follow this prime directive above all others. Check your Software interface to spend ram on programs that can help, and unfold your chassis to take a holographic form and move around the world." + greeted = 1 + // this function shows the information about being silenced as a pAI in the Status panel /mob/living/silicon/pai/proc/show_silenced() if(src.silence_time) diff --git a/code/modules/mob/living/silicon/pai/personality.dm b/code/modules/mob/living/silicon/pai/personality.dm index c4928878ce9..e3b439afcde 100644 --- a/code/modules/mob/living/silicon/pai/personality.dm +++ b/code/modules/mob/living/silicon/pai/personality.dm @@ -27,7 +27,7 @@ return 1 // loads the savefile corresponding to the mob's ckey -// if silent=true, report incompatible savefiles +// if silent=false, report incompatible savefiles // returns 1 if loaded (or file was incompatible) // returns 0 if savefile did not exist diff --git a/code/modules/mob/living/silicon/pai/recruit.dm b/code/modules/mob/living/silicon/pai/recruit.dm index 91a10bf3e50..291a47a1f91 100644 --- a/code/modules/mob/living/silicon/pai/recruit.dm +++ b/code/modules/mob/living/silicon/pai/recruit.dm @@ -29,6 +29,9 @@ var/datum/paiController/paiController // Global handler for pAI candidates if(href_list["download"]) var/datum/paiCandidate/candidate = locate(href_list["candidate"]) var/obj/item/device/paicard/card = locate(href_list["device"]) + if (!candidate in pai_candidates) + return + if(card.pai) return if(istype(card,/obj/item/device/paicard) && istype(candidate,/datum/paiCandidate)) @@ -107,6 +110,7 @@ var/datum/paiController/paiController // Global handler for pAI candidates candidate.key = M.key pai_candidates.Add(candidate) + candidate.savefile_load(M)//Load the pAI config before displaying the window var/dat = "" dat += {"