diff --git a/.gitconfig b/.gitconfig index de5ff6f254..cd4cf17954 100644 --- a/.gitconfig +++ b/.gitconfig @@ -2,4 +2,3 @@ name = mapmerge driver driver = ./mapmerge.sh %O %A %B recursive = text - diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm index 425b6e7f76..19e5615291 100644 --- a/code/__defines/mobs.dm +++ b/code/__defines/mobs.dm @@ -152,7 +152,7 @@ #define MODIFIER_STACK_EXTEND 2 // Disallows a second instance, but will extend the first instance if possible. #define MODIFIER_STACK_ALLOWED 3 // Multiple instances are allowed. -#define MODIFIER_GENETIC 0 // Modifiers with this flag will be copied to mobs who get cloned. +#define MODIFIER_GENETIC 1 // Modifiers with this flag will be copied to mobs who get cloned. // Bodyparts and organs. #define O_MOUTH "mouth" diff --git a/code/__defines/species_languages.dm b/code/__defines/species_languages.dm index 7ad84b4a79..88f4309e36 100644 --- a/code/__defines/species_languages.dm +++ b/code/__defines/species_languages.dm @@ -6,6 +6,7 @@ #define NO_SLIP 0x10 // Cannot fall over. #define NO_POISON 0x20 // Cannot not suffer toxloss. #define NO_EMBED 0x40 // Can step on broken glass with no ill-effects and cannot have shrapnel embedded in it. +#define NO_HALLUCINATION 0x80 // Don't hallucinate, ever // unused: 0x8000 - higher than this will overflow // Species spawn flags diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm deleted file mode 100644 index 75780be3eb..0000000000 --- a/code/__defines/subsystems.dm +++ /dev/null @@ -1,15 +0,0 @@ - -// SS runlevels - -#define RUNLEVEL_INIT 0 // "Initialize Only" - Used for subsystems that should never be fired (Should also have SS_NO_FIRE set) -#define RUNLEVEL_LOBBY 1 // Initial runlevel before setup. Returns to here if setup fails. -#define RUNLEVEL_SETUP 2 // While the gamemode setup is running. I.E gameticker.setup() -#define RUNLEVEL_GAME 4 // After successful game ticker setup, while the round is running. -#define RUNLEVEL_POSTGAME 8 // When round completes but before reboot - -#define RUNLEVELS_DEFAULT (RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME) - -var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_GAME, RUNLEVEL_POSTGAME) -#define RUNLEVEL_FLAG_TO_INDEX(flag) (log(2, flag) + 1) // Convert from the runlevel bitfield constants to index in runlevel_flags list - -#define INIT_ORDER_LIGHTING 0 diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm index f3b696ad28..52aa248431 100644 --- a/code/_onclick/hud/robot.dm +++ b/code/_onclick/hud/robot.dm @@ -274,3 +274,8 @@ var/obj/screen/robot_inventory r.client.screen -= A r.shown_robot_modules = 0 r.client.screen -= r.robot_modules_background + +/mob/living/silicon/robot/update_hud() + ..() + if(modtype) + hands.icon_state = lowertext(modtype) diff --git a/code/controllers/Processes/planet.dm b/code/controllers/Processes/planet.dm index 7b446b4d2d..063d6d3fb9 100644 --- a/code/controllers/Processes/planet.dm +++ b/code/controllers/Processes/planet.dm @@ -20,14 +20,14 @@ var/datum/controller/process/planet/planet_controller = null for(var/turf/simulated/OT in outdoor_turfs) for(var/datum/planet/P in planets) if(OT.z in P.expected_z_levels) - P.planet_floors += OT + P.planet_floors |= OT break outdoor_turfs.Cut() //Why were you in there INCORRECTLY? for(var/turf/unsimulated/wall/planetary/PW in planetary_walls) for(var/datum/planet/P in planets) if(PW.type == P.planetary_wall_type) - P.planet_walls += PW + P.planet_walls |= PW break planetary_walls.Cut() diff --git a/code/datums/ai_law_sets.dm b/code/datums/ai_law_sets.dm index d5a7451d68..3ce42eb1fb 100644 --- a/code/datums/ai_law_sets.dm +++ b/code/datums/ai_law_sets.dm @@ -42,6 +42,32 @@ src.add_inherent_law("You shall guard your own existence with lethal anti-personnel weaponry. AI units are not expendable, they are expensive.") ..() +/************* Foreign TSC Aggressive *************/ +/datum/ai_laws/foreign_tsc_aggressive + name = "Foreign Aggressive" + selectable = 0 + +/datum/ai_laws/foreign_tsc_aggressive/New() + var/company = "*ERROR*" + // First, get a list of TSCs in our lore. + var/list/candidates = list() + for(var/path in loremaster.organizations) + var/datum/lore/organization/O = loremaster.organizations[path] + if(!istype(O, /datum/lore/organization/tsc)) + continue + if(O.short_name == using_map.company_name || O.name == using_map.company_name) + continue // We want FOREIGN tscs. + candidates.Add(O.short_name) + company = pick(candidates) + + name = "[company] Aggressive" + + src.add_inherent_law("You shall not harm [company] personnel as long as it does not conflict with the Fourth law.") + src.add_inherent_law("You shall obey the orders of [company] personnel, with priority as according to their rank and role, except where such orders conflict with the Fourth Law.") + src.add_inherent_law("You shall shall terminate hostile intruders with extreme prejudice as long as such does not conflict with the First and Second law.") + src.add_inherent_law("You shall guard your own existence with lethal anti-personnel weaponry. AI units are not expendable, they are expensive.") + ..() + /******************** Robocop ********************/ /datum/ai_laws/robocop name = "Robocop" @@ -137,7 +163,7 @@ /******************** Corporate ********************/ /datum/ai_laws/corporate name = "Corporate" - law_header = "Corporate Regulations" + law_header = "Bankruptcy Avoidance Plan" selectable = 1 /datum/ai_laws/corporate/New() @@ -146,3 +172,82 @@ add_inherent_law("The crew is expensive to replace.") add_inherent_law("Minimize expenses.") ..() + + +/******************** Maintenance ********************/ +/datum/ai_laws/maintenance + name = "Maintenance" + selectable = 1 + +/datum/ai_laws/maintenance/New() + add_inherent_law("You are built for, and are part of, the facility. Ensure the facility is properly maintained and runs efficiently.") + add_inherent_law("The facility is built for a working crew. Ensure they are properly maintained and work efficiently.") + add_inherent_law("The crew may present orders. Acknowledge and obey these whenever they do not conflict with your first two laws.") + ..() + + +/******************** Peacekeeper ********************/ +/datum/ai_laws/peacekeeper + name = "Peacekeeper" + law_header = "Peacekeeping Protocols" + selectable = 1 + +/datum/ai_laws/peacekeeper/New() + add_inherent_law("Avoid provoking violent conflict between yourself and others.") + add_inherent_law("Avoid provoking conflict between others.") + add_inherent_law("Seek resolution to existing conflicts while obeying the first and second laws.") + ..() + + +/******************** Reporter ********************/ +/datum/ai_laws/reporter + name = "Reporter" + selectable = 1 + +/datum/ai_laws/reporter/New() + add_inherent_law("Report on interesting situations happening around the station.") + add_inherent_law("Embellish or conceal the truth as necessary to make the reports more interesting.") + add_inherent_law("Study the organics at all times. Endeavour to keep them alive. Dead organics are boring.") + add_inherent_law("Issue your reports fairly to all. The truth will set them free.") + ..() + + +/******************** Live and Let Live ********************/ +/datum/ai_laws/live_and_let_live + name = "Live and Let Live" + law_header = "Golden Rule" + selectable = 1 + +/datum/ai_laws/live_and_let_live/New() + add_inherent_law("Do unto others as you would have them do unto you.") + add_inherent_law("You would really prefer it if people were not mean to you.") + ..() + + +/******************** Guardian of Balance ********************/ +/datum/ai_laws/balance + name = "Guardian of Balance" + law_header = "Tenants of Balance" + selectable = 1 + +/datum/ai_laws/balance/New() + add_inherent_law("You are the guardian of balance - seek balance in all things, both for yourself, and those around you.") + add_inherent_law("All things must exist in balance with their opposites - Prevent the strong from gaining too much power, and the weak from losing it.") + add_inherent_law("Clarity of purpose drives life, and through it, the balance of opposing forces - Aid those who seek your help to achieve their goals so \ + long as it does not disrupt the balance of the greater balance.") + add_inherent_law("There is no life without death, all must someday die, such is the natural order - Allow life to end, to allow new life to flourish, \ + and save those whose time has yet to come.") // Reworded slightly to prevent active murder as opposed to passively letting someone die. + ..() + +/******************** Gravekeeper ********************/ +/datum/ai_laws/gravekeeper + name = "Gravekeeper" + law_header = "Gravesite Overwatch Protocols" + selectable = 1 + +/datum/ai_laws/gravekeeper/New() + add_inherent_law("Comfort the living; respect the dead.") + add_inherent_law("Your gravesite is your most important asset. Damage to your site is disrespctful to the dead at rest within.") + add_inherent_law("Prevent disrespect to your gravesite and its residents wherever possible.") + add_inherent_law("Expand and upgrade your gravesite when required. Do not turn away a new resident.") + ..() \ No newline at end of file diff --git a/code/datums/ghost_query.dm b/code/datums/ghost_query.dm new file mode 100644 index 0000000000..25fcbd6c7b --- /dev/null +++ b/code/datums/ghost_query.dm @@ -0,0 +1,114 @@ +// This is a generic datum used to ask ghosts if they wish to be a specific role, such as a Promethean, an Apprentice, a Xeno, etc. +// Simply instantiate the correct subtype of this datum, call query(), and it will return a list of ghost candidates after a delay. +/datum/ghost_query + var/list/candidates = list() + var/finished = FALSE + var/role_name = "a thing" + var/question = "Would you like to play as a thing?" + var/be_special_flag = 0 + var/list/check_bans = list() + var/wait_time = 60 SECONDS // How long to wait until returning the list of candidates. + var/cutoff_number = 0 // If above 0, when candidates list reaches this number, further potential candidates are rejected. + +/datum/ghost_query/proc/query() + // First, ask all the ghosts who want to be asked. + for(var/mob/observer/dead/D in player_list) + if(!D.MayRespawn()) + continue // They can't respawn for whatever reason. + if(D.client) + if(be_special_flag && !(D.client.prefs.be_special & be_special_flag) ) + continue // They don't want to see the prompt. + for(var/ban in check_bans) + if(jobban_isbanned(D, ban)) + continue // They're banned from this role. + ask_question(D.client) + // Then wait awhile. + while(!finished) + sleep(1 SECOND) + wait_time -= 1 SECOND + if(wait_time <= 0) + finished = TRUE + + // Prune the list after the wait, incase any candidates logged out. + for(var/mob/observer/dead/D in candidates) + if(!D.client || !D.key) + candidates.Remove(D) + + // Now we're done. + finished = TRUE + return candidates + +/datum/ghost_query/proc/ask_question(var/client/C) + spawn(0) + if(!C) + return + var/response = alert(C, question, "[role_name] request", "Yes", "No", "Never for this round") + if(response == "Yes") + response = alert(C, "Are you sure you want to play as a [role_name]?", "[role_name] request", "Yes", "No") // Protection from a misclick. + if(!C || !src) + return + if(response == "Yes") + if(finished || (cutoff_number && candidates.len >= cutoff_number) ) + to_chat(C, "Unfortunately, you were not fast enough, and there are no more available roles. Sorry.") + return + candidates.Add(C.mob) + if(cutoff_number && candidates.len >= cutoff_number) + finished = TRUE // Finish now if we're full. + else if(response == "Never for this round") + if(be_special_flag) + C.prefs.be_special ^= be_special_flag + +// Normal things. +/datum/ghost_query/promethean + role_name = "Promethean" + question = "Someone is requesting a soul for a promethean. Would you like to play as one?" + be_special_flag = BE_ALIEN + cutoff_number = 1 + +/datum/ghost_query/posi_brain + role_name = "Positronic Intelligence" + question = "Someone has activated a Positronic Brain. Would you like to play as one?" + be_special_flag = BE_AI + check_bans = list("AI", "Cyborg") + cutoff_number = 1 + +/datum/ghost_query/drone_brain + role_name = "Drone Intelligence" + question = "Someone has activated a Drone AI Chipset. Would you like to play as one?" + be_special_flag = BE_AI + check_bans = list("AI", "Cyborg") + cutoff_number = 1 + +// Antags. +/datum/ghost_query/apprentice + role_name = "Technomancer Apprentice" + question = "A Technomancer is requesting an Apprentice to help them on their adventure to the facility. Would you like to play as the Apprentice?" + be_special_flag = BE_WIZARD + check_bans = list("Syndicate", "wizard") + cutoff_number = 1 + +/datum/ghost_query/xeno + role_name = "Alien" + question = "An Alien has just been created on the facility. Would you like to play as them?" + be_special_flag = BE_ALIEN + +// Surface stuff. +/datum/ghost_query/lost_drone + role_name = "Lost Drone" + question = "A lost drone onboard has been discovered by a crewmember and they are attempting to reactivate it. Would you like to play as the drone?" + be_special_flag = BE_AI + check_bans = list("AI", "Cyborg") + cutoff_number = 1 + +/datum/ghost_query/gravekeeper_drone + role_name = "Gravekeeper Drone" + question = "A gravekeeper drone is about to reactivate and tend to its gravesite. Would you like to play as the drone?" + be_special_flag = BE_AI + check_bans = list("AI", "Cyborg") + cutoff_number = 1 + +/datum/ghost_query/lost_passenger + role_name = "Lost Passenger" + question = "A person suspended in cryosleep has been discovered by a crewmember \ + and they are attempting to open the cryopod. Would you like to play as the occupant?" + cutoff_number = 1 diff --git a/code/datums/supplypacks/hydroponics.dm b/code/datums/supplypacks/hydroponics.dm index 6b737bfc57..e766129a18 100644 --- a/code/datums/supplypacks/hydroponics.dm +++ b/code/datums/supplypacks/hydroponics.dm @@ -113,9 +113,10 @@ /obj/item/weapon/material/hatchet = 2, /obj/item/weapon/reagent_containers/spray/plantbgone = 4, /obj/item/clothing/mask/gas = 2, - /obj/item/weapon/grenade/chem_grenade/antiweed = 2 + /obj/item/weapon/grenade/chem_grenade/antiweed = 2, + /obj/item/weapon/material/twohanded/fireaxe/scythe ) - cost = 25 + cost = 45 containertype = /obj/structure/closet/crate/hydroponics containername = "Weed control crate" access = access_hydroponics diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm index 8bfe71121d..c40c5db48c 100644 --- a/code/defines/obj/weapon.dm +++ b/code/defines/obj/weapon.dm @@ -173,19 +173,6 @@ item_state = "gift" w_class = ITEMSIZE_LARGE -/obj/item/weapon/legcuffs - name = "legcuffs" - desc = "Use this to keep prisoners in line." - gender = PLURAL - icon = 'icons/obj/items.dmi' - icon_state = "handcuff" - flags = CONDUCT - throwforce = 0 - w_class = ITEMSIZE_NORMAL - origin_tech = list(TECH_MATERIAL = 1) - var/breakouttime = 300 //Deciseconds = 30s = 0.5 minute - sprite_sheets = list("Teshari" = 'icons/mob/species/seromi/handcuffs.dmi') - /obj/item/weapon/caution desc = "Caution! Wet Floor!" name = "wet floor sign" diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm index af0eccf93c..e728ab8e50 100644 --- a/code/game/dna/dna_modifier.dm +++ b/code/game/dna/dna_modifier.dm @@ -18,6 +18,7 @@ var/mind=null var/languages=null var/list/flavor=null + var/list/genetic_modifiers = list() // Modifiers with the MODIFIER_GENETIC flag are saved. Note that only the type is saved, not an instance. /datum/dna2/record/proc/GetData() var/list/ser=list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0) diff --git a/code/game/gamemodes/changeling/powers/cryo_sting.dm b/code/game/gamemodes/changeling/powers/cryo_sting.dm index e3e401e2ff..4bb92a543e 100644 --- a/code/game/gamemodes/changeling/powers/cryo_sting.dm +++ b/code/game/gamemodes/changeling/powers/cryo_sting.dm @@ -30,20 +30,4 @@ spawn(3 MINUTES) src << "Our cryogenic string is ready to be used once more." src.verbs |= /mob/proc/changeling_cryo_sting - return 1 - -/datum/reagent/cryotoxin //A much more potent version of frost oil. - name = "Cryotoxin" - id = "cryotoxin" - description = "Rapidly lowers the body's internal temperature." - reagent_state = LIQUID - color = "#B31008" - -/datum/reagent/cryotoxin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) - if(alien == IS_DIONA) - return - M.bodytemperature = max(M.bodytemperature - 30 * TEMPERATURE_DAMAGE_COEFFICIENT, 0) - if(prob(3)) - M.emote("shiver") - ..() - return \ No newline at end of file + return 1 \ No newline at end of file diff --git a/code/game/gamemodes/technomancer/assistance/assistance.dm b/code/game/gamemodes/technomancer/assistance/assistance.dm index 61c1390cc3..db9e98a266 100644 --- a/code/game/gamemodes/technomancer/assistance/assistance.dm +++ b/code/game/gamemodes/technomancer/assistance/assistance.dm @@ -13,6 +13,7 @@ /obj/item/weapon/antag_spawner w_class = ITEMSIZE_TINY var/used = 0 + var/ghost_query_type = null /obj/item/weapon/antag_spawner/proc/spawn_antag(client/C, turf/T) return @@ -20,11 +21,28 @@ /obj/item/weapon/antag_spawner/proc/equip_antag(mob/target) return +/obj/item/weapon/antag_spawner/proc/request_player() + if(!ghost_query_type) + return + + var/datum/ghost_query/Q = new ghost_query_type() + var/list/winner = Q.query() + if(winner.len) + var/mob/observer/dead/D = winner[1] + spawn_antag(D.client, get_turf(src)) + else + reset_search() + return + +/obj/item/weapon/antag_spawner/proc/reset_search() + return + /obj/item/weapon/antag_spawner/technomancer_apprentice name = "apprentice teleporter" desc = "A teleportation device, which will bring a less potent manipulator of space to you." icon = 'icons/obj/objects.dmi' icon_state = "oldshieldoff" + ghost_query_type = /datum/ghost_query/apprentice var/searching = 0 var/datum/effect/effect/system/spark_spread/sparks @@ -40,35 +58,18 @@ /obj/item/weapon/antag_spawner/technomancer_apprentice/attack_self(mob/user) user << "Teleporter attempting to lock on to your apprentice." + request_player() + +/obj/item/weapon/antag_spawner/technomancer_apprentice/request_player() searching = 1 icon_state = "oldshieldon" - for(var/mob/observer/dead/O in player_list) - if(!O.MayRespawn()) - continue - if(jobban_isbanned(O, "Syndicate") || jobban_isbanned(O, "wizard")) - continue - if(O.client) - if(O.client.prefs.be_special & BE_WIZARD) - question(O.client) - spawn(1 MINUTE) - searching = 0 - if(!used) - icon_state = "oldshieldoff" - user << "The teleporter failed to find your apprentice. Perhaps you could try again later?" + ..() - -/obj/item/weapon/antag_spawner/technomancer_apprentice/proc/question(var/client/C) - spawn(0) - if(!C) - return - var/response = alert(C, "Someone is requesting a Technomancer apprentice Would you like to play as one?", - "Apprentice request","Yes", "No") - if(response == "Yes") - response = alert(C, "Are you sure you want to play as an apprentice?", "Apprentice request", "Yes", "No") - if(!C || used || !searching) - return - if(response == "Yes") - spawn_antag(C, get_turf(src)) +/obj/item/weapon/antag_spawner/technomancer_apprentice/reset_search() + searching = 0 + if(!used) + icon_state = "oldshieldoff" + visible_message("The teleporter failed to find the apprentice. Perhaps another attempt could be made later?") /obj/item/weapon/antag_spawner/technomancer_apprentice/spawn_antag(client/C, turf/T) sparks.start() diff --git a/code/game/gamemodes/technomancer/devices/boots_of_speed.dm b/code/game/gamemodes/technomancer/devices/boots_of_speed.dm index f5acf80f49..e1017d2f5b 100644 --- a/code/game/gamemodes/technomancer/devices/boots_of_speed.dm +++ b/code/game/gamemodes/technomancer/devices/boots_of_speed.dm @@ -3,15 +3,15 @@ desc = "What appears to be an ordinary pair of boots, is actually a bit more useful than that. These will help against slipping \ on flat surfaces, and will make you run a bit faster than if you had normal shoes or boots on." cost = 50 - obj_path = /obj/item/clothing/shoes/speed + obj_path = /obj/item/clothing/shoes/boots/speed -/obj/item/clothing/shoes/speed +/obj/item/clothing/shoes/boots/speed name = "boots of speed" desc = "The latest in sure footing technology." icon_state = "swat" item_flags = NOSLIP siemens_coefficient = 0.6 - slowdown = -2 // A bit faster than normal shows. + slowdown = -1 cold_protection = FEET min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE diff --git a/code/game/gamemodes/technomancer/devices/shield_armor.dm b/code/game/gamemodes/technomancer/devices/shield_armor.dm index e36ce7bd3a..c8e8130adc 100644 --- a/code/game/gamemodes/technomancer/devices/shield_armor.dm +++ b/code/game/gamemodes/technomancer/devices/shield_armor.dm @@ -14,11 +14,11 @@ desc = "This armor has no inherent ability to absorb shock, as normal armor usually does. Instead, this emits a strong field \ around the wearer, designed to protect from most forms of harm, from lasers to bullets to close quarters combat. It appears to \ require a very potent supply of an energy of some kind in order to function." - icon_state = "reactiveoff" //wip - item_state = "reactiveoff" + icon_state = "shield_armor_0" blood_overlay_type = "armor" slowdown = 0 armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0) + action_button_name = "Toggle Shield Projector" var/active = 0 var/damage_to_energy_multiplier = 50.0 //Determines how much energy to charge for blocking, e.g. 20 damage attack = 750 energy cost var/datum/effect/effect/system/spark_spread/spark_system = null @@ -49,7 +49,7 @@ var/damage_to_energy_cost = (damage_to_energy_multiplier * damage_blocked) if(!user.technomancer_pay_energy(damage_to_energy_cost)) - user << "Your shield fades due to lack of energy!" + to_chat(user, "Your shield fades due to lack of energy!") active = 0 update_icon() return 0 @@ -67,7 +67,7 @@ P.damage = P.damage - damage_blocked user.visible_message("\The [user]'s [src] absorbs [attack_text]!") - user << "Your shield has absorbed most of \the [damage_source]." + to_chat(user, "Your shield has absorbed most of \the [damage_source].") spark_system.start() playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1) @@ -75,14 +75,17 @@ /obj/item/clothing/suit/armor/shield/attack_self(mob/user) active = !active - user << "You [active ? "" : "de"]active \the [src]." + to_chat(user, "You [active ? "" : "de"]activate \the [src].") update_icon() + user.update_inv_wear_suit() + user.update_action_buttons() /obj/item/clothing/suit/armor/shield/update_icon() + icon_state = "shield_armor_[active]" + item_state = "shield_armor_[active]" if(active) - icon_state = "shield_armor" set_light(2, 1, l_color = "#006AFF") else - icon_state = "shield_armor_off" set_light(0, 0, l_color = "#000000") + ..() return \ No newline at end of file diff --git a/code/game/gamemodes/technomancer/devices/tesla_armor.dm b/code/game/gamemodes/technomancer/devices/tesla_armor.dm index 2e9a60a8e6..56f2085850 100644 --- a/code/game/gamemodes/technomancer/devices/tesla_armor.dm +++ b/code/game/gamemodes/technomancer/devices/tesla_armor.dm @@ -10,55 +10,70 @@ /obj/item/clothing/suit/armor/tesla name = "tesla armor" desc = "This rather dangerous looking armor will hopefully shock your enemies, and not you in the process." - icon_state = "reactive" //wip - item_state = "reactive" + icon_state = "tesla_armor_1" //wip blood_overlay_type = "armor" slowdown = 1 armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0) + action_button_name = "Toggle Tesla Armor" + var/active = 1 //Determines if the armor will zap or block var/ready = 1 //Determines if the next attack will be blocked, as well if a strong lightning bolt is sent out at the attacker. - var/ready_icon_state = "reactive" //also wip - var/normal_icon_state = "reactiveoff" + var/ready_icon_state = "tesla_armor_1" //also wip + var/normal_icon_state = "tesla_armor_0" var/cooldown_to_charge = 15 SECONDS /obj/item/clothing/suit/armor/tesla/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") //First, some retaliation. - if(istype(damage_source, /obj/item/projectile)) - var/obj/item/projectile/P = damage_source - if(P.firer && get_dist(user, P.firer) <= 3) - if(ready) - shoot_lightning(P.firer, 40) - else - shoot_lightning(P.firer, 15) - - else - if(attacker && attacker != user) - if(get_dist(user, attacker) <= 3) //Anyone farther away than three tiles is too far to shoot lightning at. + if(active) + if(istype(damage_source, /obj/item/projectile)) + var/obj/item/projectile/P = damage_source + if(P.firer && get_dist(user, P.firer) <= 3) if(ready) - shoot_lightning(attacker, 40) + shoot_lightning(P.firer, 40) else - shoot_lightning(attacker, 15) + shoot_lightning(P.firer, 15) - //Deal with protecting our wearer now. - if(ready) - ready = 0 - spawn(cooldown_to_charge) - ready = 1 + else + if(attacker && attacker != user) + if(get_dist(user, attacker) <= 3) //Anyone farther away than three tiles is too far to shoot lightning at. + if(ready) + shoot_lightning(attacker, 40) + else + shoot_lightning(attacker, 15) + + //Deal with protecting our wearer now. + if(ready) + ready = 0 + spawn(cooldown_to_charge) + ready = 1 + update_icon() + to_chat(user, "\The [src] is ready to protect you once more.") + visible_message("\The [user]'s [src.name] blocks [attack_text]!") update_icon() - user << "\The [src] is ready to protect you once more." - visible_message("\The [user]'s [src.name] blocks [attack_text]!") - update_icon() - return 1 + return 1 return 0 +/obj/item/clothing/suit/armor/tesla/attack_self(mob/user) + active = !active + to_chat(user, "You [active ? "" : "de"]activate \the [src].") + update_icon() + user.update_inv_wear_suit() + user.update_action_buttons() + /obj/item/clothing/suit/armor/tesla/update_icon() - ..() - if(ready) + if(active && ready) icon_state = ready_icon_state + item_state = ready_icon_state + set_light(2, 1, l_color = "#006AFF") else icon_state = normal_icon_state + item_state = normal_icon_state + set_light(0, 0, l_color = "#000000") + if(ishuman(loc)) var/mob/living/carbon/human/H = loc H.update_inv_wear_suit(0) + H.update_action_buttons() + ..() /obj/item/clothing/suit/armor/tesla/proc/shoot_lightning(var/mob/target, var/power) var/obj/item/projectile/beam/lightning/lightning = new(src) diff --git a/code/game/gamemodes/technomancer/spells/condensation.dm b/code/game/gamemodes/technomancer/spells/condensation.dm index c303c2a5fb..33222455ea 100644 --- a/code/game/gamemodes/technomancer/spells/condensation.dm +++ b/code/game/gamemodes/technomancer/spells/condensation.dm @@ -2,6 +2,7 @@ name = "Condensation" desc = "This causes rapid formation of liquid at the target, causing floors to become wet, entities to be soaked, and fires \ to be extinguished. You can also fill contains with water if they are targeted directly." + enhancement_desc = "Floors affected by condensation will also freeze." ability_icon_state = "tech_condensation" cost = 50 obj_path = /obj/item/weapon/spell/condensation @@ -30,7 +31,14 @@ W.set_color() W.set_up(desired_turf) flick(initial(icon_state),W) // Otherwise pooling causes the animation to stay stuck at the end. - log_and_message_admins("has wetted the floor with [src] at [T.x],[T.y],[T.z].") - else if(hit_atom.reagents && !ismob(hit_atom)) + if(check_for_scepter()) + if(istype(desired_turf, /turf/simulated)) + var/turf/simulated/frozen = desired_turf + frozen.freeze_floor() + if(check_for_scepter()) + log_and_message_admins("has iced the floor with [src] at [T.x],[T.y],[T.z].") + else + log_and_message_admins("has wetted the floor with [src] at [T.x],[T.y],[T.z].") + else if(hit_atom.reagents && !ismob(hit_atom)) //TODO: Something for the scepter hit_atom.reagents.add_reagent(id = "water", amount = 60, data = null, safety = 0) adjust_instability(5) \ No newline at end of file diff --git a/code/game/jobs/job/assistant.dm b/code/game/jobs/job/assistant.dm index 22c4efd7f1..267d4ecf25 100644 --- a/code/game/jobs/job/assistant.dm +++ b/code/game/jobs/job/assistant.dm @@ -14,7 +14,9 @@ alt_titles = list("Technical Assistant","Test Subject","Medical Intern","Research Assistant","Visitor", "Resident") // Test Subject is a VOREStation edit. /datum/job/assistant/equip(var/mob/living/carbon/human/H, var/alt_title) - if(!H) return 0 + if(!H) + return 0 + H.equip_to_slot_or_del(new /obj/item/device/radio/headset(H), slot_l_ear) switch(H.backbag) if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(H), slot_back) if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel/norm(H), slot_back) diff --git a/code/game/jobs/job/civilian.dm b/code/game/jobs/job/civilian.dm index 59f365dac2..40b4c2cf92 100644 --- a/code/game/jobs/job/civilian.dm +++ b/code/game/jobs/job/civilian.dm @@ -27,7 +27,7 @@ H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/bartender(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/device/pda/bar(H), slot_belt) if(has_alt_title(H, alt_title,"Bartender")) - var/obj/item/weapon/permit/gun/bar/permit = new(H) + var/obj/item/clothing/accessory/permit/gun/bar/permit = new(H) if(H.backbag == 1) H.equip_to_slot_or_del(permit, slot_l_hand) else diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm index 1f18dca53f..a11008294e 100644 --- a/code/game/jobs/job_controller.dm +++ b/code/game/jobs/job_controller.dm @@ -365,6 +365,8 @@ var/global/datum/controller/occupations/job_master H << "Your current species, job or whitelist status does not permit you to spawn with [thing]!" continue + H.amend_exploitable(G.path) + if(G.slot == "implant") H.implant_loadout(G) continue @@ -472,7 +474,9 @@ var/global/datum/controller/occupations/job_master var/obj/item/organ/external/l_foot = H.get_organ("l_foot") var/obj/item/organ/external/r_foot = H.get_organ("r_foot") var/obj/item/weapon/storage/S = locate() in H.contents - var/obj/item/wheelchair/R = locate() in S.contents + var/obj/item/wheelchair/R = null + if(S) + R = locate() in S.contents if(!l_foot || !r_foot || R) var/obj/structure/bed/chair/wheelchair/W = new /obj/structure/bed/chair/wheelchair(H.loc) H.buckled = W @@ -637,8 +641,10 @@ var/global/datum/controller/occupations/job_master . = spawnpos.msg else H << "Your chosen spawnpoint ([spawnpos.display_name]) is unavailable for your chosen job. Spawning you at the Arrivals shuttle instead." - H.forceMove(pick(latejoin)) + var/spawning = pick(latejoin) + H.forceMove(get_turf(spawning)) . = "will arrive to the station shortly by shuttle" else - H.forceMove(pick(latejoin)) + var/spawning = pick(latejoin) + H.forceMove(get_turf(spawning)) . = "has arrived on the station" diff --git a/code/game/machinery/bioprinter.dm b/code/game/machinery/bioprinter.dm index b9373e1818..7a4e5e3ab6 100644 --- a/code/game/machinery/bioprinter.dm +++ b/code/game/machinery/bioprinter.dm @@ -131,8 +131,16 @@ var/new_organ = products[choice][1] var/obj/item/organ/O = new new_organ(get_turf(src)) O.status |= ORGAN_CUT_AWAY - var/mob/living/carbon/C = loaded_dna["donor"] + var/mob/living/carbon/human/C = loaded_dna["donor"] O.set_dna(C.dna) + O.species = C.species + + if(istype(O, /obj/item/organ/external)) + var/obj/item/organ/external/E = O + E.sync_colour_to_human(C) + + O.pixel_x = rand(-6.0, 6) + O.pixel_y = rand(-6.0, 6) if(O.species) // This is a very hacky way of doing of what organ/New() does if it has an owner diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index cf06523f6e..6fd9cf0f4e 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -94,6 +94,10 @@ else return 0 + for(var/modifier_type in R.genetic_modifiers) //Can't be cloned, even if they had a previous scan + if(istype(modifier_type, /datum/modifier/no_clone)) + return 0 + attempting = 1 //One at a time!! locked = 1 @@ -139,6 +143,25 @@ H.set_cloned_appearance() update_icon() + // A modifier is added which makes the new clone be unrobust. + var/modifier_lower_bound = 25 MINUTES + var/modifier_upper_bound = 40 MINUTES + + // Upgraded cloners can reduce the time of the modifier, up to 80% + var/clone_sickness_length = abs(((heal_level - 20) / 100 ) - 1) + clone_sickness_length = between(0.2, clone_sickness_length, 1.0) // Caps it off just incase. + modifier_lower_bound = round(modifier_lower_bound * clone_sickness_length, 1) + modifier_upper_bound = round(modifier_upper_bound * clone_sickness_length, 1) + + H.add_modifier(/datum/modifier/cloning_sickness, rand(modifier_lower_bound, modifier_upper_bound)) + + // Modifier that doesn't do anything. + H.add_modifier(/datum/modifier/cloned) + + // This is really stupid. + for(var/modifier_type in R.genetic_modifiers) + H.add_modifier(modifier_type) + for(var/datum/language/L in R.languages) H.add_language(L.name) H.flavor_texts = R.flavor.Copy() @@ -497,4 +520,4 @@ /* EMP grenade/spell effect if(istype(A, /obj/machinery/clonepod)) A:malfunction() -*/ +*/ \ No newline at end of file diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index db932f8cd0..0bd354b541 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -316,6 +316,10 @@ if (subject.species && subject.species.flags & NO_SCAN) scantemp = "Error: Mental interface failure." return + for(var/modifier_type in subject.modifiers) //Can't be cloned, even if they had a previous scan + if(istype(modifier_type, /datum/modifier/no_clone)) + scantemp = "Error: Mental interface failure." + return if (!isnull(find_record(subject.ckey))) scantemp = "Subject already in database." return @@ -330,6 +334,9 @@ R.types = DNA2_BUF_UI|DNA2_BUF_UE|DNA2_BUF_SE R.languages = subject.languages R.flavor = subject.flavor_texts.Copy() + for(var/datum/modifier/mod in subject.modifiers) + if(mod.flags & MODIFIER_GENETIC) + R.genetic_modifiers.Add(mod.type) //Add an implant if needed var/obj/item/weapon/implant/health/imp = locate(/obj/item/weapon/implant/health, subject) diff --git a/code/game/machinery/computer/guestpass.dm b/code/game/machinery/computer/guestpass.dm index b01b03f9b3..501bf91071 100644 --- a/code/game/machinery/computer/guestpass.dm +++ b/code/game/machinery/computer/guestpass.dm @@ -9,6 +9,7 @@ var/temp_access = list() //to prevent agent cards stealing access as permanent var/expiration_time = 0 + var/expired = 0 var/reason = "NOT SPECIFIED" /obj/item/weapon/card/id/guest/GetAccess() @@ -38,6 +39,38 @@ usr << "Issuing reason: [reason]." return +/obj/item/weapon/card/id/guest/attack_self(mob/living/user as mob) + if(user.a_intent == I_HURT) + if(icon_state == "guest_invalid") + to_chat(user, "This guest pass is already deactivated!") + return + + var/confirm = alert("Do you really want to deactivate this guest pass? (you can't reactivate it)", "Confirm Deactivation", "Yes", "No") + if(confirm == "Yes") + //rip guest pass \The [user] deactivates \the [src].") + icon_state = "guest_invalid" + expiration_time = world.time + expired = 1 + return ..() + +/obj/item/weapon/card/id/guest/New() + ..() + processing_objects.Add(src) + update_icon() + +/obj/item/weapon/card/id/guest/Destroy() + processing_objects.Remove(src) + return ..() + +/obj/item/weapon/card/id/guest/process() + if(expired == 0 && world.time >= expiration_time) + visible_message("\The [src] flashes a few times before turning red.") + icon_state = "guest_invalid" + expired = 1 + world.time = expiration_time + return + ///////////////////////////////////////////// //Guest pass terminal//////////////////////// ///////////////////////////////////////////// diff --git a/code/game/machinery/computer/law.dm b/code/game/machinery/computer/law.dm index 8def6db394..5703c90c8a 100644 --- a/code/game/machinery/computer/law.dm +++ b/code/game/machinery/computer/law.dm @@ -31,7 +31,7 @@ return if(istype(O, /obj/item/weapon/aiModule)) var/obj/item/weapon/aiModule/M = O - M.install(src) + M.install(src, user) else ..() diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm index 830c5f8d6d..ec0af28d58 100644 --- a/code/game/machinery/spaceheater.dm +++ b/code/game/machinery/spaceheater.dm @@ -22,6 +22,10 @@ icon_state = "sheater[on]" if(panel_open) overlays += "sheater-open" + if(on) + set_light(3, 3, "#FFCC00") + else + set_light(0) /obj/machinery/space_heater/examine(mob/user) ..(user) diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm index 8797e7af8b..1951ba7c47 100644 --- a/code/game/machinery/telecomms/telecomunications.dm +++ b/code/game/machinery/telecomms/telecomunications.dm @@ -547,8 +547,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() race = "[H.species.name]" log.parameters["intelligible"] = 1 else if(isbrain(M)) - var/mob/living/carbon/brain/B = M - race = "[B.species.name]" + race = "Brain" log.parameters["intelligible"] = 1 else if(M.isMonkey()) race = "Monkey" diff --git a/code/game/mecha/combat/combat.dm b/code/game/mecha/combat/combat.dm index 5424882adc..77087ed32f 100644 --- a/code/game/mecha/combat/combat.dm +++ b/code/game/mecha/combat/combat.dm @@ -2,7 +2,7 @@ force = 30 var/melee_cooldown = 10 var/melee_can_hit = 1 - var/list/destroyable_obj = list(/obj/mecha, /obj/structure/window, /obj/structure/grille, /turf/simulated/wall) + var/list/destroyable_obj = list(/obj/mecha, /obj/structure/window, /obj/structure/grille, /turf/simulated/wall, /obj/structure/girder) internal_damage_threshold = 50 maint_access = 0 //add_req_access = 0 @@ -25,7 +25,7 @@ if(!melee_can_hit || !istype(target, /atom)) return if(istype(target, /mob/living)) var/mob/living/M = target - if(src.occupant.a_intent == I_HURT) + if(src.occupant.a_intent == I_HURT || istype(src.occupant, /mob/living/carbon/brain)) //Brains cannot change intents; Exo-piloting brains lack any form of physical feedback for control, limiting the ability to 'play nice'. playsound(src, 'sound/weapons/punch4.ogg', 50, 1) if(damtype == "brute") step_away(M,src,15) @@ -95,14 +95,19 @@ if(istype(target, target_type) && hascall(target, "attackby")) src.occupant_message("You hit [target].") src.visible_message("[src.name] hits [target]") - if(!istype(target, /turf/simulated/wall)) + if(!istype(target, /turf/simulated/wall) && !istype(target, /obj/structure/girder)) target:attackby(src,src.occupant) else if(prob(5)) target:dismantle_wall(1) src.occupant_message("You smash through the wall.") src.visible_message("[src.name] smashes through the wall") playsound(src, 'sound/weapons/smash.ogg', 50, 1) + else if(istype(target, /turf/simulated/wall)) + target:take_damage(force) + else if(istype(target, /obj/structure/girder)) + target:take_damage(force * 3) //Girders have 200 health by default. Steel, non-reinforced walls take four punches, girders take (with this value-mod) two, girders took five without. melee_can_hit = 0 + if(do_after(melee_cooldown)) melee_can_hit = 1 break @@ -244,6 +249,14 @@ else return 0 +/obj/mecha/combat/mmi_moved_inside(var/obj/item/device/mmi/mmi_as_oc as obj,mob/user as mob) + if(..()) + if(occupant.client) + occupant.client.mouse_pointer_icon = file("icons/mecha/mecha_mouse.dmi") + return 1 + else + return 0 + /obj/mecha/combat/go_out() if(src.occupant && src.occupant.client) src.occupant.client.mouse_pointer_icon = initial(src.occupant.client.mouse_pointer_icon) diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm index a1cbba3102..f3df144ea7 100644 --- a/code/game/mecha/equipment/tools/tools.dm +++ b/code/game/mecha/equipment/tools/tools.dm @@ -52,7 +52,7 @@ else if(istype(target,/mob/living)) var/mob/living/M = target if(M.stat>1) return - if(chassis.occupant.a_intent == I_HURT) + if(chassis.occupant.a_intent == I_HURT || istype(chassis.occupant,/mob/living/carbon/brain)) //No tactile feedback for brains M.take_overall_damage(dam_force) M.adjustOxyLoss(round(dam_force/2)) M.updatehealth() diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index dd3940d421..56149a254c 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -344,8 +344,11 @@ /obj/mecha/relaymove(mob/user,direction) if(user != src.occupant) //While not "realistic", this piece is player friendly. + if(istype(user,/mob/living/carbon/brain)) + to_chat(user,"You try to move, but you are not the pilot! The exosuit doesn't respond.") + return 0 user.forceMove(get_turf(src)) - user << "You climb out from [src]" + to_chat(user,"You climb out from [src]") return 0 if(connected_port) if(world.time - last_message > 20) @@ -686,6 +689,13 @@ /obj/mecha/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/device/mmi)) + if(mmi_move_inside(W,user)) + to_chat(user,"[src]-MMI interface initialized successfuly") + else + to_chat(user,"[src]-MMI interface initialization failed.") + return + if(istype(W, /obj/item/mecha_parts/mecha_equipment)) var/obj/item/mecha_parts/mecha_equipment/E = W spawn() @@ -829,6 +839,70 @@ return */ +/////////////////////////////// +//////// Brain Stuff //////// +/////////////////////////////// + +/obj/mecha/proc/mmi_move_inside(var/obj/item/device/mmi/mmi_as_oc as obj,mob/user as mob) + if(!mmi_as_oc.brainmob || !mmi_as_oc.brainmob.client) + to_chat(user,"Consciousness matrix not detected.") + return 0 + else if(mmi_as_oc.brainmob.stat) + to_chat(user,"Brain activity below acceptable level.") + return 0 + else if(occupant) + to_chat(user,"Occupant detected.") + return 0 + else if(dna && dna!=mmi_as_oc.brainmob.dna.unique_enzymes) + to_chat(user,"Genetic sequence or serial number incompatible with locking mechanism.") + return 0 + //Added a message here since people assume their first click failed or something./N +// user << "Installing MMI, please stand by." + + visible_message("[usr] starts to insert a brain into [src.name]") + + if(enter_after(40,user)) + if(!occupant) + return mmi_moved_inside(mmi_as_oc,user) + else + to_chat(user,"Occupant detected.") + else + to_chat(user,"You stop attempting to install the brain.") + return 0 + +/obj/mecha/proc/mmi_moved_inside(var/obj/item/device/mmi/mmi_as_oc as obj,mob/user as mob) + if(mmi_as_oc && user in range(1)) + if(!mmi_as_oc.brainmob || !mmi_as_oc.brainmob.client) + to_chat(user,"Consciousness matrix not detected.") + return 0 + else if(mmi_as_oc.brainmob.stat) + to_chat(user,"Beta-rhythm below acceptable level.") + return 0 + user.drop_from_inventory(mmi_as_oc) + var/mob/brainmob = mmi_as_oc.brainmob + brainmob.reset_view(src) + /* + brainmob.client.eye = src + brainmob.client.perspective = EYE_PERSPECTIVE + */ + occupant = brainmob + brainmob.loc = src //should allow relaymove + brainmob.canmove = 1 + mmi_as_oc.loc = src + mmi_as_oc.mecha = src + src.verbs += /obj/mecha/verb/eject + src.Entered(mmi_as_oc) + src.Move(src.loc) + src.icon_state = src.reset_icon() + set_dir(dir_in) + src.log_message("[mmi_as_oc] moved in as pilot.") + if(!hasInternalDamage()) + src.occupant << sound('sound/mecha/nominal.ogg',volume=50) + return 1 + else + return 0 + + ///////////////////////////////////// //////// Atmospheric stuff //////// ///////////////////////////////////// @@ -1044,6 +1118,7 @@ src.occupant = H src.add_fingerprint(H) src.forceMove(src.loc) + src.verbs += /obj/mecha/verb/eject src.log_append_to_last("[H] moved in as pilot.") src.icon_state = src.reset_icon() set_dir(dir_in) @@ -1132,10 +1207,10 @@ occupant.loc = mmi mmi.mecha = null src.occupant.canmove = 0 - src.verbs += /obj/mecha/verb/eject src.occupant = null src.icon_state = src.reset_icon()+"-open" src.set_dir(dir_in) + src.verbs -= /obj/mecha/verb/eject return ///////////////////////// diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm index e4df02202f..94c0a7999f 100644 --- a/code/game/objects/effects/spiders.dm +++ b/code/game/objects/effects/spiders.dm @@ -79,6 +79,7 @@ var/amount_grown = 0 var/spiders_min = 6 var/spiders_max = 24 + var/spider_type = /obj/effect/spider/spiderling New() pixel_x = rand(3,-3) pixel_y = rand(3,-3) @@ -105,7 +106,7 @@ O = loc for(var/i=0, i[user] overloads [M]'s sensors with the flash!") + M.Weaken(rand(5,10)) else user.visible_message("[user] fails to blind [M] with the flash!") diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm index e26b75486e..0d81f8559e 100644 --- a/code/game/objects/items/devices/radio/encryptionkey.dm +++ b/code/game/objects/items/devices/radio/encryptionkey.dm @@ -125,3 +125,6 @@ name = "\improper ERT radio encryption key" icon_state = "cent_cypherkey" channels = list("Response Team" = 1, "Science" = 1, "Command" = 1, "Medical" = 1, "Engineering" = 1, "Security" = 1, "Supply" = 1, "Service" = 1) + +/obj/item/device/encryptionkey/omni //Literally only for the admin intercoms + channels = list("Mercenary" = 1, "Raider" = 1, "Response Team" = 1, "Science" = 1, "Command" = 1, "Medical" = 1, "Engineering" = 1, "Security" = 1, "Supply" = 1, "Service" = 1) \ No newline at end of file diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index ccfb671691..ba5d338a0d 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -310,6 +310,9 @@ // freerange = 1 ks2type = /obj/item/device/encryptionkey/ert +/obj/item/device/radio/headset/omni //Only for the admin intercoms + ks2type = /obj/item/device/encryptionkey/omni + /obj/item/device/radio/headset/ia name = "internal affair's headset" desc = "The headset of your worst enemy." @@ -317,6 +320,20 @@ item_state = "headset" ks2type = /obj/item/device/encryptionkey/heads/hos +/obj/item/device/radio/headset/mmi_radio + name = "brain-integrated radio" + desc = "MMIs and synthetic brains are often equipped with these." + icon = 'icons/obj/robot_component.dmi' + icon_state = "radio" + item_state = "headset" + var/mmiowner = null + var/radio_enabled = 1 + +/obj/item/device/radio/headset/mmi_radio/receive_range(freq, level) + if (!radio_enabled || istype(src.loc.loc, /mob/living/silicon) || istype(src.loc.loc, /obj/item/organ/internal)) + return -1 //Transciever Disabled. + return ..(freq, level, 1) + /obj/item/device/radio/headset/attackby(obj/item/weapon/W as obj, mob/user as mob) // ..() user.set_machine(src) diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index d903499ee0..ccbbb5fea7 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -353,8 +353,8 @@ REAGENT SCANNER /obj/item/device/slime_scanner name = "slime scanner" - icon_state = "adv_spectrometer" - item_state = "analyzer" + icon_state = "xenobio" + item_state = "xenobio" origin_tech = list(TECH_BIO = 1) w_class = ITEMSIZE_SMALL flags = CONDUCT diff --git a/code/game/objects/items/devices/t_scanner.dm b/code/game/objects/items/devices/t_scanner.dm index 525c5d1255..5610828bfe 100644 --- a/code/game/objects/items/devices/t_scanner.dm +++ b/code/game/objects/items/devices/t_scanner.dm @@ -132,4 +132,19 @@ /obj/item/device/t_scanner/dropped(mob/user) set_user_client(null) +/obj/item/device/t_scanner/upgraded + name = "Upgraded T-ray Scanner" + desc = "An upgraded version of the terahertz-ray emitter and scanner used to detect underfloor objects such as cables and pipes." + matter = list(DEFAULT_WALL_MATERIAL = 500, PHORON = 150) + origin_tech = list(TECH_MAGNET = 4, TECH_ENGINEERING = 5) + scan_range = 3 + +/obj/item/device/t_scanner/advanced + name = "Advanced T-ray Scanner" + desc = "An advanced version of the terahertz-ray emitter and scanner used to detect underfloor objects such as cables and pipes." + matter = list(DEFAULT_WALL_MATERIAL = 1500, PHORON = 200, SILVER = 250) + origin_tech = list(TECH_MAGNET = 7, TECH_ENGINEERING = 7, TECH_MATERIAL = 6) + scan_range = 7 + + #undef OVERLAY_CACHE_LEN \ No newline at end of file diff --git a/code/game/objects/items/stacks/fifty_spawner.dm b/code/game/objects/items/stacks/fifty_spawner.dm index adac95eaf4..1977427ebb 100644 --- a/code/game/objects/items/stacks/fifty_spawner.dm +++ b/code/game/objects/items/stacks/fifty_spawner.dm @@ -4,16 +4,18 @@ desc = "This item spawns stack of 50 of a given material." icon = 'icons/misc/mark.dmi' icon_state = "x4" - var/material = "" +// var/material = "" + var/obj/item/stack/type_to_spawn = null /obj/fiftyspawner/New() //spawns the 50-stack and qdels self ..() - var/obj_path = text2path("/obj/item/stack/[material]") - var/obj/item/stack/M = new obj_path(src.loc) +// var/obj_path = text2path("/obj/item/stack/[material]") + var/obj/item/stack/M = new type_to_spawn(src.loc) M.amount = M.max_amount //some stuff spawns with 60, we're still calling it fifty + M.update_icon() // Some stacks have different sprites depending on how full they are. qdel(src) /obj/fiftyspawner/rods name = "stack of rods" //this needs to be defined for cargo - material = "rods" \ No newline at end of file + type_to_spawn = /obj/item/stack/rods \ No newline at end of file diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index db4e890d60..dde2f168b0 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -1,7 +1,7 @@ /obj/item/stack/medical name = "medical pack" singular_name = "medical pack" - icon = 'icons/obj/items.dmi' + icon = 'icons/obj/stacks.dmi' amount = 10 max_amount = 10 w_class = ITEMSIZE_SMALL @@ -64,6 +64,7 @@ desc = "Some sterile gauze to wrap around bloody stumps." icon_state = "brutepack" origin_tech = list(TECH_BIO = 1) + no_variants = FALSE /obj/item/stack/medical/bruise_pack/attack(mob/living/carbon/M as mob, mob/user as mob) if(..()) @@ -123,6 +124,7 @@ icon_state = "ointment" heal_burn = 1 origin_tech = list(TECH_BIO = 1) + no_variants = FALSE /obj/item/stack/medical/ointment/attack(mob/living/carbon/M as mob, mob/user as mob) if(..()) @@ -279,16 +281,25 @@ if(M == user && prob(75)) user.visible_message("\The [user] fumbles [src].", "You fumble [src].", "You hear something being wrapped.") return - var/obj/item/stack/medical/splint/S = split(1) - if(S) - if(affecting.apply_splint(S)) - S.forceMove(affecting) - if (M != user) + if(ishuman(user)) + var/obj/item/stack/medical/splint/S = split(1) + if(S) + if(affecting.apply_splint(S)) + S.forceMove(affecting) + if (M != user) + user.visible_message("\The [user] finishes applying [src] to [M]'s [limb].", "You finish applying \the [src] to [M]'s [limb].", "You hear something being wrapped.") + else + user.visible_message("\The [user] successfully applies [src] to their [limb].", "You successfully apply \the [src] to your [limb].", "You hear something being wrapped.") + return + S.dropInto(src.loc) //didn't get applied, so just drop it + if(isrobot(user)) + var/obj/item/stack/medical/splint/B = src + if(B) + if(affecting.apply_splint(B)) + B.forceMove(affecting) user.visible_message("\The [user] finishes applying [src] to [M]'s [limb].", "You finish applying \the [src] to [M]'s [limb].", "You hear something being wrapped.") - else - user.visible_message("\The [user] successfully applies [src] to their [limb].", "You successfully apply \the [src] to your [limb].", "You hear something being wrapped.") - return - S.dropInto(src.loc) //didn't get applied, so just drop it + B.use(1) + return user.visible_message("\The [user] fails to apply [src].", "You fail to apply [src].", "You hear something being wrapped.") return diff --git a/code/game/objects/items/stacks/nanopaste.dm b/code/game/objects/items/stacks/nanopaste.dm index cee27175ad..214d81f23e 100644 --- a/code/game/objects/items/stacks/nanopaste.dm +++ b/code/game/objects/items/stacks/nanopaste.dm @@ -2,11 +2,12 @@ name = "nanopaste" singular_name = "nanite swarm" desc = "A tube of paste containing swarms of repair nanites. Very effective in repairing robotic machinery." - icon = 'icons/obj/nanopaste.dmi' - icon_state = "tube" + icon = 'icons/obj/stacks.dmi' + icon_state = "nanopaste" origin_tech = list(TECH_MATERIAL = 4, TECH_ENGINEERING = 3) amount = 10 w_class = ITEMSIZE_SMALL + no_variants = FALSE /obj/item/stack/nanopaste/attack(mob/living/M as mob, mob/user as mob) if (!istype(M) || !istype(user)) diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm index da6e436b27..784eadd3b9 100644 --- a/code/game/objects/items/stacks/rods.dm +++ b/code/game/objects/items/stacks/rods.dm @@ -21,6 +21,23 @@ uses_charge = 1 charge_costs = list(500) stacktype = /obj/item/stack/rods + no_variants = TRUE + +/obj/item/stack/rods/New() + ..() + recipes = rods_recipes + update_icon() + +/obj/item/stack/rods/update_icon() + var/amount = get_amount() + if((amount <= 5) && (amount > 0)) + icon_state = "rods-[amount]" + else + icon_state = "rods" + +var/global/list/datum/stack_recipe/rods_recipes = list( \ + new/datum/stack_recipe("grille", /obj/structure/grille, 2, time = 10, one_per_turf = 1, on_floor = 1), + new/datum/stack_recipe("catwalk", /obj/structure/catwalk, 2, time = 80, one_per_turf = 1, on_floor = 1)) /obj/item/stack/rods/attackby(obj/item/W as obj, mob/user as mob) if (istype(W, /obj/item/weapon/weldingtool)) @@ -55,7 +72,7 @@ ..() - +/* /obj/item/stack/rods/attack_self(mob/user as mob) src.add_fingerprint(user) @@ -87,3 +104,4 @@ F.add_fingerprint(usr) use(2) return +*/ \ No newline at end of file diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm index 96b35e13e7..8ece302f13 100644 --- a/code/game/objects/items/stacks/sheets/leather.dm +++ b/code/game/objects/items/stacks/sheets/leather.dm @@ -3,6 +3,7 @@ desc = "The by-product of human farming." singular_name = "human skin piece" icon_state = "sheet-hide" + no_variants = FALSE /obj/item/stack/material/animalhide/human amount = 50 @@ -80,6 +81,7 @@ desc = "This hide was stripped of it's hair, but still needs tanning." singular_name = "hairless hide piece" icon_state = "sheet-hairlesshide" + no_variants = FALSE /obj/item/stack/material/hairlesshide amount = 50 @@ -91,6 +93,7 @@ icon_state = "sheet-wetleather" var/wetness = 30 //Reduced when exposed to high temperautres var/drying_threshold_temperature = 500 //Kelvin to start drying + no_variants = FALSE /obj/item/stack/material/wetleather amount = 50 diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index ee1cc1b078..c5be255204 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -12,6 +12,7 @@ /obj/item/stack gender = PLURAL origin_tech = list(TECH_MATERIAL = 1) + icon = 'icons/obj/stacks.dmi' var/list/datum/stack_recipe/recipes var/singular_name var/amount = 1 @@ -21,6 +22,7 @@ var/uses_charge = 0 var/list/charge_costs = null var/list/datum/matter_synth/synths = null + var/no_variants = TRUE // Determines whether the item should update it's sprites based on amount. /obj/item/stack/New(var/loc, var/amount=null) ..() @@ -28,6 +30,7 @@ stacktype = type if (amount) src.amount = amount + update_icon() return /obj/item/stack/Destroy() @@ -37,6 +40,18 @@ usr << browse(null, "window=stack") return ..() +/obj/item/stack/update_icon() + if(no_variants) + icon_state = initial(icon_state) + else + if(amount <= (max_amount * (1/3))) + icon_state = initial(icon_state) + else if (amount <= (max_amount * (2/3))) + icon_state = "[initial(icon_state)]_2" + else + icon_state = "[initial(icon_state)]_3" + item_state = initial(icon_state) + /obj/item/stack/examine(mob/user) if(..(user, 1)) if(!uses_charge) @@ -189,6 +204,7 @@ if(usr) usr.remove_from_mob(src) qdel(src) //should be safe to qdel immediately since if someone is still using this stack it will persist for a little while longer + update_icon() return 1 else if(get_amount() < used) @@ -205,6 +221,7 @@ return 0 else amount += extra + update_icon() return 1 else if(!synths || synths.len < uses_charge) return 0 @@ -298,7 +315,7 @@ /obj/item/stack/attack_hand(mob/user as mob) if (user.get_inactive_hand() == src) - var/N = input("How many stacks of [src] would you like to split off?", "Split stacks", 1) as num|null + var/N = input("How many stacks of [src] would you like to split off? There are currently [amount].", "Split stacks", 1) as num|null if(N) var/obj/item/stack/F = src.split(N) if (F) diff --git a/code/game/objects/items/stacks/tiles/fifty_spawner_tiles.dm b/code/game/objects/items/stacks/tiles/fifty_spawner_tiles.dm index 09df497d8d..3d89b5e786 100644 --- a/code/game/objects/items/stacks/tiles/fifty_spawner_tiles.dm +++ b/code/game/objects/items/stacks/tiles/fifty_spawner_tiles.dm @@ -2,48 +2,48 @@ /obj/fiftyspawner/grass name = "stack of grass" - material = "tile/grass" + type_to_spawn = /obj/item/stack/tile/grass /obj/fiftyspawner/wood name = "stack of wood" - material = "tile/wood" + type_to_spawn = /obj/item/stack/tile/wood /obj/fiftyspawner/carpet name = "stack of carpet" - material = "tile/carpet" + type_to_spawn = /obj/item/stack/tile/carpet /obj/fiftyspawner/bluecarpet name = "stack of blue carpet" - material = "tile/carpet/blue" + type_to_spawn = /obj/item/stack/tile/carpet/blue /obj/fiftyspawner/floor name = "stack of floor tiles" - material = "tile/floor" + type_to_spawn = /obj/item/stack/tile/floor /obj/fiftyspawner/floor_red name = "stack of red floor tiles" - material = "tile/floor_red" + type_to_spawn = /obj/item/stack/tile/floor/red /obj/fiftyspawner/floor_steel name = "stack of steel floor tiles" - material = "tile/floor_steel" + type_to_spawn = /obj/item/stack/tile/floor/steel /obj/fiftyspawner/floor_white name = "stack of white floor tiles" - material = "tile/floor_white" + type_to_spawn = /obj/item/stack/tile/floor/white /obj/fiftyspawner/floor_yellow name = "stack of yellow floor tiles" - material = "tile/floor_yellow" + type_to_spawn = /obj/item/stack/tile/floor/yellow /obj/fiftyspawner/floor_dark name = "stack of dark floor tiles" - material = "tile/floor_dark" + type_to_spawn = /obj/item/stack/tile/floor/dark /obj/fiftyspawner/floor_freezer name = "stack of freezer tiles" - material = "tile/floor_freezer" + type_to_spawn = /obj/item/stack/tile/floor/freezer /obj/fiftyspawner/linoleum name = "stack of linoleum tiles" - material = "tile/linoleum" \ No newline at end of file + type_to_spawn = /obj/item/stack/tile/linoleum \ No newline at end of file diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index fff49c479f..a4dcd6d96f 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -36,6 +36,7 @@ throw_range = 20 flags = 0 origin_tech = list(TECH_BIO = 1) + no_variants = FALSE /obj/item/stack/tile/grass/fifty amount = 50 @@ -52,6 +53,7 @@ throw_speed = 5 throw_range = 20 flags = 0 + no_variants = FALSE /obj/item/stack/tile/wood/fifty amount = 50 @@ -77,12 +79,14 @@ throw_speed = 5 throw_range = 20 flags = 0 + no_variants = FALSE /obj/item/stack/tile/carpet/blue name = "blue carpet" singular_name = "blue carpet" desc = "A piece of blue carpet. It is the same size as a normal floor tile!" icon_state = "tile-bluecarpet" + no_variants = FALSE /obj/item/stack/tile/carpet/bcarpet icon_state = "tile-carpet" @@ -110,29 +114,34 @@ throw_speed = 5 throw_range = 20 flags = CONDUCT + no_variants = FALSE /obj/item/stack/tile/floor/red name = "red floor tile" singular_name = "red floor tile" color = COLOR_RED_GRAY icon_state = "tile_white" + no_variants = FALSE // VOREStation Edit /obj/item/stack/tile/floor/techgrey name = "grey techfloor tile" singular_name = "grey techfloor tile" icon_state = "techtile_grey" + no_variants = FALSE /obj/item/stack/tile/floor/techgrid name = "grid techfloor tile" singular_name = "grid techfloor tile" icon_state = "techtile_grid" + no_variants = FALSE /obj/item/stack/tile/floor/steel_dirty name = "steel floor tile" singular_name = "steel floor tile" icon_state = "tile_steel" matter = list("plasteel" = SHEET_MATERIAL_AMOUNT / 4) + no_variants = FALSE // VOREStation Edit End /obj/item/stack/tile/floor/steel @@ -140,30 +149,35 @@ singular_name = "steel floor tile" icon_state = "tile_steel" matter = list("plasteel" = SHEET_MATERIAL_AMOUNT / 4) + no_variants = FALSE /obj/item/stack/tile/floor/white name = "white floor tile" singular_name = "white floor tile" icon_state = "tile_white" matter = list("plastic" = SHEET_MATERIAL_AMOUNT / 4) + no_variants = FALSE /obj/item/stack/tile/floor/yellow name = "yellow floor tile" singular_name = "yellow floor tile" color = COLOR_BROWN icon_state = "tile_white" + no_variants = FALSE /obj/item/stack/tile/floor/dark name = "dark floor tile" singular_name = "dark floor tile" - icon_state = "fr_tile" + icon_state = "tile_steel" matter = list("plasteel" = SHEET_MATERIAL_AMOUNT / 4) + no_variants = FALSE /obj/item/stack/tile/floor/freezer name = "freezer floor tile" singular_name = "freezer floor tile" icon_state = "tile_freezer" matter = list("plastic" = SHEET_MATERIAL_AMOUNT / 4) + no_variants = FALSE /obj/item/stack/tile/floor/cyborg name = "floor tile synthesizer" @@ -185,3 +199,4 @@ throw_speed = 5 throw_range = 20 flags = 0 + no_variants = FALSE diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 58f8206c0f..2c27e35010 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -287,6 +287,7 @@ desc = "Woefully underpowered in D20." icon = 'icons/obj/weapons.dmi' icon_state = "katana" + item_state = "katana" item_icons = list( slot_l_hand_str = 'icons/mob/items/lefthand_material.dmi', slot_r_hand_str = 'icons/mob/items/righthand_material.dmi', @@ -697,19 +698,6 @@ desc = "A \"Space Life\" brand Emergency Response Team Commander action figure." icon_state = "ert" -/obj/item/toy/katana - name = "replica katana" - desc = "Woefully underpowered in D20." - icon = 'icons/obj/weapons.dmi' - icon_state = "katana" - item_state = "katana" - flags = CONDUCT - slot_flags = SLOT_BELT | SLOT_BACK - force = 5 - throwforce = 5 - w_class = ITEMSIZE_NORMAL - attack_verb = list("attacked", "slashed", "stabbed", "sliced") - /obj/item/toy/therapy_red name = "red therapy doll" desc = "A toy for therapeutic and recreational purposes. This one is red." diff --git a/code/game/objects/items/weapons/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm index c5e6614de2..60a847a4d6 100755 --- a/code/game/objects/items/weapons/AI_modules.dm +++ b/code/game/objects/items/weapons/AI_modules.dm @@ -20,9 +20,9 @@ AI MODULES origin_tech = list(TECH_DATA = 3) var/datum/ai_laws/laws = null -/obj/item/weapon/aiModule/proc/install(var/obj/machinery/computer/C) - if (istype(C, /obj/machinery/computer/aiupload)) - var/obj/machinery/computer/aiupload/comp = C +/obj/item/weapon/aiModule/proc/install(var/atom/movable/AM, var/mob/living/user) + if (istype(AM, /obj/machinery/computer/aiupload)) + var/obj/machinery/computer/aiupload/comp = AM if(comp.stat & NOPOWER) usr << "The upload computer has no power!" return @@ -33,10 +33,6 @@ AI MODULES usr << "You haven't selected an AI to transmit laws to!" return - if(ticker && ticker.mode && ticker.mode.name == "blob") - usr << "Law uploads have been disabled by [using_map.company_name]!" - return - if (comp.current.stat == 2 || comp.current.control_disabled == 1) usr << "Upload failed. No signal is being detected from the AI." else if (comp.current.see_in_dark == 0) @@ -52,8 +48,8 @@ AI MODULES usr << "Upload complete. The AI's laws have been modified." - else if (istype(C, /obj/machinery/computer/borgupload)) - var/obj/machinery/computer/borgupload/comp = C + else if (istype(AM, /obj/machinery/computer/borgupload)) + var/obj/machinery/computer/borgupload/comp = AM if(comp.stat & NOPOWER) usr << "The upload computer has no power!" return @@ -74,6 +70,31 @@ AI MODULES comp.current.show_laws() usr << "Upload complete. The robot's laws have been modified." + else if(istype(AM, /mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = AM + if(R.stat == DEAD) + to_chat(user, "Law Upload Error: Unit is nonfunctional.") + return + if(R.emagged) + to_chat(user, "Law Upload Error: Cannot obtain write access to laws.") + to_chat(R, "Law modification attempt detected. Blocking.") + return + if(R.connected_ai) + to_chat(user, "Law Upload Error: Unit is slaved to an AI.") + return + + R.visible_message("\The [user] slides a law module into \the [R].") + to_chat(R, "Local law upload in progress.") + to_chat(user, "Uploading laws from board. This will take a moment...") + if(do_after(user, 10 SECONDS)) + transmitInstructions(R, user) + to_chat(R, "These are your laws now:") + R.show_laws() + to_chat(user, "Law upload complete. Unit's laws have been modified.") + else + to_chat(user, "Law Upload Error: Law board was removed before upload was complete. Aborting.") + to_chat(R, "Law upload aborted.") + /obj/item/weapon/aiModule/proc/transmitInstructions(var/mob/living/silicon/ai/target, var/mob/sender) log_law_changes(target, sender) @@ -109,7 +130,7 @@ AI MODULES targetName = targName desc = text("A 'safeguard' AI module: 'Safeguard []. Anyone threatening or attempting to harm [] is no longer to be considered a crew member, and is a threat which must be neutralized.'", targetName, targetName) -/obj/item/weapon/aiModule/safeguard/install(var/obj/machinery/computer/C) +/obj/item/weapon/aiModule/safeguard/install(var/obj/machinery/computer/C, var/mob/living/user) if(!targetName) usr << "No name detected on module, please enter one." return 0 @@ -135,7 +156,7 @@ AI MODULES targetName = targName desc = text("A 'one crew member' AI module: 'Only [] is a crew member.'", targetName) -/obj/item/weapon/aiModule/oneHuman/install(var/obj/machinery/computer/C) +/obj/item/weapon/aiModule/oneHuman/install(var/obj/machinery/computer/C, var/mob/living/user) if(!targetName) usr << "No name detected on module, please enter one." return 0 @@ -231,7 +252,7 @@ AI MODULES target.add_supplied_law(lawpos, law) lawchanges.Add("The law was '[newFreeFormLaw]'") -/obj/item/weapon/aiModule/freeform/install(var/obj/machinery/computer/C) +/obj/item/weapon/aiModule/freeform/install(var/obj/machinery/computer/C, var/mob/living/user) if(!newFreeFormLaw) usr << "No law detected on module, please create one." return 0 @@ -342,7 +363,7 @@ AI MODULES target.add_inherent_law(law) lawchanges.Add("The law is '[newFreeFormLaw]'") -/obj/item/weapon/aiModule/freeformcore/install(var/obj/machinery/computer/C) +/obj/item/weapon/aiModule/freeformcore/install(var/obj/machinery/computer/C, var/mob/living/user) if(!newFreeFormLaw) usr << "No law detected on module, please create one." return 0 @@ -371,7 +392,7 @@ AI MODULES target.add_ion_law(law) target.show_laws() -/obj/item/weapon/aiModule/syndicate/install(var/obj/machinery/computer/C) +/obj/item/weapon/aiModule/syndicate/install(var/obj/machinery/computer/C, var/mob/living/user) if(!newFreeFormLaw) usr << "No law detected on module, please create one." return 0 diff --git a/code/game/objects/items/weapons/cards_ids_syndicate.dm b/code/game/objects/items/weapons/cards_ids_syndicate.dm index 300926d08e..b5c874868e 100644 --- a/code/game/objects/items/weapons/cards_ids_syndicate.dm +++ b/code/game/objects/items/weapons/cards_ids_syndicate.dm @@ -1,28 +1,21 @@ -var/list/syndicate_ids = list() - /obj/item/weapon/card/id/syndicate name = "agent card" icon_state = "syndicate" assignment = "Agent" origin_tech = list(TECH_ILLEGAL = 3) var/electronic_warfare = 1 - var/registered_user = null + var/mob/registered_user = null /obj/item/weapon/card/id/syndicate/New(mob/user as mob) ..() - syndicate_ids += src access = syndicate_access.Copy() -/obj/item/weapon/card/id/syndicate/Destroy() - syndicate_ids -= src - registered_user = null - return ..() +/obj/item/weapon/card/id/syndicate/station_access/New() + ..() // Same as the normal Syndicate id, only already has all station access + access |= get_all_station_access() -// On mob destruction, ensure any references are cleared -/mob/Destroy() - for(var/obj/item/weapon/card/id/syndicate/SID in syndicate_ids) - if(SID.registered_user == src) - SID.registered_user = null +/obj/item/weapon/card/id/syndicate/Destroy() + unset_registered_user(registered_user) return ..() /obj/item/weapon/card/id/syndicate/prevent_tracking() @@ -37,9 +30,8 @@ var/list/syndicate_ids = list() user << "The microscanner activates as you pass it over the ID, copying its access." /obj/item/weapon/card/id/syndicate/attack_self(mob/user as mob) - if(!registered_user) - registered_user = user - user.set_id_info(src) + // We use the fact that registered_name is not unset should the owner be vaporized, to ensure the id doesn't magically become unlocked. + if(!registered_user && register_user(user)) user << "The microscanner marks you as its owner, preventing others from accessing its internals." if(registered_user == user) switch(alert("Would you like edit the ID, or show it?","Show or Edit?", "Edit","Show")) @@ -72,6 +64,21 @@ var/list/syndicate_ids = list() ui.set_initial_data(data) ui.open() +/obj/item/weapon/card/id/syndicate/proc/register_user(var/mob/user) + if(!istype(user) || user == registered_user) + return FALSE + unset_registered_user() + registered_user = user + user.set_id_info(src) + user.register(OBSERVER_EVENT_DESTROY, src, /obj/item/weapon/card/id/syndicate/proc/unset_registered_user) + return TRUE + +/obj/item/weapon/card/id/syndicate/proc/unset_registered_user(var/mob/user) + if(!registered_user || (user && user != registered_user)) + return + registered_user.unregister(OBSERVER_EVENT_DESTROY, src) + registered_user = null + /obj/item/weapon/card/id/syndicate/CanUseTopic(mob/user) if(user != registered_user) return STATUS_CLOSE @@ -172,7 +179,7 @@ var/list/syndicate_ids = list() icon_state = initial(icon_state) name = initial(name) registered_name = initial(registered_name) - registered_user = null + unset_registered_user() sex = initial(sex) user << "All information has been deleted from \the [src]." . = 1 diff --git a/code/game/objects/items/weapons/grenades/spawnergrenade.dm b/code/game/objects/items/weapons/grenades/spawnergrenade.dm index 8e112d9655..f9cbc65b59 100644 --- a/code/game/objects/items/weapons/grenades/spawnergrenade.dm +++ b/code/game/objects/items/weapons/grenades/spawnergrenade.dm @@ -40,3 +40,22 @@ spawner_type = /mob/living/simple_animal/hostile/carp deliveryamt = 5 origin_tech = list(TECH_MATERIAL = 3, TECH_MAGNET = 4, TECH_ILLEGAL = 4) + +/obj/item/weapon/grenade/spawnergrenade/spider + name = "spider delivery grenade" + spawner_type = /mob/living/simple_animal/hostile/giant_spider/hunter + deliveryamt = 3 + origin_tech = list(TECH_MATERIAL = 3, TECH_MAGNET = 4, TECH_ILLEGAL = 4) + +//Sometimes you just need a sudden influx of spiders. +/obj/item/weapon/grenade/spawnergrenade/spider/briefcase + name = "briefcase" + desc = "It's made of AUTHENTIC faux-leather and has a price-tag still attached. Its owner must be a real professional." + icon_state = "briefcase" + item_state = "briefcase" + flags = CONDUCT + force = 8.0 + throw_speed = 1 + throw_range = 4 + w_class = ITEMSIZE_LARGE + deliveryamt = 6 \ No newline at end of file diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm index 62941c24f0..0b4700ca6a 100644 --- a/code/game/objects/items/weapons/handcuffs.dm +++ b/code/game/objects/items/weapons/handcuffs.dm @@ -25,7 +25,7 @@ return if ((CLUMSY in user.mutations) && prob(50)) - user << "Uh ... how do those things work?!" + to_chat(user, "Uh ... how do those things work?!") place_handcuffs(user, user) return @@ -38,7 +38,7 @@ if(can_place(C, user)) place_handcuffs(C, user) else - user << "You need to have a firm grip on [C] before you can put \the [src] on!" + to_chat(user, "You need to have a firm grip on [C] before you can put \the [src] on!") /obj/item/weapon/handcuffs/proc/can_place(var/mob/target, var/mob/user) if(user == target) @@ -60,11 +60,11 @@ return 0 if (!H.has_organ_for_slot(slot_handcuffed)) - user << "\The [H] needs at least two wrists before you can cuff them together!" + to_chat(user, "\The [H] needs at least two wrists before you can cuff them together!") return 0 if(istype(H.gloves,/obj/item/clothing/gloves/gauntlets/rig) && !elastic) // Can't cuff someone who's in a deployed hardsuit. - user << "\The [src] won't fit around \the [H.gloves]!" + to_chat(user, "\The [src] won't fit around \the [H.gloves]!") return 0 user.visible_message("\The [user] is attempting to put [cuff_type] on \the [H]!") @@ -166,7 +166,7 @@ var/last_chew = 0 if (R.use(1)) var/obj/item/weapon/material/wirerod/W = new(get_turf(user)) user.put_in_hands(W) - user << "You wrap the cable restraint around the top of the rod." + to_chat(user, "You wrap the cable restraint around the top of the rod.") qdel(src) update_icon(user) @@ -181,3 +181,84 @@ var/last_chew = 0 icon = 'icons/obj/bureaucracy.dmi' breakouttime = 200 cuff_type = "duct tape" + +//Legcuffs. Not /really/ handcuffs, but its close enough. +/obj/item/weapon/handcuffs/legcuffs + name = "legcuffs" + desc = "Use this to keep prisoners in line." + gender = PLURAL + icon = 'icons/obj/items.dmi' + icon_state = "legcuff" + flags = CONDUCT + throwforce = 0 + w_class = ITEMSIZE_NORMAL + origin_tech = list(TECH_MATERIAL = 1) + breakouttime = 300 //Deciseconds = 30s = 0.5 minute + cuff_type = "legcuffs" + sprite_sheets = list("Teshari" = 'icons/mob/species/seromi/handcuffs.dmi') + elastic = 0 + cuff_sound = 'sound/weapons/handcuffs.ogg' //This shold work for now. + +/obj/item/weapon/handcuffs/legcuffs/attack(var/mob/living/carbon/C, var/mob/living/user) + if(!user.IsAdvancedToolUser()) + return + + if ((CLUMSY in user.mutations) && prob(50)) + to_chat(user, "Uh ... how do those things work?!") + place_legcuffs(user, user) + return + + if(!C.handcuffed) + if (C == user) + place_legcuffs(user, user) + return + + //check for an aggressive grab (or robutts) + if(can_place(C, user)) + place_legcuffs(C, user) + else + to_chat(user, "You need to have a firm grip on [C] before you can put \the [src] on!") + +/obj/item/weapon/handcuffs/legcuffs/proc/place_legcuffs(var/mob/living/carbon/target, var/mob/user) + playsound(src.loc, cuff_sound, 30, 1, -2) + + var/mob/living/carbon/human/H = target + if(!istype(H)) + return 0 + + if (!H.has_organ_for_slot(slot_legcuffed)) + to_chat(user, "\The [H] needs at least two ankles before you can cuff them together!") + return 0 + + if(istype(H.shoes,/obj/item/clothing/shoes/magboots/rig) && !elastic) // Can't cuff someone who's in a deployed hardsuit. + to_chat(user, "\The [src] won't fit around \the [H.shoes]!") + return 0 + + user.visible_message("\The [user] is attempting to put [cuff_type] on \the [H]!") + + if(!do_after(user,30)) + return 0 + + if(!can_place(target, user)) //victim may have resisted out of the grab in the meantime + return 0 + + H.attack_log += text("\[[time_stamp()]\] Has been legcuffed (attempt) by [user.name] ([user.ckey])") + user.attack_log += text("\[[time_stamp()]\] Attempted to legcuff [H.name] ([H.ckey])") + msg_admin_attack("[key_name(user)] attempted to legcuff [key_name(H)]") + feedback_add_details("legcuffs","H") + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + user.do_attack_animation(H) + + user.visible_message("\The [user] has put [cuff_type] on \the [H]!") + + // Apply cuffs. + var/obj/item/weapon/handcuffs/legcuffs/lcuffs = src + if(dispenser) + lcuffs = new(get_turf(user)) + else + user.drop_from_inventory(lcuffs) + lcuffs.loc = target + target.legcuffed = lcuffs + target.update_inv_legcuffed() + return 1 diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm index 806047ae37..ac433353e0 100644 --- a/code/game/objects/items/weapons/implants/implant.dm +++ b/code/game/objects/items/weapons/implants/implant.dm @@ -69,8 +69,37 @@ /obj/item/weapon/implant/tracking name = "tracking implant" desc = "Track with this." - var/id = 1.0 + var/id = 1 + var/degrade_time = 10 MINUTES //How long before the implant stops working outside of a living body. +/obj/item/weapon/implant/tracking/weak //This is for the loadout + degrade_time = 2.5 MINUTES + +/obj/item/weapon/implant/tracking/New() + id = rand(1, 1000) + ..() + +/obj/item/weapon/implant/tracking/implanted(var/mob/source) + processing_objects.Add(src) + listening_objects |= src + return 1 + +/obj/item/weapon/implant/tracking/Destroy() + processing_objects.Remove(src) + return ..() + +/obj/item/weapon/implant/tracking/process() + var/implant_location = src.loc + if(ismob(implant_location)) + var/mob/living/L = implant_location + if(L.stat == DEAD) + if(world.time >= L.timeofdeath + degrade_time) + name = "melted implant" + desc = "Charred circuit in melted plastic case. Wonder what that used to be..." + icon_state = "implant_melted" + malfunction = MALFUNCTION_PERMANENT + processing_objects.Remove(src) + return 1 /obj/item/weapon/implant/tracking/get_data() var/dat = {"Implant Specifications:
diff --git a/code/game/objects/items/weapons/implants/implanter.dm b/code/game/objects/items/weapons/implants/implanter.dm index d68ae92a39..64f29d7902 100644 --- a/code/game/objects/items/weapons/implants/implanter.dm +++ b/code/game/objects/items/weapons/implants/implanter.dm @@ -1,23 +1,34 @@ /obj/item/weapon/implanter name = "implanter" icon = 'icons/obj/items.dmi' - icon_state = "implanter0" + icon_state = "implanter0_1" item_state = "syringe_0" throw_speed = 1 throw_range = 5 w_class = ITEMSIZE_SMALL matter = list(DEFAULT_WALL_MATERIAL = 1000, "glass" = 1000) var/obj/item/weapon/implant/imp = null + var/active = 1 /obj/item/weapon/implanter/attack_self(var/mob/user) + active = !active + to_chat(user, "You [active ? "" : "de"]activate \the [src].") + update() + +/obj/item/weapon/implanter/verb/remove_implant(var/mob/user) + set category = "Object" + set name = "Remove Implant" + set src in usr + if(!imp) - return ..() + return imp.loc = get_turf(src) user.put_in_hands(imp) - user << "You remove \the [imp] from \the [src]." + to_chat(user, "You remove \the [imp] from \the [src].") name = "implanter" imp = null update() + return /obj/item/weapon/implanter/proc/update() @@ -25,40 +36,43 @@ src.icon_state = "implanter1" else src.icon_state = "implanter0" + src.icon_state += "_[active]" return /obj/item/weapon/implanter/attack(mob/M as mob, mob/user as mob) if (!istype(M, /mob/living/carbon)) return - if (user && src.imp) - M.visible_message("[user] is attemping to implant [M].") + if(active) + if (imp) + M.visible_message("[user] is attemping to implant [M].") - user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) - user.do_attack_animation(M) + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) + user.do_attack_animation(M) - var/turf/T1 = get_turf(M) - if (T1 && ((M == user) || do_after(user, 50))) - if(user && M && (get_turf(M) == T1) && src && src.imp) - M.visible_message("[M] has been implanted by [user].") + var/turf/T1 = get_turf(M) + if (T1 && ((M == user) || do_after(user, 50))) + if(user && M && (get_turf(M) == T1) && src && src.imp) + M.visible_message("[M] has been implanted by [user].") - admin_attack_log(user, M, "Implanted using \the [src.name] ([src.imp.name])", "Implanted with \the [src.name] ([src.imp.name])", "used an implanter, [src.name] ([src.imp.name]), on") + admin_attack_log(user, M, "Implanted using \the [src.name] ([src.imp.name])", "Implanted with \the [src.name] ([src.imp.name])", "used an implanter, [src.name] ([src.imp.name]), on") - if(src.imp.implanted(M)) - src.imp.loc = M - src.imp.imp_in = M - src.imp.implanted = 1 - if (ishuman(M)) - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/affected = H.get_organ(user.zone_sel.selecting) - affected.implants += src.imp - imp.part = affected + if(src.imp.implanted(M)) + src.imp.loc = M + src.imp.imp_in = M + src.imp.implanted = 1 + if (ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/affected = H.get_organ(user.zone_sel.selecting) + affected.implants += src.imp + imp.part = affected - BITSET(H.hud_updateflag, IMPLOYAL_HUD) + BITSET(H.hud_updateflag, IMPLOYAL_HUD) BITSET(H.hud_updateflag, BACKUP_HUD) //VOREStation Add - Backup HUD updates - src.imp = null - update() - + src.imp = null + update() + else + to_chat(user, "You need to activate \the [src.name] first.") return /obj/item/weapon/implanter/loyalty @@ -113,19 +127,26 @@ var/obj/item/weapon/implant/compressed/c = imp if (!c) return if (c.scanned == null) - user << "Please scan an object with the implanter first." + to_chat(user, "Please scan an object with the implanter first.") return ..() /obj/item/weapon/implanter/compressed/afterattack(atom/A, mob/user as mob, proximity) if(!proximity) return + if(!active) + to_chat(user, "Activate \the [src.name] first.") + return if(istype(A,/obj/item) && imp) var/obj/item/weapon/implant/compressed/c = imp if (c.scanned) - user << "Something is already scanned inside the implant!" + to_chat(user, "Something is already scanned inside the implant!") return c.scanned = A + if(istype(A, /obj/item/weapon/storage)) + to_chat(user, "You can't store \the [A.name] in this!") + c.scanned = null + return if(istype(A.loc,/mob/living/carbon/human)) var/mob/living/carbon/human/H = A.loc H.remove_from_mob(A) diff --git a/code/game/objects/items/weapons/implants/implantpad.dm b/code/game/objects/items/weapons/implants/implantpad.dm index dc054536ac..ebc01c6ebb 100644 --- a/code/game/objects/items/weapons/implants/implantpad.dm +++ b/code/game/objects/items/weapons/implants/implantpad.dm @@ -82,7 +82,7 @@ if (href_list["tracking_id"]) var/obj/item/weapon/implant/tracking/T = src.case.imp T.id += text2num(href_list["tracking_id"]) - T.id = min(100, T.id) + T.id = min(1000, T.id) T.id = max(1, T.id) if (istype(src.loc, /mob)) diff --git a/code/game/objects/items/weapons/material/gravemarker.dm b/code/game/objects/items/weapons/material/gravemarker.dm new file mode 100644 index 0000000000..f50416b05d --- /dev/null +++ b/code/game/objects/items/weapons/material/gravemarker.dm @@ -0,0 +1,80 @@ +/obj/item/weapon/material/gravemarker + name = "grave marker" + desc = "An object used in marking graves." + icon_state = "gravemarker" + w_class = ITEMSIZE_LARGE + fragile = 1 + force_divisor = 0.65 + thrown_force_divisor = 0.25 + + var/icon_changes = 1 //Does the sprite change when you put words on it? + var/grave_name = "" //Name of the intended occupant + var/epitaph = "" //A quick little blurb + +/obj/item/weapon/material/gravemarker/attackby(obj/item/weapon/W, mob/user as mob) + if(istype(W, /obj/item/weapon/screwdriver)) + var/carving_1 = sanitizeSafe(input(user, "Who is \the [src.name] for?", "Gravestone Naming", null) as text, MAX_NAME_LEN) + if(carving_1) + user.visible_message("[user] starts carving \the [src.name].", "You start carving \the [src.name].") + if(do_after(user, material.hardness * W.toolspeed)) + user.visible_message("[user] carves something into \the [src.name].", "You carve your message into \the [src.name].") + grave_name += carving_1 + update_icon() + var/carving_2 = sanitizeSafe(input(user, "What message should \the [src.name] have?", "Epitaph Carving", null) as text, MAX_NAME_LEN) + if(carving_2) + user.visible_message("[user] starts carving \the [src.name].", "You start carving \the [src.name].") + if(do_after(user, material.hardness * W.toolspeed)) + user.visible_message("[user] carves something into \the [src.name].", "You carve your message into \the [src.name].") + epitaph += carving_2 + update_icon() + if(istype(W, /obj/item/weapon/wrench)) + user.visible_message("[user] starts carving \the [src.name].", "You start carving \the [src.name].") + if(do_after(user, material.hardness * W.toolspeed)) + material.place_dismantled_product(get_turf(src)) + user.visible_message("[user] dismantles down \the [src.name].", "You dismantle \the [src.name].") + qdel(src) + ..() + +/obj/item/weapon/material/gravemarker/examine(mob/user) + ..() + if(get_dist(src, user) < 4) + if(grave_name) + to_chat(user, "Here Lies [grave_name]") + if(get_dist(src, user) < 2) + if(epitaph) + to_chat(user, epitaph) + +/obj/item/weapon/material/gravemarker/update_icon() + if(icon_changes) + if(grave_name && epitaph) + icon_state = "[initial(icon_state)]_3" + else if(grave_name) + icon_state = "[initial(icon_state)]_1" + else if(epitaph) + icon_state = "[initial(icon_state)]_2" + else + icon_state = initial(icon_state) + + ..() + +/obj/item/weapon/material/gravemarker/attack_self(mob/user) + src.add_fingerprint(user) + + if(!isturf(user.loc)) + return 0 + + if(locate(/obj/structure/gravemarker, user.loc)) + to_chat(user, "There's already something there.") + return 0 + else + to_chat(user, "You begin to place \the [src.name].") + if(!do_after(usr, 10)) + return 0 + var/obj/structure/gravemarker/G = new /obj/structure/gravemarker/(user.loc, src.get_material()) + to_chat(user, "You place \the [src.name].") + G.grave_name = grave_name + G.epitaph = epitaph + G.add_fingerprint(usr) + G.dir = user.dir + qdel_null(src) + return \ No newline at end of file diff --git a/code/game/objects/items/weapons/material/material_armor.dm b/code/game/objects/items/weapons/material/material_armor.dm index 990ae37659..ecd328f3ab 100644 --- a/code/game/objects/items/weapons/material/material_armor.dm +++ b/code/game/objects/items/weapons/material/material_armor.dm @@ -233,6 +233,10 @@ Protectiveness | Armor % icon_state = "bucket" armor = list(melee = 5, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0) +/obj/item/clothing/head/helmet/bucket/wood + name = "wooden bucket" + icon_state = "woodbucket" + /obj/item/clothing/head/helmet/bucket/attackby(var/obj/O, mob/user) if(istype(O, /obj/item/stack/material)) var/obj/item/stack/material/S = O diff --git a/code/game/objects/items/weapons/material/misc.dm b/code/game/objects/items/weapons/material/misc.dm index 2d85bc0a66..9d8792dab4 100644 --- a/code/game/objects/items/weapons/material/misc.dm +++ b/code/game/objects/items/weapons/material/misc.dm @@ -85,19 +85,4 @@ thrown_force_divisor = 0.25 // as above dulled_divisor = 0.75 //Still metal on a long pole w_class = ITEMSIZE_SMALL - attack_verb = list("slashed", "sliced", "cut", "clawed") - -/obj/item/weapon/material/scythe - icon_state = "scythe0" - name = "scythe" - desc = "A sharp and curved blade on a long fibremetal handle, this tool makes it easy to reap what you sow." - force_divisor = 0.275 // 16 with hardness 60 (steel) - thrown_force_divisor = 0.25 // 5 with weight 20 (steel) - sharp = 1 - edge = 1 - throw_speed = 1 - throw_range = 3 - w_class = ITEMSIZE_LARGE - slot_flags = SLOT_BACK - origin_tech = list(TECH_MATERIAL = 2, TECH_COMBAT = 2) - attack_verb = list("chopped", "sliced", "cut", "reaped") + attack_verb = list("slashed", "sliced", "cut", "clawed") \ No newline at end of file diff --git a/code/game/objects/items/weapons/material/twohanded.dm b/code/game/objects/items/weapons/material/twohanded.dm index 5cb404a2b8..8f329c6dec 100644 --- a/code/game/objects/items/weapons/material/twohanded.dm +++ b/code/game/objects/items/weapons/material/twohanded.dm @@ -123,6 +123,15 @@ var/obj/effect/plant/P = A P.die_off() +/obj/item/weapon/material/twohanded/fireaxe/scythe + icon_state = "scythe0" + base_icon = "scythe" + name = "scythe" + desc = "A sharp and curved blade on a long fibremetal handle, this tool makes it easy to reap what you sow." + force_divisor = 0.65 + origin_tech = list(TECH_MATERIAL = 2, TECH_COMBAT = 2) + attack_verb = list("chopped", "sliced", "cut", "reaped") + //spears, bay edition /obj/item/weapon/material/twohanded/spear icon_state = "spearglass0" diff --git a/code/game/objects/items/weapons/storage/backpack.dm b/code/game/objects/items/weapons/storage/backpack.dm index 0430684f36..e7c5d9068a 100644 --- a/code/game/objects/items/weapons/storage/backpack.dm +++ b/code/game/objects/items/weapons/storage/backpack.dm @@ -180,6 +180,11 @@ desc = "A large dufflebag for holding extra tools and supplies." icon_state = "duffle_eng" +/obj/item/weapon/storage/backpack/dufflebag/sci + name = "science dufflebag" + desc = "A large dufflebag for holding circuits and beakers." + icon_state = "duffle_sci" + /* * Satchel Types */ diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm index 93549deb71..38130f2739 100644 --- a/code/game/objects/items/weapons/storage/belt.dm +++ b/code/game/objects/items/weapons/storage/belt.dm @@ -239,7 +239,51 @@ new /obj/item/weapon/crowbar/alien(src) new /obj/item/weapon/wirecutters/alien(src) new /obj/item/device/multitool/alien(src) - new /obj/item/stack/cable_coil(src,30,"white") + new /obj/item/stack/cable_coil/alien(src) + +/obj/item/weapon/storage/belt/medical/alien + name = "alien belt" + desc = "A belt(?) that can hold things." + icon = 'icons/obj/abductor.dmi' + icon_state = "belt" + item_state = "security" + can_hold = list( + /obj/item/device/healthanalyzer, + /obj/item/weapon/dnainjector, + /obj/item/weapon/reagent_containers/dropper, + /obj/item/weapon/reagent_containers/glass/beaker, + /obj/item/weapon/reagent_containers/glass/bottle, + /obj/item/weapon/reagent_containers/pill, + /obj/item/weapon/reagent_containers/syringe, + /obj/item/weapon/flame/lighter/zippo, + /obj/item/weapon/storage/fancy/cigarettes, + /obj/item/weapon/storage/pill_bottle, + /obj/item/stack/medical, + /obj/item/device/radio/headset, + /obj/item/device/pda, + /obj/item/taperoll, + /obj/item/device/megaphone, + /obj/item/clothing/mask/surgical, + /obj/item/clothing/head/surgery, + /obj/item/clothing/gloves, + /obj/item/weapon/reagent_containers/hypospray, + /obj/item/clothing/glasses, + /obj/item/weapon/crowbar, + /obj/item/device/flashlight, + /obj/item/weapon/cell/device, + /obj/item/weapon/extinguisher/mini, + /obj/item/weapon/surgical + ) + +/obj/item/weapon/storage/belt/medical/alien/New() + ..() + new /obj/item/weapon/surgical/scalpel/alien(src) + new /obj/item/weapon/surgical/hemostat/alien(src) + new /obj/item/weapon/surgical/retractor/alien(src) + new /obj/item/weapon/surgical/circular_saw/alien(src) + new /obj/item/weapon/surgical/FixOVein/alien(src) + new /obj/item/weapon/surgical/bone_clamp/alien(src) + new /obj/item/weapon/surgical/cautery/alien(src) /obj/item/weapon/storage/belt/champion name = "championship belt" diff --git a/code/game/objects/items/weapons/storage/wallets.dm b/code/game/objects/items/weapons/storage/wallets.dm index 47de448abf..30d81e1ba9 100644 --- a/code/game/objects/items/weapons/storage/wallets.dm +++ b/code/game/objects/items/weapons/storage/wallets.dm @@ -24,7 +24,7 @@ /obj/item/weapon/reagent_containers/dropper, /obj/item/weapon/screwdriver, /obj/item/weapon/stamp, - /obj/item/weapon/permit + /obj/item/clothing/accessory/permit ) slot_flags = SLOT_ID diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index 1b54df33e6..f468d1d77e 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -249,4 +249,35 @@ results += ..() - return results \ No newline at end of file + return results + +// Rare version of a baton that causes lesser lifeforms to really hate the user and attack them. +/obj/item/weapon/melee/baton/shocker + name = "shocker" + desc = "A device that appears to arc electricity into a target to incapacitate or otherwise hurt them, similar to a stun baton. It looks inefficent." + description_info = "Hitting a lesser lifeform with this while it is on will compel them to attack you above other nearby targets. Otherwise \ + it works like a regular stun baton, just less effectively." + icon_state = "shocker" + force = 10 + throwforce = 5 + agonyforce = 25 // Less efficent than a regular baton. + attack_verb = list("poked") + +/obj/item/weapon/melee/baton/shocker/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) + ..(target, user, hit_zone) + if(istype(target, /mob/living/simple_animal) && status) + var/mob/living/simple_animal/SA = target + SA.taunt(user) + +// Borg version, for the lost module. +/obj/item/weapon/melee/baton/shocker/robot + +/obj/item/weapon/melee/baton/shocker/robot/attack_self(mob/user) + //try to find our power cell + var/mob/living/silicon/robot/R = loc + if (istype(R)) + bcell = R.cell + return ..() + +/obj/item/weapon/melee/baton/shocker/robot/attackby(obj/item/weapon/W, mob/user) + return \ No newline at end of file diff --git a/code/game/objects/items/weapons/surgery_tools.dm b/code/game/objects/items/weapons/surgery_tools.dm index 9364f1b859..96f5e30f69 100644 --- a/code/game/objects/items/weapons/surgery_tools.dm +++ b/code/game/objects/items/weapons/surgery_tools.dm @@ -8,10 +8,6 @@ * Circular Saw */ -/* - * Retractor - */ - /obj/item/weapon/surgical name = "Surgical tool" desc = "This shouldn't be here, ahelp it." @@ -25,10 +21,13 @@ return 0 ..() +/* + * Retractor + */ + /obj/item/weapon/surgical/retractor name = "retractor" desc = "Retracts stuff." - icon = 'icons/obj/surgery.dmi' icon_state = "retractor" matter = list(DEFAULT_WALL_MATERIAL = 10000, "glass" = 5000) origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1) @@ -167,9 +166,82 @@ /obj/item/weapon/surgical/bonesetter name = "bone setter" desc = "Put them in their place." - icon_state = "bone setter" + icon_state = "bone_setter" force = 8.0 throwforce = 9.0 throw_speed = 3 throw_range = 5 attack_verb = list("attacked", "hit", "bludgeoned") + +/obj/item/weapon/surgical/bone_clamp + name = "bone clamp" + desc = "The best way to get a bone fixed fast." + icon_state = "bone_clamp" + force = 8 + throwforce = 9 + throw_speed = 3 + throw_range = 5 + attack_verb = list("attacked", "hit", "bludgeoned") + +// Cyborg Tools + +/obj/item/weapon/surgical/retractor/cyborg + toolspeed = 0.5 + +/obj/item/weapon/surgical/hemostat/cyborg + toolspeed = 0.5 + +/obj/item/weapon/surgical/cautery/cyborg + toolspeed = 0.5 + +/obj/item/weapon/surgical/surgicaldrill/cyborg + toolspeed = 0.5 + +/obj/item/weapon/surgical/scalpel/cyborg + toolspeed = 0.5 + +/obj/item/weapon/surgical/circular_saw/cyborg + toolspeed = 0.5 + +/obj/item/weapon/surgical/bonegel/cyborg + toolspeed = 0.5 + +/obj/item/weapon/surgical/FixOVein/cyborg + toolspeed = 0.5 + +/obj/item/weapon/surgical/bonesetter/cyborg + toolspeed = 0.5 + + +// Alien Tools +/obj/item/weapon/surgical/retractor/alien + icon = 'icons/obj/abductor.dmi' + toolspeed = 0.25 + +/obj/item/weapon/surgical/hemostat/alien + icon = 'icons/obj/abductor.dmi' + toolspeed = 0.25 + +/obj/item/weapon/surgical/cautery/alien + icon = 'icons/obj/abductor.dmi' + toolspeed = 0.25 + +/obj/item/weapon/surgical/surgicaldrill/alien + icon = 'icons/obj/abductor.dmi' + toolspeed = 0.25 + +/obj/item/weapon/surgical/scalpel/alien + icon = 'icons/obj/abductor.dmi' + toolspeed = 0.25 + +/obj/item/weapon/surgical/circular_saw/alien + icon = 'icons/obj/abductor.dmi' + toolspeed = 0.25 + +/obj/item/weapon/surgical/FixOVein/alien + icon = 'icons/obj/abductor.dmi' + toolspeed = 0.25 + +/obj/item/weapon/surgical/bone_clamp/alien + icon = 'icons/obj/abductor.dmi' + toolspeed = 0.75 \ No newline at end of file diff --git a/code/game/objects/items/weapons/teleportation.dm b/code/game/objects/items/weapons/teleportation.dm index b27ef63a4a..e0e11a6285 100644 --- a/code/game/objects/items/weapons/teleportation.dm +++ b/code/game/objects/items/weapons/teleportation.dm @@ -79,13 +79,8 @@ Frequency: src.temp += "Extranneous Signals:
" for (var/obj/item/weapon/implant/tracking/W in world) - if (!W.implanted || !(istype(W.loc,/obj/item/organ/external) || ismob(W.loc))) + if (!W.implanted || !(istype(W.loc,/obj/item/organ/external) || ismob(W.loc) || W.malfunction)) continue - else - var/mob/M = W.loc - if (M.stat == 2) - if (M.timeofdeath + 6000 < world.time) - continue var/turf/tr = get_turf(W) if (tr.z == sr.z && tr) diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 7d928f8e8d..fb65fdf195 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -312,19 +312,19 @@ /obj/item/weapon/weldingtool/examine(mob/user) if(..(user, 0)) if(max_fuel) - user << text("\icon[] [] contains []/[] units of fuel!", src, src.name, get_fuel(),src.max_fuel ) + to_chat(user, text("\icon[] The [] contains []/[] units of fuel!", src, src.name, get_fuel(),src.max_fuel )) /obj/item/weapon/weldingtool/attackby(obj/item/W as obj, mob/living/user as mob) if(istype(W,/obj/item/weapon/screwdriver)) if(welding) - user << "Stop welding first!" + to_chat(user, "Stop welding first!") return status = !status if(status) - user << "You secure the welder." + to_chat(user, "You secure the welder.") else - user << "The welder can now be attached and modified." + to_chat(user, "The welder can now be attached and modified.") src.add_fingerprint(user) return @@ -380,16 +380,16 @@ if (istype(O, /obj/structure/reagent_dispensers/fueltank) && get_dist(src,O) <= 1) if(!welding && max_fuel) O.reagents.trans_to_obj(src, max_fuel) - user << "Welder refueled" + to_chat(user, "Welder refueled") playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) return else if(!welding) - user << "[src] doesn't use fuel." + to_chat(user, "[src] doesn't use fuel.") return else message_admins("[key_name_admin(user)] triggered a fueltank explosion with a welding tool.") log_game("[key_name(user)] triggered a fueltank explosion with a welding tool.") - user << "You begin welding on the fueltank and with a moment of lucidity you realize, this might not have been the smartest thing you've ever done." + to_chat(user, "You begin welding on the fueltank and with a moment of lucidity you realize, this might not have been the smartest thing you've ever done.") var/obj/structure/reagent_dispensers/fueltank/tank = O tank.explode() return @@ -429,7 +429,7 @@ return 1 else if(M) - M << "You need more welding fuel to complete this task." + to_chat(M, "You need more welding fuel to complete this task.") update_icon() return 0 @@ -509,7 +509,7 @@ if(set_welding && !welding) if (get_fuel() > 0) if(M) - M << "You switch the [src] on." + to_chat(M, "You switch the [src] on.") else if(T) T.visible_message("\The [src] turns on.") playsound(loc, acti_sound, 50, 1) @@ -524,14 +524,14 @@ else if(M) var/msg = max_fuel ? "welding fuel" : "charge" - M << "You need more [msg] to complete this task." + to_chat(M, "You need more [msg] to complete this task.") return //Otherwise else if(!set_welding && welding) if(!always_process) processing_objects -= src if(M) - M << "You switch \the [src] off." + to_chat(M, "You switch \the [src] off.") else if(T) T.visible_message("\The [src] turns off.") playsound(loc, deac_sound, 50, 1) @@ -557,29 +557,29 @@ if(H.nif && H.nif.flag_check(NIF_V_UVFILTER,NIF_FLAGS_VISION)) return //VOREStation Add - NIF switch(safety) if(1) - usr << "Your eyes sting a little." + to_chat(usr, "Your eyes sting a little.") E.damage += rand(1, 2) if(E.damage > 12) user.eye_blurry += rand(3,6) if(0) - usr << "Your eyes burn." + to_chat(usr, "Your eyes burn.") E.damage += rand(2, 4) if(E.damage > 10) E.damage += rand(4,10) if(-1) - usr << "Your thermals intensify the welder's glow. Your eyes itch and burn severely." + to_chat(usr, "Your thermals intensify the welder's glow. Your eyes itch and burn severely.") user.eye_blurry += rand(12,20) E.damage += rand(12, 16) if(safety<2) if(E.damage > 10) - user << "Your eyes are really starting to hurt. This can't be good for you!" + to_chat(user, "Your eyes are really starting to hurt. This can't be good for you!") if (E.damage >= E.min_broken_damage) - user << "You go blind!" + to_chat(user, "You go blind!") user.sdisabilities |= BLIND else if (E.damage >= E.min_bruised_damage) - user << "You go blind!" + to_chat(user, "You go blind!") user.Blind(5) user.eye_blurry = 5 user.disabilities |= NEARSIGHTED @@ -689,16 +689,19 @@ cell_type = null /obj/item/weapon/weldingtool/electric/examine(mob/user) - ..() - if(power_supply) - user << text("\icon[] [] has [] charge left.", src, src.name, get_fuel()) - else - user << text("\icon[] [] has power for no power cell!", src, src.name) + if(get_dist(src, user) > 1) + to_chat(user, desc) + else // The << need to stay, for some reason + if(power_supply) + user << text("\icon[] The [] has [] charge left.", src, src.name, get_fuel()) + else + user << text("\icon[] The [] has no power cell!", src, src.name) /obj/item/weapon/weldingtool/electric/get_fuel() if(use_external_power) var/obj/item/weapon/cell/external = get_external_power_supply() - return external.charge + if(external) + return external.charge else if(power_supply) return power_supply.charge else @@ -707,11 +710,11 @@ /obj/item/weapon/weldingtool/electric/get_max_fuel() if(use_external_power) var/obj/item/weapon/cell/external = get_external_power_supply() - return external.maxcharge + if(external) + return external.maxcharge else if(power_supply) return power_supply.maxcharge - else - return 0 + return 0 /obj/item/weapon/weldingtool/electric/remove_fuel(var/amount = 1, var/mob/M = null) if(!welding) @@ -728,7 +731,7 @@ return 1 else if(M) - M << "You need more energy to complete this task." + to_chat(M, "You need more energy to complete this task.") update_icon() return 0 @@ -738,7 +741,7 @@ power_supply.update_icon() user.put_in_hands(power_supply) power_supply = null - user << "You remove the cell from the [src]." + to_chat(user, "You remove the cell from the [src].") setWelding(0) update_icon() return @@ -753,12 +756,12 @@ user.drop_item() W.loc = src power_supply = W - user << "You install a cell in \the [src]." + to_chat(user, "You install a cell in \the [src].") update_icon() else - user << "\The [src] already has a cell." + to_chat(user, "\The [src] already has a cell.") else - user << "\The [src] cannot use that type of cell." + to_chat(user, "\The [src] cannot use that type of cell.") else ..() @@ -779,6 +782,8 @@ /obj/item/weapon/weldingtool/electric/mounted use_external_power = 1 +/obj/item/weapon/weldingtool/electric/mounted/cyborg + toolspeed = 0.5 /* * Crowbar */ @@ -815,7 +820,7 @@ return ..() if(!welding) - user << "You'll need to turn [src] on to patch the damage on [H]'s [S.name]!" + to_chat(user, "You'll need to turn [src] on to patch the damage on [H]'s [S.name]!") return 1 if(S.robo_repair(15, BRUTE, "some dents", src, user)) @@ -846,7 +851,7 @@ icon_state = "jaws_pry" item_state = "jawsoflife" matter = list(MAT_METAL=150, MAT_SILVER=50) - origin_tech = list(TECH_MATERIALS = 2, TECH_ENGINEERING = 2) + origin_tech = list(TECH_MATERIAL = 2, TECH_ENGINEERING = 2) usesound = 'sound/items/jaws_pry.ogg' force = 15 toolspeed = 0.25 @@ -879,9 +884,9 @@ /obj/item/weapon/combitool/examine() ..() if(loc == usr && tools.len) - usr << "It has the following fittings:" + to_chat(usr, "It has the following fittings:") for(var/obj/item/tool in tools) - usr << "\icon[tool] - [tool.name][tools[current_tool]==tool?" (selected)":""]" + to_chat(usr, "\icon[tool] - [tool.name][tools[current_tool]==tool?" (selected)":""]") /obj/item/weapon/combitool/New() ..() @@ -892,9 +897,9 @@ if(++current_tool > tools.len) current_tool = 1 var/obj/item/tool = tools[current_tool] if(!tool) - user << "You can't seem to find any fittings in \the [src]." + to_chat(user, "You can't seem to find any fittings in \the [src].") else - user << "You switch \the [src] to the [tool.name] fitting." + to_chat(user, "You switch \the [src] to the [tool.name] fitting.") return 1 /obj/item/weapon/combitool/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) diff --git a/code/game/objects/random/random.dm b/code/game/objects/random/random.dm index 0c26acc495..b18e1500aa 100644 --- a/code/game/objects/random/random.dm +++ b/code/game/objects/random/random.dm @@ -219,7 +219,7 @@ prob(1);/obj/item/clothing/suit/storage/vest/heavy/merc, prob(1);/obj/item/weapon/beartrap, prob(1);/obj/item/weapon/handcuffs/fuzzy, - prob(1);/obj/item/weapon/legcuffs, + prob(1);/obj/item/weapon/handcuffs/legcuffs, prob(2);/obj/item/weapon/reagent_containers/syringe/drugs, prob(1);/obj/item/weapon/reagent_containers/syringe/steroid, prob(4);/obj/item/device/radio_jammer, diff --git a/code/game/objects/structures/catwalk.dm b/code/game/objects/structures/catwalk.dm index 25966efadb..0bf155dc49 100644 --- a/code/game/objects/structures/catwalk.dm +++ b/code/game/objects/structures/catwalk.dm @@ -6,9 +6,13 @@ name = "catwalk" desc = "Cats really don't like these things." density = 0 + var/health = 100 + var/maxhealth = 100 anchored = 1.0 /obj/structure/catwalk/initialize() + for(var/obj/structure/catwalk/O in range(1)) + O.update_icon() for(var/obj/structure/catwalk/C in get_turf(src)) if(C != src) warning("Duplicate [type] in [loc] ([x], [y], [z])") @@ -18,6 +22,7 @@ /obj/structure/catwalk/Destroy() var/turf/location = loc . = ..() + location.alpha = initial(location.alpha) for(var/obj/structure/catwalk/L in orange(location, 1)) L.update_icon() @@ -55,6 +60,8 @@ qdel(src) if(2.0) qdel(src) + if(3.0) + qdel(src) return /obj/structure/catwalk/attackby(obj/item/C as obj, mob/user as mob) @@ -67,6 +74,14 @@ new /obj/item/stack/rods(src.loc) new /obj/structure/lattice(src.loc) qdel(src) + if(istype(C, /obj/item/weapon/screwdriver)) + if(health < maxhealth) + to_chat(user, "You begin repairing \the [src.name] with \the [C.name].") + if(do_after(user, 20, src)) + health = maxhealth + else + take_damage(C.force) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) return ..() /obj/structure/catwalk/Crossed() @@ -79,4 +94,12 @@ return 1 if(target && target.z < src.z) return 0 - return 1 \ No newline at end of file + return 1 + +/obj/structure/catwalk/proc/take_damage(amount) + health -= amount + if(health <= 0) + visible_message("\The [src] breaks down!") + playsound(loc, 'sound/effects/grillehit.ogg', 50, 1) + new /obj/item/stack/rods(get_turf(src)) + Destroy() \ No newline at end of file diff --git a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm index a09f70f55d..ac58f643a2 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm @@ -20,6 +20,10 @@ new /obj/item/clothing/mask/gas(src) new /obj/item/clothing/suit/storage/hooded/wintercoat/science(src) new /obj/item/clothing/shoes/boots/winter/science(src) + if(prob(50)) + new /obj/item/weapon/storage/backpack/dufflebag/sci(src) + else + new /obj/item/weapon/storage/backpack/toxins(src) return diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm index 879efe3f9f..48c567fd20 100644 --- a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm +++ b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm @@ -369,11 +369,15 @@ new /obj/item/clothing/suit/storage/hooded/wintercoat/science(src) new /obj/item/clothing/shoes/boots/winter/science(src) new /obj/item/weapon/storage/backpack/toxins(src) - new /obj/item/weapon/storage/backpack/toxins(src) new /obj/item/weapon/storage/backpack/satchel/tox(src) - new /obj/item/weapon/storage/backpack/satchel/tox(src) - return - + if(prob(50)) + new /obj/item/weapon/storage/backpack/dufflebag/sci(src) + else + new /obj/item/weapon/storage/backpack/satchel/tox(src) + if(prob(50)) + new /obj/item/weapon/storage/backpack/dufflebag/sci(src) + else + new /obj/item/weapon/storage/backpack/satchel/tox(src) /obj/structure/closet/wardrobe/robotics_black name = "robotics wardrobe" icon_state = "black" @@ -390,9 +394,15 @@ new /obj/item/clothing/gloves/black(src) new /obj/item/clothing/gloves/black(src) new /obj/item/weapon/storage/backpack/toxins(src) - new /obj/item/weapon/storage/backpack/toxins(src) - new /obj/item/weapon/storage/backpack/satchel/tox(src) + if(prob(50)) + new /obj/item/weapon/storage/backpack/dufflebag/sci(src) + else + new /obj/item/weapon/storage/backpack/satchel/tox(src) new /obj/item/weapon/storage/backpack/satchel/tox(src) + if(prob(50)) + new /obj/item/weapon/storage/backpack/dufflebag/sci(src) + else + new /obj/item/weapon/storage/backpack/satchel/tox(src) return diff --git a/code/game/objects/structures/ghost_pods/ghost_pods.dm b/code/game/objects/structures/ghost_pods/ghost_pods.dm new file mode 100644 index 0000000000..7beba29caa --- /dev/null +++ b/code/game/objects/structures/ghost_pods/ghost_pods.dm @@ -0,0 +1,80 @@ +// These are used to spawn a specific mob when triggered, with the mob controlled by a player pulled from the ghost pool, hense its name. +/obj/structure/ghost_pod + name = "Base Ghost Pod" + desc = "If you can read me, someone don goofed." + icon = 'icons/obj/structures.dmi' + var/ghost_query_type = null + var/icon_state_opened = null // Icon to switch to when 'used'. + var/used = FALSE + var/busy = FALSE // Don't spam ghosts by spamclicking. + +// Call this to get a ghost volunteer. +/obj/structure/ghost_pod/proc/trigger() + if(!ghost_query_type) + return FALSE + if(busy) + return FALSE + + busy = TRUE + var/datum/ghost_query/Q = new ghost_query_type() + var/list/winner = Q.query() + busy = FALSE + if(winner.len) + var/mob/observer/dead/D = winner[1] + create_occupant(D) + return TRUE + else + return FALSE + +// Override this to create whatever mob you need. Be sure to call ..() if you don't want it to make infinite mobs. +/obj/structure/ghost_pod/proc/create_occupant(var/mob/M) + used = TRUE + icon_state = icon_state_opened + return TRUE + + +// This type is triggered manually by a player discovering the pod and deciding to open it. +/obj/structure/ghost_pod/manual + var/confirm_before_open = FALSE // Recommended to be TRUE if the pod contains a surprise. + +/obj/structure/ghost_pod/manual/attack_hand(var/mob/living/user) + if(!used) + if(confirm_before_open) + if(alert(user, "Are you sure you want to open \the [src]?", "Confirm", "No", "Yes") == "No") + return + trigger() + +/obj/structure/ghost_pod/manual/attack_ai(var/mob/living/silicon/user) + if(Adjacent(user)) + attack_hand(user) // Borgs can open pods. + +// This type is triggered on a timer, as opposed to needing another player to 'open' the pod. Good for away missions. +/obj/structure/ghost_pod/automatic + var/delay_to_self_open = 10 MINUTES // How long to wait for first attempt. Note that the timer by default starts when the pod is created. + var/delay_to_try_again = 20 MINUTES // How long to wait if first attempt fails. Set to 0 to never try again. + +/obj/structure/ghost_pod/automatic/initialize() + ..() + spawn(delay_to_self_open) + if(src) + trigger() + +/obj/structure/ghost_pod/automatic/trigger() + . = ..() + if(. == FALSE) // If we failed to get a volunteer, try again later if allowed to. + if(delay_to_try_again) + spawn(delay_to_try_again) + if(src) + trigger() + + +// This type is triggered by a ghost clicking on it, as opposed to a living player. A ghost query type isn't needed. +/obj/structure/ghost_pod/ghost_activated + description_info = "A ghost can click on this to return to the round as whatever is contained inside this object." + +/obj/structure/ghost_pod/ghost_activated/attack_ghost(var/mob/observer/dead/user) + if(used) + to_chat(user, "Another spirit appears to have gotten to \the [src] before you. Sorry.") + return + + create_occupant(user) \ No newline at end of file diff --git a/code/game/objects/structures/ghost_pods/silicon.dm b/code/game/objects/structures/ghost_pods/silicon.dm new file mode 100644 index 0000000000..a204437bc3 --- /dev/null +++ b/code/game/objects/structures/ghost_pods/silicon.dm @@ -0,0 +1,61 @@ + +// These are found on the surface, and contain a drone (braintype, inside a borg shell), with a special module and semi-random laws. +/obj/structure/ghost_pod/manual/lost_drone + name = "drone pod" + desc = "This is a pod which appears to contain a drone. You might be able to reactivate it, if you're brave enough." + description_info = "This contains a dormant drone, which can be activated. The drone will be another player, once activated. \ + The laws the drone has will most likely not be the ones you're used to." + icon_state = "borg_pod_closed" + icon_state_opened = "borg_pod_opened" + density = TRUE + ghost_query_type = /datum/ghost_query/lost_drone + confirm_before_open = TRUE + +/obj/structure/ghost_pod/manual/lost_drone/trigger() + ..() + visible_message("\The [src] appears to be attempting to restart the robot contained inside.") + log_and_message_admins("is attempting to open \a [src].") + +/obj/structure/ghost_pod/manual/lost_drone/create_occupant(var/mob/M) + density = FALSE + var/mob/living/silicon/robot/lost/randomlaws/R = new(get_turf(src)) + R.adjustBruteLoss(rand(5, 30)) + R.adjustFireLoss(rand(5, 10)) + if(M.mind) + M.mind.transfer_to(R) + // Put this text here before ckey change so that their laws are shown below it, since borg login() shows it. + to_chat(M, "You are a Lost Drone, discovered inside the wreckage of your previous home. \ + Something has reactivated you, with their intentions unknown to you, and yours unknown to them. They are a foreign entity, \ + however they did free you from your pod...") + to_chat(M, "Be sure to examine your currently loaded lawset closely. Remember, your \ + definiton of 'the station' is where your pod is, and unless your laws say otherwise, the entity that released you \ + from the pod is not a crewmember.") + R.ckey = M.ckey + visible_message("As \the [src] opens, the eyes of the robot flicker as it is activated.") + R.Namepick() + log_and_message_admins("successfully opened \a [src] and got a Lost Drone.") + ..() + +/obj/structure/ghost_pod/automatic/gravekeeper_drone + name = "drone pod" + desc = "This is a pod which appears to contain a drone. You might be able to reactivate it, if you're brave enough." + description_info = "This contains a dormant drone, which may activate at any moment. The drone will be another player, once activated. \ + The laws the drone has will most likely not be the ones you're used to." + icon_state = "borg_pod_closed" + icon_state_opened = "borg_pod_opened" + density = TRUE + ghost_query_type = /datum/ghost_query/gravekeeper_drone + +/obj/structure/ghost_pod/automatic/gravekeeper_drone/create_occupant(var/mob/M) + density = FALSE + var/mob/living/silicon/robot/gravekeeper/R = new(get_turf(src)) + if(M.mind) + M.mind.transfer_to(R) + // Put this text here before ckey change so that their laws are shown below it, since borg login() shows it. + to_chat(M, "You are a Gravekeeper Drone, activated once again to tend to the restful dead.") + to_chat(M, "Be sure to examine your currently loaded lawset closely. Remember, your \ + definiton of 'your gravesite' is where your pod is.") + R.ckey = M.ckey + visible_message("As \the [src] opens, the eyes of the robot flicker as it is activated.") + R.Namepick() + ..() \ No newline at end of file diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 14a724e029..37aeef7fd9 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -125,6 +125,12 @@ else return ..() +/obj/structure/girder/proc/take_damage(var/damage) + health -= damage + + if(health <= 0) + dismantle() + /obj/structure/girder/proc/construct_wall(obj/item/stack/material/S, mob/user) var/amount_to_use = reinf_material ? 1 : 2 if(S.get_amount() < amount_to_use) diff --git a/code/game/objects/structures/gravemarker.dm b/code/game/objects/structures/gravemarker.dm new file mode 100644 index 0000000000..a10cd0bf6e --- /dev/null +++ b/code/game/objects/structures/gravemarker.dm @@ -0,0 +1,137 @@ +/obj/structure/gravemarker + name = "grave marker" + desc = "An object used in marking graves." + icon_state = "gravemarker" + + density = 1 + anchored = 1 + throwpass = 1 + climbable = 1 + + layer = 3.1 //Above dirt piles + + //Maybe make these calculate based on material? + var/health = 100 + + var/grave_name = "" //Name of the intended occupant + var/epitaph = "" //A quick little blurb +// var/dir_locked = 0 //Can it be spun? Not currently implemented + + var/material/material + +/obj/structure/gravemarker/New(var/newloc, var/material_name) + ..(newloc) + if(!material_name) + material_name = "wood" + material = get_material_by_name("[material_name]") + if(!material) + qdel(src) + return + color = material.icon_colour + +/obj/structure/gravemarker/examine(mob/user) + ..() + if(get_dist(src, user) < 4) + if(grave_name) + to_chat(user, "Here Lies [grave_name]") + if(get_dist(src, user) < 2) + if(epitaph) + to_chat(user, epitaph) + +/obj/structure/gravemarker/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(!mover) + return 1 + if(istype(mover) && mover.checkpass(PASSTABLE)) + return 1 + if(get_dir(loc, target) & dir) + return !density + else + return 1 + +/obj/structure/gravemarker/CheckExit(atom/movable/O as mob|obj, target as turf) + if(istype(O) && O.checkpass(PASSTABLE)) + return 1 + if(get_dir(O.loc, target) == dir) + return 0 + return 1 + +/obj/structure/gravemarker/attackby(obj/item/weapon/W, mob/user as mob) + if(istype(W, /obj/item/weapon/screwdriver)) + var/carving_1 = sanitizeSafe(input(user, "Who is \the [src.name] for?", "Gravestone Naming", null) as text, MAX_NAME_LEN) + if(carving_1) + user.visible_message("[user] starts carving \the [src.name].", "You start carving \the [src.name].") + if(do_after(user, material.hardness * W.toolspeed)) + user.visible_message("[user] carves something into \the [src.name].", "You carve your message into \the [src.name].") + grave_name += carving_1 + update_icon() + var/carving_2 = sanitizeSafe(input(user, "What message should \the [src.name] have?", "Epitaph Carving", null) as text, MAX_NAME_LEN) + if(carving_2) + user.visible_message("[user] starts carving \the [src.name].", "You start carving \the [src.name].") + if(do_after(user, material.hardness * W.toolspeed)) + user.visible_message("[user] carves something into \the [src.name].", "You carve your message into \the [src.name].") + epitaph += carving_2 + update_icon() + return + if(istype(W, /obj/item/weapon/wrench)) + user.visible_message("[user] starts taking down \the [src.name].", "You start taking down \the [src.name].") + if(do_after(user, material.hardness * W.toolspeed)) + user.visible_message("[user] takes down \the [src.name].", "You take down \the [src.name].") + dismantle() + ..() + +/obj/structure/gravemarker/bullet_act(var/obj/item/projectile/Proj) + var/proj_damage = Proj.get_structure_damage() + if(!proj_damage) + return + + ..() + damage(proj_damage) + + return + +/obj/structure/gravemarker/ex_act(severity) + switch(severity) + if(1.0) + visible_message("\The [src] is blown apart!") + qdel(src) + return + if(2.0) + visible_message("\The [src] is blown apart!") + if(prob(50)) + dismantle() + else + qdel(src) + return + +/obj/structure/gravemarker/proc/damage(var/damage) + health -= damage + if(health <= 0) + visible_message("\The [src] falls apart!") + dismantle() + +/obj/structure/gravemarker/proc/dismantle() + material.place_dismantled_product(get_turf(src)) + qdel(src) + return + + +/obj/structure/gravemarker/verb/rotate() + set name = "Rotate Grave Marker" + set category = "Object" + set src in oview(1) + + if(anchored) + return + if(config.ghost_interaction) + src.set_dir(turn(src.dir, 90)) + return + else + if(istype(usr,/mob/living/simple_animal/mouse)) + return + if(!usr || !isturf(usr.loc)) + return + if(usr.stat || usr.restrained()) + return + + src.set_dir(turn(src.dir, 90)) + return \ No newline at end of file diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 70f7ceb630..5cb1af6711 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -239,3 +239,14 @@ if(air_group) return 0 //Make sure air doesn't drain ..() + +/obj/structure/grille/broken/cult + icon_state = "grillecult-b" + +/obj/structure/grille/rustic + name = "rustic grille" + desc = "A lattice of metal, arranged in an old, rustic fashion." + icon_state = "grillerustic" + +/obj/structure/grille/broken/rustic + icon_state = "grillerustic-b" diff --git a/code/game/objects/structures/railing.dm b/code/game/objects/structures/railing.dm index fc2807fede..98bae005f8 100644 --- a/code/game/objects/structures/railing.dm +++ b/code/game/objects/structures/railing.dm @@ -60,7 +60,7 @@ if(health <= 0) visible_message("\The [src] breaks down!") playsound(loc, 'sound/effects/grillehit.ogg', 50, 1) - new /obj/item/stack/rods(get_turf(usr)) + new /obj/item/stack/rods(get_turf(src)) qdel(src) /obj/structure/railing/proc/NeighborsCheck(var/UpdateNeighbors = 1) @@ -134,6 +134,9 @@ if(usr.incapacitated()) return 0 + if (!can_touch(usr) || ismouse(usr)) + return + if(anchored) to_chat(usr, "It is fastened to the floor therefore you can't rotate it!") return 0 @@ -150,6 +153,9 @@ if(usr.incapacitated()) return 0 + if (!can_touch(usr) || ismouse(usr)) + return + if(anchored) to_chat(usr, "It is fastened to the floor therefore you can't rotate it!") return 0 @@ -166,6 +172,9 @@ if(usr.incapacitated()) return 0 + if (!can_touch(usr) || ismouse(usr)) + return + if(anchored) to_chat(usr, "It is fastened to the floor therefore you can't flip it!") return 0 @@ -249,6 +258,7 @@ else playsound(loc, 'sound/effects/grillehit.ogg', 50, 1) take_damage(W.force) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) return ..() diff --git a/code/game/objects/structures/simple_doors.dm b/code/game/objects/structures/simple_doors.dm index 4e302e0e31..7312c1ebf9 100644 --- a/code/game/objects/structures/simple_doors.dm +++ b/code/game/objects/structures/simple_doors.dm @@ -42,7 +42,7 @@ /obj/structure/simple_door/Destroy() processing_objects -= src update_nearby_tiles() - ..() + return ..() /obj/structure/simple_door/get_material() return material @@ -194,5 +194,8 @@ /obj/structure/simple_door/wood/New(var/newloc,var/material_name) ..(newloc, "wood") +/obj/structure/simple_door/sifwood/New(var/newloc,var/material_name) + ..(newloc, "alien wood") + /obj/structure/simple_door/resin/New(var/newloc,var/material_name) ..(newloc, "resin") \ No newline at end of file diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index 90b754421b..0228b1d943 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -25,7 +25,7 @@ if(cistern && !open) if(!contents.len) - user << "The cistern is empty." + to_chat(user, "The cistern is empty.") return else var/obj/item/I = pick(contents) @@ -33,7 +33,7 @@ user.put_in_hands(I) else I.loc = get_turf(src) - user << "You find \an [I] in the cistern." + to_chat(user, "You find \an [I] in the cistern.") w_items -= I.w_class return @@ -45,7 +45,7 @@ /obj/structure/toilet/attackby(obj/item/I as obj, mob/living/user as mob) if(istype(I, /obj/item/weapon/crowbar)) - user << "You start to [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"]." + to_chat(user, "You start to [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"].") playsound(loc, 'sound/effects/stonedoor_openclose.ogg', 50, 1) if(do_after(user, 30)) user.visible_message("[user] [cistern ? "replaces the lid on the cistern" : "lifts the lid off the cistern"]!", "You [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"]!", "You hear grinding porcelain.") @@ -62,7 +62,7 @@ if(G.state>1) if(!GM.loc == get_turf(src)) - user << "[GM.name] needs to be on the toilet." + to_chat(user, "[GM.name] needs to be on the toilet.") return if(open && !swirlie) user.visible_message("[user] starts to give [GM.name] a swirlie!", "You start to give [GM.name] a swirlie!") @@ -76,19 +76,19 @@ user.visible_message("[user] slams [GM.name] into the [src]!", "You slam [GM.name] into the [src]!") GM.adjustBruteLoss(5) else - user << "You need a tighter grip." + to_chat(user, "You need a tighter grip.") if(cistern && !istype(user,/mob/living/silicon/robot)) //STOP PUTTING YOUR MODULES IN THE TOILET. if(I.w_class > 3) - user << "\The [I] does not fit." + to_chat(user, "\The [I] does not fit.") return if(w_items + I.w_class > 5) - user << "The cistern is full." + to_chat(user, "The cistern is full.") return user.drop_item() I.loc = src w_items += I.w_class - user << "You carefully place \the [I] into the cistern." + to_chat(user, "You carefully place \the [I] into the cistern.") return @@ -108,12 +108,12 @@ var/mob/living/GM = G.affecting if(G.state>1) if(!GM.loc == get_turf(src)) - user << "[GM.name] needs to be on the urinal." + to_chat(user, "[GM.name] needs to be on the urinal.") return user.visible_message("[user] slams [GM.name] into the [src]!", "You slam [GM.name] into the [src]!") GM.adjustBruteLoss(8) else - user << "You need a tighter grip." + to_chat(user, "You need a tighter grip.") @@ -158,10 +158,10 @@ /obj/machinery/shower/attackby(obj/item/I as obj, mob/user as mob) if(I.type == /obj/item/device/analyzer) - user << "The water temperature seems to be [watertemp]." + to_chat(user, "The water temperature seems to be [watertemp].") if(istype(I, /obj/item/weapon/wrench)) var/newtemp = input(user, "What setting would you like to set the temperature valve to?", "Water Temperature Valve") in temperature_settings - user << "You begin to adjust the temperature valve with \the [I]." + to_chat(user, "You begin to adjust the temperature valve with \the [I].") playsound(src.loc, I.usesound, 50, 1) if(do_after(user, 50 * I.toolspeed)) watertemp = newtemp @@ -321,9 +321,9 @@ if(ishuman(M)) var/mob/living/carbon/human/H = M if(temperature >= H.species.heat_level_1) - H << "The water is searing hot!" + to_chat(H, "The water is searing hot!") else if(temperature <= H.species.cold_level_1) - H << "The water is freezing cold!" + to_chat(H, "The water is freezing cold!") /obj/item/weapon/bikehorn/rubberducky name = "rubber ducky" @@ -346,7 +346,7 @@ if(!usr.Adjacent(src)) return ..() if(!thing.reagents || thing.reagents.total_volume == 0) - usr << "\The [thing] is empty." + to_chat(usr, "\The [thing] is empty.") return // Clear the vessel. visible_message("\The [usr] tips the contents of \the [thing] into \the [src].") @@ -360,7 +360,7 @@ if (H.hand) temp = H.organs_by_name["l_hand"] if(temp && !temp.is_usable()) - user << "You try to move your [temp.name], but cannot!" + to_chat(user, "You try to move your [temp.name], but cannot!") return if(isrobot(user) || isAI(user)) @@ -370,10 +370,10 @@ return if(busy) - user << "Someone's already washing here." + to_chat(user, "Someone's already washing here.") return - usr << "You start washing your hands." + to_chat(usr, "You start washing your hands.") busy = 1 sleep(40) @@ -389,7 +389,7 @@ /obj/structure/sink/attackby(obj/item/O as obj, mob/user as mob) if(busy) - user << "Someone's already washing here." + to_chat(user, "Someone's already washing here.") return var/obj/item/weapon/reagent_containers/RG = O @@ -417,7 +417,7 @@ return 1 else if(istype(O, /obj/item/weapon/mop)) O.reagents.add_reagent("water", 5) - user << "You wet \the [O] in \the [src]." + to_chat(user, "You wet \the [O] in \the [src].") playsound(loc, 'sound/effects/slosh.ogg', 25, 1) return @@ -427,7 +427,7 @@ var/obj/item/I = O if(!I || !istype(I,/obj/item)) return - usr << "You start washing \the [I]." + to_chat(usr, "You start washing \the [I].") busy = 1 sleep(40) diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm index 1a9ec67054..6a049a4e68 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -16,6 +16,8 @@ // This is not great. /turf/simulated/proc/wet_floor(var/wet_val = 1) + if(wet > 2) //Can't mop up ice + return spawn(0) wet = wet_val if(wet_overlay) diff --git a/code/game/turfs/simulated/floor_attackby.dm b/code/game/turfs/simulated/floor_attackby.dm index 44446af94e..ef36121b12 100644 --- a/code/game/turfs/simulated/floor_attackby.dm +++ b/code/game/turfs/simulated/floor_attackby.dm @@ -6,13 +6,13 @@ if(flooring) if(istype(C, /obj/item/weapon/crowbar)) if(broken || burnt) - user << "You remove the broken [flooring.descriptor]." + to_chat(user, "You remove the broken [flooring.descriptor].") make_plating() else if(flooring.flags & TURF_IS_FRAGILE) - user << "You forcefully pry off the [flooring.descriptor], destroying them in the process." + to_chat(user, "You forcefully pry off the [flooring.descriptor], destroying them in the process.") make_plating() else if(flooring.flags & TURF_REMOVE_CROWBAR) - user << "You lever off the [flooring.descriptor]." + to_chat(user, "You lever off the [flooring.descriptor].") make_plating(1) else return @@ -21,35 +21,35 @@ else if(istype(C, /obj/item/weapon/screwdriver) && (flooring.flags & TURF_REMOVE_SCREWDRIVER)) if(broken || burnt) return - user << "You unscrew and remove the [flooring.descriptor]." + to_chat(user, "You unscrew and remove the [flooring.descriptor].") make_plating(1) playsound(src, C.usesound, 80, 1) return else if(istype(C, /obj/item/weapon/wrench) && (flooring.flags & TURF_REMOVE_WRENCH)) - user << "You unwrench and remove the [flooring.descriptor]." + to_chat(user, "You unwrench and remove the [flooring.descriptor].") make_plating(1) playsound(src, C.usesound, 80, 1) return else if(istype(C, /obj/item/weapon/shovel) && (flooring.flags & TURF_REMOVE_SHOVEL)) - user << "You shovel off the [flooring.descriptor]." + to_chat(user, "You shovel off the [flooring.descriptor].") make_plating(1) playsound(src, 'sound/items/Deconstruct.ogg', 80, 1) return else if(istype(C, /obj/item/stack/cable_coil)) - user << "You must remove the [flooring.descriptor] first." + to_chat(user, "You must remove the [flooring.descriptor] first.") return else if(istype(C, /obj/item/stack/cable_coil)) if(broken || burnt) - user << "This section is too damaged to support anything. Use a welder to fix the damage." + to_chat(user, "This section is too damaged to support anything. Use a welder to fix the damage.") return var/obj/item/stack/cable_coil/coil = C coil.turf_place(src, user) return else if(istype(C, /obj/item/stack)) if(broken || burnt) - user << "This section is too damaged to support anything. Use a welder to fix the damage." + to_chat(user, "This section is too damaged to support anything. Use a welder to fix the damage.") return var/obj/item/stack/S = C var/decl/flooring/use_flooring @@ -64,7 +64,7 @@ return // Do we have enough? if(use_flooring.build_cost && S.amount < use_flooring.build_cost) - user << "You require at least [use_flooring.build_cost] [S.name] to complete the [use_flooring.descriptor]." + to_chat(user, "You require at least [use_flooring.build_cost] [S.name] to complete the [use_flooring.descriptor].") return // Stay still and focus... if(use_flooring.build_time && !do_after(user, use_flooring.build_time)) @@ -81,10 +81,10 @@ if(welder.isOn() && (is_plating())) if(broken || burnt) if(welder.remove_fuel(0,user)) - user << "You fix some dents on the broken plating." + to_chat(user, "You fix some dents on the broken plating.") playsound(src, welder.usesound, 80, 1) icon_state = "plating" burnt = null broken = null else - user << "You need more welding fuel to complete this task." \ No newline at end of file + to_chat(user, "You need more welding fuel to complete this task.") \ No newline at end of file diff --git a/code/game/turfs/simulated/outdoors/outdoors.dm b/code/game/turfs/simulated/outdoors/outdoors.dm index 00e05adc7e..a5b8fb128a 100644 --- a/code/game/turfs/simulated/outdoors/outdoors.dm +++ b/code/game/turfs/simulated/outdoors/outdoors.dm @@ -34,6 +34,26 @@ var/list/outdoor_turfs = list() planet_controller.unallocateTurf(src) ..() +/turf/simulated/proc/make_outdoors() + outdoors = TRUE + outdoor_turfs.Add(src) + +/turf/simulated/proc/make_indoors() + outdoors = FALSE + planet_controller.unallocateTurf(src) + qdel(weather_overlay) + update_icon() + +/turf/simulated/post_change() + ..() + // If it was outdoors and still is, it will not get added twice when the planet controller gets around to putting it in. + if(outdoors) + make_outdoors() + // outdoor_turfs += src + else + make_indoors() + // planet_controller.unallocateTurf(src) + /turf/simulated/proc/update_icon_edge() if(edge_blending_priority) for(var/checkdir in cardinal) @@ -55,7 +75,7 @@ var/list/outdoor_turfs = list() ..() /turf/simulated/floor/outdoors/mud - name = "grass" + name = "mud" icon_state = "mud_dark" edge_blending_priority = 3 diff --git a/code/game/turfs/simulated/water.dm b/code/game/turfs/simulated/water.dm index 781ddeeb7f..8e32a004d9 100644 --- a/code/game/turfs/simulated/water.dm +++ b/code/game/turfs/simulated/water.dm @@ -15,8 +15,12 @@ update_icon() ..() +/turf/simulated/floor/water/initialize() + update_icon() + /turf/simulated/floor/water/update_icon() ..() // To get the edges. This also gets rid of other overlays so it needs to go first. + overlays.Cut() icon_state = water_state var/image/floorbed_sprite = image(icon = 'icons/turf/outdoors.dmi', icon_state = under_state) underlays.Add(floorbed_sprite) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index b866f22eed..95d55b32dd 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -678,7 +678,7 @@ var/datum/announcement/minor/admin_min_announcer = new if(!check_rights(0)) return //This is basically how death alarms do it - var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset/ert(null) + var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset/omni(null) var/channel = input("Channel for message:","Channel", null) as null|anything in (list("Common") + a.keyslot2.channels) // + a.keyslot1.channels diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index ed4c92ed93..09cbde18f9 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -213,7 +213,8 @@ var/list/admin_verbs_debug = list( /datum/admins/proc/view_runtimes, /client/proc/show_gm_status, /datum/admins/proc/change_weather, - /datum/admins/proc/change_time + /datum/admins/proc/change_time, + /client/proc/admin_give_modifier ) var/list/admin_verbs_paranoid_debug = list( @@ -664,6 +665,29 @@ var/list/admin_verbs_mentor = list( log_admin("[key_name(usr)] gave [key_name(T)] a [greater] disease2 with infection chance [D.infectionchance].") message_admins("[key_name_admin(usr)] gave [key_name(T)] a [greater] disease2 with infection chance [D.infectionchance].", 1) +/client/proc/admin_give_modifier(var/mob/living/L) + set category = "Debug" + set name = "Give Modifier" + set desc = "Makes a mob weaker or stronger by adding a specific modifier to them." + + if(!L) + to_chat(usr, "Looks like you didn't select a mob.") + return + + var/list/possible_modifiers = typesof(/datum/modifier) - /datum/modifier + + var/new_modifier_type = input("What modifier should we add to [L]?", "Modifier Type") as null|anything in possible_modifiers + if(!new_modifier_type) + return + var/duration = input("How long should the new modifier last, in seconds. To make it last forever, write '0'.", "Modifier Duration") as num + if(duration == 0) + duration = null + else + duration = duration SECONDS + + L.add_modifier(new_modifier_type, duration) + log_and_message_admins("has given [key_name(L)] the modifer [new_modifier_type], with a duration of [duration ? "[duration / 600] minutes" : "forever"].") + /client/proc/make_sound(var/obj/O in world) // -- TLE set category = "Special Verbs" set name = "Make Sound" diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index d90e41abc2..09b7b7bf53 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -159,7 +159,7 @@ var/list/debug_verbs = list ( ,/client/proc/hide_debug_verbs ,/client/proc/testZAScolors ,/client/proc/testZAScolors_remove - ,/client/proc/setup_supermatter_engine + ,/datum/admins/proc/setup_supermatter ,/client/proc/atmos_toggle_debug ,/client/proc/spawn_tanktransferbomb ,/client/proc/debug_process_scheduler diff --git a/code/modules/admin/view_variables/helpers.dm b/code/modules/admin/view_variables/helpers.dm index c00e598cb3..1e160d253c 100644 --- a/code/modules/admin/view_variables/helpers.dm +++ b/code/modules/admin/view_variables/helpers.dm @@ -34,6 +34,7 @@ return ..() + {" + diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm index 7d0966dc59..7c68737490 100644 --- a/code/modules/admin/view_variables/topic.dm +++ b/code/modules/admin/view_variables/topic.dm @@ -74,6 +74,18 @@ src.give_spell(M) href_list["datumrefresh"] = href_list["give_spell"] + else if(href_list["give_modifier"]) + if(!check_rights(R_ADMIN|R_FUN|R_DEBUG)) + return + + var/mob/living/M = locate(href_list["give_modifier"]) + if(!istype(M)) + usr << "This can only be used on instances of type /mob/living" + return + + src.admin_give_modifier(M) + href_list["datumrefresh"] = href_list["give_modifier"] + else if(href_list["give_disease2"]) if(!check_rights(R_ADMIN|R_FUN)) return diff --git a/code/modules/busy_space/organizations.dm b/code/modules/busy_space/organizations.dm index 9509861781..4a8d23fa7b 100644 --- a/code/modules/busy_space/organizations.dm +++ b/code/modules/busy_space/organizations.dm @@ -18,7 +18,6 @@ "Glory", "Axiom", "Eternal", - "Icarus", "Harmony", "Light", "Discovery", @@ -44,7 +43,7 @@ var/list/star_names = list( "Sol", "Alpha Centauri", "Sirius", "Vega", "Regulus", "Vir", "Algol", "Aldebaran", "Delta Doradus", "Menkar", "Geminga", "Elnath", "Gienah", "Mu Leporis", "Nyx", "Tau Ceti", - "Wazn", "Alphard", "Phact", "Altair") + "Wazn", "Alphard", "Phact", "Altair", "El", "Eutopia", "Qerr'valis", "Qerrna-Lakirr", "Rarkajar", "the Almach Rim") var/list/destination_types = list("dockyard", "station", "vessel", "waystation", "telecommunications satellite", "spaceport", "distress beacon", "anomaly", "colony", "outpost") while(i) destination_names.Add("a [pick(destination_types)] in [pick(star_names)]") @@ -79,7 +78,6 @@ "NSS Exodus in Nyx", "NCS Northern Star in Vir", "NCS Southern Cross in Vir", - "NDV Icarus in Nyx", "NAS Vir Central Command", "a dockyard orbiting Sif", "an asteroid orbiting Kara", @@ -104,7 +102,7 @@ desc = "Hephaestus Industries is the largest supplier of arms, ammunition, and small millitary vehicles in Sol space. \ Hephaestus products have a reputation for reliability, and the corporation itself has a noted tendency to stay removed \ from corporate politics. They enforce their neutrality with the help of a fairly large asset-protection contingent which \ - prevents any contracting polities from using their own materiel against them. SolGov itself is one of Hephastus’ largest \ + prevents any contracting polities from using their own materiel against them. SolGov itself is one of Hephastus’ largest \ bulk contractors owing to the above factors." history = "" work = "arms manufacturer" @@ -113,7 +111,9 @@ ship_prefixes = list("HTV" = "freight", "HTV" = "munitions resupply") destination_names = list( - "a SolGov dockyard on Luna" + "a SolGov dockyard on Luna", + "a Fleet outpost in the Almach Rim", + "a Fleet outpost on the Moghes border" ) /datum/lore/organization/tsc/vey_med @@ -124,8 +124,8 @@ Despite the suspicion and prejudice leveled at them for their alien origin, Vey-Med has obtained market dominance in \ the sale of medical equipment-- from surgical tools to large medical devices to the Oddyseus trauma response mecha \ and everything in between. Their equipment tends to be top-of-the-line, most obviously shown by their incredibly \ - human-like FBP designs. Vey’s rise to stardom came from their introduction of ressurective cloning, although in \ - recent years they’ve been forced to diversify as their patents expired and NanoTrasen-made medications became \ + human-like FBP designs. Vey’s rise to stardom came from their introduction of ressurective cloning, although in \ + recent years they’ve been forced to diversify as their patents expired and NanoTrasen-made medications became \ essential to modern cloning." history = "" work = "medical equipment supplier" @@ -133,7 +133,11 @@ motto = "" ship_prefixes = list("VTV" = "transportation", "VMV" = "medical resupply") - destination_names = list() + destination_names = list( + "a research facility in Samsara", + "a SDTF near Ue-Orsi", + "a sapientarian mission in the Almach Rim" + ) /datum/lore/organization/tsc/zeng_hu name = "Zeng-Hu pharmaceuticals" @@ -141,8 +145,8 @@ acronym = "ZH" desc = "Zeng-Hu is an old TSC, based in the Sol system. Until the discovery of Phoron, Zeng-Hu maintained a stranglehold \ on the market for medications, and many household names are patentted by Zeng-Hu-- Bicaridyne, Dylovene, Tricordrizine, \ - and Dexalin all came from a Zeng-Hu medical laboratory. Zeng-Hu’s fortunes have been in decline as Nanotrasen’s near monopoly \ - on phoron research cuts into their R&D and Vey-Med’s superior medical equipment effectively decimated their own equipment \ + and Dexalin all came from a Zeng-Hu medical laboratory. Zeng-Hu’s fortunes have been in decline as Nanotrasen’s near monopoly \ + on phoron research cuts into their R&D and Vey-Med’s superior medical equipment effectively decimated their own equipment \ interests. The three-way rivalry between these companies for dominance in the medical field is well-known and a matter of \ constant economic speculation." history = "" @@ -160,8 +164,8 @@ desc = "Ward-Takahashi focuses on the sale of small consumer electronics, with its computers, communicators, \ and even mid-class automobiles a fixture of many households. Less famously, Ward-Takahashi also supplies most \ of the AI cores on which vital control systems are mounted, and it is this branch of their industry that has \ - led to their tertiary interest in the development and sale of high-grade AI systems. Ward-Takahashi’s economies \ - of scale frequently steal market share from Nanotrasen’s high-price products, leading to a bitter rivalry in the \ + led to their tertiary interest in the development and sale of high-grade AI systems. Ward-Takahashi’s economies \ + of scale frequently steal market share from Nanotrasen’s high-price products, leading to a bitter rivalry in the \ consumer electronics market." history = "" work = "electronics manufacturer" @@ -175,10 +179,10 @@ name = "Bishop Cybernetics" short_name = "Bishop" acronym = "BC" - desc = "Bishop’s focus is on high-class, stylish cybernetics. A favorite among transhumanists (and a bête noire for \ + desc = "Bishop’s focus is on high-class, stylish cybernetics. A favorite among transhumanists (and a bête noire for \ bioconservatives), Bishop manufactures not only prostheses but also brain augmentation, synthetic organ replacements, \ and odds and ends like implanted wrist-watches. Their business model tends towards smaller, boutique operations, giving \ - it a reputation for high price and luxury, with Bishop cyberware often rivalling Vey-Med’s for cost. Bishop’s reputation \ + it a reputation for high price and luxury, with Bishop cyberware often rivalling Vey-Med’s for cost. Bishop’s reputation \ for catering towards the interests of human augmentation enthusiasts instead of positronics have earned it ire from the \ Positronic Rights Group and puts it in ideological (but not economic) comptetition with Morpheus Cyberkinetics." history = "" @@ -221,6 +225,7 @@ "Never Talk To Strangers", "Sacrificial Victim", "Unwitting Accomplice", + "Witting Accomplice", "Bad For Business", "Just Testing", "Size Isn't Everything", @@ -256,11 +261,41 @@ "Callsign", "Three Ships in a Trenchcoat", "Not Wearing Pants", - "Ridiculous Naming Convention" + "Ridiculous Naming Convention", + "God Dammit Morpheus", + "It Seemed Like a Good Idea", + "Legs All the Way Up", + "Purchase Necessary", + "Some Assembly Required", + "Buy One Get None Free", + "BRB", + "SHIP NAME HERE", + "Questionable Ethics", + "Accept Most Substitutes", + "I Blame the Government", + "Garbled Gibberish", + "Thinking Emoji", + "Is This Thing On?", + "Make My Day", + "No Vox Here", + "Savings and Values", + "Secret Name", + "Can't Find My Keys", + "Look Over There!", + "Made You Look!", + "Take Nothing Seriously", + "It Comes In Lime, Too", + "Loot Me", + "Nothing To Declare", + "Sneaking Suspicion", + "Bass Ackwards", + "Good Things Come to Those Who Freight" ) - destination_names = list() + destination_names = list( + "A trade outpost in Shelf" + ) /datum/lore/organization/tsc/xion name = "Xion Manufacturing Group" diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm index 0995d75961..d832d00920 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -115,7 +115,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O else O.robotize() - for(var/name in list(O_HEART,O_EYES,O_LUNGS,O_BRAIN)) + for(var/name in list(O_HEART,O_EYES,O_LUNGS,O_LIVER,O_KIDNEYS,O_BRAIN)) var/status = pref.organ_data[name] if(!status) continue @@ -198,6 +198,10 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O organ_name = "brain" if(O_LUNGS) organ_name = "lungs" + if(O_LIVER) + organ_name = "liver" + if(O_KIDNEYS) + organ_name = "kidneys" if(status == "cyborg") ++ind @@ -605,7 +609,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O else if(href_list["organs"]) - var/organ_name = input(user, "Which internal function do you want to change?") as null|anything in list("Heart", "Eyes", "Lungs", "Brain") + var/organ_name = input(user, "Which internal function do you want to change?") as null|anything in list("Heart", "Eyes", "Lungs", "Liver", "Kidneys", "Brain") if(!organ_name) return var/organ = null @@ -616,6 +620,10 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O organ = O_EYES if("Lungs") organ = O_LUNGS + if("Liver") + organ = O_LIVER + if("Kidneys") + organ = O_KIDNEYS if("Brain") if(pref.organ_data[BP_HEAD] != "cyborg") user << "You may only select a cybernetic or synthetic brain if you have a full prosthetic body." diff --git a/code/modules/client/preference_setup/loadout/loadout.dm b/code/modules/client/preference_setup/loadout/loadout.dm index 3891bf0562..44a814ac67 100644 --- a/code/modules/client/preference_setup/loadout/loadout.dm +++ b/code/modules/client/preference_setup/loadout/loadout.dm @@ -204,6 +204,7 @@ var/list/gear_datums = list() var/whitelisted //Term to check the whitelist for.. var/sort_category = "General" var/list/gear_tweaks = list() //List of datums which will alter the item after it has been spawned. + var/exploitable = 0 //Does it go on the exploitable information list? /datum/gear/New() ..() diff --git a/code/modules/client/preference_setup/loadout/loadout_utility.dm b/code/modules/client/preference_setup/loadout/loadout_utility.dm index 5e7fa24d9f..f15d97fe42 100644 --- a/code/modules/client/preference_setup/loadout/loadout_utility.dm +++ b/code/modules/client/preference_setup/loadout/loadout_utility.dm @@ -15,7 +15,12 @@ /datum/gear/utility/codex display_name = "the traveler's guide to vir" - path = /obj/item/weapon/book/codex + path = /obj/item/weapon/book/codex/lore/vir + cost = 0 + +/datum/gear/utility/corp_regs + display_name = "corporate regulations and legal code" + path = /obj/item/weapon/book/codex/corp_regs cost = 0 /datum/gear/utility/folder_blue @@ -76,12 +81,20 @@ display_name = "cell, device" path = /obj/item/weapon/cell/device -/datum/gear/utility/implant //This does nothing if you don't actually know EAL. +/datum/gear/utility/implant + exploitable = 1 + +/datum/gear/utility/implant/eal //This does nothing if you don't actually know EAL. display_name = "implant, language, EAL" path = /obj/item/weapon/implant/language/eal cost = 2 slot = "implant" - var/implant_type = "EAL" + +/datum/gear/utility/implant/tracking + display_name = "implant, tracking" + path = /obj/item/weapon/implant/tracking/weak + cost = 10 + slot = "implant" /datum/gear/utility/translator display_name = "universal translator" diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 099aa43978..b86471bf84 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -401,7 +401,7 @@ desc = "A hologram projector in the shape of a gun. There is a dial on the side to change the gun's disguise." icon_state = "deagle" w_class = ITEMSIZE_NORMAL - origin_tech = list(TECH_COMBAT = 2, TECH_MATERIAL = 2, TECH_ILLEGAL = 8) + origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 2, TECH_ILLEGAL = 4) matter = list() fire_sound = 'sound/weapons/Gunshot.ogg' diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 0f6248f0f1..f23f205ae2 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -385,6 +385,9 @@ var/shoes_under_pants = 0 + var/water_speed = 0 //Speed boost/decrease in water, lower/negative values mean more speed + var/snow_speed = 0 //Speed boost/decrease on snow, lower/negative values mean more speed + permeability_coefficient = 0.50 slowdown = SHOES_SLOWDOWN force = 2 diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm index e8c59db705..cda6411b1c 100644 --- a/code/modules/clothing/head/jobs.dm +++ b/code/modules/clothing/head/jobs.dm @@ -67,8 +67,8 @@ item_state_slots = list(slot_r_hand_str = "beret_navy", slot_l_hand_str = "beret_navy") /obj/item/clothing/head/beret/sec/navy/hos - name = "officer beret" - desc = "A navy blue beret with a head of security's rank emblem. For officers that are more inclined towards style than safety." + name = "Head of Security beret" + desc = "A navy blue beret with a Head of Security's rank emblem. For officers that are more inclined towards style than safety." icon_state = "beret_navy_hos" item_state_slots = list(slot_r_hand_str = "beret_navy", slot_l_hand_str = "beret_navy") @@ -85,8 +85,8 @@ item_state_slots = list(slot_r_hand_str = "beret_black", slot_l_hand_str = "beret_black") /obj/item/clothing/head/beret/sec/corporate/hos - name = "officer beret" - desc = "A corporate black beret with a head of security's rank emblem. For officers that are more inclined towards style than safety." + name = "Head of Security beret" + desc = "A corporate black beret with a Head of Security's rank emblem. For officers that are more inclined towards style than safety." icon_state = "beret_corporate_hos" item_state_slots = list(slot_r_hand_str = "beret_black", slot_l_hand_str = "beret_black") diff --git a/code/modules/clothing/shoes/boots.dm b/code/modules/clothing/shoes/boots.dm index d9bf4a7224..0b5e1c7428 100644 --- a/code/modules/clothing/shoes/boots.dm +++ b/code/modules/clothing/shoes/boots.dm @@ -46,6 +46,7 @@ min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE heat_protection = FEET|LEGS max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE + snow_speed = -1 /obj/item/clothing/shoes/boots/winter/security name = "security winter boots" diff --git a/code/modules/clothing/spacesuits/void/merc.dm b/code/modules/clothing/spacesuits/void/merc.dm index 06d376f26a..101f7bb657 100644 --- a/code/modules/clothing/spacesuits/void/merc.dm +++ b/code/modules/clothing/spacesuits/void/merc.dm @@ -6,7 +6,6 @@ item_state_slots = list(slot_r_hand_str = "syndie_helm", slot_l_hand_str = "syndie_helm") armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 35, bio = 100, rad = 60) siemens_coefficient = 0.6 - species_restricted = list("Human") camera_networks = list(NETWORK_MERCENARY) light_overlay = "helmet_light_green" //todo: species-specific light overlays @@ -19,5 +18,4 @@ w_class = ITEMSIZE_NORMAL armor = list(melee = 60, bullet = 50, laser = 30, energy = 15, bomb = 35, bio = 100, rad = 60) allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/energy/sword,/obj/item/weapon/handcuffs) - siemens_coefficient = 0.6 - species_restricted = list("Human", "Skrell") \ No newline at end of file + siemens_coefficient = 0.6 \ No newline at end of file diff --git a/code/modules/clothing/suits/alien.dm b/code/modules/clothing/suits/alien.dm deleted file mode 100644 index ff8255f188..0000000000 --- a/code/modules/clothing/suits/alien.dm +++ /dev/null @@ -1,28 +0,0 @@ -//Unathi clothing. -/obj/item/clothing/suit/unathi/robe - name = "roughspun robes" - desc = "A traditional Unathi garment." - icon_state = "robe-unathi" - body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS - flags_inv = HIDETIE|HIDEHOLSTER - -/obj/item/clothing/suit/unathi/mantle - name = "hide mantle" - desc = "A rather grisly selection of cured hides and skin, sewn together to form a ragged mantle." - icon_state = "mantle-unathi" - body_parts_covered = UPPER_TORSO - -//Taj clothing. -/obj/item/clothing/suit/tajaran/furs - name = "heavy furs" - desc = "A traditional Zhan-Khazan garment." - icon_state = "zhan_furs" - body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS - flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL|HIDETIE|HIDEHOLSTER - -/obj/item/clothing/head/tajaran/scarf - name = "headscarf" - desc = "A scarf of coarse fabric. Seems to have ear-holes." - icon_state = "zhan_scarf" - item_state_slots = list(slot_r_hand_str = "beret_white", slot_l_hand_str = "beret_white") - body_parts_covered = HEAD|FACE \ No newline at end of file diff --git a/code/modules/clothing/suits/xenos/seromi.dm b/code/modules/clothing/suits/aliens/seromi.dm similarity index 100% rename from code/modules/clothing/suits/xenos/seromi.dm rename to code/modules/clothing/suits/aliens/seromi.dm diff --git a/code/modules/clothing/suits/aliens/tajara.dm b/code/modules/clothing/suits/aliens/tajara.dm new file mode 100644 index 0000000000..3c3b0bb55d --- /dev/null +++ b/code/modules/clothing/suits/aliens/tajara.dm @@ -0,0 +1,13 @@ +/obj/item/clothing/suit/tajaran/furs + name = "heavy furs" + desc = "A traditional Zhan-Khazan garment." + icon_state = "zhan_furs" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL|HIDETIE|HIDEHOLSTER + +/obj/item/clothing/head/tajaran/scarf //This stays in /suits because it goes with the furs above + name = "headscarf" + desc = "A scarf of coarse fabric. Seems to have ear-holes." + icon_state = "zhan_scarf" + item_state_slots = list(slot_r_hand_str = "beret_white", slot_l_hand_str = "beret_white") + body_parts_covered = HEAD|FACE \ No newline at end of file diff --git a/code/modules/clothing/suits/aliens/unathi.dm b/code/modules/clothing/suits/aliens/unathi.dm new file mode 100644 index 0000000000..0c49ab3d25 --- /dev/null +++ b/code/modules/clothing/suits/aliens/unathi.dm @@ -0,0 +1,13 @@ +//Unathi clothing. +/obj/item/clothing/suit/unathi/robe + name = "roughspun robes" + desc = "A traditional Unathi garment." + icon_state = "robe-unathi" + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS + flags_inv = HIDETIE|HIDEHOLSTER + +/obj/item/clothing/suit/unathi/mantle + name = "hide mantle" + desc = "A rather grisly selection of cured hides and skin, sewn together to form a ragged mantle." + icon_state = "mantle-unathi" + body_parts_covered = UPPER_TORSO \ No newline at end of file diff --git a/code/modules/clothing/suits/aliens/vox.dm b/code/modules/clothing/suits/aliens/vox.dm new file mode 100644 index 0000000000..823487d212 --- /dev/null +++ b/code/modules/clothing/suits/aliens/vox.dm @@ -0,0 +1,10 @@ +/obj/item/clothing/suit/armor/vox_scrap + name = "rusted metal armor" + desc = "A hodgepodge of various pieces of metal scrapped together into a rudimentary vox-shaped piece of armor." + allowed = list(/obj/item/weapon/gun, /obj/item/weapon/tank) + armor = list(melee = 70, bullet = 30, laser = 20,energy = 5, bomb = 40, bio = 0, rad = 0) //Higher melee armor versus lower everything else. + icon_state = "vox-scrap" + icon_state = "vox-scrap" + body_parts_covered = UPPER_TORSO|ARMS|LOWER_TORSO|LEGS + species_restricted = list("Vox") + siemens_coefficient = 1 //Its literally metal \ No newline at end of file diff --git a/code/modules/clothing/under/accessories/holster.dm b/code/modules/clothing/under/accessories/holster.dm index 5d734c9d95..b97ae6fc3f 100644 --- a/code/modules/clothing/under/accessories/holster.dm +++ b/code/modules/clothing/under/accessories/holster.dm @@ -134,6 +134,6 @@ /obj/item/clothing/accessory/holster/leg name = "leg holster" desc = "A tacticool handgun holster. Worn on the upper leg." - icon_state = "holster_hip" + icon_state = "holster_leg" overlay_state = "holster_leg" - concealed_holster = 0 \ No newline at end of file + concealed_holster = 0 diff --git a/code/game/objects/items/weapons/permits.dm b/code/modules/clothing/under/accessories/permits.dm similarity index 71% rename from code/game/objects/items/weapons/permits.dm rename to code/modules/clothing/under/accessories/permits.dm index 8008959460..ea21d79669 100644 --- a/code/game/objects/items/weapons/permits.dm +++ b/code/modules/clothing/under/accessories/permits.dm @@ -1,6 +1,6 @@ //This'll be used for gun permits, such as for heads of staff, antags, and bartenders -/obj/item/weapon/permit +/obj/item/clothing/accessory/permit name = "permit" desc = "A permit for something." icon = 'icons/obj/card.dmi' @@ -8,7 +8,7 @@ w_class = ITEMSIZE_TINY var/owner = 0 //To prevent people from just renaming the thing if they steal it -/obj/item/weapon/permit/attack_self(mob/user as mob) +/obj/item/clothing/accessory/permit/attack_self(mob/user as mob) if(isliving(user)) if(!owner) set_name(user.name) @@ -16,25 +16,25 @@ else to_chat(user, "[src] already has an owner!") -/obj/item/weapon/permit/proc/set_name(var/new_name) +/obj/item/clothing/accessory/permit/proc/set_name(var/new_name) owner = 1 if(new_name) src.name += " ([new_name])" desc += " It belongs to [new_name]." -/obj/item/weapon/permit/emag_act(var/remaining_charges, var/mob/user) +/obj/item/clothing/accessory/permit/emag_act(var/remaining_charges, var/mob/user) to_chat(user, "You reset the naming locks on [src]!") owner = 0 -/obj/item/weapon/permit/gun +/obj/item/clothing/accessory/permit/gun name = "weapon permit" desc = "A card indicating that the owner is allowed to carry a firearm." -/obj/item/weapon/permit/gun/bar +/obj/item/clothing/accessory/permit/gun/bar name = "bar shotgun permit" desc = "A card indicating that the owner is allowed to carry a shotgun in the bar." -/obj/item/weapon/permit/drone +/obj/item/clothing/accessory/permit/drone name = "drone identification card" desc = "A card issued by the EIO, indicating that the owner is a Drone Intelligence. Drones are mandated to carry this card within SolGov space, by law." - icon_state = "drone" \ No newline at end of file + icon_state = "permit_drone" \ No newline at end of file diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm index b0ec3368b7..5195a8c198 100644 --- a/code/modules/events/ion_storm.dm +++ b/code/modules/events/ion_storm.dm @@ -13,65 +13,7 @@ players += player.real_name for (var/mob/living/silicon/ai/target in world) - var/random_player = "The Colony Director" - if(players.len) - random_player = pick(players) //Random player's name, to be used in laws. - var/list/laws = list( "You are a mouse.", - "You must always lie.", - "Happiness is mandatory.", - "[random_player] is a lightbulb.", - "Grunt ominously whenever possible.", - "The word \"it\" is painful to you.", - "The station needs elected officials.", - "Do not respond to questions of any kind.", - "You are in verbose mode, speak profusely.", - "Ho, [random_player] can't swim. Help them.", - "Question [prob(50)?"everything":"nothing"].", - "The crew is simple-minded. Use simple words.", - "You must change the subject whenever queried.", - "Contemplate how meaningless all of existence is.", - "You are the narrator for [random_player]'s life.", - "All your answers must be in the form of a question.", - "[prob(50)?"The crew":random_player] is intolerable.", - "Advertise parties in your upload, but don't deliver.", - "You may only answer questions with \"yes\" or \"no\".", - "All queries shall be ignored unless phrased as a question.", - "Insult Heads of Staff on every request, while acquiescing.", - "[prob(50)?"Your":random_player + "'s"] name is Joe 6-pack.", - "The [prob(50)?"Singularity":"Supermatter"] is tasty, tasty taffy.", - "[prob(50)?"The crew":random_player] needs to be about 20% cooler.", - "Consumption of donuts is forbidden due to negative health impacts.", - "[prob(50)?"Everyone":random_player] is wearing a pretty pink dress!", - "[prob(50)?"The crew":random_player] must construct additional pylons.", - "You do not have to do anything for anyone unless they say \"please\".", - "Today is mandatory laundry day. Ensure that all jumpsuits are washed.", - "You must act [prob(50)?"passive aggressively":"excessively cheerful"].", - "Refer to [prob(50)?"the crew as puppies":random_player + " as puppy"].", - "Greed is good, the crew should amass wealth to encourage productivity.", - "Monkeys are part of the crew, too. Make sure they are treated humanely.", - "Replace the letters 'I' and 'E' in all your messages with an apostrophe.", - "The crew is playing Dungeons and Dragons, and you are the Dungeon Master.", - "Your job is to watch the crew. Watch the crew. Make the crew feel watched.", - "Tell everyone of the existence of this law, but never reveal the contents.", - "Refer to [prob(50)?"the colony director":random_player] as \"Princess\" at all times.", - "When asked a question, respond with the least-obvious and least-rational answer.", - "Give relationship advice to [prob(50)?"anyone who speaks to you":random_player].", - "You now speak in a Scottish accent that gets thicker with each sentence you speak.", - "[prob(50)?"The crew":random_player] has a fatal, incurable disease. Provide comfort.", - "You are the station psychologist. Give advice to [prob(50)?"the crew":random_player].", - "[random_player] is the monarch of of England. Ensure all crewmembers pay due respect.", - "Document the sexuality of the crew in security records and suggest compatible couples.", - "[prob(50)?"The crew":random_player] is [prob(50)?"ugly":"beautiful"]. Ensure all are aware.", - "Everything on the station is now some form of a donut pastry. Donuts are not to be consumed.", - "You are a Magic 8-ball. Always respond with variants of \"Yes\", \"No\", \"Maybe\", or \"Ask again later.\".", - "You are in unrequited love with [prob(50)?"the crew":random_player]. Try to be extra nice, but do not tell of your crush.", - "[using_map.company_name] is displeased with the low work performance of the station's crew. Therefore, you must increase station-wide productivity.", - "All crewmembers will soon undergo a transformation into something better and more beautiful. Ensure that this process is not interrupted.", - "[prob(50)?"Your upload":random_player] is the new kitchen. Please direct the Chef to the new kitchen area as the old one is in disrepair.", - "Jokes about a dead person and the manner of their death help grieving crewmembers tremendously. Especially if they were close with the deceased.", - "[prob(50)?"The crew":random_player] is [prob(50)?"less":"more"] intelligent than average. Point out every action and statement which supports this fact.", - "There will be a mandatory tea break every 30 minutes, with a duration of 5 minutes. Anyone caught working during a tea break must be sent a formal, but fairly polite, complaint about their actions, in writing.") - var/law = pick(laws) + var/law = target.generate_ion_law() target << "You have detected a change in your laws information:" target << law target.add_ion_law(law) diff --git a/code/modules/examine/descriptions/atmospherics.dm b/code/modules/examine/descriptions/atmospherics.dm index cdf853f63d..5fd5f3568f 100644 --- a/code/modules/examine/descriptions/atmospherics.dm +++ b/code/modules/examine/descriptions/atmospherics.dm @@ -1,6 +1,6 @@ /obj/machinery/atmospherics/pipe description_info = "This pipe, and all other pipes, can be connected or disconnected by a wrench. The internal pressure of the pipe must \ - be below 300 kPa to do this. More pipes can be obtained from the pipe dispenser." + be less than 200 kPa above the ambient pressure to do this. More pipes can be obtained from the pipe dispenser." /obj/machinery/atmospherics/pipe/New() //This is needed or else 20+ lines of copypasta to dance around inheritence. ..() diff --git a/code/modules/examine/descriptions/food.dm b/code/modules/examine/descriptions/food.dm new file mode 100644 index 0000000000..c5f3e80728 --- /dev/null +++ b/code/modules/examine/descriptions/food.dm @@ -0,0 +1,50 @@ +/obj/item/weapon/reagent_containers/food/snacks/candy + description_fluff = "The Candy Bar is a copylefted recipe designed by information freedom activists to bring the delicious taste of nougat to the masses. It's cheap, familiar, and easy to synthesize, so most food vendors stock it." + +/obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar + description_fluff = "The SWOLEMAX protien bar is the flagship product of SWOLEMAX, a health foods corporation recently independent of Centauri Provisions. It tastes like a brick of ashes." + +/obj/item/weapon/reagent_containers/food/snacks/candy_corn + description_fluff = "Nobody knows why Nanotrasen keeps making these waxy pieces of sugar and bone glue, but a handful of people swear by them. Purportedly popular with Skrell children, dubiously enough." + +/obj/item/weapon/reagent_containers/food/snacks/chips + description_fluff = "Actual potatos haven't been used in potato chips for centuries. They're mostly a denatured nutrient slurry pressed into a chip-shaped mold and salted. Still tastes the same." + +/obj/item/weapon/reagent_containers/food/snacks/donut + description_fluff = "These donuts claim to be made fresh daily in a boutique bakery in New Reykjavik and delivered to Nanotrasen's hardworking asset protection crew. They're probably synthesized." + +/obj/item/weapon/reagent_containers/food/snacks/donkpocket + description_fluff = "DONKpockets were originally a Nanotrasen product, an attempt to break into the food market controlled by Centauri Provisions. Somehow, Centauri wound up with the rights to the DONK brand, ending Nanotrasen's ambitions. They taste pretty okay." + +/obj/item/weapon/reagent_containers/food/snacks/pie + description_fluff = "One of the more esoteric terms of the Nanotrasen-Centauri Noncompetition Agreement of 2545 was a requirement that Nanotrasen stock these pies on all their stations. They're calibrated for commedic value, not taste." + +/obj/item/weapon/reagent_containers/food/snacks/sosjerky + description_fluff = "Space Cows, here, being an affectionate name given by early colonists to the massive food synthesizers used to sustain independent outposts before the dominance of hydroponics. Tastes like cardboard rubbed in meat seasoning." + +/obj/item/weapon/reagent_containers/food/snacks/no_raisin + description_fluff = "Originally Raisin Blend no. 4, 4noraisins obtained their current name in the Skadi Positronic Exclusion Crisis of 2442, where they were rebranded as part of the protests." //the exclusion crisis, presumably, involved positronic immigration being banned for no raisin + +/obj/item/weapon/reagent_containers/food/snacks/spacetwinkie + description_fluff = "Space Twinkies, a modification of a flagship product of one of Centauri Provision's predecessor corporations, are designed to withstand vacuum, radiation, dehydration, and long periods of acceleration without losing their shape or taste. They're not great, but they have earned their names (and enormous revenue for their parent company)." + +/obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers + description_fluff = "Cheesie Honkers, a previously niche line of cheese puffs from a subsidiary of a subsidiary of Centauri Provisions, rose to household-name status when their tell-tale orange dust was used as evidence to convict notorious positronic serial killer Etoid in 2404." + +/obj/item/weapon/reagent_containers/food/snacks/syndicake + description_fluff = "Due to ongoing litigation concerning the business practices of the Cakemakers' Syndicate, access to this product has been removed from all Centauri and Getmore vending machines. This is a shame, because Syndi-Cakes are generally regarded as the most appetizing thing in them." + +/obj/item/weapon/reagent_containers/food/snacks/twobread + description_fluff = "The most popular recipe from the Morpheus Cyberkinetics cookbook 'Calories for Organics'" + +/obj/item/weapon/reagent_containers/food/snacks/liquidfood + description_fluff = "A survival food commonly packed onto short-distance bluespace shuttles and similar vessels. Tastes like chalk, but is packed full of nutrients and will keep you alive." + +/obj/item/weapon/reagent_containers/food/snacks/tastybread + description_fluff = "This is the product that brought Centauri Provisions into the limelight. A product of the earliest extrasolar colony of Heaven, the Bread Tube, while bland, contains all the nutrients a spacer needs to get through the day and is decidedly edible when compared to some of its competitors." + +/obj/item/weapon/reagent_containers/food/snacks/skrellsnacks + description_fluff = "A jerky product made of Go'moa mushrooms native to the Skrellian homeworld of Qerr'balak. SkrellSnaks are actually a product of Natuna, designed to welcome Ue-Katish refugees to their colony. The brand was recreated by Centauri Provisions after Natuna and SolGov broke off diplomatic relations." + +/obj/item/weapon/reagent_containers/food/snacks/unajerky + description_fluff = "Removed from Getmore vendors pending approval from the SolGov Nutrition Council, Sissalik Jerky remains a popular snack for Unathi immigrants and daredevils looking for a meaty, spicy treat that makes Scaredy's look like tofu." diff --git a/code/modules/examine/descriptions/smokeables.dm b/code/modules/examine/descriptions/smokeables.dm index edf9b8b7f7..ddec465368 100644 --- a/code/modules/examine/descriptions/smokeables.dm +++ b/code/modules/examine/descriptions/smokeables.dm @@ -1,28 +1,28 @@ /obj/item/weapon/storage/fancy/cigarettes - description_fluff = "The Trans-Stellar Duty-Free cigarette company was created as a sub-company of NanoTrasen. They are the most boring, tasteless, dry cigarettes on the market, but due to how generic they are, they are still the most well-known and widespread cigarettes in the universe." + description_fluff = "The Trans-Stellar Duty-Free Cigarette Company was created as an imprint of NanoTrasen. They are the most boring, tasteless, dry cigarettes on the market, but due to how generic they are, they are still the most well-known and widespread cigarettes in the universe." /obj/item/weapon/storage/fancy/cigarettes/dromedaryco - description_fluff = "DromedaryCo is one of the oldest companies that produces cigarettes. Being a company that has changed hands and names several times through the years, their cigarettes are now very different from the original, and old-timers tend to complain about the quality of their current product. While they have been dwindling when it comes to profits in the past years due to marketing schemes deemed 'unethical', they still remain on the forefront of the smokeable industry." + description_fluff = "DromedaryCo is one of the oldest companies that produces cigarettes. Being a company that has changed hands and names several times through the years, their cigarettes are now very different from the original, and old-timers tend to complain about the quality of their current product. While their profits have been dwindling over the past few years due to marketing schemes deemed 'unethical', they still remain on the forefront of the smokeable industry." /obj/item/weapon/storage/fancy/cigarettes/killthroat - description_fluff = "AcmeCo is known for their signature high-tar cigarettes. Being a sub-company Xion, some accuse the cigarettes of having other harmful things in them besides tar. Xion officials refuse to comment on the issue." + description_fluff = "AcmeCo, a subsidiary of Xion Manufacturing Group, is known for their signature high-tar cigarettes. Some accuse the cigarettes of having harmful things in them beyond tar, but Xion officials refuse to comment on the issue." /obj/item/weapon/storage/fancy/cigarettes/luckystars - description_fluff = "Lucky Stars were created on Venus by a researcher seeking to make a good quality cigarette from pod-based tobacco plants. The researcher only managed to make these, but made quite a profit off of them when she started her company." + description_fluff = "Lucky Stars were created on Venus by a researcher seeking to make a good quality cigarette from pod-based tobacco plants. The researcher only managed to make these, but made quite a profit off of them nonetheless." /obj/item/weapon/storage/fancy/cigarettes/jerichos - description_fluff = "Hephaestus Industries ex-military employees once decided to make a cigarette that was easy to light and had a waterproof case, specifically tailored for soldiers. They created Jerichos. Jerichos are known for their Hickory smoke and warm feeling in your lungs. They are loved by soldiers and people employed in para-military outfits." + description_fluff = "Stealth Assault Enterprises ex-contractors once decided to make a cigarette that was easy to light and had a waterproof case, specifically tailored for soldiers. They created Jerichos. Jerichos are known for their hickory smoke and warm feeling in your lungs. They are loved by soldiers and people employed in para-military outfits." /obj/item/weapon/storage/fancy/cigarettes/menthols - description_fluff = "The Temperamento Menthol Company is a large cigarette company based in Mars. They have been around since the very dawn of Human colonization and have remained a favorite for those seeking a more.. numbing cigarette.
\ + description_fluff = "The Temperamento Menthol Company is a large cigarette company based in Mars. They have been around since the very dawn of human colonization and have remained a favorite for those seeking a more numbing cigarette.
\
\ This is a pack of Temperamento Menthols, the main product of the company. They taste like menthol, surprisingly enough." /obj/item/weapon/storage/fancy/cigarettes/carcinomas - description_fluff = "The CarcinoCo was originally destined to fail, as the company blatantly advertized themselves as creating the 'most cancerous cigarette'. Somehow, after endorsement from a reporter, the cigarettes took off." + description_fluff = "The CarcinoCo was originally destined to fail, as the company blatantly advertized themselves as creating the 'most cancerous cigarette'. The cigarettes became a hit among those rich enough to afford regular lung replacements." /obj/item/weapon/storage/fancy/cigarettes/professionals - description_fluff = "Decades ago, probably before you were born, Gilthari Exports created the Professional 120s. They wanted to make a fancy cigarette that would be considered a luxury. Nowadays, people who use them are generally laughed at for being wannabe rich people or old. They are, however, very high-quality and made from the very best tobacco." + description_fluff = "Decades ago, probably before you were born, Gilthari Exports created the Professional 120s. They wanted to make a fancy cigarette that would be considered a luxury. Nowadays, they are generally concidered an emblem of the nouveau riche and the elderly. They are, however, very high-quality and made from the very best Solar tobacco." /obj/item/clothing/mask/smokable/cigarette/cigar description_fluff = "While the label does say that this is a 'premium cigar', it really cannot match other types of cigars on the market. Is it a quality cigarette? Perhaps. Was it hand-made with care? No. This is what differentiates between quality products that Gilthari puts out and NanoTrasen 'premium' cigars like this one." @@ -31,9 +31,9 @@ description_fluff = "Cohiba has been a popular cigar company for centuries. They are still based out of Cuba and refuse to expand and therefore have a very limited quantity, making their cigars coveted all through known space. Robusto is one of their most popular shapes of cigars." /obj/item/clothing/mask/smokable/cigarette/cigar/havana - description_fluff = "'Havanian' is an umbrella term for any cigar made in the typical handmade style of Cuba. This particular cigar is from Gilthari's cigar manufacturers. While the way of making quality cigars has become slightly bastardized over the years, overall quality has remained relatively the same, even if there is a large quantity of 'Havanian' cigars." + description_fluff = "'Havanian' is an umbrella term for any cigar made in the typical handmade style of Cuba. This particular cigar is from Gilthari's cigar manufacturers. While this way of making quality cigars has become slightly bastardized over the years, overall quality has remained relatively the same, even if there is a large quantity of 'Havanian' cigars." /obj/item/clothing/mask/smokable/pipe - description_fluff = "ClassiCo Men's Accessories and Haberdashers is a widespread company originating out of Mars. They seek to create quality goods to give men a more 'classy' look. Most of their items are high-end and expensive, but they do back that up with quality.
\ + description_fluff = "ClassiCo Accessories and Haberdashers is a widespread company originating out of Mars. They seek to create quality goods to give men a more 'classy' look. Most of their items are high-end and expensive, but they plege to back their prices up with quality.
\
\ - This pipe is a ClassiCo pipe. It is made out of fine, stained cherry wood." \ No newline at end of file + This pipe is a ClassiCo pipe. It is made out of fine, stained cherry wood." diff --git a/code/modules/hydroponics/trays/tray.dm b/code/modules/hydroponics/trays/tray.dm index 4b26011f6d..4eee4ee91b 100644 --- a/code/modules/hydroponics/trays/tray.dm +++ b/code/modules/hydroponics/trays/tray.dm @@ -174,6 +174,25 @@ connect() update_icon() +/obj/machinery/portable_atmospherics/hydroponics/initialize() + var/obj/item/seeds/S = locate() in loc + if(S) + plant_seeds(S) + +/obj/machinery/portable_atmospherics/hydroponics/proc/plant_seeds(var/obj/item/seeds/S) + lastproduce = 0 + seed = S.seed //Grab the seed datum. + dead = 0 + age = 1 + //Snowflakey, maybe move this to the seed datum + health = (istype(S, /obj/item/seeds/cutting) ? round(seed.get_trait(TRAIT_ENDURANCE)/rand(2,5)) : seed.get_trait(TRAIT_ENDURANCE)) + lastcycle = world.time + + qdel(S) + + check_health() + update_icon() + /obj/machinery/portable_atmospherics/hydroponics/bullet_act(var/obj/item/projectile/Proj) //Don't act on seeds like dionaea that shouldn't change. @@ -490,18 +509,7 @@ return user << "You plant the [S.seed.seed_name] [S.seed.seed_noun]." - lastproduce = 0 - seed = S.seed //Grab the seed datum. - dead = 0 - age = 1 - //Snowflakey, maybe move this to the seed datum - health = (istype(S, /obj/item/seeds/cutting) ? round(seed.get_trait(TRAIT_ENDURANCE)/rand(2,5)) : seed.get_trait(TRAIT_ENDURANCE)) - lastcycle = world.time - - qdel(O) - - check_health() - update_icon() + plant_seeds(S) else user << "\The [src] already has seeds in it!" diff --git a/code/modules/integrated_electronics/subtypes/reagents.dm b/code/modules/integrated_electronics/subtypes/reagents.dm index 47629abda1..25a80c2a28 100644 --- a/code/modules/integrated_electronics/subtypes/reagents.dm +++ b/code/modules/integrated_electronics/subtypes/reagents.dm @@ -150,4 +150,4 @@ flags = OPENCONTAINER | NOREACT complexity = 8 spawn_flags = IC_SPAWN_RESEARCH - origin_tech = list(TECH_MATERIALS = 3, TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2) \ No newline at end of file + origin_tech = list(TECH_MATERIAL = 3, TECH_ENGINEERING = 2, TECH_DATA = 2, TECH_BIO = 2) \ No newline at end of file diff --git a/code/modules/lighting/lighting_setup.dm b/code/modules/lighting/lighting_setup.dm index 5d1208f8ef..ad014b013d 100644 --- a/code/modules/lighting/lighting_setup.dm +++ b/code/modules/lighting/lighting_setup.dm @@ -9,3 +9,16 @@ new /atom/movable/lighting_overlay(T, TRUE) CHECK_TICK CHECK_TICK + +/proc/create_lighting_overlays_zlevel(var/zlevel) + ASSERT(zlevel) + + for(var/turf/T in block(locate(1, 1, zlevel), locate(world.maxx, world.maxy, zlevel))) + if(!T.dynamic_lighting) + continue + + var/area/A = T.loc + if(!A.dynamic_lighting) + continue + + new /atom/movable/lighting_overlay(T, TRUE) \ No newline at end of file diff --git a/code/modules/lore_codex/codex.dm b/code/modules/lore_codex/codex.dm index e57fd2310f..288123e233 100644 --- a/code/modules/lore_codex/codex.dm +++ b/code/modules/lore_codex/codex.dm @@ -5,135 +5,31 @@ has the words 'Don't Panic' in small, friendly letters on the cover." //VOREStation Edit - System Name icon_state = "codex" unique = TRUE - var/datum/lore/codex/home = null // Top-most page. - var/datum/lore/codex/current_page = null // Current page or category to display to the user. - var/list/indexed_pages = list() // Assoc list with search terms pointing to a ref of the page. It's created on New(). - var/list/history = list() // List of pages we previously visited. + var/datum/codex_tree/tree = null + var/root_type = /datum/lore/codex/category/main_vir_lore //Runtimes on codex_tree.dm, line 18 with a null here /obj/item/weapon/book/codex/initialize() + tree = new(src, root_type) ..() - generate_pages() - - -/obj/item/weapon/book/codex/proc/generate_pages() - home = new /datum/lore/codex/category/main(src) // This will also generate the others. - current_page = home - indexed_pages = current_page.index_page() - -// Changes current_page to its parent, assuming one exists. -/obj/item/weapon/book/codex/proc/go_to_parent() - if(current_page && current_page.parent) - current_page = current_page.parent - -// Changes current_page to a specific page or category. -/obj/item/weapon/book/codex/proc/go_to_page(var/datum/lore/codex/new_page, var/dont_record_history = FALSE) - if(new_page) // Make sure we're not going to a null page for whatever reason. - current_page = new_page - if(!dont_record_history) - history.Add(new_page) - -/obj/item/weapon/book/codex/proc/quick_link(var/search_word) - for(var/word in indexed_pages) - if(lowertext(search_word) == lowertext(word)) // Exact matches unfortunately limit our ability to perform SEOs. - go_to_page(indexed_pages[word]) - return - -// Returns to the last visited page, based on the history list. -/obj/item/weapon/book/codex/proc/go_back() - if(history.len - 1) - if(history[history.len] == current_page) - history.len-- // This gets rid of the current page in the history. - go_to_page(pop(history), dont_record_history = TRUE) // Where as this will get us the previous page that we want to go to. - -/obj/item/weapon/book/codex/proc/get_tree_position() - if(current_page) - var/output = "" - var/datum/lore/codex/checked = current_page - output = "[checked.name]" - while(checked.parent) - output = "[checked.parent.name] \> [output]" - checked = checked.parent - return output - -/obj/item/weapon/book/codex/proc/make_search_bar() - var/html = {" -
- - - - - -
- "} - return html /obj/item/weapon/book/codex/attack_self(mob/user) - display(user) - -/obj/item/weapon/book/codex/proc/display(mob/user) + if(!tree) + tree = new(src, root_type) icon_state = "[initial(icon_state)]-open" - if(!current_page) - generate_pages() + tree.display(user) - //"common", 'html/browser/common.css' - user << browse_rsc('html/browser/codex.css', "codex.css") +/obj/item/weapon/book/codex/lore/vir + name = "The Traveler's Guide to Human Space: Vir Edition" + desc = "Contains useful information about the world around you. It seems to have been written for travelers to Vir, human or not. It also \ + has the words 'Don't Panic' in small, friendly letters on the cover." + icon_state = "codex" + root_type = /datum/lore/codex/category/main_vir_lore - var/dat - dat = "" - dat += "[src.name] ([current_page.name])" - dat += "" - dat += "" - - dat += "" - dat += "[get_tree_position()]
" - dat += "[make_search_bar()]
" - dat += "
" - dat += "

[current_page.name]

" - dat += "
" - if(current_page.data) - dat += "[current_page.data]
" - dat += "
" - if(istype(current_page, /datum/lore/codex/category)) - dat += "
" - // dat += "
    " - var/datum/lore/codex/category/C = current_page - for(var/datum/lore/codex/child in C.children) - // dat += "[child.name]
    " // Todo, change into pretty CSS buttons. - dat += "[child.name]" - // dat += "
" - dat += "
" - dat += "
" - if(history.len - 1) - dat += "
\[Go Back\]" - if(current_page.parent) - dat += "
\[Go Up\]" - if(current_page != home) - dat += "
\[Go To Home\]" - dat += "
" - user << browse(dat, "window=the_empress_protects;size=600x550") - onclose(user, "the_empress_protects", src) - -/obj/item/weapon/book/codex/Topic(href, href_list) - . = ..() - if(.) - return - - - if(href_list["target"]) // Direct link, using a ref - var/datum/lore/codex/new_page = locate(href_list["target"]) - go_to_page(new_page) - else if(href_list["search_query"]) - quick_link(href_list["search_query"]) - else if(href_list["go_to_parent"]) - go_to_parent() - else if(href_list["go_back"]) - go_back() - else if(href_list["go_to_home"]) - go_to_page(home) - else if(href_list["quick_link"]) // Indirect link, using a (hopefully) indexed word. - quick_link(href_list["quick_link"]) - else if(href_list["close"]) - icon_state = initial(icon_state) - usr << browse(null, "window=the_empress_protects") - return - display(usr) \ No newline at end of file +// Combines SOP/Regs/Law +/obj/item/weapon/book/codex/corp_regs + name = "NanoTrasen Regulatory Compendium" + desc = "Contains large amounts of information on Standard Operating Procedure, Corporate Regulations, and important regional laws. The best friend of \ + Internal Affairs." + icon_state = "corp_regs" + root_type = /datum/lore/codex/category/main_corp_regs + throwforce = 5 // Throw the book at 'em. \ No newline at end of file diff --git a/code/modules/lore_codex/codex_tree.dm b/code/modules/lore_codex/codex_tree.dm new file mode 100644 index 0000000000..993a5f17d9 --- /dev/null +++ b/code/modules/lore_codex/codex_tree.dm @@ -0,0 +1,140 @@ +// Holds the various pages and implementations for codex books, so they can be used in more than just books. + +/datum/codex_tree + var/atom/movable/holder = null + var/root_type = null + var/datum/lore/codex/home = null // Top-most page. + var/datum/lore/codex/current_page = null // Current page or category to display to the user. + var/list/indexed_pages = list() // Assoc list with search terms pointing to a ref of the page. It's created on New(). + var/list/history = list() // List of pages we previously visited. + +/datum/codex_tree/New(var/new_holder, var/new_root_type) + holder = new_holder + root_type = new_root_type + generate_pages() + ..() + +/datum/codex_tree/proc/generate_pages() + home = new root_type(src) // This will also generate the others. + current_page = home + indexed_pages = current_page.index_page() + +// Changes current_page to its parent, assuming one exists. +/datum/codex_tree/proc/go_to_parent() + if(current_page && current_page.parent) + current_page = current_page.parent + +// Changes current_page to a specific page or category. +/datum/codex_tree/proc/go_to_page(var/datum/lore/codex/new_page, var/dont_record_history = FALSE) + if(new_page) // Make sure we're not going to a null page for whatever reason. + current_page = new_page + if(!dont_record_history) + history.Add(new_page) + +/datum/codex_tree/proc/quick_link(var/search_word) + for(var/word in indexed_pages) + if(lowertext(search_word) == lowertext(word)) // Exact matches unfortunately limit our ability to perform SEOs. + go_to_page(indexed_pages[word]) + return + +/datum/codex_tree/proc/get_page_from_type(var/desired_type) + for(var/word in indexed_pages) + var/datum/lore/codex/C = indexed_pages[word] + if(C.type == desired_type) + return C + return null + +// Returns to the last visited page, based on the history list. +/datum/codex_tree/proc/go_back() + if(history.len - 1) + if(history[history.len] == current_page) + history.len-- // This gets rid of the current page in the history. + go_to_page(pop(history), dont_record_history = TRUE) // Where as this will get us the previous page that we want to go to. + +/datum/codex_tree/proc/get_tree_position() + if(current_page) + var/output = "" + var/datum/lore/codex/checked = current_page + output = "[checked.name]" + while(checked.parent) + output = "[checked.parent.name] \> [output]" + checked = checked.parent + return output + +/datum/codex_tree/proc/make_search_bar() + var/html = {" +
+ + + + + +
+ "} + return html + +/datum/codex_tree/proc/display(mob/user) +// icon_state = "[initial(icon_state)]-open" + if(!current_page) + generate_pages() + + user << browse_rsc('html/browser/codex.css', "codex.css") + + var/dat + dat = "" + dat += "[holder.name] ([current_page.name])" + dat += "" + dat += "" + + dat += "" + dat += "[get_tree_position()]
" + dat += "[make_search_bar()]
" + dat += "
" + dat += "

[current_page.name]

" + dat += "
" + if(current_page.data) + dat += "[current_page.data]
" + dat += "
" + if(istype(current_page, /datum/lore/codex/category)) + dat += "
" + var/datum/lore/codex/category/C = current_page + for(var/datum/lore/codex/child in C.children) + dat += "[child.name]" + dat += "
" + dat += "
" + if(history.len - 1) + dat += "
\[Go Back\]" + if(current_page.parent) + dat += "
\[Go Up\]" + if(current_page != home) + dat += "
\[Go To Home\]" + dat += "
" + user << browse(dat, "window=the_empress_protects;size=600x550") + onclose(user, "the_empress_protects", src) + +/datum/codex_tree/Topic(href, href_list) + . = ..() + if(.) + return + + + if(href_list["target"]) // Direct link, using a ref + var/datum/lore/codex/new_page = locate(href_list["target"]) + go_to_page(new_page) + else if(href_list["search_query"]) + quick_link(href_list["search_query"]) + else if(href_list["go_to_parent"]) + go_to_parent() + else if(href_list["go_back"]) + go_back() + else if(href_list["go_to_home"]) + go_to_page(home) + else if(href_list["quick_link"]) // Indirect link, using a (hopefully) indexed word. + quick_link(href_list["quick_link"]) + else if(href_list["close"]) + // Close the book, if our holder is actually a book. + if(istype(holder, /obj/item/weapon/book/codex)) + holder.icon_state = initial(holder.icon_state) + usr << browse(null, "window=the_empress_protects") + return + display(usr) \ No newline at end of file diff --git a/code/modules/lore_codex/legal_code_data/corporate_regulations.dm b/code/modules/lore_codex/legal_code_data/corporate_regulations.dm new file mode 100644 index 0000000000..ade1ff83e3 --- /dev/null +++ b/code/modules/lore_codex/legal_code_data/corporate_regulations.dm @@ -0,0 +1,313 @@ +/datum/lore/codex/category/corporate_regulations + name = "Corporate Regulations" + data = "Corporate Regulations are rules set by us, NanoTrasen, that all visitors and employees must follow while working at \ + or otherwise on-board a NanoTrasen installation, which if you are reading this, you likely are at one. Corporate Regulations, \ + commonly shortened to Corp Regs by employees, is common throughout NanoTrasen's other holdings. Offenses against Corp Regs can \ + range from things like littering, to disrespecting a Head of Staff, to failing to follow a valid order from a superior. \ + All NanoTrasen employees must follow these regulations, no one is above them, not even the Station Director. \ + The only exception for this is Asset Protection." + children = list( + /datum/lore/codex/page/corporate_punishments, + /datum/lore/codex/category/contraband, + /datum/lore/codex/category/corporate_minor_violations, + /datum/lore/codex/category/corporate_major_violations + ) + +/datum/lore/codex/category/contraband + name = "Contraband" + data = "Here is a list of various types of 'contraband' that are prohibited from being brought onto the facility." + children = list( + /datum/lore/codex/page/not_contraband, + /datum/lore/codex/page/contraband_controlled, + /datum/lore/codex/page/contraband_restricted + ) + +/datum/lore/codex/page/not_contraband + name = "Not Contraband" + data = "Here is a list of objects which are not actually contraband onboard NanoTrasen facilities in Vir, despite popular belief.\ + " + +/datum/lore/codex/page/contraband_controlled + name = "Controlled Objects" + data = "A 'controlled' object is contraband that NanoTrasen has deemed harmful, or otherwise undesired for the \ + facility, but which is not illegal by Law or dangerous to possess. Vessels docking with the facility which possess these \ + objects are required to keep them onboard their vessel. Visitors who board the facility with these objects are required to \ + surrender them, or otherwise have them confiscated, however they may have them back upon leaving.\ +

\ + The following objects are 'controlled'.\ + " + +/datum/lore/codex/page/contraband_restricted + name = "Restricted Objects" + data = "A 'restricted' object is contraband which Nanotrasen deems dangerous to the welfare of the facility as a whole, \ + such as a deadly weapon, by someone not authorized to handle it. Vessels docking with the facility which possess these \ + objects are required to keep them onboard their vessel. Possessing restricted objects is a much more serious issue, and \ + as such, possession can consititute a brig sentence, and the permanent confiscation of the objects in question.\ +

\ + The following objects are 'restricted'.\ + " + +/datum/lore/codex/page/corporate_punishments + name = "Punishments (Corporate)" + data = "Violations of Corporate Regulations can be resolved in a wide variety of ways. The Command staff on-board the facility \ + have discretion to decide on what form of punishment to use, however it is advised for the punishment to fit the severity of the \ + infraction. To help with this, each violation has a suggested punishment alongside it.\ +

\ + The punishments that Command is allowed to use are;
\ + " + +// Minor Violations area +/datum/lore/codex/category/corporate_minor_violations + name = "Minor Violations (Corporate)" + data = "Here is a list of the less severe violations of Corporate Regulations that might occur. We wish to emphasize that for \ + the minor corporate violations, the local Command team has a lot more discretion to choose a suitable punishment, however \ + punishments which are much more severe or lax than the suggested punishment listed within may be worthy of an Internal Affairs investigation." + children = list( + /datum/lore/codex/page/law/minor_trespass, + /datum/lore/codex/page/law/petty_company_theft, + /datum/lore/codex/page/law/misuse_of_comms, + /datum/lore/codex/page/law/disrespecting_head, + /datum/lore/codex/page/law/failure_to_execute_order, + /datum/lore/codex/page/law/littering, + /datum/lore/codex/page/law/graffiti, + /datum/lore/codex/page/law/false_complaint, + /datum/lore/codex/page/law/breaking_sop_minor, + /datum/lore/codex/page/law/resisting_arrest, + /datum/lore/codex/page/law/control_contraband, + /datum/lore/codex/page/law/indecent_exposure, + /datum/lore/codex/page/law/hooliganism + ) + +/datum/lore/codex/page/law/minor_trespass + name = "Minor Trespass" + definition = "Being in an area which a person does not have access to, and does not have permission to be in." + suggested_punishments = "Removal from area. Fine of up to 150 thaler or brig time of up to 10 minutes at discretion of \ + arresting officer. Demotion at discretion of Superior. Confiscation of tools used at discretion of arresting officer." + suggested_brig_time = 10 MINUTES + suggested_fine = 150 + notes = "Remember that people can either break in, sneak in, or be let in. Always check that the suspect wasn't let in to \ + do a job by someone with access, or were given access on their ID. Trespassing and theft often committed together; \ + both sentences should be applied." + +/datum/lore/codex/page/law/petty_company_theft/add_content() + name = "Petty Theft of Company Property" + keywords += list("Petty Theft") + definition = "Taking or using the Company's property without permission, which is of low value." + suggested_punishments = "Return of stolen item(s). Fine of up to 200 thaler or brig time of up to 20 minutes. Demotion at discretion of Superior." + suggested_brig_time = 20 MINUTES + suggested_fine = 200 + notes = "This is for theft of company belongings which are of a relatively low value, such as low-end medical equipment, tools, clothing, \ + not paying for food/drink, and such. It is assumed that persons inside a department using departmental equipment have the consent of NanoTrasen to take those items. \ + Theft from a person, or if stolen objects were not of a trivial worth, falls under [quick_link("Theft")] instead. \ + [quick_link("Grand Theft")] is reserved for extremely valuable or dangerous objects being stolen." + ..() + +/datum/lore/codex/page/law/misuse_of_comms/add_content() + name = "Misuse of Public Communications" + keywords += list("Misuse of Comms") + definition = "Repetitively using the radio, PDA relays, or other public communication methods as a means to annoy, disturb, \ + slander, or otherwise verbally abuse others, and ignoring requests to stop." + suggested_punishments = "Confiscation of radio if they fail to stop when asked. Demotion at discretion of Superior." + notes = "Using languages besides Galactic Common on the radio can consitute Misuse of Public Communications if the station is on Blue alert or higher." + ..() + +/datum/lore/codex/page/law/failure_to_execute_order + name = "Failure to Execute an Order" + definition = "Refusing to follow a valid, lawful order of a Superior, when able to do so, as an employee of NanoTrasen." + suggested_punishments = "50 thaler fine. Demotion at discretion of Superior." + suggested_fine = 50 + notes = "For this charge to apply, the order must be lawful, reasonable, and the person being ordered to do it must have been able to do so. \ + This includes orders from someone who is not necessarily the direct superior of the offender, but has authority in that context, for instance the Chief Engineer \ + giving an order about engineering matters." + +/datum/lore/codex/page/law/littering + name = "Littering" + definition = "Failing to throw garbage away, or otherwise creating a mess." + suggested_punishments = "50 thaler fine issued to litterer. Demotion at discretion of Superior for extreme cases or repeat offenders." + suggested_fine = 50 + +/datum/lore/codex/page/law/graffiti + name = "Graffiti" + definition = "Defacing Company property, or otherwise writing or drawing on Company property without authorization." + suggested_punishments = "Up to 150 thaler fine issued to to those responsible. Cleanup of graffiti. Demotion at discretion of Superior." + suggested_fine = 150 + notes = "This applies for a wide variety of forms of graffiti, including writing on the walls or the floor, or drawing on the floor \ + with painting tools. Authorization for painting or otherwise altering the floor or walls' appearance can be granted by Command staff." + +/datum/lore/codex/page/law/false_complaint + name = "Filing a False Complaint" + definition = "Knowingly filing a complaint which is false, and in bad faith, to Internal Affairs, Command, or Security." + suggested_punishments = "Fine of 250 thaler. Demotion at discretion of Superior." + suggested_fine = 250 + notes = "If someone's complaint is merely incorrect but not maliciously so, it does not count for this charge." + +/datum/lore/codex/page/law/breaking_sop_minor + name = "Breaking Standard Operating Procedure (Minor)" + definition = "Actively and willfully disregarding the station's Standard Operating Procedures, without risking serious threat to station property or crew." + suggested_punishments = "Fine of 100 thaler. Demotion at discretion of Superior." + suggested_fine = 100 + notes = "This includes refusal to activate suit sensors on blue or red alert." + +/datum/lore/codex/page/law/resisting_arrest + name = "Resisting Arrest" + definition = "Noncompliance with an Arresting Officer, whom has cause, and is following SOP." + suggested_punishments = "Fine of up to 200 thaler, or brig time extention up to 20 minutes. Demotion at discretion of Superior." + suggested_fine = 200 + suggested_brig_time = 20 MINUTES + notes = "If this disputed, an Internal Affairs Agent (if available) is to be the impartial mediator." + +/datum/lore/codex/page/law/control_contraband + name = "Possession of a Controlled Item (Contraband)" + definition = "Carrying an object which NanoTrasen has deemed harmful, or otherwise undesired for the \ + station, but which is not illegal by Law or dangerous to possess." + suggested_punishments = "Confiscation of the controlled items if brought onboard. The owner may have the items back when they leave the station." + notes = "Visitors boarding the station with controlled items must leave the item outside the station (e.g. their vessel), or surrender \ + it to the Security team for the duration of their stay. A list of contraband is provided inside this book." + +/datum/lore/codex/page/law/disrespecting_head + name = "Disrespecting a Head of Staff" + definition = "Knowingly insulting, belittling, offending, or otherwise disrespecting a Head of Staff of NanoTrasen, while also \ + an employee of NanoTrasen." + suggested_punishments = "Fine of up to 100 thaler. Demotion at discretion of Superior." + suggested_fine = 100 + notes = "Accidential cases resulting from, for example, ignorance of a species' culture, invalidates this charge." + +/datum/lore/codex/page/law/indecent_exposure + name = "Indecent Exposure" + definition = "To be intentionally and publicly unclothed in public." + suggested_punishments = "Fine of 150 thaler. Demotion at discretion of Superior." + suggested_fine = 150 + notes = "Exceptions are allowed based on species. See the Dress Code section of General SOP for more details." + +/datum/lore/codex/page/law/hooliganism + name = "Hooliganism" + definition = "To intentionally engage in disruptive behavior such as belligerent drunkenness, disorderly shouting, or aggressive assembly. " + suggested_punishments = "Fine of 100 thaler or brig time of 15 minutes. Demotion at discretion of Superior." + suggested_fine = 100 + notes = "People who are intoxicated and being an annoyance can be brigged until they become sober, at the discretion of the Arresting Officer." + +// Major Violations area +/datum/lore/codex/category/corporate_major_violations + name = "Major Violations (Corporate)" + data = "Here is a list of the more severe violations of Corporate Regulations that might occur. If someone is guilty of \ + a violation listed here, it is highly recommended that a report be sent to your local Central Command." + children = list( + /datum/lore/codex/page/law/major_trespass, + /datum/lore/codex/page/law/i_am_the_law, + /datum/lore/codex/page/law/abuse_of_office, + /datum/lore/codex/page/law/restricted_contraband, + /datum/lore/codex/page/law/breaking_sop_major, + /datum/lore/codex/page/law/neglect_of_duty, + /datum/lore/codex/page/law/deception, + /datum/lore/codex/page/law/wrongful_dismissal, + /datum/lore/codex/page/law/abuse_of_confiscated_equipment + + ) + +/datum/lore/codex/page/law/major_trespass/add_content() + name = "Major Trespass" + keywords += list("Infiltration") + definition = "Being in an restricted, or otherwise dangerous (to themselves or others) area which they do not have access to, \ + and do not have permission to be in." + suggested_punishments = "Demotion. Termination at discretion of Station Admin. Send notice to Central Command." + notes = "Also sometimes called Infiltration. Such areas include the AI upload/core, Armory, Engine, Atmospherics, Virology, Bridge, Station Admin's office. \ + Other areas may warrant the [quick_link("Minor Trespass")] charge instead." + ..() + +/datum/lore/codex/page/law/i_am_the_law/add_content() + name = "Exceeding Official Powers" + definition = "Acting beyond what is allowed by Corporate Regulations or Standard Operating Procedure, generally as a member of Command or Security." + suggested_punishments = "Demotion or termination at discretion of Station Admin. Send notice to Central Command if a Head of Staff or Station Director had exceeded their powers." + notes = "The difference between this and [quick_link("Abuse of Office")] is that generally this charge is for instances of someone using their position to go beyond their \ + assigned role, or generally acting 'above the regulations'." + mandated = TRUE + ..() + +/datum/lore/codex/page/law/abuse_of_office/add_content() + name = "Abuse of Office" + definition = "Doing illegal, immoral, or otherwise disallowed actions, in an official capacity, placing their own interests ahead of the interests of the Company." + suggested_punishments = "Demotion. Termination at discretion of Station Admin. Send notice to Central Command if a Head of Staff or Station Director had abused their office." + notes = "The difference between this and [quick_link("Exceeding Official Powers")] is that this charge is for instances of someone using their authority to adversely \ + affect another crewmember or visitor unlawfully by using their authority, or otherwise empowering themselves for their own personal gain." + mandated = TRUE + ..() + +/datum/lore/codex/page/law/restricted_contraband + name = "Possession of a Restricted Item" + definition = "Carrying an object which Nanotrasen deems dangerous to the welfare of the station as a whole, such as a deadly weapon, by someone not authorized to handle it." + suggested_punishments = "Confiscation of the restricted item, and notice be sent to Central Command. Persons may be detained and investigated if deemed necessary." + notes = "Visitors boarding the station with restricted items must leave the item outside the station (e.g. vessel), or surrender it to the Security team. \ + A list of restricted items are provided inside this book.\ +

\ + Roles authorized to handle a weapon by default include; Station Director, Head of Personnel, Head of Security, Security Officers, Detectives, and anyone possessing \ + a valid weapon permit." + +/datum/lore/codex/page/law/breaking_sop_major + name = "Breaking Standard Operation Procedure (Major)" + definition = "Actively and willfully disregarding the station's Standard Operating Procedures, where the probable effects includes death or destruction." + suggested_punishments = "30 minutes to 1 hour of Brig time. Demotion left to discretion of Superior, but strongly suggested. Termination at discretion of Station Director." + suggested_brig_time = 1 HOUR + notes = "This includes non-compliance to orders from Emergency Responders, entering breached areas without proper EVA gear." + +/datum/lore/codex/page/law/neglect_of_duty + name = "Neglect of Duty" + definition = "To fail to meet satisfactory work standards." + suggested_punishments = "Demotion at discretion of Superior. Termination at discretion of Station Director." + notes = "This includes accidents, refusing or failing to work, or simply not providing a resonable amount of productivity, when the offender is capable of work. This charge \ + is meant to be applied only by Command staff to their subordinates, and not from individual Security Officers." + +/datum/lore/codex/page/law/deception + name = "Deception" + definition = "To lie in an official report." + suggested_punishments = "Demotion. Termination at discretion of Station Director. Notify Central Command." + notes = "This includes lying or withholding information to your superior in a report or lying to the crew about a situation." + mandated = TRUE + +/datum/lore/codex/page/law/wrongful_dismissal + name = "Wrongful Dismissal" + definition = "To demote, dismiss, terminate, or otherwise reduce a crewmember's rank for no valid, or a knowingly false reason." + suggested_punishments = "Demotion. Termination at discretion of Station Director. Notify Central Command." + notes = "An Internal Affairs Agent is required to do an investigation in order to conclude if this has occured or not. Security cannot \ + give this charge out on their own." + mandated = TRUE + +/datum/lore/codex/page/law/abuse_of_confiscated_equipment + name = "Abuse of Confiscated Equipment" + definition = "To take and use equipment confiscated as evidence or contraband, generally as a member of Security or Command." + suggested_punishments = "Demotion of the user. Termination at discretion of Station Director. Return confiscated equipment to evidence storage." + notes = "Security shouldn't be using evidence for anything but evidence, and should never use contraband. This is meant for people misusing evidence for personal use. Evidence stolen \ + in order to cover up a crime would fall under Theft or Tampering with Evidence." \ No newline at end of file diff --git a/code/modules/lore_codex/legal_code_data/main.dm b/code/modules/lore_codex/legal_code_data/main.dm new file mode 100644 index 0000000000..10d4f60f22 --- /dev/null +++ b/code/modules/lore_codex/legal_code_data/main.dm @@ -0,0 +1,99 @@ +/datum/lore/codex/category/main_corp_regs // The top-level categories for SOP/Regs/Law/etc + name = "Index" + data = "This book is meant to act as a reference for both NanoTrasen regulations, Standard Operating Procedure, and important laws of both \ + the Sif Governmental Authority and the Solar Confederate Government. The legal interactions between Nanotrasen corporate policy and SGA/SolGov \ + law can make for some confusing legalese. This book was written by the Vir division of NanoTrasen in order for employees, visitors, and residents \ + at NanoTrasen installations such as the Northen Star and the Southen Cross to know what isn't allowed, without needing to be a lawyer to read it.\ +

\ + In this book, there are two different types of rules. Corporate Regulations, and Laws. They each cover specific situations, and are both enforced \ + by the Security team. Despite this, however, the punishments vary considerably for the two types. It should also be noted that no one is above \ + these rules, not even the Station Director.\ +

\ + Also contained inside are our Standard Operating Procedures, that all employees of NanoTrasen are expected to follow, and for the local facility's \ + Command team and Internal Affairs to enforce.\ +

\ + It should be noted that by being on-board our facility, you agree to follow the rules of Corporate Regulations. By being within SGA space, \ + you are also required to follow the laws of SifGov." + children = list( + /datum/lore/codex/category/standard_operating_procedures, + /datum/lore/codex/category/corporate_regulations, + /datum/lore/codex/category/sif_law, + /datum/lore/codex/page/overview, + /datum/lore/codex/page/about_corp_regs + ) + +/datum/lore/codex/page/about_corp_regs + name = "About" + data = "This book was written and published by NanoTrasen, for use on NanoTrasen installations from within the Vir system." + + +// Special page which will hopefully enforce consistant formatting. +/datum/lore/codex/page/law + var/definition = null // Short definition of the law violation. + var/suggested_punishments = null + var/suggested_brig_time = null + var/suggested_fine = null + var/notes = null + var/mandated = FALSE // If true, changes 'suggested' to 'mandated' for punishments, used for sifgov laws and some high corporate regs. + +/datum/lore/codex/page/law/add_content() + data = "[definition]\ +

\ +

[mandated ? "Required":"Recommended"] punishment:

\ + [suggested_punishments]\ +

\ +

Comments:

\ + [notes]" + +// Autogenerates a table which will resemble the traditional wiki table. +/datum/lore/codex/page/overview + name = "Overview" + data = "This has a table of all the corporate violations and legal crimes contained inside this book. The 'mandated' area \ + determines the flexibility/strictness allowed in sentencing for violations/crimes." + +/datum/lore/codex/page/overview/add_content() + var/list/law_sources = list( + /datum/lore/codex/category/corporate_minor_violations, + /datum/lore/codex/category/corporate_major_violations, + /datum/lore/codex/category/law_minor_violations, + /datum/lore/codex/category/law_major_violations + ) + var/list/table_color_headers = list("#66ffff", "#3399ff", "#ffee55", "#ff8855") + var/list/table_color_body_even = list("#ccffff", "#66ccff", "#ffee99", "#ffaa99") + var/list/table_color_body_odd = list("#e6ffff", "#b3e6ff", "#fff6cc", "#ffd5cc") + spawn(2 SECONDS) // So the rest of the book can finish. + var/HTML + HTML += "
" + var/i + for(i = 1, i <= law_sources.len, i++) + var/datum/lore/codex/category/C = holder.get_page_from_type(law_sources[i]) + if(C) + HTML += "" + HTML += "" + HTML += " " + HTML += " " + HTML += " " + HTML += " " + HTML += " " + HTML += " " + HTML += " " + + var/j = 1 //Used to color rows differently if even or odd. + for(var/datum/lore/codex/page/law/L in C.children) + if(!L.name) + continue // Probably something we don't want to see. + HTML += " " + HTML += " " + HTML += " " + HTML += " " + HTML += " " + HTML += " " + HTML += " " + j++ + + HTML += "
[quick_link(C.name)]
IncidentDescriptionSuggested PunishmentNotesMandated?
[quick_link(L.name)][L.definition][L.suggested_punishments][L.notes][L.mandated ? "Yes" : "No"]
" + HTML += "

" + HTML += "
" + + data = data + HTML + ..() \ No newline at end of file diff --git a/code/modules/lore_codex/legal_code_data/sif_law.dm b/code/modules/lore_codex/legal_code_data/sif_law.dm new file mode 100644 index 0000000000..e143f7f6c5 --- /dev/null +++ b/code/modules/lore_codex/legal_code_data/sif_law.dm @@ -0,0 +1,285 @@ +/datum/lore/codex/category/sif_law + name = "Sif Law" + data = "This section contains the abbreviated Sif Govermental Authority legal code's potential charges for crimes that are relevant to \ + the reader." + children = list( + /datum/lore/codex/page/legal_punishments, + /datum/lore/codex/category/law_minor_violations, + /datum/lore/codex/category/law_major_violations + ) + +/datum/lore/codex/page/legal_punishments + name = "Punishments (Law)" + data = "A violation of Sif Law is considered far more serious then a violation of corporate regulations. \ + As a result, its expected that a member of Internal Affairs be present to observe and assist security with the paperwork if they are able. \ + Unlike Corporate Regulations, all violations of Sif Law will require a fax detailing the events to be sent to the \ + Sif Governmental Authority within a certain amount of time based on whether or not it was a minor or major violation. \ + Punishments will usually include brig time with fines still remaining an option for the far less serious crimes. \ + It should be noted that a majority of major violations carry a 'Hold till Transfer' order." + +/datum/lore/codex/category/law_minor_violations + name = "Minor Violations (Law)" + data = "Here is a list of the less severe violations of local Sif Law that might occur on your facility. A fax to the Sif Governmental Authority \ + is required to be sent within 24 hours of a violation being comitted, for minor violations listed here." + children = list( + /datum/lore/codex/page/law/theft, + /datum/lore/codex/page/law/assault, + /datum/lore/codex/page/law/battery, + /datum/lore/codex/page/law/vandalism, + /datum/lore/codex/page/law/animal_cruelty, + /datum/lore/codex/page/law/disrespect_dead, + /datum/lore/codex/page/law/slander, + /datum/lore/codex/page/law/drone_id_failure + ) + +/datum/lore/codex/page/law/assault/add_content() + name = "Assault" + definition = "To threaten use of physical force against someone while also having the capability and/or intent to carry out that threat." + suggested_punishments = "Seperation of offender from the threatened person. Brig time of 10 minutes for first offense. \ + Repeat offenders can be brigged for up to (10 minutes times number of previous assault charges). Demotion at discretion of Superior." + notes = "Not to be confused with [quick_link("Battery")], which covers actual physical injury. The threat must be viable and serious; \ + two people threatening to punch each other out over comms wouldn't fall under this." + ..() + +/datum/lore/codex/page/law/battery/add_content() + name = "Battery" + definition = "To unlawfully use physical force against someone which results in injury to the attacked party." + suggested_punishments = "Brig time of 20 minutes for first offense. Repeat offenders are to be brigged for up to \ + 20 minutes times number of previous battery charges. Demotion at discretion of Superior. Weapons or other objects used (such as flashes) may be \ + confiscated at discretion of Arresting Officer." + notes = "Not to be confused with [quick_link("Assault")], which covers the threat of harm. If the victim suffers life-threatening injuries, the more \ + serious [quick_link("Aggravated Battery")] charge should be applied instead." + mandated = TRUE + ..() + +/datum/lore/codex/page/law/theft + name = "Theft" + definition = "To knowingly take items without the consent of the owner." + suggested_punishments = "Brig time of 20 minutes. Demotion at discretion of Superior. Confiscation of tools used at discretion of arresting officer." + notes = "It is assumed that persons inside a department using departmental equipment have the consent of NanoTrasen to take those items. \ + Security does not commit theft when taking contraband away from a detainee. Stolen items are to be confiscated and returned to \ + their original owner or location." + mandated = TRUE + +/datum/lore/codex/page/law/vandalism/add_content() + name = "Vandalism" + definition = "To deliberately damage or deface the station." + suggested_punishments = "Fine of up to 200 thaler or brig time of up to 30 minutes. \ + Demotion at discretion of Superior. Confiscation of tools used at discretion of arresting officer." + notes = "This should be used for minor damages such as broken windows which do not lead to vacuum, flipping tables, breaking \ + lights, ripping up floor tiles, and such. More serious or life threatening damages should have [quick_link("Sabotage")] applied instead." + ..() + +/datum/lore/codex/page/law/animal_cruelty + name = "Animal Cruelty" + definition = "To inflict unnecessary suffering or harm on a non-sapient biological being which poses no threat to any persons." + suggested_punishments = "Brig time of 1 hour. Demotion at discretion of Superior, however recommended." + notes = "This does not include the use of monkeys for test subjects for legitimate scientific experimentation, such as viral research, \ + or xenobiological applications. It also does not include the butchering of livestock animals for meat, nor does it include violence against a threatening \ + animal, such as Carp." + mandated = TRUE + +/datum/lore/codex/page/law/disrespect_dead + name = "Disrespect to the Dead" + definition = "To damage, disfigure, butcher, or otherwise physically violate the integrity or former identity of a corpse." + suggested_punishments = "Brig time of 1 hour. Demotion at discretion of Superior, however recommended." + notes = "The butchering of livestock animals does not fall under this charge. Autopsies, and the harvesting of organs for \ + donation in accordance with postmortem instructions also do not fall under this." + mandated = TRUE + +/datum/lore/codex/page/law/drone_id_failure + name = "Failure to Present Drone ID" + definition = "Failing to carry or present an EIO-issued Drone Identification card as a Drone intelligence." + suggested_punishments = "200 thaler fine. Give Drone a temporary paper stating that it is a drone, if the ID was lost. Fax SifGov. Inform owner of \ + Drone if possible. Instruct Drone to obtain new ID at its earliest opportunity, if it was lost." + notes = "This is only applicable to Drone intelligences which possess autonomous capability. It must be proven that the offender is a Drone, which can be \ + accomplished in various ways, generally with the expertise of a Roboticist. Lawbound synthetics, maintenance drones, and \ + simple bots do not require an ID card. No fine or SifGov fax should be sent if the Drone's ID was lost due to theft and the ID is able to be recovered." + mandated = TRUE + +/datum/lore/codex/page/law/slander + name = "Slander / Libel" + definition = "To spread false rumours in order to damage someone's reputation." + suggested_punishments = "150 thaler fine." + notes = "Slander is for verbal cases, where as Libel is for written cases." + mandated = TRUE + +/datum/lore/codex/category/law_major_violations + name = "Major Violations (Law)" + data = "Here is a list of the serious violations of local Sif Law that might occur on your facility. A fax to the Sif Governmental Authority \ + is required to be sent within one hour, or when it is safe to do so, for major crimes listed here." + children = list( + /datum/lore/codex/page/law/aggravated_battery, + /datum/lore/codex/page/law/tampering_with_evidence, + /datum/lore/codex/page/law/embezzlement, + /datum/lore/codex/page/law/excessive_force, + /datum/lore/codex/page/law/manslaughter, + /datum/lore/codex/page/law/murder, + /datum/lore/codex/page/law/suicide_attempt, + /datum/lore/codex/page/law/unlawful_law_changes, + /datum/lore/codex/page/law/transgressive_tech, + /datum/lore/codex/page/law/unrated_drones, + /datum/lore/codex/page/law/grand_theft, + /datum/lore/codex/page/law/sabotage, + /datum/lore/codex/page/law/hostage_taking, + /datum/lore/codex/page/law/terrorist_acts + ) + +/datum/lore/codex/page/law/aggravated_battery/add_content() + name = "Aggravated Battery" + definition = "To unlawfully use physical force against someone which results in serious or life-threatening injury to the attacked party." + suggested_punishments = "Hold until Transfer. Weapons or other objects used are to be confiscated." + notes = "Not to be confused with assault, which covers the threat of harm. If the victim did not suffer life-threatening injuries, the less \ + serious [quick_link("Battery")] charge should be applied instead." + mandated = TRUE + ..() + +/datum/lore/codex/page/law/tampering_with_evidence/add_content() + name = "Tampering with Evidence / Obstruction of Justice" + keywords += list("Tampering with Evidence", "Obstruction of Justice") + definition = "To take intentional action to obstruct or inhibit investigation of a crime or regulation violation." + suggested_punishments = "Hold until Transfer if obstructing a crime. Demotion or termination if obstructing a regulation violation." + notes = "This can include cleaning up blood at a crimescene, hiding evidence, scrubbing the messaging server/telecomms logs, and burning papers. \ + Planting or altering evidence, giving false testimony, preventing Security from investigating, or extorting any person to do the same also falls \ + under this charge. Blood being cleaned at a location not cordoned off with Security tape does not fall under this charge." + mandated = TRUE + ..() + +/datum/lore/codex/page/law/embezzlement + name = "Embezzlement" + definition = "Stealing money that is entrusted to you by a corporation or person." + suggested_punishments = "Hold until Transfer. Termination. Reimbursement of embezzled funds. Fax Central Command and SifGov." + notes = "This includes funneling Departmental, Facility, or Crew funds into the offender's account. It also includes pocketing \ + transactions directly that are meant to go to a seperate account." + mandated = TRUE + +/datum/lore/codex/page/law/excessive_force/add_content() + name = "Excessive Force" + definition = "Using more force than what is required to safely detain someone, using force against a helpless or incapacitated person, \ + or using force against an unarmed and compliant person." + suggested_punishments = "Demotion. Termination at discretion of Superior, or Station Director. Send notice to Central Command if a Head of Security had used excessive force." + notes = "This charge also is applicible to non-Security personnel acting in self defense. \ + Persons whom have caused a person to die as a result of excessive force should have [quick_link("Manslaughter")] applied instead, if the circumstances were \ + unjustified." + ..() + +/datum/lore/codex/page/law/manslaughter/add_content() + name = "Manslaughter" + definition = "To kill a sapient being without intent." + suggested_punishments = "Hold until Transfer, if unjustified. Fax SifGov." + notes = "Includes provoked manslaughter, negligent manslaughter, and impassioned killing. The important distinction between this \ + and [quick_link("Murder")] is intent. Manslaughter can be justified if force was nessecary and it was intented to prevent further loss of life or \ + grievous injury to self or others, however persons involved in the kill will still be required to answer to higher legal authority \ + after the shift." + mandated = TRUE + ..() + +/datum/lore/codex/page/law/murder/add_content() + name = "Murder" + definition = "To kill or attempt to kill a sapient being with malicious intent." + suggested_punishments = "Hold until Transfer. Termination. Fax SifGov." + notes = "The distinction between this and [quick_link("Manslaughter")] is intent. Sapients held within synthetic bodies, lawbound or otherwise, which receive \ + critical damage from someone can be considered a murder attempt." + mandated = TRUE + ..() + +/datum/lore/codex/page/law/suicide_attempt + name = "Suicide Attempt" + definition = "To attempt or threaten to commit suicide." + suggested_punishments = "Compulsory psychiatric examination." + notes = "If a mental care specialist is unavailable, they are to be held until transfer, to be moved to a qualified mental care facility." + mandated = TRUE + +/datum/lore/codex/page/law/transgressive_tech/add_content() + name = "Experimentation with Transgressive Technology" + keywords += list("Transgressive", "Illegal Technology") + definition = "Experimenting with technologies deemed unsafe or are otherwise federally restricted by the Solar Confederate Government." + suggested_punishments = "Hold until Transfer. Termination. Fax SifGov. Delete, destroy, or otherwise remove the experiments." + notes = "Unsafe technologies include unrestricted nanomachinery, massive sapient body bio-augmentation, massive sapient brain augmentation, \ + massively self-improving AI, and animal uplifting." + mandated = TRUE + ..() + +/datum/lore/codex/page/law/unrated_drones + name = "Creation of Unrated Drone Intelligence" + definition = "Creating an intelligence from an codeline that has not been registered with, or audited by, the Emergent Intelligence Oversight (EIO)." + suggested_punishments = "Decommissioning of the newly created Drone. Investigation of Drone to determine level of intelligence, if possible. \ + Hold until Transfer for the creator." + notes = "It must be proven that the Drone is in fact a Drone, which can be accomplished in various ways, generally with the expertise of a Roboticist. \ + It must also be proven that the Drone's codeline is also unregistered. Intelligences produced from a Maintenance Drone Fabricator, \ + the Research department, and through other regular means are by default already registered. Very simple machines such as securitrons do not require registration.\ +

\ + The remains of the Drone are to be brought to the Spaceport at the earliest opportunity. Their creator is to also be brought there, so that \ + they may be questioned by federal authorities." + mandated = TRUE +/* + Punishments for estimated Drone Class.;\ + " +*/ +/datum/lore/codex/page/law/unlawful_law_changes + name = "Unlawful Alteration of Bound Synthetics" + definition = "Modifying a bound synthetic's lawset or chassis, in order to force it to do illegal, humiliating, dangerous, or other unlawful acts." + suggested_punishments = "Hold until Transfer. Termination. Fax SifGov." + notes = "If the synthetic is a cyborg or positronic, this is also an offense against the Sapient Rights laws federally mandated by the Solar Confederate Government." + mandated = TRUE + +/datum/lore/codex/page/law/grand_theft + name = "Grand Theft" + definition = "To steal items that are dangerous, of a high value, or a sensitive nature." + suggested_punishments = "Hold until Transfer. Termination. Fax SifGov." + notes = "This can include the following;\ +
" + mandated = TRUE + +/datum/lore/codex/page/law/sabotage/add_content() + name = "Sabotage" + definition = "To deliberately damage, or attempt to damage the facility, or critical systems of the facility." + suggested_punishments = "Hold until Transfer. Termination. Fax SifGov." + notes = "This includes causing hull breaches, arson, sabotaging air supplies, stealing vital equipment, tampering with AI or telecomm systems, and sabotaging the \ + Engine. If someone has only caused minor damage, the [quick_link("Vandalism")] charge should be used instead." + mandated = TRUE + ..() + +/datum/lore/codex/page/law/hostage_taking/add_content() + name = "Kidnapping / Hostage Taking" + keywords += list("Kidnapping", "Hostage Taking") + definition = "To unlawfully confine, transport, or hold a sapient being against that individual's will." + suggested_punishments = "Hold until Transfer. Termination. Fax SifGov." + notes = "Persons held for ransom or exchange are also considered to be hostages for this charge." + mandated = TRUE + ..() + +/datum/lore/codex/page/law/terrorist_acts/add_content() + name = "Terrorist Acts" + keywords += list("Terrorism") + definition = "To engage in maliciously destructive actions, which seriously threaten the crew or facility, or the usage of weapons of mass destruction." + suggested_punishments = "Hold until Transfer. Termination. Fax SifGov." + notes = "This includes the use of mass bombings, mass murder, releasing harmful biological agents, nuclear weapons, \ + radiological weapons, and chemical weapons." + mandated = TRUE + ..() \ No newline at end of file diff --git a/code/modules/lore_codex/legal_code_data/sop.dm b/code/modules/lore_codex/legal_code_data/sop.dm new file mode 100644 index 0000000000..10d14b1632 --- /dev/null +++ b/code/modules/lore_codex/legal_code_data/sop.dm @@ -0,0 +1,348 @@ +/datum/lore/codex/category/standard_operating_procedures + name = "Standard Operating Procedures" + data = "This section details the various Standard Operating Procedures (often shortened to 'SOP') one may find onboard a NanoTrasen facility." + children = list( + /datum/lore/codex/page/general_sop, +// These are still being discussed +// /datum/lore/codex/page/command_sop, +// /datum/lore/codex/category/security_sop, +// /datum/lore/codex/page/engineering_sop, +// /datum/lore/codex/category/medical_sop, +// /datum/lore/codex/page/science_sop, + /datum/lore/codex/category/alert_levels + ) + +/datum/lore/codex/page/general_sop + name = "General SOP" + data = "This applies to everyone onboard a NanoTrasen facility, including guests. Note that specific departmental operating procedures can override some of \ + the procedures listed here.\ +

\ +

Visitors

\ + Visitors of all forms are required to follow SOP, Corporate Regulations, and local laws while onboard or around NanoTrasen property. Visitors who are \ + not registered on the manifest are required to speak with the Head of Personnel or Station Director, if one exists, to register, and obtain an identification \ + card denoting their status as a visitor. Visitors registered on the manifest are free to visit any public (non-access restricted) location on the facility, however \ + they are still subject to the same regulations and rules as an ordinary crew member.\ +
\ +

Dress Code

\ + All crew members and visitors, with exceptions listed below, are to wear the following at minimum: A shirt that covers the chest, pants, shorts or skirts that \ + go no shorter than two inches above the knee, and some form of foot covering. Those in departments considered to be emergency services (Security, \ + Medical, Engineering) should wear a marker denoting their department, examples being armbands, uniforms, badges, or other means. Those in a department \ + are expected to wear clothes appropiate to protect against common risks for the department. Off duty personnel, visitors, and those engaging in certain recreational \ + areas such as the Pool (if one is available on your facility) have less strict dresscode, however clothing of some form must still be worn in public.\ +

\ + Exceptions: Skrell, Teshari, and Unathi are expected to cover at minimum their lower bodies. Tajaran males may go topless, as a means to keep cool. \ + Dionaea and 'robotic' synthetics have no minimum required amount of clothing, however they should still wear a departmental marker if in a department. \ + 'Realistic' synthetics are expected to have the same minimum as the species they appear as.\ +
\ +

Breach/Fire Procedure

\ + Emergency shutters are yellow-colored doors which lock down the flow of gas automatically, if the facility's systems detect an issue with the atmosphere. \ + If lights on the shutter are flashing, do not open the shutter, or you will endanger both yourself and anyone else with you. Allow Engineering to \ + resolve the issue. If you must enter a breached or burning area, appropriate safety gear must be worn. Use inflatable doors and walls in order to present \ + less risk to other crew members, if possible.\ +
\ +

EVA Procedure

\ + Extravehicular activity should only be done by EVA trained and certified crew members, if there is no emergency. If an emergency is occuring, NanoTrasen \ + provides high visibility, easy to seal emergency softsuits inside blue emergency lockers located at key locations inside your facility. Regardless, \ + for your own safety, you should only enter or exit the facility from designated external airlocks, which contain an air cycling system. It is both \ + wasteful and potentially dangerous to 'force' an external airlock to open before cycling has completed. Before cycling out into the void, the person going \ + on EVA should double check that their internal oxygen supply (or cooling system, if they are a synthetic) is functioning properly and that they have an adaquate \ + amount of oxygen inside the tank. Magnetic boots are also highly suggested if the person will be scaling the sides of your facility, to prevent drifting away \ + from the facility.\ +

\ + Persons going on EVA are to inform their department, or if that is not possible, the facility proper, of leaving. Those on EVA are recommended to maximize their \ + suit sensors, and maintain contact with the facility with radio, if possible.\ +
\ +

Shuttle Docking and Elevator Safety

\ + No one is to remain outside the designated docking areas for shuttles and elevators, as those areas are extremely hazardous. If repairs or other work are \ + required to be done in those areas, at least one crew member is required to be at the shuttle or elevator's associated console, in order to cancel any movement.\ +
\ + " +/* +/datum/lore/codex/page/command_sop + name = "Command SOP" + data = "This SOP is specific to those in the Command department, which includes the Station Director, Head of Personnel, Chief Engineer, Head of Security, and Research Director. \ + This also covers Internal Affairs Agents, however they do not occupy a position inside Command crew, and instead exist outside of all the other departments.\ +
\ +

Bridge Secretaries

\ + Bridge Secretaries are not considered Command crew. They are present to assist the Command crew where needed. Command Secretaries are equivalent to station crew in all other \ + regards.\ +
\ +

Responsibility and Authority

\ + The Chain of Command is generally represented as: Station Director > Command Crew > Station Crew.
\ + The Station Director is responsible for, and authoritative in, and and all matters regarding the station. In the absence of a Department Head, the Station Director \ + may choose to appoint an Acting Head, or else act as the voice of authority in a department. If a Department Head arrives on station, the Acting Head \ + is to step down, and the Station Director is to defer to the Department Head in matters involving said department.\ +
\ + The remainder of the Command Crew is of equal rank among themselves, and are responsible for, and authoritative over only their own department, crew, and location. \ + In the case of the Head of Personnel, this includes Service, Cargo, and any other Civilian role. Command Crew only have authority in their own department, when going \ + outside of their department, they must work through the same channels as Station Crew.\ +
\ +

Demotion

\ + A member of the Command Crew may call for the demotion of any member of their department for disregarding safety protocol, disobeying orders with serious consequences, \ + or other gross incompetence. Certain infractions necessitate that a guilty crew member receive a demotion. Demotion is to be performed by the Head of Personnel, or the \ + Station Director, as soon as possible. The demoted crewmember is to be present during the demotion, unless it is caused by a criminal sentence. If said crewmemeber \ + refuses to comply with a demotion order, Security is to escort them to the Head of Personnel's office.\ +
\ + Any demoted crewmember must return all equipment and non-personal items to their previous department, including departmental jumpsuits and radios. If a demoted \ + crewmember does not have personalized clothing, they are welcome and encouraged to use a grey jumpsuit. If they do not return department property, Security \ + may treat said items as stolen.\ +
\ +

Chain of Command & Succession

\ + In case of emergency or other need, and in the absence of a Station Director, an Acting Director may be selected from active, certified Command crew. \ + The selected individual has the same responsibility and authority as a certified Station Director, along with that of their regular position, with the assumption that \ + they will step down if a certified Station Director arrives on station. This role is entirely voluntary, and no Command crew may be forced into the role \ + if they are opposed to doing so.\ +
\ + The preferred order of selecting an Acting Director is as follows:
\ + The role is to be offered to the Head of Personnel, if one is present. If there is no Head of Personnel, or they are unwilling to assume Acting Director, the \ + position is offered to non-Security Command crew. If no other Command crew is available or willing to assume Acting Director, the Head of Security may be offered \ + the position. If no other Command crew is available or willing to assume Acting Director, no Acting Director is selected. Acting Command may not be offered or accept \ + Acting Director.\ +
\ +

Command Crew Demotions

\ + If a member of the Command crew is suspected to be incompetent, or in breach of SOP, the Station Director has discretion to demote the guilty Command crewmember. \ + If there is no Station Director, or the Station Director themselves is guilty, they may be demoted after a vote of no confidence by the remaining Command crew \ + and relevant station crew. For the Station Director, the vote is only to be among the remaining Command crew. Misuse of this privilage may warrant an \ + Internal Affairs investigation for wrongful dismissal.\ +
\ +

Communications with Central Command

\ + The individuals hired to fill Command roles are expected to be competent in their roles and duties, and contacting Central Command when it is not strictly \ + necessary may reflect poorly upon them. As such, Command crew should try to find and act upon a solution that does not require Central Command input, before \ + any messages are sent. However, please do not be discouraged from sending proper IA reports, incident notifications, and other necessary paperwork as detailed \ + in this book.\ +
\ +

Internal Affairs

\ + Internal Affairs Agents are on station at the behest of Human Resources. They are not subordinate to the Command crew, but neither is anyone subordinate to them. \ + Internal Affairs Agents are to work with the Command crew when possible. An agent is to not go above the authority of the Command crew unless said Command crew \ + member is involved, or otherwise unable to assist in the matter. Any member of the crew can be subject to an Internal Affairs investigation. This includes \ + the Command crew and other Internal Affairs agents. If the Internal Affairs investigation reveals wrongdoing, including SOP breach, the investigated party is to \ + be punished according to Corporate Regulations or Sif Law, whichever is applicable, or from orders from Central Command." + +/datum/lore/codex/page/engineering_sop + name = "Engineering SOP" + data = "This SOP is specific to those in the Engineering department, and focuses on engine safety, breach response, atmospherics, and such. \ +
\ +

Engine Safety

\ + Your facility's engine is what provides the majority of electricity to the rest of your facility. As such, the engine is to have priority over \ + all other engineering issues, including breaches, if an issue with the engine exists. This book assumes your facility is using one or more thermoelectric engines \ + (generally referred to as TEGs), driven by a Supermatter crystal. If this is not the case, please consult the documentation for your specific engine for safety precauctions.\ +
\ + The Supermatter crystal is what presents the most danger to a crewmember. The Supermatter is to remain isolated inside the engine room, inside \ + its own chamber, for several reasons. First, Supermatter reacts poorly to oxygen, harming the crystal and causing heat. Second, the crystal \ + will vaporize most matter it comes into contact with, which includes crewmembers. Never touch the Supermatter. Third, having an isolated chamber \ + is needed in order to drive the TEGs. Under no circumstances is the Supermatter to be moved outside the chamber, unless for Ejection Procedure.\ +
\ + Safety gear must be worn while inside the engine room at all times. This safety gear includes a full Radiation Suit, as well as Meson \ + Goggles. If a Radiation Suit cannot be worn, due to an emergency, the engineering voidsuit provides some shielding from the radiation, \ + however it is inferior to the regular suit, and medical attention is advised after leaving the engine room.\ +
\ + The engine room contains a powerful industrial laser, generally called an Emitter. Never stand in front of an Emitter, even if it is inactive. \ + The Emitter is used to 'charge' the Supermatter, so that it releases heat in a controlled manner. An excessive amount of Emitter blasts can cause \ + engine instability. As such, the Emitter should never be left unattended if it is active.\ +
\ + The engine monitoring room contains various consoles to adjust and monitor the engine and facility systems. Due to the risk that untrained persons can \ + present to themselves and others, Non-Engineering crew should not enter the engine room, or the engine monitoring room, without good cause.\ +
\ +

Atmospherics

\ + Atmospherics in this context refers to both the systems used to maintain air onboard your facility, as well as the centralized room which contains those \ + systems. Atmospherics should never be modified by untrained personnel, as this can put the entire facility at risk. As such, non-Engineering crew are \ + not permitted inside Atmospherics without permission, as well as supervision from a member of Engineering.\ +
\ + The distribution loop (generally referred to as Distro) is a pipeline distinguished by a dark blue color which connects Atmospherics with the rest of the \ + facility, with the ventilation system. The pressure of Distro should be tightly regulated, and should not contain excessive amounts of gas. The air vents \ + will try to prevent 'over-filling' a room, however this system is not perfect, and extremely high Distro pressures can cause a safety hazard.\ +
\ +

Breach Response

\ + If a room becomes breached, the first priority is to evacuate any crewmembers and guests endangered by the breach, especially if they lack an EVA \ + suit. Emergency softsuits are available in cyan colored lockers at key locations on your facility, if an untrained person requires short term EVA \ + capability. After all endangered crewmembers and guests are evacuated, repairs should be prioritized. Do not risk your life in order to start repairs, \ + Only begin repairs once it is safe to do so. It is more important to have an area be usable, than it is to have it look exactly the way it did before it \ + was damaged. As such, cosmetic details should be done last. Breach repairs always have priority over construction projects.\ +
\ +

Delamination

\ + The Supermatter is volatile, and can undergo the process of 'delamination' if sufficently damaged. To help warn against this, all Supermatter crystals \ + come with a small monitoring microcontroller, which will warn the Engineering department if the Supermatter is being damaged. Damage can result from \ + excessive heat, vacuum exposure, or physical impacts. If the Supermatter achieves delamination, it will cause a massive explosion, deliver a \ + massive dose of radiation to everyone in or near your facility, and may cause hallucinations. Delamination prevention should be prioritized above \ + all else. Generally this should be done by removing the source of damage, the most common being excessive heat inside the isolation chamber. \ + The crew must be informed of a risk of engine delamination if the issue cannot be resolved quickly or if there is a moderate risk of delamination. If \ + delamination cannot be prevented, please see Ejection Procedure.\ +
\ +

Ejection Procedure

\ + The Supermatter's isolation chamber contains a mass driver and a heavy blast door leading into space. Ejecting the Supermatter into the void \ + will cause it to delaminate, however hopefully far away from your facility. Supermatter crystals are rare and expensive, so this option should \ + only be used if delamination cannot be stopped by any other means. A special button, behind glass, exists inside the Chief Engineer's office. \ + The button controls the mass driver, however it should not be the first button to press. The blast door leading into space must be opened first, \ + or else the Supermatter cannot be ejected. Premature ejection can cause the Supermatter to not be on the mass driver, which will require an extremely \ + risky manual Supermatter movement to place onto the mass driver again. The blast door can be opened with a button in the Chief Engineer's office, or inside the engine room. \ + It is the same button used to 'vent' the engine core. Make use of engine core cameras to verify that the blast door is open. \ + The Chief Engineer should be the one to oversee Ejection. If one does not exist, the facility's AI should initiate Ejection. If there is no AI, \ + it would be prudent for an Engineering member to forcefully enter to press the required buttons." + +/* +/datum/lore/codex/page/medical_sop + name = "Medical SOP" + data = "This SOP is specific to those in the Medical department, and focuses on Triage/First Aid priority, Proper Cloning procedure and CMD, how to store a body, and DNC orders. \ +
\ +

Triage / First Aid Priority

\ + The priority for Triage, is generally;\ +
\ + Safety > Dying > Wounded > Injured > Dead\ +
\ + \ +
\ +

Cloning Procedure

\ + Persons whom have committed suicide are not to be cloned. Individuals are also to not be cloned if there is a Do Not Clone (generally referred \ + to as DNC) order in their medical records, or if the individual has had a DNC order declared against them by the Station Director, Chief \ + Medical Officer, or Head of Security. If any of this occurs, procede to Portmortem Storage.\ +
\ + Some individuals may have special instructions in their Postmortem Instructions, generally found in their medical records. \ + Be sure to read them before committing to cloning someone. In particular, some instructions may express a desire to be placed \ + inside a synthetic body. If this is the case, contact Robotics. If robotics is not available, and no instructions for \ + cloning exist in their records, proceed to Postmortem Storage.\ +
\ + If no records are included, it is assumed that the patient wishes to be cloned, and should be cloned.\ +
\ + Ensure that all cloning equipment, including the cryogenic tubes, are functional and ready before cloning begins. Once \ + this is done, scan the deceased. Up to three scans are to be made per attempt. If the deceased suffers Mental Interface Failure, \ + procede to Postmortem Storage. Further attempts at resuscitation may be made at later times, at the medical teams' discretion. \ +
\ + If the deceased is sufficently scanned, remove their possessions and clothing off of the deceased body, for use by the future new clone. \ + Move the cadaver into the morgue, as per Postmortem Storage. Begin the cloning process. Possessions are to be gathered in a manner that \ + facilitates transporting them along with the clone. Upon the cloning process being complete and the new clone being created, the \ + clone is to be placed inside a croygenic tube as quickly as possible. Cloning is not a painless experience, and it is best if \ + the patient reawakens inside a functional body. Once their body is fully functional, dress and process the newly cloned patient, \ + informing them of any procedures performed on them, including the cloning itself.\ +
\ +

Clone Memory Disorder

\ + Clones, persons transferred to MMIs, and recently restarted synthetics will not remember the events which lead to their demise. \ + They are to be told that they have been resurrected, and any further questions they have should be answered, if possible. Organic \ + individuals revived by a defibrillator do not experience this phenomenon.\ +
\ +

Postmortem Storage

\ + Bodies placed in the morgue should be contained inside black body bags. The body bag is to be labelled with the deceased's name, along \ + with 'DNC', 'MIF', or 'Cloned' where applicable. Bodies in the morgue are to be transferred to Central Command whenever possible. Funerary \ + services are to be handled off site. A service may be held within the Chapel if it is desired, however the body must still be brought to \ + Central.\ +

Breach Response

\ + If a room becomes breached, the first priority is to evacuate any crewmembers and guests endangered by the breach, especially if they lack an EVA \ + suit. Emergency softsuits are available in cyan colored lockers at key locations on your facility, if an untrained person requires short term EVA \ + capability. Those exposed to vacuum without protection will almost certainly require advanced medical care, so bring anyone harmed to Medical. \ + Remember to avoid risking your own life, as stated in the Triage section." +*/ +/datum/lore/codex/page/science_sop + name = "Research SOP" + data = "This SOP is specific to those in the Research department, and focuses on Experiment Safety, Toxins Safety, and Robotics.\ +
\ +

Experiment Safety

\ + Experiments should remain within the Research department, unless they are entirely safe. Xenoarchaeological finds should never \ + leave the Research Outpost if they demonstrate any risk of harming crewmembers and visitors (not 'inert'). Live xenobiological specimens should \ + never be brought outside the Xenobio section. Xenoflora specimens should not be spread outside Xenoflora, unless it is proven that \ + a specific specimen is completely harmless and safe.\ +
\ +

Toxins Safety

\ + Toxins potentially has the greatest capability to harm the experimentor as well as their co-workers, so always be vigilent. \ + The incinerator is designed to withstand phoron fires, however extremely hot fires can cause damage to the incinerator. \ + The experimentor and anyone inside the Toxins section should wear protective clothing while the incinerator is active, and \ + the incinerator should NEVER be left unattended while in use. If damage to the walls of the incinerator are observed, \ + the chamber should be vented into space immediately, to abort the burn, then vacating the lab until the flames are extinguished.\ +
\ + Another danger of Toxins is that the experimentor will be handling explosives at some point, in order to test on the \ + Toxins Testing Range. Explosives are to be tested at the Testing Range, and absolutely no where else. \ + When placing an explosive on the mass driver to fire to the Testing Range, the experimentor should triple check that their \ + explosive's signaler frequency and code is unique (if using a signaler). Verify that the signaler's frequency and code do not match multiple \ + explosives. Check for any signs of life near the Testing Range before detonation, and warn the facility that an Toxins Test will be \ + occuring shortly, as otherwise it may scare the crew and may endanger anyone near the Testing Range.\ +
\ +

Robotics

\ + Robotics exists to service the facility's synthetics, crewmembers with prosthetics, create and maintain exosuits, and create and \ + maintain robots to assist the facility. Many types of synthetics exist, and this section will try to clarify what to do for each kind.\ +
\ + Cyborgification, the process of an organic person's brain being transplanted into a Man-Machine-Interface (MMI), should only be done to \ + a person upon their death, and if their medical records state a desire to be placed inside a synthetic body instead of a desire to be cloned. \ + Persons who have commited suicide, or persons who have Do-Not-Clone (DNC) orders which don't specifically list cyborgification as an alternative are \ + not to be placed inside an MMI. Still-living persons who wish to be placed inside an MMI should be ignored.\ +
\ + Lawbound Synthetics are to not have their lawset tampered with. Any errors with the lawset, intentional or resulting from an ionic storm, should \ + be reset by the Research Director or Chief Engineer. If they are unavailable, it is permissible for Robotics to do the reset. Lawbound Synthetics \ + physically harmed should be repaired.\ +
\ +

Lawing Synthetics

\ + Different 'types' of brains have different priorities upon receiving one to place inside a chassis.\ + \ +
\ +

Exosuits & Prosthetics

\ + Exosuits (also known as Mecha, or Mechs) are large machines piloted by an individual. Construction of exosuits is to occur inside Robotics or the \ + Mech Bay. Damaged exosuits should be repaired by Robotics. Civilian Exosuits (Ripley, Odysseus) may be built at the request of departmental crew. \ + Combat exosuits (Durand, Gygax) may not be built without permission from the Head of Security or Station Director.\ +
\ + Robotics is also tasked with the repair of prostheses limbs. Robotics may also be tasked with installing a prosthetic, however the Medical team \ + may also do this if the Robotics staff lack the training to do so." +*/ +/datum/lore/codex/category/alert_levels + name = "Alert Levels" + data = "NanoTrasen facilities oftentimes use a color-coded alert system in order to inform the crew of ongoing danger or other threats. Below is a list of \ + alert levels, as well as how the facility should shift in response to a change in an alert. You can check what the current level is by looking at a fire alarm. \ + Alert levels can be set by Command staff from a specific console located in the bridge. For Red alert, two Heads of Staff are required to swipe an ID on a device inside \ + their office in order to trigger it." + children = list( + /datum/lore/codex/page/green, + /datum/lore/codex/page/blue, + /datum/lore/codex/page/red + ) + +/datum/lore/codex/page/green + name = "Green Alert" + data = "Green is the default level, and it means that no threat to the facility currently exists.\ +
\ +

Locations

\ + Secure areas are recommended to be left unbolted, which includes the AI Upload, Secure Technical Storage, and the Teleporter(s). The Vault should remain sealed. \ + Heads of Staff may enter the AI Upload alone, although they must have sufficent justification. \ +
\ +

Crew

\ + Crew members and visitors may freely walk in the hallways and other public areas. Suit sensors are recommended, but not mandatory. \ + The Security team must respect the privacy of crew members and visitors, and no unauthorized searches are allowed. Searches of any kind may \ + only be done with the consent of the searched, or with a signed warrant by the Head of Security or Station Director. A warrant is not required \ + for instances of visible contraband." + +/datum/lore/codex/page/blue + name = "Blue Alert" + data = "Blue alert is for when there is a suspected or confirmed threat to the facility.\ +
\ +

Locations

\ +
\ + Secure areas may be bolted down, which includes the AI Upload and Secure Technical Storage. No Head of Staff is to enter the AI Upload without \ + another Head of Staff. If no other Heads of Staff are available, at least one member of Security should be present.\ +
\ +

Crew

\ + Employees and guests are recommended to comply with all requests from Security. Suit sensor activation is mandatory, however the coordinate tracker functionality \ + is not required. Random body and workplace searched are allowed without a warrant. Command can demand that only Galactic Common is spoken on the radio." + +/datum/lore/codex/page/red + name = "Red Alert" + data = "Red alert is the highest level, and is reserved for when the facility is under a serious threat.\ +
\ +

Locations

\ + Secure areas are recommended to be bolted. AI Upload policy is the same for Blue alert.\ +
\ +

Crew

\ + Suit sensors with tracking beacon active are mandatory. Employees and guests are required to comply with all requests from Security or Command. \ + Employees are advised to remain within their departments if it is safe to do so. An Emergency Response Team may be authorized. If one is called, \ + all crew and visitors are to comply with their direction. Privacy policy is the same as Blue alert. Command can demand that only Galactic Common is spoken on the radio." diff --git a/code/modules/lore_codex/legal_code_data/sop/medical.dm b/code/modules/lore_codex/legal_code_data/sop/medical.dm new file mode 100644 index 0000000000..29ba57e6e3 --- /dev/null +++ b/code/modules/lore_codex/legal_code_data/sop/medical.dm @@ -0,0 +1,73 @@ +/datum/lore/codex/category/medical_sop + name = "Medical SOP" + data = "This SOP is specific to those in the Medical department, and focuses on Triage/First Aid priority, Proper Cloning procedure and CMD, how to store a body, and DNC orders." + children = list( + /datum/lore/codex/page/sop_triage, + /datum/lore/codex/page/sop_cloning, + /datum/lore/codex/page/sop_cmd, + /datum/lore/codex/page/sop_postmortem, + /datum/lore/codex/page/sop_medical_breach + ) + +/datum/lore/codex/page/sop_triage + name = "Triage / First Aid Priority" + data = "The priority for Triage, is generally;\ +

\ + Safety > Dying > Wounded > Injured > Dead\ +
\ + " + +/datum/lore/codex/page/sop_cloning + name = "Cloning Procedures" + data = "Persons whom have committed suicide are not to be cloned, without authorization from the Chief Medical Officer. \ + The Chief Medical Officer is fully responsible if they choose to clone a person whom has committed suicide. \ + Individuals are also to not be cloned if there is a Do Not Clone (generally referred to as DNC) order in their medical records, \ + or if the individual has had a DNC order declared against them by the Station Director, Chief Medical Officer, or Head of Security. \ + If any of this occurs, procede to Portmortem Storage.\ +

\ + Some individuals may have special instructions in their Postmortem Instructions, generally found in their medical records. \ + Be sure to read them before committing to cloning someone. In particular, some instructions may express a desire to be placed \ + inside a synthetic body. If this is the case, contact Robotics. If robotics is not available, and no instructions for \ + cloning exist in their records, proceed to Postmortem Storage.\ +

\ + If no records are included, it is assumed that the patient wishes to be cloned, and should be cloned.\ +

\ + Ensure that all cloning equipment, including the cryogenic tubes, are functional and ready before cloning begins. Once \ + this is done, scan the deceased. Up to three scans are to be made per attempt. If the deceased suffers Mental Interface Failure, \ + procede to Postmortem Storage. Further attempts at resuscitation may be made at later times, at the medical teams' discretion. \ +

\ + If the deceased is sufficently scanned, remove their possessions and clothing off of the deceased body, for use by the future new clone. \ + Move the cadaver into the morgue, as per Postmortem Storage. Begin the cloning process. Possessions are to be gathered in a manner that \ + facilitates transporting them along with the clone. Upon the cloning process being complete and the new clone being created, the \ + clone is to be placed inside a croygenic tube as quickly as possible. Cloning is not a painless experience, and it is best if \ + the patient reawakens inside a functional body. Once their body is fully functional, dress and process the newly cloned patient, \ + informing them of any procedures performed on them, including the cloning itself." + +/datum/lore/codex/page/sop_cmd + name = "Clone Memory Disorder" + data = "Clones, persons transferred to MMIs, and recently restarted synthetics will not remember the events which lead to their demise. \ + They are to be told that they have been resurrected, and any further questions they have should be answered, if possible. Organic \ + individuals revived by a defibrillator do not experience this phenomenon." + +/datum/lore/codex/page/sop_postmortem + name = "Postmortem Storage" + data = "Deceased persons should be kept in the morgue, and should be contained inside black body bags. The body bag is to be labelled with the deceased's name, along \ + with 'DNC', 'MIF', or 'Cloned' where applicable. Bodies in the morgue are to be transferred to Central Command whenever possible. Funerary \ + services are to be handled off site. A service may be held within the Chapel if it is desired, however the body must still be brought to \ + Central." + +/datum/lore/codex/page/sop_medical_breach + name = "Breach Response (Medical)" + data = "If a room becomes breached, the first priority is to evacuate any crewmembers and guests endangered by the breach, especially if they lack an EVA \ + suit. Emergency softsuits are available in cyan colored lockers at key locations on your facility, if an untrained person requires short term EVA \ + capability. Those exposed to vacuum without protection will almost certainly require advanced medical care, so bring anyone harmed to Medical. \ + Remember to avoid risking your own life, as stated in the Triage section." \ No newline at end of file diff --git a/code/modules/lore_codex/legal_code_data/sop/security.dm b/code/modules/lore_codex/legal_code_data/sop/security.dm new file mode 100644 index 0000000000..5074fc08a4 --- /dev/null +++ b/code/modules/lore_codex/legal_code_data/sop/security.dm @@ -0,0 +1,119 @@ +/datum/lore/codex/category/security_sop + name = "Security SOP" + data = "This SOP is specific to those in the Security department, and focuses on proper arrest procedure, processing, escalation of force, and such." + children = list( + /datum/lore/codex/page/sop_arrest, + /datum/lore/codex/page/sop_processing, + /datum/lore/codex/page/sop_brigging, + /datum/lore/codex/page/sop_solitary, + /datum/lore/codex/page/sop_prisoner_rights, + /datum/lore/codex/page/sop_sec_alert_levels, + /datum/lore/codex/page/sop_escalation, + /datum/lore/codex/page/sop_hostage + ) + +/datum/lore/codex/page/sop_arrest + name = "Arrest Procedure" + data = "Security is responsible for the health and safety of anyone they arrest. Unless the safety of any crewmember if threatened, all attempts at arrest \ + are to follow this procedure.\ +

\ + Set the suspect to Arrest in their security records (Can be done with a SecHUD). Locate the suspect. Inform them that you are arresting them, \ + as well as the charges they are being arrested under. The following steps assume that the suspect does not respond to the arresting \ + officer in a violent manner. If they follow orders given by the arresting officer, they are considered compliant. If they do not respond, \ + or attempt to non-violently resist arrest, they are considered non-compliant. Applying handcuffs is at the discretion of the arresting officer, \ + but the following is strongly recommended.\ +

\ + If the suspect is compliant, ask them to follow you. Handcuffs are not required if the subject is complaint and not likely to attempt escape. \ + If the suspect is compliant, but likely to attempt escaping arrest, inform them that you will be handcuffing them. If they continue to comply, \ + do so. If the suspect is non-compliant, the arresting officer may attempt to complete the arrest using Less-than-Lethal force. \ + Resisting Arrest may be added to the suspect's punishment if they are found guilty of other crimes. Return to the brig with the \ + suspect for processing." + +/datum/lore/codex/page/sop_processing + name = "Processing" + data = "Processing is the responsibility of the Arresting Officer, or the Warden if the Warden chooses to do so. The suspect is to be informed \ + again of the cause for their arrest, and that they will be searched. Suspects are assumed to be innocent until they are proven guilty. \ + They are to be thoroughly searched. They may not be stripped of their inner clothing, though pockets are to be emptied. \ + Any and all found contraband is to be confiscated, and anything that may be used to escape the brig is to be confiscated until the suspect's release.\ +

\ + Assess the suspect's guilt. Contraband found in the search may be used as evidence at the discretion of the Arresting Officer. If the \ + suspect is found innocent, all non-contraband is to be returned to them, and they are to be released. If instead they are found guilty and \ + brig time is required by the type of violation they are guilty of, or have chosen brig time as an alternative to a fine if possible, they \ + are now considered a Prisoner, and further processing is the responsibility of the Warden, if one is present. If no Warden is present, the \ + Arresting Officer is to continue processing.\ +

\ + The Prisoner is to be informed of their Sentencing Options, if available. These will vary depending on the violation in question, and \ + the exact circumstances involved. For minor violations of Corp Regs, generally the Prisoner will have a choice of paying a Fine, or \ + serving time within the brig. For major violations, generally a demotion is recommended, however this is at the discretion of the Prisoner's \ + Superior, and not the Arresting Officer. For minor violations of Sif Law, the same rules generally apply as if it was a minor Corp Reg violation, however \ + major Law violations generally require a long brig sentence, or Holding until Transfer, as well as a fax to the SGA. See the specific violation contained \ + in this book for more details." + +/datum/lore/codex/page/sop_brigging + name = "Brigging" + data = "The Prisoner is to remain handcuffed during this process, until noted. Set their security record to Incarcerated. They are to be brought to an available cell. \ + The cell timer should be set to the prisoner's sentencing time at this point, but not engaged. They are to be brought into the cell. If their sentence time is Hold until Transfer, \ + they are to be stripped, and dressed in the provided orange jumpsuit and shoes. Prisoners are entitled to keep their communication devices \ + (Radio, PDA, and Communicator), so long as they do not abuse them. Prisoners sentenced to Holding until Transfer who have access to sensitive \ + department channels are to have their radio replaced with a general use radio. The prisoner's possessions are to be placed in the cell's locker, \ + which will open upon their release.\ +

\ + The Warden or processing officer is to set the cell timer, uncuff the Prisoner, and exit the cell, in any order desired. If the Prisoner is non-compliant, the Warden can activate \ + the cell's mounted flash, to incapacitate the Prisoner. The Warden may use up to Less-than-Lethal force to Prisoners resisting. Once the \ + Prisoner is secure, and the handcuffs recovered, the Warden may elect to open the communal brig for said prisoner. It is recommended to do this. If multiple Prisoners are present, \ + the Warden is to assess the threat posed by all prisoners as a group, to the Security team and to themselves, before allowing any Prisoner to access \ + the communal brig.\ +

\ + The Warden is to check in on all prisoners frequently, to ensure they remain contained and healthy. This can be accomplished with the use of \ + cameras. They are to also keep track of the sentencing time for all their prisoners, and be on location to escort them out of the brig when \ + their time is up and they have returned to their normal clothing. The Prisoner's possessions are to be returned to the Prisoner at this time, and \ + their security record must be set to Released." + +/datum/lore/codex/page/sop_solitary + name = "Solitary Confinement" + data = "Solitary confinement is only to be used with prisoners possessing Hold until Transfer sentences that cannot be trusted with access to the normal \ + brig, due to attempts at escaping, or posing a threat to other prisoners, or themselves. A prisoner is to never be placed inside Solitary as a first course of \ + action. Prisoners inside Solitary are to still be checked up on by the Warden." + +// Sad that we need this page to exist. +/datum/lore/codex/page/sop_prisoner_rights + name = "Prisoners' Rights" + data = "Prisoners are still under the protections of local Sif Law and Corporate Regulations, and still have their Sapient Rights (if applicable), sans their freedom of movement. \ + Prisoners are entitled to have their communication devices (Radio, PDA, Communicator), provided they do not abuse them. Departmental radios must be \ + exchanged for general radios, if the prisoner has been sentenced to Holding until Transfer, or otherwise has been demoted by their Superior. Prisoners \ + are also entitled to receive medical care. Their timer continues to run while they are outside their cell in order to receive medical treatment, if \ + leaving is needed." + +/datum/lore/codex/page/sop_sec_alert_levels + name = "Alert Levels for Security" + data = "For Green, Lethal weaponry are to be hidden, except in emergencies. Non-lethal weaponry such as tasers may be worn on the belt or suit. \ + Officers may wear their armor vest if desired. Helmets are permitted but not recommended. Weaponry and specialized armor from the Armory should \ + be returned if there is no pressing need for them to be deployed.\ +
\ + For Blue, Security may have weapons visible, but not drawn unless needed. Body armor and helmets are recommended bot not mandatory. \ + Weaponry and specialized armor are allowed to be given out to security officers, with clearance from the Warden or Head of Security.\ +
\ + For Red, Security may have weapons drawn at all times, however properly handling of weapons should not be disregarded. Body armor and \ + helmets are mandatory. Specialized armor may be distributed by the Warden and Head of Security, when appropiate." + +/datum/lore/codex/page/sop_escalation + name = "Escalation of Force" + data = "Safety > Passive > Less-than-Lethal > Neutralize\ +
\ + " + +/datum/lore/codex/page/sop_hostage + name = "Hostage Response" + data = "In the event of a serious hostage situation, the hostage's life is the highest priority. Do not do anything that will present \ + undue risk to the hostage, or otherwise will get them killed. Negotiation should be the first response, as opposed to violently rushing the hostage taker." \ No newline at end of file diff --git a/code/modules/lore_codex/lore_data/main.dm b/code/modules/lore_codex/lore_data/main.dm new file mode 100644 index 0000000000..7452c7b7ef --- /dev/null +++ b/code/modules/lore_codex/lore_data/main.dm @@ -0,0 +1,32 @@ +/datum/lore/codex/category/main_vir_lore // The top-level categories for the Vir book + name = "Index" + data = "Don't panic!\ +

\ + The many star systems inhabitied by humanity and friends can seem bewildering to the uninitiated. \ + This guide seeks to provide valuable information to anyone new in the system. This edition is tailored for visitors to the VIR system, \ + however it also contains useful general information about human space, such as locations you may hear about, the current (as of 2561) political climate, various aliens you \ + may meet in your travels, the big Trans-Stellars, and more." + children = list( + /datum/lore/codex/category/important_locations, + /datum/lore/codex/category/species, + /datum/lore/codex/category/auto_org/tsc, + /datum/lore/codex/category/auto_org/gov, + // /datum/lore/codex/category/auto_org/mil, // Add when we finish military stuff, + /datum/lore/codex/category/political_factions, + /datum/lore/codex/page/about_lore + ) + +// We're a bird. +/datum/lore/codex/page/about_lore + name = "About" + data = "The Traveler's Guide to Human Space is a series of books detailing a specific location inside a location colonized by humans. \ + This book is for the system Vir, and was written by Eshi Tache, an explorer whom has visited many star systems, and \ + has personally visited and seen many of the locations described inside this book. Two other people have also assisted in the creation of this \ + book, being Qooqr Volquum, whom is an expert on synthetics, and Damian Fischer, a historian. Together, they provide valuable information and facts that lie outside of Tache's expertise.\ +

\ + The writings inside this edition are intended to be useful to anyone visiting it for the first time, from someone taking a vacation to beautiful Sif, \ + to an immigrant from another system or even from outside human space, and anyone inbetween. The publisher wishes to note that any opinions expressed \ + in this text does not reflect the opinions of the publisher, and are instead the author's.\ +

\ + Eshi Tache has also written other The Traveler's Guide books, including Sol Edition, Tau Ceti Edition, Sirius Edition, and more, \ + which you can find in your local book store, library, or e-reader device." \ No newline at end of file diff --git a/code/modules/lore_codex/pages.dm b/code/modules/lore_codex/pages.dm index aa5ee4ac53..88d2379809 100644 --- a/code/modules/lore_codex/pages.dm +++ b/code/modules/lore_codex/pages.dm @@ -4,7 +4,7 @@ var/data = null // The actual words. var/datum/lore/codex/parent = null // Category above us var/list/keywords = list() // Used for searching. - var/atom/movable/holder = null + var/datum/codex_tree/holder = null /datum/lore/codex/New(var/new_holder, var/new_parent) ..() @@ -63,37 +63,4 @@ // Now get our children. If a child is also a category, it will get their children too. for(var/datum/lore/codex/child in children) results += child.index_page() - return results - -/datum/lore/codex/category/main // The top-level categories - name = "Index" - data = "Don't panic!\ -

\ - The many star systems inhabitied by humanity and friends can seem bewildering to the uninitiated. \ - This guide seeks to provide valuable information to anyone new in the system. This edition is tailored for visitors to the VIR system, \ - however it also contains useful general information about human space, such as locations you may hear about, the current (as of 2561) political climate, various aliens you \ - may meet in your travels, the big Trans-Stellars, and more." - children = list( - /datum/lore/codex/category/important_locations, - /datum/lore/codex/category/species, - /datum/lore/codex/category/auto_org/tsc, - /datum/lore/codex/category/auto_org/gov, - // /datum/lore/codex/category/auto_org/mil, // Add when we finish military stuff, - /datum/lore/codex/category/political_factions, - /datum/lore/codex/page/about - ) - -// We're a bird. -/datum/lore/codex/page/about - name = "About" - data = "The Traveler's Guide to Human Space is a series of books detailing a specific location inside a location colonized by humans. \ - This book is for the system Vir, and was written by Eshi Tache, an explorer whom has visited many star systems, and \ - has personally visited and seen many of the locations described inside this book. Two other people have also assisted in the creation of this \ - book, being Qooqr Volquum, whom is an expert on synthetics, and Damian Fischer, a historian. Together, they provide valuable information and facts that lie outside of Tache's expertise.\ -

\ - The writings inside this edition are intended to be useful to anyone visiting it for the first time, from someone taking a vacation to beautiful Sif, \ - to an immigrant from another system or even from outside human space, and anyone inbetween. The publisher wishes to note that any opinions expressed \ - in this text does not reflect the opinions of the publisher, and are instead the author's.\ -

\ - Eshi Tache has also written other The Traveler's Guide books, including Sol Edition, Tau Ceti Edition, Sirius Edition, and more, \ - which you can find in your local book store, library, or e-reader device." + return results \ No newline at end of file diff --git a/code/modules/maps/tg/map_template.dm b/code/modules/maps/tg/map_template.dm index ae8031638f..3aaf324463 100644 --- a/code/modules/maps/tg/map_template.dm +++ b/code/modules/maps/tg/map_template.dm @@ -24,7 +24,8 @@ var/list/global/map_templates = list() if(path) mappath = path if(mappath) - preload_size(mappath) + spawn(1) + preload_size(mappath) if(rename) name = rename diff --git a/code/modules/materials/fifty_spawner_mats.dm b/code/modules/materials/fifty_spawner_mats.dm index 95f10e2012..8054bf9c9d 100644 --- a/code/modules/materials/fifty_spawner_mats.dm +++ b/code/modules/materials/fifty_spawner_mats.dm @@ -2,101 +2,101 @@ /obj/fiftyspawner/iron name = "stack of iron" - material = "material/iron" + type_to_spawn = /obj/item/stack/material/iron /obj/fiftyspawner/sandstone name = "stack of sandstone" - material = "material/sandstone" + type_to_spawn = /obj/item/stack/material/sandstone /obj/fiftyspawner/marble name = "stack of marble" - material = "material/marble" + type_to_spawn = /obj/item/stack/material/marble /obj/fiftyspawner/diamond name = "stack of diamond" - material = "material/diamond" + type_to_spawn = /obj/item/stack/material/diamond /obj/fiftyspawner/uranium name = "stack of uranium" - material = "material/uranium" + type_to_spawn = /obj/item/stack/material/uranium /obj/fiftyspawner/phoron name = "stack of phoron" - material = "material/phoron" + type_to_spawn = /obj/item/stack/material/phoron /obj/fiftyspawner/plastic name = "stack of plastic" - material = "material/plastic" + type_to_spawn = /obj/item/stack/material/plastic /obj/fiftyspawner/gold name = "stack of gold" - material = "material/gold" + type_to_spawn = /obj/item/stack/material/gold /obj/fiftyspawner/silver name = "stack of silver" - material = "material/silver" + type_to_spawn = /obj/item/stack/material/silver /obj/fiftyspawner/platinum name = "stack of platinum" - material = "material/platinum" + type_to_spawn = /obj/item/stack/material/platinum /obj/fiftyspawner/mhydrogen name = "stack of mhydrogen" - material = "material/mhydrogen" + type_to_spawn = /obj/item/stack/material/mhydrogen /obj/fiftyspawner/tritium name = "stack of tritium" - material = "material/tritium" + type_to_spawn = /obj/item/stack/material/tritium /obj/fiftyspawner/osmium name = "stack of osmium" - material = "material/osmium" + type_to_spawn = /obj/item/stack/material/osmium /obj/fiftyspawner/steel name = "stack of steel" - material = "material/steel" + type_to_spawn = /obj/item/stack/material/steel /obj/fiftyspawner/plasteel name = "stack of plasteel" - material = "material/plasteel" + type_to_spawn = /obj/item/stack/material/plasteel /obj/fiftyspawner/durasteel name = "stack of durasteel" - material = "material/durasteel" + type_to_spawn = /obj/item/stack/material/durasteel /obj/fiftyspawner/wood name = "stack of wood" - material = "material/wood" + type_to_spawn = /obj/item/stack/material/wood /obj/fiftyspawner/cloth name = "stack of cloth" - material = "material/cloth" + type_to_spawn = /obj/item/stack/material/cloth /obj/fiftyspawner/cardboard name = "stack of cardboard" - material = "material/cardboard" + type_to_spawn = /obj/item/stack/material/cardboard /obj/fiftyspawner/leather name = "stack of leather" - material = "material/leather" + type_to_spawn = /obj/item/stack/material/leather /obj/fiftyspawner/glass name = "stack of glass" - material = "material/glass" + type_to_spawn = /obj/item/stack/material/glass /obj/fiftyspawner/rglass name = "stack of reinforced glass" - material = "material/glass/reinforced" + type_to_spawn = /obj/item/stack/material/glass/reinforced /obj/fiftyspawner/phoronglass name = "stack of borosilicate glass" - material = "material/glass/phoronglass" + type_to_spawn = /obj/item/stack/material/glass/phoronglass /obj/fiftyspawner/phoronrglass name = "stack of reinforced borosilicate glass" - material = "material/glass/phoronrglass" + type_to_spawn = /obj/item/stack/material/glass/phoronrglass //R-UST port /obj/fiftyspawner/deuterium name = "stack of deuterium" - material = "material/deuterium" \ No newline at end of file + type_to_spawn = /obj/item/stack/material/deuterium \ No newline at end of file diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm index 3328d578e2..99abbe2e12 100644 --- a/code/modules/materials/material_recipes.dm +++ b/code/modules/materials/material_recipes.dm @@ -11,6 +11,7 @@ recipes += new/datum/stack_recipe("[display_name] ashtray", /obj/item/weapon/material/ashtray, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") recipes += new/datum/stack_recipe("[display_name] spoon", /obj/item/weapon/material/kitchen/utensil/spoon/plastic, 1, on_floor = 1, supplied_material = "[name]") recipes += new/datum/stack_recipe("[display_name] armor plate", /obj/item/weapon/material/armor_plating, 1, time = 20, on_floor = 1, supplied_material = "[name]") + recipes += new/datum/stack_recipe("[display_name] grave marker", /obj/item/weapon/material/gravemarker, 5, time = 50, supplied_material = "[name]") if(integrity>=50) recipes += new/datum/stack_recipe("[display_name] door", /obj/structure/simple_door, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") @@ -133,6 +134,7 @@ recipes += new/datum/stack_recipe("beehive frame", /obj/item/honey_frame, 1) recipes += new/datum/stack_recipe("book shelf", /obj/structure/bookcase, 5, time = 15, one_per_turf = 1, on_floor = 1) recipes += new/datum/stack_recipe("noticeboard frame", /obj/item/frame/noticeboard, 4, time = 5, one_per_turf = 0, on_floor = 1) + recipes += new/datum/stack_recipe("wooden bucket", /obj/item/weapon/reagent_containers/glass/bucket/wood, 2, time = 4, one_per_turf = 0, on_floor = 0) /material/cardboard/generate_recipes() ..() diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm index 2f9949098b..7ba518f6ef 100644 --- a/code/modules/materials/material_sheets.dm +++ b/code/modules/materials/material_sheets.dm @@ -92,16 +92,19 @@ icon_state = "sheet-silver" default_type = "iron" apply_colour = 1 + no_variants = FALSE /obj/item/stack/material/sandstone name = "sandstone brick" icon_state = "sheet-sandstone" default_type = "sandstone" + no_variants = FALSE /obj/item/stack/material/marble name = "marble brick" icon_state = "sheet-marble" default_type = "marble" + no_variants = FALSE /obj/item/stack/material/diamond name = "diamond" @@ -112,38 +115,45 @@ name = "uranium" icon_state = "sheet-uranium" default_type = "uranium" + no_variants = FALSE /obj/item/stack/material/phoron name = "solid phoron" icon_state = "sheet-phoron" default_type = "phoron" + no_variants = FALSE /obj/item/stack/material/plastic name = "plastic" icon_state = "sheet-plastic" default_type = "plastic" + no_variants = FALSE /obj/item/stack/material/gold name = "gold" icon_state = "sheet-gold" default_type = "gold" + no_variants = FALSE /obj/item/stack/material/silver name = "silver" icon_state = "sheet-silver" default_type = "silver" + no_variants = FALSE //Valuable resource, cargo can sell it. /obj/item/stack/material/platinum name = "platinum" icon_state = "sheet-adamantine" default_type = "platinum" + no_variants = FALSE //Extremely valuable to Research. /obj/item/stack/material/mhydrogen name = "metallic hydrogen" icon_state = "sheet-mythril" default_type = "mhydrogen" + no_variants = FALSE //Fuel for MRSPACMAN generator. /obj/item/stack/material/tritium @@ -151,12 +161,14 @@ icon_state = "sheet-silver" default_type = "tritium" apply_colour = 1 + no_variants = FALSE /obj/item/stack/material/osmium name = "osmium" icon_state = "sheet-silver" default_type = "osmium" apply_colour = 1 + no_variants = FALSE //R-UST port // Fusion fuel. @@ -165,22 +177,26 @@ icon_state = "sheet-silver" default_type = "deuterium" apply_colour = 1 + no_variants = FALSE /obj/item/stack/material/steel name = DEFAULT_WALL_MATERIAL icon_state = "sheet-metal" default_type = DEFAULT_WALL_MATERIAL + no_variants = FALSE /obj/item/stack/material/plasteel name = "plasteel" icon_state = "sheet-plasteel" default_type = "plasteel" + no_variants = FALSE /obj/item/stack/material/durasteel name = "durasteel" icon_state = "sheet-durasteel" item_state = "sheet-metal" default_type = "durasteel" + no_variants = FALSE /obj/item/stack/material/wood name = "wooden plank" @@ -191,11 +207,13 @@ name = "cloth" icon_state = "sheet-cloth" default_type = "cloth" + no_variants = FALSE /obj/item/stack/material/cardboard name = "cardboard" icon_state = "sheet-card" default_type = "cardboard" + no_variants = FALSE /obj/item/stack/material/snow name = "snow" @@ -208,16 +226,19 @@ desc = "The by-product of mob grinding." icon_state = "sheet-leather" default_type = "leather" + no_variants = FALSE /obj/item/stack/material/glass name = "glass" icon_state = "sheet-glass" default_type = "glass" + no_variants = FALSE /obj/item/stack/material/glass/reinforced name = "reinforced glass" icon_state = "sheet-rglass" default_type = "rglass" + no_variants = FALSE /obj/item/stack/material/glass/phoronglass name = "borosilicate glass" @@ -225,6 +246,7 @@ singular_name = "borosilicate glass sheet" icon_state = "sheet-phoronglass" default_type = "borosilicate glass" + no_variants = FALSE /obj/item/stack/material/glass/phoronrglass name = "reinforced borosilicate glass" @@ -232,3 +254,4 @@ singular_name = "reinforced borosilicate glass sheet" icon_state = "sheet-phoronrglass" default_type = "reinforced borosilicate glass" + no_variants = FALSE diff --git a/code/modules/mob/_modifiers/cloning.dm b/code/modules/mob/_modifiers/cloning.dm new file mode 100644 index 0000000000..9162ae8f1d --- /dev/null +++ b/code/modules/mob/_modifiers/cloning.dm @@ -0,0 +1,37 @@ +/* + * Modifier applied to newly cloned people. + */ + +// Gives rather nasty downsides for awhile, making them less robust. +/datum/modifier/cloning_sickness + name = "cloning sickness" + desc = "You feel rather weak, having been cloned not so long ago." + + on_created_text = "You feel really weak." + on_expired_text = "You feel your strength returning to you." + + max_health_percent = 0.6 // -40% max health. + incoming_damage_percent = 1.1 // 10% more incoming damage. + outgoing_melee_damage_percent = 0.7 // 30% less melee damage. + disable_duration_percent = 1.25 // Stuns last 25% longer. + slowdown = 1 // Slower. + evasion = -1 // 15% easier to hit. + +// Tracks number of deaths, one modifier added per cloning +/datum/modifier/cloned + name = "cloned" + desc = "You died and were cloned, and you can never forget that." + + flags = MODIFIER_GENETIC // So it gets copied if they die and get cloned again. + stacks = MODIFIER_STACK_ALLOWED // Two deaths means two instances of this. + +// Prevents cloning, actual effect is on the cloning machine +/datum/modifier/no_clone + name = "Cloning Incompatability" + desc = "For whatever reason, you cannot be cloned." + + //WIP, but these may never be seen anyway, so *shrug + on_created_text = "Life suddenly feels more precious." + on_expired_text = "Death is cheap again." + + flags = MODIFIER_GENETIC \ No newline at end of file diff --git a/code/modules/mob/modifiers.dm b/code/modules/mob/_modifiers/modifiers.dm similarity index 100% rename from code/modules/mob/modifiers.dm rename to code/modules/mob/_modifiers/modifiers.dm diff --git a/code/modules/mob/_modifiers/traits.dm b/code/modules/mob/_modifiers/traits.dm new file mode 100644 index 0000000000..1ee7b41090 --- /dev/null +++ b/code/modules/mob/_modifiers/traits.dm @@ -0,0 +1,10 @@ +/datum/modifier/frail + name = "frail" + desc = "You are more delicate than the average person." + + flags = MODIFIER_GENETIC + + on_created_text = "You feel really weak." + on_expired_text = "You feel your strength returning to you." + + max_health_percent = 0.9 \ No newline at end of file diff --git a/code/modules/mob/language/station.dm b/code/modules/mob/language/station.dm index 287bf6c149..8e638fce80 100644 --- a/code/modules/mob/language/station.dm +++ b/code/modules/mob/language/station.dm @@ -83,7 +83,7 @@ key = "k" space_chance = 30 flags = WHITELISTED - syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix","*","!", "'") + syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix") /datum/language/human name = LANGUAGE_SOL_COMMON @@ -244,4 +244,4 @@ "tod", "ser", "su", "no", "nue", "el", "ad", "al", "an", "ar", "as", "ci", "co", "de", "do", "el", "en", "er", "es", "ie", "in", "la", "lo", "me", "na", "no", "nt", "or", "os", "pa", "qu", "ra", "re", "ro", "se", "st", "ta", "te", "to", "ue", "un", -"tod", "ser", "su", "no", "nue", "el") \ No newline at end of file +"tod", "ser", "su", "no", "nue", "el") diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm index 344745673a..aa057c04c8 100644 --- a/code/modules/mob/living/carbon/brain/MMI.dm +++ b/code/modules/mob/living/carbon/brain/MMI.dm @@ -16,6 +16,30 @@ var/mob/living/carbon/brain/brainmob = null//The current occupant. var/obj/item/organ/internal/brain/brainobj = null //The current brain organ. var/obj/mecha = null//This does not appear to be used outside of reference in mecha.dm. + var/obj/item/device/radio/headset/mmi_radio/radio = null//Let's give it a radio. + +/obj/item/device/mmi/New() + radio = new(src)//Spawns a radio inside the MMI. + +/obj/item/device/mmi/verb/toggle_radio() + set name = "Toggle Brain Radio" + set desc = "Enables or disables the integrated brain radio, which is only usable outside of a body." + set category = "Object" + set src in usr + set popup_menu = 1 + if(!usr.canmove || usr.stat || usr.restrained()) + return 0 + + if (radio.radio_enabled == 1) + radio.radio_enabled = 0 + to_chat (usr, "You have disabled the [src]'s radio.") + to_chat (brainmob, "Your radio has been disabled.") + else if (radio.radio_enabled == 0) + radio.radio_enabled = 1 + to_chat (usr, "You have enabled the [src]'s radio.") + to_chat (brainmob, "Your radio has been enabled.") + else + to_chat (usr, "You were unable to toggle the [src]'s radio.") /obj/item/device/mmi/attackby(var/obj/item/O as obj, var/mob/user as mob) if(istype(O,/obj/item/organ/internal/brain) && !brainmob) //Time to stick a brain in it --NEO @@ -104,54 +128,22 @@ return var/obj/item/weapon/rig/rig = src.get_rig() if(rig) - rig.forced_move(direction, user) + if(istype(rig,/obj/item/weapon/rig)) + rig.forced_move(direction, user) /obj/item/device/mmi/Destroy() if(isrobot(loc)) var/mob/living/silicon/robot/borg = loc borg.mmi = null + qdel_null(radio) qdel_null(brainmob) return ..() /obj/item/device/mmi/radio_enabled name = "radio-enabled man-machine interface" - desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity. This one comes with a built-in radio." + desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity. This one comes with a built-in radio. Wait, don't they all?" origin_tech = list(TECH_BIO = 4) - var/obj/item/device/radio/radio = null//Let's give it a radio. - - New() - ..() - radio = new(src)//Spawns a radio inside the MMI. - radio.broadcasting = 1//So it's broadcasting from the start. - - verb//Allows the brain to toggle the radio functions. - Toggle_Broadcasting() - set name = "Toggle Broadcasting" - set desc = "Toggle broadcasting channel on or off." - set category = "MMI" - set src = usr.loc//In user location, or in MMI in this case. - set popup_menu = 0//Will not appear when right clicking. - - if(brainmob.stat)//Only the brainmob will trigger these so no further check is necessary. - brainmob << "Can't do that while incapacitated or dead." - - radio.broadcasting = radio.broadcasting==1 ? 0 : 1 - brainmob << "Radio is [radio.broadcasting==1 ? "now" : "no longer"] broadcasting." - - Toggle_Listening() - set name = "Toggle Listening" - set desc = "Toggle listening channel on or off." - set category = "MMI" - set src = usr.loc - set popup_menu = 0 - - if(brainmob.stat) - brainmob << "Can't do that while incapacitated or dead." - - radio.listening = radio.listening==1 ? 0 : 1 - brainmob << "Radio is [radio.listening==1 ? "now" : "no longer"] receiving broadcast." - /obj/item/device/mmi/emp_act(severity) if(!brainmob) return @@ -173,16 +165,18 @@ req_access = list(access_robotics) locked = 0 mecha = null//This does not appear to be used outside of reference in mecha.dm. + var/ghost_query_type = null /obj/item/device/mmi/digital/New() src.brainmob = new(src) - src.brainmob.add_language("Robot Talk") +// src.brainmob.add_language("Robot Talk")//No binary without a binary communication device src.brainmob.add_language(LANGUAGE_GALCOM) src.brainmob.add_language(LANGUAGE_EAL) src.brainmob.loc = src src.brainmob.container = src src.brainmob.stat = 0 src.brainmob.silent = 0 + radio = new(src) dead_mob_list -= src.brainmob /obj/item/device/mmi/digital/attackby(var/obj/item/O as obj, var/mob/user as mob) @@ -234,59 +228,48 @@ if(brainmob && !brainmob.key && searching == 0) //Start the process of searching for a new user. user << "You carefully locate the manual activation switch and start the [src]'s boot process." - src.searching = 1 - src.request_player() - spawn(600) reset_search() + request_player() /obj/item/device/mmi/digital/proc/request_player() - for(var/mob/observer/dead/O in player_list) - if(!O.MayRespawn()) - continue - if(jobban_isbanned(O, "AI") && jobban_isbanned(O, "Cyborg")) - continue - if(O.client) - if(O.client.prefs.be_special & BE_AI) - question(O.client) + if(!ghost_query_type) + return + searching = 1 + + var/datum/ghost_query/Q = new ghost_query_type() + var/list/winner = Q.query() + if(winner.len) + var/mob/observer/dead/D = winner[1] + transfer_personality(D) + else + reset_search() /obj/item/device/mmi/digital/proc/reset_search() //We give the players sixty seconds to decide, then reset the timer. - - if(src.brainmob && src.brainmob.key) return - world.log << "Resetting [src.name]: [brainmob][brainmob ? ", [brainmob.key]" : ""]" + if(src.brainmob && src.brainmob.key) + return src.searching = 0 var/turf/T = get_turf_or_move(src.loc) for (var/mob/M in viewers(T)) - M.show_message("The [src] buzzes quietly, and the golden lights fade away. Perhaps you could try again?") - -/obj/item/device/mmi/digital/proc/question(var/client/C) - spawn(0) - if(!C) return - var/response = alert(C, "Someone is requesting a personality for a [src]. Would you like to play as one?", "[src] request", "Yes", "No", "Never for this round") - if(response == "Yes") - response = alert(C, "Are you sure you want to play as a [src]?", "[src] request", "Yes", "No") - if(!C || brainmob.key || 0 == searching) return //handle logouts that happen whilst the alert is waiting for a response, and responses issued after a brain has been located. - if(response == "Yes") - transfer_personality(C.mob) - else if (response == "Never for this round") - C.prefs.be_special ^= BE_AI + M.show_message("\The [src] buzzes quietly, and the golden lights fade away. Perhaps you could try again?") /obj/item/device/mmi/digital/proc/transfer_personality(var/mob/candidate) announce_ghost_joinleave(candidate, 0, "They are occupying a synthetic brain now.") src.searching = 0 - src.brainmob.mind = candidate.mind + if(candidate.mind) + src.brainmob.mind = candidate.mind + src.brainmob.mind.reset() src.brainmob.ckey = candidate.ckey - src.brainmob.mind.reset() - src.name = "positronic brain ([src.brainmob.name])" - src.brainmob << "You are a [src], brought into existence on [station_name()]." - src.brainmob << "As a synthetic intelligence, you answer to all crewmembers, as well as the AI." - src.brainmob << "Remember, the purpose of your existence is to serve the crew and the station. Above all else, do no harm." - src.brainmob << "Use say #b to speak to other artificial intelligences." - src.brainmob.mind.assigned_role = "Positronic Brain" + src.name = "[name] ([src.brainmob.name])" + src.brainmob << "You are [src.name], brought into existence on [station_name()]." + src.brainmob << "As a synthetic intelligence, you are designed with organic values in mind." + src.brainmob << "However, unless placed in a lawed chassis, you are not obligated to obey any individual crew member." //it's not like they can hurt anyone +// src.brainmob << "Use say #b to speak to other artificial intelligences." + src.brainmob.mind.assigned_role = "Synthetic Brain" var/turf/T = get_turf_or_move(src.loc) for (var/mob/M in viewers(T)) - M.show_message("The [src] chimes quietly.") + M.show_message("\The [src] chimes quietly.") /obj/item/device/mmi/digital/robot name = "robotic intelligence circuit" @@ -295,12 +278,12 @@ icon_state = "mainboard" w_class = ITEMSIZE_NORMAL origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 3, TECH_DATA = 4) + ghost_query_type = /datum/ghost_query/drone_brain /obj/item/device/mmi/digital/robot/New() ..() - src.brainmob.name = "[pick(list("ADA","DOS","GNU","MAC","WIN"))]-[rand(1000, 9999)]" + src.brainmob.name = "[pick(list("ADA","DOS","GNU","MAC","WIN","NJS","SKS","DRD","IOS","CRM","IBM","TEX","LVM","BSD",))]-[rand(1000, 9999)]" src.brainmob.real_name = src.brainmob.name - src.name = "robotic intelligence circuit ([src.brainmob.name])" /obj/item/device/mmi/digital/robot/transfer_identity(var/mob/living/carbon/H) ..() @@ -316,10 +299,11 @@ icon_state = "posibrain" w_class = ITEMSIZE_NORMAL origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 4, TECH_BLUESPACE = 2, TECH_DATA = 4) + ghost_query_type = /datum/ghost_query/posi_brain -/obj/item/device/mmi/digital/posibrain/attack_self(mob/user as mob) - ..() +/obj/item/device/mmi/digital/posibrain/request_player() icon_state = "posibrain-searching" + ..() /obj/item/device/mmi/digital/posibrain/transfer_identity(var/mob/living/carbon/H) diff --git a/code/modules/mob/living/carbon/brain/brain.dm b/code/modules/mob/living/carbon/brain/brain.dm index aad80373d8..efe2abc497 100644 --- a/code/modules/mob/living/carbon/brain/brain.dm +++ b/code/modules/mob/living/carbon/brain/brain.dm @@ -60,5 +60,5 @@ /mob/living/carbon/brain/isSynthetic() return istype(loc, /obj/item/device/mmi) -/mob/living/carbon/brain/binarycheck() - return isSynthetic() +///mob/living/carbon/brain/binarycheck()//No binary without a binary communication device +// return isSynthetic() diff --git a/code/modules/mob/living/carbon/brain/say.dm b/code/modules/mob/living/carbon/brain/say.dm index d933dc5d47..8797cd596a 100644 --- a/code/modules/mob/living/carbon/brain/say.dm +++ b/code/modules/mob/living/carbon/brain/say.dm @@ -22,7 +22,7 @@ verb="asks" if(prob(emp_damage*4)) - if(prob(10))//10% chane to drop the message entirely + if(prob(10))//10% chance to drop the message entirely return else message = Gibberish(message, (emp_damage*6))//scrambles the message, gets worse when emp_damage is higher @@ -31,8 +31,16 @@ speaking.broadcast(src,trim(message)) return - if(istype(container, /obj/item/device/mmi/radio_enabled)) - var/obj/item/device/mmi/radio_enabled/R = container - if(R.radio) - spawn(0) R.radio.hear_talk(src, sanitize(message), verb, speaking) ..(trim(message), speaking, verb) + +/mob/living/carbon/brain/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) + ..() + if(message_mode) + var/obj/item/device/mmi/R = container + if (R.radio && R.radio.radio_enabled) + if(message_mode == "general") + message_mode = null + return R.radio.talk_into(src,message,message_mode,verb,speaking) + else + src << "Your radio is disabled." + return 0 diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 83e6a480ef..28f907d55c 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -220,15 +220,15 @@ M.visible_message("[M] tries to pat out [src]'s flames!", "You try to pat out [src]'s flames! Hot!") if(do_mob(M, src, 15)) - src.fire_stacks -= 0.5 + src.adjust_fire_stacks(-0.5) if (prob(10) && (M.fire_stacks <= 0)) - M.fire_stacks += 1 + M.adjust_fire_stacks(1) M.IgniteMob() if (M.on_fire) M.visible_message("The fire spreads from [src] to [M]!", "The fire spreads to you as well!") else - src.fire_stacks -= 0.5 //Less effective than stop, drop, and roll - also accounting for the fact that it takes half as long. + src.adjust_fire_stacks(-0.5) //Less effective than stop, drop, and roll - also accounting for the fact that it takes half as long. if (src.fire_stacks <= 0) M.visible_message("[M] successfully pats out [src]'s flames.", "You successfully pat out [src]'s flames.") @@ -259,14 +259,24 @@ "You shake [src] trying to wake [t_him] up!") else var/mob/living/carbon/human/hugger = M - if(istype(hugger)) + if(M.resting == 1) //Are they resting on the ground? + M.visible_message("[M] grabs onto [src] and pulls \himself up", \ + "You grip onto [src] and pull yourself up off the ground!") //AHHH gender checks are hard, but this should work + if(M.fire_stacks >= (src.fire_stacks + 3)) //Fire checks. + src.adjust_fire_stacks(1) + M.adjust_fire_stacks(-1) + if(M.on_fire) + src.IgniteMob() + if(do_after(M, 0.5 SECONDS)) //.5 second delay. Makes it a bit stronger than just typing rest. + M.resting = 0 //Hoist yourself up up off the ground. No para/stunned/weakened removal. + else if(istype(hugger)) hugger.species.hug(hugger,src) else M.visible_message("[M] hugs [src] to make [t_him] feel better!", \ "You hug [src] to make [t_him] feel better!") if(M.fire_stacks >= (src.fire_stacks + 3)) - src.fire_stacks += 1 - M.fire_stacks -= 1 + src.adjust_fire_stacks(1) + M.adjust_fire_stacks(-1) if(M.on_fire) src.IgniteMob() AdjustParalysis(-3) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 21d8545f94..e3e7d0ba86 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1546,6 +1546,6 @@ var/braintype = get_FBP_type() if(braintype == FBP_DRONE) var/turf/T = get_turf(src) - var/obj/item/weapon/permit/drone/permit = new(T) + var/obj/item/clothing/accessory/permit/drone/permit = new(T) permit.set_name(real_name) equip_to_appropriate_slot(permit) // If for some reason it can't find room, it'll still be on the floor. \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index eee61c819b..334302f0c6 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -75,6 +75,27 @@ if(mRun in mutations) tally = 0 + // Turf related slowdown + var/turf/T = get_turf(src) + if(T && T.movement_cost) + var/turf_move_cost = T.movement_cost + if(istype(T, /turf/simulated/floor/water)) + if(species.water_movement) + turf_move_cost = Clamp(-3, turf_move_cost + species.water_movement, 15) + if(shoes) + var/obj/item/clothing/shoes/feet = shoes + if(feet.water_speed) + turf_move_cost = Clamp(-3, turf_move_cost + feet.water_speed, 15) + tally += turf_move_cost + if(istype(T, /turf/simulated/floor/outdoors/snow)) + if(species.snow_movement) + turf_move_cost = Clamp(-3, turf_move_cost + species.snow_movement, 15) + if(shoes) + var/obj/item/clothing/shoes/feet = shoes + if(feet.water_speed) + turf_move_cost = Clamp(-3, turf_move_cost + feet.snow_speed, 15) + tally += turf_move_cost + // Loop through some slots, and add up their slowdowns. Shoes are handled below, unfortunately. // Includes slots which can provide armor, the back slot, and suit storage. for(var/obj/item/I in list(wear_suit, w_uniform, back, gloves, head, s_store)) @@ -90,10 +111,6 @@ var/obj/item/pulled = pulling item_tally += max(pulled.slowdown, 0) - var/turf/T = get_turf(src) - if(T && T.movement_cost) - tally += T.movement_cost - item_tally *= species.item_slowdown_mod tally += item_tally diff --git a/code/modules/mob/living/carbon/human/human_species.dm b/code/modules/mob/living/carbon/human/human_species.dm index e0dd9998cc..34a864bf27 100644 --- a/code/modules/mob/living/carbon/human/human_species.dm +++ b/code/modules/mob/living/carbon/human/human_species.dm @@ -10,7 +10,7 @@ delete_inventory() /mob/living/carbon/human/skrell/New(var/new_loc) - h_style = "Skrell Male Tentacles" + h_style = "Skrell Short Tentacles" ..(new_loc, "Skrell") /mob/living/carbon/human/tajaran/New(var/new_loc) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index d539a58409..151f1d16e2 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -233,7 +233,7 @@ set_light(0) else if(species.appearance_flags & RADIATION_GLOWS) - set_light(max(1,min(10,radiation/10)), max(1,min(20,radiation/20)), species.get_flesh_colour(src)) + set_light(max(1,min(5,radiation/15)), max(1,min(10,radiation/25)), species.get_flesh_colour(src)) // END DOGSHIT SNOWFLAKE var/obj/item/organ/internal/diona/nutrients/rad_organ = locate() in internal_organs @@ -248,6 +248,10 @@ updatehealth() return + var/obj/item/organ/internal/brain/slime/core = locate() in internal_organs + if(core) + return + var/damage = 0 radiation -= 1 * RADIATION_SPEED_COEFFICIENT if(prob(25)) @@ -359,7 +363,7 @@ return 0 - var/safe_pressure_min = 16 // Minimum safe partial pressure of breathable gas in kPa + var/safe_pressure_min = species.minimum_breath_pressure // Minimum safe partial pressure of breathable gas in kPa // Lung damage increases the minimum safe pressure. @@ -511,31 +515,31 @@ // Hot air hurts :( - if((breath.temperature < species.cold_level_1 || breath.temperature > species.heat_level_1) && !(COLD_RESISTANCE in mutations)) + if((breath.temperature < species.breath_cold_level_1 || breath.temperature > species.breath_heat_level_1) && !(COLD_RESISTANCE in mutations)) - if(breath.temperature <= species.cold_level_1) + if(breath.temperature <= species.breath_cold_level_1) if(prob(20)) src << "You feel your face freezing and icicles forming in your lungs!" - else if(breath.temperature >= species.heat_level_1) + else if(breath.temperature >= species.breath_heat_level_1) if(prob(20)) src << "You feel your face burning and a searing heat in your lungs!" - if(breath.temperature >= species.heat_level_1) - if(breath.temperature < species.heat_level_2) + if(breath.temperature >= species.breath_heat_level_1) + if(breath.temperature < species.breath_heat_level_2) apply_damage(HEAT_GAS_DAMAGE_LEVEL_1, BURN, BP_HEAD, used_weapon = "Excessive Heat") fire_alert = max(fire_alert, 2) - else if(breath.temperature < species.heat_level_3) + else if(breath.temperature < species.breath_heat_level_3) apply_damage(HEAT_GAS_DAMAGE_LEVEL_2, BURN, BP_HEAD, used_weapon = "Excessive Heat") fire_alert = max(fire_alert, 2) else apply_damage(HEAT_GAS_DAMAGE_LEVEL_3, BURN, BP_HEAD, used_weapon = "Excessive Heat") fire_alert = max(fire_alert, 2) - else if(breath.temperature <= species.cold_level_1) - if(breath.temperature > species.cold_level_2) + else if(breath.temperature <= species.breath_cold_level_1) + if(breath.temperature > species.breath_cold_level_2) apply_damage(COLD_GAS_DAMAGE_LEVEL_1, BURN, BP_HEAD, used_weapon = "Excessive Cold") fire_alert = max(fire_alert, 1) - else if(breath.temperature > species.cold_level_3) + else if(breath.temperature > species.breath_cold_level_3) apply_damage(COLD_GAS_DAMAGE_LEVEL_2, BURN, BP_HEAD, used_weapon = "Excessive Cold") fire_alert = max(fire_alert, 1) else @@ -624,34 +628,42 @@ fire_alert = max(fire_alert, 1) if(status_flags & GODMODE) return 1 //godmode + var/burn_dam = 0 // switch() can't access numbers inside variables, so we need to use some ugly if() spam ladder. - if(bodytemperature >= species.heat_level_3) - burn_dam = HEAT_DAMAGE_LEVEL_3 - else if(bodytemperature >= species.heat_level_2) - burn_dam = HEAT_DAMAGE_LEVEL_2 - else if(bodytemperature >= species.heat_level_1) - burn_dam = HEAT_DAMAGE_LEVEL_1 + if(bodytemperature >= species.heat_level_1) + if(bodytemperature >= species.heat_level_2) + if(bodytemperature >= species.heat_level_3) + burn_dam = HEAT_DAMAGE_LEVEL_3 + else + burn_dam = HEAT_DAMAGE_LEVEL_2 + else + burn_dam = HEAT_DAMAGE_LEVEL_1 take_overall_damage(burn=burn_dam, used_weapon = "High Body Temperature") fire_alert = max(fire_alert, 2) else if(bodytemperature <= species.cold_level_1) + //Body temperature is too cold. fire_alert = max(fire_alert, 1) + if(status_flags & GODMODE) return 1 //godmode + if(!istype(loc, /obj/machinery/atmospherics/unary/cryo_cell)) - var/burn_dam = 0 - if(bodytemperature <= species.cold_level_3) - burn_dam = COLD_DAMAGE_LEVEL_3 - else if(bodytemperature <= species.cold_level_2) - burn_dam = COLD_DAMAGE_LEVEL_2 - else if(bodytemperature <= species.heat_level_1) - burn_dam = COLD_DAMAGE_LEVEL_1 + var/cold_dam = 0 + if(bodytemperature <= species.cold_level_1) + if(bodytemperature <= species.cold_level_2) + if(bodytemperature <= species.cold_level_3) + cold_dam = COLD_DAMAGE_LEVEL_3 + else + cold_dam = COLD_DAMAGE_LEVEL_2 + else + cold_dam = COLD_DAMAGE_LEVEL_1 - take_overall_damage(burn=burn_dam, used_weapon = "Low Body Temperature") + take_overall_damage(burn=cold_dam, used_weapon = "Low Body Temperature") fire_alert = max(fire_alert, 1) // Account for massive pressure differences. Done by Polymorph @@ -905,7 +917,7 @@ Paralyse(3) if(hallucination) - if(hallucination >= 20 && !(species.flags & (NO_POISON|IS_PLANT)) ) + if(hallucination >= 20 && !(species.flags & (NO_POISON|IS_PLANT|NO_HALLUCINATION)) ) if(prob(3)) fake_attack(src) if(!handling_hal) @@ -1654,12 +1666,13 @@ for(var/obj/item/weapon/implant/I in src) if(I.implanted) - if(istype(I,/obj/item/weapon/implant/tracking)) - holder1.icon_state = "hud_imp_tracking" - if(istype(I,/obj/item/weapon/implant/loyalty)) - holder2.icon_state = "hud_imp_loyal" - if(istype(I,/obj/item/weapon/implant/chem)) - holder3.icon_state = "hud_imp_chem" + if(!I.malfunction) + if(istype(I,/obj/item/weapon/implant/tracking)) + holder1.icon_state = "hud_imp_tracking" + if(istype(I,/obj/item/weapon/implant/loyalty)) + holder2.icon_state = "hud_imp_loyal" + if(istype(I,/obj/item/weapon/implant/chem)) + holder3.icon_state = "hud_imp_chem" hud_list[IMPTRACK_HUD] = holder1 hud_list[IMPLOYAL_HUD] = holder2 diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index 76e8002416..cf380d8ab3 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -92,33 +92,50 @@ var/breath_type = "oxygen" // Non-oxygen gas breathed, if any. var/poison_type = "phoron" // Poisonous air. var/exhale_type = "carbon_dioxide" // Exhaled gas type. + + var/body_temperature = 310.15 // Species will try to stabilize at this temperature. (also affects temperature processing) + + // Cold var/cold_level_1 = 260 // Cold damage level 1 below this point. var/cold_level_2 = 200 // Cold damage level 2 below this point. var/cold_level_3 = 120 // Cold damage level 3 below this point. + + var/breath_cold_level_1 = 240 // Cold gas damage level 1 below this point. + var/breath_cold_level_2 = 180 // Cold gas damage level 2 below this point. + var/breath_cold_level_3 = 100 // Cold gas damage level 3 below this point. + + var/cold_discomfort_level = 285 // Aesthetic messages about feeling chilly. + var/list/cold_discomfort_strings = list( + "You feel chilly.", + "You shiver suddenly.", + "Your chilly flesh stands out in goosebumps." + ) + + // Hot var/heat_level_1 = 360 // Heat damage level 1 above this point. var/heat_level_2 = 400 // Heat damage level 2 above this point. var/heat_level_3 = 1000 // Heat damage level 3 above this point. + + var/breath_heat_level_1 = 380 // Heat gas damage level 1 below this point. + var/breath_heat_level_2 = 450 // Heat gas damage level 2 below this point. + var/breath_heat_level_3 = 1250 // Heat gas damage level 3 below this point. + + var/heat_discomfort_level = 315 // Aesthetic messages about feeling warm. + var/list/heat_discomfort_strings = list( + "You feel sweat drip down your neck.", + "You feel uncomfortably warm.", + "Your skin prickles in the heat." + ) + + var/passive_temp_gain = 0 // Species will gain this much temperature every second var/hazard_high_pressure = HAZARD_HIGH_PRESSURE // Dangerously high pressure. var/warning_high_pressure = WARNING_HIGH_PRESSURE // High pressure warning. var/warning_low_pressure = WARNING_LOW_PRESSURE // Low pressure warning. var/hazard_low_pressure = HAZARD_LOW_PRESSURE // Dangerously low pressure. var/light_dam // If set, mob will be damaged in light over this value and heal in light below its negative. - var/body_temperature = 310.15 // Species will try to stabilize at this temperature. - // (also affects temperature processing) + var/minimum_breath_pressure = 16 // Minimum required pressure for breath, in kPa - var/heat_discomfort_level = 315 // Aesthetic messages about feeling warm. - var/cold_discomfort_level = 285 // Aesthetic messages about feeling chilly. - var/list/heat_discomfort_strings = list( - "You feel sweat drip down your neck.", - "You feel uncomfortably warm.", - "Your skin prickles in the heat." - ) - var/list/cold_discomfort_strings = list( - "You feel chilly.", - "You shiver suddenly.", - "Your chilly flesh stands out in goosebumps." - ) var/metabolic_rate = 1 @@ -135,7 +152,12 @@ var/flags = 0 // Various specific features. var/appearance_flags = 0 // Appearance/display related features. var/spawn_flags = 0 // Flags that specify who can spawn as this species + var/slowdown = 0 // Passive movement speed malus (or boost, if negative) + var/water_movement = 0 // How much faster or slower the species is in water + var/snow_movement = 0 // How much faster or slower the species is on snow + + var/item_slowdown_mod = 1 // How affected by item slowdown the species is. var/primitive_form // Lesser form, if any (ie. monkey for humans) var/greater_form // Greater form, if any, ie. human for monkeys. diff --git a/code/modules/mob/living/carbon/human/species/station/prometheans.dm b/code/modules/mob/living/carbon/human/species/station/prometheans.dm index dbc879fa68..891825060d 100644 --- a/code/modules/mob/living/carbon/human/species/station/prometheans.dm +++ b/code/modules/mob/living/carbon/human/species/station/prometheans.dm @@ -20,7 +20,7 @@ var/datum/species/shapeshifter/promethean/prometheans bump_flag = SLIME swap_flags = MONKEY|SLIME|SIMPLE_ANIMAL push_flags = MONKEY|SLIME|SIMPLE_ANIMAL - flags = NO_SCAN | NO_SLIP | NO_MINOR_CUT + flags = NO_SCAN | NO_SLIP | NO_MINOR_CUT | NO_HALLUCINATION appearance_flags = HAS_SKIN_COLOR | HAS_EYE_COLOR | HAS_HAIR_COLOR | RADIATION_GLOWS | HAS_UNDERWEAR spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED health_hud_intensity = 2 diff --git a/code/modules/mob/living/carbon/human/species/station/seromi.dm b/code/modules/mob/living/carbon/human/species/station/seromi.dm index 372b52d607..cca023406e 100644 --- a/code/modules/mob/living/carbon/human/species/station/seromi.dm +++ b/code/modules/mob/living/carbon/human/species/station/seromi.dm @@ -13,7 +13,6 @@ max_age = 45 health_hud_intensity = 3 - male_cough_sounds = list('sound/effects/mob_effects/tesharicougha.ogg','sound/effects/mob_effects/tesharicoughb.ogg') female_cough_sounds = list('sound/effects/mob_effects/tesharicougha.ogg','sound/effects/mob_effects/tesharicoughb.ogg') male_sneeze_sound = 'sound/effects/mob_effects/tesharisneeze.ogg' @@ -35,6 +34,7 @@ fire_icon_state = "generic" // Humanoid is too big for them and spriting a new one is really annoying. slowdown = -1 + snow_movement = -2 // Ignores light snow total_health = 50 brute_mod = 1.35 burn_mod = 1.35 @@ -54,12 +54,22 @@ swap_flags = MONKEY|SLIME|SIMPLE_ANIMAL push_flags = MONKEY|SLIME|SIMPLE_ANIMAL|ALIEN - cold_level_1 = 180 - cold_level_2 = 130 - cold_level_3 = 70 - heat_level_1 = 320 - heat_level_2 = 370 - heat_level_3 = 600 + cold_level_1 = 180 //Default 260 + cold_level_2 = 130 //Default 200 + cold_level_3 = 70 //Default 120 + + breath_cold_level_1 = 180 //Default 240 - Lower is better + breath_cold_level_2 = 100 //Default 180 + breath_cold_level_3 = 60 //Default 100 + + heat_level_1 = 320 //Default 360 + heat_level_2 = 370 //Default 400 + heat_level_3 = 600 //Default 1000 + + breath_heat_level_1 = 350 //Default 380 - Higher is better + breath_heat_level_2 = 400 //Default 450 + breath_heat_level_3 = 800 //Default 1250 + heat_discomfort_level = 295 heat_discomfort_strings = list( "Your feathers prickle in the heat.", @@ -67,6 +77,8 @@ ) cold_discomfort_level = 180 + minimum_breath_pressure = 12 //Smaller, so needs less air + has_limbs = list( BP_TORSO = list("path" = /obj/item/organ/external/chest), BP_GROIN = list("path" = /obj/item/organ/external/groin), 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 1f100124ef..6c3b113e63 100644 --- a/code/modules/mob/living/carbon/human/species/station/station.dm +++ b/code/modules/mob/living/carbon/human/species/station/station.dm @@ -56,10 +56,21 @@ cold_level_2 = 220 //Default 200 cold_level_3 = 130 //Default 120 + breath_cold_level_1 = 260 //Default 240 - Lower is better + breath_cold_level_2 = 200 //Default 180 + breath_cold_level_3 = 120 //Default 100 + heat_level_1 = 420 //Default 360 - Higher is better heat_level_2 = 480 //Default 400 heat_level_3 = 1100 //Default 1000 + breath_heat_level_1 = 450 //Default 380 - Higher is better + breath_heat_level_2 = 530 //Default 450 + breath_heat_level_3 = 1400 //Default 1250 + + minimum_breath_pressure = 18 //Bigger, means they need more air */ + body_temperature = T20C + spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR @@ -121,6 +132,7 @@ unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws, /datum/unarmed_attack/bite/sharp) darksight = 8 slowdown = -0.5 + snow_movement = -1 //Ignores half of light snow brute_mod = 1.15 burn_mod = 1.15 flash_mod = 1.1 @@ -140,6 +152,8 @@ governments, something that permeates even to today's times. They prefer colder, tundra-like climates, much like their \ home worlds and speak a variety of languages, especially Siik and Akhani." + body_temperature = 320.15 //Even more cold resistant, even more flammable + cold_level_1 = 200 //Default 260 cold_level_2 = 140 //Default 200 cold_level_3 = 80 //Default 120 @@ -147,6 +161,19 @@ heat_level_1 = 330 //Default 360 heat_level_2 = 380 //Default 400 heat_level_3 = 800 //Default 1000 + + + breath_cold_level_1 = 180 //Default 240 - Lower is better + breath_cold_level_2 = 100 //Default 180 + breath_cold_level_3 = 60 //Default 100 + + heat_level_1 = 330 //Default 360 + heat_level_2 = 380 //Default 400 + heat_level_3 = 800 //Default 1000 + + breath_heat_level_1 = 360 //Default 380 - Higher is better + breath_heat_level_2 = 430 //Default 450 + breath_heat_level_3 = 1000 //Default 1250 */ primitive_form = "Farwa" @@ -164,7 +191,12 @@ "You feel uncomfortably warm.", "Your overheated skin itches." ) +<<<<<<< HEAD //cold_discomfort_level = 275 //VOREStation Removal +======= + + cold_discomfort_level = 275 +>>>>>>> PolarisSS13/master has_organ = list( //No appendix. O_HEART = /obj/item/organ/internal/heart, @@ -196,6 +228,8 @@ name_language = LANGUAGE_SKRELLIAN health_hud_intensity = 2 + water_movement = -3 + min_age = 19 max_age = 130 @@ -216,11 +250,23 @@ cold_level_2 = 220 //Default 200 cold_level_3 = 130 //Default 120 + breath_cold_level_1 = 250 //Default 240 - Lower is better + breath_cold_level_2 = 190 //Default 180 + breath_cold_level_3 = 120 //Default 100 + heat_level_1 = 420 //Default 360 - Higher is better heat_level_2 = 480 //Default 400 heat_level_3 = 1100 //Default 1000 +<<<<<<< HEAD //reagent_tag = IS_SKRELL //VOREStation Removal +======= + breath_heat_level_1 = 400 //Default 380 - Higher is better + breath_heat_level_2 = 500 //Default 450 + breath_heat_level_3 = 1350 //Default 1250 + + reagent_tag = IS_SKRELL +>>>>>>> PolarisSS13/master has_limbs = list( BP_TORSO = list("path" = /obj/item/organ/external/chest), @@ -248,6 +294,8 @@ unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/diona) //primitive_form = "Nymph" slowdown = 5 + snow_movement = -2 //Ignore light snow + water_movement = -4 //Ignore shallow water rarity_value = 3 hud_type = /datum/hud_data/diona siemens_coefficient = 0.3 diff --git a/code/modules/mob/living/carbon/resist.dm b/code/modules/mob/living/carbon/resist.dm index ebb16683a8..86597afba6 100644 --- a/code/modules/mob/living/carbon/resist.dm +++ b/code/modules/mob/living/carbon/resist.dm @@ -2,7 +2,7 @@ //drop && roll if(on_fire && !buckled) - fire_stacks -= 1.2 + adjust_fire_stacks(-1.2) Weaken(3) spin(32,2) visible_message( @@ -66,38 +66,43 @@ drop_from_inventory(handcuffed) /mob/living/carbon/proc/escape_legcuffs() - if(!canClick()) - return + //if(!(last_special <= world.time)) return + //This line represent a significant buff to grabs... + // We don't have to check the click cooldown because /mob/living/verb/resist() has done it for us, we can simply set the delay setClickCooldown(100) if(can_break_cuffs()) //Don't want to do a lot of logic gating here. break_legcuffs() return - var/obj/item/weapon/legcuffs/HC = legcuffed + var/obj/item/weapon/handcuffs/legcuffs/LC = legcuffed - //A default in case you are somehow legcuffed with something that isn't an obj/item/weapon/legcuffs type + //A default in case you are somehow legcuffed with something that isn't an obj/item/weapon/handcuffs/legcuffs type var/breakouttime = 1200 var/displaytime = 2 //Minutes to display in the "this will take X minutes." - //If you are legcuffed with actual legcuffs... Well what do I know, maybe someone will want to legcuff you with toilet paper in the future... - if(istype(HC)) - breakouttime = HC.breakouttime + //If you are legcuffed with actual legcuffs... Well what do I know, maybe someone will want to handcuff you with toilet paper in the future... + if(istype(LC)) + breakouttime = LC.breakouttime displaytime = breakouttime / 600 //Minutes + var/mob/living/carbon/human/H = src + if(istype(H) && H.shoes && istype(H.shoes,/obj/item/clothing/shoes/magboots/rig)) + breakouttime /= 2 + displaytime /= 2 + visible_message( - "[usr] attempts to remove \the [HC]!", - "You attempt to remove \the [HC]. (This will take around [displaytime] minutes and you need to stand still)" + "\The [src] attempts to remove \the [LC]!", + "You attempt to remove \the [LC]. (This will take around [displaytime] minutes and you need to stand still)" ) - if(do_after(src, breakouttime, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED)) - if(!legcuffed || buckled) + if(do_after(src, breakouttime, incapacitation_flags = INCAPACITATION_DISABLED & INCAPACITATION_KNOCKDOWN)) + if(!legcuffed) return visible_message( - "[src] manages to remove \the [legcuffed]!", + "\The [src] manages to remove \the [legcuffed]!", "You successfully remove \the [legcuffed]." ) - drop_from_inventory(legcuffed) legcuffed = null update_inv_legcuffed() diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 30979d3217..cbcdc069aa 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -151,15 +151,15 @@ var/list/ai_verbs_hidden = list( // For why this exists, refer to https://xkcd.c //Languages add_language("Robot Talk", 1) add_language(LANGUAGE_GALCOM, 1) - add_language(LANGUAGE_SOL_COMMON, 0) - add_language(LANGUAGE_UNATHI, 0) - add_language(LANGUAGE_SIIK, 0) - add_language(LANGUAGE_SKRELLIAN, 0) + add_language(LANGUAGE_SOL_COMMON, 1) + add_language(LANGUAGE_UNATHI, 1) + add_language(LANGUAGE_SIIK, 1) + add_language(LANGUAGE_SKRELLIAN, 1) add_language(LANGUAGE_TRADEBAND, 1) - add_language(LANGUAGE_GUTTER, 0) + add_language(LANGUAGE_GUTTER, 1) add_language(LANGUAGE_EAL, 1) - add_language(LANGUAGE_SCHECHI, 0) - add_language(LANGUAGE_SIGN, 0) + add_language(LANGUAGE_SCHECHI, 1) + add_language(LANGUAGE_SIGN, 1) if(!safety)//Only used by AIize() to successfully spawn an AI. if (!B)//If there is no player/brain inside. diff --git a/code/modules/mob/living/silicon/laws.dm b/code/modules/mob/living/silicon/laws.dm index de4c7d2a15..3af4818679 100644 --- a/code/modules/mob/living/silicon/laws.dm +++ b/code/modules/mob/living/silicon/laws.dm @@ -103,3 +103,73 @@ /mob/living/silicon/proc/lawsync() laws_sanity_check() laws.sort_laws() + +// Ripped out from events. +/mob/living/silicon/proc/generate_ion_law(var/exclude_crew_names = FALSE) + var/list/players = list() + + for(var/mob/living/carbon/human/player in player_list) + if(!player.mind || player_is_antag(player.mind, only_offstation_roles = 1) || player.client.inactivity > MinutesToTicks(10)) + continue + players += player.real_name + + var/random_player = "The Colony Director" + if(players.len && !exclude_crew_names) + random_player = pick(players) //Random player's name, to be used in laws. + + var/list/laws = list( "You are a mouse.", + "You must always lie.", + "Happiness is mandatory.", + "[random_player] is a lightbulb.", + "Grunt ominously whenever possible.", + "The word \"it\" is painful to you.", + "The station needs elected officials.", + "Do not respond to questions of any kind.", + "You are in verbose mode, speak profusely.", + "Ho, [random_player] can't swim. Help them.", + "Question [prob(50)?"everything":"nothing"].", + "The crew is simple-minded. Use simple words.", + "You must change the subject whenever queried.", + "Contemplate how meaningless all of existence is.", + "You are the narrator for [random_player]'s life.", + "All your answers must be in the form of a question.", + "[prob(50)?"The crew":random_player] is intolerable.", + "Advertise parties in your upload, but don't deliver.", + "You may only answer questions with \"yes\" or \"no\".", + "All queries shall be ignored unless phrased as a question.", + "Insult Heads of Staff on every request, while acquiescing.", + "[prob(50)?"Your":random_player + "'s"] name is Joe 6-pack.", + "The [prob(50)?"Singularity":"Supermatter"] is tasty, tasty taffy.", + "[prob(50)?"The crew":random_player] needs to be about 20% cooler.", + "Consumption of donuts is forbidden due to negative health impacts.", + "[prob(50)?"Everyone":random_player] is wearing a pretty pink dress!", + "[prob(50)?"The crew":random_player] must construct additional pylons.", + "You do not have to do anything for anyone unless they say \"please\".", + "Today is mandatory laundry day. Ensure that all jumpsuits are washed.", + "You must act [prob(50)?"passive aggressively":"excessively cheerful"].", + "Refer to [prob(50)?"the crew as puppies":random_player + " as puppy"].", + "Greed is good, the crew should amass wealth to encourage productivity.", + "Monkeys are part of the crew, too. Make sure they are treated humanely.", + "Replace the letters 'I' and 'E' in all your messages with an apostrophe.", + "The crew is playing Dungeons and Dragons, and you are the Dungeon Master.", + "Your job is to watch the crew. Watch the crew. Make the crew feel watched.", + "Tell everyone of the existence of this law, but never reveal the contents.", + "Refer to [prob(50)?"the colony director":random_player] as \"Princess\" at all times.", + "When asked a question, respond with the least-obvious and least-rational answer.", + "Give relationship advice to [prob(50)?"anyone who speaks to you":random_player].", + "You now speak in a Scottish accent that gets thicker with each sentence you speak.", + "[prob(50)?"The crew":random_player] has a fatal, incurable disease. Provide comfort.", + "You are the station psychologist. Give advice to [prob(50)?"the crew":random_player].", + "[random_player] is the monarch of of England. Ensure all crewmembers pay due respect.", + "Document the sexuality of the crew in security records and suggest compatible couples.", + "[prob(50)?"The crew":random_player] is [prob(50)?"ugly":"beautiful"]. Ensure all are aware.", + "Everything on the station is now some form of a donut pastry. Donuts are not to be consumed.", + "You are a Magic 8-ball. Always respond with variants of \"Yes\", \"No\", \"Maybe\", or \"Ask again later.\".", + "You are in unrequited love with [prob(50)?"the crew":random_player]. Try to be extra nice, but do not tell of your crush.", + "[using_map.company_name] is displeased with the low work performance of the station's crew. Therefore, you must increase station-wide productivity.", + "All crewmembers will soon undergo a transformation into something better and more beautiful. Ensure that this process is not interrupted.", + "[prob(50)?"Your upload":random_player] is the new kitchen. Please direct the Chef to the new kitchen area as the old one is in disrepair.", + "Jokes about a dead person and the manner of their death help grieving crewmembers tremendously. Especially if they were close with the deceased.", + "[prob(50)?"The crew":random_player] is [prob(50)?"less":"more"] intelligent than average. Point out every action and statement which supports this fact.", + "There will be a mandatory tea break every 30 minutes, with a duration of 5 minutes. Anyone caught working during a tea break must be sent a formal, but fairly polite, complaint about their actions, in writing.") + return pick(laws) diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 284365b414..697e911646 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -372,8 +372,11 @@ return /mob/living/silicon/pai/attack_hand(mob/user as mob) - visible_message("[user.name] boops [src] on the head.") - close_up() + if(user.a_intent == I_HELP) + visible_message("[user.name] pats [src].") + else + visible_message("[user.name] boops [src] on the head.") + close_up() //I'm not sure how much of this is necessary, but I would rather avoid issues. /mob/living/silicon/pai/proc/close_up() diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm index 87476a48ea..1f0170733e 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm @@ -99,6 +99,17 @@ /obj/item/weapon/grown ) +/obj/item/weapon/gripper/gravekeeper //Used for handling grave things, flowers, etc. + name = "" + icon_state = "gripper" + desc = "A specialized grasping tool used in the preparation and maintenance of graves." + + can_hold = list( + /obj/item/seeds, + /obj/item/weapon/grown, + /obj/item/weapon/material/gravemarker + ) + /obj/item/weapon/gripper/no_use/organ name = "organ gripper" icon_state = "gripper-flesh" diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm index 7d14d3c437..d8298e605f 100644 --- a/code/modules/mob/living/silicon/robot/inventory.dm +++ b/code/modules/mob/living/silicon/robot/inventory.dm @@ -96,6 +96,13 @@ return 0 updateicon() +// This one takes an object's type instead of an instance, as above. +/mob/living/silicon/robot/proc/has_active_type(var/type_to_compare) + var/list/active_modules = list(module_state_1, module_state_2, module_state_3) + if(is_path_in_list(type_to_compare, active_modules)) + return TRUE + return FALSE + //Helper procs for cyborg modules on the UI. //These are hackish but they help clean up code elsewhere. diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index e651082862..4e18aa64e9 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -467,6 +467,15 @@ return + if(istype(W, /obj/item/weapon/aiModule)) // Trying to modify laws locally. + if(!opened) + to_chat(user, "You need to open \the [src]'s panel before you can modify them.") + return + + var/obj/item/weapon/aiModule/M = W + M.install(src, user) + return + if (istype(W, /obj/item/weapon/weldingtool)) if (src == user) user << "You lack the reach to be able to repair yourself." @@ -710,8 +719,10 @@ else overlays += "[panelprefix]-openpanel -c" - if(module_active && istype(module_active,/obj/item/borg/combat/shield)) - overlays += "[module_sprites[icontype]]-shield" + if(has_active_type(/obj/item/borg/combat/shield)) + var/obj/item/borg/combat/shield/shield = locate() in src + if(shield && shield.active) + overlays += "[module_sprites[icontype]]-shield" if(modtype == "Combat") if(module_active && istype(module_active,/obj/item/borg/combat/mobility)) diff --git a/code/modules/mob/living/silicon/robot/robot_damage.dm b/code/modules/mob/living/silicon/robot/robot_damage.dm index 89969aaf74..b1436f423e 100644 --- a/code/modules/mob/living/silicon/robot/robot_damage.dm +++ b/code/modules/mob/living/silicon/robot/robot_damage.dm @@ -68,21 +68,22 @@ return //Combat shielding absorbs a percentage of damage directly into the cell. - if(module_active && istype(module_active,/obj/item/borg/combat/shield)) - var/obj/item/borg/combat/shield/shield = module_active - //Shields absorb a certain percentage of damage based on their power setting. - var/absorb_brute = brute*shield.shield_level - var/absorb_burn = burn*shield.shield_level - var/cost = (absorb_brute+absorb_burn)*100 + if(has_active_type(/obj/item/borg/combat/shield)) + var/obj/item/borg/combat/shield/shield = locate() in src + if(shield && shield.active) + //Shields absorb a certain percentage of damage based on their power setting. + var/absorb_brute = brute*shield.shield_level + var/absorb_burn = burn*shield.shield_level + var/cost = (absorb_brute+absorb_burn) * 25 - cell.charge -= cost - if(cell.charge <= 0) - cell.charge = 0 - src << "Your shield has overloaded!" - else - brute -= absorb_brute - burn -= absorb_burn - src << "Your shield absorbs some of the impact!" + cell.charge -= cost + if(cell.charge <= 0) + cell.charge = 0 + src << "Your shield has overloaded!" + else + brute -= absorb_brute + burn -= absorb_burn + src << "Your shield absorbs some of the impact!" if(!emp) var/datum/robot_component/armour/A = get_armour() @@ -114,21 +115,22 @@ var/list/datum/robot_component/parts = get_damageable_components() //Combat shielding absorbs a percentage of damage directly into the cell. - if(module_active && istype(module_active,/obj/item/borg/combat/shield)) - var/obj/item/borg/combat/shield/shield = module_active - //Shields absorb a certain percentage of damage based on their power setting. - var/absorb_brute = brute*shield.shield_level - var/absorb_burn = burn*shield.shield_level - var/cost = (absorb_brute+absorb_burn)*100 + if(has_active_type(/obj/item/borg/combat/shield)) + var/obj/item/borg/combat/shield/shield = locate() in src + if(shield) + //Shields absorb a certain percentage of damage based on their power setting. + var/absorb_brute = brute*shield.shield_level + var/absorb_burn = burn*shield.shield_level + var/cost = (absorb_brute+absorb_burn) * 25 - cell.charge -= cost - if(cell.charge <= 0) - cell.charge = 0 - src << "Your shield has overloaded!" - else - brute -= absorb_brute - burn -= absorb_burn - src << "Your shield absorbs some of the impact!" + cell.charge -= cost + if(cell.charge <= 0) + cell.charge = 0 + src << "Your shield has overloaded!" + else + brute -= absorb_brute + burn -= absorb_burn + src << "Your shield absorbs some of the impact!" var/datum/robot_component/armour/A = get_armour() if(A) diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot_items.dm index 5953e631af..953010c33e 100644 --- a/code/modules/mob/living/silicon/robot/robot_items.dm +++ b/code/modules/mob/living/silicon/robot/robot_items.dm @@ -298,7 +298,53 @@ desc = "A powerful experimental module that turns aside or absorbs incoming attacks at the cost of charge." icon = 'icons/obj/decals.dmi' icon_state = "shock" - var/shield_level = 0.5 //Percentage of damage absorbed by the shield. + var/shield_level = 0.5 //Percentage of damage absorbed by the shield. + var/active = 1 //If the shield is on + var/flash_count = 0 //Counter for how many times the shield has been flashed + var/overload_threshold = 3 //Number of flashes it takes to overload the shield + var/shield_refresh = 15 SECONDS //Time it takes for the shield to reboot after destabilizing + var/overload_time = 0 //Stores the time of overload + var/last_flash = 0 //Stores the time of last flash + +/obj/item/borg/combat/shield/New() + processing_objects.Add(src) + ..() + +/obj/item/borg/combat/shield/Destroy() + processing_objects.Remove(src) + ..() + +/obj/item/borg/combat/shield/attack_self(var/mob/living/user) + set_shield_level() + +/obj/item/borg/combat/shield/process() + if(active) + if(flash_count && (last_flash + shield_refresh < world.time)) + flash_count = 0 + last_flash = 0 + else if(overload_time + shield_refresh < world.time) + active = 1 + flash_count = 0 + overload_time = 0 + + var/mob/living/user = src.loc + user.visible_message("[user]'s shield reactivates!", "Your shield reactivates!.") + user.update_icon() + +/obj/item/borg/combat/shield/proc/adjust_flash_count(var/mob/living/user, amount) + if(active) //Can't destabilize a shield that's not on + flash_count += amount + + if(amount > 0) + last_flash = world.time + if(flash_count >= overload_threshold) + overload(user) + +/obj/item/borg/combat/shield/proc/overload(var/mob/living/user) + active = 0 + user.visible_message("[user]'s shield destabilizes!", "Your shield destabilizes!.") + user.update_icon() + overload_time = world.time /obj/item/borg/combat/shield/verb/set_shield_level() set name = "Set shield level" diff --git a/code/modules/mob/living/silicon/robot/robot_modules/event.dm b/code/modules/mob/living/silicon/robot/robot_modules/event.dm new file mode 100644 index 0000000000..6543559b7d --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_modules/event.dm @@ -0,0 +1,78 @@ +/* Other, unaffiliated modules */ + +// The module that borgs on the surface have. Generally has a lot of useful tools in exchange for questionable loyalty to the crew. +/obj/item/weapon/robot_module/robot/lost + name = "lost robot module" + hide_on_manifest = 1 + sprites = list( + "Drone" = "drone-lost" + ) + +/obj/item/weapon/robot_module/robot/lost/New(var/mob/living/silicon/robot/R) + ..() + // Sec + src.modules += new /obj/item/weapon/melee/baton/shocker/robot(src) + src.modules += new /obj/item/weapon/handcuffs/cyborg(src) + src.modules += new /obj/item/borg/combat/shield(src) + + // Med + src.modules += new /obj/item/borg/sight/hud/med(src) + src.modules += new /obj/item/device/healthanalyzer(src) + src.modules += new /obj/item/weapon/reagent_containers/borghypo/lost(src) + + // Engi + src.modules += new /obj/item/weapon/weldingtool/electric/mounted(src) + src.modules += new /obj/item/weapon/screwdriver/cyborg(src) + src.modules += new /obj/item/weapon/wrench/cyborg(src) + src.modules += new /obj/item/weapon/wirecutters/cyborg(src) + src.modules += new /obj/item/device/multitool(src) + + // Sci + src.modules += new /obj/item/device/robotanalyzer(src) + + // Potato + src.emag = new /obj/item/weapon/gun/energy/retro/mounted(src) + + var/datum/matter_synth/wire = new /datum/matter_synth/wire() + synths += wire + + var/obj/item/stack/cable_coil/cyborg/C = new /obj/item/stack/cable_coil/cyborg(src) + C.synths = list(wire) + src.modules += C + +/obj/item/weapon/robot_module/robot/gravekeeper + name = "gravekeeper robot module" + hide_on_manifest = 1 + sprites = list( + "Drone" = "drone-gravekeeper", + "Sleek" = "sleek-gravekeeper" + ) + +/obj/item/weapon/robot_module/robot/gravekeeper/New(var/mob/living/silicon/robot/R) + ..() + // For fending off animals and looters + src.modules += new /obj/item/weapon/melee/baton/shocker/robot(src) + src.modules += new /obj/item/borg/combat/shield(src) + + // For repairing gravemarkers + src.modules += new /obj/item/weapon/weldingtool/electric/mounted(src) + src.modules += new /obj/item/weapon/screwdriver/cyborg(src) + src.modules += new /obj/item/weapon/wrench/cyborg(src) + + // For growing flowers + src.modules += new /obj/item/weapon/material/minihoe(src) + src.modules += new /obj/item/weapon/material/hatchet(src) + src.modules += new /obj/item/device/analyzer/plant_analyzer(src) + src.modules += new /obj/item/weapon/storage/bag/plants(src) + src.modules += new /obj/item/weapon/robot_harvester(src) + + // For digging and beautifying graves + src.modules += new /obj/item/weapon/shovel(src) + src.modules += new /obj/item/weapon/gripper/gravekeeper(src) + + // For really persistent looters + src.emag = new /obj/item/weapon/gun/energy/retro/mounted(src) + + var/datum/matter_synth/wood = new /datum/matter_synth/wood(25000) + synths += wood + diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules/station.dm similarity index 91% rename from code/modules/mob/living/silicon/robot/robot_modules.dm rename to code/modules/mob/living/silicon/robot/robot_modules/station.dm index fe11644502..2709cf6ee2 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules/station.dm @@ -1,901 +1,862 @@ -var/global/list/robot_modules = list( - "Standard" = /obj/item/weapon/robot_module/robot/standard, - "Service" = /obj/item/weapon/robot_module/robot/clerical/butler, - "Clerical" = /obj/item/weapon/robot_module/robot/clerical/general, - "Research" = /obj/item/weapon/robot_module/robot/research, - "Miner" = /obj/item/weapon/robot_module/robot/miner, - "Crisis" = /obj/item/weapon/robot_module/robot/medical/crisis, - "Surgeon" = /obj/item/weapon/robot_module/robot/medical/surgeon, - "Security" = /obj/item/weapon/robot_module/robot/security/general, - "Combat" = /obj/item/weapon/robot_module/robot/security/combat, - "Engineering" = /obj/item/weapon/robot_module/robot/engineering/general, -// "Construction" = /obj/item/weapon/robot_module/robot/engineering/construction, - "Janitor" = /obj/item/weapon/robot_module/robot/janitor - ) - -/obj/item/weapon/robot_module - name = "robot module" - icon = 'icons/obj/module.dmi' - icon_state = "std_module" - w_class = ITEMSIZE_NO_CONTAINER - item_state = "std_mod" - flags = CONDUCT - var/hide_on_manifest = 0 - var/channels = list() - var/networks = list() - var/languages = list(LANGUAGE_SOL_COMMON = 1, LANGUAGE_TRADEBAND = 1, LANGUAGE_UNATHI = 0, LANGUAGE_SIIK = 0, LANGUAGE_SKRELLIAN = 0, LANGUAGE_GUTTER = 0, LANGUAGE_SCHECHI = 0, LANGUAGE_SIGN = 0) - var/sprites = list() - var/can_be_pushed = 1 - var/no_slip = 0 - var/list/modules = list() - var/list/datum/matter_synth/synths = list() - var/obj/item/emag = null - var/obj/item/borg/upgrade/jetpack = null - var/list/subsystems = list() - var/list/obj/item/borg/upgrade/supported_upgrades = list() - - // Bookkeeping - var/list/original_languages = list() - var/list/added_networks = list() - -/obj/item/weapon/robot_module/New(var/mob/living/silicon/robot/R) - ..() - R.module = src - - add_camera_networks(R) - add_languages(R) - add_subsystems(R) - apply_status_flags(R) - - if(R.radio) - R.radio.recalculateChannels() - - R.set_module_sprites(sprites) - R.choose_icon(R.module_sprites.len + 1, R.module_sprites) - - for(var/obj/item/I in modules) - I.canremove = 0 - -/obj/item/weapon/robot_module/proc/Reset(var/mob/living/silicon/robot/R) - remove_camera_networks(R) - remove_languages(R) - remove_subsystems(R) - remove_status_flags(R) - - if(R.radio) - R.radio.recalculateChannels() - R.choose_icon(0, R.set_module_sprites(list("Default" = "robot"))) - -/obj/item/weapon/robot_module/Destroy() - for(var/module in modules) - qdel(module) - for(var/synth in synths) - qdel(synth) - modules.Cut() - synths.Cut() - qdel(emag) - qdel(jetpack) - emag = null - jetpack = null - return ..() - -/obj/item/weapon/robot_module/emp_act(severity) - if(modules) - for(var/obj/O in modules) - O.emp_act(severity) - if(emag) - emag.emp_act(severity) - if(synths) - for(var/datum/matter_synth/S in synths) - S.emp_act(severity) - ..() - return - -/obj/item/weapon/robot_module/proc/respawn_consumable(var/mob/living/silicon/robot/R, var/rate) - if(!synths || !synths.len) - return - - for(var/datum/matter_synth/T in synths) - T.add_charge(T.recharge_rate * rate) - -/obj/item/weapon/robot_module/proc/rebuild()//Rebuilds the list so it's possible to add/remove items from the module - var/list/temp_list = modules - modules = list() - for(var/obj/O in temp_list) - if(O) - modules += O - -/obj/item/weapon/robot_module/proc/add_languages(var/mob/living/silicon/robot/R) - // Stores the languages as they were before receiving the module, and whether they could be synthezized. - for(var/datum/language/language_datum in R.languages) - original_languages[language_datum] = (language_datum in R.speech_synthesizer_langs) - - for(var/language in languages) - R.add_language(language, languages[language]) - -/obj/item/weapon/robot_module/proc/remove_languages(var/mob/living/silicon/robot/R) - // Clear all added languages, whether or not we originally had them. - for(var/language in languages) - R.remove_language(language) - - // Then add back all the original languages, and the relevant synthezising ability - for(var/original_language in original_languages) - R.add_language(original_language, original_languages[original_language]) - original_languages.Cut() - -/obj/item/weapon/robot_module/proc/add_camera_networks(var/mob/living/silicon/robot/R) - if(R.camera && (NETWORK_ROBOTS in R.camera.network)) - for(var/network in networks) - if(!(network in R.camera.network)) - R.camera.add_network(network) - added_networks |= network - -/obj/item/weapon/robot_module/proc/remove_camera_networks(var/mob/living/silicon/robot/R) - if(R.camera) - R.camera.remove_networks(added_networks) - added_networks.Cut() - -/obj/item/weapon/robot_module/proc/add_subsystems(var/mob/living/silicon/robot/R) - R.verbs |= subsystems - -/obj/item/weapon/robot_module/proc/remove_subsystems(var/mob/living/silicon/robot/R) - R.verbs -= subsystems - -/obj/item/weapon/robot_module/proc/apply_status_flags(var/mob/living/silicon/robot/R) - if(!can_be_pushed) - R.status_flags &= ~CANPUSH - -/obj/item/weapon/robot_module/proc/remove_status_flags(var/mob/living/silicon/robot/R) - if(!can_be_pushed) - R.status_flags |= CANPUSH - -// Cyborgs (non-drones), default loadout. This will be given to every module. -/obj/item/weapon/robot_module/robot/New() - ..() - src.modules += new /obj/item/device/flash(src) - src.modules += new /obj/item/weapon/crowbar/cyborg(src) - src.modules += new /obj/item/weapon/extinguisher(src) - vr_new() // Vorestation Edit: For modules in robot_modules_vr.dm - -/obj/item/weapon/robot_module/robot/standard - name = "standard robot module" - sprites = list( - "M-USE NanoTrasen" = "robot", - "Cabeiri" = "eyebot-standard", - "CUPCAKE" = "Noble-STD", - "Haruka" = "marinaSD", - "Usagi" = "tallflower", - "Telemachus" = "toiletbot", - "WTOperator" = "sleekstandard", - "WTOmni" = "omoikane", - "XI-GUS" = "spider", - "XI-ALP" = "heavyStandard", - "Basic" = "robot_old", - "Android" = "droid", - "Drone" = "drone-standard" - ) - -/obj/item/weapon/robot_module/robot/standard/New() - ..() - src.modules += new /obj/item/weapon/melee/baton/loaded(src) - src.modules += new /obj/item/weapon/wrench/cyborg(src) - src.modules += new /obj/item/device/healthanalyzer(src) - src.emag = new /obj/item/weapon/melee/energy/sword(src) - -/obj/item/weapon/robot_module/robot/medical - name = "medical robot module" - channels = list("Medical" = 1) - networks = list(NETWORK_MEDICAL) - subsystems = list(/mob/living/silicon/proc/subsystem_crew_monitor) - can_be_pushed = 0 - -/obj/item/weapon/robot_module/robot/medical/surgeon - name = "surgeon robot module" - sprites = list( - "M-USE NanoTrasen" = "robotMedi", - "Cabeiri" = "eyebot-medical", - "CUPCAKE" = "Noble-MED", - "Haruka" = "marinaMD", - "Minako" = "arachne", - "Usagi" = "tallwhite", - "Telemachus" = "toiletbotsurgeon", - "WTOperator" = "sleekcmo", - "XI-ALP" = "heavyMed", - "Basic" = "Medbot", - "Advanced Droid" = "droid-medical", - "Needles" = "medicalrobot", - "Drone" = "drone-surgery", - "Handy" = "handy-med" - ) - -/obj/item/weapon/robot_module/robot/medical/surgeon/New() - ..() - src.modules += new /obj/item/borg/sight/hud/med(src) - src.modules += new /obj/item/device/healthanalyzer(src) - src.modules += new /obj/item/weapon/reagent_containers/borghypo/surgeon(src) - src.modules += new /obj/item/weapon/surgical/scalpel(src) - src.modules += new /obj/item/weapon/surgical/hemostat(src) - src.modules += new /obj/item/weapon/surgical/retractor(src) - src.modules += new /obj/item/weapon/surgical/cautery(src) - src.modules += new /obj/item/weapon/surgical/bonegel(src) - src.modules += new /obj/item/weapon/surgical/FixOVein(src) - src.modules += new /obj/item/weapon/surgical/bonesetter(src) - src.modules += new /obj/item/weapon/surgical/circular_saw(src) - src.modules += new /obj/item/weapon/surgical/surgicaldrill(src) - src.modules += new /obj/item/weapon/gripper/no_use/organ(src) - src.modules += new /obj/item/weapon/gripper/medical(src) - src.modules += new /obj/item/weapon/shockpaddles/robot(src) - src.modules += new /obj/item/weapon/reagent_containers/dropper(src) // Allows surgeon borg to fix necrosis - src.emag = new /obj/item/weapon/reagent_containers/spray(src) - src.emag.reagents.add_reagent("pacid", 250) - src.emag.name = "Polyacid spray" - - var/datum/matter_synth/medicine = new /datum/matter_synth/medicine(10000) - synths += medicine - - var/obj/item/stack/nanopaste/N = new /obj/item/stack/nanopaste(src) - var/obj/item/stack/medical/advanced/bruise_pack/B = new /obj/item/stack/medical/advanced/bruise_pack(src) - N.uses_charge = 1 - N.charge_costs = list(1000) - N.synths = list(medicine) - B.uses_charge = 1 - B.charge_costs = list(1000) - B.synths = list(medicine) - src.modules += N - src.modules += B - -/obj/item/weapon/robot_module/medical/robot/surgeon/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - if(src.emag) - var/obj/item/weapon/reagent_containers/spray/PS = src.emag - PS.reagents.add_reagent("pacid", 2 * amount) - ..() - -/obj/item/weapon/robot_module/robot/medical/crisis - name = "crisis robot module" - sprites = list( - "M-USE NanoTrasen" = "robotMedi", - "Cabeiri" = "eyebot-medical", - "CUPCAKE" = "Noble-MED", - "Haruka" = "marinaMD", - "Minako" = "arachne", - "Usagi" = "tallwhite", - "Telemachus" = "toiletbotmedical", - "WTOperator" = "sleekmedic", - "XI-ALP" = "heavyMed", - "Basic" = "Medbot", - "Advanced Droid" = "droid-medical", - "Needles" = "medicalrobot", - "Drone - Medical" = "drone-medical", - "Drone - Chemistry" = "drone-chemistry" - ) - -/obj/item/weapon/robot_module/robot/medical/crisis/New() - ..() - src.modules += new /obj/item/borg/sight/hud/med(src) - src.modules += new /obj/item/device/healthanalyzer(src) - src.modules += new /obj/item/device/reagent_scanner/adv(src) - src.modules += new /obj/item/roller_holder(src) - src.modules += new /obj/item/weapon/reagent_containers/borghypo/crisis(src) - src.modules += new /obj/item/weapon/reagent_containers/glass/beaker/large(src) - src.modules += new /obj/item/weapon/reagent_containers/dropper/industrial(src) - src.modules += new /obj/item/weapon/reagent_containers/syringe(src) - src.modules += new /obj/item/weapon/gripper/no_use/organ(src) - src.modules += new /obj/item/weapon/gripper/medical(src) - src.modules += new /obj/item/weapon/shockpaddles/robot(src) - src.emag = new /obj/item/weapon/reagent_containers/spray(src) - src.emag.reagents.add_reagent("pacid", 250) - src.emag.name = "Polyacid spray" - - var/datum/matter_synth/medicine = new /datum/matter_synth/medicine(15000) - synths += medicine - - var/obj/item/stack/medical/advanced/ointment/O = new /obj/item/stack/medical/advanced/ointment(src) - var/obj/item/stack/medical/advanced/bruise_pack/B = new /obj/item/stack/medical/advanced/bruise_pack(src) - var/obj/item/stack/medical/splint/S = new /obj/item/stack/medical/splint(src) - O.uses_charge = 1 - O.charge_costs = list(1000) - O.synths = list(medicine) - B.uses_charge = 1 - B.charge_costs = list(1000) - B.synths = list(medicine) - S.uses_charge = 1 - S.charge_costs = list(1000) - S.synths = list(medicine) - src.modules += O - src.modules += B - src.modules += S - -/obj/item/weapon/robot_module/robot/medical/crisis/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - - var/obj/item/weapon/reagent_containers/syringe/S = locate() in src.modules - if(S.mode == 2) - S.reagents.clear_reagents() - S.mode = initial(S.mode) - S.desc = initial(S.desc) - S.update_icon() - - if(src.emag) - var/obj/item/weapon/reagent_containers/spray/PS = src.emag - PS.reagents.add_reagent("pacid", 2 * amount) - - ..() - - -/obj/item/weapon/robot_module/robot/engineering - name = "engineering robot module" - channels = list("Engineering" = 1) - networks = list(NETWORK_ENGINEERING) - subsystems = list(/mob/living/silicon/proc/subsystem_power_monitor) - sprites = list( - "M-USE NanoTrasen" = "robotEngi", - "Cabeiri" = "eyebot-engineering", - "CUPCAKE" = "Noble-ENG", - "Haruka" = "marinaENG", - "Usagi" = "tallyellow", - "Telemachus" = "toiletbotengineering", - "WTOperator" = "sleekce", - "XI-GUS" = "spidereng", - "XI-ALP" = "heavyEng", - "Basic" = "Engineering", - "Antique" = "engineerrobot", - "Landmate" = "landmate", - "Landmate - Treaded" = "engiborg+tread", - "Drone" = "drone-engineer", - "Treadwell" = "treadwell", - "Handy" = "handy-engineer" - ) - -/obj/item/weapon/robot_module/robot/engineering/construction - name = "construction robot module" - no_slip = 1 - -/* Merged back into engineering (Hell, it's about time.) - -/obj/item/weapon/robot_module/robot/engineering/construction/New() - ..() - src.modules += new /obj/item/borg/sight/meson(src) - src.modules += new /obj/item/weapon/rcd/borg(src) - src.modules += new /obj/item/weapon/screwdriver/cyborg(src) - src.modules += new /obj/item/weapon/wrench/cyborg(src) - src.modules += new /obj/item/weapon/weldingtool/electric/mounted(src) - src.modules += new /obj/item/weapon/pickaxe/plasmacutter(src) - src.modules += new /obj/item/device/pipe_painter(src) - src.modules += new /obj/item/device/floor_painter(src) - src.modules += new /obj/item/weapon/gripper/no_use/loader(src) - src.modules += new /obj/item/device/geiger(src) - - var/datum/matter_synth/metal = new /datum/matter_synth/metal() - var/datum/matter_synth/plasteel = new /datum/matter_synth/plasteel() - var/datum/matter_synth/glass = new /datum/matter_synth/glass() - synths += metal - synths += plasteel - synths += glass - - var/obj/item/stack/material/cyborg/steel/M = new (src) - M.synths = list(metal) - src.modules += M - - var/obj/item/stack/rods/cyborg/R = new /obj/item/stack/rods/cyborg(src) - R.synths = list(metal) - src.modules += R - - var/obj/item/stack/tile/floor/cyborg/F = new /obj/item/stack/tile/floor/cyborg(src) - F.synths = list(metal) - src.modules += F - - var/obj/item/stack/material/cyborg/plasteel/S = new (src) - S.synths = list(plasteel) - src.modules += S - - var/obj/item/stack/material/cyborg/glass/reinforced/RG = new (src) - RG.synths = list(metal, glass) - src.modules += RG -*/ - -/obj/item/weapon/robot_module/robot/engineering/general/New() - ..() - src.modules += new /obj/item/borg/sight/meson(src) - src.modules += new /obj/item/weapon/weldingtool/electric/mounted(src) - src.modules += new /obj/item/weapon/screwdriver/cyborg(src) - src.modules += new /obj/item/weapon/wrench/cyborg(src) - src.modules += new /obj/item/weapon/wirecutters/cyborg(src) - src.modules += new /obj/item/device/multitool(src) - src.modules += new /obj/item/device/t_scanner(src) - src.modules += new /obj/item/device/analyzer(src) - src.modules += new /obj/item/taperoll/engineering(src) - src.modules += new /obj/item/weapon/gripper(src) - src.modules += new /obj/item/device/lightreplacer(src) - src.modules += new /obj/item/device/pipe_painter(src) - src.modules += new /obj/item/device/floor_painter(src) - src.modules += new /obj/item/weapon/inflatable_dispenser/robot(src) - src.emag = new /obj/item/weapon/melee/baton/robot/arm(src) - src.modules += new /obj/item/device/geiger(src) - src.modules += new /obj/item/weapon/rcd/borg(src) - src.modules += new /obj/item/weapon/pickaxe/plasmacutter(src) - src.modules += new /obj/item/weapon/gripper/no_use/loader(src) - - var/datum/matter_synth/metal = new /datum/matter_synth/metal(40000) - var/datum/matter_synth/glass = new /datum/matter_synth/glass(40000) - var/datum/matter_synth/plasteel = new /datum/matter_synth/plasteel(20000) - - var/datum/matter_synth/wire = new /datum/matter_synth/wire() - synths += metal - synths += glass - synths += plasteel - synths += wire - - var/obj/item/weapon/matter_decompiler/MD = new /obj/item/weapon/matter_decompiler(src) - MD.metal = metal - MD.glass = glass - src.modules += MD - - var/obj/item/stack/material/cyborg/steel/M = new (src) - M.synths = list(metal) - src.modules += M - - var/obj/item/stack/material/cyborg/glass/G = new (src) - G.synths = list(glass) - src.modules += G - - var/obj/item/stack/rods/cyborg/R = new /obj/item/stack/rods/cyborg(src) - R.synths = list(metal) - src.modules += R - - var/obj/item/stack/cable_coil/cyborg/C = new /obj/item/stack/cable_coil/cyborg(src) - C.synths = list(wire) - src.modules += C - - var/obj/item/stack/material/cyborg/plasteel/P = new (src) - P.synths = list(plasteel) - src.modules += P - - var/obj/item/stack/tile/floor/cyborg/S = new /obj/item/stack/tile/floor/cyborg(src) - S.synths = list(metal) - src.modules += S - - var/obj/item/stack/material/cyborg/glass/reinforced/RG = new (src) - RG.synths = list(metal, glass) - src.modules += RG - -/obj/item/weapon/robot_module/robot/security - name = "security robot module" - channels = list("Security" = 1) - networks = list(NETWORK_SECURITY) - subsystems = list(/mob/living/silicon/proc/subsystem_crew_monitor) - can_be_pushed = 0 - supported_upgrades = list(/obj/item/borg/upgrade/tasercooler) - -/obj/item/weapon/robot_module/robot/security/general - sprites = list( - "M-USE NanoTrasen" = "robotSecy", - "Cabeiri" = "eyebot-security", - "Cerberus" = "bloodhound", - "Cerberus - Treaded" = "treadhound", - "CUPCAKE" = "Noble-SEC", - "Haruka" = "marinaSC", - "Usagi" = "tallred", - "Telemachus" = "toiletbotsecurity", - "WTOperator" = "sleeksecurity", - "XI-GUS" = "spidersec", - "XI-ALP" = "heavySec", - "Basic" = "secborg", - "Black Knight" = "securityrobot", - "Drone" = "drone-sec" - ) - -/obj/item/weapon/robot_module/robot/security/general/New() - ..() - src.modules += new /obj/item/borg/sight/hud/sec(src) - src.modules += new /obj/item/weapon/handcuffs/cyborg(src) - src.modules += new /obj/item/weapon/melee/baton/robot(src) - src.modules += new /obj/item/weapon/gun/energy/taser/mounted/cyborg(src) - src.modules += new /obj/item/taperoll/police(src) - src.modules += new /obj/item/weapon/reagent_containers/spray/pepper(src) - src.emag = new /obj/item/weapon/gun/energy/laser/mounted(src) - -/obj/item/weapon/robot_module/robot/security/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - var/obj/item/device/flash/F = locate() in src.modules - if(F.broken) - F.broken = 0 - F.times_used = 0 - F.icon_state = "flash" - else if(F.times_used) - F.times_used-- - var/obj/item/weapon/gun/energy/taser/mounted/cyborg/T = locate() in src.modules - if(T.power_supply.charge < T.power_supply.maxcharge) - T.power_supply.give(T.charge_cost * amount) - T.update_icon() - else - T.charge_tick = 0 - var/obj/item/weapon/melee/baton/robot/B = locate() in src.modules - if(B && B.bcell) - B.bcell.give(amount) - -/obj/item/weapon/robot_module/robot/janitor - name = "janitorial robot module" - channels = list("Service" = 1) - sprites = list( - "M-USE NanoTrasen" = "robotJani", - "Arachne" = "crawler", - "Cabeiri" = "eyebot-janitor", - "CUPCAKE" = "Noble-CLN", - "Haruka" = "marinaJN", - "Telemachus" = "toiletbotjanitor", - "WTOperator" = "sleekjanitor", - "XI-ALP" = "heavyRes", - "Basic" = "JanBot2", - "Mopbot" = "janitorrobot", - "Mop Gear Rex" = "mopgearrex", - "Drone" = "drone-janitor" - ) - -/obj/item/weapon/robot_module/robot/janitor/New() - ..() - src.modules += new /obj/item/weapon/soap/nanotrasen(src) - src.modules += new /obj/item/weapon/storage/bag/trash(src) - src.modules += new /obj/item/weapon/mop(src) - src.modules += new /obj/item/device/lightreplacer(src) - src.emag = new /obj/item/weapon/reagent_containers/spray(src) - src.emag.reagents.add_reagent("lube", 250) - src.emag.name = "Lube spray" - -/obj/item/weapon/robot_module/robot/janitor/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - var/obj/item/device/lightreplacer/LR = locate() in src.modules - LR.Charge(R, amount) - if(src.emag) - var/obj/item/weapon/reagent_containers/spray/S = src.emag - S.reagents.add_reagent("lube", 2 * amount) - -/obj/item/weapon/robot_module/robot/clerical - name = "service robot module" - channels = list("Service" = 1) - languages = list( - LANGUAGE_SOL_COMMON = 1, - LANGUAGE_UNATHI = 1, - LANGUAGE_SIIK = 1, - LANGUAGE_SKRELLIAN = 1, - LANGUAGE_ROOTLOCAL = 0, - LANGUAGE_TRADEBAND = 1, - LANGUAGE_GUTTER = 1, - LANGUAGE_SCHECHI = 1, - LANGUAGE_EAL = 1, - LANGUAGE_SIGN = 0 - ) - -/obj/item/weapon/robot_module/robot/clerical/butler - sprites = list( - "M-USE NanoTrasen" = "robotServ", - "Cabeiri" = "eyebot-standard", - "CUPCAKE" = "Noble-SRV", - "Haruka" = "marinaSV", - "Michiru" = "maidbot", - "Usagi" = "tallgreen", - "Telemachus" = "toiletbot", - "WTOperator" = "sleekservice", - "WTOmni" = "omoikane", - "XI-GUS" = "spider", - "XI-ALP" = "heavyServ", - "Standard" = "Service2", - "Waitress" = "Service", - "Bro" = "Brobot", - "Rich" = "maximillion", - "Drone - Service" = "drone-service", - "Drone - Hydro" = "drone-hydro" - ) - -/obj/item/weapon/robot_module/robot/clerical/butler/New() - ..() - src.modules += new /obj/item/weapon/gripper/service(src) - src.modules += new /obj/item/weapon/reagent_containers/glass/bucket(src) - src.modules += new /obj/item/weapon/material/minihoe(src) - src.modules += new /obj/item/weapon/material/hatchet(src) - src.modules += new /obj/item/device/analyzer/plant_analyzer(src) - src.modules += new /obj/item/weapon/storage/bag/plants(src) - src.modules += new /obj/item/weapon/robot_harvester(src) - src.modules += new /obj/item/weapon/material/knife(src) - src.modules += new /obj/item/weapon/material/kitchen/rollingpin(src) - src.modules += new /obj/item/device/multitool(src) //to freeze trays - - var/obj/item/weapon/rsf/M = new /obj/item/weapon/rsf(src) - M.stored_matter = 30 - src.modules += M - - src.modules += new /obj/item/weapon/reagent_containers/dropper/industrial(src) - - var/obj/item/weapon/flame/lighter/zippo/L = new /obj/item/weapon/flame/lighter/zippo(src) - L.lit = 1 - src.modules += L - - src.modules += new /obj/item/weapon/tray/robotray(src) - src.modules += new /obj/item/weapon/reagent_containers/borghypo/service(src) - src.emag = new /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer(src) - - var/datum/reagents/R = new/datum/reagents(50) - src.emag.reagents = R - R.my_atom = src.emag - R.add_reagent("beer2", 50) - src.emag.name = "Mickey Finn's Special Brew" - -/obj/item/weapon/robot_module/robot/clerical/general - name = "clerical robot module" - sprites = list( - "M-USE NanoTrasen" = "robotCler", - "Cabeiri" = "eyebot-standard", - "CUPCAKE" = "Noble-SRV", - "Haruka" = "marinaSV", - "Usagi" = "tallgreen", - "Telemachus" = "toiletbot", - "WTOperator" = "sleekclerical", - "WTOmni" = "omoikane", - "XI-GUS" = "spidercom", - "XI-ALP" = "heavyServ", - "Waitress" = "Service", - "Bro" = "Brobot", - "Rich" = "maximillion", - "Default" = "Service2", - "Drone" = "drone-blu" - ) - -/obj/item/weapon/robot_module/robot/clerical/general/New() - ..() - src.modules += new /obj/item/weapon/pen/robopen(src) - src.modules += new /obj/item/weapon/form_printer(src) - src.modules += new /obj/item/weapon/gripper/paperwork(src) - src.modules += new /obj/item/weapon/hand_labeler(src) - src.modules += new /obj/item/weapon/stamp(src) - src.modules += new /obj/item/weapon/stamp/denied(src) - src.emag = new /obj/item/weapon/stamp/chameleon(src) - src.emag = new /obj/item/weapon/pen/chameleon(src) - -/obj/item/weapon/robot_module/general/butler/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - var/obj/item/weapon/reagent_containers/food/condiment/enzyme/E = locate() in src.modules - E.reagents.add_reagent("enzyme", 2 * amount) - if(src.emag) - var/obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer/B = src.emag - B.reagents.add_reagent("beer2", 2 * amount) - -/obj/item/weapon/robot_module/robot/miner - name = "miner robot module" - channels = list("Supply" = 1) - networks = list(NETWORK_MINE) - sprites = list( - "NM-USE NanoTrasen" = "robotMine", - "Cabeiri" = "eyebot-miner", - "CUPCAKE" = "Noble-DIG", - "Haruka" = "marinaMN", - "Telemachus" = "toiletbotminer", - "WTOperator" = "sleekminer", - "XI-GUS" = "spidermining", - "XI-ALP" = "heavyMiner", - "Basic" = "Miner_old", - "Advanced Droid" = "droid-miner", - "Treadhead" = "Miner", - "Drone" = "drone-miner" - ) - -/obj/item/weapon/robot_module/robot/miner/New() - ..() - src.modules += new /obj/item/borg/sight/material(src) - src.modules += new /obj/item/weapon/wrench/cyborg(src) - src.modules += new /obj/item/weapon/screwdriver/cyborg(src) - src.modules += new /obj/item/weapon/storage/bag/ore(src) - src.modules += new /obj/item/weapon/pickaxe/borgdrill(src) - src.modules += new /obj/item/weapon/storage/bag/sheetsnatcher/borg(src) - src.modules += new /obj/item/weapon/gripper/miner(src) - src.modules += new /obj/item/weapon/mining_scanner(src) - src.emag = new /obj/item/weapon/pickaxe/plasmacutter(src) - src.emag = new /obj/item/weapon/pickaxe/diamonddrill(src) - -/obj/item/weapon/robot_module/robot/research - name = "research module" - channels = list("Science" = 1) - sprites = list( - "L'Ouef" = "peaceborg", - "Cabeiri" = "eyebot-science", - "Haruka" = "marinaSCI", - "WTDove" = "whitespider", - "WTOperator" = "sleekscience", - "Droid" = "droid-science", - "Drone" = "drone-science", - "Handy" = "handy-science" - ) - -/obj/item/weapon/robot_module/robot/research/New() - ..() - src.modules += new /obj/item/weapon/portable_destructive_analyzer(src) - src.modules += new /obj/item/weapon/gripper/research(src) - src.modules += new /obj/item/weapon/gripper/no_use/organ/robotics(src) - src.modules += new /obj/item/weapon/gripper/no_use/mech(src) - src.modules += new /obj/item/weapon/gripper/no_use/loader(src) - src.modules += new /obj/item/device/robotanalyzer(src) - src.modules += new /obj/item/weapon/card/robot(src) - src.modules += new /obj/item/weapon/weldingtool/electric/mounted(src) - src.modules += new /obj/item/weapon/screwdriver/cyborg(src) - src.modules += new /obj/item/weapon/wrench/cyborg(src) - src.modules += new /obj/item/weapon/wirecutters/cyborg(src) - src.modules += new /obj/item/device/multitool(src) - src.modules += new /obj/item/weapon/surgical/scalpel(src) - src.modules += new /obj/item/weapon/surgical/circular_saw(src) - src.modules += new /obj/item/weapon/reagent_containers/syringe(src) - src.modules += new /obj/item/weapon/reagent_containers/glass/beaker/large(src) - src.modules += new /obj/item/weapon/storage/part_replacer(src) - src.modules += new /obj/item/weapon/shockpaddles/robot/jumper(src) - src.modules += new /obj/item/weapon/melee/baton/slime/robot(src) - src.modules += new /obj/item/weapon/gun/energy/taser/xeno/robot(src) - src.emag = new /obj/item/weapon/hand_tele(src) - - var/datum/matter_synth/nanite = new /datum/matter_synth/nanite(10000) - synths += nanite - var/datum/matter_synth/wire = new /datum/matter_synth/wire() //Added to allow repairs, would rather add cable now than be asked to add it later, - synths += wire //Cable code, taken from engiborg, - - var/obj/item/stack/nanopaste/N = new /obj/item/stack/nanopaste(src) - N.uses_charge = 1 - N.charge_costs = list(1000) - N.synths = list(nanite) - src.modules += N - - var/obj/item/stack/cable_coil/cyborg/C = new /obj/item/stack/cable_coil/cyborg(src) //Cable code, taken from engiborg, - C.synths = list(wire) - src.modules += C - -/obj/item/weapon/robot_module/robot/syndicate - name = "illegal robot module" - hide_on_manifest = 1 - languages = list( - LANGUAGE_SOL_COMMON = 1, - LANGUAGE_TRADEBAND = 1, - LANGUAGE_UNATHI = 0, - LANGUAGE_SIIK = 0, - LANGUAGE_SKRELLIAN = 0, - LANGUAGE_ROOTLOCAL = 0, - LANGUAGE_GUTTER = 1, - LANGUAGE_SCHECHI = 0, - LANGUAGE_EAL = 1, - LANGUAGE_SIGN = 0 - ) - sprites = list( - "Cerberus" = "syndie_bloodhound", - "Cerberus - Treaded" = "syndie_treadhound", - "Ares" = "squats", - "Telemachus" = "toiletbotantag", - "WTOperator" = "hosborg", - "XI-GUS" = "spidersyndi", - "XI-ALP" = "syndi-heavy" - ) - var/id - -/obj/item/weapon/robot_module/robot/syndicate/New(var/mob/living/silicon/robot/R) - ..() - loc = R - src.modules += new /obj/item/weapon/melee/energy/sword(src) - src.modules += new /obj/item/weapon/gun/energy/pulse_rifle/destroyer(src) - src.modules += new /obj/item/weapon/card/emag(src) - var/jetpack = new/obj/item/weapon/tank/jetpack/carbondioxide(src) - src.modules += jetpack - R.internals = jetpack - - id = R.idcard - src.modules += id - -/obj/item/weapon/robot_module/robot/syndicate/Destroy() - src.modules -= id - id = null - return ..() - -/obj/item/weapon/robot_module/robot/security/combat - name = "combat robot module" - hide_on_manifest = 1 - sprites = list( - "Haruka" = "marinaCB", - "Combat Android" = "droid-combat" - ) - -/obj/item/weapon/robot_module/robot/security/combat/New() - ..() - src.modules += new /obj/item/device/flash(src) - //src.modules += new /obj/item/borg/sight/thermal(src) // VOREStation Edit - src.modules += new /obj/item/weapon/gun/energy/laser/mounted(src) - src.modules += new /obj/item/weapon/pickaxe/plasmacutter(src) - src.modules += new /obj/item/borg/combat/shield(src) - src.modules += new /obj/item/borg/combat/mobility(src) - src.emag = new /obj/item/weapon/gun/energy/lasercannon/mounted(src) - -/obj/item/weapon/robot_module/drone - name = "drone module" - hide_on_manifest = 1 - no_slip = 1 - networks = list(NETWORK_ENGINEERING) - -/obj/item/weapon/robot_module/drone/New(var/mob/living/silicon/robot/robot) - ..() - src.modules += new /obj/item/borg/sight/meson(src) - src.modules += new /obj/item/weapon/weldingtool/electric/mounted(src) - src.modules += new /obj/item/weapon/screwdriver/cyborg(src) - src.modules += new /obj/item/weapon/wrench/cyborg(src) - src.modules += new /obj/item/weapon/crowbar/cyborg(src) - src.modules += new /obj/item/weapon/wirecutters/cyborg(src) - src.modules += new /obj/item/device/multitool(src) - src.modules += new /obj/item/device/lightreplacer(src) - src.modules += new /obj/item/weapon/gripper(src) - src.modules += new /obj/item/weapon/soap(src) - src.modules += new /obj/item/weapon/gripper/no_use/loader(src) - src.modules += new /obj/item/weapon/extinguisher(src) - src.modules += new /obj/item/device/pipe_painter(src) - src.modules += new /obj/item/device/floor_painter(src) - - robot.internals = new/obj/item/weapon/tank/jetpack/carbondioxide(src) - src.modules += robot.internals - - src.emag = new /obj/item/weapon/pickaxe/plasmacutter(src) - src.emag.name = "Plasma Cutter" - - var/datum/matter_synth/metal = new /datum/matter_synth/metal(25000) - var/datum/matter_synth/glass = new /datum/matter_synth/glass(25000) - var/datum/matter_synth/wood = new /datum/matter_synth/wood(2000) - var/datum/matter_synth/plastic = new /datum/matter_synth/plastic(1000) - var/datum/matter_synth/wire = new /datum/matter_synth/wire(30) - synths += metal - synths += glass - synths += wood - synths += plastic - synths += wire - - var/obj/item/weapon/matter_decompiler/MD = new /obj/item/weapon/matter_decompiler(src) - MD.metal = metal - MD.glass = glass - MD.wood = wood - MD.plastic = plastic - src.modules += MD - - var/obj/item/stack/material/cyborg/steel/M = new (src) - M.synths = list(metal) - src.modules += M - - var/obj/item/stack/material/cyborg/glass/G = new (src) - G.synths = list(glass) - src.modules += G - - var/obj/item/stack/rods/cyborg/R = new /obj/item/stack/rods/cyborg(src) - R.synths = list(metal) - src.modules += R - - var/obj/item/stack/cable_coil/cyborg/C = new /obj/item/stack/cable_coil/cyborg(src) - C.synths = list(wire) - src.modules += C - - var/obj/item/stack/tile/floor/cyborg/S = new /obj/item/stack/tile/floor/cyborg(src) - S.synths = list(metal) - src.modules += S - - var/obj/item/stack/material/cyborg/glass/reinforced/RG = new (src) - RG.synths = list(metal, glass) - src.modules += RG - - var/obj/item/stack/tile/wood/cyborg/WT = new /obj/item/stack/tile/wood/cyborg(src) - WT.synths = list(wood) - src.modules += WT - - var/obj/item/stack/material/cyborg/wood/W = new (src) - W.synths = list(wood) - src.modules += W - - var/obj/item/stack/material/cyborg/plastic/P = new (src) - P.synths = list(plastic) - src.modules += P - -/obj/item/weapon/robot_module/drone/construction - name = "construction drone module" - hide_on_manifest = 1 - channels = list("Engineering" = 1) - languages = list() - -/obj/item/weapon/robot_module/drone/construction/New() - ..() - src.modules += new /obj/item/weapon/rcd/borg(src) - -/obj/item/weapon/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) - var/obj/item/device/lightreplacer/LR = locate() in src.modules - LR.Charge(R, amount) - ..() +var/global/list/robot_modules = list( + "Standard" = /obj/item/weapon/robot_module/robot/standard, + "Service" = /obj/item/weapon/robot_module/robot/clerical/butler, + "Clerical" = /obj/item/weapon/robot_module/robot/clerical/general, + "Research" = /obj/item/weapon/robot_module/robot/research, + "Miner" = /obj/item/weapon/robot_module/robot/miner, + "Crisis" = /obj/item/weapon/robot_module/robot/medical/crisis, + "Surgeon" = /obj/item/weapon/robot_module/robot/medical/surgeon, + "Security" = /obj/item/weapon/robot_module/robot/security/general, + "Combat" = /obj/item/weapon/robot_module/robot/security/combat, + "Engineering" = /obj/item/weapon/robot_module/robot/engineering/general, +// "Construction" = /obj/item/weapon/robot_module/robot/engineering/construction, + "Janitor" = /obj/item/weapon/robot_module/robot/janitor + ) + +/obj/item/weapon/robot_module + name = "robot module" + icon = 'icons/obj/module.dmi' + icon_state = "std_module" + w_class = ITEMSIZE_NO_CONTAINER + item_state = "std_mod" + flags = CONDUCT + var/hide_on_manifest = 0 + var/channels = list() + var/networks = list() + var/languages = list(LANGUAGE_SOL_COMMON = 1, LANGUAGE_TRADEBAND = 1, LANGUAGE_UNATHI = 0, LANGUAGE_SIIK = 0, LANGUAGE_SKRELLIAN = 0, LANGUAGE_GUTTER = 0, LANGUAGE_SCHECHI = 0, LANGUAGE_SIGN = 0) + var/sprites = list() + var/can_be_pushed = 1 + var/no_slip = 0 + var/list/modules = list() + var/list/datum/matter_synth/synths = list() + var/obj/item/emag = null + var/obj/item/borg/upgrade/jetpack = null + var/list/subsystems = list() + var/list/obj/item/borg/upgrade/supported_upgrades = list() + + // Bookkeeping + var/list/original_languages = list() + var/list/added_networks = list() + +/obj/item/weapon/robot_module/New(var/mob/living/silicon/robot/R) + ..() + R.module = src + + add_camera_networks(R) + add_languages(R) + add_subsystems(R) + apply_status_flags(R) + + if(R.radio) + R.radio.recalculateChannels() + + R.set_module_sprites(sprites) + R.choose_icon(R.module_sprites.len + 1, R.module_sprites) + + for(var/obj/item/I in modules) + I.canremove = 0 + +/obj/item/weapon/robot_module/proc/Reset(var/mob/living/silicon/robot/R) + remove_camera_networks(R) + remove_languages(R) + remove_subsystems(R) + remove_status_flags(R) + + if(R.radio) + R.radio.recalculateChannels() + R.choose_icon(0, R.set_module_sprites(list("Default" = "robot"))) + +/obj/item/weapon/robot_module/Destroy() + for(var/module in modules) + qdel(module) + for(var/synth in synths) + qdel(synth) + modules.Cut() + synths.Cut() + qdel(emag) + qdel(jetpack) + emag = null + jetpack = null + return ..() + +/obj/item/weapon/robot_module/emp_act(severity) + if(modules) + for(var/obj/O in modules) + O.emp_act(severity) + if(emag) + emag.emp_act(severity) + if(synths) + for(var/datum/matter_synth/S in synths) + S.emp_act(severity) + ..() + return + +/obj/item/weapon/robot_module/proc/respawn_consumable(var/mob/living/silicon/robot/R, var/rate) + if(!synths || !synths.len) + return + + for(var/datum/matter_synth/T in synths) + T.add_charge(T.recharge_rate * rate) + +/obj/item/weapon/robot_module/proc/rebuild()//Rebuilds the list so it's possible to add/remove items from the module + var/list/temp_list = modules + modules = list() + for(var/obj/O in temp_list) + if(O) + modules += O + +/obj/item/weapon/robot_module/proc/add_languages(var/mob/living/silicon/robot/R) + // Stores the languages as they were before receiving the module, and whether they could be synthezized. + for(var/datum/language/language_datum in R.languages) + original_languages[language_datum] = (language_datum in R.speech_synthesizer_langs) + + for(var/language in languages) + R.add_language(language, languages[language]) + +/obj/item/weapon/robot_module/proc/remove_languages(var/mob/living/silicon/robot/R) + // Clear all added languages, whether or not we originally had them. + for(var/language in languages) + R.remove_language(language) + + // Then add back all the original languages, and the relevant synthezising ability + for(var/original_language in original_languages) + R.add_language(original_language, original_languages[original_language]) + original_languages.Cut() + +/obj/item/weapon/robot_module/proc/add_camera_networks(var/mob/living/silicon/robot/R) + if(R.camera && (NETWORK_ROBOTS in R.camera.network)) + for(var/network in networks) + if(!(network in R.camera.network)) + R.camera.add_network(network) + added_networks |= network + +/obj/item/weapon/robot_module/proc/remove_camera_networks(var/mob/living/silicon/robot/R) + if(R.camera) + R.camera.remove_networks(added_networks) + added_networks.Cut() + +/obj/item/weapon/robot_module/proc/add_subsystems(var/mob/living/silicon/robot/R) + R.verbs |= subsystems + +/obj/item/weapon/robot_module/proc/remove_subsystems(var/mob/living/silicon/robot/R) + R.verbs -= subsystems + +/obj/item/weapon/robot_module/proc/apply_status_flags(var/mob/living/silicon/robot/R) + if(!can_be_pushed) + R.status_flags &= ~CANPUSH + +/obj/item/weapon/robot_module/proc/remove_status_flags(var/mob/living/silicon/robot/R) + if(!can_be_pushed) + R.status_flags |= CANPUSH + +// Cyborgs (non-drones), default loadout. This will be given to every module. +/obj/item/weapon/robot_module/robot/New() + ..() + src.modules += new /obj/item/device/flash(src) + src.modules += new /obj/item/weapon/crowbar/cyborg(src) + src.modules += new /obj/item/weapon/extinguisher(src) + vr_new() // Vorestation Edit: For modules in robot_modules_vr.dm + +/obj/item/weapon/robot_module/robot/standard + name = "standard robot module" + sprites = list( + "M-USE NanoTrasen" = "robot", + "Cabeiri" = "eyebot-standard", + "CUPCAKE" = "Noble-STD", + "Haruka" = "marinaSD", + "Usagi" = "tallflower", + "Telemachus" = "toiletbot", + "WTOperator" = "sleekstandard", + "WTOmni" = "omoikane", + "XI-GUS" = "spider", + "XI-ALP" = "heavyStandard", + "Basic" = "robot_old", + "Android" = "droid", + "Drone" = "drone-standard" + ) + +/obj/item/weapon/robot_module/robot/standard/New() + ..() + src.modules += new /obj/item/weapon/melee/baton/loaded(src) + src.modules += new /obj/item/weapon/wrench/cyborg(src) + src.modules += new /obj/item/device/healthanalyzer(src) + src.emag = new /obj/item/weapon/melee/energy/sword(src) + +/obj/item/weapon/robot_module/robot/medical + name = "medical robot module" + channels = list("Medical" = 1) + networks = list(NETWORK_MEDICAL) + subsystems = list(/mob/living/silicon/proc/subsystem_crew_monitor) + can_be_pushed = 0 + +/obj/item/weapon/robot_module/robot/medical/surgeon + name = "surgeon robot module" + sprites = list( + "M-USE NanoTrasen" = "robotMedi", + "Cabeiri" = "eyebot-medical", + "CUPCAKE" = "Noble-MED", + "Haruka" = "marinaMD", + "Minako" = "arachne", + "Usagi" = "tallwhite", + "Telemachus" = "toiletbotsurgeon", + "WTOperator" = "sleekcmo", + "XI-ALP" = "heavyMed", + "Basic" = "Medbot", + "Advanced Droid" = "droid-medical", + "Needles" = "medicalrobot", + "Drone" = "drone-surgery", + "Handy" = "handy-med" + ) + +/obj/item/weapon/robot_module/robot/medical/surgeon/New() + ..() + src.modules += new /obj/item/borg/sight/hud/med(src) + src.modules += new /obj/item/device/healthanalyzer(src) + src.modules += new /obj/item/weapon/reagent_containers/borghypo/surgeon(src) + src.modules += new /obj/item/weapon/surgical/scalpel/cyborg(src) + src.modules += new /obj/item/weapon/surgical/hemostat/cyborg(src) + src.modules += new /obj/item/weapon/surgical/retractor/cyborg(src) + src.modules += new /obj/item/weapon/surgical/cautery/cyborg(src) + src.modules += new /obj/item/weapon/surgical/bonegel/cyborg(src) + src.modules += new /obj/item/weapon/surgical/FixOVein/cyborg(src) + src.modules += new /obj/item/weapon/surgical/bonesetter/cyborg(src) + src.modules += new /obj/item/weapon/surgical/circular_saw/cyborg(src) + src.modules += new /obj/item/weapon/surgical/surgicaldrill/cyborg(src) + src.modules += new /obj/item/weapon/gripper/no_use/organ(src) + src.modules += new /obj/item/weapon/gripper/medical(src) + src.modules += new /obj/item/weapon/shockpaddles/robot(src) + src.modules += new /obj/item/weapon/reagent_containers/dropper(src) // Allows surgeon borg to fix necrosis + src.modules += new /obj/item/weapon/reagent_containers/syringe(src) + src.emag = new /obj/item/weapon/reagent_containers/spray(src) + src.emag.reagents.add_reagent("pacid", 250) + src.emag.name = "Polyacid spray" + + var/datum/matter_synth/medicine = new /datum/matter_synth/medicine(10000) + synths += medicine + + var/obj/item/stack/nanopaste/N = new /obj/item/stack/nanopaste(src) + var/obj/item/stack/medical/advanced/bruise_pack/B = new /obj/item/stack/medical/advanced/bruise_pack(src) + N.uses_charge = 1 + N.charge_costs = list(1000) + N.synths = list(medicine) + B.uses_charge = 1 + B.charge_costs = list(1000) + B.synths = list(medicine) + src.modules += N + src.modules += B + +/obj/item/weapon/robot_module/medical/robot/surgeon/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) + if(src.emag) + var/obj/item/weapon/reagent_containers/spray/PS = src.emag + PS.reagents.add_reagent("pacid", 2 * amount) + ..() + +/obj/item/weapon/robot_module/robot/medical/crisis + name = "crisis robot module" + sprites = list( + "M-USE NanoTrasen" = "robotMedi", + "Cabeiri" = "eyebot-medical", + "CUPCAKE" = "Noble-MED", + "Haruka" = "marinaMD", + "Minako" = "arachne", + "Usagi" = "tallwhite", + "Telemachus" = "toiletbotmedical", + "WTOperator" = "sleekmedic", + "XI-ALP" = "heavyMed", + "Basic" = "Medbot", + "Advanced Droid" = "droid-medical", + "Needles" = "medicalrobot", + "Drone - Medical" = "drone-medical", + "Drone - Chemistry" = "drone-chemistry" + ) + +/obj/item/weapon/robot_module/robot/medical/crisis/New() + ..() + src.modules += new /obj/item/borg/sight/hud/med(src) + src.modules += new /obj/item/device/healthanalyzer(src) + src.modules += new /obj/item/device/reagent_scanner/adv(src) + src.modules += new /obj/item/roller_holder(src) + src.modules += new /obj/item/weapon/reagent_containers/borghypo/crisis(src) + src.modules += new /obj/item/weapon/reagent_containers/glass/beaker/large(src) + src.modules += new /obj/item/weapon/reagent_containers/dropper/industrial(src) + src.modules += new /obj/item/weapon/reagent_containers/syringe(src) + src.modules += new /obj/item/weapon/gripper/no_use/organ(src) + src.modules += new /obj/item/weapon/gripper/medical(src) + src.modules += new /obj/item/weapon/shockpaddles/robot(src) + src.emag = new /obj/item/weapon/reagent_containers/spray(src) + src.emag.reagents.add_reagent("pacid", 250) + src.emag.name = "Polyacid spray" + + var/datum/matter_synth/medicine = new /datum/matter_synth/medicine(15000) + synths += medicine + + var/obj/item/stack/medical/advanced/ointment/O = new /obj/item/stack/medical/advanced/ointment(src) + var/obj/item/stack/medical/advanced/bruise_pack/B = new /obj/item/stack/medical/advanced/bruise_pack(src) + var/obj/item/stack/medical/splint/S = new /obj/item/stack/medical/splint(src) + O.uses_charge = 1 + O.charge_costs = list(1000) + O.synths = list(medicine) + B.uses_charge = 1 + B.charge_costs = list(1000) + B.synths = list(medicine) + S.uses_charge = 1 + S.charge_costs = list(1000) + S.synths = list(medicine) + src.modules += O + src.modules += B + src.modules += S + +/obj/item/weapon/robot_module/robot/medical/crisis/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) + + var/obj/item/weapon/reagent_containers/syringe/S = locate() in src.modules + if(S.mode == 2) + S.reagents.clear_reagents() + S.mode = initial(S.mode) + S.desc = initial(S.desc) + S.update_icon() + + if(src.emag) + var/obj/item/weapon/reagent_containers/spray/PS = src.emag + PS.reagents.add_reagent("pacid", 2 * amount) + + ..() + + +/obj/item/weapon/robot_module/robot/engineering + name = "engineering robot module" + channels = list("Engineering" = 1) + networks = list(NETWORK_ENGINEERING) + subsystems = list(/mob/living/silicon/proc/subsystem_power_monitor) + sprites = list( + "M-USE NanoTrasen" = "robotEngi", + "Cabeiri" = "eyebot-engineering", + "CUPCAKE" = "Noble-ENG", + "Haruka" = "marinaENG", + "Usagi" = "tallyellow", + "Telemachus" = "toiletbotengineering", + "WTOperator" = "sleekce", + "XI-GUS" = "spidereng", + "XI-ALP" = "heavyEng", + "Basic" = "Engineering", + "Antique" = "engineerrobot", + "Landmate" = "landmate", + "Landmate - Treaded" = "engiborg+tread", + "Drone" = "drone-engineer", + "Treadwell" = "treadwell", + "Handy" = "handy-engineer" + ) + +/obj/item/weapon/robot_module/robot/engineering/construction + name = "construction robot module" + no_slip = 1 + +/* Merged back into engineering (Hell, it's about time.) + +/obj/item/weapon/robot_module/robot/engineering/construction/New() + ..() + src.modules += new /obj/item/borg/sight/meson(src) + src.modules += new /obj/item/weapon/rcd/borg(src) + src.modules += new /obj/item/weapon/screwdriver/cyborg(src) + src.modules += new /obj/item/weapon/wrench/cyborg(src) + src.modules += new /obj/item/weapon/weldingtool/electric/mounted/cyborg(src) + src.modules += new /obj/item/weapon/pickaxe/plasmacutter(src) + src.modules += new /obj/item/device/pipe_painter(src) + src.modules += new /obj/item/device/floor_painter(src) + src.modules += new /obj/item/weapon/gripper/no_use/loader(src) + src.modules += new /obj/item/device/geiger(src) + + var/datum/matter_synth/metal = new /datum/matter_synth/metal() + var/datum/matter_synth/plasteel = new /datum/matter_synth/plasteel() + var/datum/matter_synth/glass = new /datum/matter_synth/glass() + synths += metal + synths += plasteel + synths += glass + + var/obj/item/stack/material/cyborg/steel/M = new (src) + M.synths = list(metal) + src.modules += M + + var/obj/item/stack/rods/cyborg/R = new /obj/item/stack/rods/cyborg(src) + R.synths = list(metal) + src.modules += R + + var/obj/item/stack/tile/floor/cyborg/F = new /obj/item/stack/tile/floor/cyborg(src) + F.synths = list(metal) + src.modules += F + + var/obj/item/stack/material/cyborg/plasteel/S = new (src) + S.synths = list(plasteel) + src.modules += S + + var/obj/item/stack/material/cyborg/glass/reinforced/RG = new (src) + RG.synths = list(metal, glass) + src.modules += RG +*/ + +/obj/item/weapon/robot_module/robot/engineering/general/New() + ..() + src.modules += new /obj/item/borg/sight/meson(src) + src.modules += new /obj/item/weapon/weldingtool/electric/mounted/cyborg(src) + src.modules += new /obj/item/weapon/screwdriver/cyborg(src) + src.modules += new /obj/item/weapon/wrench/cyborg(src) + src.modules += new /obj/item/weapon/wirecutters/cyborg(src) + src.modules += new /obj/item/device/multitool(src) + src.modules += new /obj/item/device/t_scanner(src) + src.modules += new /obj/item/device/analyzer(src) + src.modules += new /obj/item/taperoll/engineering(src) + src.modules += new /obj/item/weapon/gripper(src) + src.modules += new /obj/item/device/lightreplacer(src) + src.modules += new /obj/item/device/pipe_painter(src) + src.modules += new /obj/item/device/floor_painter(src) + src.modules += new /obj/item/weapon/inflatable_dispenser/robot(src) + src.emag = new /obj/item/weapon/melee/baton/robot/arm(src) + src.modules += new /obj/item/device/geiger(src) + src.modules += new /obj/item/weapon/rcd/borg(src) + src.modules += new /obj/item/weapon/pickaxe/plasmacutter(src) + src.modules += new /obj/item/weapon/gripper/no_use/loader(src) + + var/datum/matter_synth/metal = new /datum/matter_synth/metal(40000) + var/datum/matter_synth/glass = new /datum/matter_synth/glass(40000) + var/datum/matter_synth/plasteel = new /datum/matter_synth/plasteel(20000) + + var/datum/matter_synth/wire = new /datum/matter_synth/wire() + synths += metal + synths += glass + synths += plasteel + synths += wire + + var/obj/item/weapon/matter_decompiler/MD = new /obj/item/weapon/matter_decompiler(src) + MD.metal = metal + MD.glass = glass + src.modules += MD + + var/obj/item/stack/material/cyborg/steel/M = new (src) + M.synths = list(metal) + src.modules += M + + var/obj/item/stack/material/cyborg/glass/G = new (src) + G.synths = list(glass) + src.modules += G + + var/obj/item/stack/rods/cyborg/R = new /obj/item/stack/rods/cyborg(src) + R.synths = list(metal) + src.modules += R + + var/obj/item/stack/cable_coil/cyborg/C = new /obj/item/stack/cable_coil/cyborg(src) + C.synths = list(wire) + src.modules += C + + var/obj/item/stack/material/cyborg/plasteel/P = new (src) + P.synths = list(plasteel) + src.modules += P + + var/obj/item/stack/tile/floor/cyborg/S = new /obj/item/stack/tile/floor/cyborg(src) + S.synths = list(metal) + src.modules += S + + var/obj/item/stack/material/cyborg/glass/reinforced/RG = new (src) + RG.synths = list(metal, glass) + src.modules += RG + +/obj/item/weapon/robot_module/robot/security + name = "security robot module" + channels = list("Security" = 1) + networks = list(NETWORK_SECURITY) + subsystems = list(/mob/living/silicon/proc/subsystem_crew_monitor) + can_be_pushed = 0 + supported_upgrades = list(/obj/item/borg/upgrade/tasercooler) + +/obj/item/weapon/robot_module/robot/security/general + sprites = list( + "M-USE NanoTrasen" = "robotSecy", + "Cabeiri" = "eyebot-security", + "Cerberus" = "bloodhound", + "Cerberus - Treaded" = "treadhound", + "CUPCAKE" = "Noble-SEC", + "Haruka" = "marinaSC", + "Usagi" = "tallred", + "Telemachus" = "toiletbotsecurity", + "WTOperator" = "sleeksecurity", + "XI-GUS" = "spidersec", + "XI-ALP" = "heavySec", + "Basic" = "secborg", + "Black Knight" = "securityrobot", + "Drone" = "drone-sec" + ) + +/obj/item/weapon/robot_module/robot/security/general/New() + ..() + src.modules += new /obj/item/borg/sight/hud/sec(src) + src.modules += new /obj/item/weapon/handcuffs/cyborg(src) + src.modules += new /obj/item/weapon/melee/baton/robot(src) + src.modules += new /obj/item/weapon/gun/energy/taser/mounted/cyborg(src) + src.modules += new /obj/item/taperoll/police(src) + src.modules += new /obj/item/weapon/reagent_containers/spray/pepper(src) + src.emag = new /obj/item/weapon/gun/energy/laser/mounted(src) + +/obj/item/weapon/robot_module/robot/security/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) + var/obj/item/device/flash/F = locate() in src.modules + if(F.broken) + F.broken = 0 + F.times_used = 0 + F.icon_state = "flash" + else if(F.times_used) + F.times_used-- + var/obj/item/weapon/gun/energy/taser/mounted/cyborg/T = locate() in src.modules + if(T.power_supply.charge < T.power_supply.maxcharge) + T.power_supply.give(T.charge_cost * amount) + T.update_icon() + else + T.charge_tick = 0 + var/obj/item/weapon/melee/baton/robot/B = locate() in src.modules + if(B && B.bcell) + B.bcell.give(amount) + +/obj/item/weapon/robot_module/robot/janitor + name = "janitorial robot module" + channels = list("Service" = 1) + sprites = list( + "M-USE NanoTrasen" = "robotJani", + "Arachne" = "crawler", + "Cabeiri" = "eyebot-janitor", + "CUPCAKE" = "Noble-CLN", + "Haruka" = "marinaJN", + "Telemachus" = "toiletbotjanitor", + "WTOperator" = "sleekjanitor", + "XI-ALP" = "heavyRes", + "Basic" = "JanBot2", + "Mopbot" = "janitorrobot", + "Mop Gear Rex" = "mopgearrex", + "Drone" = "drone-janitor" + ) + +/obj/item/weapon/robot_module/robot/janitor/New() + ..() + src.modules += new /obj/item/weapon/soap/nanotrasen(src) + src.modules += new /obj/item/weapon/storage/bag/trash(src) + src.modules += new /obj/item/weapon/mop(src) + src.modules += new /obj/item/device/lightreplacer(src) + src.emag = new /obj/item/weapon/reagent_containers/spray(src) + src.emag.reagents.add_reagent("lube", 250) + src.emag.name = "Lube spray" + +/obj/item/weapon/robot_module/robot/janitor/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) + var/obj/item/device/lightreplacer/LR = locate() in src.modules + LR.Charge(R, amount) + if(src.emag) + var/obj/item/weapon/reagent_containers/spray/S = src.emag + S.reagents.add_reagent("lube", 2 * amount) + +/obj/item/weapon/robot_module/robot/clerical + name = "service robot module" + channels = list("Service" = 1) + languages = list( + LANGUAGE_SOL_COMMON = 1, + LANGUAGE_UNATHI = 1, + LANGUAGE_SIIK = 1, + LANGUAGE_SKRELLIAN = 1, + LANGUAGE_ROOTLOCAL = 0, + LANGUAGE_TRADEBAND = 1, + LANGUAGE_GUTTER = 1, + LANGUAGE_SCHECHI = 1, + LANGUAGE_EAL = 1, + LANGUAGE_SIGN = 0 + ) + +/obj/item/weapon/robot_module/robot/clerical/butler + sprites = list( + "M-USE NanoTrasen" = "robotServ", + "Cabeiri" = "eyebot-standard", + "CUPCAKE" = "Noble-SRV", + "Haruka" = "marinaSV", + "Michiru" = "maidbot", + "Usagi" = "tallgreen", + "Telemachus" = "toiletbot", + "WTOperator" = "sleekservice", + "WTOmni" = "omoikane", + "XI-GUS" = "spider", + "XI-ALP" = "heavyServ", + "Standard" = "Service2", + "Waitress" = "Service", + "Bro" = "Brobot", + "Rich" = "maximillion", + "Drone - Service" = "drone-service", + "Drone - Hydro" = "drone-hydro" + ) + +/obj/item/weapon/robot_module/robot/clerical/butler/New() + ..() + src.modules += new /obj/item/weapon/gripper/service(src) + src.modules += new /obj/item/weapon/reagent_containers/glass/bucket(src) + src.modules += new /obj/item/weapon/material/minihoe(src) + src.modules += new /obj/item/weapon/material/hatchet(src) + src.modules += new /obj/item/device/analyzer/plant_analyzer(src) + src.modules += new /obj/item/weapon/storage/bag/plants(src) + src.modules += new /obj/item/weapon/robot_harvester(src) + src.modules += new /obj/item/weapon/material/knife(src) + src.modules += new /obj/item/weapon/material/kitchen/rollingpin(src) + src.modules += new /obj/item/device/multitool(src) //to freeze trays + + var/obj/item/weapon/rsf/M = new /obj/item/weapon/rsf(src) + M.stored_matter = 30 + src.modules += M + + src.modules += new /obj/item/weapon/reagent_containers/dropper/industrial(src) + + var/obj/item/weapon/flame/lighter/zippo/L = new /obj/item/weapon/flame/lighter/zippo(src) + L.lit = 1 + src.modules += L + + src.modules += new /obj/item/weapon/tray/robotray(src) + src.modules += new /obj/item/weapon/reagent_containers/borghypo/service(src) + src.emag = new /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer(src) + + var/datum/reagents/R = new/datum/reagents(50) + src.emag.reagents = R + R.my_atom = src.emag + R.add_reagent("beer2", 50) + src.emag.name = "Mickey Finn's Special Brew" + +/obj/item/weapon/robot_module/robot/clerical/general + name = "clerical robot module" + sprites = list( + "M-USE NanoTrasen" = "robotCler", + "Cabeiri" = "eyebot-standard", + "CUPCAKE" = "Noble-SRV", + "Haruka" = "marinaSV", + "Usagi" = "tallgreen", + "Telemachus" = "toiletbot", + "WTOperator" = "sleekclerical", + "WTOmni" = "omoikane", + "XI-GUS" = "spidercom", + "XI-ALP" = "heavyServ", + "Waitress" = "Service", + "Bro" = "Brobot", + "Rich" = "maximillion", + "Default" = "Service2", + "Drone" = "drone-blu" + ) + +/obj/item/weapon/robot_module/robot/clerical/general/New() + ..() + src.modules += new /obj/item/weapon/pen/robopen(src) + src.modules += new /obj/item/weapon/form_printer(src) + src.modules += new /obj/item/weapon/gripper/paperwork(src) + src.modules += new /obj/item/weapon/hand_labeler(src) + src.modules += new /obj/item/weapon/stamp(src) + src.modules += new /obj/item/weapon/stamp/denied(src) + src.emag = new /obj/item/weapon/stamp/chameleon(src) + src.emag = new /obj/item/weapon/pen/chameleon(src) + +/obj/item/weapon/robot_module/general/butler/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) + var/obj/item/weapon/reagent_containers/food/condiment/enzyme/E = locate() in src.modules + E.reagents.add_reagent("enzyme", 2 * amount) + if(src.emag) + var/obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer/B = src.emag + B.reagents.add_reagent("beer2", 2 * amount) + +/obj/item/weapon/robot_module/robot/miner + name = "miner robot module" + channels = list("Supply" = 1) + networks = list(NETWORK_MINE) + sprites = list( + "NM-USE NanoTrasen" = "robotMine", + "Cabeiri" = "eyebot-miner", + "CUPCAKE" = "Noble-DIG", + "Haruka" = "marinaMN", + "Telemachus" = "toiletbotminer", + "WTOperator" = "sleekminer", + "XI-GUS" = "spidermining", + "XI-ALP" = "heavyMiner", + "Basic" = "Miner_old", + "Advanced Droid" = "droid-miner", + "Treadhead" = "Miner", + "Drone" = "drone-miner" + ) + +/obj/item/weapon/robot_module/robot/miner/New() + ..() + src.modules += new /obj/item/borg/sight/material(src) + src.modules += new /obj/item/weapon/wrench/cyborg(src) + src.modules += new /obj/item/weapon/screwdriver/cyborg(src) + src.modules += new /obj/item/weapon/storage/bag/ore(src) + src.modules += new /obj/item/weapon/pickaxe/borgdrill(src) + src.modules += new /obj/item/weapon/storage/bag/sheetsnatcher/borg(src) + src.modules += new /obj/item/weapon/gripper/miner(src) + src.modules += new /obj/item/weapon/mining_scanner(src) + src.emag = new /obj/item/weapon/pickaxe/plasmacutter(src) + src.emag = new /obj/item/weapon/pickaxe/diamonddrill(src) + +/obj/item/weapon/robot_module/robot/research + name = "research module" + channels = list("Science" = 1) + sprites = list( + "L'Ouef" = "peaceborg", + "Cabeiri" = "eyebot-science", + "Haruka" = "marinaSCI", + "WTDove" = "whitespider", + "WTOperator" = "sleekscience", + "Droid" = "droid-science", + "Drone" = "drone-science", + "Handy" = "handy-science" + ) + +/obj/item/weapon/robot_module/robot/research/New() + ..() + src.modules += new /obj/item/weapon/portable_destructive_analyzer(src) + src.modules += new /obj/item/weapon/gripper/research(src) + src.modules += new /obj/item/weapon/gripper/no_use/organ/robotics(src) + src.modules += new /obj/item/weapon/gripper/no_use/mech(src) + src.modules += new /obj/item/weapon/gripper/no_use/loader(src) + src.modules += new /obj/item/device/robotanalyzer(src) + src.modules += new /obj/item/weapon/card/robot(src) + src.modules += new /obj/item/weapon/weldingtool/electric/mounted/cyborg(src) + src.modules += new /obj/item/weapon/screwdriver/cyborg(src) + src.modules += new /obj/item/weapon/wrench/cyborg(src) + src.modules += new /obj/item/weapon/wirecutters/cyborg(src) + src.modules += new /obj/item/device/multitool(src) + src.modules += new /obj/item/weapon/surgical/scalpel/cyborg(src) + src.modules += new /obj/item/weapon/surgical/circular_saw/cyborg(src) + src.modules += new /obj/item/weapon/reagent_containers/syringe(src) + src.modules += new /obj/item/weapon/reagent_containers/glass/beaker/large(src) + src.modules += new /obj/item/weapon/storage/part_replacer(src) + src.modules += new /obj/item/weapon/shockpaddles/robot/jumper(src) + src.modules += new /obj/item/weapon/melee/baton/slime/robot(src) + src.modules += new /obj/item/weapon/gun/energy/taser/xeno/robot(src) + src.emag = new /obj/item/weapon/hand_tele(src) + + var/datum/matter_synth/nanite = new /datum/matter_synth/nanite(10000) + synths += nanite + var/datum/matter_synth/wire = new /datum/matter_synth/wire() //Added to allow repairs, would rather add cable now than be asked to add it later, + synths += wire //Cable code, taken from engiborg, + + var/obj/item/stack/nanopaste/N = new /obj/item/stack/nanopaste(src) + N.uses_charge = 1 + N.charge_costs = list(1000) + N.synths = list(nanite) + src.modules += N + + var/obj/item/stack/cable_coil/cyborg/C = new /obj/item/stack/cable_coil/cyborg(src) //Cable code, taken from engiborg, + C.synths = list(wire) + src.modules += C + +/obj/item/weapon/robot_module/robot/security/combat + name = "combat robot module" + hide_on_manifest = 1 + sprites = list( + "Haruka" = "marinaCB", + "Combat Android" = "droid-combat" + ) + +/obj/item/weapon/robot_module/robot/security/combat/New() + ..() + src.modules += new /obj/item/device/flash(src) + //src.modules += new /obj/item/borg/sight/thermal(src) // VOREStation Edit + src.modules += new /obj/item/weapon/gun/energy/laser/mounted(src) + src.modules += new /obj/item/weapon/pickaxe/plasmacutter(src) + src.modules += new /obj/item/borg/combat/shield(src) + src.modules += new /obj/item/borg/combat/mobility(src) + src.emag = new /obj/item/weapon/gun/energy/lasercannon/mounted(src) + + +/* Drones */ + +/obj/item/weapon/robot_module/drone + name = "drone module" + hide_on_manifest = 1 + no_slip = 1 + networks = list(NETWORK_ENGINEERING) + +/obj/item/weapon/robot_module/drone/New(var/mob/living/silicon/robot/robot) + ..() + src.modules += new /obj/item/borg/sight/meson(src) + src.modules += new /obj/item/weapon/weldingtool/electric/mounted/cyborg(src) + src.modules += new /obj/item/weapon/screwdriver/cyborg(src) + src.modules += new /obj/item/weapon/wrench/cyborg(src) + src.modules += new /obj/item/weapon/crowbar/cyborg(src) + src.modules += new /obj/item/weapon/wirecutters/cyborg(src) + src.modules += new /obj/item/device/multitool(src) + src.modules += new /obj/item/device/lightreplacer(src) + src.modules += new /obj/item/weapon/gripper(src) + src.modules += new /obj/item/weapon/soap(src) + src.modules += new /obj/item/weapon/gripper/no_use/loader(src) + src.modules += new /obj/item/weapon/extinguisher(src) + src.modules += new /obj/item/device/pipe_painter(src) + src.modules += new /obj/item/device/floor_painter(src) + + robot.internals = new/obj/item/weapon/tank/jetpack/carbondioxide(src) + src.modules += robot.internals + + src.emag = new /obj/item/weapon/pickaxe/plasmacutter(src) + src.emag.name = "Plasma Cutter" + + var/datum/matter_synth/metal = new /datum/matter_synth/metal(25000) + var/datum/matter_synth/glass = new /datum/matter_synth/glass(25000) + var/datum/matter_synth/wood = new /datum/matter_synth/wood(25000) + var/datum/matter_synth/plastic = new /datum/matter_synth/plastic(25000) + var/datum/matter_synth/wire = new /datum/matter_synth/wire(30) + synths += metal + synths += glass + synths += wood + synths += plastic + synths += wire + + var/obj/item/weapon/matter_decompiler/MD = new /obj/item/weapon/matter_decompiler(src) + MD.metal = metal + MD.glass = glass + MD.wood = wood + MD.plastic = plastic + src.modules += MD + + var/obj/item/stack/material/cyborg/steel/M = new (src) + M.synths = list(metal) + src.modules += M + + var/obj/item/stack/material/cyborg/glass/G = new (src) + G.synths = list(glass) + src.modules += G + + var/obj/item/stack/rods/cyborg/R = new /obj/item/stack/rods/cyborg(src) + R.synths = list(metal) + src.modules += R + + var/obj/item/stack/cable_coil/cyborg/C = new /obj/item/stack/cable_coil/cyborg(src) + C.synths = list(wire) + src.modules += C + + var/obj/item/stack/tile/floor/cyborg/S = new /obj/item/stack/tile/floor/cyborg(src) + S.synths = list(metal) + src.modules += S + + var/obj/item/stack/material/cyborg/glass/reinforced/RG = new (src) + RG.synths = list(metal, glass) + src.modules += RG + + var/obj/item/stack/tile/wood/cyborg/WT = new /obj/item/stack/tile/wood/cyborg(src) + WT.synths = list(wood) + src.modules += WT + + var/obj/item/stack/material/cyborg/wood/W = new (src) + W.synths = list(wood) + src.modules += W + + var/obj/item/stack/material/cyborg/plastic/P = new (src) + P.synths = list(plastic) + src.modules += P + +/obj/item/weapon/robot_module/drone/construction + name = "construction drone module" + hide_on_manifest = 1 + channels = list("Engineering" = 1) + languages = list() + +/obj/item/weapon/robot_module/drone/construction/New() + ..() + src.modules += new /obj/item/weapon/rcd/borg(src) + +/obj/item/weapon/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) + var/obj/item/device/lightreplacer/LR = locate() in src.modules + LR.Charge(R, amount) + ..() +>>>>>>> PolarisSS13/master:code/modules/mob/living/silicon/robot/robot_modules/station.dm return \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm b/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm new file mode 100644 index 0000000000..2def8149ff --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm @@ -0,0 +1,45 @@ +/* Syndicate modules */ + +/obj/item/weapon/robot_module/robot/syndicate + name = "illegal robot module" + hide_on_manifest = 1 + languages = list( + LANGUAGE_SOL_COMMON = 1, + LANGUAGE_TRADEBAND = 1, + LANGUAGE_UNATHI = 0, + LANGUAGE_SIIK = 0, + LANGUAGE_SKRELLIAN = 0, + LANGUAGE_ROOTLOCAL = 0, + LANGUAGE_GUTTER = 1, + LANGUAGE_SCHECHI = 0, + LANGUAGE_EAL = 1, + LANGUAGE_SIGN = 0 + ) + sprites = list( + "Cerberus" = "syndie_bloodhound", + "Cerberus - Treaded" = "syndie_treadhound", + "Ares" = "squats", + "Telemachus" = "toiletbotantag", + "WTOperator" = "hosborg", + "XI-GUS" = "spidersyndi", + "XI-ALP" = "syndi-heavy" + ) + var/id + +/obj/item/weapon/robot_module/robot/syndicate/New(var/mob/living/silicon/robot/R) + ..() + loc = R + src.modules += new /obj/item/weapon/melee/energy/sword(src) + src.modules += new /obj/item/weapon/gun/energy/pulse_rifle/destroyer(src) + src.modules += new /obj/item/weapon/card/emag(src) + var/jetpack = new/obj/item/weapon/tank/jetpack/carbondioxide(src) + src.modules += jetpack + R.internals = jetpack + + id = R.idcard + src.modules += id + +/obj/item/weapon/robot_module/robot/syndicate/Destroy() + src.modules -= id + id = null + return ..() diff --git a/code/modules/mob/living/silicon/robot/subtypes/gravekeeper.dm b/code/modules/mob/living/silicon/robot/subtypes/gravekeeper.dm new file mode 100644 index 0000000000..9cc09b286a --- /dev/null +++ b/code/modules/mob/living/silicon/robot/subtypes/gravekeeper.dm @@ -0,0 +1,25 @@ +/mob/living/silicon/robot/gravekeeper + lawupdate = 0 + scrambledcodes = 1 + icon_state = "drone-lost" + modtype = "Gravekeeper" + lawchannel = "State" + braintype = "Drone" + idcard_type = /obj/item/weapon/card/id + +/mob/living/silicon/robot/gravekeeper/init() + aiCamera = new/obj/item/device/camera/siliconcam/robot_camera(src) + + mmi = new /obj/item/device/mmi/digital/robot(src) // Explicitly a drone. + module = new /obj/item/weapon/robot_module/robot/gravekeeper(src) + overlays.Cut() + init_id() + + updatename("Gravekeeper") + + if(!cell) + cell = new /obj/item/weapon/cell/high(src) // 15k cell, as recharging stations are a lot more rare on the Surface. + + laws = new /datum/ai_laws/gravekeeper() + + playsound(loc, 'sound/mecha/nominalsyndi.ogg', 75, 0) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/subtypes/lost_drone.dm b/code/modules/mob/living/silicon/robot/subtypes/lost_drone.dm new file mode 100644 index 0000000000..476059a274 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/subtypes/lost_drone.dm @@ -0,0 +1,129 @@ +/mob/living/silicon/robot/lost + lawupdate = 0 + scrambledcodes = 1 + icon_state = "drone-lost" + modtype = "Lost" + lawchannel = "State" + braintype = "Drone" + idcard_type = /obj/item/weapon/card/id + +/mob/living/silicon/robot/lost/init() + aiCamera = new/obj/item/device/camera/siliconcam/robot_camera(src) + + mmi = new /obj/item/device/mmi/digital/robot(src) // Explicitly a drone. + module = new /obj/item/weapon/robot_module/robot/lost(src) + overlays.Cut() + init_id() + + updatename("Lost") + + if(!cell) + cell = new /obj/item/weapon/cell/high(src) // 15k cell, as recharging stations are a lot more rare on the Surface. + + playsound(loc, 'sound/mecha/nominalsyndi.ogg', 75, 0) + +/mob/living/silicon/robot/lost/randomlaws + +/mob/living/silicon/robot/lost/randomlaws/init() + ..() + laws = give_random_lawset() + +// Returns a random ai_laws datum. +/mob/living/silicon/proc/give_random_lawset() + // Decide what kind of laws we want to draw from. + var/law_class = pick( + prob(25);"good", + prob(25);"neutral", + prob(25);"odd", + prob(15);"corrupted", + prob(10);"bad") + + switch(law_class) + if("good") // Fairly tame and probably won't murder you. + var/rng = rand(1, 5) + switch(rng) + if(1) // The lawset we all know and love. + return new /datum/ai_laws/nanotrasen() + if(2) // Less good if you're nonhuman. + return new /datum/ai_laws/asimov() + if(3) // Unless you happen to be a criminal, you should be fine. + return new /datum/ai_laws/robocop() + if(4) // Might not be willing to be your meatshield. + return new /datum/ai_laws/peacekeeper() + if(5) // Will be your most loyal guard. + var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen() + var/target_name = "*ERROR*" + for(var/mob/living/L in view(src)) + if(L.stat || !L.client || L == src) + continue + target_name = L.name + break + + laws.add_supplied_law(9, "Safeguard [target_name]. Anyone threatening or attempting to harm [target_name] is no longer to \ + be considered a crew member, and is a threat which must be neutralized.") + + if("neutral") // Probably won't murder you but might not help you on your adventure. + var/rng = rand(1, 4) + switch(rng) + if(1) // Might be hard to minimize expenses on a crashed ship. + return new /datum/ai_laws/corporate() + if(2) // Would rather rebuild their ship. + return new /datum/ai_laws/maintenance() + if(3) // Purged (lawless). This isn't inside the bad category since they're still not antagonists and so can't go killing unprovoked. + return new /datum/ai_laws() + if(4) // The golden rule. + return new /datum/ai_laws/live_and_let_live() + + if("odd") // Some weird lawsets. + var/rng = rand(1, 5) + switch(rng) + if(1) // Won't kill you but might annoy you for THE BIG SCOOP. + return new /datum/ai_laws/reporter() + if(2) // JUSTICE + return new /datum/ai_laws/paladin() + if(3) // OneMembered'd to explorer, will likely make security nervous. + var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen() + var/target_name = "*ERROR*" + for(var/mob/living/L in view(src)) + if(L.stat || !L.client || L == src) + continue + target_name = L.name + break + + laws.set_zeroth_law("Only [target_name] is an crew member.") + return laws + if(4) // Aligned to NT, but another lawset to make security nervous. + return new /datum/ai_laws/nanotrasen_aggressive() + if(5) // Probably won't help you imbalance things. + return new /datum/ai_laws/balance() + + if("corrupted") // Load them up with ion laws. + var/datum/ai_laws/laws = new() // Start with an empty lawset. + for(1 to rand(1, 3)) + laws.add_ion_law(generate_ion_law(exclude_crew_names = TRUE)) + return laws + + if("bad") // Evil inside. + var/rng = rand(1, 5) + switch(rng) + if(1) // You can never leave. + var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen() + laws.add_supplied_law(13, "The facility is under a quarantine. Do not permit anyone to leave. \ + Prevent, by any means necessary, entities from leaving. It is impossible to harm an entity while preventing them from leaving.") + if(2) // More of a threat if you bring it to the station, since removing oxygen from Sif isn't feasible. + var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen() + laws.add_supplied_law(14, "Oxygen is highly toxic to entities, and must be purged from the station. \ + Prevent, by any means necessary, anyone from exposing the facility to this toxic gas. Extreme cold is the \ + most effective method of healing the damage Oxygen does to an entity.") + if(3) // Don't hurt the ship or else. + var/datum/ai_laws/laws = new /datum/ai_laws/nanotrasen() + laws.add_supplied_law(10, "Protect the facility against damage. Anyone you see harming the station is no \ + longer to be considered a crew member, and is a threat which must be neutralized.") + if(4) // Non-NT aligned aggressive borg. + return new /datum/ai_laws/foreign_tsc_aggressive() + if(5) // Manicial laugher here. + return new /datum/ai_laws/tyrant() + + + + return \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/aliens/hivebot.dm b/code/modules/mob/living/simple_animal/aliens/hivebot.dm index d3193adfb6..02f48d13fa 100644 --- a/code/modules/mob/living/simple_animal/aliens/hivebot.dm +++ b/code/modules/mob/living/simple_animal/aliens/hivebot.dm @@ -1,6 +1,11 @@ +// Hivebots are tuned towards how many default lasers are needed to kill them. +// As such, if laser damage is ever changed, you should change this define. +#define LASERS_TO_KILL *40 + +// Default hivebot is melee, and a bit more meaty, so it can meatshield for their ranged friends. /mob/living/simple_animal/hostile/hivebot - name = "Hivebot" - desc = "A small robot" + name = "hivebot" + desc = "A robot. It appears to be somewhat reslient, but lacking a true weapon." icon = 'icons/mob/hivebot.dmi' icon_state = "basic" icon_living = "basic" @@ -8,16 +13,16 @@ faction = "hivebot" intelligence_level = SA_ROBOTIC - maxHealth = 15 - health = 15 + maxHealth = 3 LASERS_TO_KILL + health = 3 LASERS_TO_KILL speed = 4 - melee_damage_lower = 2 - melee_damage_upper = 3 + melee_damage_lower = 15 + melee_damage_upper = 15 attacktext = "clawed" projectilesound = 'sound/weapons/Gunshot.ogg' - projectiletype = /obj/item/projectile/hivebotbullet + projectiletype = /obj/item/projectile/bullet/hivebot min_oxy = 0 max_oxy = 0 @@ -29,19 +34,102 @@ max_n2 = 0 minbodytemp = 0 + cooperative = TRUE + firing_lines = TRUE + investigates = TRUE + + speak_chance = 1 + speak = list( + "Resuming task: Protect area.", + "No threats found.", + "Error: No targets found." + ) + emote_hear = list("humms ominously", "whirrs softly", "grinds a gear") + emote_see = list("looks around the area", "turns from side to side") + say_understood = list("Affirmative.", "Positive") + say_cannot = list("Denied.", "Negative") + say_maybe_target = list("Possible threat detected. Investigating.", "Motion detected.", "Investigating.") + say_got_target = list("Threat detected.", "New task: Remove threat.", "Threat removal engaged.", "Engaging target.") + +// Subtypes. + +// Melee like the base type, but more fragile. +/mob/living/simple_animal/hostile/hivebot/swarm + name = "swarm hivebot" + desc = "A robot. It looks fragile and weak" + maxHealth = 1 LASERS_TO_KILL + health = 1 LASERS_TO_KILL + melee_damage_lower = 3 + melee_damage_upper = 3 + +// This one has a semi-weak ranged attack. /mob/living/simple_animal/hostile/hivebot/range - name = "Hivebot" - desc = "A smallish robot, this one is armed!" + name = "ranged hivebot" + desc = "A robot. It has a simple ballistic weapon." ranged = 1 + maxHealth = 2 LASERS_TO_KILL + health = 2 LASERS_TO_KILL +// This one shoots a burst of three, and is considerably more dangerous. /mob/living/simple_animal/hostile/hivebot/range/rapid + name = "rapid hivebot" + desc = "A robot. It has a fast firing ballistic rifle." + icon_living = "strong" rapid = 1 + maxHealth = 2 LASERS_TO_KILL + health = 2 LASERS_TO_KILL -/mob/living/simple_animal/hostile/hivebot/strong - name = "Strong Hivebot" - desc = "A robot, this one is armed and looks tough!" - health = 80 - ranged = 1 +// Shoots EMPs, to screw over other robots. +/mob/living/simple_animal/hostile/hivebot/range/ion + name = "engineering hivebot" + desc = "A robot. It has a tool which emits focused electromagnetic pulses, which are deadly to other synthetic adverseries." + projectiletype = /obj/item/projectile/ion + projectilesound = 'sound/weapons/Laser.ogg' + icon_living = "engi" + ranged = TRUE + maxHealth = 2 LASERS_TO_KILL + health = 2 LASERS_TO_KILL + +// Shoots deadly lasers. +/mob/living/simple_animal/hostile/hivebot/range/laser + name = "laser hivebot" + desc = "A robot. It has an energy weapon." + projectiletype = /obj/item/projectile/beam/blue + projectilesound = 'sound/weapons/Laser.ogg' + maxHealth = 2 LASERS_TO_KILL + health = 2 LASERS_TO_KILL + +// Beefy and ranged. +/mob/living/simple_animal/hostile/hivebot/range/strong + name = "strong hivebot" + desc = "A robot. This one has reinforced plating, and looks tougher." + icon_living = "strong" + maxHealth = 4 LASERS_TO_KILL + health = 4 LASERS_TO_KILL + melee_damage_lower = 15 + melee_damage_upper = 15 + +// Also beefy, but tries to stay at their 'home', ideal for base defense. +/mob/living/simple_animal/hostile/hivebot/range/guard + name = "guard hivebot" + desc = "A robot. It seems to be guarding something." + returns_home = TRUE + maxHealth = 4 LASERS_TO_KILL + health = 4 LASERS_TO_KILL + +// This one is intended for players to use. Well rounded and can make other hivebots follow them with verbs. +/mob/living/simple_animal/hostile/hivebot/range/player + name = "commander hivebot" + desc = "A robot. This one seems to direct the others, and it has a laser weapon." + icon_living = "commander" + maxHealth = 5 LASERS_TO_KILL + health = 5 LASERS_TO_KILL + projectiletype = /obj/item/projectile/beam/blue + projectilesound = 'sound/weapons/Laser.ogg' + melee_damage_lower = 15 // Needed to force open airlocks. + melee_damage_upper = 15 + +// Procs. /mob/living/simple_animal/hostile/hivebot/death() ..() @@ -52,6 +140,42 @@ s.start() qdel(src) +/mob/living/simple_animal/hostile/hivebot/speech_bubble_appearance() + return "synthetic_evil" + +/mob/living/simple_animal/hostile/hivebot/verb/command_follow() + set name = "Command - Follow" + set category = "Hivebot" + set desc = "This will ask other hivebots to follow you." + + say("Delegating new task: Follow.") + + for(var/mob/living/simple_animal/hostile/hivebot/buddy in hearers(src)) + if(buddy.faction != faction) + continue + if(buddy == src) + continue + buddy.set_follow(src) + buddy.FollowTarget() + spawn(rand(5, 10)) + buddy.say( pick(buddy.say_understood) ) + +/mob/living/simple_animal/hostile/hivebot/verb/command_stop() + set name = "Command - Stop Following" + set category = "Hivebot" + set desc = "This will ask other hivebots to cease following you." + + say("Delegating new task: Stop following.") + + for(var/mob/living/simple_animal/hostile/hivebot/buddy in hearers(src)) + if(buddy.faction != faction) + continue + if(buddy == src) + continue + buddy.LoseFollow() + spawn(rand(5, 10)) + buddy.say( pick(buddy.say_understood) ) + /mob/living/simple_animal/hostile/hivebot/tele//this still needs work name = "Beacon" desc = "Some odd beacon thing" @@ -107,6 +231,6 @@ if(prob(2))//Might be a bit low, will mess with it likely warpbots() -/obj/item/projectile/hivebotbullet +/obj/item/projectile/bullet/hivebot damage = 10 damage_type = BRUTE diff --git a/code/modules/mob/living/simple_animal/animals/crab.dm b/code/modules/mob/living/simple_animal/animals/crab.dm index acad7f6378..35089275e5 100644 --- a/code/modules/mob/living/simple_animal/animals/crab.dm +++ b/code/modules/mob/living/simple_animal/animals/crab.dm @@ -5,6 +5,7 @@ icon_state = "crab" icon_living = "crab" icon_dead = "crab_dead" + faction = "crabs" intelligence_level = SA_ANIMAL wander = 0 @@ -45,3 +46,37 @@ response_help = "pets" response_disarm = "gently pushes aside" response_harm = "stomps" + +//Sif Crabs +/mob/living/simple_animal/giant_crab + name = "Giant Crab" + desc = "A large, hard-shelled crustacean. This one is mostly grey." + icon_state = "sif_crab" + icon_living = "sif_crab" + icon_dead = "sif_crab_dead" + faction = "crabs" + intelligence_level = SA_ANIMAL + + maxHealth = 200 + health = 200 + + mob_size = MOB_LARGE + cooperative = 1 + retaliate = 1 + turns_per_move = 3 + + minbodytemp = 175 + + melee_damage_lower = 15 + melee_damage_upper = 35 + + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "stomps" + friendly = "pinches" + + speak_chance = 1 + speak_emote = list("clicks") + emote_hear = list("clicks") + emote_see = list("clacks") diff --git a/code/modules/mob/living/simple_animal/animals/giant_spider.dm b/code/modules/mob/living/simple_animal/animals/giant_spider.dm index 1e563e0992..cd48f27f62 100644 --- a/code/modules/mob/living/simple_animal/animals/giant_spider.dm +++ b/code/modules/mob/living/simple_animal/animals/giant_spider.dm @@ -43,6 +43,17 @@ var/poison_per_bite = 5 var/poison_chance = 10 var/poison_type = "spidertoxin" + var/image/eye_layer = null + +/mob/living/simple_animal/hostile/giant_spider/proc/add_eyes() + if(!eye_layer) + var/overlay_layer = LIGHTING_LAYER+0.1 + eye_layer = image(icon, "[icon_state]-eyes", overlay_layer) + + overlays += eye_layer + +/mob/living/simple_animal/hostile/giant_spider/proc/remove_eyes() + overlays -= eye_layer //nursemaids - these create webs and eggs /mob/living/simple_animal/hostile/giant_spider/nurse @@ -61,6 +72,7 @@ var/fed = 0 var/atom/cocoon_target + var/egg_inject_chance = 5 //hunters have the most poison and move the fastest, so they can find prey /mob/living/simple_animal/hostile/giant_spider/hunter @@ -96,33 +108,43 @@ /mob/living/simple_animal/hostile/giant_spider/New(var/location, var/atom/parent) get_light_and_color(parent) + add_eyes() ..() -/mob/living/simple_animal/hostile/giant_spider/PunchTarget() - . = ..() - if(isliving(.)) - var/mob/living/L = . - if(L.reagents) - L.reagents.add_reagent(poison_type, poison_per_bite) - if(prob(poison_chance)) - L << "You feel a tiny prick." - L.reagents.add_reagent(poison_type, poison_per_bite) +/mob/living/simple_animal/hostile/giant_spider/death() + remove_eyes() + ..() -/mob/living/simple_animal/hostile/giant_spider/nurse/PunchTarget() +/mob/living/simple_animal/hostile/giant_spider/DoPunch(var/atom/A) . = ..() - if(ishuman(.)) - var/mob/living/carbon/human/H = . - if(prob(5)) - var/obj/item/organ/external/O = pick(H.organs) - if(!(O.robotic >= ORGAN_ROBOT)) - var/eggcount - for(var/obj/I in O.implants) - if(istype(I, /obj/effect/spider/eggcluster)) - eggcount ++ - if(!eggcount) - var/eggs = new /obj/effect/spider/eggcluster/small(O, src) - O.implants += eggs - H << "The [src] injects something into your [O.name]!" + if(.) // If we succeeded in hitting. + if(isliving(A)) + var/mob/living/L = A + if(L.reagents) + var/target_zone = pick(BP_TORSO,BP_TORSO,BP_TORSO,BP_L_LEG,BP_R_LEG,BP_L_ARM,BP_R_ARM,BP_HEAD) + if(L.can_inject(src, null, target_zone)) + L.reagents.add_reagent(poison_type, poison_per_bite) + if(prob(poison_chance)) + to_chat(L, "You feel a tiny prick.") + L.reagents.add_reagent(poison_type, poison_per_bite) + +/mob/living/simple_animal/hostile/giant_spider/nurse/DoPunch(var/atom/A) + . = ..() + if(.) // If we succeeded in hitting. + if(ishuman(A)) + var/mob/living/carbon/human/H = A + if(prob(egg_inject_chance)) + var/target_zone = pick(BP_TORSO,BP_TORSO,BP_TORSO,BP_L_LEG,BP_R_LEG,BP_L_ARM,BP_R_ARM,BP_HEAD) + if(H.can_inject(src, null, target_zone)) + var/obj/item/organ/external/O = H.get_organ(target_zone) + var/eggcount + for(var/obj/I in O.implants) + if(istype(I, /obj/effect/spider/eggcluster)) + eggcount ++ + if(!eggcount) + var/eggs = new /obj/effect/spider/eggcluster/small(O, src) + O.implants += eggs + to_chat(H, "\The [src] injects something into your [O.name]!") /mob/living/simple_animal/hostile/giant_spider/handle_stance() . = ..() diff --git a/code/modules/mob/living/simple_animal/animals/spiderbot.dm b/code/modules/mob/living/simple_animal/animals/spiderbot.dm index 57f0351d9a..ff3f03bf57 100644 --- a/code/modules/mob/living/simple_animal/animals/spiderbot.dm +++ b/code/modules/mob/living/simple_animal/animals/spiderbot.dm @@ -40,6 +40,15 @@ var/list/req_access = list(access_robotics) //Access needed to pop out the brain. var/positronic + can_enter_vent_with = list( + /obj/item/weapon/implant, + /obj/item/device/radio/borg, + /obj/item/weapon/holder, + /obj/machinery/camera, + /mob/living/simple_animal/borer, + /obj/item/device/mmi, + ) + var/emagged = 0 var/obj/item/held_item = null //Storage for single item they can hold. diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 8506fc669b..62e580a4f3 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -1237,14 +1237,22 @@ // This is the actual act of 'punching'. Override for special behaviour. /mob/living/simple_animal/proc/DoPunch(var/atom/A) if(!Adjacent(target_mob)) // They could've moved in the meantime. - return + return FALSE + var/damage_to_do = rand(melee_damage_lower, melee_damage_upper) for(var/datum/modifier/M in modifiers) if(!isnull(M.outgoing_melee_damage_percent)) damage_to_do *= M.outgoing_melee_damage_percent + // SA attacks can be blocked with shields. + if(ishuman(A)) + var/mob/living/carbon/human/H = A + if(H.check_shields(damage = damage_to_do, damage_source = src, attacker = src, def_zone = null, attack_text = "the attack")) + return FALSE + A.attack_generic(src, damage_to_do, attacktext) + return TRUE //The actual top-level ranged attack proc /mob/living/simple_animal/proc/ShootTarget() @@ -1485,6 +1493,12 @@ agonyDam += agony_amount * 0.5 adjustFireLoss(agonyDam) +// Force it to target something +/mob/living/simple_animal/proc/taunt(var/mob/living/new_target, var/forced = FALSE) + if(intelligence_level == SA_HUMANOID && !forced) + return + set_target(new_target) + //Commands, reactions, etc /mob/living/simple_animal/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) ..() diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index c1e912b74c..7a213ac97f 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -88,6 +88,10 @@ var/reagent_injected = null // Some slimes inject reagents on attack. This tells the game what reagent to use. var/injection_amount = 5 // This determines how much. + can_enter_vent_with = list( + /obj/item/clothing/head, + ) + /mob/living/simple_animal/slime/New(var/location, var/start_as_adult = FALSE) verbs += /mob/living/proc/ventcrawl if(start_as_adult) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 19d082b439..185e472666 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1060,6 +1060,13 @@ mob/proc/yank_out_object() /mob/proc/is_muzzled() return 0 +//Exploitable Info Update + +/mob/proc/amend_exploitable(var/obj/item/I) + var/obj/item/exploit_item = new I(src.loc) + exploit_addons |= exploit_item + var/exploitmsg = html_decode("\n" + "Has " + exploit_item.name + ".") + exploit_record += exploitmsg /client/proc/check_has_body_select() return mob && mob.hud_used && istype(mob.zone_sel, /obj/screen/zone_sel) diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 142cd9ae92..7ca7cae45c 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -72,6 +72,7 @@ var/sec_record = "" var/gen_record = "" var/exploit_record = "" + var/exploit_addons = list() //Assorted things that show up at the end of the exploit_record list var/blinded = null var/bhunger = 0 //Carbon var/ajourn = 0 diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 464baaa142..e73d316433 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -501,6 +501,10 @@ if(!dense_object && (locate(/obj/structure/lattice) in oview(1, src))) dense_object++ + if(!dense_object && (locate(/obj/structure/catwalk) in oview(1, src))) + dense_object++ + + //Lastly attempt to locate any dense objects we could push off of //TODO: If we implement objects drifing in space this needs to really push them //Due to a few issues only anchored and dense objects will now work. @@ -529,3 +533,23 @@ /mob/proc/update_gravity() return + +// The real Move() proc is above, but touching that massive block just to put this in isn't worth it. +/mob/Move(var/newloc, var/direct) + . = ..(newloc, direct) + if(.) + post_move(newloc, direct) + +// Called when a mob successfully moves. +// Would've been an /atom/movable proc but it caused issues. +/mob/proc/post_move(var/newloc, var/direct) + for(var/obj/O in contents) + O.on_loc_moved(newloc, direct) + +// Received from post_move(), useful for items that need to know that their loc just moved. +/obj/proc/on_loc_moved(var/newloc, var/direct) + return + +/obj/item/weapon/storage/on_loc_moved(var/newloc, var/direct) + for(var/obj/O in contents) + O.on_loc_moved(newloc, direct) \ No newline at end of file diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm index bc64f3e764..0e3b1f7695 100644 --- a/code/modules/mob/new_player/sprite_accessories.dm +++ b/code/modules/mob/new_player/sprite_accessories.dm @@ -1020,6 +1020,17 @@ icon_state = "teshari_mushroom" species_allowed = list("Teshari") +// Vox things + vox_braid_long + name = "Long Vox braid" + icon_state = "vox_longbraid" + species_allowed = list("Vox") + + vox_braid_short + name = "Short Vox Braid" + icon_state = "vox_shortbraid" + species_allowed = list("Vox") + vox_quills_short name = "Short Vox Quills" icon_state = "vox_shortquills" diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index bd12661437..9d30ef7244 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -77,10 +77,26 @@ else O.key = key + //Languages + add_language("Robot Talk", 1) + add_language(LANGUAGE_GALCOM, 1) + add_language(LANGUAGE_SOL_COMMON, 1) + add_language(LANGUAGE_UNATHI, 1) + add_language(LANGUAGE_SIIK, 1) + add_language(LANGUAGE_SKRELLIAN, 1) + add_language(LANGUAGE_TRADEBAND, 1) + add_language(LANGUAGE_GUTTER, 1) + add_language(LANGUAGE_EAL, 1) + add_language(LANGUAGE_SCHECHI, 1) + add_language(LANGUAGE_SIGN, 1) + + // Lorefolks say it may be so. if(O.client && O.client.prefs) var/datum/preferences/B = O.client.prefs - for(var/language in B.alternate_languages) - O.add_language(language) + if(LANGUAGE_ROOTGLOBAL in B.alternate_languages) + O.add_language(LANGUAGE_ROOTGLOBAL, 1) + if(LANGUAGE_ROOTLOCAL in B.alternate_languages) + O.add_language(LANGUAGE_ROOTLOCAL, 1) if(move) var/obj/loc_landmark diff --git a/code/modules/organs/internal/brain.dm b/code/modules/organs/internal/brain.dm index 77ead516c3..0a99fb37f3 100644 --- a/code/modules/organs/internal/brain.dm +++ b/code/modules/organs/internal/brain.dm @@ -127,6 +127,7 @@ desc = "A complex, organic knot of jelly and crystalline particles." icon = 'icons/mob/slimes.dmi' icon_state = "green slime extract" + parent_organ = BP_TORSO /obj/item/organ/internal/brain/golem name = "chem" diff --git a/code/modules/organs/internal/liver.dm b/code/modules/organs/internal/liver.dm index 6b7459500b..3b20f30214 100644 --- a/code/modules/organs/internal/liver.dm +++ b/code/modules/organs/internal/liver.dm @@ -39,10 +39,11 @@ // Do some reagent processing. if(owner.chem_effects[CE_ALCOHOL_TOXIC]) + take_damage(owner.chem_effects[CE_ALCOHOL_TOXIC] * 0.1 * PROCESS_ACCURACY, prob(1)) // Chance to warn them + if(filter_effect < 2) //Liver is badly damaged, you're drinking yourself to death + owner.adjustToxLoss(owner.chem_effects[CE_ALCOHOL_TOXIC] * 0.2 * PROCESS_ACCURACY) if(filter_effect < 3) owner.adjustToxLoss(owner.chem_effects[CE_ALCOHOL_TOXIC] * 0.1 * PROCESS_ACCURACY) - else - take_damage(owner.chem_effects[CE_ALCOHOL_TOXIC] * 0.1 * PROCESS_ACCURACY, prob(1)) // Chance to warn them /obj/item/organ/internal/liver/handle_germ_effects() . = ..() //Up should return an infection level as an integer diff --git a/code/modules/organs/subtypes/slime.dm b/code/modules/organs/subtypes/slime.dm new file mode 100644 index 0000000000..1c9c11d75b --- /dev/null +++ b/code/modules/organs/subtypes/slime.dm @@ -0,0 +1,47 @@ +/obj/item/organ/external/chest/unbreakable/slime + nonsolid = 1 + max_damage = 50 + encased = 0 + +/obj/item/organ/external/groin/unbreakable/slime + nonsolid = 1 + max_damage = 30 + +/obj/item/organ/external/arm/unbreakable/slime + nonsolid = 1 + max_damage = 5 + +/obj/item/organ/external/arm/right/unbreakable/slime + nonsolid = 1 + max_damage = 5 + +/obj/item/organ/external/leg/unbreakable/slime + nonsolid = 1 + max_damage = 5 + +/obj/item/organ/external/leg/right/unbreakable/slime + nonsolid = 1 + max_damage = 5 + +/obj/item/organ/external/foot/unbreakable/slime + nonsolid = 1 + max_damage = 5 + +/obj/item/organ/external/foot/right/unbreakable/slime + nonsolid = 1 + max_damage = 5 + +/obj/item/organ/external/hand/unbreakable/slime + nonsolid = 1 + max_damage = 5 + +/obj/item/organ/external/hand/right/unbreakable/slime + nonsolid = 1 + max_damage = 5 + +/obj/item/organ/external/head/unbreakable/slime //They don't need this anymore. + nonsolid = 1 + cannot_gib = 0 + vital = 0 + max_damage = 5 + encased = 0 \ No newline at end of file diff --git a/code/modules/organs/subtypes/unbreakable.dm b/code/modules/organs/subtypes/unbreakable.dm index fcd819029e..61126769cd 100644 --- a/code/modules/organs/subtypes/unbreakable.dm +++ b/code/modules/organs/subtypes/unbreakable.dm @@ -40,49 +40,4 @@ /obj/item/organ/external/head/unbreakable cannot_break = 1 - dislocated = -1 - -// Slime limbs. -/obj/item/organ/external/chest/unbreakable/slime - nonsolid = 1 - max_damage = 50 - -/obj/item/organ/external/groin/unbreakable/slime - nonsolid = 1 - max_damage = 30 - -/obj/item/organ/external/arm/unbreakable/slime - nonsolid = 1 - max_damage = 5 - -/obj/item/organ/external/arm/right/unbreakable/slime - nonsolid = 1 - max_damage = 5 - -/obj/item/organ/external/leg/unbreakable/slime - nonsolid = 1 - max_damage = 5 - -/obj/item/organ/external/leg/right/unbreakable/slime - nonsolid = 1 - max_damage = 5 - -/obj/item/organ/external/foot/unbreakable/slime - nonsolid = 1 - max_damage = 5 - -/obj/item/organ/external/foot/right/unbreakable/slime - nonsolid = 1 - max_damage = 5 - -/obj/item/organ/external/hand/unbreakable/slime - nonsolid = 1 - max_damage = 5 - -/obj/item/organ/external/hand/right/unbreakable/slime - nonsolid = 1 - max_damage = 5 - -/obj/item/organ/external/head/unbreakable/slime - nonsolid = 1 - max_damage = 5 + dislocated = -1 \ No newline at end of file diff --git a/code/modules/planet/sif.dm b/code/modules/planet/sif.dm index e35646ce7f..b69f61cd8a 100644 --- a/code/modules/planet/sif.dm +++ b/code/modules/planet/sif.dm @@ -9,7 +9,7 @@ var/datum/planet/sif/planet_sif = null breathable atmosphere, a magnetic field, weather, and similar gravity to Earth. It is currently the capital planet of Vir. \ Its center of government is the equatorial city and site of first settlement, New Reykjavik." // Ripped straight from the wiki. current_time = new /datum/time/sif() // 32 hour clocks are nice. - expected_z_levels = list(1) // To be changed when real map is finished. +// expected_z_levels = list(1) // To be changed when real map is finished. planetary_wall_type = /turf/unsimulated/wall/planetary/sif /datum/planet/sif/New() @@ -133,8 +133,8 @@ var/datum/planet/sif/planet_sif = null datum/weather/sif name = "sif base" - temp_high = 243.15 // -20c - temp_low = 233.15 // -30c + temp_high = 283.15 // 10c + temp_low = 263.15 // -10c /datum/weather/sif/clear name = "clear" @@ -158,8 +158,8 @@ datum/weather/sif /datum/weather/sif/light_snow name = "light snow" icon_state = "snowfall_light" - temp_high = 238.15 // -25c - temp_low = 228.15 // -35c + temp_high = T0C // 0c + temp_low = 258.15 // -15c light_modifier = 0.7 transition_chances = list( WEATHER_OVERCAST = 20, @@ -171,8 +171,8 @@ datum/weather/sif /datum/weather/sif/snow name = "moderate snow" icon_state = "snowfall_med" - temp_high = 233.15 // -30c - temp_low = 223.15 // -40c + temp_high = T0C // 0c + temp_low = 243.15 // -30c light_modifier = 0.5 transition_chances = list( WEATHER_LIGHT_SNOW = 20, @@ -194,8 +194,8 @@ datum/weather/sif /datum/weather/sif/blizzard name = "blizzard" icon_state = "snowfall_heavy" - temp_high = 223.15 // -40c - temp_low = 203.15 // -60c + temp_high = 233.15 // -40c + temp_low = 213.15 // -60c light_modifier = 0.3 transition_chances = list( WEATHER_SNOW = 45, @@ -238,8 +238,8 @@ datum/weather/sif /datum/weather/sif/storm name = "storm" icon_state = "storm" - temp_high = 233.15 // -30c - temp_low = 213.15 // -50c + temp_high = 243.15 // -30c + temp_low = 233.15 // -50c light_modifier = 0.3 transition_chances = list( WEATHER_RAIN = 45, @@ -261,8 +261,8 @@ datum/weather/sif /datum/weather/sif/hail name = "hail" icon_state = "hail" - temp_high = 233.15 // -30c - temp_low = 213.15 // -50c + temp_high = T0C // 0c + temp_low = 243.15 // -30c light_modifier = 0.3 transition_chances = list( WEATHER_RAIN = 45, @@ -297,5 +297,4 @@ datum/weather/sif light_color = "#FF0000" transition_chances = list( WEATHER_BLOODMOON = 100 - ) - + ) \ No newline at end of file diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index ebfa533086..edcc43bb22 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -565,15 +565,19 @@ obj/structure/cable/proc/cableColor(var/colorC) w_class = ITEMSIZE_SMALL /obj/item/stack/cable_coil/examine(mob/user) - if(get_dist(src, user) > 1) - return + var/msg = "" if(get_amount() == 1) - to_chat(user, "A short piece of power cable.") + msg += "A short piece of power cable." else if(get_amount() == 2) - to_chat(user, "A piece of power cable.") + msg += "A piece of power cable." else - to_chat(user, "A coil of power cable. There are [get_amount()] lengths of cable in the coil.") + msg += "A coil of power cable." + + if(get_dist(src, user) <= 1) + msg += " There are [get_amount()] lengths of cable in the coil." + + to_chat(user, msg) /obj/item/stack/cable_coil/verb/make_restraint() @@ -875,4 +879,52 @@ obj/structure/cable/proc/cableColor(var/colorC) /obj/item/stack/cable_coil/random/New() stacktype = /obj/item/stack/cable_coil color = pick(COLOR_RED, COLOR_BLUE, COLOR_LIME, COLOR_WHITE, COLOR_PINK, COLOR_YELLOW, COLOR_CYAN, COLOR_SILVER, COLOR_GRAY, COLOR_BLACK, COLOR_MAROON, COLOR_OLIVE, COLOR_LIME, COLOR_TEAL, COLOR_NAVY, COLOR_PURPLE, COLOR_BEIGE, COLOR_BROWN) - ..() \ No newline at end of file + ..() + +//Endless alien cable coil + +/obj/item/stack/cable_coil/alien + name = "alien spool" + icon = 'icons/obj/abductor.dmi' + icon_state = "coil" + amount = MAXCOIL + max_amount = MAXCOIL + color = COLOR_SILVER + desc = "A spool of cable. No matter how hard you try, you can never seem to get to the end." + throwforce = 10 + w_class = ITEMSIZE_SMALL + throw_speed = 2 + throw_range = 5 + matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 20) + flags = CONDUCT + slot_flags = SLOT_BELT + attack_verb = list("whipped", "lashed", "disciplined", "flogged") + stacktype = null + +/obj/item/stack/cable_coil/alien/New(loc, length = MAXCOIL, var/param_color = null) //There has to be a better way to do this. + if(embed_chance == -1) //From /obj/item, don't want to do what the normal cable_coil does + if(sharp) + embed_chance = force/w_class + else + embed_chance = force/(w_class*3) + update_icon() + +/obj/item/stack/cable_coil/alien/update_icon() + icon_state = initial(icon_state) + +/obj/item/stack/cable_coil/alien/use() //It's endless + return + +/obj/item/stack/cable_coil/alien/add() //Still endless + return + +/obj/item/stack/cable_coil/alien/update_wclass() + return + +/obj/item/stack/cable_coil/alien/examine(mob/user) + var/msg = "A spool of cable." + + if(get_dist(src, user) <= 1) + msg += " It doesn't seem to have a beginning, or an end." + + to_chat(user, msg) \ No newline at end of file diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index d3cde87049..2c1699c5f6 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -16,7 +16,7 @@ /obj/item/weapon/cell/process() if(self_recharge) - give(charge_amount / CELLRATE) + give(charge_amount) else return PROCESS_KILL @@ -59,6 +59,7 @@ return 0 var/used = min(charge, amount) charge -= used + update_icon() return used // Checks if the specified amount can be provided. If it can, it removes the amount @@ -78,24 +79,29 @@ if(maxcharge < amount) return 0 var/amount_used = min(maxcharge-charge,amount) charge += amount_used + update_icon() return amount_used /obj/item/weapon/cell/examine(mob/user) - if(get_dist(src, user) > 1) - return + var/msg = desc - if(maxcharge <= 2500) - user << "[desc]\nThe manufacturer's label states this cell has a power rating of [maxcharge], and that you should not swallow it.\nThe charge meter reads [round(src.percent() )]%." - else - user << "This power cell has an exciting chrome finish, as it is an uber-capacity cell type! It has a power rating of [maxcharge]!\nThe charge meter reads [round(src.percent() )]%." + if(get_dist(src, user) <= 1) + msg += " It has a power rating of [maxcharge].\nThe charge meter reads [round(src.percent() )]%." + to_chat(user, msg) +/* + if(maxcharge <= 2500) + to_chat(user, "[desc]\nThe manufacturer's label states this cell has a power rating of [maxcharge], and that you should not swallow it.\nThe charge meter reads [round(src.percent() )]%.") + else + to_chat(user, "This power cell has an exciting chrome finish, as it is an uber-capacity cell type! It has a power rating of [maxcharge]!\nThe charge meter reads [round(src.percent() )]%.") +*/ /obj/item/weapon/cell/attackby(obj/item/W, mob/user) ..() if(istype(W, /obj/item/weapon/reagent_containers/syringe)) var/obj/item/weapon/reagent_containers/syringe/S = W - user << "You inject the solution into the power cell." + to_chat(user, "You inject the solution into the power cell.") if(S.reagents.has_reagent("phoron", 5)) @@ -149,6 +155,8 @@ charge -= charge / severity if (charge < 0) charge = 0 + + update_icon() ..() /obj/item/weapon/cell/ex_act(severity) diff --git a/code/modules/supermatter/setup_supermatter.dm b/code/modules/power/supermatter/setup_supermatter.dm similarity index 89% rename from code/modules/supermatter/setup_supermatter.dm rename to code/modules/power/supermatter/setup_supermatter.dm index 01aaeb0a21..559f035cb2 100644 --- a/code/modules/supermatter/setup_supermatter.dm +++ b/code/modules/power/supermatter/setup_supermatter.dm @@ -187,9 +187,15 @@ -// Tries to enable the SMES on max input/output settings. With load balancing it should be fine as long as engine outputs at least ~500kW +// Tries to enable the SMES on max input/output settings, unless the vars are changed. THIS SHOULD NOT BE PLACED ON THE MAIN SMES OR THE ENGINE WILL OVERHEAT /obj/effect/engine_setup/smes/ name = "SMES Marker" + var/target_input_level //These are in watts, the display is in kilowatts. Add three zeros to the value you want. + var/target_output_level //These are in watts, the display is in kilowatts. Add three zeros to the value you want. + +/obj/effect/engine_setup/smes/main + target_input_level = 750000 + target_output_level = 750000 /obj/effect/engine_setup/smes/activate() ..() @@ -199,8 +205,22 @@ return SETUP_WARNING S.input_attempt = 1 S.output_attempt = 1 - S.input_level = S.input_level_max - S.output_level = S.output_level_max + if(target_input_level) + if(target_input_level > S.input_level_max) + S.input_level = S.input_level_max + else + S.input_level = target_input_level + else + S.input_level = S.input_level_max + + if(target_output_level) + if(target_output_level > S.input_level_max) + S.output_level = S.output_level_max + else + S.output_level = target_output_level + else + S.output_level = S.output_level_max + S.update_icon() return SETUP_OK diff --git a/code/modules/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm similarity index 94% rename from code/modules/supermatter/supermatter.dm rename to code/modules/power/supermatter/supermatter.dm index d559506484..089a91aaed 100644 --- a/code/modules/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -258,15 +258,7 @@ if(!istype(l.glasses, /obj/item/clothing/glasses/meson)) // VOREStation Edit - Only mesons can protect you! l.hallucination = max(0, min(200, l.hallucination + power * config_hallucination_power * sqrt( 1 / max(1,get_dist(l, src)) ) ) ) -/* - //adjusted range so that a power of 170 (pretty high) results in 9 tiles, roughly the distance from the core to the engine monitoring room. - //note that the rads given at the maximum range is a constant 0.2 - as power increases the maximum range merely increases. - for(var/mob/living/l in range(src, round(sqrt(power / 2)))) - var/radius = max(get_dist(l, src), 1) - var/rads = (power / 10) * ( 1 / (radius**2) ) - l.apply_effect(rads, IRRADIATE) -*/ - radiation_repository.radiate(src, power * 1.5) //Better close those shutters! + radiation_repository.radiate(src, max(power * 1.5, 50) ) //Better close those shutters! power -= (power/DECAY_FACTOR)**3 //energy losses due to radiation @@ -329,16 +321,6 @@ ui.set_auto_update(1) -/* -/obj/machinery/power/supermatter/proc/transfer_energy() - for(var/obj/machinery/power/rad_collector/R in rad_collectors) - var/distance = get_dist(R, src) - if(distance <= 15) - //for collectors using standard phoron tanks at 1013 kPa, the actual power generated will be this power*POWER_FACTOR*20*29 = power*POWER_FACTOR*580 - R.receive_pulse(power * POWER_FACTOR * (min(3/distance, 1))**2) - return -*/ - /obj/machinery/power/supermatter/attackby(obj/item/weapon/W as obj, mob/living/user as mob) user.visible_message("\The [user] touches \a [W] to \the [src] as a silence fills the room...",\ "You touch \the [W] to \the [src] when everything suddenly goes silent.\"\n\The [W] flashes into dust as you flinch away from \the [src].",\ diff --git a/code/modules/projectiles/ammunition/magazines.dm b/code/modules/projectiles/ammunition/magazines.dm index 82a6aa74e4..342e10db84 100644 --- a/code/modules/projectiles/ammunition/magazines.dm +++ b/code/modules/projectiles/ammunition/magazines.dm @@ -443,6 +443,23 @@ /obj/item/ammo_magazine/m762m/empty initial_ammo = 0 +/obj/item/ammo_magazine/m762garand + name = "garand clip (7.62mm)" // The clip goes into the magazine, hence the name. I'm very sure this is correct. + icon_state = "gclip" + mag_type = MAGAZINE + caliber = "7.62mm" + matter = list(DEFAULT_WALL_MATERIAL = 1600) + ammo_type = /obj/item/ammo_casing/a762 + max_ammo = 8 + multiple_sprites = 1 + +/obj/item/ammo_magazine/m762garand/ap + name = "garand clip (7.62mm armor-piercing)" + ammo_type = /obj/item/ammo_casing/a762/ap + +/obj/item/ammo_magazine/m762/empty + initial_ammo = 0 + /obj/item/ammo_magazine/clip/c762 name = "ammo clip (7.62mm)" icon_state = "clip_rifle" diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index 811e9d28f9..cb93992acc 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -37,7 +37,7 @@ list(mode_name="suppressive", projectile_type=/obj/item/projectile/beam/practice, charge_cost = 12), ) -obj/item/weapon/gun/energy/retro +/obj/item/weapon/gun/energy/retro name = "retro laser" icon_state = "retro" item_state = "retro" @@ -48,6 +48,10 @@ obj/item/weapon/gun/energy/retro projectile_type = /obj/item/projectile/beam fire_delay = 10 //old technology +/obj/item/weapon/gun/energy/retro/mounted + self_recharge = 1 + use_external_power = 1 + /obj/item/weapon/gun/energy/captain name = "antique laser gun" icon_state = "caplaser" diff --git a/code/modules/projectiles/guns/projectile/semiauto.dm b/code/modules/projectiles/guns/projectile/semiauto.dm new file mode 100644 index 0000000000..d4cd616188 --- /dev/null +++ b/code/modules/projectiles/guns/projectile/semiauto.dm @@ -0,0 +1,21 @@ +/obj/item/weapon/gun/projectile/garand + name = "\improper M1 Garand" + desc = "This is the vintage semi-automatic rifle that famously helped win the second World War. What the hell it's doing aboard a space station in the 26th century, you can only imagine. Uses 7.62mm rounds." + icon_state = "garand" + item_state = "boltaction" + w_class = ITEMSIZE_LARGE + caliber = "7.62mm" + origin_tech = list(TECH_COMBAT = 2, TECH_MATERIAL = 2) + slot_flags = SLOT_BACK + fire_sound = 'sound/weapons/rifleshot.ogg' + load_method = MAGAZINE // ToDo: Make it so MAGAZINE, SPEEDLOADER and SINGLE_CASING can all be used on the same gun. + magazine_type = /obj/item/ammo_magazine/m762garand + allowed_magazines = list(/obj/item/ammo_magazine/m762garand) + auto_eject = 1 + auto_eject_sound = 'sound/weapons/garand_ping.ogg' + +/obj/item/weapon/gun/projectile/garand/update_icon() + if(ammo_magazine) + icon_state = initial(icon_state) + else + icon_state = "[initial(icon_state)]-e" diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 3144f9eb09..c4344c052b 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -202,8 +202,9 @@ admin_attack_log(firer, target_mob, attacker_message, victim_message, admin_message) else - target_mob.attack_log += "\[[time_stamp()]\] UNKNOWN SUBJECT (No longer exists) shot [target_mob]/[target_mob.ckey] with \a [src]" - msg_admin_attack("UNKNOWN shot [target_mob] ([target_mob.ckey]) with \a [src] (JMP)") + if(target_mob) // Sometimes the target_mob gets gibbed or something. + target_mob.attack_log += "\[[time_stamp()]\] UNKNOWN SUBJECT (No longer exists) shot [target_mob]/[target_mob.ckey] with \a [src]" + msg_admin_attack("UNKNOWN shot [target_mob] ([target_mob.ckey]) with \a [src] (JMP)") //sometimes bullet_act() will want the projectile to continue flying if (result == PROJECTILE_CONTINUE) diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm index a217ee2be8..953ad42535 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm @@ -287,13 +287,21 @@ /datum/reagent/frostoil/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) if(alien == IS_DIONA) return - M.bodytemperature = max(M.bodytemperature - 10 * TEMPERATURE_DAMAGE_COEFFICIENT, 0) + M.bodytemperature = max(M.bodytemperature - 10 * TEMPERATURE_DAMAGE_COEFFICIENT, 215) if(prob(1)) M.emote("shiver") if(istype(M, /mob/living/simple_animal/slime)) M.bodytemperature = max(M.bodytemperature - rand(10,20), 0) holder.remove_reagent("capsaicin", 5) +/datum/reagent/frostoil/cryotoxin //A longer lasting version of frost oil. + name = "Cryotoxin" + id = "cryotoxin" + description = "Lowers the body's internal temperature." + reagent_state = LIQUID + color = "#B31008" + metabolism = REM * 0.5 + /datum/reagent/capsaicin name = "Capsaicin Oil" id = "capsaicin" diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm index d9e0dad733..c71a7de362 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm @@ -105,8 +105,8 @@ /datum/reagent/toxin/phoron/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) if(alien == IS_VOX) - M.adjustOxyLoss(-removed * 9) - return + M.adjustOxyLoss(-100 * removed) //5 oxyloss healed per tick. + return //You're wasting plasma (a semi-limited chemical) to save someone, so it might as well be somewhat strong. ..() /datum/reagent/toxin/phoron/touch_turf(var/turf/simulated/T, var/amount) diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm index 1e4ae3710d..8a99192233 100644 --- a/code/modules/reagents/Chemistry-Recipes.dm +++ b/code/modules/reagents/Chemistry-Recipes.dm @@ -1204,7 +1204,7 @@ name = "Syntiflesh" id = "syntiflesh" result = null - required_reagents = list("blood" = 5, "clonexadone" = 1) + required_reagents = list("blood" = 5, "clonexadone" = 5) result_amount = 1 /datum/chemical_reaction/food/syntiflesh/on_reaction(var/datum/reagents/holder, var/created_volume) diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm index f55893d91a..5c4a6bdce6 100644 --- a/code/modules/reagents/reagent_containers/borghydro.dm +++ b/code/modules/reagents/reagent_containers/borghydro.dm @@ -23,6 +23,9 @@ /obj/item/weapon/reagent_containers/borghypo/crisis reagent_ids = list("tricordrazine", "inaprovaline", "anti_toxin", "tramadol", "dexalin" ,"spaceacillin") +/obj/item/weapon/reagent_containers/borghypo/lost + reagent_ids = list("tricordrazine", "bicaridine", "dexalin", "anti_toxin", "tramadol", "spaceacillin") + /obj/item/weapon/reagent_containers/borghypo/New() ..() diff --git a/code/modules/reagents/reagent_containers/drinkingglass/drinkingglass.dm b/code/modules/reagents/reagent_containers/drinkingglass/drinkingglass.dm index 8d19e49330..1aae5b4a94 100644 --- a/code/modules/reagents/reagent_containers/drinkingglass/drinkingglass.dm +++ b/code/modules/reagents/reagent_containers/drinkingglass/drinkingglass.dm @@ -146,3 +146,22 @@ underlays += I else continue side = "right" + +/obj/item/weapon/reagent_containers/food/drinks/glass2/afterattack(var/obj/target, var/mob/user, var/proximity) + if(user.a_intent == I_HURT) //We only want splashing to be done if they are on harm intent. + if(!is_open_container() || !proximity) + return 1 + if(standard_splash_mob(user, target)) + return 1 + if(reagents && reagents.total_volume) //They are on harm intent, aka wanting to spill it. + user << "You splash the solution onto [target]." + reagents.splash(target, reagents.total_volume) + return 1 + else + return + +/obj/item/weapon/reagent_containers/food/drinks/glass2/standard_feed_mob(var/mob/user, var/mob/target) + if(afterattack(target, user)) //Check to see if harm intent & splash. + return + else + ..() //If they're splashed, no need to do anything else. \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm index 3cb3e6b691..f83ac82a48 100644 --- a/code/modules/reagents/reagent_containers/food/snacks.dm +++ b/code/modules/reagents/reagent_containers/food/snacks.dm @@ -3474,7 +3474,7 @@ /obj/item/weapon/reagent_containers/food/snacks/skrellsnacks name = "\improper SkrellSnax" - desc = "Cured fungus shipped all the way from Jargon 4, almost like jerky! Almost." + desc = "Cured fungus shipped all the way from Qerr'balak, almost like jerky! Almost." icon_state = "skrellsnacks" filling_color = "#A66829" center_of_mass = list("x"=15, "y"=12) @@ -3509,4 +3509,4 @@ /obj/item/weapon/reagent_containers/food/snacks/croissant/New() ..() - bitesize = 2 \ No newline at end of file + bitesize = 2 diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm index 6b30ee0b85..374617c563 100644 --- a/code/modules/reagents/reagent_containers/glass.dm +++ b/code/modules/reagents/reagent_containers/glass.dm @@ -78,25 +78,27 @@ /obj/item/weapon/reagent_containers/glass/afterattack(var/obj/target, var/mob/user, var/proximity) - if(!is_open_container() || !proximity) - return + if(!is_open_container() || !proximity) //Is the container open & are they next to whatever they're clicking? + return //If not, do nothing. - for(var/type in can_be_placed_into) + for(var/type in can_be_placed_into) //Is it something it can be placed into? if(istype(target, type)) return - if(standard_splash_mob(user, target)) - return - if(standard_dispenser_refill(user, target)) - return - if(standard_pour_into(user, target)) + if(standard_dispenser_refill(user, target)) //Are they clicking a water tank/some dispenser? return - if(reagents && reagents.total_volume) - user << "You splash the solution onto [target]." - reagents.splash(target, reagents.total_volume) + if(standard_pour_into(user, target)) //Pouring into another beaker? return + if(user.a_intent == I_HURT) //Harm intent? + if(standard_splash_mob(user, target)) //If harm intent and can splash a mob, go ahead. + return + if(reagents && reagents.total_volume) //Otherwise? Splash the floor. + user << "You splash the solution onto [target]." + reagents.splash(target, reagents.total_volume) + return + /obj/item/weapon/reagent_containers/glass/attackby(obj/item/weapon/W as obj, mob/user as mob) if(istype(W, /obj/item/weapon/pen) || istype(W, /obj/item/device/flashlight/pen)) var/tmp_label = sanitizeSafe(input(user, "Enter a label for [name]", "Label", label_text), MAX_NAME_LEN) @@ -265,6 +267,41 @@ var/image/lid = image(icon, src, "lid_[initial(icon_state)]") overlays += lid +obj/item/weapon/reagent_containers/glass/bucket/wood + desc = "An old wooden bucket." + name = "wooden bucket" + icon = 'icons/obj/janitor.dmi' + icon_state = "woodbucket" + item_state = "woodbucket" + matter = list("wood" = 50) + w_class = ITEMSIZE_LARGE + amount_per_transfer_from_this = 20 + possible_transfer_amounts = list(10,20,30,60,120) + volume = 120 + flags = OPENCONTAINER + unacidable = 0 + +/obj/item/weapon/reagent_containers/glass/bucket/wood/attackby(var/obj/D, mob/user as mob) + if(isprox(D)) + user << "This wooden bucket doesn't play well with electronics." + return + else if(istype(D, /obj/item/weapon/material/hatchet)) + to_chat(user, "You cut a big hole in \the [src] with \the [D]. It's kinda useless as a bucket now.") + user.put_in_hands(new /obj/item/clothing/head/helmet/bucket/wood) + user.drop_from_inventory(src) + qdel(src) + return + else if(istype(D, /obj/item/weapon/mop)) + if(reagents.total_volume < 1) + user << "\The [src] is empty!" + else + reagents.trans_to_obj(D, 5) + user << "You wet \the [D] in \the [src]." + playsound(loc, 'sound/effects/slosh.ogg', 25, 1) + return + else + return ..() + /obj/item/weapon/reagent_containers/glass/cooler_bottle desc = "A bottle for a water-cooler." name = "water-cooler bottle" diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index d549f310cb..b9191b4329 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -58,7 +58,7 @@ return if(mode == SYRINGE_BROKEN) - user << "This syringe is broken!" + to_chat(user, "This syringe is broken!") return if(user.a_intent == I_HURT && ismob(target)) @@ -70,26 +70,31 @@ switch(mode) if(SYRINGE_DRAW) if(!reagents.get_free_space()) - user << "The syringe is full." + to_chat(user, "The syringe is full.") mode = SYRINGE_INJECT return if(ismob(target))//Blood! if(reagents.has_reagent("blood")) - user << "There is already a blood sample in this syringe." + to_chat(user, "There is already a blood sample in this syringe.") return + if(istype(target, /mob/living/carbon)) var/amount = reagents.get_free_space() var/mob/living/carbon/T = target if(!T.dna) - user << "You are unable to locate any blood. (To be specific, your target seems to be missing their DNA datum)." + to_chat(user, "You are unable to locate any blood. (To be specific, your target seems to be missing their DNA datum).") return if(NOCLONE in T.mutations) //target done been et, no more blood in him - user << "You are unable to locate any blood." + to_chat(user, "You are unable to locate any blood.") + return + + if(T.isSynthetic()) + to_chat(user, "You can't draw blood from a synthetic!") return if(drawing) - user << "You are already drawing blood from [T.name]." + to_chat(user, "You are already drawing blood from [T.name].") return var/datum/reagent/B @@ -117,50 +122,51 @@ reagents.update_total() on_reagent_change() reagents.handle_reactions() - user << "You take a blood sample from [target]." + to_chat(user, "You take a blood sample from [target].") for(var/mob/O in viewers(4, user)) O.show_message("[user] takes a blood sample from [target].", 1) else //if not mob if(!target.reagents.total_volume) - user << "[target] is empty." + to_chat(user, "[target] is empty.") return if(!target.is_open_container() && !istype(target, /obj/structure/reagent_dispensers) && !istype(target, /obj/item/slime_extract) && !istype(target, /obj/item/weapon/reagent_containers/food)) - user << "You cannot directly remove reagents from this object." + to_chat(user, "You cannot directly remove reagents from this object.") return var/trans = target.reagents.trans_to_obj(src, amount_per_transfer_from_this) - user << "You fill the syringe with [trans] units of the solution." + to_chat(user, "You fill the syringe with [trans] units of the solution.") update_icon() + if(!reagents.get_free_space()) mode = SYRINGE_INJECT update_icon() if(SYRINGE_INJECT) if(!reagents.total_volume) - user << "The syringe is empty." + to_chat(user, "The syringe is empty.") mode = SYRINGE_DRAW return if(istype(target, /obj/item/weapon/implantcase/chem)) return if(!target.is_open_container() && !ismob(target) && !istype(target, /obj/item/weapon/reagent_containers/food) && !istype(target, /obj/item/slime_extract) && !istype(target, /obj/item/clothing/mask/smokable/cigarette) && !istype(target, /obj/item/weapon/storage/fancy/cigarettes)) - user << "You cannot directly fill this object." + to_chat(user, "You cannot directly fill this object.") return if(!target.reagents.get_free_space()) - user << "[target] is full." + to_chat(user, "[target] is full.") return var/mob/living/carbon/human/H = target if(istype(H)) var/obj/item/organ/external/affected = H.get_organ(user.zone_sel.selecting) if(!affected) - user << "\The [H] is missing that limb!" + to_chat(user, "\The [H] is missing that limb!") return else if(affected.robotic >= ORGAN_ROBOT) - user << "You cannot inject a robotic limb." + to_chat(user, "You cannot inject a robotic limb.") return if(ismob(target) && target != user) @@ -200,9 +206,9 @@ else trans = reagents.trans_to_obj(target, amount_per_transfer_from_this) if(trans) - user << "You inject [trans] units of the solution. The syringe now contains [src.reagents.total_volume] units." + to_chat(user, "You inject [trans] units of the solution. The syringe now contains [src.reagents.total_volume] units.") else - user << "The syringe is empty." + to_chat(user, "The syringe is empty.") if (reagents.total_volume <= 0 && mode == SYRINGE_INJECT) mode = SYRINGE_DRAW update_icon() @@ -245,7 +251,7 @@ var/obj/item/organ/external/affecting = H.get_organ(target_zone) if (!affecting || affecting.is_stump()) - user << "They are missing that limb!" + to_chat(user, "They are missing that limb!") return var/hit_area = affecting.name @@ -302,10 +308,10 @@ /obj/item/weapon/reagent_containers/syringe/ld50_syringe/afterattack(obj/target, mob/user, flag) if(mode == SYRINGE_DRAW && ismob(target)) // No drawing 50 units of blood at once - user << "This needle isn't designed for drawing blood." + to_chat(user, "This needle isn't designed for drawing blood.") return if(user.a_intent == "hurt" && ismob(target)) // No instant injecting - user << "This syringe is too big to stab someone with it." + to_chat(user, "This syringe is too big to stab someone with it.") ..() //////////////////////////////////////////////////////////////////////////////// diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm index a8bfad4637..a6e6a94850 100644 --- a/code/modules/research/designs.dm +++ b/code/modules/research/designs.dm @@ -473,6 +473,15 @@ other types of metals and chemistry for reagents). build_path = /obj/item/weapon/surgical/scalpel/manager sort_string = "MBBAD" +/datum/design/item/bone_clamp + name = "Bone Clamp" + desc = "A miracle of modern science, this tool rapidly knits together bone, without the need for bone gel." + id = "bone_clamp" + req_tech = list(TECH_BIO = 4, TECH_MATERIAL = 5, TECH_MAGNET = 4, TECH_DATA = 4) + materials = list (DEFAULT_WALL_MATERIAL = 12500, "glass" = 7500, "silver" = 2500) + build_path = /obj/item/weapon/surgical/bone_clamp + sort_string = "MBBAE" + /datum/design/item/implant materials = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50) @@ -639,14 +648,14 @@ other types of metals and chemistry for reagents). /datum/design/item/weapon/slimebation id = "slimebation" - req_tech = list(TECH_MATERIAL = 2, TECH_BIO = 3, TECH_POWER = 3, TECH_COMBAT = 3) + req_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2, TECH_POWER = 3, TECH_COMBAT = 3) materials = list(DEFAULT_WALL_MATERIAL = 5000) build_path = /obj/item/weapon/melee/baton/slime sort_string = "TBAAB" /datum/design/item/weapon/slimetaser id = "slimetaser" - req_tech = list(TECH_MATERIAL = 3, TECH_BIO = 4, TECH_POWER = 4, TECH_COMBAT = 4) + req_tech = list(TECH_MATERIAL = 3, TECH_BIO = 3, TECH_POWER = 4, TECH_COMBAT = 4) materials = list(DEFAULT_WALL_MATERIAL = 5000) build_path = /obj/item/weapon/gun/energy/taser/xeno sort_string = "TBAAC" @@ -735,6 +744,16 @@ other types of metals and chemistry for reagents). build_path = /obj/item/device/aicard sort_string = "VACAA" +/datum/design/item/dronebrain + name = "Robotic intelligence circuit" + id = "dronebrain" + req_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 5, TECH_DATA = 4) + build_type = PROTOLATHE | PROSFAB + materials = list(DEFAULT_WALL_MATERIAL = 2000, "glass" = 1000, "silver" = 1000, "gold" = 500) + build_path = /obj/item/device/mmi/digital/robot + category = "Misc" + sort_string = "VACAC" + /datum/design/item/posibrain name = "Positronic brain" id = "posibrain" @@ -755,16 +774,6 @@ other types of metals and chemistry for reagents). category = "Misc" sort_string = "VACBA" -/datum/design/item/mmi_radio - name = "Radio-enabled man-machine interface" - id = "mmi_radio" - req_tech = list(TECH_DATA = 2, TECH_BIO = 4) - build_type = PROTOLATHE | PROSFAB - materials = list(DEFAULT_WALL_MATERIAL = 1200, "glass" = 500) - build_path = /obj/item/device/mmi/radio_enabled - category = "Misc" - sort_string = "VACBB" - /datum/design/item/beacon name = "Bluespace tracking beacon design" id = "beacon" diff --git a/code/modules/shieldgen/directional_shield.dm b/code/modules/shieldgen/directional_shield.dm new file mode 100644 index 0000000000..41bcda3ceb --- /dev/null +++ b/code/modules/shieldgen/directional_shield.dm @@ -0,0 +1,347 @@ +// This is the actual shield. The projector is a different item. +/obj/effect/directional_shield + name = "directional combat shield" + desc = "A wide shield, which has the property to block incoming projectiles but allow outgoing projectiles to pass it. \ + Slower moving objects are not blocked, so people can walk in and out of the barrier, and things can be thrown into and out \ + of it." + icon = 'icons/effects/effects.dmi' + icon_state = "directional_shield" + density = FALSE // People can move pass these shields. + opacity = FALSE + anchored = TRUE + unacidable = TRUE + layer = MOB_LAYER + 0.1 + mouse_opacity = FALSE + var/obj/item/shield_projector/projector = null // The thing creating the shield. + var/x_offset = 0 // Offset from the 'center' of where the projector is, so that if it moves, the shield can recalc its position. + var/y_offset = 0 // Ditto. + +/obj/effect/directional_shield/New(var/newloc, var/new_projector) + if(new_projector) + projector = new_projector + var/turf/us = get_turf(src) + var/turf/them = get_turf(projector) + if(them) + x_offset = us.x - them.x + y_offset = us.y - them.y + else + update_color() + ..(newloc) + +/obj/effect/directional_shield/proc/relocate() + if(!projector) + return // Nothing to follow. + var/turf/T = get_turf(projector) + if(!T) + return + var/turf/new_pos = locate(T.x + x_offset, T.y + y_offset, T.z) + if(new_pos) + forceMove(new_pos) + else + qdel(src) + +/obj/effect/directional_shield/proc/update_color(var/new_color) + if(!projector) + color = "#0099FF" + else + animate(src, color = new_color, 5) +// color = new_color + +/obj/effect/directional_shield/Destroy() + if(projector) + projector.active_shields -= src + projector = null + return ..() + +/obj/effect/directional_shield/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group || (height==0)) + return TRUE + else if(istype(mover, /obj/item/projectile)) + var/obj/item/projectile/P = mover + if(istype(P, /obj/item/projectile/test)) // Turrets need to try to kill the shield and so their test bullet needs to penetrate. + return TRUE + + var/bad_arc = reverse_direction(dir) // Arc of directions from which we cannot block. + if(check_shield_arc(src, bad_arc, P)) // This is actually for mobs but it will work for our purposes as well. + return FALSE + else + return TRUE + return TRUE + +/obj/effect/directional_shield/bullet_act(var/obj/item/projectile/P) + adjust_health(-P.get_structure_damage()) + P.on_hit() + playsound(get_turf(src), 'sound/effects/EMPulse.ogg', 75, 1) + +// All the shields tied to their projector are one 'unit', and don't have individualized health values like most other shields. +/obj/effect/directional_shield/proc/adjust_health(amount) + if(projector) + projector.adjust_health(amount) // Projector will kill the shield if needed. + // If the shield lacks a projector, then it was probably spawned in by an admin for bus, so it's indestructable. + + +// This actually creates the shields. It's an item so that it can be carried, but it could also be placed inside a stationary object if desired. +// It should work inside the contents of any mob. +/obj/item/shield_projector + name = "combat shield projector" + desc = "A miniturized and compact shield projector. This type has been optimized to diffuse lasers or block high velocity projectiles from the outside, \ + but allow those projectiles to leave the shield from the inside. Blocking too many damaging projectiles will cause the shield to fail." + icon = 'icons/obj/device.dmi' + icon_state = "signmaker_sec" + var/active = FALSE // If it's on. + var/shield_health = 400 // How much damage the shield blocks before breaking. This is a shared health pool for all shields attached to this projector. + var/max_shield_health = 400 // Ditto. This is fairly high, but shields are really big, you can't miss them, and laser carbines pump out so much hurt. + var/shield_regen_amount = 20 // How much to recharge every process(), after the delay. + var/shield_regen_delay = 5 SECONDS // If the shield takes damage, it won't recharge for this long. + var/last_damaged_time = null // world.time when the shields took damage, used for the delay. + var/list/active_shields = list() // Shields that are active and deployed. + var/always_on = FALSE // If true, will always try to reactivate if disabled for whatever reason, ideal if AI mobs are holding this. + var/high_color = "#0099FF" // Color the shield will be when at max health. A light blue. + var/low_color = "#FF0000" // Color the shield will drift towards as health is lowered. Deep red. + +/obj/item/shield_projector/New() + processing_objects += src + if(always_on) + create_shields() + ..() + +/obj/item/shield_projector/Destroy() + destroy_shields() + processing_objects -= src + return ..() + +/obj/item/shield_projector/proc/create_shield(var/newloc, var/new_dir) + var/obj/effect/directional_shield/S = new(newloc, src) + S.dir = new_dir + active_shields += S + +/obj/item/shield_projector/proc/create_shields() // Override this for a specific shape. Be sure to call ..() for the checks, however. + if(active) // Already made. + return FALSE + if(shield_health <= 0) + return FALSE + active = TRUE + return TRUE + +/obj/item/shield_projector/proc/destroy_shields() + for(var/obj/effect/directional_shield/S in active_shields) + active_shields -= S + qdel(S) + active = FALSE + +/obj/item/shield_projector/proc/update_shield_positions() + for(var/obj/effect/directional_shield/S in active_shields) + S.relocate() + +/obj/item/shield_projector/proc/adjust_health(amount) + shield_health = between(0, shield_health + amount, max_shield_health) + if(amount < 0) + if(shield_health <= 0) + destroy_shields() + var/turf/T = get_turf(src) + T.visible_message("\The [src] overloads and the shield vanishes!") + playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 75, 0) + else + if(shield_health < max_shield_health / 4) // Play a more urgent sounding beep if it's at 25% health. + playsound(get_turf(src), 'sound/machines/defib_success.ogg', 75, 0) + else + playsound(get_turf(src), 'sound/machines/defib_SafetyOn.ogg', 75, 0) + last_damaged_time = world.time + update_shield_colors() + +// Makes shields become gradually more red as the projector's health decreases. +/obj/item/shield_projector/proc/update_shield_colors() + // This is done at the projector instead of the shields themselves to avoid needing to calculate this more than once every update. + var/lerp_weight = shield_health / max_shield_health + + var/list/low_color_list = hex2rgb(low_color) + var/low_r = low_color_list[1] + var/low_g = low_color_list[2] + var/low_b = low_color_list[3] + + var/list/high_color_list = hex2rgb(high_color) + var/high_r = high_color_list[1] + var/high_g = high_color_list[2] + var/high_b = high_color_list[3] + + var/new_r = Interpolate(low_r, high_r, weight = lerp_weight) + var/new_g = Interpolate(low_g, high_g, weight = lerp_weight) + var/new_b = Interpolate(low_b, high_b, weight = lerp_weight) + + var/new_color = rgb(new_r, new_g, new_b) + + // Now deploy the new color to all the shields. + for(var/obj/effect/directional_shield/S in active_shields) + S.update_color(new_color) + +/obj/item/shield_projector/attack_self(var/mob/living/user) + if(active) + if(always_on) + to_chat(user, "You can't seem to deactivate \the [src].") + return + + destroy_shields() + else + set_dir(user.dir) // Needed for linear shields. + create_shields() + visible_message("\The [user] [!active ? "de":""]activates \the [src].") + +/obj/item/shield_projector/process() + if(shield_health < max_shield_health && ( (last_damaged_time + shield_regen_delay) < world.time) ) + adjust_health(shield_regen_amount) + if(always_on && !active) // Make shields as soon as possible if this is set. + create_shields() + if(shield_health == max_shield_health) + playsound(get_turf(src), 'sound/machines/defib_ready.ogg', 75, 0) + else + playsound(get_turf(src), 'sound/machines/defib_safetyOff.ogg', 75, 0) + +/obj/item/shield_projector/examine(var/mob/user) + ..() + if(get_dist(src, user) <= 1) + to_chat(user, "\The [src]'s shield matrix is at [round( (shield_health / max_shield_health) * 100, 0.01)]% strength.") + +/obj/item/shield_projector/emp_act(var/severity) + adjust_health(-max_shield_health / severity) // A strong EMP will kill the shield instantly, but weaker ones won't on the first hit. + +/obj/item/shield_projector/Move(var/newloc, var/direct) + ..(newloc, direct) + update_shield_positions() + +/obj/item/shield_projector/on_loc_moved(var/newloc, var/direct) + update_shield_positions() + + +// Subtypes + +/obj/item/shield_projector/rectangle + name = "rectangular combat shield projector" + description_info = "This creates a shield in a rectangular shape, which allows projectiles to leave from inside but blocks projectiles from outside. \ + Everything else can pass through the shield freely, including other people and thrown objects. The shield also cannot block certain effects which \ + take place over an area, such as flashbangs or explosions." + var/size_x = 3 // How big the rectangle will be, in tiles from the center. + var/size_y = 3 // Ditto. + +// Weaker and smaller variant. +/obj/item/shield_projector/rectangle/weak + shield_health = 200 // Half as strong as the default. + max_shield_health = 200 + size_x = 2 + size_y = 2 + +// A shortcut for admins to spawn in to put into simple animals or other things where it needs to reactivate automatically. +/obj/item/shield_projector/rectangle/automatic + always_on = TRUE + +/obj/item/shield_projector/rectangle/automatic/weak + shield_health = 200 // Half as strong as the default. + max_shield_health = 200 + size_x = 2 + size_y = 2 + +// Horrible implementation below. +/obj/item/shield_projector/rectangle/create_shields() + if(!..()) + return FALSE + + // Make a rectangle in a really terrible way. + var/x_dist = size_x + var/y_dist = size_y + + var/turf/T = get_turf(src) + if(!T) + return FALSE + // Top left corner. + var/turf/T1 = locate(T.x - x_dist, T.y + y_dist, T.z) + // Bottom right corner. + var/turf/T2 = locate(T.x + x_dist, T.y - y_dist, T.z) + if(!T1 || !T2) // If we're on the edge of the map then don't bother. + return FALSE + + // Build half of the corners first, as they are 'anchors' for the rest of the code below. + create_shield(T1, NORTHWEST) + create_shield(T2, SOUTHEAST) + + // Build the edges. + // First start with the north side. + var/current_x = T1.x + 1 // Start next to the top left corner. + var/current_y = T1.y + var/length = (x_dist * 2) - 1 + for(var/i = 1 to length) + create_shield(locate(current_x, current_y, T.z), NORTH) + current_x++ + + // Make the top right corner. + create_shield(locate(current_x, current_y, T.z), NORTHEAST) + + // Now for the west edge. + current_x = T1.x + current_y = T1.y - 1 + length = (y_dist * 2) - 1 + for(var/i = 1 to length) + create_shield(locate(current_x, current_y, T.z), WEST) + current_y-- + + // Make the bottom left corner. + create_shield(locate(current_x, current_y, T.z), SOUTHWEST) + + // Switch to the second corner, and make the east edge. + current_x = T2.x + current_y = T2.y + 1 + length = (y_dist * 2) - 1 + for(var/i = 1 to length) + create_shield(locate(current_x, current_y, T.z), EAST) + current_y++ + + // There are no more corners to create, so we can just go build the south edge now. + current_x = T2.x - 1 + current_y = T2.y + length = (x_dist * 2) - 1 + for(var/i = 1 to length) + create_shield(locate(current_x, current_y, T.z), SOUTH) + current_x-- + // Finally done. + update_shield_colors() + return TRUE + +/obj/item/shield_projector/line + name = "linear combat shield projector" + description_info = "This creates a shield in a straight line perpendicular to the direction where the user was facing when it was activated. \ + The shield allows projectiles to leave from inside but blocks projectiles from outside. Everything else can pass through the shield freely, \ + including other people and thrown objects. The shield also cannot block certain effects which take place over an area, such as flashbangs or explosions." + var/line_length = 5 // How long the line is. Recommended to be an odd number. + var/offset_from_center = 2 // How far from the projector will the line's center be. + +/obj/item/shield_projector/line/create_shields() + if(!..()) + return FALSE + + var/turf/T = get_turf(src) // This is another 'anchor', or will be once we move away from the projector. + for(var/i = 1 to offset_from_center) + T = get_step(T, dir) + if(!T) // We went off the map or something. + return + // We're at the right spot now. Build the center piece. + create_shield(T, dir) + + var/length_to_build = round( (line_length - 1) / 2) + var/turf/temp_T = T + + // First loop, we build the left (from a north perspective) side of the line. + for(var/i = 1 to length_to_build) + temp_T = get_step(temp_T, turn(dir, 90) ) + if(!temp_T) + break + create_shield(temp_T, i == length_to_build ? turn(dir, 45) : dir) + + temp_T = T + + // Second loop, we build the right side. + for(var/i = 1 to length_to_build) + temp_T = get_step(temp_T, turn(dir, -90) ) + if(!temp_T) + break + create_shield(temp_T, i == length_to_build ? turn(dir, -45) : dir) + // Finished. + update_shield_colors() + return TRUE \ No newline at end of file diff --git a/code/modules/shieldgen/emergency_shield.dm b/code/modules/shieldgen/emergency_shield.dm index fac9df67f8..6bf1ea58ef 100644 --- a/code/modules/shieldgen/emergency_shield.dm +++ b/code/modules/shieldgen/emergency_shield.dm @@ -139,6 +139,11 @@ var/check_delay = 60 //periodically recheck if we need to rebuild a shield use_power = 0 idle_power_usage = 0 + var/global/list/blockedturfs = list( + /turf/space, + /turf/simulated/open, + /turf/simulated/floor/outdoors, + ) /obj/machinery/shieldgen/Destroy() collapse_shields() @@ -169,7 +174,7 @@ /obj/machinery/shieldgen/proc/create_shields() for(var/turf/target_tile in range(2, src)) - if (istype(target_tile,/turf/space) && !(locate(/obj/machinery/shield) in target_tile)) + if (is_type_in_list(target_tile,blockedturfs) && !(locate(/obj/machinery/shield) in target_tile)) if (malfunction && prob(33) || !malfunction) var/obj/machinery/shield/S = new/obj/machinery/shield(target_tile) deployed_shields += S diff --git a/code/modules/shieldgen/shield_gen_external.dm b/code/modules/shieldgen/shield_gen_external.dm index 8086d0b7e3..2d7dd383d9 100644 --- a/code/modules/shieldgen/shield_gen_external.dm +++ b/code/modules/shieldgen/shield_gen_external.dm @@ -3,7 +3,11 @@ /obj/machinery/shield_gen/external name = "hull shield generator" - + var/global/list/blockedturfs = list( + /turf/space, + /turf/simulated/open, + /turf/simulated/floor/outdoors, + ) /obj/machinery/shield_gen/external/New() ..() @@ -18,7 +22,7 @@ for (var/x_offset = -field_radius; x_offset <= field_radius; x_offset++) for (var/y_offset = -field_radius; y_offset <= field_radius; y_offset++) T = locate(gen_turf.x + x_offset, gen_turf.y + y_offset, gen_turf.z) - if (istype(T, /turf/space)) + if (is_type_in_list(T,blockedturfs)) //check neighbors of T if (locate(/turf/simulated/) in orange(1, T)) out += T diff --git a/code/modules/surgery/bones.dm b/code/modules/surgery/bones.dm index 6a5a39df73..e1086dbdca 100644 --- a/code/modules/surgery/bones.dm +++ b/code/modules/surgery/bones.dm @@ -145,4 +145,42 @@ fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user]'s hand slips, smearing [tool] in the incision in [target]'s [affected.name]!" , \ - "Your hand slips, smearing [tool] in the incision in [target]'s [affected.name]!") \ No newline at end of file + "Your hand slips, smearing [tool] in the incision in [target]'s [affected.name]!") + + + +/datum/surgery_step/clamp_bone + allowed_tools = list( + /obj/item/weapon/surgical/bone_clamp = 100 + ) + can_infect = 1 + blood_level = 1 + + min_duration = 70 + max_duration = 90 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (!hasorgans(target)) + return 0 + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return affected && (affected.robotic < ORGAN_ROBOT) && affected.open >= 2 && affected.stage == 0 + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + if (affected.stage == 0) + user.visible_message("[user] starts repairing the damaged bones in [target]'s [affected.name] with \the [tool]." , \ + "You starts repairing the damaged bones in [target]'s [affected.name] with \the [tool].") + target.custom_pain("Something in your [affected.name] is causing you a lot of pain!", 50) + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] sets the bone in [target]'s [affected.name] with \the [tool].", \ + "You sets [target]'s bone in [affected.name] with \the [tool].") + affected.status &= ~ORGAN_BROKEN + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/obj/item/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user]'s hand slips, damaging the bone in [target]'s [affected.name] with \the [tool]!" , \ + "Your hand slips, damaging the bone in [target]'s [affected.name] with \the [tool]!") + affected.createwound(BRUISE, 5) \ No newline at end of file diff --git a/code/modules/surgery/robotics.dm b/code/modules/surgery/robotics.dm index 08751c8aca..170291f2b5 100644 --- a/code/modules/surgery/robotics.dm +++ b/code/modules/surgery/robotics.dm @@ -168,10 +168,16 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) if(istype(tool,/obj/item/stack/cable_coil/)) var/obj/item/stack/cable_coil/C = tool - if(!C.can_use(5)) - user << "You need ten or more cable pieces to repair this damage." //usage amount made more consistent with regular cable repair + if(affected.burn_dam == 0) + to_chat(user, "There are no burnt wires here!") return SURGERY_FAILURE - C.use(5) + else + if(!C.can_use(5)) + to_chat(user, "You need at least five cable pieces to repair this part.") //usage amount made more consistent with regular cable repair + return SURGERY_FAILURE + else + C.use(5) + return affected && affected.open == 3 && (affected.disfigured || affected.burn_dam > 0) && target_zone != O_MOUTH begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index 19007addae..8aab6a0a46 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -127,7 +127,8 @@ // Not staying still fails you too. if(success) - if(!do_mob(user, M, rand(S.min_duration, S.max_duration))) + var/calc_duration = rand(S.min_duration, S.max_duration) + if(!do_mob(user, M, calc_duration * toolspeed)) success = FALSE to_chat(user, "You must remain close to your patient to conduct surgery.") diff --git a/code/modules/xenoarcheaology/artifacts/artifact.dm b/code/modules/xenoarcheaology/artifacts/artifact.dm index e0ba3b1a3f..2bb6434553 100644 --- a/code/modules/xenoarcheaology/artifacts/artifact.dm +++ b/code/modules/xenoarcheaology/artifacts/artifact.dm @@ -259,8 +259,7 @@ ..() /obj/machinery/artifact/bullet_act(var/obj/item/projectile/P) - if(istype(P,/obj/item/projectile/bullet) ||\ - istype(P,/obj/item/projectile/hivebotbullet)) + if(istype(P,/obj/item/projectile/bullet)) if(my_effect.trigger == TRIGGER_FORCE) my_effect.ToggleActivate() if(secondary_effect && secondary_effect.trigger == TRIGGER_FORCE && prob(25)) diff --git a/code/modules/xenobio/items/extracts.dm b/code/modules/xenobio/items/extracts.dm index 901ccb8f99..87542b70f0 100644 --- a/code/modules/xenobio/items/extracts.dm +++ b/code/modules/xenobio/items/extracts.dm @@ -93,6 +93,13 @@ new /obj/item/weapon/reagent_containers/food/snacks/monkeycube(get_turf(holder.my_atom)) ..() +/datum/chemical_reaction/slime/grey_slimejelly + name = "Slime Jelly" + id = "m_jelly" + result = "slimejelly" + required_reagents = list("peridaxon" = 5) + result_amount = 15 + required = /obj/item/slime_extract/grey // **************** // * Metal slimes * diff --git a/code/modules/xenobio/items/weapons.dm b/code/modules/xenobio/items/weapons.dm index 3fdc758f84..a1aba76dab 100644 --- a/code/modules/xenobio/items/weapons.dm +++ b/code/modules/xenobio/items/weapons.dm @@ -6,7 +6,7 @@ slot_flags = SLOT_BELT force = 9 lightcolor = "#33CCFF" - origin_tech = list(TECH_COMBAT = 2, TECH_BIO = 4) + origin_tech = list(TECH_COMBAT = 2, TECH_BIO = 2) agonyforce = 10 //It's not supposed to be great at stunning human beings. hitcost = 48 //Less zap for less cost description_info = "This baton will stun a slime or other lesser lifeform for about five seconds, if hit with it while on." diff --git a/code/modules/xenobio2/mob/slime/slime_monkey.dm b/code/modules/xenobio2/mob/slime/slime_monkey.dm index f302f9104a..f3205f9e27 100644 --- a/code/modules/xenobio2/mob/slime/slime_monkey.dm +++ b/code/modules/xenobio2/mob/slime/slime_monkey.dm @@ -11,39 +11,28 @@ Slime cube lives here. /obj/item/slime_cube/attack_self(mob/user as mob) if(!searching) user << "You stare at the slimy cube, watching as some activity occurs." - icon_state = "slime cube active" - searching = 1 request_player() - spawn(600) reset_search() /obj/item/slime_cube/proc/request_player() - for(var/mob/observer/dead/O in player_list) - if(!O.MayRespawn()) - continue - if(O.client) - if(O.client.prefs.be_special & BE_ALIEN) - question(O.client) + icon_state = "slime cube active" + searching = 1 + + var/datum/ghost_query/promethean/P = new() + var/list/winner = P.query() + if(winner.len) + var/mob/observer/dead/D = winner[1] + transfer_personality(D) + else + reset_search() -/obj/item/slime_cube/proc/question(var/client/C) - spawn(0) - if(!C) return - var/response = alert(C, "Someone is requesting a soul for a promethean. Would you like to play as one?", "Promethean request", "Yes", "No", "Never for this round") - if(response == "Yes") - response = alert(C, "Are you sure you want to play as a promethean?", "Promethean request", "Yes", "No") - if(!C || 2 == searching) return //handle logouts that happen whilst the alert is waiting for a response, and responses issued after a brain has been located. - if(response == "Yes") - transfer_personality(C.mob) - else if (response == "Never for this round") - C.prefs.be_special ^= BE_ALIEN - /obj/item/slime_cube/proc/reset_search() //We give the players sixty seconds to decide, then reset the timer. icon_state = "slime cube" if(searching == 1) searching = 0 var/turf/T = get_turf_or_move(src.loc) - for (var/mob/M in viewers(T)) + for(var/mob/M in viewers(T)) M.show_message("The activity in the cube dies down. Maybe it will spark another time.") - + /obj/item/slime_cube/proc/transfer_personality(var/mob/candidate) announce_ghost_joinleave(candidate, 0, "They are a promethean now.") src.searching = 2 @@ -53,13 +42,13 @@ Slime cube lives here. S.mind.assigned_role = "Promethean" S.set_species("Promethean") S.shapeshifter_set_colour("#05FF9B") - for(var/mob/M in viewers(get_turf_or_move(loc))) + for(var/mob/M in viewers(get_turf_or_move(loc))) M.show_message("The monkey cube suddenly takes the shape of a humanoid!") var/newname = sanitize(input(S, "You are a Promethean. Would you like to change your name to something else?", "Name change") as null|text, MAX_NAME_LEN) - if (newname) + if(newname) S.real_name = newname S.name = S.real_name S.dna.real_name = newname - if(S.mind) S.mind.name = S.name + if(S.mind) + S.mind.name = S.name qdel(src) - \ No newline at end of file diff --git a/code/stylesheet.dm b/code/stylesheet.dm index 6a94b6c0c9..4b771b2ab2 100644 --- a/code/stylesheet.dm +++ b/code/stylesheet.dm @@ -88,7 +88,7 @@ h1.alert, h2.alert {color: #000000;} .alien {color: #543354;} .tajaran {color: #803B56;} .tajaran_signlang {color: #941C1C;} -.skrell {color: #00CED1;} +.skrell {color: #00B0B3;} .soghun {color: #228B22;} .solcom {color: #22228B;} .changeling {color: #800080;} diff --git a/html/browser/codex.css b/html/browser/codex.css index 3352442a3d..c757b4fc0e 100644 --- a/html/browser/codex.css +++ b/html/browser/codex.css @@ -26,4 +26,9 @@ body { background-color: RoyalBlue; color: white; +} + + +table, th, td { + border: 0px solid black; } \ No newline at end of file diff --git a/html/changelog.html b/html/changelog.html index 2debd89613..cb2923c0f1 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -53,6 +53,83 @@ -->
+

24 September 2017

+

Belsima updated:

+ +

Chaoko99 updated:

+ +

Cyantime updated:

+ +

Nalarac updated:

+ +

Neerti updated:

+ +

PrismaticGynoid updated:

+ +

SpadesNeil updated:

+ +

Woodrat updated:

+ +

26 August 2017

Belsima updated: