From 4f77afece11459d6ce828652596695046749157b Mon Sep 17 00:00:00 2001 From: Neerti Date: Sun, 8 Nov 2015 10:09:14 -0500 Subject: [PATCH] Revert 58ef59734fa5075355940a85c0acf8054c256635 --- code/ZAS/Fire.dm | 44 +- code/ZAS/Variable Settings.dm | 3 +- code/__defines/atmos.dm | 8 +- code/__defines/mobs.dm | 11 - code/_helpers/areas.dm | 21 - code/_helpers/functional.dm | 14 - code/_helpers/lists.dm | 16 +- code/_helpers/turfs.dm | 9 - code/_helpers/unsorted.dm | 25 +- code/_onclick/item_attack.dm | 110 +- code/datums/category.dm | 75 - code/datums/diseases/xeno_transformation.dm | 11 +- code/datums/wires/airlock.dm | 2 +- code/defines/gases.dm | 3 - code/defines/procs/hud.dm | 2 +- code/game/antagonist/_antagonist_setup.dm | 1 - code/game/antagonist/alien/xenomorph.dm | 5 - code/game/antagonist/antagonist.dm | 63 +- code/game/antagonist/antagonist_create.dm | 3 +- code/game/antagonist/antagonist_helpers.dm | 24 +- code/game/antagonist/antagonist_place.dm | 2 +- code/game/antagonist/outsider/deathsquad.dm | 2 +- code/game/antagonist/outsider/ert.dm | 2 +- code/game/antagonist/station/rogue_ai.dm | 4 +- code/game/area/Space Station 13 areas.dm | 8 +- code/game/asteroid.dm | 11 +- code/game/gamemodes/calamity/calamity.dm | 13 +- code/game/gamemodes/changeling/changeling.dm | 1 + code/game/gamemodes/cult/cult.dm | 1 + code/game/gamemodes/cult/cult_items.dm | 30 +- code/game/gamemodes/cult/ritual.dm | 6 +- code/game/gamemodes/epidemic/epidemic.dm | 1 + code/game/gamemodes/game_mode.dm | 16 +- code/game/gamemodes/game_mode_latespawn.dm | 60 +- code/game/gamemodes/heist/heist.dm | 1 + .../game/gamemodes/malfunction/malfunction.dm | 1 + .../newmalf_ability_trees/tree_networking.dm | 9 +- code/game/gamemodes/meme/meme.dm | 1 + code/game/gamemodes/mixed/bughunt.dm | 1 + code/game/gamemodes/mixed/conflux.dm | 1 + code/game/gamemodes/mixed/paranoia.dm | 1 + code/game/gamemodes/mixed/traitorling.dm | 1 + code/game/gamemodes/mixed/uprising.dm | 1 + code/game/gamemodes/ninja/ninja.dm | 3 +- code/game/gamemodes/nuclear/nuclear.dm | 1 + code/game/gamemodes/revolution/revolution.dm | 1 + code/game/gamemodes/wizard/wizard.dm | 1 + code/game/machinery/computer/computer.dm | 9 +- code/game/machinery/doors/airlock.dm | 4 +- code/game/machinery/machinery.dm | 5 +- code/game/machinery/nuclear_bomb.dm | 12 +- code/game/objects/effects/aliens.dm | 414 +- code/game/objects/effects/chem/chemsmoke.dm | 111 +- code/game/objects/effects/landmarks.dm | 4 + .../objects/effects/spawners/bombspawner.dm | 83 +- code/game/objects/items.dm | 9 +- code/game/objects/items/devices/PDA/PDA.dm | 7 +- code/game/objects/items/devices/flash.dm | 24 +- code/game/objects/items/devices/flashlight.dm | 2 - .../game/objects/items/devices/radio/radio.dm | 127 +- .../objects/items/devices/transfer_valve.dm | 49 +- code/game/objects/items/robot/robot_items.dm | 27 +- code/game/objects/items/stacks/medical.dm | 99 +- code/game/objects/items/stacks/stack.dm | 13 +- code/game/objects/items/weapons/cards_ids.dm | 2 +- .../circuitboards/computer/air_management.dm | 112 +- .../circuitboards/computer/holodeckcontrol.dm | 31 - .../game/objects/items/weapons/clown_items.dm | 4 +- .../objects/items/weapons/dna_injector.dm | 3 - code/game/objects/items/weapons/explosives.dm | 1 - .../objects/items/weapons/gift_wrappaper.dm | 3 +- .../items/weapons/grenades/flashbang.dm | 2 +- .../items/weapons/grenades/spawnergrenade.dm | 2 +- code/game/objects/items/weapons/handcuffs.dm | 3 - .../items/weapons/implants/implanter.dm | 10 +- .../objects/items/weapons/material/kitchen.dm | 11 +- .../weapons/material/material_weapons.dm | 5 +- .../objects/items/weapons/material/misc.dm | 1 + code/game/objects/items/weapons/policetape.dm | 211 +- .../objects/items/weapons/storage/boxes.dm | 13 +- .../objects/items/weapons/storage/firstaid.dm | 6 +- .../items/weapons/storage/laundry_basket.dm | 87 - .../objects/items/weapons/storage/storage.dm | 27 +- code/game/objects/items/weapons/stunbaton.dm | 71 +- .../objects/items/weapons/swords_axes_etc.dm | 38 +- .../game/objects/items/weapons/tanks/tanks.dm | 14 +- code/game/objects/items/weapons/tools.dm | 10 +- code/game/objects/items/weapons/weaponry.dm | 39 +- code/game/objects/objs.dm | 6 +- code/game/objects/structures/alien/alien.dm | 61 - code/game/objects/structures/alien/egg.dm | 96 - code/game/objects/structures/alien/node.dm | 19 - code/game/objects/structures/alien/resin.dm | 50 - .../structures/crates_lockers/closets.dm | 9 - .../closets/secure/engineering.dm | 2 +- .../closets/secure/secure_closets.dm | 2 - code/game/objects/structures/inflatable.dm | 7 +- code/game/objects/structures/lamarr_cage.dm | 87 + .../structures/stool_bed_chair_nest/stools.dm | 3 - code/game/objects/structures/window.dm | 18 +- .../game/objects/structures/window_spawner.dm | 7 +- code/global.dm | 1 + code/modules/admin/admin.dm | 7 +- code/modules/admin/admin_attack_log.dm | 5 +- code/modules/admin/topic.dm | 10 + code/modules/admin/verbs/debug.dm | 18 +- code/modules/admin/verbs/mapping.dm | 1 - code/modules/admin/view_variables/topic.dm | 14 + .../preference_setup/antagonism/01_basic.dm | 38 - .../antagonism/02_candidacy.dm | 54 - .../preference_setup/general/01_basic.dm | 90 - .../preference_setup/general/02_language.dm | 93 - .../preference_setup/general/03_body.dm | 498 -- .../preference_setup/general/04_equipment.dm | 146 - .../preference_setup/general/05_background.dm | 125 - .../preference_setup/general/06_flavor.dm | 127 - .../client/preference_setup/global/01_ui.dm | 73 - .../preference_setup/global/02_settings.dm | 38 - .../client/preference_setup/global/03_pai.dm | 54 - .../preference_setup/occupation/occupation.dm | 291 - .../preference_setup/preference_setup.dm | 209 - .../client/preference_setup/skills/skills.dm | 77 - code/modules/client/preferences.dm | 1522 ++++- code/modules/client/preferences_gear.dm | 5 +- code/modules/client/preferences_savefile.dm | 299 +- code/modules/clothing/clothing.dm | 4 +- code/modules/clothing/glasses/glasses.dm | 20 +- code/modules/clothing/glasses/hud.dm | 8 +- code/modules/clothing/head/misc_special.dm | 6 - .../clothing/spacesuits/miscellaneous.dm | 2 +- .../clothing/spacesuits/rig/suits/light.dm | 2 +- .../modules/clothing/spacesuits/spacesuits.dm | 1 - .../clothing/under/accessories/badges.dm | 2 - code/modules/events/blob.dm | 6 +- code/modules/holodeck/HolodeckControl.dm | 80 +- code/modules/holodeck/HolodeckObjects.dm | 3 + code/modules/hydroponics/grown.dm | 76 +- .../hydroponics/spreading/spreading.dm | 23 +- .../hydroponics/trays/tray_reagents.dm | 14 + code/modules/library/lib_items.dm | 1 - code/modules/materials/material_sheets.dm | 5 +- code/modules/materials/materials.dm | 2 + code/modules/mob/dead/observer/observer.dm | 17 +- code/modules/mob/language/language.dm | 6 - code/modules/mob/living/bot/bot.dm | 2 + .../mob/living/carbon/alien/larva/larva.dm | 3 +- .../mob/living/carbon/alien/larva/life.dm | 26 +- .../mob/living/carbon/alien/larva/powers.dm | 111 - code/modules/mob/living/carbon/alien/life.dm | 9 +- .../mob/living/carbon/alien/progression.dm | 9 +- code/modules/mob/living/carbon/breathe.dm | 10 +- .../mob/living/carbon/carbon_defense.dm | 98 - code/modules/mob/living/carbon/human/human.dm | 36 +- .../living/carbon/human/human_attackhand.dm | 17 + .../mob/living/carbon/human/human_defense.dm | 163 +- .../mob/living/carbon/human/human_defines.dm | 8 - .../mob/living/carbon/human/human_helpers.dm | 83 - .../mob/living/carbon/human/human_powers.dm | 15 +- code/modules/mob/living/carbon/human/life.dm | 269 +- .../living/carbon/human/species/species.dm | 46 - .../carbon/human/species/station/station.dm | 16 +- .../human/species/xenomorphs/alien_embryo.dm | 159 + .../species/xenomorphs/alien_facehugger.dm | 7 +- .../human/species/xenomorphs/alien_powers.dm | 58 +- .../human/species/xenomorphs/alien_species.dm | 25 +- .../human/species/xenomorphs/xenomorphs.dm | 25 + .../mob/living/carbon/human/unarmed_attack.dm | 5 +- .../mob/living/carbon/human/update_icons.dm | 4 +- .../mob/living/carbon/metroid/items.dm | 84 + code/modules/mob/living/life.dm | 50 +- code/modules/mob/living/living_defense.dm | 87 +- code/modules/mob/living/silicon/laws.dm | 20 +- .../mob/living/silicon/robot/robot_modules.dm | 20 +- code/modules/mob/living/silicon/say.dm | 57 +- code/modules/mob/living/silicon/silicon.dm | 3 + .../living/simple_animal/friendly/corgi.dm | 8 + .../living/simple_animal/friendly/slime.dm | 5 - .../simple_animal/friendly/spiderbot.dm | 2 +- .../mob/living/simple_animal/simple_animal.dm | 38 +- code/modules/mob/mob_helpers.dm | 6 - code/modules/mob/new_player/new_player.dm | 6 +- .../mob/new_player/preferences_setup.dm | 19 +- code/modules/mob/transform_procs.dm | 24 + code/modules/nano/modules/human_appearance.dm | 2 +- code/modules/organs/organ.dm | 3 - code/modules/organs/organ_external.dm | 47 +- code/modules/organs/subtypes/xenos.dm | 27 +- code/modules/organs/wound.dm | 17 +- code/modules/power/lighting.dm | 5 - code/modules/power/solar.dm | 3 +- code/modules/projectiles/gun.dm | 2 +- .../modules/projectiles/projectile/bullets.dm | 4 +- code/modules/projectiles/projectile/energy.dm | 4 +- code/modules/reagents/Chemistry-Holder.dm | 14 +- code/modules/reagents/Chemistry-Machinery.dm | 28 +- .../Chemistry-Reagents-Food-Drinks.dm | 108 +- .../Chemistry-Reagents-Toxins.dm | 6 +- code/modules/reagents/Chemistry-Recipes.dm | 2 +- code/modules/reagents/dispenser/dispenser2.dm | 11 +- code/modules/reagents/reagent_containers.dm | 7 +- .../reagent_containers/food/condiment.dm | 5 +- .../reagent_containers/food/drinks.dm | 7 +- .../reagent_containers/food/drinks/bottle.dm | 75 +- .../reagent_containers/food/snacks.dm | 45 +- .../reagents/reagent_containers/hypospray.dm | 2 - .../reagents/reagent_containers/pill.dm | 24 +- .../reagents/reagent_containers/syringes.dm | 3 - .../artifact/artifact_unknown.dm | 31 +- code/modules/spells/general/rune_write.dm | 4 - code/modules/spells/targeted/subjugate.dm | 6 +- code/modules/surgery/encased.dm | 10 +- code/modules/surgery/organs_internal.dm | 40 + html/changelog.html | 72 - html/changelogs/.all_changelog.yml | 53 - .../changelogs/HarpyEagle-powercellsanity.yml | 27 + html/changelogs/Hubblenaut-dev.yml | 39 + icons/mob/items/lefthand.dmi | Bin 113612 -> 112747 bytes icons/mob/items/righthand.dmi | Bin 114007 -> 112614 bytes icons/mob/screen1_alien.dmi | Bin 141059 -> 141060 bytes icons/obj/janitor.dmi | Bin 11231 -> 10662 bytes icons/obj/xenoarchaeology.dmi | Bin 70667 -> 64235 bytes icons/policetape.dmi | Bin 3566 -> 2510 bytes maps/colony-2.dmm | 1 - maps/colony-4.dmm | 1 - maps/colony-5.dmm | 123 +- maps/exodus-1.dmm | 5222 +++++++++-------- maps/exodus-2.dmm | 3 +- maps/exodus-4.dmm | 3 +- maps/exodus-5.dmm | 2838 ++++----- maps/polaris-1.dmm | 2 +- maps/polaris-2.dmm | 1 - maps/polaris-4.dmm | 1 - maps/polaris-5.dmm | 1 - nano/templates/radio_basic.tmpl | 110 - polaris.dme | 29 +- 235 files changed, 8451 insertions(+), 9025 deletions(-) delete mode 100644 code/_helpers/areas.dm delete mode 100644 code/_helpers/functional.dm delete mode 100644 code/datums/category.dm delete mode 100644 code/game/objects/items/weapons/circuitboards/computer/holodeckcontrol.dm delete mode 100644 code/game/objects/items/weapons/storage/laundry_basket.dm delete mode 100644 code/game/objects/structures/alien/alien.dm delete mode 100644 code/game/objects/structures/alien/egg.dm delete mode 100644 code/game/objects/structures/alien/node.dm delete mode 100644 code/game/objects/structures/alien/resin.dm create mode 100644 code/game/objects/structures/lamarr_cage.dm delete mode 100644 code/modules/client/preference_setup/antagonism/01_basic.dm delete mode 100644 code/modules/client/preference_setup/antagonism/02_candidacy.dm delete mode 100644 code/modules/client/preference_setup/general/01_basic.dm delete mode 100644 code/modules/client/preference_setup/general/02_language.dm delete mode 100644 code/modules/client/preference_setup/general/03_body.dm delete mode 100644 code/modules/client/preference_setup/general/04_equipment.dm delete mode 100644 code/modules/client/preference_setup/general/05_background.dm delete mode 100644 code/modules/client/preference_setup/general/06_flavor.dm delete mode 100644 code/modules/client/preference_setup/global/01_ui.dm delete mode 100644 code/modules/client/preference_setup/global/02_settings.dm delete mode 100644 code/modules/client/preference_setup/global/03_pai.dm delete mode 100644 code/modules/client/preference_setup/occupation/occupation.dm delete mode 100644 code/modules/client/preference_setup/preference_setup.dm delete mode 100644 code/modules/client/preference_setup/skills/skills.dm delete mode 100644 code/modules/mob/living/carbon/alien/larva/powers.dm delete mode 100644 code/modules/mob/living/carbon/carbon_defense.dm delete mode 100644 code/modules/mob/living/carbon/human/human_helpers.dm create mode 100644 code/modules/mob/living/carbon/human/species/xenomorphs/alien_embryo.dm create mode 100644 html/changelogs/HarpyEagle-powercellsanity.yml create mode 100644 html/changelogs/Hubblenaut-dev.yml delete mode 100644 nano/templates/radio_basic.tmpl diff --git a/code/ZAS/Fire.dm b/code/ZAS/Fire.dm index dba966e9fb9..501c49ae556 100644 --- a/code/ZAS/Fire.dm +++ b/code/ZAS/Fire.dm @@ -1,9 +1,13 @@ /* Making Bombs with ZAS: -Get gas to react in an air tank so that it gains pressure. If it gains enough pressure, it goes boom. -The more pressure, the more boom. -If it gains pressure too slowly, it may leak or just rupture instead of exploding. +Make burny fire with lots of burning +Draw off 5000K gas from burny fire +Separate gas into oxygen and phoron components +Obtain phoron and oxygen tanks filled up about 50-75% with normal-temp gas +Fill rest with super hot gas from separated canisters, they should be about 125C now. +Attach to transfer valve and open. BOOM. + */ //#define FIREDBG @@ -264,16 +268,16 @@ turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0) //determine how far the reaction can progress var/reaction_limit = min(total_oxidizers*(FIRE_REACTION_FUEL_AMOUNT/FIRE_REACTION_OXIDIZER_AMOUNT), total_fuel) //stoichiometric limit + //calculate the firelevel. + var/firelevel = calculate_firelevel(total_fuel, total_oxidizers, reaction_limit) + var/firelevel_ratio = firelevel / vsc.fire_firelevel_multiplier + //vapour fuels are extremely volatile! The reaction progress is a percentage of the total fuel (similar to old zburn).) - var/gas_firelevel = calculate_firelevel(gas_fuel, total_oxidizers, reaction_limit, volume*group_multiplier) / vsc.fire_firelevel_multiplier var/min_burn = 0.30*volume*group_multiplier/CELL_VOLUME //in moles - so that fires with very small gas concentrations burn out fast - var/gas_reaction_progress = min(max(min_burn, gas_firelevel*gas_fuel)*FIRE_GAS_BURNRATE_MULT, gas_fuel) + var/gas_reaction_progress = min(max(min_burn, firelevel_ratio*gas_fuel)*FIRE_GAS_BURNRATE_MULT, gas_fuel) //liquid fuels are not as volatile, and the reaction progress depends on the size of the area that is burning. Limit the burn rate to a certain amount per area. - var/liquid_firelevel = calculate_firelevel(liquid_fuel, total_oxidizers, reaction_limit, 0) / vsc.fire_firelevel_multiplier - var/liquid_reaction_progress = min((liquid_firelevel*0.2 + 0.05)*fuel_area*FIRE_LIQUID_BURNRATE_MULT, liquid_fuel) - - var/firelevel = (gas_fuel*gas_firelevel + liquid_fuel*liquid_firelevel)/total_fuel + var/liquid_reaction_progress = min((firelevel_ratio*0.2 + 0.05)*fuel_area*FIRE_LIQUID_BURNRATE_MULT, liquid_fuel) var/total_reaction_progress = gas_reaction_progress + liquid_reaction_progress var/used_fuel = min(total_reaction_progress, reaction_limit) @@ -282,7 +286,7 @@ turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0) #ifdef FIREDBG log_debug("gas_fuel = [gas_fuel], liquid_fuel = [liquid_fuel], total_oxidizers = [total_oxidizers]") log_debug("fuel_area = [fuel_area], total_fuel = [total_fuel], reaction_limit = [reaction_limit]") - log_debug("firelevel -> [firelevel] (gas: [gas_firelevel], liquid: [liquid_firelevel])") + log_debug("firelevel -> [firelevel] / [vsc.fire_firelevel_multiplier]") log_debug("liquid_reaction_progress = [liquid_reaction_progress]") log_debug("gas_reaction_progress = [gas_reaction_progress]") log_debug("total_reaction_progress = [total_reaction_progress]") @@ -311,13 +315,13 @@ turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0) //calculate the energy produced by the reaction and then set the new temperature of the mix temperature = (starting_energy + vsc.fire_fuel_energy_release * (used_gas_fuel + used_liquid_fuel)) / heat_capacity() - update_values() #ifdef FIREDBG log_debug("used_gas_fuel = [used_gas_fuel]; used_liquid_fuel = [used_liquid_fuel]; total = [used_fuel]") - log_debug("new temperature = [temperature]; new pressure = [return_pressure()]") + log_debug("new temperature = [temperature]") #endif - + + update_values() return firelevel datum/gas_mixture/proc/check_recombustability(list/fuel_objs) @@ -359,31 +363,27 @@ datum/gas_mixture/proc/check_recombustability(list/fuel_objs) break //returns a value between 0 and vsc.fire_firelevel_multiplier -/datum/gas_mixture/proc/calculate_firelevel(total_fuel, total_oxidizers, reaction_limit, gas_volume) +/datum/gas_mixture/proc/calculate_firelevel(total_fuel, total_oxidizers, reaction_limit) //Calculates the firelevel based on one equation instead of having to do this multiple times in different areas. var/firelevel = 0 var/total_combustables = (total_fuel + total_oxidizers) - var/active_combustables = (FIRE_REACTION_OXIDIZER_AMOUNT/FIRE_REACTION_FUEL_AMOUNT + 1)*reaction_limit if(total_combustables > 0) //slows down the burning when the concentration of the reactants is low - var/damping_multiplier = min(1, active_combustables / (total_moles/group_multiplier)) - - //weight the damping mult so that it only really brings down the firelevel when the ratio is closer to 0 - damping_multiplier = 2*damping_multiplier - (damping_multiplier*damping_multiplier) + var/dampening_multiplier = min(1, reaction_limit / (total_moles/group_multiplier)) //calculates how close the mixture of the reactants is to the optimum - //fires burn better when there is more oxidizer -- too much fuel will choke the fire out a bit, reducing firelevel. + //fires burn better when there is more oxidizer -- too much fuel will choke them out a bit, reducing firelevel. var/mix_multiplier = 1 / (1 + (5 * ((total_fuel / total_combustables) ** 2))) #ifdef FIREDBG - ASSERT(damping_multiplier <= 1) + ASSERT(dampening_multiplier <= 1) ASSERT(mix_multiplier <= 1) #endif //toss everything together -- should produce a value between 0 and fire_firelevel_multiplier - firelevel = vsc.fire_firelevel_multiplier * mix_multiplier * damping_multiplier + firelevel = vsc.fire_firelevel_multiplier * mix_multiplier * dampening_multiplier return max( 0, firelevel) diff --git a/code/ZAS/Variable Settings.dm b/code/ZAS/Variable Settings.dm index 7e91a26b3f2..674be3fc5ea 100644 --- a/code/ZAS/Variable Settings.dm +++ b/code/ZAS/Variable Settings.dm @@ -9,8 +9,7 @@ var/global/vs_control/vsc = new var/fire_firelevel_multiplier_NAME = "Fire - Firelevel Constant" var/fire_firelevel_multiplier_DESC = "Multiplied by the equation for firelevel, affects mainly the extingiushing of fires." - //Note that this parameter and the phoron heat capacity have a significant impact on TTV yield. - var/fire_fuel_energy_release = 866000 //J/mol. Adjusted to compensate for fire energy release being fixed, was 397000 + var/fire_fuel_energy_release = 397000 var/fire_fuel_energy_release_NAME = "Fire - Fuel energy release" var/fire_fuel_energy_release_DESC = "The energy in joule released when burning one mol of a burnable substance" diff --git a/code/__defines/atmos.dm b/code/__defines/atmos.dm index 73b323ba77d..e93bf450859 100644 --- a/code/__defines/atmos.dm +++ b/code/__defines/atmos.dm @@ -59,15 +59,15 @@ //These control the speed at which fire burns #define FIRE_GAS_BURNRATE_MULT 1 -#define FIRE_LIQUID_BURNRATE_MULT 0.225 +#define FIRE_LIQUID_BURNRATE_MULT 1 //If the fire is burning slower than this rate then the reaction is going too slow to be self sustaining and the fire burns itself out. //This ensures that fires don't grind to a near-halt while still remaining active forever. #define FIRE_GAS_MIN_BURNRATE 0.01 -#define FIRE_LIQUD_MIN_BURNRATE 0.0025 +#define FIRE_LIQUD_MIN_BURNRATE 0.01 //How many moles of fuel are contained within one solid/liquid fuel volume unit -#define LIQUIDFUEL_AMOUNT_TO_MOL 0.45 //mol/volume unit +#define LIQUIDFUEL_AMOUNT_TO_MOL 1 //mol/volume unit // XGM gas flags. #define XGM_GAS_FUEL 1 @@ -92,4 +92,4 @@ #define ATMOSTANK_OXYGEN 40000 // O2 is also important for airmix, but not as much as N2 as it's only 21% of it. #define ATMOSTANK_CO2 25000 // CO2 and PH are not critically important for station, only for toxins and alternative coolants, no need to store a lot of those. #define ATMOSTANK_PHORON 25000 -#define ATMOSTANK_NITROUSOXIDE 10000 // N2O doesn't have a real useful use, i guess it's on station just to allow refilling of sec's riot control canisters? +#define ATMOSTANK_NITROUSOXIDE 10000 // N2O doesn't have a real useful use, i guess it's on station just to allow refilling of sec's riot control canisters? \ No newline at end of file diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm index c72678fdc84..e99f62d2b79 100644 --- a/code/__defines/mobs.dm +++ b/code/__defines/mobs.dm @@ -82,7 +82,6 @@ // Click cooldown #define DEFAULT_ATTACK_COOLDOWN 8 //Default timeout for aggressive actions -#define DEFAULT_QUICK_COOLDOWN 4 #define MIN_SUPPLIED_LAW_NUMBER 15 @@ -115,13 +114,3 @@ #define MOB_SMALL 10 #define MOB_TINY 5 #define MOB_MINISCULE 1 - -#define TINT_NONE 0 -#define TINT_MODERATE 1 -#define TINT_HEAVY 2 -#define TINT_BLIND 3 - -#define FLASH_PROTECTION_REDUCED -1 -#define FLASH_PROTECTION_NONE 0 -#define FLASH_PROTECTION_MODERATE 1 -#define FLASH_PROTECTION_MAJOR 2 diff --git a/code/_helpers/areas.dm b/code/_helpers/areas.dm deleted file mode 100644 index b5987c0ce16..00000000000 --- a/code/_helpers/areas.dm +++ /dev/null @@ -1,21 +0,0 @@ -//Takes: Area type as text string or as typepath OR an instance of the area. -//Returns: A list of all turfs in areas of that type in the world. -/proc/get_area_turfs(var/areatype, var/list/predicates) - if(!areatype) return null - if(istext(areatype)) areatype = text2path(areatype) - if(isarea(areatype)) - var/area/areatemp = areatype - areatype = areatemp.type - - var/list/turfs = new/list() - for(var/areapath in typesof(areatype)) - var/area/A = locate(areapath) - for(var/turf/T in A.contents) - if(!predicates || all_predicates_true(T, predicates)) - turfs += T - return turfs - -/proc/pick_area_turf(var/areatype, var/list/predicates) - var/list/turfs = get_area_turfs(areatype, predicates) - if(turfs && turfs.len) - return pick(turfs) diff --git a/code/_helpers/functional.dm b/code/_helpers/functional.dm deleted file mode 100644 index c5ecfb631a6..00000000000 --- a/code/_helpers/functional.dm +++ /dev/null @@ -1,14 +0,0 @@ -/proc/all_predicates_true(var/input, var/list/predicates) - for(var/i = 1 to predicates.len) - if(!call(predicates[i])(input)) - return FALSE - return TRUE - -/proc/any_predicate_true(var/input, var/list/predicates) - if(!predicates.len) - return TRUE - - for(var/i = 1 to predicates.len) - if(call(predicates[i])(input)) - return TRUE - return FALSE diff --git a/code/_helpers/lists.dm b/code/_helpers/lists.dm index 3abe6c1aa19..f8a4b12b96d 100644 --- a/code/_helpers/lists.dm +++ b/code/_helpers/lists.dm @@ -71,12 +71,6 @@ proc/isemptylist(list/list) return 1 return 0 -/proc/instances_of_type_in_list(var/atom/A, var/list/L) - var/instances = 0 - for(var/type in L) - if(istype(A, type)) - instances++ - return instances //Checks for specific paths in a list /proc/is_path_in_list(var/atom/A, var/list/L) for(var/path in L) @@ -84,11 +78,11 @@ proc/isemptylist(list/list) return 1 return 0 - -//Empties the list by .Cut(). Setting lenght = 0 has been confirmed to leak references. -proc/clearlist(var/list/L) - if(islist(L)) - L.Cut() +//Empties the list by setting the length to 0. Hopefully the elements get garbage collected +proc/clearlist(list/list) + if(istype(list)) + list.len = 0 + return //Removes any null entries from the list proc/listclearnulls(list/list) diff --git a/code/_helpers/turfs.dm b/code/_helpers/turfs.dm index ca5c60be9d9..85836281143 100644 --- a/code/_helpers/turfs.dm +++ b/code/_helpers/turfs.dm @@ -32,12 +32,3 @@ if(!available_turfs.len) available_turfs = start_turfs return pick(available_turfs) - -/proc/turf_contains_dense_objects(var/turf/T) - return T.contains_dense_objects() - -/proc/not_turf_contains_dense_objects(var/turf/T) - return !turf_contains_dense_objects(T) - -/proc/is_station_turf(var/turf/T) - return T && isStationLevel(T.z) diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index e70e3159b67..fb79b29cb90 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -229,14 +229,14 @@ Turf and target are seperate in case you want to teleport some distance from a t #define LOCATE_COORDS(X, Y, Z) locate(between(1, X, world.maxx), between(1, Y, world.maxy), Z) /proc/getcircle(turf/center, var/radius) //Uses a fast Bresenham rasterization algorithm to return the turfs in a thin circle. if(!radius) return list(center) - + var/x = 0 var/y = radius var/p = 3 - 2 * radius - + . = list() while(y >= x) // only formulate 1/8 of circle - + . += LOCATE_COORDS(center.x - x, center.y - y, center.z) //upper left left . += LOCATE_COORDS(center.x - y, center.y - x, center.z) //upper upper left . += LOCATE_COORDS(center.x + y, center.y - x, center.z) //upper upper right @@ -247,7 +247,7 @@ Turf and target are seperate in case you want to teleport some distance from a t . += LOCATE_COORDS(center.x + x, center.y + y, center.z) //lower right right if(p < 0) - p += 4*x++ + 6; + p += 4*x++ + 6; else p += 4*(x++ - y--) + 10; @@ -558,7 +558,7 @@ Turf and target are seperate in case you want to teleport some distance from a t var/y = min(world.maxy, max(1, A.y + dy)) return locate(x,y,A.z) -//Makes sure MIDDLE is between LOW and HIGH. If not, it adjusts it. Returns the adjusted value. Lower bound takes priority. +//Makes sure MIDDLE is between LOW and HIGH. If not, it adjusts it. Returns the adjusted value. /proc/between(var/low, var/middle, var/high) return max(min(middle, high), low) @@ -718,6 +718,21 @@ proc/GaussRandRound(var/sigma,var/roundto) if(istype(N, areatype)) areas += N return areas +//Takes: Area type as text string or as typepath OR an instance of the area. +//Returns: A list of all turfs in areas of that type of that type in the world. +/proc/get_area_turfs(var/areatype) + if(!areatype) return null + if(istext(areatype)) areatype = text2path(areatype) + if(isarea(areatype)) + var/area/areatemp = areatype + areatype = areatemp.type + + var/list/turfs = new/list() + for(var/area/N in world) + if(istype(N, areatype)) + for(var/turf/T in N) turfs += T + return turfs + //Takes: Area type as text string or as typepath OR an instance of the area. //Returns: A list of all atoms (objs, turfs, mobs) in areas of that type of that type in the world. /proc/get_area_all_atoms(var/areatype) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 3c65b03f736..0cca5569c25 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -1,59 +1,40 @@ -/* -=== Item Click Call Sequences === -These are the default click code call sequences used when clicking on stuff with an item. - -Atoms: - -mob/ClickOn() calls the item's resolve_attackby() proc. -item/resolve_attackby() calls the target atom's attackby() proc. - -Mobs: - -mob/living/attackby() after checking for surgery, calls the item's attack() proc. -item/attack() generates attack logs, sets click cooldown and calls the mob's attacked_with_item() proc. If you override this, consider whether you need to set a click cooldown, play attack animations, and generate logs yourself. -mob/attacked_with_item() should then do mob-type specific stuff (like determining hit/miss, handling shields, etc) and then possibly call the item's apply_hit_effect() proc to actually apply the effects of being hit. - -Item Hit Effects: - -item/apply_hit_effect() can be overriden to do whatever you want. However "standard" physical damage based weapons should make use of the target mob's hit_with_weapon() proc to -avoid code duplication. This includes items that may sometimes act as a standard weapon in addition to having other effects (e.g. stunbatons on harm intent). -*/ // Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown. /obj/item/proc/attack_self(mob/user) return -//I would prefer to rename this to attack(), but that would involve touching hundreds of files. -/obj/item/proc/resolve_attackby(atom/A, mob/user) - add_fingerprint(user) - return A.attackby(src, user) - // No comment /atom/proc/attackby(obj/item/W, mob/user) return /atom/movable/attackby(obj/item/W, mob/user) - if(!(W.flags & NOBLUDGEON)) + if(!(W.flags&NOBLUDGEON)) visible_message("[src] has been hit by [user] with [W].") /mob/living/attackby(obj/item/I, mob/user) - if(!ismob(user)) - return 0 - if(can_operate(src) && do_surgery(src,user,I)) //Surgery - return 1 - return I.attack(src, user, user.zone_sel.selecting) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(istype(I) && ismob(user)) + I.attack(src, user) + // Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person. // Click parameters is the params string from byond Click() code, see that documentation. /obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters) return -//I would prefer to rename this attack_as_weapon(), but that would involve touching hundreds of files. -/obj/item/proc/attack(mob/living/M, mob/living/user, var/target_zone) - if(!force || (flags & NOBLUDGEON)) - return 0 - if(M == user && user.a_intent != I_HURT) - return 0 +//TODO: refactor mob attack code. +/* +Busy writing something else that I don't want to get mixed up in a general attack code, and I don't want to forget this so leaving a note here. +leave attackby() as handling the general case of "using an item on a mob" +attackby() will decide to call attacked_by() or not. +attacked_by() will be made a living level proc and handle the specific case of "attacking with an item to cause harm" +attacked_by() will then call attack() so that stunbatons and other weapons that have special attack effects can do their thing. +attacked_by() will handle hitting/missing/logging as it does now, and will call attack() to apply the attack effects (damage) instead of the other way around (as it is now). +*/ + +/obj/item/proc/attack(mob/living/M as mob, mob/living/user as mob, def_zone) + + if(!istype(M) || (can_operate(M) && do_surgery(M,user,src))) return 0 ///////////////////////// user.lastattacked = M @@ -65,22 +46,49 @@ avoid code duplication. This includes items that may sometimes act as a standard msg_admin_attack("[key_name(user)] attacked [key_name(M)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" ) ///////////////////////// - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.do_attack_animation(M) + // Attacking someone with a weapon while they are neck-grabbed + if(user.a_intent == I_HURT) + for(var/obj/item/weapon/grab/G in M.grabbed_by) + if(G.assailant == user && G.state >= GRAB_NECK) + M.attack_throat(src, G, user) - var/hit_zone = M.resolve_item_attack(src, user, target_zone) - if(hit_zone) - apply_hit_effect(M, user, hit_zone) - - return 1 - -//Called when a weapon is used to make a successful melee attack on a mob. Returns the blocked result -/obj/item/proc/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) - if(hitsound) - playsound(loc, hitsound, 50, 1, -1) - var/power = force if(HULK in user.mutations) power *= 2 - return target.hit_with_weapon(src, user, power, hit_zone) + // TODO: needs to be refactored into a mob/living level attacked_by() proc. ~Z + user.do_attack_animation(M) + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + + // Handle striking to cripple. + var/dislocation_str + if(user.a_intent == I_DISARM) + dislocation_str = H.attack_joint(src, user, def_zone) + if(H.attacked_by(src, user, def_zone) && hitsound) + playsound(loc, hitsound, 50, 1, -1) + spawn(1) //ugh I hate this but I don't want to root through human attack procs to print it after this call resolves. + if(dislocation_str) user.visible_message("[dislocation_str]") + return 1 + return 0 + else + if(attack_verb.len) + user.visible_message("[M] has been [pick(attack_verb)] with [src] by [user]!") + else + user.visible_message("[M] has been attacked with [src] by [user]!") + + if (hitsound) + playsound(loc, hitsound, 50, 1, -1) + switch(damtype) + if("brute") + M.take_organ_damage(power) + if(prob(33)) // Added blood for whacking non-humans too + var/turf/simulated/location = get_turf(M) + if(istype(location)) location.add_blood_floor(M) + if("fire") + if (!(COLD_RESISTANCE in M.mutations)) + M.take_organ_damage(0, power) + M << "Aargh it burns!" + M.updatehealth() + add_fingerprint(user) + return 1 diff --git a/code/datums/category.dm b/code/datums/category.dm deleted file mode 100644 index 01cbc21386a..00000000000 --- a/code/datums/category.dm +++ /dev/null @@ -1,75 +0,0 @@ -/********************** -* Category Collection * -**********************/ -/datum/category_collection - var/category_group_type // The type of categories to initialize - var/list/datum/category_group/categories // The list of initialized categories - -/datum/category_collection/New() - ..() - categories = new() - for(var/category_type in typesof(category_group_type)) - var/datum/category_group/category = category_type - if(initial(category.name)) - category = new category(src) - categories += category - categories = dd_sortedObjectList(categories) - -/datum/category_collection/Destroy() - for(var/category in categories) - qdel(category) - categories.Cut() - return ..() - -/****************** -* Category Groups * -******************/ -/datum/category_group - var/name = "" - var/category_item_type // The type of items to initialize - var/list/datum/category_item/items // The list of initialized items - var/datum/category_collection/collection // The collection this group belongs to - -/datum/category_group/New(var/datum/category_collection/cc) - ..() - collection = cc - items = new() - - for(var/item_type in typesof(category_item_type)) - var/datum/category_item/item = item_type - if(initial(item.name)) - item = new item(src) - items += item - - // For whatever reason dd_insertObjectList(items, item) doesn't insert in the correct order - // If you change this, confirm that character setup doesn't become completely unordered. - items = dd_sortedObjectList(items) - -/datum/category_group/Destroy() - for(var/item in items) - qdel(item) - items.Cut() - collection = null - return ..() - -datum/category_group/dd_SortValue() - return name - - -/***************** -* Category Items * -*****************/ -/datum/category_item - var/name = "" - var/list/datum/category_group/category // The group this item belongs to - -/datum/category_item/New(var/datum/category_group/cg) - ..() - category = cg - -/datum/category_item/Destroy() - category = null - return ..() - -datum/category_item/dd_SortValue() - return name diff --git a/code/datums/diseases/xeno_transformation.dm b/code/datums/diseases/xeno_transformation.dm index 172a62c08e1..d6fa155cfcd 100644 --- a/code/datums/diseases/xeno_transformation.dm +++ b/code/datums/diseases/xeno_transformation.dm @@ -53,12 +53,9 @@ affected_mob.updatehealth() if(prob(40)) if(gibbed != 0) return 0 + var/turf/T = find_loc(affected_mob) + gibs(T) src.cure(0) gibbed = 1 - var/mob/living/carbon/human/H = affected_mob - if(istype(H)) - var/turf/origin = find_loc(affected_mob) - gibs(origin) - H.set_species("Xenomorph [pick(list("Hunter","Sentinel","Drone"))]") - return - affected_mob.gib() \ No newline at end of file + affected_mob:Alienize() + diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm index 85546a79d75..3c247d6c7f9 100644 --- a/code/datums/wires/airlock.dm +++ b/code/datums/wires/airlock.dm @@ -41,7 +41,7 @@ var/const/AIRLOCK_WIRE_LIGHT = 2048 (A.locked ? "The door bolts have fallen!" : "The door bolts look up."), ((A.lights && haspower) ? "The door bolt lights are on." : "The door bolt lights are off!"), ((haspower) ? "The test light is on." : "The test light is off!"), - ((A.backup_power_lost_until) ? "The backup power light is off!" : "The backup power light is on."), + ((A.backupPowerCablesCut()) ? "The backup power light is off!" : "The backup power light is on."), ((A.aiControlDisabled==0 && !A.emagged && haspower)? "The 'AI control allowed' light is on." : "The 'AI control allowed' light is off."), ((A.safe==0 && haspower)? "The 'Check Wiring' light is on." : "The 'Check Wiring' light is off."), ((A.normalspeed==0 && haspower)? "The 'Check Timing Mechanism' light is on." : "The 'Check Timing Mechanism' light is off."), diff --git a/code/defines/gases.dm b/code/defines/gases.dm index 659bd2e21ae..1f8c871ad3f 100644 --- a/code/defines/gases.dm +++ b/code/defines/gases.dm @@ -21,9 +21,6 @@ /decl/xgm_gas/phoron id = "phoron" name = "Phoron" - - //Note that this has a significant impact on TTV yield. - //Because it is so high, any leftover phoron soaks up a lot of heat and drops the yield pressure. specific_heat = 200 // J/(mol*K) //Hypothetical group 14 (same as carbon), period 8 element. diff --git a/code/defines/procs/hud.dm b/code/defines/procs/hud.dm index ae099c64be9..e5560e5ce05 100644 --- a/code/defines/procs/hud.dm +++ b/code/defines/procs/hud.dm @@ -61,7 +61,7 @@ proc/can_process_hud(var/mob/M) return 1 //Deletes the current HUD images so they can be refreshed with new ones. -mob/proc/handle_hud_glasses() //Used in the life.dm of mobs that can use HUDs. +mob/proc/handle_regular_hud_updates() //Used in the life.dm of mobs that can use HUDs. if(client) for(var/image/hud in client.images) if(copytext(hud.icon_state,1,4) == "hud") diff --git a/code/game/antagonist/_antagonist_setup.dm b/code/game/antagonist/_antagonist_setup.dm index a5212256026..fa99f001f32 100644 --- a/code/game/antagonist/_antagonist_setup.dm +++ b/code/game/antagonist/_antagonist_setup.dm @@ -26,7 +26,6 @@ #define ANTAG_RANDSPAWN 256 // Potentially randomly spawns due to events. #define ANTAG_VOTABLE 512 // Can be voted as an additional antagonist before roundstart. #define ANTAG_SET_APPEARANCE 1024 // Causes antagonists to use an appearance modifier on spawn. -#define ANTAG_RANDOM_EXCEPTED 2048 // If a game mode randomly selects antag types, antag types with this flag should be excluded. // Globals. var/global/list/all_antag_types = list() diff --git a/code/game/antagonist/alien/xenomorph.dm b/code/game/antagonist/alien/xenomorph.dm index 36f5216045a..08cbeebca9e 100644 --- a/code/game/antagonist/alien/xenomorph.dm +++ b/code/game/antagonist/alien/xenomorph.dm @@ -11,11 +11,6 @@ var/datum/antagonist/xenos/xenomorphs welcome_text = "Hiss! You are a larval alien. Hide and bide your time until you are ready to evolve." antaghud_indicator = "hudalien" - faction_role_text = "Xenomorph Thrall" - faction_descriptor = "Hive" - faction_welcome = "Your will is ripped away as your humanity merges with the xenomorph overmind. You are now \ - a thrall to the queen and her brood. Obey their instructions without question. Serve the hive." - hard_cap = 5 hard_cap_round = 8 initial_spawn_req = 4 diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm index 011ae5ebe6c..faf7526a9cb 100644 --- a/code/game/antagonist/antagonist.dm +++ b/code/game/antagonist/antagonist.dm @@ -86,8 +86,7 @@ /datum/antagonist/proc/tick() return 1 -// Get the raw list of potential players. -/datum/antagonist/proc/build_candidate_list(var/ghosts_only) +/datum/antagonist/proc/get_candidates(var/ghosts_only) candidates = list() // Clear. // Prune restricted status. Broke it up for readability. @@ -109,57 +108,46 @@ return candidates /datum/antagonist/proc/attempt_random_spawn() - update_current_antag_max() build_candidate_list(flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB)) attempt_spawn() finalize_spawn() -/datum/antagonist/proc/attempt_auto_spawn() +/datum/antagonist/proc/attempt_late_spawn(var/datum/mind/player) if(!can_late_spawn()) return 0 - - update_current_antag_max() - var/active_antags = get_active_antag_count() - log_debug("[uppertext(id)]: Found [active_antags]/[cur_max] active [role_text_plural].") - - if(active_antags >= cur_max) - log_debug("Could not auto-spawn a [role_text], active antag limit reached.") + if(!istype(player)) + var/list/players = get_candidates(is_latejoin_template()) + if(players && players.len) + player = pick(players) + if(!istype(player)) + message_admins("AUTO[uppertext(ticker.mode.name)]: Failed to find a candidate for [role_text].") return 0 - - build_candidate_list(flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB)) - if(!candidates.len) - log_debug("Could not auto-spawn a [role_text], no candidates found.") - return 0 - - attempt_spawn(1) //auto-spawn antags one at a time - if(!pending_antagonists.len) - log_debug("Could not auto-spawn a [role_text], none of the available candidates could be selected.") - return 0 - - var/datum/mind/player = pending_antagonists[1] - if(!add_antagonist(player,0,0,0,1,1)) - log_debug("Could not auto-spawn a [role_text], failed to add antagonist.") - return 0 - - reset_antag_selection() - + player.current << "You have been selected this round as an antagonist!" + message_admins("AUTO[uppertext(ticker.mode.name)]: Selected [player] as a [role_text].") + if(istype(player.current, /mob/dead)) + create_default(player.current) + else + add_antagonist(player,0,0,0,1,1) return 1 +/datum/antagonist/proc/build_candidate_list(var/ghosts_only) + // Get the raw list of potential players. + update_current_antag_max() + candidates = get_candidates(ghosts_only) + //Selects players that will be spawned in the antagonist role from the potential candidates //Selected players are added to the pending_antagonists lists. //Attempting to spawn an antag role with ANTAG_OVERRIDE_JOB should be done before jobs are assigned, //so that they do not occupy regular job slots. All other antag roles should be spawned after jobs are //assigned, so that job restrictions can be respected. -/datum/antagonist/proc/attempt_spawn(var/spawn_target = null) - if(spawn_target == null) - spawn_target = initial_spawn_target +/datum/antagonist/proc/attempt_spawn(var/rebuild_candidates = 1) // Update our boundaries. if(!candidates.len) return 0 //Grab candidates randomly until we have enough. - while(candidates.len && pending_antagonists.len < spawn_target) + while(candidates.len && pending_antagonists.len < initial_spawn_target) var/datum/mind/player = pick(candidates) candidates -= player draft_antagonist(player) @@ -198,16 +186,11 @@ for(var/datum/mind/player in pending_antagonists) pending_antagonists -= player add_antagonist(player,0,0,1) - - reset_antag_selection() -//Resets the antag selection, clearing all pending_antagonists and their special_role -//(and assigned_role if ANTAG_OVERRIDE_JOB is set) as well as clearing the candidate list. -//Existing antagonists are left untouched. -/datum/antagonist/proc/reset_antag_selection() +//Resets all pending_antagonists, clearing their special_role (and assigned_role if ANTAG_OVERRIDE_JOB is set) +/datum/antagonist/proc/reset() for(var/datum/mind/player in pending_antagonists) if(flags & ANTAG_OVERRIDE_JOB) player.assigned_role = null player.special_role = null pending_antagonists.Cut() - candidates.Cut() diff --git a/code/game/antagonist/antagonist_create.dm b/code/game/antagonist/antagonist_create.dm index bbae60800ef..072dd88bee4 100644 --- a/code/game/antagonist/antagonist_create.dm +++ b/code/game/antagonist/antagonist_create.dm @@ -16,8 +16,7 @@ create_objectives(target) update_icons_added(target) greet(target) - if(!gag_announcement) - announce_antagonist_spawn() + announce_antagonist_spawn() /datum/antagonist/proc/create_default(var/mob/source) var/mob/living/M diff --git a/code/game/antagonist/antagonist_helpers.dm b/code/game/antagonist/antagonist_helpers.dm index 1a3f9aa67d0..056fbd18651 100644 --- a/code/game/antagonist/antagonist_helpers.dm +++ b/code/game/antagonist/antagonist_helpers.dm @@ -20,17 +20,6 @@ /datum/antagonist/proc/get_antag_count() return current_antagonists ? current_antagonists.len : 0 -/datum/antagonist/proc/get_active_antag_count() - var/active_antags = 0 - for(var/datum/mind/player in current_antagonists) - var/mob/living/L = player.current - if(!L || L.stat == DEAD) - continue //no mob or dead - if(!L.client && !L.teleop) - continue //SSD - active_antags++ - return active_antags - /datum/antagonist/proc/is_antagonist(var/datum/mind/player) if(player in current_antagonists) return 1 @@ -44,15 +33,10 @@ return (flags & ANTAG_VOTABLE) /datum/antagonist/proc/can_late_spawn() + update_current_antag_max() + if(get_antag_count() >= cur_max) + return 0 return 1 /datum/antagonist/proc/is_latejoin_template() - return (flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB)) - -/proc/all_random_antag_types() - // No caching as the ANTAG_RANDOM_EXCEPTED flag can be added/removed mid-round. - var/list/antag_candidates = all_antag_types.Copy() - for(var/datum/antagonist/antag in antag_candidates) - if(antag.flags & ANTAG_RANDOM_EXCEPTED) - antag_candidates -= antag - return antag_candidates + return (flags & (ANTAG_OVERRIDE_MOB|ANTAG_OVERRIDE_JOB)) \ No newline at end of file diff --git a/code/game/antagonist/antagonist_place.dm b/code/game/antagonist/antagonist_place.dm index 11ea718f8cc..b5f62868dc5 100644 --- a/code/game/antagonist/antagonist_place.dm +++ b/code/game/antagonist/antagonist_place.dm @@ -23,5 +23,5 @@ /datum/antagonist/proc/place_mob(var/mob/living/mob) if(!starting_locations || !starting_locations.len) return - var/turf/T = pick_mobless_turf_if_exists(starting_locations) + var/turf/T = pick_mobless_turf_if_exists(mob) mob.forceMove(T) diff --git a/code/game/antagonist/outsider/deathsquad.dm b/code/game/antagonist/outsider/deathsquad.dm index ca0b39aaefe..4cc8afff6ce 100644 --- a/code/game/antagonist/outsider/deathsquad.dm +++ b/code/game/antagonist/outsider/deathsquad.dm @@ -7,7 +7,7 @@ var/datum/antagonist/deathsquad/deathsquad role_text_plural = "Death Commandos" welcome_text = "You work in the service of corporate Asset Protection, answering directly to the Board of Directors." landmark_id = "Commando" - flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_HAS_NUKE | ANTAG_HAS_LEADER | ANTAG_RANDOM_EXCEPTED + flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_HAS_NUKE | ANTAG_HAS_LEADER default_access = list(access_cent_general, access_cent_specops, access_cent_living, access_cent_storage) antaghud_indicator = "huddeathsquad" diff --git a/code/game/antagonist/outsider/ert.dm b/code/game/antagonist/outsider/ert.dm index e8517dbf4e8..98a44442dc6 100644 --- a/code/game/antagonist/outsider/ert.dm +++ b/code/game/antagonist/outsider/ert.dm @@ -11,7 +11,7 @@ var/datum/antagonist/ert/ert landmark_id = "Response Team" id_type = /obj/item/weapon/card/id/centcom/ERT - flags = ANTAG_OVERRIDE_JOB | ANTAG_SET_APPEARANCE | ANTAG_HAS_LEADER | ANTAG_CHOOSE_NAME | ANTAG_RANDOM_EXCEPTED + flags = ANTAG_OVERRIDE_JOB | ANTAG_SET_APPEARANCE | ANTAG_HAS_LEADER | ANTAG_CHOOSE_NAME antaghud_indicator = "hudloyalist" hard_cap = 5 diff --git a/code/game/antagonist/station/rogue_ai.dm b/code/game/antagonist/station/rogue_ai.dm index 4240708cc22..c17b6c0f86b 100644 --- a/code/game/antagonist/station/rogue_ai.dm +++ b/code/game/antagonist/station/rogue_ai.dm @@ -22,11 +22,13 @@ var/datum/antagonist/rogue_ai/malf malf = src -/datum/antagonist/rogue_ai/build_candidate_list() +/datum/antagonist/rogue_ai/get_candidates() ..() for(var/datum/mind/player in candidates) if(player.assigned_role && player.assigned_role != "AI") candidates -= player + if(!candidates.len) + return list() return candidates diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 535161e08ab..6aadd775e30 100755 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -61,8 +61,8 @@ var/list/teleportlocs = list() for(var/area/AR in world) if(istype(AR, /area/shuttle) || istype(AR, /area/syndicate_station) || istype(AR, /area/wizard_station)) continue if(teleportlocs.Find(AR.name)) continue - var/turf/picked = pick_area_turf(AR.type, list(/proc/is_station_turf)) - if (picked) + var/turf/picked = pick(get_area_turfs(AR.type)) + if (picked.z in config.station_levels) teleportlocs += AR.name teleportlocs[AR.name] = AR @@ -78,8 +78,8 @@ var/list/ghostteleportlocs = list() if(istype(AR, /area/turret_protected/aisat) || istype(AR, /area/derelict) || istype(AR, /area/tdome) || istype(AR, /area/shuttle/specops/centcom)) ghostteleportlocs += AR.name ghostteleportlocs[AR.name] = AR - var/turf/picked = pick_area_turf(AR.type, list(/proc/is_station_turf)) - if (picked) + var/turf/picked = pick(get_area_turfs(AR.type)) + if (picked.z in config.player_levels) ghostteleportlocs += AR.name ghostteleportlocs[AR.name] = AR diff --git a/code/game/asteroid.dm b/code/game/asteroid.dm index 350401df132..795970068c4 100644 --- a/code/game/asteroid.dm +++ b/code/game/asteroid.dm @@ -1,5 +1,6 @@ -var/global/list/space_surprises = list( /obj/item/weapon/pickaxe/silver =4, +var/global/list/space_surprises = list( /obj/item/clothing/mask/facehugger =4, + /obj/item/weapon/pickaxe/silver =4, /obj/item/weapon/pickaxe/drill =4, /obj/item/weapon/pickaxe/jackhammer =4, //mob/living/simple_animal/hostile/carp =3, @@ -21,7 +22,7 @@ proc/spawn_room(var/atom/start_loc,var/x_size,var/y_size,var/wall,var/floor , va //world << "Room spawned at [start_loc.x],[start_loc.y],[start_loc.z]" if(!wall) - wall = pick(/turf/simulated/wall/r_wall,/turf/simulated/wall,/obj/structure/alien/resin) + wall = pick(/turf/simulated/wall/r_wall,/turf/simulated/wall,/obj/effect/alien/resin) if(!floor) floor = pick(/turf/simulated/floor,/turf/simulated/floor/tiled,/turf/simulated/floor/reinforced) @@ -42,9 +43,9 @@ proc/spawn_room(var/atom/start_loc,var/x_size,var/y_size,var/wall,var/floor , va if(x == 0 || x==x_size-1 || y==0 || y==y_size-1) - if(wall == /obj/structure/alien/resin) + if(wall == /obj/effect/alien/resin) T = new floor(cur_loc) - new /obj/structure/alien/resin(T) + new /obj/effect/alien/resin(T) else T = new wall(cur_loc) room_turfs["walls"] += T @@ -72,7 +73,7 @@ proc/admin_spawn_room_at_pos() if("Regular wall") wall=/turf/simulated/wall if("Resin wall") - wall=/obj/structure/alien/resin + wall=/obj/effect/alien/resin switch(alert("Floor type",null,"Regular floor","Reinforced floor")) if("Regular floor") floor=/turf/simulated/floor/tiled diff --git a/code/game/gamemodes/calamity/calamity.dm b/code/game/gamemodes/calamity/calamity.dm index b17277aaae9..4f7b9ab49de 100644 --- a/code/game/gamemodes/calamity/calamity.dm +++ b/code/game/gamemodes/calamity/calamity.dm @@ -11,17 +11,18 @@ event_delay_mod_major = 0.75 /datum/game_mode/calamity/create_antagonists() - var/list/antag_candidates = all_random_antag_types() + shuffle(all_antag_types) // This is probably the only instance in the game where the order will be important. + var/i = 1 var/grab_antags = round(num_players()/ANTAG_TYPE_RATIO)+1 - while(antag_candidates.len && antag_tags.len < grab_antags) - var/antag_id = pick(antag_candidates) - antag_candidates -= antag_id + for(var/antag_id in all_antag_types) + if(i > grab_antags) + break antag_tags |= antag_id - + i++ ..() /datum/game_mode/calamity/check_victory() world << "This terrible, terrible day has finally ended!" -#undef ANTAG_TYPE_RATIO +#undef ANTAG_TYPE_RATIO \ No newline at end of file diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index bf68c71823f..ba82a064f66 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -12,6 +12,7 @@ certain though... there is never just one of them. Good luck." config_tag = "changeling" required_players = 2 + required_players_secret = 10 required_enemies = 1 end_on_antag_death = 0 antag_scaling_coeff = 10 diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index bbff09a6363..c3ffef61bb7 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -4,6 +4,7 @@ extended_round_description = "The station has been infiltrated by a fanatical group of death-cultists! They will use powers from beyond your comprehension to subvert you to their cause and ultimately please their gods through sacrificial summons and physical immolation! Try to survive!" config_tag = "cult" required_players = 5 + required_players_secret = 15 required_enemies = 3 end_on_antag_death = 0 antag_tags = list(MODE_CULTIST) diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm index afa21ebc1e9..70e2219440a 100644 --- a/code/game/gamemodes/cult/cult_items.dm +++ b/code/game/gamemodes/cult/cult_items.dm @@ -6,35 +6,23 @@ w_class = 4 force = 30 throwforce = 10 - hitsound = 'sound/weapons/bladeslice.ogg' attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") /obj/item/weapon/melee/cultblade/cultify() return -/obj/item/weapon/melee/cultblade/attack(mob/living/M, mob/living/user, var/target_zone) +/obj/item/weapon/melee/cultblade/attack(mob/living/target as mob, mob/living/carbon/human/user as mob) if(iscultist(user)) + playsound(loc, 'sound/weapons/bladeslice.ogg', 50, 1, -1) return ..() - - var/zone = (user.hand ? "l_arm":"r_arm") - if(ishuman(user)) - var/mob/living/carbon/human/H = user - var/obj/item/organ/external/affecting = H.get_organ(zone) - user << "An unexplicable force rips through your [affecting.name], tearing the sword from your grasp!" else - user << "An unexplicable force rips through you, tearing the sword from your grasp!" - - //random amount of damage between half of the blade's force and the full force of the blade. - user.apply_damage(rand(force/2, force), BRUTE, zone, 0, sharp=1, edge=1) - user.Weaken(5) - - user.drop_from_inventory(src) - throw_at(get_edge_target_turf(src, pick(alldirs)), rand(1,3), throw_speed) - - var/spooky = pick('sound/hallucinations/growl1.ogg', 'sound/hallucinations/growl2.ogg', 'sound/hallucinations/growl3.ogg', 'sound/hallucinations/wail.ogg') - playsound(loc, spooky, 50, 1) - - return 1 + user.Paralyse(5) + user << "An unexplicable force powerfully repels the sword from [target]!" + var/organ = ((user.hand ? "l_":"r_") + "arm") + var/obj/item/organ/external/affecting = user.get_organ(organ) + if(affecting.take_damage(rand(force/2, force))) //random amount of damage between half of the blade's force and the full force of the blade. + user.UpdateDamageIcon() + return /obj/item/weapon/melee/cultblade/pickup(mob/living/user as mob) if(!iscultist(user)) diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm index 932719c8564..cba7a96ef4a 100644 --- a/code/game/gamemodes/cult/ritual.dm +++ b/code/game/gamemodes/cult/ritual.dm @@ -527,11 +527,7 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa"," user << "You do not have enough space to write a proper rune." var/list/runes = list("teleport", "itemport", "tome", "armor", "convert", "tear in reality", "emp", "drain", "seer", "raise", "obscure", "reveal", "astral journey", "manifest", "imbue talisman", "sacrifice", "wall", "freedom", "cultsummon", "deafen", "blind", "bloodboil", "communicate", "stun") r = input("Choose a rune to scribe", "Rune Scribing") in runes //not cancellable. - if(locate(/obj/effect/rune) in user.loc) - user << "There is already a rune in this location." - return - - var/obj/effect/rune/R = new /obj/effect/rune(user.loc) + var/obj/effect/rune/R = new /obj/effect/rune if(istype(user, /mob/living/carbon/human)) var/mob/living/carbon/human/H = user R.blood_DNA = list() diff --git a/code/game/gamemodes/epidemic/epidemic.dm b/code/game/gamemodes/epidemic/epidemic.dm index 05b2d484376..4f98bbcc2bb 100644 --- a/code/game/gamemodes/epidemic/epidemic.dm +++ b/code/game/gamemodes/epidemic/epidemic.dm @@ -2,6 +2,7 @@ name = "epidemic" config_tag = "epidemic" required_players = 1 + required_players_secret = 15 round_description = "A deadly epidemic is spreading on the station. Find a cure as fast as possible, and keep your distance to anyone who speaks in a hoarse voice!" var/cruiser_arrival diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 881dea4dbd4..412e9033d4d 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -10,6 +10,7 @@ var/global/list/additional_antag_types = list() var/probability = 0 var/required_players = 0 // Minimum players for round to start if voted in. + var/required_players_secret = 0 // Minimum number of players for that game mode to be chose in Secret var/required_enemies = 0 // Minimum antagonists for round to start. var/newscaster_announcements = null var/end_on_antag_death = 0 // Round will end when all antagonists are dead. @@ -21,6 +22,7 @@ var/global/list/additional_antag_types = list() var/list/antag_tags = list() // Core antag templates to spawn. var/list/antag_templates // Extra antagonist types to include. + var/list/latejoin_templates = list() var/round_autoantag = 0 // Will this round attempt to periodically spawn more antagonists? var/antag_scaling_coeff = 5 // Coefficient for scaling max antagonists to player count. var/require_all_templates = 0 // Will only start if all templates are checked and can spawn. @@ -145,8 +147,12 @@ var/global/list/additional_antag_types = list() if((player.client)&&(player.ready)) playerC++ - if(playerC < required_players) - return 0 + if(master_mode=="secret") + if(playerC < required_players_secret) + return 0 + else + if(playerC < required_players) + return 0 if(!(antag_templates && antag_templates.len)) return 1 @@ -182,7 +188,6 @@ var/global/list/additional_antag_types = list() /datum/game_mode/proc/pre_setup() for(var/datum/antagonist/antag in antag_templates) - antag.update_current_antag_max() antag.build_candidate_list() //compile a list of all eligible candidates //antag roles that replace jobs need to be assigned before the job controller hands out jobs. @@ -207,6 +212,8 @@ var/global/list/additional_antag_types = list() if(!(antag.flags & ANTAG_OVERRIDE_JOB)) antag.attempt_spawn() //select antags to be spawned antag.finalize_spawn() //actually spawn antags + if(antag.is_latejoin_template()) + latejoin_templates |= antag if(emergency_shuttle && auto_recall_shuttle) emergency_shuttle.auto_recall = 1 @@ -219,7 +226,7 @@ var/global/list/additional_antag_types = list() /datum/game_mode/proc/fail_setup() for(var/datum/antagonist/antag in antag_templates) - antag.reset_antag_selection() + antag.reset() /datum/game_mode/proc/announce_ert_disabled() if(!ert_disabled) @@ -491,7 +498,6 @@ var/global/list/additional_antag_types = list() if(antag) antag_templates |= antag - shuffle(antag_templates) //In the case of multiple antag types newscaster_announcements = pick(newscaster_standard_feeds) /datum/game_mode/proc/check_victory() diff --git a/code/game/gamemodes/game_mode_latespawn.dm b/code/game/gamemodes/game_mode_latespawn.dm index 9c79a689251..038cf351ab8 100644 --- a/code/game/gamemodes/game_mode_latespawn.dm +++ b/code/game/gamemodes/game_mode_latespawn.dm @@ -3,39 +3,55 @@ /datum/game_mode/var/max_autotraitor_delay = 12000 // Approx 20 minutes. /datum/game_mode/var/process_count = 0 +/datum/game_mode/proc/get_usable_templates(var/list/supplied_templates) + var/list/usable_templates = list() + for(var/datum/antagonist/A in supplied_templates) + if(A.can_late_spawn()) + message_admins("AUTO[uppertext(name)]: [A.id] selected for spawn attempt.") + usable_templates |= A + return usable_templates + ///process() ///Called by the gameticker /datum/game_mode/proc/process() - if(round_autoantag && world.time < next_spawn && !emergency_shuttle.departed) - process_autoantag() + // Slow this down a bit so latejoiners have a chance of being antags. + process_count++ + if(process_count >= 10) + process_count = 0 + try_latespawn() -//This can be overriden in case a game mode needs to do stuff when a player latejoins -/datum/game_mode/proc/handle_latejoin(var/mob/living/carbon/human/character) +/datum/game_mode/proc/latespawn(var/mob/living/carbon/human/character) + if(!character.mind) + return + try_latespawn(character.mind) return 0 -/datum/game_mode/proc/process_autoantag() - message_admins("[uppertext(name)]: Attempting autospawn.") +/datum/game_mode/proc/try_latespawn(var/datum/mind/player, var/latejoin_only) - var/list/usable_templates = list() - for(var/datum/antagonist/A in antag_templates) - if(A.can_late_spawn()) - message_admins("[uppertext(name)]: [A.id] selected for spawn attempt.") - usable_templates |= A - - if(!usable_templates.len) - message_admins("[uppertext(name)]: Failed to find configured mode spawn templates, please re-enable auto-antagonists after one is added.") + if(emergency_shuttle.departed || !round_autoantag) + return + + if(world.time < next_spawn) + return + + message_admins("AUTO[uppertext(name)]: Attempting spawn.") + + var/list/usable_templates + if(latejoin_only && latejoin_templates.len) + usable_templates = get_usable_templates(latejoin_templates) + else if (antag_templates && antag_templates.len) + usable_templates = get_usable_templates(antag_templates) + else + message_admins("AUTO[uppertext(name)]: Failed to find configured mode spawn templates, please disable auto-antagonists until one is added.") round_autoantag = 0 return - + while(usable_templates.len) var/datum/antagonist/spawn_antag = pick(usable_templates) usable_templates -= spawn_antag - - if(spawn_antag.attempt_auto_spawn()) - message_admins("[uppertext(name)]: Auto-added a new [spawn_antag.role_text].") - message_admins("There are now [spawn_antag.get_active_antag_count()]/[spawn_antag.cur_max] active [spawn_antag.role_text_plural].") + if(spawn_antag.attempt_late_spawn(player)) + message_admins("AUTO[uppertext(name)]: Attempting to latespawn [spawn_antag.id]. ([spawn_antag.get_antag_count()]/[spawn_antag.cur_max])") next_spawn = world.time + rand(min_autotraitor_delay, max_autotraitor_delay) return - - message_admins("[uppertext(name)]: Failed to proc a viable spawn template.") - next_spawn = world.time + min_autotraitor_delay //recheck again in the miniumum time + message_admins("AUTO[uppertext(name)]: Failed to proc a viable spawn template.") + next_spawn = world.time + rand(min_autotraitor_delay, max_autotraitor_delay) diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm index 5fcfce49c70..e1b0735b1ee 100644 --- a/code/game/gamemodes/heist/heist.dm +++ b/code/game/gamemodes/heist/heist.dm @@ -8,6 +8,7 @@ var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind' name = "heist" config_tag = "heist" required_players = 15 + required_players_secret = 25 required_enemies = 4 round_description = "An unidentified bluespace signature has slipped past the Icarus and is approaching the station!" end_on_antag_death = 0 diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm index b4409316fef..ea98f32558f 100644 --- a/code/game/gamemodes/malfunction/malfunction.dm +++ b/code/game/gamemodes/malfunction/malfunction.dm @@ -4,6 +4,7 @@ extended_round_description = "The AI will attempt to hack the APCs around the station in order to gain as much control as possible." config_tag = "malfunction" required_players = 2 + required_players_secret = 7 required_enemies = 1 end_on_antag_death = 0 auto_recall_shuttle = 0 diff --git a/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm b/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm index 642514115bf..11f3c55ef57 100644 --- a/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm +++ b/code/game/gamemodes/malfunction/newmalf_ability_trees/tree_networking.dm @@ -85,7 +85,7 @@ /datum/game_mode/malfunction/verb/advanced_encryption_hack() set category = "Software" - set name = "Advanced Encryption Hack" + set name = "Advanced Encrypthion Hack" set desc = "75 CPU - Attempts to bypass encryption on the Command Quantum Relay, giving you ability to fake legitimate messages. Has chance of failing." var/price = 75 var/mob/living/silicon/ai/user = usr @@ -106,12 +106,15 @@ announce_hack_failure(user, "quantum message relay") return - command_announcement.Announce(text, title) + var/datum/announcement/priority/command/AN = new/datum/announcement/priority/command() + AN.title = title + AN.Announce(text) + /datum/game_mode/malfunction/verb/elite_encryption_hack() set category = "Software" set name = "Elite Encryption Hack" - set desc = "200 CPU - Allows you to hack station's ALERTCON system, changing alert level. Has high chance of failing." + set desc = "200 CPU - Allows you to hack station's ALERTCON system, changing alert level. Has high chance of failijng." var/price = 200 var/mob/living/silicon/ai/user = usr if(!ability_prechecks(user, price)) diff --git a/code/game/gamemodes/meme/meme.dm b/code/game/gamemodes/meme/meme.dm index 0cd534870db..0a4846d7635 100644 --- a/code/game/gamemodes/meme/meme.dm +++ b/code/game/gamemodes/meme/meme.dm @@ -6,6 +6,7 @@ name = "Memetic Anomaly" config_tag = "meme" required_players = 3 + required_players_secret = 10 restricted_jobs = list("AI", "Cyborg") recommended_enemies = 2 // need at least a meme and a host votable = 0 // temporarily disable this mode for voting diff --git a/code/game/gamemodes/mixed/bughunt.dm b/code/game/gamemodes/mixed/bughunt.dm index 5ca6ed82a29..cfdb25c9a5b 100644 --- a/code/game/gamemodes/mixed/bughunt.dm +++ b/code/game/gamemodes/mixed/bughunt.dm @@ -3,6 +3,7 @@ round_description = "A mercenary strike force is approaching the station to eradicate a xenomorph infestation!" config_tag = "bughunt" required_players = 15 + required_players_secret = 25 required_enemies = 1 end_on_antag_death = 1 antag_tags = list(MODE_XENOMORPH, MODE_DEATHSQUAD) diff --git a/code/game/gamemodes/mixed/conflux.dm b/code/game/gamemodes/mixed/conflux.dm index 1923c3fbf92..2d8753ce1a7 100644 --- a/code/game/gamemodes/mixed/conflux.dm +++ b/code/game/gamemodes/mixed/conflux.dm @@ -4,6 +4,7 @@ extended_round_description = "Cultists and wizards spawn during this round." config_tag = "conflux" required_players = 15 + required_players_secret = 15 required_enemies = 5 end_on_antag_death = 1 antag_tags = list(MODE_WIZARD, MODE_CULTIST) diff --git a/code/game/gamemodes/mixed/paranoia.dm b/code/game/gamemodes/mixed/paranoia.dm index de7a9d153e7..7c3e903b140 100644 --- a/code/game/gamemodes/mixed/paranoia.dm +++ b/code/game/gamemodes/mixed/paranoia.dm @@ -4,6 +4,7 @@ extended_round_description = "Rampant AIs, renegades and changelings spawn in this mode." config_tag = "paranoia" required_players = 2 + required_players_secret = 7 required_enemies = 1 end_on_antag_death = 1 require_all_templates = 1 diff --git a/code/game/gamemodes/mixed/traitorling.dm b/code/game/gamemodes/mixed/traitorling.dm index 6972aee5540..12527f08777 100644 --- a/code/game/gamemodes/mixed/traitorling.dm +++ b/code/game/gamemodes/mixed/traitorling.dm @@ -4,6 +4,7 @@ extended_round_description = "Traitors and changelings both spawn during this mode." config_tag = "traitorling" required_players = 10 + required_players_secret = 15 required_enemies = 5 end_on_antag_death = 1 require_all_templates = 1 diff --git a/code/game/gamemodes/mixed/uprising.dm b/code/game/gamemodes/mixed/uprising.dm index 9dad2ecfa97..005d9dce915 100644 --- a/code/game/gamemodes/mixed/uprising.dm +++ b/code/game/gamemodes/mixed/uprising.dm @@ -4,6 +4,7 @@ round_description = "Some crewmembers are attempting to start a revolution while a cult plots in the shadows!" extended_round_description = "Cultists and revolutionaries spawn in this round." required_players = 15 + required_players_secret = 15 required_enemies = 3 end_on_antag_death = 1 antag_tags = list(MODE_REVOLUTIONARY, MODE_LOYALIST, MODE_CULTIST) diff --git a/code/game/gamemodes/ninja/ninja.dm b/code/game/gamemodes/ninja/ninja.dm index 8570f84e743..7a4981c0fa9 100644 --- a/code/game/gamemodes/ninja/ninja.dm +++ b/code/game/gamemodes/ninja/ninja.dm @@ -10,6 +10,7 @@ only hope this unknown assassin isn't here for you." config_tag = "ninja" required_players = 1 + required_players_secret = 10 required_enemies = 1 end_on_antag_death = 0 - antag_tags = list(MODE_NINJA) + antag_tags = list(MODE_NINJA) \ No newline at end of file diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index 0ac412ca7e4..e3ab6b151ba 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -9,6 +9,7 @@ var/list/nuke_disks = list() round_description = "A mercenary strike force is approaching the station!" config_tag = "mercenary" required_players = 15 + required_players_secret = 25 // 25 players - 5 players to be the nuke ops = 20 players remaining required_enemies = 1 end_on_antag_death = 0 var/nuke_off_station = 0 //Used for tracking if the syndies actually haul the nuke to the station diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm index 0ec94c44f9c..b7a38fd8d5c 100644 --- a/code/game/gamemodes/revolution/revolution.dm +++ b/code/game/gamemodes/revolution/revolution.dm @@ -4,6 +4,7 @@ round_description = "Some crewmembers are attempting to start a revolution!" extended_round_description = "Revolutionaries - Remove the heads of staff from power. Convert other crewmembers to your cause using the 'Convert Bourgeoise' verb. Protect your leaders." required_players = 4 + required_players_secret = 15 required_enemies = 3 auto_recall_shuttle = 0 //NO THANKS end_on_antag_death = 0 diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm index d3694dd8d32..7926fd22be9 100644 --- a/code/game/gamemodes/wizard/wizard.dm +++ b/code/game/gamemodes/wizard/wizard.dm @@ -4,6 +4,7 @@ extended_round_description = "A powerful entity capable of manipulating the elements around him, most commonly referred to as a 'wizard', has infiltrated the station. They have a wide variety of powers and spells available to them that makes your own simple moral self tremble with fear and excitement. Ultimately, their purpose is unknown. However, it is up to you and your crew to decide if their powers can be used for good or if their arrival foreshadows the destruction of the entire station." config_tag = "wizard" required_players = 1 + required_players_secret = 10 required_enemies = 1 end_on_antag_death = 0 antag_tags = list(MODE_WIZARD) diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm index 04418f0860a..35cd31399ef 100644 --- a/code/game/machinery/computer/computer.dm +++ b/code/game/machinery/computer/computer.dm @@ -127,4 +127,11 @@ M.deconstruct(src) qdel(src) else - ..() + src.attack_hand(user) + return + + + + + + diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 0a4a173144d..9b7abebdeda 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1081,8 +1081,8 @@ About the new airlock wires panel: /obj/machinery/door/airlock/emp_act(var/severity) if(prob(40/severity)) - var/duration = SecondsToTicks(30 / severity) - if(electrified_until > -1 && (duration + world.time) > electrified_until) + var/duration = world.time + SecondsToTicks(30 / severity) + if(duration > electrified_until) electrify(duration) ..() diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index 6d69941b813..455c6256a4f 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -191,10 +191,7 @@ Class Procs: return (stat & (NOPOWER|BROKEN|additional_flags)) /obj/machinery/CanUseTopic(var/mob/user) - if(stat & BROKEN) - return STATUS_CLOSE - - if(!interact_offline && (stat & NOPOWER)) + if(!interact_offline && (stat & (NOPOWER|BROKEN))) return STATUS_CLOSE return ..() diff --git a/code/game/machinery/nuclear_bomb.dm b/code/game/machinery/nuclear_bomb.dm index a8ca3f1dbea..d02d3522a4a 100644 --- a/code/game/machinery/nuclear_bomb.dm +++ b/code/game/machinery/nuclear_bomb.dm @@ -418,14 +418,10 @@ obj/machinery/nuclearbomb/proc/nukehack_win(mob/user as mob) nuke_disks |= src /obj/item/weapon/disk/nuclear/Destroy() - nuke_disks -= src - if(!nuke_disks.len) - var/turf/T = pick_area_turf(/area/maintenance, list(/proc/is_station_turf, /proc/not_turf_contains_dense_objects)) - if(T) - var/obj/D = new /obj/item/weapon/disk/nuclear(T) - log_and_message_admins_with_location("[src], the last authentication disk, has been destroyed. Spawning [D] at ([D.x], [D.y], [D.z]).", T.x, T.y, T.z) - else - log_and_message_admins("[src], the last authentication disk, has been destroyed. Failed to respawn disc!") + if(!nuke_disks.len && blobstart.len > 0) + var/obj/D = new /obj/item/weapon/disk/nuclear(pick(blobstart)) + message_admins("[src], the last authentication disk, has been destroyed. Spawning [D] at ([D.x], [D.y], [D.z]).") + log_game("[src], the last authentication disk, has been destroyed. Spawning [D] at ([D.x], [D.y], [D.z]).") ..() /obj/item/weapon/disk/nuclear/touch_map_edge() diff --git a/code/game/objects/effects/aliens.dm b/code/game/objects/effects/aliens.dm index 24754c22701..aa9f9394932 100644 --- a/code/game/objects/effects/aliens.dm +++ b/code/game/objects/effects/aliens.dm @@ -1,11 +1,271 @@ +/* Alien Effects! + * Contains: + * effect/alien + * Resin + * Weeds + * Acid + * Egg + */ + +/* + * effect/alien + */ +/obj/effect/alien + name = "alien thing" + desc = "theres something alien about this" + icon = 'icons/mob/alien.dmi' + +/* + * Resin + */ +/obj/effect/alien/resin + name = "resin" + desc = "Looks like some kind of slimy growth." + icon_state = "resin" + + density = 1 + opacity = 1 + anchored = 1 + var/health = 200 + //var/mob/living/affecting = null + +/obj/effect/alien/resin/wall + name = "resin wall" + desc = "Purple slime solidified into a wall." + icon_state = "resinwall" //same as resin, but consistency ho! + +/obj/effect/alien/resin/membrane + name = "resin membrane" + desc = "Purple slime just thin enough to let light pass through." + icon_state = "resinmembrane" + opacity = 0 + health = 120 + +/obj/effect/alien/resin/New() + ..() + var/turf/T = get_turf(src) + T.thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT + +/obj/effect/alien/resin/Destroy() + var/turf/T = get_turf(src) + T.thermal_conductivity = initial(T.thermal_conductivity) + ..() + +/obj/effect/alien/resin/proc/healthcheck() + if(health <=0) + density = 0 + qdel(src) + return + +/obj/effect/alien/resin/bullet_act(var/obj/item/projectile/Proj) + health -= Proj.damage + ..() + healthcheck() + return + +/obj/effect/alien/resin/ex_act(severity) + switch(severity) + if(1.0) + health-=50 + if(2.0) + health-=50 + if(3.0) + if (prob(50)) + health-=50 + else + health-=25 + healthcheck() + return + +/obj/effect/alien/resin/hitby(AM as mob|obj) + ..() + for(var/mob/O in viewers(src, null)) + O.show_message("[src] was hit by [AM].", 1) + var/tforce = 0 + if(ismob(AM)) + tforce = 10 + else + tforce = AM:throwforce + playsound(loc, 'sound/effects/attackblob.ogg', 100, 1) + health = max(0, health - tforce) + healthcheck() + ..() + return + +/obj/effect/alien/resin/attack_hand() + usr.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if (HULK in usr.mutations) + usr << "You easily destroy the [name]." + for(var/mob/O in oviewers(src)) + O.show_message("[usr] destroys the [name]!", 1) + health = 0 + else + + // Aliens can get straight through these. + if(istype(usr,/mob/living/carbon)) + var/mob/living/carbon/M = usr + if(locate(/obj/item/organ/xenos/hivenode) in M.internal_organs) + for(var/mob/O in oviewers(src)) + O.show_message("[usr] strokes the [name] and it melts away!", 1) + health = 0 + healthcheck() + return + + usr << "You claw at the [name]." + for(var/mob/O in oviewers(src)) + O.show_message("[usr] claws at the [name]!", 1) + health -= rand(5,10) + healthcheck() + return + +/obj/effect/alien/resin/attackby(obj/item/weapon/W as obj, mob/user as mob) + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + var/aforce = W.force + health = max(0, health - aforce) + playsound(loc, 'sound/effects/attackblob.ogg', 100, 1) + healthcheck() + ..() + return + +/obj/effect/alien/resin/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group) return 0 + if(istype(mover) && mover.checkpass(PASSGLASS)) + return !opacity + return !density + + +/* + * Weeds + */ +#define NODERANGE 3 + +/obj/effect/alien/weeds + name = "weeds" + desc = "Weird purple weeds." + icon_state = "weeds" + + anchored = 1 + density = 0 + layer = 2 + var/health = 15 + var/obj/effect/alien/weeds/node/linked_node = null + +/obj/effect/alien/weeds/node + icon_state = "weednode" + name = "purple sac" + desc = "Weird purple octopus-like thing." + layer = 3 + light_range = NODERANGE + var/node_range = NODERANGE + +/obj/effect/alien/weeds/node/New() + ..(src.loc, src) + + +/obj/effect/alien/weeds/New(pos, node) + ..() + if(istype(loc, /turf/space)) + qdel(src) + return + linked_node = node + if(icon_state == "weeds")icon_state = pick("weeds", "weeds1", "weeds2") + spawn(rand(150, 200)) + if(src) + Life() + return + +/obj/effect/alien/weeds/proc/Life() + set background = 1 + var/turf/U = get_turf(src) +/* + if (locate(/obj/movable, U)) + U = locate(/obj/movable, U) + if(U.density == 1) + qdel(src) + return + +Alien plants should do something if theres a lot of poison + if(U.poison> 200000) + health -= round(U.poison/200000) + update() + return +*/ + if (istype(U, /turf/space)) + qdel(src) + return + + if(!linked_node || (get_dist(linked_node, src) > linked_node.node_range) ) + return + + direction_loop: + for(var/dirn in cardinal) + var/turf/T = get_step(src, dirn) + + if (!istype(T) || T.density || locate(/obj/effect/alien/weeds) in T || istype(T.loc, /area/arrival) || istype(T, /turf/space)) + continue + + // if (locate(/obj/movable, T)) // don't propogate into movables + // continue + + for(var/obj/O in T) + if(O.density) + continue direction_loop + + PoolOrNew(/obj/effect/alien/weeds, T, linked_node) + + +/obj/effect/alien/weeds/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + if(2.0) + if (prob(50)) + qdel(src) + if(3.0) + if (prob(5)) + qdel(src) + return + +/obj/effect/alien/weeds/attackby(var/obj/item/weapon/W, var/mob/user) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(W.attack_verb.len) + visible_message("\The [src] have been [pick(W.attack_verb)] with \the [W][(user ? " by [user]." : ".")]") + else + visible_message("\The [src] have been attacked with \the [W][(user ? " by [user]." : ".")]") + + var/damage = W.force / 4.0 + + if(istype(W, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/WT = W + + if(WT.remove_fuel(0, user)) + damage = 15 + playsound(loc, 'sound/items/Welder.ogg', 100, 1) + + health -= damage + healthcheck() + +/obj/effect/alien/weeds/proc/healthcheck() + if(health <= 0) + qdel(src) + + +/obj/effect/alien/weeds/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature > 300 + T0C) + health -= 5 + healthcheck() + +#undef NODERANGE + + /* * Acid */ -/obj/effect/acid +/obj/effect/alien/acid name = "acid" - desc = "Burbling corrosive stuff. Probably a bad idea to roll around in it." + desc = "Burbling corrossive stuff. I wouldn't want to touch it." icon_state = "acid" - icon = 'icons/mob/alien.dmi' density = 0 opacity = 0 @@ -15,9 +275,9 @@ var/ticks = 0 var/target_strength = 0 -/obj/effect/acid/New(loc, supplied_target) +/obj/effect/alien/acid/New(loc, target) ..(loc) - target = supplied_target + src.target = target if(isturf(target)) // Turf take twice as long to take down. target_strength = 8 @@ -25,13 +285,17 @@ target_strength = 4 tick() -/obj/effect/acid/proc/tick() +/obj/effect/alien/acid/proc/tick() if(!target) qdel(src) - ticks++ + ticks += 1 + if(ticks >= target_strength) - target.visible_message("\The [target] collapses under its own weight into a puddle of goop and undigested debris!") + + for(var/mob/O in hearers(src, null)) + O.show_message("[src.target] collapses under its own weight into a puddle of goop and undigested debris!", 1) + if(istype(target, /turf/simulated/wall)) // I hate turf code. var/turf/simulated/wall/W = target W.dismantle_wall(1) @@ -42,11 +306,135 @@ switch(target_strength - ticks) if(6) - visible_message("\The [src.target] is holding up against the acid!") + visible_message("[src.target] is holding up against the acid!") if(4) - visible_message("\The [src.target]\s structure is being melted by the acid!") + visible_message("[src.target]\s structure is being melted by the acid!") if(2) - visible_message("\The [src.target] is struggling to withstand the acid!") + visible_message("[src.target] is struggling to withstand the acid!") if(0 to 1) - visible_message("\The [src.target] begins to crumble under the acid!") - spawn(rand(150, 200)) tick() \ No newline at end of file + visible_message("[src.target] begins to crumble under the acid!") + spawn(rand(150, 200)) tick() + +/* + * Egg + */ +/var/const //for the status var + BURST = 0 + BURSTING = 1 + GROWING = 2 + GROWN = 3 + + MIN_GROWTH_TIME = 1800 //time it takes to grow a hugger + MAX_GROWTH_TIME = 3000 + +/obj/effect/alien/egg + desc = "It looks like a weird egg" + name = "egg" + icon_state = "egg_growing" + density = 0 + anchored = 1 + + var/health = 100 + var/status = GROWING //can be GROWING, GROWN or BURST; all mutually exclusive + flags = PROXMOVE + +/obj/effect/alien/egg/New() + if(config.aliens_allowed) + ..() + spawn(rand(MIN_GROWTH_TIME,MAX_GROWTH_TIME)) + Grow() + else + qdel(src) + +/obj/effect/alien/egg/attack_hand(user as mob) + + var/mob/living/carbon/M = user + if(!istype(M) || !(locate(/obj/item/organ/xenos/hivenode) in M.internal_organs)) + return attack_hand(user) + + switch(status) + if(BURST) + user << "You clear the hatched egg." + qdel(src) + return + if(GROWING) + user << "The child is not developed yet." + return + if(GROWN) + user << "You retrieve the child." + Burst(0) + return + +/obj/effect/alien/egg/proc/GetFacehugger() + return locate(/obj/item/clothing/mask/facehugger) in contents + +/obj/effect/alien/egg/proc/Grow() + icon_state = "egg" + status = GROWN + new /obj/item/clothing/mask/facehugger(src) + return + +/obj/effect/alien/egg/proc/Burst(var/kill = 1) //drops and kills the hugger if any is remaining + if(status == GROWN || status == GROWING) + var/obj/item/clothing/mask/facehugger/child = GetFacehugger() + icon_state = "egg_hatched" + flick("egg_opening", src) + status = BURSTING + spawn(15) + status = BURST + child.loc = get_turf(src) + + if(kill && istype(child)) + child.Die() + else + for(var/mob/M in range(1,src)) + if(CanHug(M)) + child.Attach(M) + break + +/obj/effect/alien/egg/bullet_act(var/obj/item/projectile/Proj) + health -= Proj.damage + ..() + healthcheck() + return + + +/obj/effect/alien/egg/attackby(var/obj/item/weapon/W, var/mob/user) + if(health <= 0) + return + if(W.attack_verb.len) + src.visible_message("\The [src] has been [pick(W.attack_verb)] with \the [W][(user ? " by [user]." : ".")]") + else + src.visible_message("\The [src] has been attacked with \the [W][(user ? " by [user]." : ".")]") + var/damage = W.force / 4.0 + + if(istype(W, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/WT = W + + if(WT.remove_fuel(0, user)) + damage = 15 + playsound(src.loc, 'sound/items/Welder.ogg', 100, 1) + + src.health -= damage + src.healthcheck() + + +/obj/effect/alien/egg/proc/healthcheck() + if(health <= 0) + Burst() + +/obj/effect/alien/egg/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature > 500 + T0C) + health -= 5 + healthcheck() + +/obj/effect/alien/egg/HasProximity(atom/movable/AM as mob|obj) + if(status == GROWN) + if(!CanHug(AM)) + return + + var/mob/living/carbon/C = AM + if(C.stat == CONSCIOUS && C.status_flags & XENO_HOST) + return + + Burst(0) diff --git a/code/game/objects/effects/chem/chemsmoke.dm b/code/game/objects/effects/chem/chemsmoke.dm index 034ce946864..3fa93e7e467 100644 --- a/code/game/objects/effects/chem/chemsmoke.dm +++ b/code/game/objects/effects/chem/chemsmoke.dm @@ -4,76 +4,14 @@ /obj/effect/effect/smoke/chem icon = 'icons/effects/chemsmoke.dmi' opacity = 0 - layer = 6 time_to_live = 300 pass_flags = PASSTABLE | PASSGRILLE | PASSGLASS //PASSGLASS is fine here, it's just so the visual effect can "flow" around glass - var/splash_amount = 10 //atoms moving through a smoke cloud get splashed with up to 10 units of reagent - var/turf/destination -/obj/effect/effect/smoke/chem/New(var/newloc, smoke_duration, turf/dest_turf = null, icon/cached_icon = null) - time_to_live = smoke_duration - +/obj/effect/effect/smoke/chem/New() ..() - create_reagents(500) - - if(cached_icon) - icon = cached_icon - - set_dir(pick(cardinal)) - pixel_x = -32 + rand(-8, 8) - pixel_y = -32 + rand(-8, 8) - - //switching opacity on after the smoke has spawned, and then turning it off before it is deleted results in cleaner - //lighting and view range updates (Is this still true with the new lighting system?) - opacity = 1 + return - //float over to our destination, if we have one - destination = dest_turf - if(destination) - walk_to(src, destination) - -/obj/effect/effect/smoke/chem/Destroy() - opacity = 0 - fadeOut() - ..() - -/obj/effect/effect/smoke/chem/Move() - var/list/oldlocs = view(1, src) - . = ..() - if(.) - for(var/turf/T in view(1, src) - oldlocs) - for(var/atom/movable/AM in T) - if(!istype(AM, /obj/effect/effect/smoke/chem)) - reagents.splash(AM, splash_amount, copy = 1) - if(loc == destination) - bound_width = 96 - bound_height = 96 - -/obj/effect/effect/smoke/chem/Crossed(atom/movable/AM) - ..() - if(!istype(AM, /obj/effect/effect/smoke/chem)) - reagents.splash(AM, splash_amount, copy = 1) - -/obj/effect/effect/smoke/chem/proc/initial_splash() - for(var/turf/T in view(1, src)) - for(var/atom/movable/AM in T) - if(!istype(AM, /obj/effect/effect/smoke/chem)) - reagents.splash(AM, splash_amount, copy = 1) - -// Fades out the smoke smoothly using it's alpha variable. -/obj/effect/effect/smoke/chem/proc/fadeOut(var/frames = 16) - if(!alpha) return //already transparent - - frames = max(frames, 1) //We will just assume that by 0 frames, the coder meant "during one frame". - var/alpha_step = round(alpha / frames) - while(alpha > 0) - alpha = max(0, alpha - alpha_step) - sleep(world.tick_lag) - -///////////////////////////////////////////// -// Chem Smoke Effect System -///////////////////////////////////////////// /datum/effect/effect/system/smoke_spread/chem smoke_type = /obj/effect/effect/smoke/chem var/obj/chemholder @@ -177,21 +115,13 @@ else I = icon('icons/effects/96x96.dmi', "smoke") - //Calculate smoke duration - var/smoke_duration = 150 - - var/pressure = 0 - var/datum/gas_mixture/environment = location.return_air() - if(environment) pressure = environment.return_pressure() - smoke_duration = between(5, smoke_duration*pressure/(ONE_ATMOSPHERE/3), smoke_duration) - var/const/arcLength = 2.3559 //distance between each smoke cloud for(var/i = 0, i < range, i++) //calculate positions for smoke coverage - then spawn smoke var/radius = i * 1.5 if(!radius) spawn(0) - spawnSmoke(location, I, 1, 1) + spawnSmoke(location, I, 1) continue var/offset = 0 @@ -216,26 +146,43 @@ // Randomizes and spawns the smoke effect. // Also handles deleting the smoke once the effect is finished. //------------------------------------------ -/datum/effect/effect/system/smoke_spread/chem/proc/spawnSmoke(var/turf/T, var/icon/I, var/smoke_duration, var/dist = 1, var/splash_initial=0, var/obj/effect/effect/smoke/chem/passed_smoke) +/datum/effect/effect/system/smoke_spread/chem/proc/spawnSmoke(var/turf/T, var/icon/I, var/dist = 1, var/obj/effect/effect/smoke/chem/passed_smoke) var/obj/effect/effect/smoke/chem/smoke if(passed_smoke) smoke = passed_smoke else - smoke = PoolOrNew(/obj/effect/effect/smoke/chem, list(location, smoke_duration + rand(0, 20), T, I)) + smoke = PoolOrNew(/obj/effect/effect/smoke/chem, location) if(chemholder.reagents.reagent_list.len) chemholder.reagents.trans_to_obj(smoke, chemholder.reagents.total_volume / dist, copy = 1) //copy reagents to the smoke so mob/breathe() can handle inhaling the reagents + smoke.icon = I + smoke.layer = 6 + smoke.set_dir(pick(cardinal)) + smoke.pixel_x = -32 + rand(-8, 8) + smoke.pixel_y = -32 + rand(-8, 8) + walk_to(smoke, T) + smoke.opacity = 1 //switching opacity on after the smoke has spawned, and then + sleep(150+rand(0,20)) // turning it off before it is deleted results in cleaner + smoke.opacity = 0 // lighting and view range updates + fadeOut(smoke) + qdel(src) - //Kinda ugly, but needed unless the system is reworked - if(splash_initial) - smoke.initial_splash() - - -/datum/effect/effect/system/smoke_spread/chem/spores/spawnSmoke(var/turf/T, var/smoke_duration, var/icon/I, var/dist = 1) +/datum/effect/effect/system/smoke_spread/chem/spores/spawnSmoke(var/turf/T, var/icon/I, var/dist = 1) var/obj/effect/effect/smoke/chem/spores = PoolOrNew(/obj/effect/effect/smoke/chem, location) spores.name = "cloud of [seed.seed_name] [seed.seed_noun]" - ..(T, I, smoke_duration, dist, spores) + ..(T, I, dist, spores) + +/datum/effect/effect/system/smoke_spread/chem/proc/fadeOut(var/atom/A, var/frames = 16) // Fades out the smoke smoothly using it's alpha variable. + if(A.alpha == 0) //Handle already transparent case + return + if(frames == 0) + frames = 1 //We will just assume that by 0 frames, the coder meant "during one frame". + var/step = A.alpha / frames + for(var/i = 0, i < frames, i++) + A.alpha -= step + sleep(world.tick_lag) + return /datum/effect/effect/system/smoke_spread/chem/proc/smokeFlow() // Smoke pathfinder. Uses a flood fill method based on zones to quickly check what turfs the smoke (airflow) can actually reach. diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm index ed518a6f53d..9dfe1c3b196 100644 --- a/code/game/objects/effects/landmarks.dm +++ b/code/game/objects/effects/landmarks.dm @@ -52,6 +52,10 @@ prisonsecuritywarp += loc qdel(src) return + if("blobstart") + blobstart += loc + qdel(src) + return if("xeno_spawn") xeno_spawn += loc qdel(src) diff --git a/code/game/objects/effects/spawners/bombspawner.dm b/code/game/objects/effects/spawners/bombspawner.dm index fb4716043f1..547931a5118 100644 --- a/code/game/objects/effects/spawners/bombspawner.dm +++ b/code/game/objects/effects/spawners/bombspawner.dm @@ -105,61 +105,27 @@ qdel(src) */ -/client/proc/spawn_tanktransferbomb() - set category = "Debug" - set desc = "Spawn a tank transfer valve bomb" - set name = "Instant TTV" - - if(!check_rights(R_SPAWN)) return - - var/obj/effect/spawner/newbomb/proto = /obj/effect/spawner/newbomb/radio/custom - - var/p = input("Enter phoron amount (mol):","Phoron", initial(proto.phoron_amt)) as num|null - if(p == null) return - - var/o = input("Enter oxygen amount (mol):","Oxygen", initial(proto.oxygen_amt)) as num|null - if(o == null) return - - var/c = input("Enter carbon dioxide amount (mol):","Carbon Dioxide", initial(proto.carbon_amt)) as num|null - if(c == null) return - - new /obj/effect/spawner/newbomb/radio/custom(get_turf(mob), p, o, c) - /obj/effect/spawner/newbomb - name = "TTV bomb" + name = "bomb" icon = 'icons/mob/screen1.dmi' icon_state = "x" - - var/assembly_type = /obj/item/device/assembly/signaler - - //Note that the maximum amount of gas you can put in a 70L air tank at 1013.25 kPa and 519K is 16.44 mol. - var/phoron_amt = 10.96 - var/oxygen_amt = 16.44 - var/carbon_amt = 0.0 + var/btype = 0 // 0=radio, 1=prox, 2=time -/obj/effect/spawner/newbomb/timer - name = "TTV bomb - timer" - assembly_type = /obj/item/device/assembly/timer + timer + btype = 2 -/obj/effect/spawner/newbomb/timer/syndicate - name = "TTV bomb - merc" - //High yield bombs. Yes, it is possible to make these with toxins - phoron_amt = 15.66 - oxygen_amt = 24.66 + syndicate -/obj/effect/spawner/newbomb/proximity - name = "TTV bomb - proximity" - assembly_type = /obj/item/device/assembly/prox_sensor + proximity + btype = 1 -/obj/effect/spawner/newbomb/radio/custom/New(var/newloc, ph, ox, co) - if(ph != null) phoron_amt = ph - if(ox != null) oxygen_amt = ox - if(co != null) carbon_amt = co + radio + btype = 0 + + +/obj/effect/spawner/newbomb/New() ..() -/obj/effect/spawner/newbomb/New(newloc) - ..(newloc) - var/obj/item/device/transfer_valve/V = new(src.loc) var/obj/item/weapon/tank/phoron/PT = new(V) var/obj/item/weapon/tank/oxygen/OT = new(V) @@ -171,15 +137,28 @@ OT.master = V PT.air_contents.temperature = PHORON_FLASHPOINT - PT.air_contents.gas["phoron"] = phoron_amt - PT.air_contents.gas["carbon_dioxide"] = carbon_amt - PT.air_contents.update_values() + PT.air_contents.adjust_multi("phoron", 12, "carbon_dioxide", 8) OT.air_contents.temperature = PHORON_FLASHPOINT - OT.air_contents.gas["oxygen"] = oxygen_amt - OT.air_contents.update_values() + OT.air_contents.adjust_gas("oxygen", 20) - var/obj/item/device/assembly/S = new assembly_type(V) + var/obj/item/device/assembly/S + + switch (src.btype) + // radio + if (0) + + S = new/obj/item/device/assembly/signaler(V) + + // proximity + if (1) + + S = new/obj/item/device/assembly/prox_sensor(V) + + // timer + if (2) + + S = new/obj/item/device/assembly/timer(V) V.attached_device = S diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 887bfe575aa..9fa9ce9ff28 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -438,9 +438,6 @@ var/list/global/slot_flags_enumeration = list( M.attack_log += "\[[time_stamp()]\] Attacked by [user.name] ([user.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])" msg_admin_attack("[user.name] ([user.ckey]) attacked [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)]) (JMP)") //BS12 EDIT ALG - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.do_attack_animation(M) - src.add_fingerprint(user) //if((CLUMSY in user.mutations) && prob(50)) // M = user @@ -613,4 +610,8 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out. return /obj/item/proc/pwr_drain() - return 0 // Process Kill + return 0 // Process Kill + +/obj/item/proc/resolve_attackby(atom/A, mob/source) + return A.attackby(src,source) + diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 1f6e517d58f..e0d7ddad3a0 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -722,8 +722,7 @@ var/global/list/obj/item/device/pda/PDAs = list() if("Message") var/obj/item/device/pda/P = locate(href_list["target"]) - var/tap = istype(U, /mob/living/carbon) - src.create_message(U, P, tap) + src.create_message(U, P, !href_list["notap"]) if(mode == 2) if(href_list["target"] in conversations) // Need to make sure the message went through, if not welp. active_conversation = href_list["target"] @@ -1042,7 +1041,7 @@ var/global/list/obj/item/device/pda/PDAs = list() new_message(sending_device, sending_device.owner, sending_device.ownjob, message) /obj/item/device/pda/proc/new_message(var/sending_unit, var/sender, var/sender_job, var/message) - var/reception_message = "\icon[src] Message from [sender] ([sender_job]), \"[message]\" (Reply)" + var/reception_message = "\icon[src] Message from [sender] ([sender_job]), \"[message]\" (Reply)" new_info(message_silent, ttone, reception_message) log_pda("[usr] (PDA: [sending_unit]) sent \"[message]\" to [name]") @@ -1054,7 +1053,7 @@ var/global/list/obj/item/device/pda/PDAs = list() if(ismob(sending_unit.loc) && isAI(loc)) track = "(Follow)" - var/reception_message = "\icon[src] Message from [sender] ([sender_job]), \"[message]\" (Reply) [track]" + var/reception_message = "\icon[src] Message from [sender] ([sender_job]), \"[message]\" (Reply) [track]" new_info(message_silent, newstone, reception_message) log_pda("[usr] (PDA: [sending_unit]) sent \"[message]\" to [name]") diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm index 0f00cbd1cfa..cfbe33e5fd9 100644 --- a/code/game/objects/items/devices/flash.dm +++ b/code/game/objects/items/devices/flash.dm @@ -31,17 +31,14 @@ last_used = world.time times_used = max(0,round(times_used)) //sanity -//attack_as_weapon -/obj/item/device/flash/attack(mob/living/M, mob/living/user, var/target_zone) + +/obj/item/device/flash/attack(mob/living/M as mob, mob/user as mob) if(!user || !M) return //sanity M.attack_log += text("\[[time_stamp()]\] Has been flashed (attempt) with [src.name] by [user.name] ([user.ckey])") user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to flash [M.name] ([M.ckey])") msg_admin_attack("[user.name] ([user.ckey]) Used the [src.name] to flash [M.name] ([M.ckey]) (JMP)") - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.do_attack_animation(M) - if(!clown_check(user)) return if(broken) user << "\The [src] is broken." @@ -68,9 +65,8 @@ if(iscarbon(M)) if(M.stat!=DEAD) - var/mob/living/carbon/C = M - var/safety = C.eyecheck() - if(safety < FLASH_PROTECTION_MODERATE) + var/safety = M:eyecheck() + if(safety <= 0) var/flash_strength = 10 if(ishuman(M)) var/mob/living/carbon/human/H = M @@ -116,9 +112,6 @@ /obj/item/device/flash/attack_self(mob/living/carbon/user as mob, flag = 0, emp = 0) if(!user || !clown_check(user)) return - - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - if(broken) user.show_message("The [src.name] is broken", 2) return @@ -157,8 +150,8 @@ for(var/obj/item/weapon/cloaking_device/S in M) S.active = 0 S.icon_state = "shield0" - var/safety = M.eyecheck() - if(safety < FLASH_PROTECTION_MODERATE) + var/safety = M:eyecheck() + if(!safety) if(!M.blinded) flick("flash", M.flash) @@ -177,7 +170,7 @@ if(istype(loc, /mob/living/carbon)) var/mob/living/carbon/M = loc var/safety = M.eyecheck() - if(safety < FLASH_PROTECTION_MODERATE) + if(safety <= 0) M.Weaken(10) flick("e_flash", M.flash) for(var/mob/O in viewers(M, null)) @@ -190,8 +183,7 @@ icon_state = "sflash" origin_tech = list(TECH_MAGNET = 2, TECH_COMBAT = 1) -//attack_as_weapon -/obj/item/device/flash/synthetic/attack(mob/living/M, mob/living/user, var/target_zone) +/obj/item/device/flash/synthetic/attack(mob/living/M as mob, mob/user as mob) ..() if(!broken) broken = 1 diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index a2707fd01f0..21b6a0e7208 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -79,8 +79,6 @@ user << "\The [M]'s pupils narrow slightly, but are still very dilated." else user << "\The [M]'s pupils narrow." - - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) //can be used offensively flick("flash", M.flash) else return ..() diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 0c5b1c4231b..b88f34ef519 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -83,66 +83,58 @@ var/global/list/default_medbay_channels = list( secure_radio_connections[ch_name] = radio_controller.add_object(src, radiochannels[ch_name], RADIO_CHAT) /obj/item/device/radio/attack_ghost(mob/user) - return ui_interact(user) + interact(user) /obj/item/device/radio/attack_self(mob/user as mob) user.set_machine(src) interact(user) -/obj/item/device/radio/interact(mob/user) - if(!user) - return 0 +/obj/item/device/radio/interact(mob/user as mob) + if(!on) + return - if(b_stat) - wires.Interact(user) + if(active_uplink_check(user)) + return - return ui_interact(user) + var/dat = "[src]" -/obj/item/device/radio/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] + if(!istype(src, /obj/item/device/radio/headset)) //Headsets dont get a mic button + dat += "Microphone: [broadcasting ? "Engaged" : "Disengaged"]
" - data["mic_status"] = broadcasting - data["speaker"] = listening - data["freq"] = format_frequency(frequency) - data["rawfreq"] = num2text(frequency) + dat += {" + Speaker: [listening ? "Engaged" : "Disengaged"]
+ Frequency: + - + - + [format_frequency(frequency)] + + + +
+ "} - data["mic_cut"] = (wires.IsIndexCut(WIRE_TRANSMIT) || wires.IsIndexCut(WIRE_SIGNAL)) - data["spk_cut"] = (wires.IsIndexCut(WIRE_RECEIVE) || wires.IsIndexCut(WIRE_SIGNAL)) + dat+=list_channels(user) - var/list/chanlist = list_channels(user) - if(islist(chanlist) && chanlist.len) - data["chan_list"] = chanlist - data["chan_list_len"] = chanlist.len - - if(syndie) - data["useSyndMode"] = 1 - - ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "radio_basic.tmpl", "[name]", 400, 430) - ui.set_initial_data(data) - ui.open() + dat+={"[text_wires()]
"} + user << browse(dat, "window=radio") + onclose(user, "radio") + return /obj/item/device/radio/proc/list_channels(var/mob/user) return list_internal_channels(user) /obj/item/device/radio/proc/list_secure_channels(var/mob/user) - var/dat[0] - - for(var/ch_name in channels) - var/chan_stat = channels[ch_name] - var/listening = !!(chan_stat & FREQ_LISTENING) != 0 - - dat.Add(list(list("chan" = ch_name, "display_name" = ch_name, "secure_channel" = 1, "sec_channel_listen" = !listening, "chan_span" = frequency_span_class(radiochannels[ch_name])))) - + var/dat = "" + for (var/ch_name in channels) + dat+=text_sec_channel(ch_name, channels[ch_name]) return dat /obj/item/device/radio/proc/list_internal_channels(var/mob/user) - var/dat[0] - for(var/internal_chan in internal_channels) + var/dat = "" + for (var/internal_chan in internal_channels) if(has_channel_access(user, internal_chan)) - dat.Add(list(list("chan" = internal_chan, "display_name" = get_frequency_name(text2num(internal_chan)), "chan_span" = frequency_span_class(text2num(internal_chan))))) + dat+="[get_frequency_name(text2num(internal_chan))]
" + if(dat) + dat = "
Internal Channels
" + dat return dat /obj/item/device/radio/proc/has_channel_access(var/mob/user, var/freq) @@ -180,13 +172,9 @@ var/global/list/default_medbay_channels = list( /obj/item/device/radio/proc/ToggleReception() listening = !listening && !(wires.IsIndexCut(WIRE_RECEIVE) || wires.IsIndexCut(WIRE_SIGNAL)) -/obj/item/device/radio/CanUseTopic() - if(!on) - return STATUS_CLOSE - return ..() - /obj/item/device/radio/Topic(href, href_list) - if(..()) + if(..() || !on) + usr << browse(null, "window=radio") return 1 usr.set_machine(src) @@ -228,7 +216,7 @@ var/global/list/default_medbay_channels = list( return 1 if(.) - nanomanager.update_uis(src) + interact(usr) /obj/item/device/radio/proc/autosay(var/message, var/from, var/channel) //BS12 EDIT var/datum/radio_frequency/connection = null @@ -695,40 +683,31 @@ var/global/list/default_medbay_channels = list( . = 1 if(.) - nanomanager.update_uis(src) + interact(usr) /obj/item/device/radio/borg/interact(mob/user as mob) if(!on) return - . = ..() + var/dat = "[src]" + dat += {" + Speaker: [listening ? "Engaged" : "Disengaged"]
+ Frequency: + - + - + [format_frequency(frequency)] + + + +
+ Broadcasting: [subspace_transmission ? "Disable" : "Enable"]
+ Loudspeaker: [shut_up ? "Enable" : "Disable"]
+ "} -/obj/item/device/radio/borg/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - - data["mic_status"] = broadcasting - data["speaker"] = listening - data["freq"] = format_frequency(frequency) - data["rawfreq"] = num2text(frequency) - - var/list/chanlist = list_channels(user) - if(islist(chanlist) && chanlist.len) - data["chan_list"] = chanlist - data["chan_list_len"] = chanlist.len - - if(syndie) - data["useSyndMode"] = 1 - - data["has_loudspeaker"] = 1 - data["loudspeaker"] = !shut_up - data["has_subspace"] = 1 - data["subspace"] = subspace_transmission - - ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "radio_basic.tmpl", "[name]", 400, 430) - ui.set_initial_data(data) - ui.open() + if(subspace_transmission)//Don't even bother if subspace isn't turned on + dat+=list_channels(user) + dat+={"[text_wires()]
"} + user << browse(dat, "window=radio") + onclose(user, "radio") + return /obj/item/device/radio/proc/config(op) if(radio_controller) diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm index 88b53bd342d..4135dda5f7c 100644 --- a/code/game/objects/items/devices/transfer_valve.dm +++ b/code/game/objects/items/devices/transfer_valve.dm @@ -100,9 +100,17 @@ if (src.loc != usr) return 0 if(tank_one && href_list["tankone"]) - remove_tank(tank_one) + split_gases() + valve_open = 0 + tank_one.loc = get_turf(src) + tank_one = null + update_icon() else if(tank_two && href_list["tanktwo"]) - remove_tank(tank_two) + split_gases() + valve_open = 0 + tank_two.loc = get_turf(src) + tank_two = null + update_icon() else if(href_list["open"]) toggle_valve() else if(attached_device) @@ -141,43 +149,20 @@ if(attached_device) overlays += "device" -/obj/item/device/transfer_valve/proc/remove_tank(obj/item/weapon/tank/T) - if(tank_one == T) - split_gases() - tank_one = null - else if(tank_two == T) - split_gases() - tank_two = null - else - return - - T.loc = get_turf(src) - update_icon() - /obj/item/device/transfer_valve/proc/merge_gases() - if(valve_open) - return tank_two.air_contents.volume += tank_one.air_contents.volume var/datum/gas_mixture/temp temp = tank_one.air_contents.remove_ratio(1) tank_two.air_contents.merge(temp) - valve_open = 1 /obj/item/device/transfer_valve/proc/split_gases() - if(!valve_open) + if (!valve_open || !tank_one || !tank_two) return - - valve_open = 0 - - if(deleted(tank_one) || deleted(tank_two)) - return - var/ratio1 = tank_one.air_contents.volume/tank_two.air_contents.volume var/datum/gas_mixture/temp temp = tank_two.air_contents.remove_ratio(ratio1) tank_one.air_contents.merge(temp) tank_two.air_contents.volume -= tank_one.air_contents.volume - /* Exadv1: I know this isn't how it's going to work, but this was just to check @@ -185,7 +170,8 @@ */ /obj/item/device/transfer_valve/proc/toggle_valve() - if(!valve_open && (tank_one && tank_two)) + if(valve_open==0 && (tank_one && tank_two)) + valve_open = 1 var/turf/bombturf = get_turf(src) var/area/A = get_area(bombturf) @@ -211,11 +197,16 @@ message_admins(log_str, 0, 1) log_game(log_str) merge_gases() + spawn(20) // In case one tank bursts + for (var/i=0,i<5,i++) + src.update_icon() + sleep(10) + src.update_icon() else if(valve_open==1 && (tank_one && tank_two)) split_gases() - - src.update_icon() + valve_open = 0 + src.update_icon() // this doesn't do anything but the timer etc. expects it to be here // eventually maybe have it update icon to show state (timer, prox etc.) like old bombs diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm index 164c3dd73c2..afe50bc2b76 100644 --- a/code/game/objects/items/robot/robot_items.dm +++ b/code/game/objects/items/robot/robot_items.dm @@ -10,20 +10,31 @@ icon = 'icons/obj/decals.dmi' icon_state = "shock" -/obj/item/borg/stun/apply_hit_effect(mob/living/M, mob/living/silicon/robot/user, var/hit_zone) - if(!istype(user)) +/obj/item/borg/stun/attack(var/mob/living/M, var/mob/living/silicon/robot/user) + + if(!istype(M)) return - user.visible_message("\The [user] has prodded \the [M] with \a [src]!") + // How the Hell. + if(!istype(user)) + var/mob/living/temp = user + if(istype(temp)) + temp.drop_from_inventory(src) + qdel(src) + return + + M.attack_log += text("\[[time_stamp()]\] Has been attacked with [src.name] by [user.name] ([user.ckey])") + user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to attack [M.name] ([M.ckey])") + msg_admin_attack("[user.name] ([user.ckey]) used the [src.name] to attack [M.name] ([M.ckey]) (JMP)") if(!user.cell || !user.cell.checked_use(1250)) //Slightly more than a baton. + user.visible_message("\The [user] has prodded \the [M] with its arm!") return - playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) - - M.apply_effect(5, STUTTER) - M.stun_effect_act(0, 70, check_zone(hit_zone), src) - + if (M.stuttering < 5) + M.stuttering = 5 + M.stun_effect_act(0, 70, check_zone(user.zone_sel.selecting), src) + user.visible_message("\The [user] has prodded \the [M] with \a [src]!") if(ishuman(M)) var/mob/living/carbon/human/H = M H.forcesay(hit_appends) diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index 06925300da6..d3ba0a96a81 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -65,42 +65,24 @@ var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) if(affecting.open == 0) - if(affecting.is_bandaged()) + if(!affecting.bandage()) user << "The wounds on [M]'s [affecting.name] have already been bandaged." return 1 else - user.visible_message("\The [user] starts treating [M]'s [affecting.name].", \ - "You start treating [M]'s [affecting.name]." ) - var/used = 0 for (var/datum/wound/W in affecting.wounds) if (W.internal) continue - if(W.bandaged) - continue - if(used == amount) - break - if(!do_mob(user, M, W.damage/5)) - user << "You must stand still to bandage wounds." - break if (W.current_stage <= W.max_bleeding_stage) - user.visible_message("\The [user] bandages \a [W.desc] on [M]'s [affecting.name].", \ - "You bandage \a [W.desc] on [M]'s [affecting.name]." ) + user.visible_message("\The [user] bandages [W.desc] on [M]'s [affecting.name].", \ + "You bandage [W.desc] on [M]'s [affecting.name]." ) //H.add_side_effect("Itch") else if (istype(W,/datum/wound/bruise)) - user.visible_message("\The [user] places a bruise patch over \a [W.desc] on [M]'s [affecting.name].", \ - "You place a bruise patch over \a [W.desc] on [M]'s [affecting.name]." ) + user.visible_message("\The [user] places a bruise patch over [W.desc] on [M]'s [affecting.name].", \ + "You place a bruise patch over [W.desc] on [M]'s [affecting.name]." ) else - user.visible_message("\The [user] places a bandaid over \a [W.desc] on [M]'s [affecting.name].", \ - "You place a bandaid over \a [W.desc] on [M]'s [affecting.name]." ) - W.bandage() - used++ - affecting.update_damages() - if(used == amount) - if(affecting.is_bandaged()) - user << "\The [src] is used up." - else - user << "\The [src] is used up, but there are more wounds to treat on \the [affecting.name]." - use(used) + user.visible_message("\The [user] places a bandaid over [W.desc] on [M]'s [affecting.name].", \ + "You place a bandaid over [W.desc] on [M]'s [affecting.name]." ) + use(1) else if (can_operate(H)) //Checks if mob is lying down on table for surgery if (do_surgery(H,user,src)) @@ -126,19 +108,13 @@ var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) if(affecting.open == 0) - if(affecting.is_salved()) + if(!affecting.salve()) user << "The wounds on [M]'s [affecting.name] have already been salved." return 1 else - user.visible_message("\The [user] starts salving wounds on [M]'s [affecting.name].", \ - "You start salving the wounds on [M]'s [affecting.name]." ) - if(!do_mob(user, M, 10)) - user << "You must stand still to salve wounds." - return 1 - user.visible_message("[user] salved wounds on [M]'s [affecting.name].", \ - "You salved wounds on [M]'s [affecting.name]." ) + user.visible_message("[user] salves wounds on [M]'s [affecting.name].", \ + "You salve wounds on [M]'s [affecting.name]." ) use(1) - affecting.salve() else if (can_operate(H)) //Checks if mob is lying down on table for surgery if (do_surgery(H,user,src)) @@ -151,7 +127,7 @@ singular_name = "advanced trauma kit" desc = "An advanced trauma kit for severe injuries." icon_state = "traumakit" - heal_brute = 0 + heal_brute = 12 origin_tech = list(TECH_BIO = 1) /obj/item/stack/medical/advanced/bruise_pack/attack(mob/living/carbon/M as mob, mob/user as mob) @@ -163,44 +139,29 @@ var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) if(affecting.open == 0) - if(affecting.is_bandaged() && affecting.is_disinfected()) + var/bandaged = affecting.bandage() + var/disinfected = affecting.disinfect() + + if(!(bandaged || disinfected)) user << "The wounds on [M]'s [affecting.name] have already been treated." return 1 else - user.visible_message("\The [user] starts treating [M]'s [affecting.name].", \ - "You start treating [M]'s [affecting.name]." ) - var/used = 0 for (var/datum/wound/W in affecting.wounds) if (W.internal) continue - if (W.bandaged && W.disinfected) - continue - if(used == amount) - break - if(!do_mob(user, M, W.damage/5)) - user << "You must stand still to bandage wounds." - break if (W.current_stage <= W.max_bleeding_stage) - user.visible_message("\The [user] cleans \a [W.desc] on [M]'s [affecting.name] and seals the edges with bioglue.", \ - "You clean and seal \a [W.desc] on [M]'s [affecting.name]." ) + user.visible_message("\The [user] cleans [W.desc] on [M]'s [affecting.name] and seals the edges with bioglue.", \ + "You clean and seal [W.desc] on [M]'s [affecting.name]." ) //H.add_side_effect("Itch") else if (istype(W,/datum/wound/bruise)) - user.visible_message("\The [user] places a medical patch over \a [W.desc] on [M]'s [affecting.name].", \ - "You place a medical patch over \a [W.desc] on [M]'s [affecting.name]." ) + user.visible_message("\The [user] places a medical patch over [W.desc] on [M]'s [affecting.name].", \ + "You place a medical patch over [W.desc] on [M]'s [affecting.name]." ) else - user.visible_message("\The [user] smears some bioglue over \a [W.desc] on [M]'s [affecting.name].", \ - "You smear some bioglue over \a [W.desc] on [M]'s [affecting.name]." ) - W.bandage() - W.disinfect() - W.heal_damage(heal_brute) - used++ - affecting.update_damages() - if(used == amount) - if(affecting.is_bandaged()) - user << "\The [src] is used up." - else - user << "\The [src] is used up, but there are more wounds to treat on \the [affecting.name]." - use(used) + user.visible_message("\The [user] smears some bioglue over [W.desc] on [M]'s [affecting.name].", \ + "You smear some bioglue over [W.desc] on [M]'s [affecting.name]." ) + if (bandaged) + affecting.heal_damage(heal_brute,0) + use(1) else if (can_operate(H)) //Checks if mob is lying down on table for surgery if (do_surgery(H,user,src)) @@ -213,7 +174,7 @@ singular_name = "advanced burn kit" desc = "An advanced treatment kit for severe burns." icon_state = "burnkit" - heal_burn = 0 + heal_burn = 12 origin_tech = list(TECH_BIO = 1) @@ -226,20 +187,14 @@ var/obj/item/organ/external/affecting = H.get_organ(user.zone_sel.selecting) if(affecting.open == 0) - if(affecting.is_salved()) + if(!affecting.salve()) user << "The wounds on [M]'s [affecting.name] have already been salved." return 1 else - user.visible_message("\The [user] starts salving wounds on [M]'s [affecting.name].", \ - "You start salving the wounds on [M]'s [affecting.name]." ) - if(!do_mob(user, M, 10)) - user << "You must stand still to salve wounds." - return 1 user.visible_message( "[user] covers wounds on [M]'s [affecting.name] with regenerative membrane.", \ "You cover wounds on [M]'s [affecting.name] with regenerative membrane." ) affecting.heal_damage(0,heal_burn) use(1) - affecting.salve() else if (can_operate(H)) //Checks if mob is lying down on table for surgery if (do_surgery(H,user,src)) diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index d70333bc436..2c3fc80a315 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -137,7 +137,6 @@ if (istype(O, /obj/item/stack)) var/obj/item/stack/S = O S.amount = produced - S.add_to_stacks(user) if (istype(O, /obj/item/weapon/storage)) //BubbleWrap - so newly formed boxes are empty for (var/obj/item/I in O) @@ -192,7 +191,7 @@ else if(get_amount() < used) return 0 - for(var/i = 1 to charge_costs.len) + for(var/i = 1 to uses_charge) var/datum/matter_synth/S = synths[i] S.use_charge(charge_costs[i] * used) // Doesn't need to be deleted return 1 @@ -265,8 +264,8 @@ return 0 var/datum/matter_synth/S = synths[1] . = round(S.get_charge() / charge_costs[1]) - if(charge_costs.len > 1) - for(var/i = 2 to charge_costs.len) + if(uses_charge > 1) + for(var/i = 2 to uses_charge) S = synths[i] . = min(., round(S.get_charge() / charge_costs[i])) return @@ -285,13 +284,13 @@ return return max_amount -/obj/item/stack/proc/add_to_stacks(mob/user as mob) - for (var/obj/item/stack/item in user.loc) +/obj/item/stack/proc/add_to_stacks(mob/usr as mob) + for (var/obj/item/stack/item in usr.loc) if (item==src) continue var/transfer = src.transfer_to(item) if (transfer) - user << "You add a new [item.singular_name] to the stack. It now contains [item.amount] [item.singular_name]\s." + usr << "You add a new [item.singular_name] to the stack. It now contains [item.amount] [item.singular_name]\s." if(!amount) break diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index 53517d91b07..cc805cf95bd 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -71,7 +71,7 @@ var/uses = 10 /obj/item/weapon/card/emag/resolve_attackby(atom/A, mob/user) - var/used_uses = A.emag_act(uses, user, src) + var/used_uses = A.emag_act(uses, user) if(used_uses < 0) return ..(A, user) diff --git a/code/game/objects/items/weapons/circuitboards/computer/air_management.dm b/code/game/objects/items/weapons/circuitboards/computer/air_management.dm index 7651ac7bcb5..d244fd6b5c0 100644 --- a/code/game/objects/items/weapons/circuitboards/computer/air_management.dm +++ b/code/game/objects/items/weapons/circuitboards/computer/air_management.dm @@ -1,135 +1,27 @@ #ifndef T_BOARD -#error T_BOARD macro is not defined but we need it! +#error T_BOARD macro is not defined but we need it! #endif /obj/item/weapon/circuitboard/air_management name = T_BOARD("atmosphere monitoring console") build_path = /obj/machinery/computer/general_air_control - var/console_name var/frequency = 1439 - var/list/sensors = list() - var/list/sensor_information = list() - /obj/item/weapon/circuitboard/air_management/tank_control name = T_BOARD("tank control") build_path = /obj/machinery/computer/general_air_control/large_tank_control frequency = 1441 - var/input_tag - var/output_tag - - var/list/input_info = list() - var/list/output_info = list() - - var/input_flow_setting = 200 - var/pressure_setting = ONE_ATMOSPHERE * 45 - /obj/item/weapon/circuitboard/air_management/supermatter_core name = T_BOARD("core control") build_path = /obj/machinery/computer/general_air_control/supermatter_core frequency = 1438 - var/input_tag - var/output_tag - - var/list/input_info = list() - var/list/output_info = list() - - var/input_flow_setting = 700 - var/pressure_setting = 100 - /obj/item/weapon/circuitboard/air_management/injector_control name = T_BOARD("injector control") build_path = /obj/machinery/computer/general_air_control/fuel_injection - var/device_tag - var/list/device_info - var/automation = 0 - var/cutoff_temperature = 2000 - var/on_temperature = 1200 -/************ -* Construct * -************/ /obj/item/weapon/circuitboard/air_management/construct(var/obj/machinery/computer/general_air_control/C) if (..(C)) - if(console_name) - C.name = console_name - C.set_frequency(frequency) - C.sensors = sensors.Copy() - C.sensor_information = sensor_information.Copy() - return 1 + C.frequency = frequency -/obj/item/weapon/circuitboard/air_management/tank_control/construct(var/obj/machinery/computer/general_air_control/large_tank_control/LTC) - if(..(LTC)) - LTC.input_tag = input_tag - LTC.output_tag = output_tag - - LTC.input_info = input_info.Copy() - LTC.output_info = output_info.Copy() - - LTC.input_flow_setting = input_flow_setting - LTC.pressure_setting = pressure_setting - return 1 - -/obj/item/weapon/circuitboard/air_management/supermatter_core/construct(var/obj/machinery/computer/general_air_control/supermatter_core/SC) - if(..(SC)) - SC.input_tag = input_tag - SC.output_tag = output_tag - - SC.input_info = input_info.Copy() - SC.output_info = output_info.Copy() - - SC.input_flow_setting = input_flow_setting - SC.pressure_setting = input_flow_setting - return 1 - -/obj/item/weapon/circuitboard/air_management/injector_control/construct(var/obj/machinery/computer/general_air_control/fuel_injection/FI) - if(..(FI)) - FI.device_tag = device_tag - FI.device_info = device_info.Copy() - FI.automation = automation - FI.cutoff_temperature = cutoff_temperature - FI.on_temperature = on_temperature - return 1 - -/************** -* Deconstruct * -**************/ /obj/item/weapon/circuitboard/air_management/deconstruct(var/obj/machinery/computer/general_air_control/C) if (..(C)) - console_name = C.name frequency = C.frequency - sensors = C.sensors.Copy() - sensor_information = C.sensor_information.Copy() - return 1 - -/obj/item/weapon/circuitboard/air_management/tank_control/deconstruct(var/obj/machinery/computer/general_air_control/large_tank_control/LTC) - if(..(LTC)) - input_tag = LTC.input_tag - output_tag = LTC.output_tag - - input_info = LTC.input_info.Copy() - output_info = LTC.output_info.Copy() - - input_flow_setting = LTC.input_flow_setting - pressure_setting = LTC.pressure_setting - return 1 - -/obj/item/weapon/circuitboard/air_management/supermatter_core/deconstruct(var/obj/machinery/computer/general_air_control/supermatter_core/SC) - if(..(SC)) - input_tag = SC.input_tag - output_tag = SC.output_tag - - input_info = SC.input_info.Copy() - output_info = SC.output_info.Copy() - - input_flow_setting = SC.input_flow_setting - pressure_setting = SC.input_flow_setting - return 1 - -/obj/item/weapon/circuitboard/air_management/injector_control/deconstruct(var/obj/machinery/computer/general_air_control/fuel_injection/FI) - if(..(FI)) - device_tag = FI.device_tag - device_info = FI.device_info.Copy() - automation = FI.automation - cutoff_temperature = FI.cutoff_temperature - on_temperature = FI.on_temperature - return 1 diff --git a/code/game/objects/items/weapons/circuitboards/computer/holodeckcontrol.dm b/code/game/objects/items/weapons/circuitboards/computer/holodeckcontrol.dm deleted file mode 100644 index db11c4de502..00000000000 --- a/code/game/objects/items/weapons/circuitboards/computer/holodeckcontrol.dm +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef T_BOARD -#error T_BOARD macro is not defined but we need it! -#endif - -/obj/item/weapon/circuitboard/holodeckcontrol - name = T_BOARD("holodeck control console") - build_path = /obj/machinery/computer/HolodeckControl - origin_tech = "programming=2;bluespace=2" - var/last_to_emag - var/linkedholodeck_area - var/list/supported_programs - var/list/restricted_programs - -/obj/item/weapon/circuitboard/holodeckcontrol/construct(var/obj/machinery/computer/HolodeckControl/HC) - if (..(HC)) - HC.supported_programs = supported_programs.Copy() - HC.restricted_programs = restricted_programs.Copy() - if(linkedholodeck_area) - HC.linkedholodeck = locate(linkedholodeck_area) - if(last_to_emag) - HC.last_to_emag = last_to_emag - HC.emagged = 1 - HC.safety_disabled = 1 - -/obj/item/weapon/circuitboard/holodeckcontrol/deconstruct(var/obj/machinery/computer/HolodeckControl/HC) - if (..(HC)) - linkedholodeck_area = HC.linkedholodeck_area - supported_programs = HC.supported_programs.Copy() - restricted_programs = HC.restricted_programs.Copy() - last_to_emag = HC.last_to_emag - HC.emergencyShutdown() diff --git a/code/game/objects/items/weapons/clown_items.dm b/code/game/objects/items/weapons/clown_items.dm index db8a66ac723..e32b58e098f 100644 --- a/code/game/objects/items/weapons/clown_items.dm +++ b/code/game/objects/items/weapons/clown_items.dm @@ -38,11 +38,9 @@ target.clean_blood() return -//attack_as_weapon -/obj/item/weapon/soap/attack(mob/living/target, mob/living/user, var/target_zone) +/obj/item/weapon/soap/attack(mob/target as mob, mob/user as mob) if(target && user && ishuman(target) && ishuman(user) && !target.stat && !user.stat && user.zone_sel &&user.zone_sel.selecting == "mouth" ) user.visible_message("\The [user] washes \the [target]'s mouth out with soap!") - user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) //prevent spam return ..() diff --git a/code/game/objects/items/weapons/dna_injector.dm b/code/game/objects/items/weapons/dna_injector.dm index 24f6ad53b39..484c185a14a 100644 --- a/code/game/objects/items/weapons/dna_injector.dm +++ b/code/game/objects/items/weapons/dna_injector.dm @@ -114,9 +114,6 @@ if(!do_after(user,50)) return - user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) - user.do_attack_animation(M) - M.visible_message("\The [M] has been injected with \the [src] by \the [user].") var/mob/living/carbon/human/H = M diff --git a/code/game/objects/items/weapons/explosives.dm b/code/game/objects/items/weapons/explosives.dm index 6f5e2d3d53c..8e3fed202d8 100644 --- a/code/game/objects/items/weapons/explosives.dm +++ b/code/game/objects/items/weapons/explosives.dm @@ -46,7 +46,6 @@ if (ismob(target) || istype(target, /turf/unsimulated) || istype(target, /turf/simulated/shuttle) || istype(target, /obj/item/weapon/storage/) || istype(target, /obj/item/clothing/accessory/storage/) || istype(target, /obj/item/clothing/under)) return user << "Planting explosives..." - user.do_attack_animation(target) if(do_after(user, 50) && in_range(user, target)) user.drop_item() diff --git a/code/game/objects/items/weapons/gift_wrappaper.dm b/code/game/objects/items/weapons/gift_wrappaper.dm index 46fd181a691..43b58a17264 100644 --- a/code/game/objects/items/weapons/gift_wrappaper.dm +++ b/code/game/objects/items/weapons/gift_wrappaper.dm @@ -61,7 +61,7 @@ qdel(src) /obj/item/weapon/a_gift/attack_self(mob/M as mob) - var/gift_type = pick( + var/gift_type = pick(/obj/item/weapon/sord, /obj/item/weapon/storage/wallet, /obj/item/weapon/storage/photo_album, /obj/item/weapon/storage/box/snappops, @@ -80,6 +80,7 @@ /obj/item/weapon/bikehorn, /obj/item/weapon/beach_ball, /obj/item/weapon/beach_ball/holoball, + /obj/item/weapon/banhammer, /obj/item/toy/balloon, /obj/item/toy/blink, /obj/item/toy/crossbow, diff --git a/code/game/objects/items/weapons/grenades/flashbang.dm b/code/game/objects/items/weapons/grenades/flashbang.dm index 387ca7ed9bd..d01b380925f 100644 --- a/code/game/objects/items/weapons/grenades/flashbang.dm +++ b/code/game/objects/items/weapons/grenades/flashbang.dm @@ -49,7 +49,7 @@ ear_safety += 1 //Flashing everyone - if(eye_safety < FLASH_PROTECTION_MODERATE) + if(eye_safety < 1) flick("e_flash", M.flash) M.Stun(2) M.Weaken(10) diff --git a/code/game/objects/items/weapons/grenades/spawnergrenade.dm b/code/game/objects/items/weapons/grenades/spawnergrenade.dm index 60f5b7a56fa..9677a733459 100644 --- a/code/game/objects/items/weapons/grenades/spawnergrenade.dm +++ b/code/game/objects/items/weapons/grenades/spawnergrenade.dm @@ -16,7 +16,7 @@ var/turf/T = get_turf(src) playsound(T, 'sound/effects/phasein.ogg', 100, 1) for(var/mob/living/carbon/human/M in viewers(T, null)) - if(M.eyecheck() < FLASH_PROTECTION_MODERATE) + if(M:eyecheck() <= 0) flick("e_flash", M.flash) for(var/i=1, i<=deliveryamt, i++) diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm index 61ea05aa261..c88ad3e6419 100644 --- a/code/game/objects/items/weapons/handcuffs.dm +++ b/code/game/objects/items/weapons/handcuffs.dm @@ -73,9 +73,6 @@ msg_admin_attack("[key_name(user)] attempted to handcuff [key_name(H)]") feedback_add_details("handcuffs","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. diff --git a/code/game/objects/items/weapons/implants/implanter.dm b/code/game/objects/items/weapons/implants/implanter.dm index 655727a62ae..4f168556d28 100644 --- a/code/game/objects/items/weapons/implants/implanter.dm +++ b/code/game/objects/items/weapons/implants/implanter.dm @@ -30,18 +30,18 @@ if (!istype(M, /mob/living/carbon)) return if (user && src.imp) - M.visible_message("[user] is attemping to implant [M].") - - user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) - user.do_attack_animation(M) + for (var/mob/O in viewers(M, null)) + O.show_message("[user] is attemping to implant [M].", 1) 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].") + for (var/mob/O in viewers(M, null)) + O.show_message("[M] has been implanted by [user].", 1) 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") + user.show_message("You implanted the implant into [M].") if(src.imp.implanted(M)) src.imp.loc = M src.imp.imp_in = M diff --git a/code/game/objects/items/weapons/material/kitchen.dm b/code/game/objects/items/weapons/material/kitchen.dm index 71a03b982ce..d0e81e95484 100644 --- a/code/game/objects/items/weapons/material/kitchen.dm +++ b/code/game/objects/items/weapons/material/kitchen.dm @@ -34,9 +34,6 @@ else return ..() - if(!M.can_eat(src)) - return - if (reagents.total_volume > 0) reagents.trans_to_mob(M, reagents.total_volume, CHEM_INGEST) if(M == user) @@ -85,6 +82,13 @@ return return ..() +/obj/item/weapon/material/kitchen/utensil/knife/attack(target as mob, mob/living/user as mob) + if ((CLUMSY in user.mutations) && prob(50)) + user << "You somehow managed to cut yourself with the [src]." + user.take_organ_damage(20) + return + return ..() + /obj/item/weapon/material/kitchen/utensil/knife/plastic default_material = "plastic" @@ -104,7 +108,6 @@ /obj/item/weapon/material/kitchen/rollingpin/attack(mob/living/M as mob, mob/living/user as mob) if ((CLUMSY in user.mutations) && prob(50)) user << "The [src] slips out of your hand and hits your head." - user.drop_from_inventory(src) user.take_organ_damage(10) user.Paralyse(2) return diff --git a/code/game/objects/items/weapons/material/material_weapons.dm b/code/game/objects/items/weapons/material/material_weapons.dm index fc9ac7eb32d..18181df6b07 100644 --- a/code/game/objects/items/weapons/material/material_weapons.dm +++ b/code/game/objects/items/weapons/material/material_weapons.dm @@ -64,8 +64,9 @@ processing_objects -= src ..() -/obj/item/weapon/material/apply_hit_effect() - ..() +/obj/item/weapon/material/attack() + if(!..()) + return if(!unbreakable) if(material.is_brittle()) health = 0 diff --git a/code/game/objects/items/weapons/material/misc.dm b/code/game/objects/items/weapons/material/misc.dm index aab9c1a8052..e6d2c995b11 100644 --- a/code/game/objects/items/weapons/material/misc.dm +++ b/code/game/objects/items/weapons/material/misc.dm @@ -55,6 +55,7 @@ icon = 'icons/obj/weapons.dmi' icon_state = "hoe" item_state = "hoe" + flags = CONDUCT | NOBLUDGEON force_divisor = 0.25 // 5 with weight 20 (steel) thrown_force_divisor = 0.25 // as above w_class = 2 diff --git a/code/game/objects/items/weapons/policetape.dm b/code/game/objects/items/weapons/policetape.dm index cdb87b4d84f..50be738ecce 100644 --- a/code/game/objects/items/weapons/policetape.dm +++ b/code/game/objects/items/weapons/policetape.dm @@ -18,7 +18,6 @@ var/list/tape_roll_applications = list() anchored = 1 var/lifted = 0 var/crumpled = 0 - var/tape_dir = 0 var/icon_base /obj/item/tape/New() @@ -33,7 +32,7 @@ var/list/tape_roll_applications = list() /obj/item/taperoll/police name = "police tape" desc = "A roll of police tape used to block off crime scenes from the public." - icon_state = "police" + icon_state = "police_start" tape_type = /obj/item/tape/police icon_base = "police" @@ -46,7 +45,7 @@ var/list/tape_roll_applications = list() /obj/item/taperoll/engineering name = "engineering tape" desc = "A roll of engineering tape used to block off working areas from the public." - icon_state = "engineering" + icon_state = "engineering_start" tape_type = /obj/item/tape/engineering icon_base = "engineering" @@ -56,146 +55,58 @@ var/list/tape_roll_applications = list() req_one_access = list(access_engine,access_atmospherics) icon_base = "engineering" -/obj/item/taperoll/atmos - name = "atmospherics tape" - desc = "A roll of atmospherics tape used to block off working areas from the public." - icon_state = "atmos" - tape_type = /obj/item/tape/atmos - icon_base = "atmos" - -/obj/item/tape/atmos - name = "atmospherics tape" - desc = "A length of atmospherics tape. Better not cross it." - req_one_access = list(access_engine,access_atmospherics) - icon_base = "atmos" - -/obj/item/taperoll/update_icon() - overlays.Cut() - if(ismob(loc)) - if(!start) - overlays += "start" - else - overlays += "stop" - -/obj/item/taperoll/dropped(mob/user) - ..() - update_icon() - -/obj/item/taperoll/pickup(mob/user) - ..() - update_icon() - /obj/item/taperoll/attack_self(mob/user as mob) - if(!start) + if(icon_state == "[icon_base]_start") start = get_turf(src) usr << "You place the first end of \the [src]." - update_icon() + icon_state = "[icon_base]_stop" else + icon_state = "[icon_base]_start" end = get_turf(src) if(start.y != end.y && start.x != end.x || start.z != end.z) - start = null - update_icon() usr << "\The [src] can only be laid horizontally or vertically." return - if(start == end) - // spread tape in all directions, provided there is a wall/window - var/turf/T - var/possible_dirs = 0 - for(var/dir in cardinal) - T = get_step(start, dir) - if(T && T.density) - possible_dirs += dir - else - for(var/obj/structure/window/W in T) - if(W.is_fulltile() || W.dir == reverse_dir[dir]) - possible_dirs += dir - if(!possible_dirs) - start = null - update_icon() - usr << "You can't place \the [src] here." - return - if(possible_dirs & (NORTH|SOUTH)) - var/obj/item/tape/TP = new tape_type(start) - for(var/dir in list(NORTH, SOUTH)) - if (possible_dirs & dir) - TP.tape_dir += dir - TP.icon_state = "[TP.icon_base]_[TP.tape_dir]" - if(possible_dirs & (EAST|WEST)) - var/obj/item/tape/TP = new tape_type(start) - for(var/dir in list(EAST, WEST)) - if (possible_dirs & dir) - TP.tape_dir += dir - TP.icon_state = "[TP.icon_base]_[TP.tape_dir]" - start = null - update_icon() - usr << "You finish placing \the [src]." - return - var/turf/cur = start - var/orientation = get_dir(start, end) - var/dir = 0 - switch(orientation) - if(NORTH, SOUTH) dir = NORTH|SOUTH // North-South taping - if(EAST, WEST) dir = EAST|WEST // East-West taping + var/dir + if (start.x == end.x) + var/d = end.y-start.y + if(d) d = d/abs(d) + end = get_turf(locate(end.x,end.y+d,end.z)) + dir = "v" + else + var/d = end.x-start.x + if(d) d = d/abs(d) + end = get_turf(locate(end.x+d,end.y,end.z)) + dir = "h" var/can_place = 1 - while (can_place) + while (cur!=end && can_place) if(cur.density == 1) can_place = 0 else if (istype(cur, /turf/space)) can_place = 0 else for(var/obj/O in cur) - if(O.density) + if(!istype(O, /obj/item/tape) && O.density) can_place = 0 break - if(cur == end) - break cur = get_step_towards(cur,end) if (!can_place) - start = null - update_icon() usr << "You can't run \the [src] through that!" return cur = start - var/tapetest - var/tape_dir - while (1) - tapetest = 0 - tape_dir = dir - if(cur == start) - var/turf/T = get_step(start, reverse_dir[orientation]) - if(T && !T.density) - tape_dir = orientation - for(var/obj/structure/window/W in T) - if(W.is_fulltile() || W.dir == orientation) - tape_dir = dir - else if(cur == end) - var/turf/T = get_step(end, orientation) - if(T && !T.density) - tape_dir = reverse_dir[orientation] - for(var/obj/structure/window/W in T) - if(W.is_fulltile() || W.dir == reverse_dir[orientation]) - tape_dir = dir - for(var/obj/item/tape/T in cur) - if((T.tape_dir == tape_dir) && (T.icon_base == icon_base)) + var/tapetest = 0 + while (cur!=end) + for(var/obj/item/tape/Ptest in cur) + if(Ptest.icon_state == "[Ptest.icon_base]_[dir]") tapetest = 1 - break - if(!tapetest) - var/obj/item/tape/T = new tape_type(cur) - T.icon_state = "[T.icon_base]_[tape_dir]" - T.tape_dir = tape_dir - if(tape_dir & SOUTH) - T.layer += 0.1 // Must always show above other tapes - if(cur == end) - break + if(tapetest != 1) + var/obj/item/tape/P = new tape_type(cur) + P.icon_state = "[P.icon_base]_[dir]" cur = get_step_towards(cur,end) - start = null - update_icon() usr << "You finish placing \the [src]." - return /obj/item/taperoll/afterattack(var/atom/A, mob/user as mob, proximity) if(!proximity) @@ -238,8 +149,6 @@ var/list/tape_roll_applications = list() add_fingerprint(M) if (!allowed(M)) //only select few learn art of not crumpling the tape M << "You are not supposed to go past [src]..." - if(M.a_intent == I_HELP) - return 0 crumple() return ..(mover) @@ -249,45 +158,13 @@ var/list/tape_roll_applications = list() /obj/item/tape/attack_hand(mob/user as mob) if (user.a_intent == I_HELP && src.allowed(user)) user.show_viewers("\The [user] lifts \the [src], allowing passage.") - for(var/obj/item/tape/T in gettapeline()) - T.lift(100) //~10 seconds + crumple() + lifted = 1 + spawn(200) + lifted = 0 else breaktape(null, user) -/obj/item/tape/proc/lift(time) - lifted = 1 - layer = 8 - spawn(time) - lifted = 0 - layer = initial(layer) - -// Returns a list of all tape objects connected to src, including itself. -/obj/item/tape/proc/gettapeline() - var/list/dirs = list() - if(tape_dir & NORTH) - dirs += NORTH - if(tape_dir & SOUTH) - dirs += SOUTH - if(tape_dir & WEST) - dirs += WEST - if(tape_dir & EAST) - dirs += EAST - - var/list/obj/item/tape/tapeline = list() - for (var/obj/item/tape/T in get_turf(src)) - tapeline += T - for(var/dir in dirs) - var/turf/cur = get_step(src, dir) - var/not_found = 0 - while (!not_found) - not_found = 1 - for (var/obj/item/tape/T in cur) - tapeline += T - not_found = 0 - cur = get_step(cur, dir) - return tapeline - - /obj/item/tape/proc/breaktape(obj/item/weapon/W as obj, mob/user as mob) @@ -296,11 +173,27 @@ var/list/tape_roll_applications = list() return user.show_viewers("\The [user] breaks \the [src]!") - for (var/obj/item/tape/T in gettapeline()) - if(T == src) - continue - if(T.tape_dir & get_dir(T, src)) - qdel(T) + var/dir[2] + var/icon_dir = src.icon_state + if(icon_dir == "[src.icon_base]_h") + dir[1] = EAST + dir[2] = WEST + if(icon_dir == "[src.icon_base]_v") + dir[1] = NORTH + dir[2] = SOUTH + + for(var/i=1;i<3;i++) + var/N = 0 + var/turf/cur = get_step(src,dir[i]) + while(N != 1) + N = 1 + for (var/obj/item/tape/P in cur) + if(P.icon_state == icon_dir) + N = 0 + qdel(P) + cur = get_step(cur,dir[i]) + + qdel(src) + return + - qdel(src) //TODO: Dropping a trash item holding fibers/fingerprints of all broken tape parts - return \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index 3f8ed364990..a67d9e8dafc 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -639,36 +639,35 @@ icon_state = "light" desc = "This box is shaped on the inside so that only light tubes and bulbs fit." item_state = "syringe_kit" + storage_slots=21 + can_hold = list(/obj/item/weapon/light/tube, /obj/item/weapon/light/bulb) + max_storage_space = 42 //holds 21 items of w_class 2 use_to_pickup = 1 // for picking up broken bulbs, not that most people will try - -/obj/item/weapon/storage/box/lights/New() - ..() - make_exact_fit() /obj/item/weapon/storage/box/lights/bulbs/New() + ..() for(var/i = 0; i < 21; i++) new /obj/item/weapon/light/bulb(src) - ..() /obj/item/weapon/storage/box/lights/tubes name = "box of replacement tubes" icon_state = "lighttube" /obj/item/weapon/storage/box/lights/tubes/New() + ..() for(var/i = 0; i < 21; i++) new /obj/item/weapon/light/tube(src) - ..() /obj/item/weapon/storage/box/lights/mixed name = "box of replacement lights" icon_state = "lightmixed" /obj/item/weapon/storage/box/lights/mixed/New() + ..() for(var/i = 0; i < 14; i++) new /obj/item/weapon/light/tube(src) for(var/i = 0; i < 7; i++) new /obj/item/weapon/light/bulb(src) - ..() /obj/item/weapon/storage/box/freezer name = "portable freezer" diff --git a/code/game/objects/items/weapons/storage/firstaid.dm b/code/game/objects/items/weapons/storage/firstaid.dm index a76fb4f1a1f..c23dfcdb516 100644 --- a/code/game/objects/items/weapons/storage/firstaid.dm +++ b/code/game/objects/items/weapons/storage/firstaid.dm @@ -130,7 +130,8 @@ /obj/item/weapon/storage/firstaid/surgery name = "surgery kit" - desc = "Contains tools for surgery. Has precise foam fitting for safe transport." + desc = "Contains tools for surgery." + storage_slots = 10 /obj/item/weapon/storage/firstaid/surgery/New() ..() @@ -145,8 +146,7 @@ new /obj/item/weapon/bonegel(src) new /obj/item/weapon/FixOVein(src) new /obj/item/stack/medical/advanced/bruise_pack(src) - - make_exact_fit() + return /* * Pill Bottles diff --git a/code/game/objects/items/weapons/storage/laundry_basket.dm b/code/game/objects/items/weapons/storage/laundry_basket.dm deleted file mode 100644 index 92dd28c61a5..00000000000 --- a/code/game/objects/items/weapons/storage/laundry_basket.dm +++ /dev/null @@ -1,87 +0,0 @@ -// ----------------------------- -// Laundry Basket -// ----------------------------- -// An item designed for hauling the belongings of a character. -// So this cannot be abused for other uses, we make it two-handed and inable to have its storage looked into. -/obj/item/weapon/storage/laundry_basket - name = "laundry basket" - icon = 'icons/obj/janitor.dmi' - icon_state = "laundry-empty" - item_state = "laundry" - desc = "The peak of thousands of years of laundry evolution." - - w_class = 5 - max_w_class = 4 - max_storage_space = 25 //20 for clothes + a bit of additional space for non-clothing items that were worn on body - storage_slots = 14 - use_to_pickup = 1 - allow_quick_empty = 1 - allow_quick_gather = 1 - collection_mode = 1 - var/linked - - -/obj/item/weapon/storage/laundry_basket/attack_hand(mob/user as mob) - if(ishuman(user)) - var/mob/living/carbon/human/H = user - var/obj/item/organ/external/temp = H.get_organ("r_hand") - if (user.hand) - temp = H.get_organ("l_hand") - if(!temp) - user << "You need two hands to pick this up!" - return - - if(user.get_inactive_hand()) - user << "You need your other hand to be empty" - return - return ..() - -/obj/item/weapon/storage/laundry_basket/attack_self(mob/user as mob) - var/turf/T = get_turf(user) - user << "You dump the [src]'s contents onto \the [T]." - return ..() - -/obj/item/weapon/storage/laundry_basket/pickup(mob/user) - var/obj/item/weapon/storage/laundry_basket/offhand/O = new(user) - O.name = "[name] - second hand" - O.desc = "Your second grip on the [name]." - O.linked = src - user.put_in_inactive_hand(O) - linked = O - return - -/obj/item/weapon/storage/laundry_basket/update_icon() - if(contents.len) - icon_state = "laundry-full" - else - icon_state = "laundry-empty" - return - - -/obj/item/weapon/storage/laundry_basket/MouseDrop(obj/over_object as obj) - if(over_object == usr) - return - else - return ..() - -/obj/item/weapon/storage/laundry_basket/dropped(mob/user as mob) - qdel(linked) - return ..() - -/obj/item/weapon/storage/laundry_basket/show_to(mob/user as mob) - return - -/obj/item/weapon/storage/laundry_basket/open(mob/user as mob) - - -//Offhand -/obj/item/weapon/storage/laundry_basket/offhand - icon = 'icons/obj/weapons.dmi' - icon_state = "offhand" - name = "second hand" - use_to_pickup = 0 - -/obj/item/weapon/storage/laundry_basket/offhand/dropped(mob/user as mob) - user.drop_from_inventory(linked) - return - diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm index 70caa6ba36f..78665633cfd 100644 --- a/code/game/objects/items/weapons/storage/storage.dm +++ b/code/game/objects/items/weapons/storage/storage.dm @@ -235,16 +235,12 @@ usr << "[src] is full, make some space." return 0 //Storage item is full - if(can_hold.len) - if(!is_type_in_list(W, can_hold)) - if(!stop_messages && ! istype(W, /obj/item/weapon/hand_labeler)) - usr << "[src] cannot hold \the [W]." - return 0 - var/max_instances = can_hold[W.type] - if(max_instances && instances_of_type_in_list(W, contents) >= max_instances) - if(!stop_messages && !istype(W, /obj/item/weapon/hand_labeler)) - usr << "[src] has no more space specifically for \the [W]." - return 0 + if(can_hold.len && !is_type_in_list(W, can_hold)) + if(!stop_messages) + if (istype(W, /obj/item/weapon/hand_labeler)) + return 0 + usr << "[src] cannot hold [W]." + return 0 if(cant_hold.len && is_type_in_list(W, cant_hold)) if(!stop_messages) @@ -465,17 +461,6 @@ src.quick_empty() return 1 -/obj/item/weapon/storage/proc/make_exact_fit() - storage_slots = contents.len - - can_hold.Cut() - max_w_class = 0 - max_storage_space = 0 - for(var/obj/item/I in src) - can_hold[I.type]++ - max_w_class = max(I.w_class, max_w_class) - max_storage_space += I.get_storage_cost() - //Returns the storage depth of an atom. This is the number of storage items the atom is contained in before reaching toplevel (the area). //Returns -1 if the atom was not found on container. /atom/proc/storage_depth(atom/container) diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index bbe6e8890a7..7a128d7cfa0 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -102,53 +102,70 @@ user << "[src] is out of charge." add_fingerprint(user) + /obj/item/weapon/melee/baton/attack(mob/M, mob/user) if(status && (CLUMSY in user.mutations) && prob(50)) user << "You accidentally hit yourself with the [src]!" user.Weaken(30) deductcharge(hitcost) return - return ..() -/obj/item/weapon/melee/baton/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) - if(isrobot(target)) - return ..() + if(isrobot(M)) + ..() + return var/agony = agonyforce var/stun = stunforce - var/obj/item/organ/external/affecting = null - if(ishuman(target)) - var/mob/living/carbon/human/H = target - affecting = H.get_organ(hit_zone) + var/mob/living/L = M + var/target_zone = check_zone(user.zone_sel.selecting) if(user.a_intent == I_HURT) - . = ..() - //whacking someone causes a much poorer electrical contact than deliberately prodding them. - agony *= 0.5 + if (!..()) //item/attack() does it's own messaging and logs + return 0 // item/attack() will return 1 if they hit, 0 if they missed. + agony *= 0.5 //whacking someone causes a much poorer contact than prodding them. stun *= 0.5 //we can't really extract the actual hit zone from ..(), unfortunately. Just act like they attacked the area they intended to. - else if(!status) - if(affecting) - target.visible_message("[target] has been prodded in the [affecting.name] with [src] by [user]. Luckily it was off.") - else - target.visible_message("[target] has been prodded with [src] by [user]. Luckily it was off.") else - if(affecting) - target.visible_message("[target] has been prodded in the [affecting.name] with [src] by [user]!") + //copied from human_defense.dm - human defence code should really be refactored some time. + if (ishuman(L)) + user.lastattacked = L //are these used at all, if we have logs? + L.lastattacker = user + + if (user != L) // Attacking yourself can't miss + target_zone = get_zone_with_miss_chance(user.zone_sel.selecting, L) + + if(!target_zone) + L.visible_message("\The [user] misses [L] with \the [src]!") + return 0 + + var/mob/living/carbon/human/H = L + var/obj/item/organ/external/affecting = H.get_organ(target_zone) + if (affecting) + if(!status) + L.visible_message("[L] has been prodded in the [affecting.name] with [src] by [user]. Luckily it was off.") + return 1 + else + H.visible_message("[L] has been prodded in the [affecting.name] with [src] by [user]!") else - target.visible_message("[target] has been prodded with [src] by [user]!") - playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) + if(!status) + L.visible_message("[L] has been prodded with [src] by [user]. Luckily it was off.") + return 1 + else + L.visible_message("[L] has been prodded with [src] by [user]!") //stun effects - if(status) - target.stun_effect_act(stun, agony, hit_zone, src) - msg_admin_attack("[key_name(user)] stunned [key_name(target)] with the [src].") + L.stun_effect_act(stun, agony, target_zone, src) - deductcharge(hitcost) + playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) + msg_admin_attack("[key_name(user)] stunned [key_name(L)] with the [src].") - if(ishuman(target)) - var/mob/living/carbon/human/H = target - H.forcesay(hit_appends) + deductcharge(hitcost) + + if(ishuman(L)) + var/mob/living/carbon/human/H = L + H.forcesay(hit_appends) + + return 1 /obj/item/weapon/melee/baton/emp_act(severity) if(bcell) diff --git a/code/game/objects/items/weapons/swords_axes_etc.dm b/code/game/objects/items/weapons/swords_axes_etc.dm index 8fca8ba8e99..15eb430a3f0 100644 --- a/code/game/objects/items/weapons/swords_axes_etc.dm +++ b/code/game/objects/items/weapons/swords_axes_etc.dm @@ -1,10 +1,18 @@ /* Weapons * Contains: + * Banhammer * Sword * Classic Baton */ -/* +/* + * Banhammer + */ +/obj/item/weapon/banhammer/attack(mob/M as mob, mob/user as mob) + M << " You have been banned FOR NO REISIN by [user]" + user << " You have BANNED [M]" + +/* * Classic Baton */ /obj/item/weapon/melee/classic_baton @@ -26,7 +34,33 @@ else user.take_organ_damage(2*force) return - return ..() +/*this is already called in ..() + src.add_fingerprint(user) + M.attack_log += text("\[[time_stamp()]\] Has been attacked with [src.name] by [user.name] ([user.ckey])") + user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to attack [M.name] ([M.ckey])") + + log_attack("[user.name] ([user.ckey]) attacked [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])") +*/ + if (user.a_intent == I_HURT) + if(!..()) return + //playsound(src.loc, "swing_hit", 50, 1, -1) + if (M.stuttering < 8 && (!(HULK in M.mutations)) /*&& (!istype(H:wear_suit, /obj/item/clothing/suit/judgerobe))*/) + M.stuttering = 8 + M.Stun(8) + M.Weaken(8) + for(var/mob/O in viewers(M)) + if (O.client) O.show_message("\The [M] has been beaten with \the [src] by [user]!", 1, "You hear someone fall", 2) + else + playsound(src.loc, 'sound/weapons/Genhit.ogg', 50, 1, -1) + M.Stun(5) + M.Weaken(5) + M.attack_log += text("\[[time_stamp()]\] Has been attacked with [src.name] by [user.name] ([user.ckey])") + user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to attack [M.name] ([M.ckey])") + msg_admin_attack("[key_name(user)] attacked [key_name(user)] with [src.name] (INTENT: [uppertext(user.a_intent)])") + src.add_fingerprint(user) + + for(var/mob/O in viewers(M)) + if (O.client) O.show_message("\The [M] has been stunned with \the [src] by [user]!", 1, "You hear someone fall", 2) //Telescopic baton /obj/item/weapon/melee/telebaton diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index a8e4f5ac389..a0340c1cd2c 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -41,10 +41,6 @@ processing_objects.Remove(src) - if(istype(loc, /obj/item/device/transfer_valve)) - var/obj/item/device/transfer_valve/TTV = loc - TTV.remove_tank(src) - ..() /obj/item/weapon/tank/examine(mob/user) @@ -253,10 +249,7 @@ qdel(src) else if(pressure > TANK_RUPTURE_PRESSURE) - #ifdef FIREDBG - log_debug("[x],[y] tank is rupturing: [pressure] kPa, integrity [integrity]") - #endif - + //world << "[x],[y] tank is rupturing: [pressure] kPa, integrity [integrity]" if(integrity <= 0) var/turf/simulated/T = get_turf(src) if(!T) @@ -268,10 +261,7 @@ integrity-- else if(pressure > TANK_LEAK_PRESSURE) - #ifdef FIREDBG - log_debug("[x],[y] tank is leaking: [pressure] kPa, integrity [integrity]") - #endif - + //world << "[x],[y] tank is leaking: [pressure] kPa, integrity [integrity]" if(integrity <= 0) var/turf/simulated/T = get_turf(src) if(!T) diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 640c436ccf7..282e7bece66 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -115,7 +115,7 @@ item_state = "cutters_yellow" /obj/item/weapon/wirecutters/attack(mob/living/carbon/C as mob, mob/user as mob) - if(user.a_intent == I_HELP && (C.handcuffed) && (istype(C.handcuffed, /obj/item/weapon/handcuffs/cable))) + if((C.handcuffed) && (istype(C.handcuffed, /obj/item/weapon/handcuffs/cable))) usr.visible_message("\The [usr] cuts \the [C]'s restraints with \the [src]!",\ "You cut \the [C]'s restraints with \the [src]!",\ "You hear cable being cut.") @@ -337,18 +337,18 @@ if(!E) return switch(safety) - if(FLASH_PROTECTION_MODERATE) + if(1) usr << "Your eyes sting a little." E.damage += rand(1, 2) if(E.damage > 12) user.eye_blurry += rand(3,6) - if(FLASH_PROTECTION_NONE) + if(0) usr << "Your eyes burn." E.damage += rand(2, 4) if(E.damage > 10) E.damage += rand(4,10) - if(FLASH_PROTECTION_REDUCED) - usr << "Your equipment intensify the welder's glow. Your eyes itch and burn severely." + if(-1) + 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) diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm index 0f5cebc44da..35302dc5dcd 100644 --- a/code/game/objects/items/weapons/weaponry.dm +++ b/code/game/objects/items/weapons/weaponry.dm @@ -1,3 +1,18 @@ +/obj/item/weapon/banhammer + desc = "banhammer" + name = "banhammer" + icon = 'icons/obj/items.dmi' + icon_state = "toyhammer" + slot_flags = SLOT_BELT + throwforce = 0 + w_class = 2.0 + throw_speed = 7 + throw_range = 15 + attack_verb = list("banned") + + suicide_act(mob/user) + viewers(user) << "[user] is hitting \himself with the [src.name]! It looks like \he's trying to ban \himself from life." + return (BRUTELOSS|FIRELOSS|TOXLOSS|OXYLOSS) /obj/item/weapon/nullrod name = "null rod" @@ -22,9 +37,6 @@ msg_admin_attack("[user.name] ([user.ckey]) attacked [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)]) (JMP)") - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.do_attack_animation(M) - if (!(istype(user, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") user << "You don't have the dexterity to do this!" return @@ -56,6 +68,27 @@ user << "You hit the floor with the [src]." call(/obj/effect/rune/proc/revealrunes)(src) +/obj/item/weapon/sord + name = "\improper SORD" + desc = "This thing is so unspeakably shitty you are having a hard time even holding it." + icon_state = "sord" + item_state = "sord" + slot_flags = SLOT_BELT + force = 2 + throwforce = 1 + sharp = 1 + edge = 1 + w_class = 3 + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + + suicide_act(mob/user) + viewers(user) << "[user] is impaling \himself with the [src.name]! It looks like \he's trying to commit suicide." + return(BRUTELOSS) + +/obj/item/weapon/sord/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) + playsound(loc, 'sound/weapons/bladeslice.ogg', 50, 1, -1) + return ..() + /obj/item/weapon/energy_net name = "energy net" desc = "It's a net made of green energy." diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 51e97c66aa4..800659307e8 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -46,11 +46,7 @@ /obj/proc/CouldUseTopic(var/mob/user) var/atom/host = nano_host() - if(!isAI(user) && host.Adjacent(user)) - // We are -probably- in physical contact with the object, better than how Topics() previously did it and always applied fingerprints. - host.add_fingerprint(user) - else - host.add_hiddenprint(user) + host.add_hiddenprint(user) /obj/proc/CouldNotUseTopic(var/mob/user) // Nada diff --git a/code/game/objects/structures/alien/alien.dm b/code/game/objects/structures/alien/alien.dm deleted file mode 100644 index df94cf95ac9..00000000000 --- a/code/game/objects/structures/alien/alien.dm +++ /dev/null @@ -1,61 +0,0 @@ -/obj/structure/alien - name = "alien thing" - desc = "There's something alien about this." - icon = 'icons/mob/alien.dmi' - var/health = 50 - -/obj/structure/alien/proc/healthcheck() - if(health <=0) - density = 0 - qdel(src) - return - -/obj/structure/alien/bullet_act(var/obj/item/projectile/Proj) - health -= Proj.damage - ..() - healthcheck() - return - -/obj/structure/alien/ex_act(severity) - switch(severity) - if(1.0) - health-=50 - if(2.0) - health-=50 - if(3.0) - if (prob(50)) - health-=50 - else - health-=25 - healthcheck() - return - -/obj/structure/alien/hitby(AM as mob|obj) - ..() - visible_message("\The [src] was hit by \the [AM].") - var/tforce = 0 - if(ismob(AM)) - tforce = 10 - else - tforce = AM:throwforce - playsound(loc, 'sound/effects/attackblob.ogg', 100, 1) - health = max(0, health - tforce) - healthcheck() - ..() - return - -/obj/structure/alien/attack_generic() - attack_hand(usr) - -/obj/structure/alien/attackby(var/obj/item/weapon/W, var/mob/user) - health = max(0, health - W.force) - playsound(loc, 'sound/effects/attackblob.ogg', 100, 1) - healthcheck() - ..() - return - -/obj/structure/alien/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) - if(air_group) return 0 - if(istype(mover) && mover.checkpass(PASSGLASS)) - return !opacity - return !density \ No newline at end of file diff --git a/code/game/objects/structures/alien/egg.dm b/code/game/objects/structures/alien/egg.dm deleted file mode 100644 index c16c1a182e8..00000000000 --- a/code/game/objects/structures/alien/egg.dm +++ /dev/null @@ -1,96 +0,0 @@ -#define MAX_PROGRESS 100 - -/obj/structure/alien/egg - desc = "It looks like a weird egg." - name = "egg" - icon_state = "egg_growing" - density = 0 - anchored = 1 - var/progress = 0 - -/obj/structure/alien/egg/New() - ..() - processing_objects += src - -/obj/structure/alien/egg/Destroy() - processing_objects -= src - ..() - -/obj/structure/alien/egg/CanUseTopic(var/mob/user) - return isobserver(user) ? STATUS_INTERACTIVE : STATUS_CLOSE - -/obj/structure/alien/egg/Topic(href, href_list) - if(..()) - return 1 - - if(href_list["spawn"]) - attack_ghost(usr) - -/obj/structure/alien/egg/process() - progress++ - if(progress >= MAX_PROGRESS) - for(var/mob/M in dead_mob_list) - if(istype(M,/mob/dead) && M.client && M.client.prefs && (M.client.prefs.be_special & BE_ALIEN)) - M << "An alien is ready to hatch! ([ghost_follow_link(src, M)]) (spawn)" - processing_objects -= src - update_icon() - -/obj/structure/alien/egg/update_icon() - if(progress == -1) - icon_state = "egg_hatched" - else if(progress < MAX_PROGRESS) - icon_state = "egg_growing" - else - icon_state = "egg" - -/obj/structure/alien/egg/attack_ghost(var/mob/dead/observer/user) - if(progress == -1) //Egg has been hatched. - return - - if(progress < MAX_PROGRESS) - user << "\The [src] has not yet matured." - return - - if(!user.MayRespawn(1)) - return - - // Check for bans properly. - if(jobban_isbanned(user, "Xenomorph")) - user << "You are banned from playing a Xenomorph." - return - - var/confirm = alert(user, "Are you sure you want to join as a Xenomorph larva?", "Become Larva", "No", "Yes") - - if(!src || confirm != "Yes") - return - - if(!user || !user.ckey) - return - - if(progress == -1) //Egg has been hatched. - user << "Too slow..." - return - - flick("egg_opening",src) - progress = -1 // No harvesting pls. - sleep(5) - - if(!src || !user) - visible_message("\The [src] writhes with internal motion, but nothing comes out.") - progress = MAX_PROGRESS // Someone else can have a go. - return // What a pain. - - // Create the mob, transfer over key. - var/mob/living/carbon/alien/larva/larva = new(get_turf(src)) - larva.ckey = user.ckey - spawn(-1) - if(user) qdel(user) // Remove the keyless ghost if it exists. - - visible_message("\The [src] splits open with a wet slithering noise, and \the [larva] writhes free!") - - // Turn us into a hatched egg. - name = "hatched alien egg" - desc += " This one has hatched." - update_icon() - -#undef MAX_PROGRESS diff --git a/code/game/objects/structures/alien/node.dm b/code/game/objects/structures/alien/node.dm deleted file mode 100644 index 15a9062862f..00000000000 --- a/code/game/objects/structures/alien/node.dm +++ /dev/null @@ -1,19 +0,0 @@ -/obj/structure/alien/node - name = "alien weed node" - desc = "Some kind of strange, pulsating structure." - icon_state = "weednode" - health = 100 - layer = 3.1 - -/obj/structure/alien/node/New() - ..() - processing_objects += src - -/obj/structure/alien/node/Destroy() - processing_objects -= src - ..() - -/obj/structure/alien/node/process() - if(locate(/obj/effect/plant) in loc) - return - new /obj/effect/plant(get_turf(src), plant_controller.seeds["xenomorph"]) diff --git a/code/game/objects/structures/alien/resin.dm b/code/game/objects/structures/alien/resin.dm deleted file mode 100644 index 05f6bca0e72..00000000000 --- a/code/game/objects/structures/alien/resin.dm +++ /dev/null @@ -1,50 +0,0 @@ -/obj/structure/alien/resin - name = "resin" - desc = "Looks like some kind of slimy growth." - icon_state = "resin" - - density = 1 - opacity = 1 - anchored = 1 - health = 200 - -/obj/structure/alien/resin/wall - name = "resin wall" - desc = "Purple slime solidified into a wall." - icon_state = "resinwall" - -/obj/structure/alien/resin/membrane - name = "resin membrane" - desc = "Purple slime just thin enough to let light pass through." - icon_state = "resinmembrane" - opacity = 0 - health = 120 - -/obj/structure/alien/resin/New() - ..() - var/turf/T = get_turf(src) - T.thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT - -/obj/structure/alien/resin/Destroy() - var/turf/T = get_turf(src) - T.thermal_conductivity = initial(T.thermal_conductivity) - ..() - -/obj/structure/alien/resin/attack_hand(var/mob/user) - if (HULK in user.mutations) - visible_message("\The [user] destroys \the [name]!") - health = 0 - else - // Aliens can get straight through these. - if(istype(user,/mob/living/carbon)) - var/mob/living/carbon/M = user - if(locate(/obj/item/organ/xenos/hivenode) in M.internal_organs) - visible_message("\The [user] strokes \the [name] and it melts away!") - health = 0 - healthcheck() - return - visible_message("\The [user] claws at \the [src]!") - // Todo check attack datums. - health -= rand(5,10) - healthcheck() - return \ No newline at end of file diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 852a0a3dcd8..105f2987df3 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -217,15 +217,6 @@ M.show_message("\The [src] has been cut apart by [user] with \the [WT].", 3, "You hear welding.", 2) qdel(src) return - if(istype(W, /obj/item/weapon/storage/laundry_basket) && W.contents.len) - var/obj/item/weapon/storage/laundry_basket/LB = W - var/turf/T = get_turf(src) - for(var/obj/item/I in LB.contents) - LB.remove_from_storage(I, T) - user.visible_message("[user] empties \the [LB] into \the [src].", \ - "You empty \the [LB] into \the [src].", \ - "You hear rustling of clothes.") - return if(isrobot(user)) return if(W.loc != user) // This should stop mounted modules ending up outside the module. diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm index bd2b216888b..a3e3ad86181 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm @@ -160,6 +160,6 @@ new /obj/item/clothing/suit/storage/hazardvest(src) new /obj/item/clothing/mask/gas(src) new /obj/item/weapon/cartridge/atmos(src) - new /obj/item/taperoll/atmos(src) + new /obj/item/taperoll/engineering(src) new /obj/item/clothing/suit/storage/hooded/wintercoat/engineering/atmos(src) return diff --git a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm index 076c999edba..7401aac67b3 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm @@ -65,8 +65,6 @@ /obj/structure/closet/secure_closet/attackby(obj/item/weapon/W as obj, mob/user as mob) if(src.opened) - if(istype(W, /obj/item/weapon/storage/laundry_basket)) - return ..(W,user) if(istype(W, /obj/item/weapon/grab)) var/obj/item/weapon/grab/G = W if(src.large) diff --git a/code/game/objects/structures/inflatable.dm b/code/game/objects/structures/inflatable.dm index 035826d1384..3d867111cce 100644 --- a/code/game/objects/structures/inflatable.dm +++ b/code/game/objects/structures/inflatable.dm @@ -40,7 +40,7 @@ /obj/structure/inflatable/bullet_act(var/obj/item/projectile/Proj) var/proj_damage = Proj.get_structure_damage() if(!proj_damage) return - + health -= proj_damage ..() if(health <= 0) @@ -82,9 +82,6 @@ if(health <= 0) deflate(1) -/obj/structure/inflatable/CtrlClick() - hand_deflate() - /obj/structure/inflatable/proc/deflate(var/violent=0) playsound(loc, 'sound/machines/hiss.ogg', 75, 1) if(violent) @@ -105,7 +102,7 @@ set category = "Object" set src in oview(1) - if(isobserver(usr) || usr.restrained() || !usr.Adjacent(src)) + if(isobserver(usr)) //to stop ghosts from deflating return verbs -= /obj/structure/inflatable/verb/hand_deflate diff --git a/code/game/objects/structures/lamarr_cage.dm b/code/game/objects/structures/lamarr_cage.dm new file mode 100644 index 00000000000..7d0bc76b180 --- /dev/null +++ b/code/game/objects/structures/lamarr_cage.dm @@ -0,0 +1,87 @@ +/obj/structure/lamarr + name = "lab cage" + icon = 'icons/obj/stationobjs.dmi' + icon_state = "labcage1" + desc = "A glass lab container for storing interesting creatures." + density = 1 + anchored = 1 + unacidable = 1//Dissolving the case would also delete Lamarr + var/health = 30 + var/occupied = 1 + var/destroyed = 0 + +/obj/structure/lamarr/ex_act(severity) + switch(severity) + if (1) + new /obj/item/weapon/material/shard( src.loc ) + Break() + qdel(src) + if (2) + if (prob(50)) + src.health -= 15 + src.healthcheck() + if (3) + if (prob(50)) + src.health -= 5 + src.healthcheck() + + +/obj/structure/lamarr/bullet_act(var/obj/item/projectile/Proj) + health -= Proj.damage + ..() + src.healthcheck() + return + +/obj/structure/lamarr/proc/healthcheck() + if (src.health <= 0) + if (!( src.destroyed )) + src.density = 0 + src.destroyed = 1 + new /obj/item/weapon/material/shard( src.loc ) + playsound(src, "shatter", 70, 1) + Break() + else + playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) + return + +/obj/structure/lamarr/update_icon() + if(src.destroyed) + src.icon_state = "labcageb[src.occupied]" + else + src.icon_state = "labcage[src.occupied]" + return + + +/obj/structure/lamarr/attackby(obj/item/weapon/W as obj, mob/user as mob) + src.health -= W.force + src.healthcheck() + ..() + return + +/obj/structure/lamarr/attack_hand(mob/user as mob) + if (src.destroyed) + return + else + usr << "You kick the lab cage." + for(var/mob/O in oviewers()) + if ((O.client && !( O.blinded ))) + O << "[usr] kicks the lab cage." + src.health -= 2 + healthcheck() + return + +/obj/structure/lamarr/proc/Break() + if(occupied) + new /obj/item/clothing/mask/facehugger/lamarr(src.loc) + occupied = 0 + update_icon() + return + +/obj/item/clothing/mask/facehugger/lamarr + name = "Lamarr" + desc = "The worst she might do is attempt to... couple with your head."//hope we don't get sued over a harmless reference, rite? + sterile = 1 + gender = FEMALE + +/obj/item/clothing/mask/facehugger/lamarr/New()//to prevent deleting it if aliums are disabled + return diff --git a/code/game/objects/structures/stool_bed_chair_nest/stools.dm b/code/game/objects/structures/stool_bed_chair_nest/stools.dm index 1faf83f4414..e4840bedc63 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/stools.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/stools.dm @@ -72,9 +72,6 @@ var/global/list/stool_cache = list() //haha stool /obj/item/weapon/stool/attack(mob/M as mob, mob/user as mob) if (prob(5) && istype(M,/mob/living)) user.visible_message("[user] breaks [src] over [M]'s back!") - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.do_attack_animation(M) - user.remove_from_mob(src) dismantle() qdel(src) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 87895d3950e..440cc6a8a28 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -293,7 +293,7 @@ if(usr.incapacitated()) return 0 - + if(anchored) usr << "It is fastened to the floor therefore you can't rotate it!" return 0 @@ -491,23 +491,7 @@ animate(src, color="#222222", time=5) set_opacity(1) -/obj/structure/window/reinforced/crescent/attack_hand() - return -/obj/structure/window/reinforced/crescent/attackby() - return - -/obj/structure/window/reinforced/crescent/ex_act() - return - -/obj/structure/window/reinforced/crescent/hitby() - return - -/obj/structure/window/reinforced/crescent/take_damage() - return - -/obj/structure/window/reinforced/crescent/shatter() - return /obj/machinery/button/windowtint name = "window tint control" diff --git a/code/game/objects/structures/window_spawner.dm b/code/game/objects/structures/window_spawner.dm index 96f375d9e5b..449001492b2 100644 --- a/code/game/objects/structures/window_spawner.dm +++ b/code/game/objects/structures/window_spawner.dm @@ -70,7 +70,12 @@ /obj/effect/wingrille_spawn/reinforced/crescent name = "Crescent window grille spawner" - win_path = /obj/structure/window/reinforced/crescent + icon_state = "r-wingrille" + win_path = /obj/structure/window/reinforced + +/obj/effect/wingrille_spawn/reinforced/crescent/handle_window_spawn(var/obj/structure/window/W) + W.maxhealth = 1000000 + W.health = 1000000 /obj/effect/wingrille_spawn/phoron name = "phoron window grille spawner" diff --git a/code/global.dm b/code/global.dm index dc7c19c45ce..643073055ed 100644 --- a/code/global.dm +++ b/code/global.dm @@ -80,6 +80,7 @@ var/list/tdomeobserve = list() var/list/tdomeadmin = list() var/list/prisonsecuritywarp = list() // Prison security goes to these. var/list/prisonwarped = list() // List of players already warped. +var/list/blobstart = list() var/list/ninjastart = list() var/list/cardinal = list(NORTH, SOUTH, EAST, WEST) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 32b6bde1d42..d7024147d07 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -1293,7 +1293,7 @@ proc/admin_notice(var/message, var/rights) var/datum/antagonist/antag = all_antag_types[antag_type] message_admins("[key_name(usr)] attempting to force latespawn with template [antag.id].") - antag.attempt_auto_spawn() + antag.attempt_late_spawn() /datum/admins/proc/force_mode_latespawn() set category = "Admin" @@ -1310,5 +1310,6 @@ proc/admin_notice(var/message, var/rights) usr << "Mode has not started." return - message_admins("[key_name(usr)] attempting to force mode autospawn.") - ticker.mode.process_autoantag() + message_admins("[key_name(usr)] attempting to force mode latespawn.") + ticker.mode.next_spawn = 0 + ticker.mode.try_latespawn() diff --git a/code/modules/admin/admin_attack_log.dm b/code/modules/admin/admin_attack_log.dm index 918739ec8ff..967a4375da7 100644 --- a/code/modules/admin/admin_attack_log.dm +++ b/code/modules/admin/admin_attack_log.dm @@ -1,9 +1,6 @@ /mob/var/lastattacker = null /mob/var/lastattacked = null -/mob/var/attack_log = list() - -proc/log_and_message_admins_with_location(var/message, var/x, var/y, var/z, var/mob/user = usr) - log_and_message_admins("[message] (JMP)", user) +/mob/var/attack_log = list( ) proc/log_and_message_admins(var/message as text, var/mob/user = usr) log_admin(user ? "[key_name(user)] [message]" : "EVENT [message]") diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 53ff4c3a75f..a76565bf759 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1119,6 +1119,16 @@ log_admin("[key_name(usr)] AIized [key_name(H)]") H.AIize() + else if(href_list["makealien"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/human/H = locate(href_list["makealien"]) + if(!istype(H)) + usr << "This can only be used on instances of type /mob/living/carbon/human" + return + + usr.client.cmd_admin_alienize(H) + else if(href_list["makeslime"]) if(!check_rights(R_SPAWN)) return diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 9154badcc6b..11591be4b13 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -16,7 +16,6 @@ // callproc moved to code/modules/admin/callproc - /client/proc/Cell() set category = "Debug" set name = "Cell" @@ -101,6 +100,23 @@ paiController.pai_candidates.Remove(candidate) feedback_add_details("admin_verb","MPAI") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! +/client/proc/cmd_admin_alienize(var/mob/M in mob_list) + set category = "Fun" + set name = "Make Alien" + + if(!ticker) + alert("Wait until the game starts") + return + if(ishuman(M)) + log_admin("[key_name(src)] has alienized [M.key].") + spawn(10) + M:Alienize() + feedback_add_details("admin_verb","MKAL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + log_admin("[key_name(usr)] made [key_name(M)] into an alien.") + message_admins("\blue [key_name_admin(usr)] made [key_name(M)] into an alien.", 1) + else + alert("Invalid mob") + /client/proc/cmd_admin_slimeize(var/mob/M in mob_list) set category = "Fun" set name = "Make slime" diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 29d2b95d88e..bd3c4be0d92 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -162,7 +162,6 @@ var/list/debug_verbs = list ( ,/client/proc/testZAScolors_remove ,/client/proc/setup_supermatter_engine ,/client/proc/atmos_toggle_debug - ,/client/proc/spawn_tanktransferbomb ) diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm index 6f05d00de6c..c842170b6b1 100644 --- a/code/modules/admin/view_variables/topic.dm +++ b/code/modules/admin/view_variables/topic.dm @@ -278,6 +278,20 @@ return holder.Topic(href, list("makerobot"=href_list["makerobot"])) + else if(href_list["makealien"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/human/H = locate(href_list["makealien"]) + if(!istype(H)) + usr << "This can only be done to instances of type /mob/living/carbon/human" + return + + if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") return + if(!H) + usr << "Mob doesn't exist anymore" + return + holder.Topic(href, list("makealien"=href_list["makealien"])) + else if(href_list["makeslime"]) if(!check_rights(R_SPAWN)) return diff --git a/code/modules/client/preference_setup/antagonism/01_basic.dm b/code/modules/client/preference_setup/antagonism/01_basic.dm deleted file mode 100644 index eefc531da15..00000000000 --- a/code/modules/client/preference_setup/antagonism/01_basic.dm +++ /dev/null @@ -1,38 +0,0 @@ -var/global/list/uplink_locations = list("PDA", "Headset", "None") - -/datum/category_item/player_setup_item/antagonism/basic - name = "Basic" - sort_order = 1 - -/datum/category_item/player_setup_item/antagonism/basic/load_character(var/savefile/S) - S["uplinklocation"] >> pref.uplinklocation - S["exploit_record"] >> pref.exploit_record - -/datum/category_item/player_setup_item/antagonism/basic/save_character(var/savefile/S) - S["uplinklocation"] << pref.uplinklocation - S["exploit_record"] << pref.exploit_record - -/datum/category_item/player_setup_item/antagonism/basic/sanitize_character() - pref.uplinklocation = sanitize_inlist(pref.uplinklocation, uplink_locations, initial(pref.uplinklocation)) - -/datum/category_item/player_setup_item/antagonism/basic/content(var/mob/user) - . +="Uplink Type : [pref.uplinklocation]" - . +="
" - . +="Exploitable information:
" - if(jobban_isbanned(user, "Records")) - . += "You are banned from using character records.
" - else - . +="[TextPreview(pref.exploit_record,40)]
" - -/datum/category_item/player_setup_item/antagonism/basic/OnTopic(var/href,var/list/href_list, var/mob/user) - if (href_list["antagtask"]) - pref.uplinklocation = next_in_list(pref.uplinklocation, uplink_locations) - return TOPIC_REFRESH - - if(href_list["exploitable_record"]) - var/exploitmsg = sanitize(input(user,"Set exploitable information about you here.","Exploitable Information", html_decode(pref.exploit_record)) as message|null, MAX_PAPER_MESSAGE_LEN, extra = 0) - if(!isnull(exploitmsg) && !jobban_isbanned(user, "Records") && CanUseTopic(user)) - pref.exploit_record = exploitmsg - return TOPIC_REFRESH - - return ..() diff --git a/code/modules/client/preference_setup/antagonism/02_candidacy.dm b/code/modules/client/preference_setup/antagonism/02_candidacy.dm deleted file mode 100644 index 82d44027afe..00000000000 --- a/code/modules/client/preference_setup/antagonism/02_candidacy.dm +++ /dev/null @@ -1,54 +0,0 @@ -var/global/list/special_roles = list( //keep synced with the defines BE_* in setup.dm --rastaf -//some autodetection here. -// TODO: Update to new antagonist system. - "traitor" = IS_MODE_COMPILED("traitor"), // 0 - "operative" = IS_MODE_COMPILED("nuclear"), // 1 - "changeling" = IS_MODE_COMPILED("changeling"), // 2 - "wizard" = IS_MODE_COMPILED("wizard"), // 3 - "malf AI" = IS_MODE_COMPILED("malfunction"), // 4 - "revolutionary" = IS_MODE_COMPILED("revolution"), // 5 - "alien candidate" = 1, //always show // 6 - "positronic brain" = 1, // 7 - "cultist" = IS_MODE_COMPILED("cult"), // 8 - "infested monkey" = IS_MODE_COMPILED("monkey"), // 9 - "ninja" = "true", // 10 - "raider" = IS_MODE_COMPILED("heist"), // 11 - "diona" = 1, // 12 - "loyalist" = IS_MODE_COMPILED("revolution"), // 13 - "pAI candidate" = 1, // -- TLE // 14 -) - -/datum/category_item/player_setup_item/antagonism/candidacy - name = "Candidacy" - sort_order = 2 - -/datum/category_item/player_setup_item/antagonism/candidacy/load_character(var/savefile/S) - S["be_special"] >> pref.be_special - -/datum/category_item/player_setup_item/antagonism/candidacy/save_character(var/savefile/S) - S["be_special"] << pref.be_special - -/datum/category_item/player_setup_item/antagonism/candidacy/sanitize_character() - pref.be_special = sanitize_integer(pref.be_special, 0, 65535, initial(pref.be_special)) - -/datum/category_item/player_setup_item/antagonism/candidacy/content(var/mob/user) - if(jobban_isbanned(user, "Syndicate")) - . += "You are banned from antagonist roles." - pref.be_special = 0 - else - var/n = 0 - for (var/i in special_roles) - if(special_roles[i]) //if mode is available on the server - if(jobban_isbanned(user, i) || (i == "positronic brain" && jobban_isbanned(user, "AI") && jobban_isbanned(user, "Cyborg")) || (i == "pAI candidate" && jobban_isbanned(user, "pAI"))) - . += "Be [i]: \[BANNED]
" - else - . += "Be [i]: [pref.be_special&(1<
" - n++ - -/datum/category_item/player_setup_item/antagonism/candidacy/OnTopic(var/href,var/list/href_list, var/mob/user) - if(href_list["be_special"]) - var/num = text2num(href_list["be_special"]) - pref.be_special ^= (1<> pref.real_name - S["name_is_always_random"] >> pref.be_random_name - S["gender"] >> pref.gender - S["age"] >> pref.age - S["spawnpoint"] >> pref.spawnpoint - S["OOC_Notes"] >> pref.metadata - -/datum/category_item/player_setup_item/general/basic/save_character(var/savefile/S) - S["real_name"] << pref.real_name - S["name_is_always_random"] << pref.be_random_name - S["gender"] << pref.gender - S["age"] << pref.age - S["spawnpoint"] << pref.spawnpoint - S["OOC_Notes"] << pref.metadata - -/datum/category_item/player_setup_item/general/basic/sanitize_character() - pref.real_name = sanitizeName(pref.real_name) - if(!pref.real_name) - pref.real_name = random_name(pref.gender, pref.species) - pref.spawnpoint = sanitize_inlist(pref.spawnpoint, spawntypes, initial(pref.spawnpoint)) - pref.be_random_name = sanitize_integer(pref.be_random_name, 0, 1, initial(pref.be_random_name)) - pref.age = sanitize_integer(pref.age, AGE_MIN, AGE_MAX, initial(pref.age)) - -/datum/category_item/player_setup_item/general/basic/content() - . = "Name: " - . += "[pref.real_name]
" - . += "(Random Name) " - . += "(Always Random Name: [pref.be_random_name ? "Yes" : "No"])" - . += "
" - . += "Gender: [pref.gender == MALE ? "Male" : "Female"]
" - . += "Age: [pref.age]
" - . += "Spawn Point: [pref.spawnpoint]
" - if(config.allow_Metadata) - . += "OOC Notes: Edit
" - -/datum/category_item/player_setup_item/general/basic/OnTopic(var/href,var/list/href_list, var/mob/user) - if(href_list["rename"]) - var/raw_name = input(user, "Choose your character's name:", "Character Name") as text|null - if (!isnull(raw_name) && CanUseTopic(user)) - var/new_name = sanitizeName(raw_name) - if(new_name) - pref.real_name = new_name - return TOPIC_REFRESH - else - user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and ." - return TOPIC_NOACTION - - else if(href_list["random_name"]) - pref.real_name = random_name(pref.gender, pref.species) - return TOPIC_REFRESH - - else if(href_list["always_random_name"]) - pref.be_random_name = !pref.be_random_name - return TOPIC_REFRESH - - else if(href_list["gender"]) - if(pref.gender == MALE) - pref.gender = FEMALE - else - pref.gender = MALE - return TOPIC_REFRESH - - else if(href_list["age"]) - var/new_age = input(user, "Choose your character's age:\n([AGE_MIN]-[AGE_MAX])", "Character Preference", pref.age) as num|null - if(new_age && CanUseTopic(user)) - pref.age = max(min(round(text2num(new_age)), AGE_MAX), AGE_MIN) - return TOPIC_REFRESH - - else if(href_list["spawnpoint"]) - var/list/spawnkeys = list() - for(var/S in spawntypes) - spawnkeys += S - var/choice = input(user, "Where would you like to spawn when late-joining?") as null|anything in spawnkeys - if(!choice || !spawntypes[choice] || !CanUseTopic(user)) return TOPIC_NOACTION - pref.spawnpoint = choice - return TOPIC_REFRESH - - - else if(href_list["metadata"]) - var/new_metadata = sanitize(input(user, "Enter any information you'd like others to see, such as Roleplay-preferences:", "Game Preference" , pref.metadata)) as message|null - if(new_metadata && CanUseTopic(user)) - pref.metadata = sanitize(new_metadata) - return TOPIC_REFRESH - - return ..() diff --git a/code/modules/client/preference_setup/general/02_language.dm b/code/modules/client/preference_setup/general/02_language.dm deleted file mode 100644 index 7e9a803766d..00000000000 --- a/code/modules/client/preference_setup/general/02_language.dm +++ /dev/null @@ -1,93 +0,0 @@ -/datum/category_item/player_setup_item/general/language - name = "Language" - sort_order = 2 - -/datum/category_item/player_setup_item/general/language/load_character(var/savefile/S) - S["language"] >> pref.alternate_languages - S["language_prefixes"] >> pref.language_prefixes - -/datum/category_item/player_setup_item/general/language/save_character(var/savefile/S) - S["language"] << pref.alternate_languages - S["language_prefixes"] << pref.language_prefixes - -/datum/category_item/player_setup_item/general/language/sanitize_character() - if(!islist(pref.alternate_languages)) pref.alternate_languages = list() - if(isnull(pref.language_prefixes) || !pref.language_prefixes.len) - pref.language_prefixes = config.language_prefixes.Copy() - -/datum/category_item/player_setup_item/general/language/content() - . += "Languages
" - var/datum/species/S = all_species[pref.species] - if(S.language) - . += "- [S.language]
" - if(S.default_language && S.default_language != S.language) - . += "- [S.default_language]
" - if(S.num_alternate_languages) - if(pref.alternate_languages.len) - for(var/i = 1 to pref.alternate_languages.len) - var/lang = pref.alternate_languages[i] - . += "- [lang] - remove
" - - if(pref.alternate_languages.len < S.num_alternate_languages) - . += "- add ([S.num_alternate_languages - pref.alternate_languages.len] remaining)
" - else - . += "- [pref.species] cannot choose secondary languages.
" - - . += "Language Keys
" - . += " [english_list(pref.language_prefixes, and_text = " ", comma_text = " ")] Change Reset
" - -/datum/category_item/player_setup_item/general/language/OnTopic(var/href,var/list/href_list, var/mob/user) - if(href_list["remove_language"]) - var/index = text2num(href_list["remove_language"]) - pref.alternate_languages.Cut(index, index+1) - return TOPIC_REFRESH - else if(href_list["add_language"]) - var/datum/species/S = all_species[pref.species] - if(pref.alternate_languages.len >= S.num_alternate_languages) - alert(user, "You have already selected the maximum number of alternate languages for this species!") - else - var/list/available_languages = S.secondary_langs.Copy() - for(var/L in all_languages) - var/datum/language/lang = all_languages[L] - if(!(lang.flags & RESTRICTED) && (!config.usealienwhitelist || is_alien_whitelisted(user, L) || !(lang.flags & WHITELISTED))) - available_languages |= L - - // make sure we don't let them waste slots on the default languages - available_languages -= S.language - available_languages -= S.default_language - available_languages -= pref.alternate_languages - - if(!available_languages.len) - alert(user, "There are no additional languages available to select.") - else - var/new_lang = input(user, "Select an additional language", "Character Generation", null) as null|anything in available_languages - if(new_lang) - pref.alternate_languages |= new_lang - return TOPIC_REFRESH - - else if(href_list["change_prefix"]) - var/char - var/keys[0] - do - char = input("Enter a single special character.\nYou may re-select the same characters.\nThe following characters are already in use by radio: ; : .\nThe following characters are already in use by special say commands: ! * ^", "Enter Character - [3 - keys.len] remaining") as null|text - if(char) - if(length(char) > 1) - alert(user, "Only single characters allowed.", "Error", "Ok") - else if(char in list(";", ":", ".")) - alert(user, "Radio character. Rejected.", "Error", "Ok") - else if(char in list("!","*", "^")) - alert(user, "Say character. Rejected.", "Error", "Ok") - else if(contains_az09(char)) - alert(user, "Non-special character. Rejected.", "Error", "Ok") - else - keys.Add(char) - while(char && keys.len < 3) - - if(keys.len == 3) - pref.language_prefixes = keys - return TOPIC_REFRESH - else if(href_list["reset_prefix"]) - pref.language_prefixes = config.language_prefixes.Copy() - return TOPIC_REFRESH - - return ..() diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm deleted file mode 100644 index 07530881fe3..00000000000 --- a/code/modules/client/preference_setup/general/03_body.dm +++ /dev/null @@ -1,498 +0,0 @@ -var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-") - -/datum/category_item/player_setup_item/general/body - name = "Body" - sort_order = 3 - -/datum/category_item/player_setup_item/general/body/load_character(var/savefile/S) - S["species"] >> pref.species - S["hair_red"] >> pref.r_hair - S["hair_green"] >> pref.g_hair - S["hair_blue"] >> pref.b_hair - S["facial_red"] >> pref.r_facial - S["facial_green"] >> pref.g_facial - S["facial_blue"] >> pref.b_facial - S["skin_tone"] >> pref.s_tone - S["skin_red"] >> pref.r_skin - S["skin_green"] >> pref.g_skin - S["skin_blue"] >> pref.b_skin - S["hair_style_name"] >> pref.h_style - S["facial_style_name"] >> pref.f_style - S["eyes_red"] >> pref.r_eyes - S["eyes_green"] >> pref.g_eyes - S["eyes_blue"] >> pref.b_eyes - S["b_type"] >> pref.b_type - S["disabilities"] >> pref.disabilities - S["organ_data"] >> pref.organ_data - S["rlimb_data"] >> pref.rlimb_data - -/datum/category_item/player_setup_item/general/body/save_character(var/savefile/S) - S["species"] << pref.species - S["hair_red"] << pref.r_hair - S["hair_green"] << pref.g_hair - S["hair_blue"] << pref.b_hair - S["facial_red"] << pref.r_facial - S["facial_green"] << pref.g_facial - S["facial_blue"] << pref.b_facial - S["skin_tone"] << pref.s_tone - S["skin_red"] << pref.r_skin - S["skin_green"] << pref.g_skin - S["skin_blue"] << pref.b_skin - S["hair_style_name"] << pref.h_style - S["facial_style_name"] << pref.f_style - S["eyes_red"] << pref.r_eyes - S["eyes_green"] << pref.g_eyes - S["eyes_blue"] << pref.b_eyes - S["b_type"] << pref.b_type - S["disabilities"] << pref.disabilities - S["organ_data"] << pref.organ_data - S["rlimb_data"] << pref.rlimb_data - -/datum/category_item/player_setup_item/general/body/sanitize_character(var/savefile/S) - if(!pref.species || !(pref.species in playable_species)) - pref.species = "Human" - pref.r_hair = sanitize_integer(pref.r_hair, 0, 255, initial(pref.r_hair)) - pref.g_hair = sanitize_integer(pref.g_hair, 0, 255, initial(pref.g_hair)) - pref.b_hair = sanitize_integer(pref.b_hair, 0, 255, initial(pref.b_hair)) - pref.r_facial = sanitize_integer(pref.r_facial, 0, 255, initial(pref.r_facial)) - pref.g_facial = sanitize_integer(pref.g_facial, 0, 255, initial(pref.g_facial)) - pref.b_facial = sanitize_integer(pref.b_facial, 0, 255, initial(pref.b_facial)) - pref.s_tone = sanitize_integer(pref.s_tone, -185, 34, initial(pref.s_tone)) - pref.r_skin = sanitize_integer(pref.r_skin, 0, 255, initial(pref.r_skin)) - pref.g_skin = sanitize_integer(pref.g_skin, 0, 255, initial(pref.g_skin)) - pref.b_skin = sanitize_integer(pref.b_skin, 0, 255, initial(pref.b_skin)) - pref.h_style = sanitize_inlist(pref.h_style, hair_styles_list, initial(pref.h_style)) - pref.f_style = sanitize_inlist(pref.f_style, facial_hair_styles_list, initial(pref.f_style)) - pref.r_eyes = sanitize_integer(pref.r_eyes, 0, 255, initial(pref.r_eyes)) - pref.g_eyes = sanitize_integer(pref.g_eyes, 0, 255, initial(pref.g_eyes)) - pref.b_eyes = sanitize_integer(pref.b_eyes, 0, 255, initial(pref.b_eyes)) - pref.b_type = sanitize_text(pref.b_type, initial(pref.b_type)) - - pref.disabilities = sanitize_integer(pref.disabilities, 0, 65535, initial(pref.disabilities)) - if(!pref.organ_data) pref.organ_data = list() - if(!pref.rlimb_data) pref.rlimb_data = list() - -/datum/category_item/player_setup_item/general/body/content(var/mob/user) - pref.update_preview_icon() - if(pref.preview_icon_front && pref.preview_icon_side) - user << browse_rsc(pref.preview_icon_front, "previewicon.png") - user << browse_rsc(pref.preview_icon_side, "previewicon2.png") - - var/mob_species = all_species[pref.species] - . += "
Body " - . += "(®)" - . += "
" - . += "Species: [pref.species]
" - . += "Blood Type: [pref.b_type]
" - if(has_flag(mob_species, HAS_SKIN_TONE)) - . += "Skin Tone: [-pref.s_tone + 35]/220
" - . += "Needs Glasses: [pref.disabilities & NEARSIGHTED ? "Yes" : "No"]
" - . += "Limbs: Adjust
" - . += "Internal Organs: Adjust
" - - //display limbs below - var/ind = 0 - for(var/name in pref.organ_data) - var/status = pref.organ_data[name] - var/organ_name = null - switch(name) - if("l_arm") - organ_name = "left arm" - if("r_arm") - organ_name = "right arm" - if("l_leg") - organ_name = "left leg" - if("r_leg") - organ_name = "right leg" - if("l_foot") - organ_name = "left foot" - if("r_foot") - organ_name = "right foot" - if("l_hand") - organ_name = "left hand" - if("r_hand") - organ_name = "right hand" - if("heart") - organ_name = "heart" - if("eyes") - organ_name = "eyes" - - if(status == "cyborg") - ++ind - if(ind > 1) - . += ", " - var/datum/robolimb/R - if(pref.rlimb_data[name] && all_robolimbs[pref.rlimb_data[name]]) - R = all_robolimbs[pref.rlimb_data[name]] - else - R = basic_robolimb - . += "\t[R.company] [organ_name] prothesis" - else if(status == "amputated") - ++ind - if(ind > 1) - . += ", " - . += "\tAmputated [organ_name]" - else if(status == "mechanical") - ++ind - if(ind > 1) - . += ", " - . += "\tMechanical [organ_name]" - else if(status == "assisted") - ++ind - if(ind > 1) - . += ", " - switch(organ_name) - if("heart") - . += "\tPacemaker-assisted [organ_name]" - if("voicebox") //on adding voiceboxes for speaking skrell/similar replacements - . += "\tSurgically altered [organ_name]" - if("eyes") - . += "\tRetinal overlayed [organ_name]" - else - . += "\tMechanically assisted [organ_name]" - if(!ind) - . += "\[...\]

" - else - . += "

" - - . += "
Preview
" - . += "
" - - . += "Hair
" - if(has_flag(mob_species, HAS_HAIR_COLOR)) - . += "Change Color
__
" - . += " Style: [pref.h_style]
" - - . += "
Facial
" - if(has_flag(mob_species, HAS_HAIR_COLOR)) - . += "Change Color
__
" - . += " Style: [pref.f_style]
" - - if(has_flag(mob_species, HAS_EYE_COLOR)) - . += "
Eyes
" - . += "Change Color
__

" - - if(has_flag(mob_species, HAS_SKIN_COLOR)) - . += "
Body Color
" - . += "Change Color
__

" - -/datum/category_item/player_setup_item/general/body/proc/has_flag(var/datum/species/mob_species, var/flag) - return mob_species && (mob_species.appearance_flags & flag) - -/datum/category_item/player_setup_item/general/body/OnTopic(var/href,var/list/href_list, var/mob/user) - var/mob_species = all_species[pref.species] - - if(href_list["random"]) - pref.randomize_appearance_for() - return TOPIC_REFRESH - - else if(href_list["blood_type"]) - var/new_b_type = input(user, "Choose your character's blood-type:", "Character Preference") as null|anything in valid_bloodtypes - if(new_b_type && CanUseTopic(user)) - pref.b_type = new_b_type - return TOPIC_REFRESH - - else if(href_list["show_species"]) - // Actual whitelist checks are handled elsewhere, this is just for accessing the preview window. - var/choice = input("Which species would you like to look at?") as null|anything in playable_species - if(!choice) return - pref.species_preview = choice - SetSpecies(preference_mob()) - pref.alternate_languages.Cut() // Reset their alternate languages. Todo: attempt to just fix it instead? - return TOPIC_HANDLED - - else if(href_list["set_species"]) - user << browse(null, "window=species") - if(!pref.species_preview || !(pref.species_preview in all_species)) - return TOPIC_NOACTION - - var/prev_species = pref.species - pref.species = href_list["set_species"] - if(prev_species != pref.species) - //grab one of the valid hair styles for the newly chosen species - var/list/valid_hairstyles = list() - for(var/hairstyle in hair_styles_list) - var/datum/sprite_accessory/S = hair_styles_list[hairstyle] - if(pref.gender == MALE && S.gender == FEMALE) - continue - if(pref.gender == FEMALE && S.gender == MALE) - continue - if(!(pref.species in S.species_allowed)) - continue - valid_hairstyles[hairstyle] = hair_styles_list[hairstyle] - - if(valid_hairstyles.len) - pref.h_style = pick(valid_hairstyles) - else - //this shouldn't happen - pref.h_style = hair_styles_list["Bald"] - - //grab one of the valid facial hair styles for the newly chosen species - var/list/valid_facialhairstyles = list() - for(var/facialhairstyle in facial_hair_styles_list) - var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] - if(pref.gender == MALE && S.gender == FEMALE) - continue - if(pref.gender == FEMALE && S.gender == MALE) - continue - if(!(pref.species in S.species_allowed)) - continue - - valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle] - - if(valid_facialhairstyles.len) - pref.f_style = pick(valid_facialhairstyles) - else - //this shouldn't happen - pref.f_style = facial_hair_styles_list["Shaved"] - - //reset hair colour and skin colour - pref.r_hair = 0//hex2num(copytext(new_hair, 2, 4)) - pref.g_hair = 0//hex2num(copytext(new_hair, 4, 6)) - pref.b_hair = 0//hex2num(copytext(new_hair, 6, 8)) - pref.s_tone = 0 - - return TOPIC_REFRESH - - else if(href_list["hair_color"]) - if(!has_flag(mob_species, HAS_HAIR_COLOR)) - return TOPIC_NOACTION - var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference", rgb(pref.r_hair, pref.g_hair, pref.b_hair)) as color|null - if(new_hair && has_flag(mob_species, HAS_HAIR_COLOR) && CanUseTopic(user)) - pref.r_hair = hex2num(copytext(new_hair, 2, 4)) - pref.g_hair = hex2num(copytext(new_hair, 4, 6)) - pref.b_hair = hex2num(copytext(new_hair, 6, 8)) - return TOPIC_REFRESH - - else if(href_list["hair_style"]) - var/list/valid_hairstyles = list() - for(var/hairstyle in hair_styles_list) - var/datum/sprite_accessory/S = hair_styles_list[hairstyle] - if(!(pref.species in S.species_allowed)) - continue - - valid_hairstyles[hairstyle] = hair_styles_list[hairstyle] - - var/new_h_style = input(user, "Choose your character's hair style:", "Character Preference", pref.h_style) as null|anything in valid_hairstyles - if(new_h_style && CanUseTopic(user)) - pref.h_style = new_h_style - return TOPIC_REFRESH - - else if(href_list["facial_color"]) - if(!has_flag(mob_species, HAS_HAIR_COLOR)) - return TOPIC_NOACTION - var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference", rgb(pref.r_facial, pref.g_facial, pref.b_facial)) as color|null - if(new_facial && has_flag(mob_species, HAS_HAIR_COLOR) && CanUseTopic(user)) - pref.r_facial = hex2num(copytext(new_facial, 2, 4)) - pref.g_facial = hex2num(copytext(new_facial, 4, 6)) - pref.b_facial = hex2num(copytext(new_facial, 6, 8)) - return TOPIC_REFRESH - - else if(href_list["eye_color"]) - if(!has_flag(mob_species, HAS_EYE_COLOR)) - return TOPIC_NOACTION - var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference", rgb(pref.r_eyes, pref.g_eyes, pref.b_eyes)) as color|null - if(new_eyes && has_flag(mob_species, HAS_EYE_COLOR) && CanUseTopic(user)) - pref.r_eyes = hex2num(copytext(new_eyes, 2, 4)) - pref.g_eyes = hex2num(copytext(new_eyes, 4, 6)) - pref.b_eyes = hex2num(copytext(new_eyes, 6, 8)) - return TOPIC_REFRESH - - else if(href_list["skin_tone"]) - if(!has_flag(mob_species, HAS_SKIN_TONE)) - return TOPIC_NOACTION - var/new_s_tone = input(user, "Choose your character's skin-tone:\n(Light 1 - 220 Dark)", "Character Preference", pref.s_tone) as num|null - if(new_s_tone && has_flag(mob_species, HAS_SKIN_TONE) && CanUseTopic(user)) - pref.s_tone = 35 - max(min( round(new_s_tone), 220),1) - return TOPIC_REFRESH - - else if(href_list["skin_color"]) - if(!has_flag(mob_species, HAS_SKIN_COLOR)) - return TOPIC_NOACTION - var/new_skin = input(user, "Choose your character's skin colour: ", "Character Preference", rgb(pref.r_skin, pref.g_skin, pref.b_skin)) as color|null - if(new_skin && has_flag(mob_species, HAS_SKIN_COLOR) && CanUseTopic(user)) - pref.r_skin = hex2num(copytext(new_skin, 2, 4)) - pref.g_skin = hex2num(copytext(new_skin, 4, 6)) - pref.b_skin = hex2num(copytext(new_skin, 6, 8)) - return TOPIC_REFRESH - - else if(href_list["facial_style"]) - var/list/valid_facialhairstyles = list() - for(var/facialhairstyle in facial_hair_styles_list) - var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] - if(pref.gender == MALE && S.gender == FEMALE) - continue - if(pref.gender == FEMALE && S.gender == MALE) - continue - if(!(pref.species in S.species_allowed)) - continue - - valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle] - - var/new_f_style = input(user, "Choose your character's facial-hair style:", "Character Preference", pref.f_style) as null|anything in valid_facialhairstyles - if(new_f_style && has_flag(mob_species, HAS_HAIR_COLOR) && CanUseTopic(user)) - pref.f_style = new_f_style - return TOPIC_REFRESH - - else if(href_list["limbs"]) - var/limb_name = input(user, "Which limb do you want to change?") as null|anything in list("Left Leg","Right Leg","Left Arm","Right Arm","Left Foot","Right Foot","Left Hand","Right Hand") - if(!limb_name && !CanUseTopic(user)) return TOPIC_NOACTION - - var/limb = null - var/second_limb = null // if you try to change the arm, the hand should also change - var/third_limb = null // if you try to unchange the hand, the arm should also change - switch(limb_name) - if("Left Leg") - limb = "l_leg" - second_limb = "l_foot" - if("Right Leg") - limb = "r_leg" - second_limb = "r_foot" - if("Left Arm") - limb = "l_arm" - second_limb = "l_hand" - if("Right Arm") - limb = "r_arm" - second_limb = "r_hand" - if("Left Foot") - limb = "l_foot" - third_limb = "l_leg" - if("Right Foot") - limb = "r_foot" - third_limb = "r_leg" - if("Left Hand") - limb = "l_hand" - third_limb = "l_arm" - if("Right Hand") - limb = "r_hand" - third_limb = "r_arm" - - var/new_state = input(user, "What state do you wish the limb to be in?") as null|anything in list("Normal","Amputated","Prothesis") - if(!new_state && !CanUseTopic(user)) return TOPIC_NOACTION - - switch(new_state) - if("Normal") - pref.organ_data[limb] = null - pref.rlimb_data[limb] = null - if(third_limb) - pref.organ_data[third_limb] = null - pref.rlimb_data[third_limb] = null - if("Amputated") - pref.organ_data[limb] = "amputated" - pref.rlimb_data[limb] = null - if(second_limb) - pref.organ_data[second_limb] = "amputated" - pref.rlimb_data[second_limb] = null - - if("Prothesis") - var/tmp_species = pref.species ? pref.species : "Human" - var/list/usable_manufacturers = list() - for(var/company in chargen_robolimbs) - var/datum/robolimb/M = chargen_robolimbs[company] - if(tmp_species in M.species_cannot_use) - continue - usable_manufacturers[company] = M - if(!usable_manufacturers.len) - return - var/choice = input(user, "Which manufacturer do you wish to use for this limb?") as null|anything in usable_manufacturers - if(!choice) - return - pref.rlimb_data[limb] = choice - pref.organ_data[limb] = "cyborg" - if(second_limb) - pref.rlimb_data[second_limb] = choice - pref.organ_data[second_limb] = "cyborg" - if(third_limb && pref.organ_data[third_limb] == "amputated") - pref.organ_data[third_limb] = null - return TOPIC_REFRESH - - 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") - if(!organ_name) return - - var/organ = null - switch(organ_name) - if("Heart") - organ = "heart" - if("Eyes") - organ = "eyes" - - var/new_state = input(user, "What state do you wish the organ to be in?") as null|anything in list("Normal","Assisted","Mechanical") - if(!new_state) return - - switch(new_state) - if("Normal") - pref.organ_data[organ] = null - if("Assisted") - pref.organ_data[organ] = "assisted" - if("Mechanical") - pref.organ_data[organ] = "mechanical" - return TOPIC_REFRESH - - else if(href_list["disabilities"]) - var/disability_flag = text2num(href_list["disabilities"]) - pref.disabilities ^= disability_flag - return TOPIC_REFRESH - - return ..() - -/datum/category_item/player_setup_item/general/body/proc/SetSpecies(mob/user) - if(!pref.species_preview || !(pref.species_preview in all_species)) - pref.species_preview = "Human" - var/datum/species/current_species = all_species[pref.species_preview] - var/dat = "" - dat += "

[current_species.name] \[change\]


" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "
[current_species.blurb]" - if("preview" in icon_states(current_species.icobase)) - usr << browse_rsc(icon(current_species.icobase,"preview"), "species_preview_[current_species.name].png") - dat += "

" - dat += "Language: [current_species.language]
" - dat += "" - if(current_species.spawn_flags & CAN_JOIN) - dat += "
Often present on human stations." - if(current_species.spawn_flags & IS_WHITELISTED) - dat += "
Whitelist restricted." - if(current_species.flags & NO_BLOOD) - dat += "
Does not have blood." - if(current_species.flags & NO_BREATHE) - dat += "
Does not breathe." - if(current_species.flags & NO_SCAN) - dat += "
Does not have DNA." - if(current_species.flags & NO_PAIN) - dat += "
Does not feel pain." - if(current_species.flags & NO_SLIP) - dat += "
Has excellent traction." - if(current_species.flags & NO_POISON) - dat += "
Immune to most poisons." - if(current_species.appearance_flags & HAS_SKIN_TONE) - dat += "
Has a variety of skin tones." - if(current_species.appearance_flags & HAS_SKIN_COLOR) - dat += "
Has a variety of skin colours." - if(current_species.appearance_flags & HAS_EYE_COLOR) - dat += "
Has a variety of eye colours." - if(current_species.flags & IS_PLANT) - dat += "
Has a plantlike physiology." - dat += "

" - - var/restricted = 0 - if(config.usealienwhitelist) //If we're using the whitelist, make sure to check it! - if(!(current_species.spawn_flags & CAN_JOIN)) - restricted = 2 - else if((current_species.spawn_flags & IS_WHITELISTED) && !is_alien_whitelisted(preference_mob(),current_species)) - restricted = 1 - - if(restricted) - if(restricted == 1) - dat += "You cannot play as this species.
If you wish to be whitelisted, you can make an application post on the forums.

" - else if(restricted == 2) - dat += "You cannot play as this species.
This species is not available for play as a station race..

" - if(!restricted || check_rights(R_ADMIN, 0)) - dat += "\[select\]" - dat += "
" - - user << browse(dat, "window=species;size=700x400") diff --git a/code/modules/client/preference_setup/general/04_equipment.dm b/code/modules/client/preference_setup/general/04_equipment.dm deleted file mode 100644 index 8d9db3f28e2..00000000000 --- a/code/modules/client/preference_setup/general/04_equipment.dm +++ /dev/null @@ -1,146 +0,0 @@ -/datum/category_item/player_setup_item/general/equipment - name = "Equipment" - sort_order = 4 - -/datum/category_item/player_setup_item/general/equipment/load_character(var/savefile/S) - S["underwear"] >> pref.underwear - S["undershirt"] >> pref.undershirt - S["socks"] >> pref.socks - S["backbag"] >> pref.backbag - S["gear"] >> pref.gear - -/datum/category_item/player_setup_item/general/equipment/save_character(var/savefile/S) - S["underwear"] << pref.underwear - S["undershirt"] << pref.undershirt - S["socks"] << pref.socks - S["backbag"] << pref.backbag - S["gear"] << pref.gear - -/datum/category_item/player_setup_item/general/equipment/sanitize_character() - pref.backbag = sanitize_integer(pref.backbag, 1, backbaglist.len, initial(pref.backbag)) - - if(!islist(pref.gear)) pref.gear = list() - - var/undies = get_undies() - if(!get_key_by_value(undies, pref.underwear)) - pref.underwear = undies[1] - if(!get_key_by_value(undershirt_t, pref.undershirt)) - pref.undershirt = undershirt_t[1] - if(!get_key_by_value(socks_t, pref.socks)) - pref.socks = socks_t[1] - - var/total_cost = 0 - for(var/gear_name in pref.gear) - if(!gear_datums[gear_name]) - pref.gear -= gear_name - else if(!(gear_name in valid_gear_choices())) - pref.gear -= gear_name - else - var/datum/gear/G = gear_datums[gear_name] - if(total_cost + G.cost > MAX_GEAR_COST) - pref.gear -= gear_name - else - total_cost += G.cost - -/datum/category_item/player_setup_item/general/equipment/content() - . += "Equipment Loadout:
" - . += "Underwear: [get_key_by_value(get_undies(),pref.underwear)]
" - . += "Undershirt: [get_key_by_value(undershirt_t,pref.undershirt)]
" - . += "Socks: [get_key_by_value(socks_t,pref.socks)]
" - . += "Backpack Type: [backbaglist[pref.backbag]]
" - - . += "
Custom Loadout:
" - var/total_cost = 0 - - if(pref.gear && pref.gear.len) - for(var/i = 1; i <= pref.gear.len; i++) - var/datum/gear/G = gear_datums[pref.gear[i]] - if(G) - total_cost += G.cost - . += "[pref.gear[i]] ([G.cost] points) Remove
" - - . += "Used: [total_cost] points." - else - . += "None." - - if(total_cost < MAX_GEAR_COST) - . += " Add" - if(pref.gear && pref.gear.len) - . += " Clear" - . += "
" - -/datum/category_item/player_setup_item/general/equipment/proc/get_undies() - return pref.gender == MALE ? underwear_m : underwear_f - -/datum/category_item/player_setup_item/general/equipment/proc/valid_gear_choices(var/max_cost) - var/list/valid_gear_choices = list() - for(var/gear_name in gear_datums) - var/datum/gear/G = gear_datums[gear_name] - if(G.whitelisted && !is_alien_whitelisted(preference_mob(), G.whitelisted)) - continue - if(max_cost && G.cost > max_cost) - continue - valid_gear_choices += gear_name - return valid_gear_choices - -/datum/category_item/player_setup_item/general/equipment/OnTopic(var/href,var/list/href_list, var/mob/user) - if(href_list["change_underwear"]) - var/underwear_options = get_undies() - var/new_underwear = input(user, "Choose your character's underwear:", "Character Preference", get_key_by_value(get_undies(),pref.underwear)) as null|anything in underwear_options - if(!isnull(new_underwear) && CanUseTopic(user)) - pref.underwear = underwear_options[new_underwear] - return TOPIC_REFRESH - - else if(href_list["change_undershirt"]) - var/new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference", get_key_by_value(undershirt_t,pref.undershirt)) as null|anything in undershirt_t - if(!isnull(new_undershirt) && CanUseTopic(user)) - pref.undershirt = undershirt_t[new_undershirt] - return TOPIC_REFRESH - - else if(href_list["change_socks"]) - var/new_socks = input(user, "Choose your character's socks:", "Character Preference", get_key_by_value(socks_t,pref.socks)) as null|anything in socks_t - if(!isnull(new_socks) && CanUseTopic(user)) - pref.socks = socks_t[new_socks] - return TOPIC_REFRESH -/* -+ if("socks") -+ var/r = pick(socks_t) -+ socks = socks_t[r] -+ ShowChoices(user) -*/ - - else if(href_list["change_backpack"]) - var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference", backbaglist[pref.backbag]) as null|anything in backbaglist - if(!isnull(new_backbag) && CanUseTopic(user)) - pref.backbag = backbaglist.Find(new_backbag) - return TOPIC_REFRESH - - else if(href_list["add_loadout"]) - var/total_cost = 0 - for(var/gear_name in pref.gear) - if(gear_datums[gear_name]) - var/datum/gear/G = gear_datums[gear_name] - total_cost += G.cost - - var/choice = input(user, "Select gear to add:", "Character Preference") as null|anything in valid_gear_choices(MAX_GEAR_COST - total_cost) - if(choice && gear_datums[choice] && CanUseTopic(user)) - var/datum/gear/C = gear_datums[choice] - total_cost += C.cost - if(C && total_cost <= MAX_GEAR_COST) - pref.gear += choice - user << "Added \the '[choice]' for [C.cost] points ([MAX_GEAR_COST - total_cost] points remaining)." - else - user << "Adding \the '[choice]' will exceed the maximum loadout cost of [MAX_GEAR_COST] points." - return TOPIC_REFRESH - - else if(href_list["remove_loadout"]) - var/i_remove = text2num(href_list["remove_loadout"]) - if(i_remove < 1 || i_remove > pref.gear.len) return TOPIC_NOACTION - pref.gear.Cut(i_remove, i_remove + 1) - return TOPIC_REFRESH - - else if(href_list["clear_loadout"]) - pref.gear.Cut() - return TOPIC_REFRESH - - return ..() diff --git a/code/modules/client/preference_setup/general/05_background.dm b/code/modules/client/preference_setup/general/05_background.dm deleted file mode 100644 index 5708d3c757e..00000000000 --- a/code/modules/client/preference_setup/general/05_background.dm +++ /dev/null @@ -1,125 +0,0 @@ -/datum/category_item/player_setup_item/general/background - name = "Background" - sort_order = 5 - -/datum/category_item/player_setup_item/general/background/load_character(var/savefile/S) - S["med_record"] >> pref.med_record - S["sec_record"] >> pref.sec_record - S["gen_record"] >> pref.gen_record - S["home_system"] >> pref.home_system - S["citizenship"] >> pref.citizenship - S["faction"] >> pref.faction - S["religion"] >> pref.religion - S["nanotrasen_relation"] >> pref.nanotrasen_relation - -/datum/category_item/player_setup_item/general/background/save_character(var/savefile/S) - S["med_record"] << pref.med_record - S["sec_record"] << pref.sec_record - S["gen_record"] << pref.gen_record - S["home_system"] << pref.home_system - S["citizenship"] << pref.citizenship - S["faction"] << pref.faction - S["religion"] << pref.religion - S["nanotrasen_relation"] << pref.nanotrasen_relation - -/datum/category_item/player_setup_item/general/background/sanitize_character() - if(!pref.home_system) pref.home_system = "Unset" - if(!pref.citizenship) pref.citizenship = "None" - if(!pref.faction) pref.faction = "None" - if(!pref.religion) pref.religion = "None" - - pref.nanotrasen_relation = sanitize_inlist(pref.nanotrasen_relation, COMPANY_ALIGNMENTS, initial(pref.nanotrasen_relation)) - -/datum/category_item/player_setup_item/general/background/content(var/mob/user) - . += "Background Information
" - . += "[company_name] Relation: [pref.nanotrasen_relation]
" - . += "Home System: [pref.home_system]
" - . += "Citizenship: [pref.citizenship]
" - . += "Faction: [pref.faction]
" - . += "Religion: [pref.religion]
" - - . += "
Records:
" - if(jobban_isbanned(user, "Records")) - . += "You are banned from using character records.
" - else - . += "Medical Records:
" - . += "[TextPreview(pref.med_record,40)]

" - . += "Employment Records:
" - . += "[TextPreview(pref.gen_record,40)]

" - . += "Security Records:
" - . += "[TextPreview(pref.sec_record,40)]
" - -/datum/category_item/player_setup_item/general/background/OnTopic(var/href,var/list/href_list, var/mob/user) - if(href_list["nt_relation"]) - var/new_relation = input(user, "Choose your relation to NT. Note that this represents what others can find out about your character by researching your background, not what your character actually thinks.", "Character Preference", pref.nanotrasen_relation) as null|anything in COMPANY_ALIGNMENTS - if(new_relation && CanUseTopic(user)) - pref.nanotrasen_relation = new_relation - return TOPIC_REFRESH - - else if(href_list["home_system"]) - var/choice = input(user, "Please choose a home system.", "Character Preference", pref.home_system) as null|anything in home_system_choices + list("Unset","Other") - if(!choice || !CanUseTopic(user)) - return TOPIC_NOACTION - if(choice == "Other") - var/raw_choice = sanitize(input(user, "Please enter a home system.", "Character Preference") as text|null, MAX_NAME_LEN) - if(raw_choice && CanUseTopic(user)) - pref.home_system = raw_choice - else - pref.home_system = choice - return TOPIC_REFRESH - - else if(href_list["citizenship"]) - var/choice = input(user, "Please choose your current citizenship.", "Character Preference", pref.citizenship) as null|anything in citizenship_choices + list("None","Other") - if(!choice || !CanUseTopic(user)) - return TOPIC_NOACTION - if(choice == "Other") - var/raw_choice = sanitize(input(user, "Please enter your current citizenship.", "Character Preference") as text|null, MAX_NAME_LEN) - if(raw_choice && CanUseTopic(user)) - pref.citizenship = raw_choice - else - pref.citizenship = choice - return TOPIC_REFRESH - - else if(href_list["faction"]) - var/choice = input(user, "Please choose a faction to work for.", "Character Preference", pref.faction) as null|anything in faction_choices + list("None","Other") - if(!choice || !CanUseTopic(user)) - return TOPIC_NOACTION - if(choice == "Other") - var/raw_choice = sanitize(input(user, "Please enter a faction.", "Character Preference") as text|null, MAX_NAME_LEN) - if(raw_choice) - pref.faction = raw_choice - else - pref.faction = choice - return TOPIC_REFRESH - - else if(href_list["religion"]) - var/choice = input(user, "Please choose a religion.", "Character Preference", pref.religion) as null|anything in religion_choices + list("None","Other") - if(!choice || !CanUseTopic(user)) - return TOPIC_NOACTION - if(choice == "Other") - var/raw_choice = sanitize(input(user, "Please enter a religon.", "Character Preference") as text|null, MAX_NAME_LEN) - if(raw_choice) - pref.religion = sanitize(raw_choice) - else - pref.religion = choice - return TOPIC_REFRESH - - else if(href_list["set_medical_records"]) - var/new_medical = sanitize(input(user,"Enter medical information here.","Character Preference", html_decode(pref.med_record)) as message|null, MAX_PAPER_MESSAGE_LEN, extra = 0) - if(!isnull(new_medical) && !jobban_isbanned(user, "Records") && CanUseTopic(user)) - pref.med_record = new_medical - return TOPIC_REFRESH - - else if(href_list["set_general_records"]) - var/new_general = sanitize(input(user,"Enter employment information here.","Character Preference", html_decode(pref.gen_record)) as message|null, MAX_PAPER_MESSAGE_LEN, extra = 0) - if(!isnull(new_general) && !jobban_isbanned(user, "Records") && CanUseTopic(user)) - pref.gen_record = new_general - return TOPIC_REFRESH - - else if(href_list["set_security_records"]) - var/sec_medical = sanitize(input(user,"Enter security information here.","Character Preference", html_decode(pref.sec_record)) as message|null, MAX_PAPER_MESSAGE_LEN, extra = 0) - if(!isnull(sec_medical) && !jobban_isbanned(user, "Records") && CanUseTopic(user)) - pref.sec_record = sec_medical - return TOPIC_REFRESH - - return ..() diff --git a/code/modules/client/preference_setup/general/06_flavor.dm b/code/modules/client/preference_setup/general/06_flavor.dm deleted file mode 100644 index 3c2d93073bf..00000000000 --- a/code/modules/client/preference_setup/general/06_flavor.dm +++ /dev/null @@ -1,127 +0,0 @@ -/datum/category_item/player_setup_item/general/flavor - name = "Flavor" - sort_order = 6 - -/datum/category_item/player_setup_item/general/flavor/load_character(var/savefile/S) - S["flavor_texts_general"] >> pref.flavor_texts["general"] - S["flavor_texts_head"] >> pref.flavor_texts["head"] - S["flavor_texts_face"] >> pref.flavor_texts["face"] - S["flavor_texts_eyes"] >> pref.flavor_texts["eyes"] - S["flavor_texts_torso"] >> pref.flavor_texts["torso"] - S["flavor_texts_arms"] >> pref.flavor_texts["arms"] - S["flavor_texts_hands"] >> pref.flavor_texts["hands"] - S["flavor_texts_legs"] >> pref.flavor_texts["legs"] - S["flavor_texts_feet"] >> pref.flavor_texts["feet"] - - //Flavour text for robots. - S["flavour_texts_robot_Default"] >> pref.flavour_texts_robot["Default"] - for(var/module in robot_module_types) - S["flavour_texts_robot_[module]"] >> pref.flavour_texts_robot[module] - -/datum/category_item/player_setup_item/general/flavor/save_character(var/savefile/S) - S["flavor_texts_general"] << pref.flavor_texts["general"] - S["flavor_texts_head"] << pref.flavor_texts["head"] - S["flavor_texts_face"] << pref.flavor_texts["face"] - S["flavor_texts_eyes"] << pref.flavor_texts["eyes"] - S["flavor_texts_torso"] << pref.flavor_texts["torso"] - S["flavor_texts_arms"] << pref.flavor_texts["arms"] - S["flavor_texts_hands"] << pref.flavor_texts["hands"] - S["flavor_texts_legs"] << pref.flavor_texts["legs"] - S["flavor_texts_feet"] << pref.flavor_texts["feet"] - - S["flavour_texts_robot_Default"] << pref.flavour_texts_robot["Default"] - for(var/module in robot_module_types) - S["flavour_texts_robot_[module]"] << pref.flavour_texts_robot[module] - -/datum/category_item/player_setup_item/general/flavor/sanitize_character() - return - -/datum/category_item/player_setup_item/general/flavor/content(var/mob/user) - . += "Flavor:
" - . += "Set Flavor Text
" - . += "Set Robot Flavor Text
" - -/datum/category_item/player_setup_item/general/flavor/OnTopic(var/href,var/list/href_list, var/mob/user) - if(href_list["flavor_text"]) - switch(href_list["flavor_text"]) - if("open") - else if("general") - var/msg = sanitize(input(usr,"Give a general description of your character. This will be shown regardless of clothing, and may include OOC notes and preferences.","Flavor Text",html_decode(pref.flavor_texts[href_list["task"]])) as message, extra = 0) - if(CanUseTopic(user)) - pref.flavor_texts[href_list["flavor_text"]] = msg - else - var/msg = sanitize(input(usr,"Set the flavor text for your [href_list["flavor_text"]].","Flavor Text",html_decode(pref.flavor_texts[href_list["flavor_text"]])) as message, extra = 0) - if(CanUseTopic(user)) - pref.flavor_texts[href_list["flavor_text"]] = msg - SetFlavorText(user) - return TOPIC_HANDLED - - else if(href_list["flavour_text_robot"]) - switch(href_list["flavour_text_robot"]) - if("open") - else if("Default") - var/msg = sanitize(input(usr,"Set the default flavour text for your robot. It will be used for any module without individual setting.","Flavour Text",html_decode(pref.flavour_texts_robot["Default"])) as message, extra = 0) - if(CanUseTopic(user)) - pref.flavour_texts_robot[href_list["flavour_text_robot"]] = msg - else - var/msg = sanitize(input(usr,"Set the flavour text for your robot with [href_list["flavour_text_robot"]] module. If you leave this empty, default flavour text will be used for this module.","Flavour Text",html_decode(pref.flavour_texts_robot[href_list["flavour_text_robot"]])) as message, extra = 0) - if(CanUseTopic(user)) - pref.flavour_texts_robot[href_list["flavour_text_robot"]] = msg - SetFlavourTextRobot(user) - return TOPIC_HANDLED - - return ..() - -/datum/category_item/player_setup_item/general/flavor/proc/SetFlavorText(mob/user) - var/HTML = "" - HTML += "
" - HTML += "Set Flavour Text
" - HTML += "
" - HTML += "General: " - HTML += TextPreview(pref.flavor_texts["general"]) - HTML += "
" - HTML += "Head: " - HTML += TextPreview(pref.flavor_texts["head"]) - HTML += "
" - HTML += "Face: " - HTML += TextPreview(pref.flavor_texts["face"]) - HTML += "
" - HTML += "Eyes: " - HTML += TextPreview(pref.flavor_texts["eyes"]) - HTML += "
" - HTML += "Body: " - HTML += TextPreview(pref.flavor_texts["torso"]) - HTML += "
" - HTML += "Arms: " - HTML += TextPreview(pref.flavor_texts["arms"]) - HTML += "
" - HTML += "Hands: " - HTML += TextPreview(pref.flavor_texts["hands"]) - HTML += "
" - HTML += "Legs: " - HTML += TextPreview(pref.flavor_texts["legs"]) - HTML += "
" - HTML += "Feet: " - HTML += TextPreview(pref.flavor_texts["feet"]) - HTML += "
" - HTML += "
" - HTML += "" - user << browse(HTML, "window=flavor_text;size=430x300") - return - -/datum/category_item/player_setup_item/general/flavor/proc/SetFlavourTextRobot(mob/user) - var/HTML = "" - HTML += "
" - HTML += "Set Robot Flavour Text
" - HTML += "
" - HTML += "Default: " - HTML += TextPreview(pref.flavour_texts_robot["Default"]) - HTML += "
" - for(var/module in robot_module_types) - HTML += "[module]: " - HTML += TextPreview(pref.flavour_texts_robot[module]) - HTML += "
" - HTML += "
" - HTML += "" - user << browse(HTML, "window=flavour_text_robot;size=430x300") - return diff --git a/code/modules/client/preference_setup/global/01_ui.dm b/code/modules/client/preference_setup/global/01_ui.dm deleted file mode 100644 index 09289c1068f..00000000000 --- a/code/modules/client/preference_setup/global/01_ui.dm +++ /dev/null @@ -1,73 +0,0 @@ -/datum/category_item/player_setup_item/player_global/ui - name = "UI" - sort_order = 1 - -/datum/category_item/player_setup_item/player_global/ui/load_preferences(var/savefile/S) - S["UI_style"] >> pref.UI_style - S["UI_style_color"] >> pref.UI_style_color - S["UI_style_alpha"] >> pref.UI_style_alpha - S["ooccolor"] >> pref.ooccolor - -/datum/category_item/player_setup_item/player_global/ui/save_preferences(var/savefile/S) - S["UI_style"] << pref.UI_style - S["UI_style_color"] << pref.UI_style_color - S["UI_style_alpha"] << pref.UI_style_alpha - S["ooccolor"] << pref.ooccolor - -/datum/category_item/player_setup_item/player_global/ui/sanitize_preferences() - pref.UI_style = sanitize_inlist(pref.UI_style, all_ui_styles, initial(pref.UI_style)) - pref.UI_style_color = sanitize_hexcolor(pref.UI_style_color, initial(pref.UI_style_color)) - pref.UI_style_alpha = sanitize_integer(pref.UI_style_alpha, 0, 255, initial(pref.UI_style_alpha)) - pref.ooccolor = sanitize_hexcolor(pref.ooccolor, initial(pref.ooccolor)) - -/datum/category_item/player_setup_item/player_global/ui/content(var/mob/user) - . = "UI Style: [pref.UI_style]
" - . += "Custom UI (recommended for White UI):
" - . += "-Color: [pref.UI_style_color] 
__
 reset
" - . += "-Alpha(transparency): [pref.UI_style_alpha] reset
" - if(can_select_ooc_color(user)) - . += "OOC Color: " - if(pref.ooccolor == initial(pref.ooccolor)) - . += "Using Default
" - else - . += "[pref.ooccolor]
__
 reset
" - -/datum/category_item/player_setup_item/player_global/ui/OnTopic(var/href,var/list/href_list, var/mob/user) - if(href_list["select_style"]) - var/UI_style_new = input(user, "Choose UI style.", "Character Preference", pref.UI_style) as null|anything in all_ui_styles - if(!UI_style_new || !CanUseTopic(user)) return TOPIC_NOACTION - pref.UI_style = UI_style_new - return TOPIC_REFRESH - - else if(href_list["select_color"]) - var/UI_style_color_new = input(user, "Choose UI color, dark colors are not recommended!", "Global Preference", pref.UI_style_color) as color|null - if(isnull(UI_style_color_new) || !CanUseTopic(user)) return TOPIC_NOACTION - pref.UI_style_color = UI_style_color_new - return TOPIC_REFRESH - - else if(href_list["select_alpha"]) - var/UI_style_alpha_new = input(user, "Select UI alpha (transparency) level, between 50 and 255.", "Global Preference", pref.UI_style_alpha) as num|null - if(isnull(UI_style_alpha_new) || (UI_style_alpha_new < 50 || UI_style_alpha_new > 255) || !CanUseTopic(user)) return TOPIC_NOACTION - pref.UI_style_alpha = UI_style_alpha_new - return TOPIC_REFRESH - - else if(href_list["select_ooc_color"]) - var/new_ooccolor = input(user, "Choose OOC color:", "Global Preference") as color|null - if(new_ooccolor && can_select_ooc_color(user) && CanUseTopic(user)) - pref.ooccolor = new_ooccolor - return TOPIC_REFRESH - - else if(href_list["reset"]) - switch(href_list["reset"]) - if("ui") - pref.UI_style_color = initial(pref.UI_style_color) - if("alpha") - pref.UI_style_alpha = initial(pref.UI_style_alpha) - if("ooc") - pref.ooccolor = initial(pref.ooccolor) - return TOPIC_REFRESH - - return ..() - -/datum/category_item/player_setup_item/player_global/ui/proc/can_select_ooc_color(var/mob/user) - return config.allow_admin_ooccolor && check_rights(R_ADMIN, 0, user) diff --git a/code/modules/client/preference_setup/global/02_settings.dm b/code/modules/client/preference_setup/global/02_settings.dm deleted file mode 100644 index 7b61a86cb44..00000000000 --- a/code/modules/client/preference_setup/global/02_settings.dm +++ /dev/null @@ -1,38 +0,0 @@ -/datum/category_item/player_setup_item/player_global/settings - name = "Settings" - sort_order = 2 - -/datum/category_item/player_setup_item/player_global/settings/load_preferences(var/savefile/S) - S["lastchangelog"] >> pref.lastchangelog - S["default_slot"] >> pref.default_slot - S["toggles"] >> pref.toggles - -/datum/category_item/player_setup_item/player_global/settings/save_preferences(var/savefile/S) - S["lastchangelog"] << pref.lastchangelog - S["default_slot"] << pref.default_slot - S["toggles"] << pref.toggles - -/datum/category_item/player_setup_item/player_global/settings/sanitize_preferences() - pref.lastchangelog = sanitize_text(pref.lastchangelog, initial(pref.lastchangelog)) - pref.default_slot = sanitize_integer(pref.default_slot, 1, config.character_slots, initial(pref.default_slot)) - pref.toggles = sanitize_integer(pref.toggles, 0, 65535, initial(pref.toggles)) - -/datum/category_item/player_setup_item/player_global/settings/content(var/mob/user) - . += "Play admin midis: [(pref.toggles & SOUND_MIDI) ? "Yes" : "No"]
" - . += "Play lobby music: [(pref.toggles & SOUND_LOBBY) ? "Yes" : "No"]
" - . += "Ghost ears: [(pref.toggles & CHAT_GHOSTEARS) ? "All Speech" : "Nearest Creatures"]
" - . += "Ghost sight: [(pref.toggles & CHAT_GHOSTSIGHT) ? "All Emotes" : "Nearest Creatures"]
" - . += "Ghost radio: [(pref.toggles & CHAT_GHOSTRADIO) ? "All Chatter" : "Nearest Speakers"]
" - -/datum/category_item/player_setup_item/player_global/settings/OnTopic(var/href,var/list/href_list, var/mob/user) - if(href_list["toggle"]) - var/toggle_flag = text2num(href_list["toggle"]) - pref.toggles ^= toggle_flag - if(toggle_flag == SOUND_LOBBY && isnewplayer(user)) - if(pref.toggles & SOUND_LOBBY) - user << sound(ticker.login_music, repeat = 0, wait = 0, volume = 85, channel = 1) - else - user << sound(null, repeat = 0, wait = 0, volume = 85, channel = 1) - return TOPIC_REFRESH - - return ..() diff --git a/code/modules/client/preference_setup/global/03_pai.dm b/code/modules/client/preference_setup/global/03_pai.dm deleted file mode 100644 index 7944c7b6e7d..00000000000 --- a/code/modules/client/preference_setup/global/03_pai.dm +++ /dev/null @@ -1,54 +0,0 @@ -/datum/category_item/player_setup_item/player_global/pai - name = "pAI" - sort_order = 3 - - var/datum/paiCandidate/candidate - -/datum/category_item/player_setup_item/player_global/pai/load_preferences(var/savefile/S) - if(!candidate) - candidate = new() - - if(!preference_mob()) - return - - candidate.savefile_load(preference_mob()) - -/datum/category_item/player_setup_item/player_global/pai/save_preferences(var/savefile/S) - if(!candidate) - return - - if(!preference_mob()) - return - - candidate.savefile_save(preference_mob()) - -/datum/category_item/player_setup_item/player_global/pai/content(var/mob/user) - . += "pAI:
" - . += "Name: [candidate.name ? candidate.name : "None Set"]
" - . += "Description: [candidate.description ? TextPreview(candidate.description, 40) : "None Set"]
" - . += "Role: [candidate.role ? TextPreview(candidate.role, 40) : "None Set"]
" - . += "OOC Comments: [candidate.comments ? TextPreview(candidate.comments, 40) : "None Set"]
" - -/datum/category_item/player_setup_item/player_global/pai/OnTopic(var/href,var/list/href_list, var/mob/user) - if(href_list["option"]) - var/t - switch(href_list["option"]) - if("name") - t = sanitizeName(input(user, "Enter a name for your pAI", "Global Preference", candidate.name) as text|null, MAX_NAME_LEN, 1) - if(t && CanUseTopic(user)) - candidate.name = t - if("desc") - t = input(user, "Enter a description for your pAI", "Global Preference", html_decode(candidate.description)) as message|null - if(!isnull(t) && CanUseTopic(user)) - candidate.description = sanitize(t) - if("role") - t = input(user, "Enter a role for your pAI", "Global Preference", html_decode(candidate.role)) as text|null - if(!isnull(t) && CanUseTopic(user)) - candidate.role = sanitize(t) - if("ooc") - t = input(user, "Enter any OOC comments", "Global Preference", html_decode(candidate.comments)) as message - if(!isnull(t) && CanUseTopic(user)) - candidate.comments = sanitize(t) - return TOPIC_REFRESH - - return ..() diff --git a/code/modules/client/preference_setup/occupation/occupation.dm b/code/modules/client/preference_setup/occupation/occupation.dm deleted file mode 100644 index 561ffb3ec40..00000000000 --- a/code/modules/client/preference_setup/occupation/occupation.dm +++ /dev/null @@ -1,291 +0,0 @@ -//used for pref.alternate_option -#define GET_RANDOM_JOB 0 -#define BE_ASSISTANT 1 -#define RETURN_TO_LOBBY 2 - -/datum/category_item/player_setup_item/occupation - name = "Occupation" - sort_order = 1 - -/datum/category_item/player_setup_item/occupation/load_character(var/savefile/S) - S["alternate_option"] >> pref.alternate_option - S["job_civilian_high"] >> pref.job_civilian_high - S["job_civilian_med"] >> pref.job_civilian_med - S["job_civilian_low"] >> pref.job_civilian_low - S["job_medsci_high"] >> pref.job_medsci_high - S["job_medsci_med"] >> pref.job_medsci_med - S["job_medsci_low"] >> pref.job_medsci_low - S["job_engsec_high"] >> pref.job_engsec_high - S["job_engsec_med"] >> pref.job_engsec_med - S["job_engsec_low"] >> pref.job_engsec_low - S["player_alt_titles"] >> pref.player_alt_titles - -/datum/category_item/player_setup_item/occupation/save_character(var/savefile/S) - S["alternate_option"] << pref.alternate_option - S["job_civilian_high"] << pref.job_civilian_high - S["job_civilian_med"] << pref.job_civilian_med - S["job_civilian_low"] << pref.job_civilian_low - S["job_medsci_high"] << pref.job_medsci_high - S["job_medsci_med"] << pref.job_medsci_med - S["job_medsci_low"] << pref.job_medsci_low - S["job_engsec_high"] << pref.job_engsec_high - S["job_engsec_med"] << pref.job_engsec_med - S["job_engsec_low"] << pref.job_engsec_low - S["player_alt_titles"] << pref.player_alt_titles - -/datum/category_item/player_setup_item/occupation/sanitize_character() - pref.alternate_option = sanitize_integer(pref.alternate_option, 0, 2, initial(pref.alternate_option)) - pref.job_civilian_high = sanitize_integer(pref.job_civilian_high, 0, 65535, initial(pref.job_civilian_high)) - pref.job_civilian_med = sanitize_integer(pref.job_civilian_med, 0, 65535, initial(pref.job_civilian_med)) - pref.job_civilian_low = sanitize_integer(pref.job_civilian_low, 0, 65535, initial(pref.job_civilian_low)) - pref.job_medsci_high = sanitize_integer(pref.job_medsci_high, 0, 65535, initial(pref.job_medsci_high)) - pref.job_medsci_med = sanitize_integer(pref.job_medsci_med, 0, 65535, initial(pref.job_medsci_med)) - pref.job_medsci_low = sanitize_integer(pref.job_medsci_low, 0, 65535, initial(pref.job_medsci_low)) - pref.job_engsec_high = sanitize_integer(pref.job_engsec_high, 0, 65535, initial(pref.job_engsec_high)) - pref.job_engsec_med = sanitize_integer(pref.job_engsec_med, 0, 65535, initial(pref.job_engsec_med)) - pref.job_engsec_low = sanitize_integer(pref.job_engsec_low, 0, 65535, initial(pref.job_engsec_low)) - if(!pref.player_alt_titles) pref.player_alt_titles = new() - - if(!job_master) - return - - for(var/datum/job/job in job_master.occupations) - var/alt_title = pref.player_alt_titles[job.title] - if(alt_title && !(alt_title in job.alt_titles)) - pref.player_alt_titles -= job.title - -/datum/category_item/player_setup_item/occupation/content(mob/user, limit = 16, list/splitJobs = list("Chief Medical Officer")) - if(!job_master) - return - - . += "
" - . += "Choose occupation chances
Unavailable occupations are crossed out.
" - . += "
" // Table within a table for alignment, also allows you to easily add more colomns. - . += "" - var/index = -1 - - //The job before the current job. I only use this to get the previous jobs color when I'm filling in blank rows. - var/datum/job/lastJob - if (!job_master) return - for(var/datum/job/job in job_master.occupations) - - index += 1 - if((index >= limit) || (job.title in splitJobs)) - if((index < limit) && (lastJob != null)) - //If the cells were broken up by a job in the splitJob list then it will fill in the rest of the cells with - //the last job's selection color. Creating a rather nice effect. - for(var/i = 0, i < (limit - index), i += 1) - . += "" - . += "
  
" - index = 0 - - . += "" - continue - if(!job.player_old_enough(user.client)) - var/available_in_days = job.available_in_days(user.client) - . += "[rank]" - continue - if((pref.job_civilian_low & ASSISTANT) && (rank != "Assistant")) - . += "[rank]" - continue - if((rank in command_positions) || (rank == "AI"))//Bold head jobs - . += "[rank]" - else - . += "[rank]" - - . += "" - . += "" - continue - - if(pref.GetJobDepartment(job, 1) & job.flag) - . += " \[High]" - else if(pref.GetJobDepartment(job, 2) & job.flag) - . += " \[Medium]" - else if(pref.GetJobDepartment(job, 3) & job.flag) - . += " \[Low]" - else - . += " \[NEVER]" - if(job.alt_titles) - . += "" - . += "" - - . += "
" - var/rank = job.title - lastJob = job - if(jobban_isbanned(user, rank)) - . += "[rank] \[BANNED]
\[IN [(available_in_days)] DAYS]
" - - . += "" - - if(rank == "Assistant")//Assistant is special - if(pref.job_civilian_low & ASSISTANT) - . += " \[Yes]" - else - . += " \[No]" - if(job.alt_titles) //Blatantly cloned from a few lines down. - . += "
 \[[pref.GetPlayerAltTitle(job)]\]
 \[[pref.GetPlayerAltTitle(job)]\]
" - - . += "
" - - switch(pref.alternate_option) - if(GET_RANDOM_JOB) - . += "

Get random job if preferences unavailable

" - if(BE_ASSISTANT) - . += "

Be assistant if preference unavailable

" - if(RETURN_TO_LOBBY) - . += "

Return to lobby if preference unavailable

" - - . += "
\[Reset\]
" - . += "
" - -/datum/category_item/player_setup_item/occupation/OnTopic(href, href_list, user) - if(href_list["reset_jobs"]) - ResetJobs() - return TOPIC_REFRESH - - else if(href_list["job_alternative"]) - if(pref.alternate_option == GET_RANDOM_JOB || pref.alternate_option == BE_ASSISTANT) - pref.alternate_option += 1 - else if(pref.alternate_option == RETURN_TO_LOBBY) - pref.alternate_option = 0 - return TOPIC_REFRESH - - else if(href_list["select_alt_title"]) - var/datum/job/job = locate(href_list["select_alt_title"]) - if (job) - var/choices = list(job.title) + job.alt_titles - var/choice = input("Choose an title for [job.title].", "Choose Title", pref.GetPlayerAltTitle(job)) as anything in choices|null - if(choice && CanUseTopic(user)) - SetPlayerAltTitle(job, choice) - return TOPIC_REFRESH - - else if(href_list["set_job"]) - if(SetJob(user, href_list["set_job"])) return TOPIC_REFRESH - - return ..() - -/datum/category_item/player_setup_item/occupation/proc/SetPlayerAltTitle(datum/job/job, new_title) - // remove existing entry - pref.player_alt_titles -= job.title - // add one if it's not default - if(job.title != new_title) - pref.player_alt_titles[job.title] = new_title - -/datum/category_item/player_setup_item/occupation/proc/SetJob(mob/user, role) - var/datum/job/job = job_master.GetJob(role) - if(!job) - return 0 - - if(role == "Assistant") - if(pref.job_civilian_low & job.flag) - pref.job_civilian_low &= ~job.flag - else - pref.job_civilian_low |= job.flag - return 1 - - if(pref.GetJobDepartment(job, 1) & job.flag) - SetJobDepartment(job, 1) - else if(pref.GetJobDepartment(job, 2) & job.flag) - SetJobDepartment(job, 2) - else if(pref.GetJobDepartment(job, 3) & job.flag) - SetJobDepartment(job, 3) - else//job = Never - SetJobDepartment(job, 4) - - return 1 - -/datum/category_item/player_setup_item/occupation/proc/SetJobDepartment(var/datum/job/job, var/level) - if(!job || !level) return 0 - switch(level) - if(1)//Only one of these should ever be active at once so clear them all here - pref.job_civilian_high = 0 - pref.job_medsci_high = 0 - pref.job_engsec_high = 0 - return 1 - if(2)//Set current highs to med, then reset them - pref.job_civilian_med |= pref.job_civilian_high - pref.job_medsci_med |= pref.job_medsci_high - pref.job_engsec_med |= pref.job_engsec_high - pref.job_civilian_high = 0 - pref.job_medsci_high = 0 - pref.job_engsec_high = 0 - - switch(job.department_flag) - if(CIVILIAN) - switch(level) - if(2) - pref.job_civilian_high = job.flag - pref.job_civilian_med &= ~job.flag - if(3) - pref.job_civilian_med |= job.flag - pref.job_civilian_low &= ~job.flag - else - pref.job_civilian_low |= job.flag - if(MEDSCI) - switch(level) - if(2) - pref.job_medsci_high = job.flag - pref.job_medsci_med &= ~job.flag - if(3) - pref.job_medsci_med |= job.flag - pref.job_medsci_low &= ~job.flag - else - pref.job_medsci_low |= job.flag - if(ENGSEC) - switch(level) - if(2) - pref.job_engsec_high = job.flag - pref.job_engsec_med &= ~job.flag - if(3) - pref.job_engsec_med |= job.flag - pref.job_engsec_low &= ~job.flag - else - pref.job_engsec_low |= job.flag - return 1 - -/datum/category_item/player_setup_item/occupation/proc/ResetJobs() - pref.job_civilian_high = 0 - pref.job_civilian_med = 0 - pref.job_civilian_low = 0 - - pref.job_medsci_high = 0 - pref.job_medsci_med = 0 - pref.job_medsci_low = 0 - - pref.job_engsec_high = 0 - pref.job_engsec_med = 0 - pref.job_engsec_low = 0 - - pref.player_alt_titles.Cut() - -/datum/preferences/proc/GetPlayerAltTitle(datum/job/job) - return (job.title in player_alt_titles) ? player_alt_titles[job.title] : job.title - -/datum/preferences/proc/GetJobDepartment(var/datum/job/job, var/level) - if(!job || !level) return 0 - switch(job.department_flag) - if(CIVILIAN) - switch(level) - if(1) - return job_civilian_high - if(2) - return job_civilian_med - if(3) - return job_civilian_low - if(MEDSCI) - switch(level) - if(1) - return job_medsci_high - if(2) - return job_medsci_med - if(3) - return job_medsci_low - if(ENGSEC) - switch(level) - if(1) - return job_engsec_high - if(2) - return job_engsec_med - if(3) - return job_engsec_low - return 0 diff --git a/code/modules/client/preference_setup/preference_setup.dm b/code/modules/client/preference_setup/preference_setup.dm deleted file mode 100644 index 9cb4f943f85..00000000000 --- a/code/modules/client/preference_setup/preference_setup.dm +++ /dev/null @@ -1,209 +0,0 @@ -// These are not flags, binary operations not intended -#define TOPIC_NOACTION 0 -#define TOPIC_HANDLED 1 -#define TOPIC_REFRESH 2 - -/datum/category_group/player_setup_category/general_preferences - name = "General" - sort_order = 1 - category_item_type = /datum/category_item/player_setup_item/general - -/datum/category_group/player_setup_category/skill_preferences - name = "Skills" - sort_order = 2 - category_item_type = /datum/category_item/player_setup_item/skills - -/datum/category_group/player_setup_category/occupation_preferences - name = "Occupation" - sort_order = 3 - category_item_type = /datum/category_item/player_setup_item/occupation - -/datum/category_group/player_setup_category/appearance_preferences - name = "Antagonism" - sort_order = 4 - category_item_type = /datum/category_item/player_setup_item/antagonism - -/datum/category_group/player_setup_category/global_preferences - name = "Global" - sort_order = 5 - category_item_type = /datum/category_item/player_setup_item/player_global - -/**************************** -* Category Collection Setup * -****************************/ -/datum/category_collection/player_setup_collection - category_group_type = /datum/category_group/player_setup_category - var/datum/preferences/preferences - var/datum/category_group/player_setup_category/selected_category = null - -/datum/category_collection/player_setup_collection/New(var/datum/preferences/preferences) - src.preferences = preferences - ..() - selected_category = categories[1] - -/datum/category_collection/player_setup_collection/Destroy() - preferences = null - selected_category = null - return ..() - -/datum/category_collection/player_setup_collection/proc/load_character(var/savefile/S) - for(var/datum/category_group/player_setup_category/PS in categories) - PS.load_character(S) - -/datum/category_collection/player_setup_collection/proc/save_character(var/savefile/S) - for(var/datum/category_group/player_setup_category/PS in categories) - PS.save_character(S) - -/datum/category_collection/player_setup_collection/proc/load_preferences(var/savefile/S) - for(var/datum/category_group/player_setup_category/PS in categories) - PS.load_preferences(S) - -/datum/category_collection/player_setup_collection/proc/save_preferences(var/savefile/S) - for(var/datum/category_group/player_setup_category/PS in categories) - PS.save_preferences(S) - -/datum/category_collection/player_setup_collection/proc/header() - var/dat = "" - for(var/datum/category_group/player_setup_category/PS in categories) - if(PS == selected_category) - dat += "[PS.name] " // TODO: Check how to properly mark a href/button selected in a classic browser window - else - dat += "[PS.name] " - return dat - -/datum/category_collection/player_setup_collection/proc/content(var/mob/user) - if(selected_category) - return selected_category.content(user) - -/datum/category_collection/player_setup_collection/Topic(var/href,var/list/href_list) - if(..()) - return 1 - var/mob/user = usr - if(!user.client) - return 1 - - if(href_list["category"]) - var/category = locate(href_list["category"]) - if(category && category in categories) - selected_category = category - . = 1 - - if(.) - user.client.prefs.ShowChoices(user) - -/************************** -* Category Category Setup * -**************************/ -/datum/category_group/player_setup_category - var/sort_order = 0 - -/datum/category_group/player_setup_category/dd_SortValue() - return sort_order - -/datum/category_group/player_setup_category/proc/load_character(var/savefile/S) - for(var/datum/category_item/player_setup_item/PI in items) - PI.load_character(S) - PI.sanitize_character() - -/datum/category_group/player_setup_category/proc/save_character(var/savefile/S) - for(var/datum/category_item/player_setup_item/PI in items) - PI.sanitize_character() - PI.save_character(S) - -/datum/category_group/player_setup_category/proc/load_preferences(var/savefile/S) - for(var/datum/category_item/player_setup_item/PI in items) - PI.load_preferences(S) - PI.sanitize_preferences() - -/datum/category_group/player_setup_category/proc/save_preferences(var/savefile/S) - for(var/datum/category_item/player_setup_item/PI in items) - PI.sanitize_preferences() - PI.save_preferences(S) - -/datum/category_group/player_setup_category/proc/content(var/mob/user) - . = "
" - var/current = 0 - var/halfway = items.len / 2 - for(var/datum/category_item/player_setup_item/PI in items) - if(halfway && current++ >= halfway) - halfway = 0 - . += "" - . += "[PI.content(user)]
" - . += "
" - -/datum/category_group/player_setup_category/occupation_preferences/content(var/mob/user) - for(var/datum/category_item/player_setup_item/PI in items) - . += "[PI.content(user)]
" - -/********************** -* Category Item Setup * -**********************/ -/datum/category_item/player_setup_item - var/sort_order = 0 - var/datum/preferences/pref - -/datum/category_item/player_setup_item/New() - ..() - var/datum/category_collection/player_setup_collection/psc = category.collection - pref = psc.preferences - -/datum/category_item/player_setup_item/Destroy() - pref = null - return ..() - -/datum/category_item/player_setup_item/dd_SortValue() - return sort_order - -/* -* Called when the item is asked to load per character settings -*/ -/datum/category_item/player_setup_item/proc/load_character(var/savefile/S) - return - -/* -* Called when the item is asked to save per character settings -*/ -/datum/category_item/player_setup_item/proc/save_character(var/savefile/S) - return - -/* -* Called when the item is asked to load user/global settings -*/ -/datum/category_item/player_setup_item/proc/load_preferences(var/savefile/S) - return - -/* -* Called when the item is asked to save user/global settings -*/ -/datum/category_item/player_setup_item/proc/save_preferences(var/savefile/S) - return - -/datum/category_item/player_setup_item/proc/content() - return - -/datum/category_item/player_setup_item/proc/sanitize_character() - return - -/datum/category_item/player_setup_item/proc/sanitize_preferences() - return - -/datum/category_item/player_setup_item/Topic(var/href,var/list/href_list) - if(..()) - return 1 - var/mob/user = usr - if(!user.client) - return 1 - - . = OnTopic(href, href_list, user) - if(. == TOPIC_REFRESH) - user.client.prefs.ShowChoices(user) - -/datum/category_item/player_setup_item/CanUseTopic(var/mob/user) - return 1 - -/datum/category_item/player_setup_item/proc/OnTopic(var/href,var/list/href_list, var/mob/user) - return TOPIC_NOACTION - -/datum/category_item/player_setup_item/proc/preference_mob() - if(pref && pref.client && pref.client.mob) - return pref.client.mob diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm deleted file mode 100644 index 1f60cd3bb7f..00000000000 --- a/code/modules/client/preference_setup/skills/skills.dm +++ /dev/null @@ -1,77 +0,0 @@ -/datum/category_item/player_setup_item/skills - name = "Skills" - sort_order = 1 - -/datum/category_item/player_setup_item/skills/load_character(var/savefile/S) - S["skills"] >> pref.skills - S["used_skillpoints"] >> pref.used_skillpoints - S["skill_specialization"] >> pref.skill_specialization - -/datum/category_item/player_setup_item/skills/save_character(var/savefile/S) - S["skills"] << pref.skills - S["used_skillpoints"] << pref.used_skillpoints - S["skill_specialization"] << pref.skill_specialization - -/datum/category_item/player_setup_item/skills/sanitize_character() - if(SKILLS == null) setup_skills() - if(!pref.skills) pref.skills = list() - if(!pref.skills.len) pref.ZeroSkills() - if(pref.used_skillpoints < 0) pref.used_skillpoints = 0 - -/datum/category_item/player_setup_item/skills/content() - . += "Select your Skills
" - . += "Current skill level: [pref.GetSkillClass(pref.used_skillpoints)] ([pref.used_skillpoints])
" - . += "Use preconfigured skillset
" - . += "" - for(var/V in SKILLS) - . += "" - for(var/datum/skill/S in SKILLS[V]) - var/level = pref.skills[S.ID] - . += "" - . += "" - . += "" - // secondary skills don't have an amateur level - if(S.secondary) - . += "" - else - . += "" - . += "" - . += "" - . += "" - . += "
[V]" - . += "
[S.name]\[Untrained\]\[Amateur\]\[Trained\]\[Professional\]
" - -/datum/category_item/player_setup_item/skills/OnTopic(href, href_list, user) - if(href_list["skillinfo"]) - var/datum/skill/S = locate(href_list["skillinfo"]) - var/HTML = "[S.name]
[S.desc]" - user << browse(HTML, "window=\ref[user]skillinfo") - return TOPIC_HANDLED - - else if(href_list["setskill"]) - var/datum/skill/S = locate(href_list["setskill"]) - var/value = text2num(href_list["newvalue"]) - pref.skills[S.ID] = value - pref.CalculateSkillPoints() - return TOPIC_REFRESH - - else if(href_list["preconfigured"]) - var/selected = input(user, "Select a skillset", "Skillset") as null|anything in SKILL_PRE - if(!selected && !CanUseTopic(user)) return - - pref.ZeroSkills(1) - for(var/V in SKILL_PRE[selected]) - if(V == "field") - pref.skill_specialization = SKILL_PRE[selected]["field"] - continue - pref.skills[V] = SKILL_PRE[selected][V] - pref.CalculateSkillPoints() - - return TOPIC_REFRESH - - else if(href_list["setspecialization"]) - pref.skill_specialization = href_list["setspecialization"] - pref.CalculateSkillPoints() - return TOPIC_REFRESH - - return ..() diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 82843a05554..c6a91faf861 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -2,6 +2,31 @@ var/list/preferences_datums = list() +var/global/list/special_roles = list( //keep synced with the defines BE_* in setup.dm --rastaf +//some autodetection here. +// TODO: Update to new antagonist system. + "traitor" = IS_MODE_COMPILED("traitor"), // 0 + "operative" = IS_MODE_COMPILED("nuclear"), // 1 + "changeling" = IS_MODE_COMPILED("changeling"), // 2 + "wizard" = IS_MODE_COMPILED("wizard"), // 3 + "malf AI" = IS_MODE_COMPILED("malfunction"), // 4 + "revolutionary" = IS_MODE_COMPILED("revolution"), // 5 + "alien candidate" = 1, //always show // 6 + "positronic brain" = 1, // 7 + "cultist" = IS_MODE_COMPILED("cult"), // 8 + "infested monkey" = IS_MODE_COMPILED("monkey"), // 9 + "ninja" = "true", // 10 + "raider" = IS_MODE_COMPILED("heist"), // 11 + "diona" = 1, // 12 + "loyalist" = IS_MODE_COMPILED("revolution"), // 13 + "pAI candidate" = 1, // -- TLE // 14 +) + +//used for alternate_option +#define GET_RANDOM_JOB 0 +#define BE_ASSISTANT 1 +#define RETURN_TO_LOBBY 2 + datum/preferences //doohickeys for savefiles var/path @@ -52,7 +77,7 @@ datum/preferences var/species = "Human" //Species datum to use. var/species_preview //Used for the species selection window. var/list/alternate_languages = list() //Secondary language(s) - var/list/language_prefixes = list() //Language prefix keys + var/list/language_prefixes = list() //Kanguage prefix keys var/list/gear //Custom/fluff item loadout. //Some faction information. @@ -105,22 +130,14 @@ datum/preferences var/uplinklocation = "PDA" - // OOC Metadata: + // OOC Metadata: var/metadata = "" + var/slot_name = "" var/client/client = null - var/datum/category_collection/player_setup_collection/player_setup - /datum/preferences/New(client/C) - player_setup = new(src) - - gender = pick(MALE, FEMALE) - real_name = random_name(gender,species) b_type = pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+") - - gear = list() - if(istype(C)) client = C if(!IsGuestKey(C.key)) @@ -128,6 +145,10 @@ datum/preferences if(load_preferences()) if(load_character()) return + gender = pick(MALE, FEMALE) + real_name = random_name(gender,species) + + gear = list() /datum/preferences/proc/ZeroSkills(var/forced = 0) for(var/V in SKILLS) for(var/datum/skill/S in SKILLS[V]) @@ -181,26 +202,705 @@ datum/preferences if(24 to 1000) return "God" +/datum/preferences/proc/SetSkills(mob/user) + if(SKILLS == null) + setup_skills() + + if(skills.len == 0) + ZeroSkills() + + + var/HTML = "" + HTML += "Select your Skills
" + HTML += "Current skill level: [GetSkillClass(used_skillpoints)] ([used_skillpoints])
" + HTML += "Use preconfigured skillset
" + HTML += "" + for(var/V in SKILLS) + HTML += "" + for(var/datum/skill/S in SKILLS[V]) + var/level = skills[S.ID] + HTML += "" + HTML += "" + HTML += "" + // secondary skills don't have an amateur level + if(S.secondary) + HTML += "" + else + HTML += "" + HTML += "" + HTML += "" + HTML += "" + HTML += "
[V]" + HTML += "
[S.name]\[Untrained\]\[Amateur\]\[Trained\]\[Professional\]
" + HTML += "\[Done\]" + + user << browse(null, "window=preferences") + user << browse(HTML, "window=show_skills;size=600x800") + return + /datum/preferences/proc/ShowChoices(mob/user) if(!user || !user.client) return + update_preview_icon() + if(preview_icon_front && preview_icon_side) + user << browse_rsc(preview_icon_front, "previewicon.png") + user << browse_rsc(preview_icon_side, "previewicon2.png") var/dat = "
" if(path) - dat += "Slot - " + dat += "
" + dat += "Slot [slot_name] - " dat += "Load slot - " dat += "Save slot - " dat += "Reload slot" + dat += "
" else dat += "Please create an account to save your preferences." - dat += "
" - dat += player_setup.header() - dat += "

" - dat += player_setup.content(user) + dat += "

" - dat += "" - user << browse(dat, "window=preferences;size=625x736") + dat += "Name: " + dat += "[real_name]
" + dat += "(Random Name) " + dat += "(Always Random Name: [be_random_name ? "Yes" : "No"])" + dat += "
" + + dat += "Gender: [gender == MALE ? "Male" : "Female"]
" + dat += "Age: [age]
" + dat += "Spawn Point: [spawnpoint]" + + dat += "
" + dat += "UI Style: [UI_style]
" + dat += "Custom UI(recommended for White UI):
" + dat += "-Color: [UI_style_color]
__

" + dat += "-Alpha(transparency): [UI_style_alpha]
" + dat += "Play admin midis: [(toggles & SOUND_MIDI) ? "Yes" : "No"]
" + dat += "Play lobby music: [(toggles & SOUND_LOBBY) ? "Yes" : "No"]
" + dat += "Ghost ears: [(toggles & CHAT_GHOSTEARS) ? "All Speech" : "Nearest Creatures"]
" + dat += "Ghost sight: [(toggles & CHAT_GHOSTSIGHT) ? "All Emotes" : "Nearest Creatures"]
" + dat += "Ghost radio: [(toggles & CHAT_GHOSTRADIO) ? "All Chatter" : "Nearest Speakers"]
" + + if(config.allow_Metadata) + dat += "OOC Notes: Edit
" + + dat += "
Custom Loadout: " + var/total_cost = 0 + + if(!islist(gear)) gear = list() + + if(gear && gear.len) + dat += "
" + for(var/i = 1; i <= gear.len; i++) + var/datum/gear/G = gear_datums[gear[i]] + if(G) + total_cost += G.cost + dat += "[gear[i]] ([G.cost] points) \[remove\]
" + + dat += "Used: [total_cost] points." + else + dat += "none." + + if(total_cost < MAX_GEAR_COST) + dat += " \[add\]" + if(gear && gear.len) + dat += " \[clear\]" + + dat += "

Occupation Choices
" + dat += "\tSet Preferences
" + + dat += "
Body " + dat += "(®)" + dat += "
" + dat += "Species: [species]
" + + dat += "Blood Type: [b_type]
" + dat += "Skin Tone: [-s_tone + 35]/220
" + //dat += "Skin pattern: Adjust
" + dat += "Needs Glasses: [disabilities == 0 ? "No" : "Yes"]
" + dat += "Limbs: Adjust
" + dat += "Internal Organs: Adjust
" + + //display limbs below + var/ind = 0 + for(var/name in organ_data) + //world << "[ind] \ [organ_data.len]" + var/status = organ_data[name] + var/organ_name = null + switch(name) + if("l_arm") + organ_name = "left arm" + if("r_arm") + organ_name = "right arm" + if("l_leg") + organ_name = "left leg" + if("r_leg") + organ_name = "right leg" + if("l_foot") + organ_name = "left foot" + if("r_foot") + organ_name = "right foot" + if("l_hand") + organ_name = "left hand" + if("r_hand") + organ_name = "right hand" + if("heart") + organ_name = "heart" + if("eyes") + organ_name = "eyes" + + if(status == "cyborg") + ++ind + if(ind > 1) + dat += ", " + var/datum/robolimb/R + if(rlimb_data[name] && all_robolimbs[rlimb_data[name]]) + R = all_robolimbs[rlimb_data[name]] + else + R = basic_robolimb + dat += "\t[R.company] [organ_name] prothesis" + else if(status == "amputated") + ++ind + if(ind > 1) + dat += ", " + dat += "\tAmputated [organ_name]" + else if(status == "mechanical") + ++ind + if(ind > 1) + dat += ", " + dat += "\tMechanical [organ_name]" + else if(status == "assisted") + ++ind + if(ind > 1) + dat += ", " + switch(organ_name) + if("heart") + dat += "\tPacemaker-assisted [organ_name]" + if("voicebox") //on adding voiceboxes for speaking skrell/similar replacements + dat += "\tSurgically altered [organ_name]" + if("eyes") + dat += "\tRetinal overlayed [organ_name]" + else + dat += "\tMechanically assisted [organ_name]" + if(!ind) + dat += "\[...\]

" + else + dat += "

" + + + dat += "Languages
" + var/datum/species/S = all_species[species] + if(S.language) + dat += "- [S.language]
" + if(S.default_language && S.default_language != S.language) + dat += "- [S.default_language]
" + if(S.num_alternate_languages) + if(alternate_languages.len) + for(var/i = 1 to alternate_languages.len) + var/lang = alternate_languages[i] + dat += "- [lang] - remove
" + + if(alternate_languages.len < S.num_alternate_languages) + dat += "- add ([S.num_alternate_languages - alternate_languages.len] remaining)
" + else + dat += "- [species] cannot choose secondary languages.
" + + dat += "Language Keys
" + dat += " [english_list(language_prefixes, and_text = " ", comma_text = " ")] Change Reset
" + + dat += "

" + var/list/undies = gender == MALE ? underwear_m : underwear_f + + dat += "Underwear: [get_key_by_value(undies,underwear)]
" + + dat += "Undershirt: [get_key_by_value(undershirt_t,undershirt)]
" + + dat += "Socks: [get_key_by_value(socks_t,socks)]
" + + dat += "Backpack Type:
[backbaglist[backbag]]
" + + dat += "[company_name] Relation:
[nanotrasen_relation]
" + + dat += "
Preview
" + + dat += "
" + + if(jobban_isbanned(user, "Records")) + dat += "You are banned from using character records.
" + else + dat += "Character Records
" + + dat += "Set Antag Options
" + + dat += "\tSet Skills ([GetSkillClass(used_skillpoints)] [used_skillpoints > 0 ? "[used_skillpoints]" : "0"])
" + + dat += "Set Flavor Text
" + dat += "Set Robot Flavour Text
" + + dat += "pAI Configuration
" + dat += "
" + + dat += "
Hair
" + dat += "Change Color
__
" + dat += " Style: [h_style]
" + + dat += "
Facial
" + dat += "Change Color
__
" + dat += " Style: [f_style]
" + + dat += "
Eyes
" + dat += "Change Color
__

" + + dat += "
Body Color
" + dat += "Change Color
__
" + + dat += "

Background Information
" + dat += "Home system: [home_system]
" + dat += "Citizenship: [citizenship]
" + dat += "Faction: [faction]
" + dat += "Religion: [religion]
" + + dat += "

" + + if(jobban_isbanned(user, "Syndicate")) + dat += "You are banned from antagonist roles." + src.be_special = 0 + else + var/n = 0 + for (var/i in special_roles) + if(special_roles[i]) //if mode is available on the server + if(jobban_isbanned(user, i) || (i == "positronic brain" && jobban_isbanned(user, "AI") && jobban_isbanned(user, "Cyborg")) || (i == "pAI candidate" && jobban_isbanned(user, "pAI"))) + dat += "Be [i]: \[BANNED]
" + else + dat += "Be [i]: [src.be_special&(1<
" + n++ + dat += "

" + + if(!IsGuestKey(user.key)) + dat += "Undo - " + dat += "Save Setup - " + + dat += "Reset Setup" + dat += "
" + + user << browse(dat, "window=preferences;size=560x736") + +/datum/preferences/proc/SetChoices(mob/user, limit = 16, list/splitJobs = list("Chief Medical Officer"), width = 550, height = 660) + if(!job_master) + return + + //limit - The amount of jobs allowed per column. Defaults to 17 to make it look nice. + //splitJobs - Allows you split the table by job. You can make different tables for each department by including their heads. Defaults to CE to make it look nice. + //width - Screen' width. Defaults to 550 to make it look nice. + //height - Screen's height. Defaults to 500 to make it look nice. + + + var/HTML = "" + HTML += "
" + HTML += "Choose occupation chances
Unavailable occupations are crossed out.

" + HTML += "
\[Done\]

" // Easier to press up here. + HTML += "
" // Table within a table for alignment, also allows you to easily add more colomns. + HTML += "" + var/index = -1 + + //The job before the current job. I only use this to get the previous jobs color when I'm filling in blank rows. + var/datum/job/lastJob + if (!job_master) return + for(var/datum/job/job in job_master.occupations) + + index += 1 + if((index >= limit) || (job.title in splitJobs)) + if((index < limit) && (lastJob != null)) + //If the cells were broken up by a job in the splitJob list then it will fill in the rest of the cells with + //the last job's selection color. Creating a rather nice effect. + for(var/i = 0, i < (limit - index), i += 1) + HTML += "" + HTML += "
  
" + index = 0 + + HTML += "" + continue + if(!job.player_old_enough(user.client)) + var/available_in_days = job.available_in_days(user.client) + HTML += "[rank]" + continue + if((job_civilian_low & ASSISTANT) && (rank != "Assistant")) + HTML += "[rank]" + continue + if((rank in command_positions) || (rank == "AI"))//Bold head jobs + HTML += "[rank]" + else + HTML += "[rank]" + + HTML += "" + HTML += "" + continue + + if(GetJobDepartment(job, 1) & job.flag) + HTML += " \[High]" + else if(GetJobDepartment(job, 2) & job.flag) + HTML += " \[Medium]" + else if(GetJobDepartment(job, 3) & job.flag) + HTML += " \[Low]" + else + HTML += " \[NEVER]" + if(job.alt_titles) + HTML += "" + HTML += "" + + HTML += "
" + var/rank = job.title + lastJob = job + if(jobban_isbanned(user, rank)) + HTML += "[rank] \[BANNED]
\[IN [(available_in_days)] DAYS]
" + + HTML += "" + + if(rank == "Assistant")//Assistant is special + if(job_civilian_low & ASSISTANT) + HTML += " \[Yes]" + else + HTML += " \[No]" + if(job.alt_titles) //Blatantly cloned from a few lines down. + HTML += "
 \[[GetPlayerAltTitle(job)]\]
 \[[GetPlayerAltTitle(job)]\]
" + + HTML += "
" + + switch(alternate_option) + if(GET_RANDOM_JOB) + HTML += "

Get random job if preferences unavailable

" + if(BE_ASSISTANT) + HTML += "

Be assistant if preference unavailable

" + if(RETURN_TO_LOBBY) + HTML += "

Return to lobby if preference unavailable

" + + HTML += "
\[Reset\]
" + HTML += "
" + + user << browse(null, "window=preferences") + user << browse(HTML, "window=mob_occupation;size=[width]x[height]") + return + +/datum/preferences/proc/SetDisabilities(mob/user) + var/HTML = "" + HTML += "
" + HTML += "Choose disabilities
" + + HTML += "Need Glasses? [disabilities & (1<<0) ? "Yes" : "No"]
" + HTML += "Seizures? [disabilities & (1<<1) ? "Yes" : "No"]
" + HTML += "Coughing? [disabilities & (1<<2) ? "Yes" : "No"]
" + HTML += "Tourettes/Twitching? [disabilities & (1<<3) ? "Yes" : "No"]
" + HTML += "Nervousness? [disabilities & (1<<4) ? "Yes" : "No"]
" + HTML += "Deafness? [disabilities & (1<<5) ? "Yes" : "No"]
" + + HTML += "
" + HTML += "\[Done\]" + HTML += "
" + + user << browse(null, "window=preferences") + user << browse(HTML, "window=disabil;size=350x300") + return + +/datum/preferences/proc/SetRecords(mob/user) + var/HTML = "" + HTML += "
" + HTML += "Set Character Records
" + + HTML += "Medical Records
" + + HTML += TextPreview(med_record,40) + + HTML += "

Employment Records
" + + HTML += TextPreview(gen_record,40) + + HTML += "

Security Records
" + + HTML += TextPreview(sec_record,40) + + HTML += "
" + HTML += "\[Done\]" + HTML += "
" + + user << browse(null, "window=preferences") + user << browse(HTML, "window=records;size=350x300") + return + +/datum/preferences/proc/SetSpecies(mob/user) + if(!species_preview || !(species_preview in all_species)) + species_preview = "Human" + var/datum/species/current_species = all_species[species_preview] + var/dat = "" + dat += "

[current_species.name] \[change\]


" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "
[current_species.blurb]" + if("preview" in icon_states(current_species.icobase)) + usr << browse_rsc(icon(current_species.icobase,"preview"), "species_preview_[current_species.name].png") + dat += "

" + dat += "Language: [current_species.language]
" + dat += "" + if(current_species.spawn_flags & CAN_JOIN) + dat += "
Often present on human stations." + if(current_species.spawn_flags & IS_WHITELISTED) + dat += "
Whitelist restricted." + if(current_species.flags & NO_BLOOD) + dat += "
Does not have blood." + if(current_species.flags & NO_BREATHE) + dat += "
Does not breathe." + if(current_species.flags & NO_SCAN) + dat += "
Does not have DNA." + if(current_species.flags & NO_PAIN) + dat += "
Does not feel pain." + if(current_species.flags & NO_SLIP) + dat += "
Has excellent traction." + if(current_species.flags & NO_POISON) + dat += "
Immune to most poisons." + if(current_species.appearance_flags & HAS_SKIN_TONE) + dat += "
Has a variety of skin tones." + if(current_species.appearance_flags & HAS_SKIN_COLOR) + dat += "
Has a variety of skin colours." + if(current_species.appearance_flags & HAS_EYE_COLOR) + dat += "
Has a variety of eye colours." + if(current_species.flags & IS_PLANT) + dat += "
Has a plantlike physiology." + dat += "

" + + var/restricted = 0 + if(config.usealienwhitelist) //If we're using the whitelist, make sure to check it! + if(!(current_species.spawn_flags & CAN_JOIN)) + restricted = 2 + else if((current_species.spawn_flags & IS_WHITELISTED) && !is_alien_whitelisted(user,current_species)) + restricted = 1 + + if(restricted) + if(restricted == 1) + dat += "You cannot play as this species.
If you wish to be whitelisted, you can make an application post on the forums.

" + else if(restricted == 2) + dat += "You cannot play as this species.
This species is not available for play as a station race..

" + if(!restricted || check_rights(R_ADMIN, 0)) + dat += "\[select\]" + dat += "
" + + user << browse(null, "window=preferences") + user << browse(dat, "window=species;size=700x400") + +/datum/preferences/proc/SetAntagoptions(mob/user) + if(uplinklocation == "" || !uplinklocation) + uplinklocation = "PDA" + var/HTML = "" + HTML += "
" + HTML += "Antagonist Options
" + HTML += "
" + HTML +="Uplink Type : [uplinklocation]" + HTML +="
" + HTML +="Exploitable information about you : " + HTML += "
" + if(jobban_isbanned(user, "Records")) + HTML += "You are banned from using character records.
" + else + HTML +="[TextPreview(exploit_record,40)]" + HTML +="
" + HTML +="
" + HTML +="\[Done\]" + + HTML += "
" + + user << browse(null, "window=preferences") + user << browse(HTML, "window=antagoptions") + return + +/datum/preferences/proc/SetFlavorText(mob/user) + var/HTML = "" + HTML += "
" + HTML += "Set Flavour Text
" + HTML += "
" + HTML += "General: " + HTML += TextPreview(flavor_texts["general"]) + HTML += "
" + HTML += "Head: " + HTML += TextPreview(flavor_texts["head"]) + HTML += "
" + HTML += "Face: " + HTML += TextPreview(flavor_texts["face"]) + HTML += "
" + HTML += "Eyes: " + HTML += TextPreview(flavor_texts["eyes"]) + HTML += "
" + HTML += "Body: " + HTML += TextPreview(flavor_texts["torso"]) + HTML += "
" + HTML += "Arms: " + HTML += TextPreview(flavor_texts["arms"]) + HTML += "
" + HTML += "Hands: " + HTML += TextPreview(flavor_texts["hands"]) + HTML += "
" + HTML += "Legs: " + HTML += TextPreview(flavor_texts["legs"]) + HTML += "
" + HTML += "Feet: " + HTML += TextPreview(flavor_texts["feet"]) + HTML += "
" + HTML += "
" + HTML +="\[Done\]" + HTML += "" + user << browse(null, "window=preferences") + user << browse(HTML, "window=flavor_text;size=430x300") + return + +/datum/preferences/proc/SetFlavourTextRobot(mob/user) + var/HTML = "" + HTML += "
" + HTML += "Set Robot Flavour Text
" + HTML += "
" + HTML += "Default: " + HTML += TextPreview(flavour_texts_robot["Default"]) + HTML += "
" + for(var/module in robot_module_types) + HTML += "[module]: " + HTML += TextPreview(flavour_texts_robot[module]) + HTML += "
" + HTML += "
" + HTML +="\[Done\]" + HTML += "" + user << browse(null, "window=preferences") + user << browse(HTML, "window=flavour_text_robot;size=430x300") + return + +/datum/preferences/proc/GetPlayerAltTitle(datum/job/job) + return player_alt_titles.Find(job.title) > 0 \ + ? player_alt_titles[job.title] \ + : job.title + +/datum/preferences/proc/SetPlayerAltTitle(datum/job/job, new_title) + // remove existing entry + if(player_alt_titles.Find(job.title)) + player_alt_titles -= job.title + // add one if it's not default + if(job.title != new_title) + player_alt_titles[job.title] = new_title + +/datum/preferences/proc/SetJob(mob/user, role) + var/datum/job/job = job_master.GetJob(role) + if(!job) + user << browse(null, "window=mob_occupation") + ShowChoices(user) + return + + if(role == "Assistant") + if(job_civilian_low & job.flag) + job_civilian_low &= ~job.flag + else + job_civilian_low |= job.flag + SetChoices(user) + return 1 + + if(GetJobDepartment(job, 1) & job.flag) + SetJobDepartment(job, 1) + else if(GetJobDepartment(job, 2) & job.flag) + SetJobDepartment(job, 2) + else if(GetJobDepartment(job, 3) & job.flag) + SetJobDepartment(job, 3) + else//job = Never + SetJobDepartment(job, 4) + + SetChoices(user) + return 1 + +/datum/preferences/proc/ResetJobs() + job_civilian_high = 0 + job_civilian_med = 0 + job_civilian_low = 0 + + job_medsci_high = 0 + job_medsci_med = 0 + job_medsci_low = 0 + + job_engsec_high = 0 + job_engsec_med = 0 + job_engsec_low = 0 + + +/datum/preferences/proc/GetJobDepartment(var/datum/job/job, var/level) + if(!job || !level) return 0 + switch(job.department_flag) + if(CIVILIAN) + switch(level) + if(1) + return job_civilian_high + if(2) + return job_civilian_med + if(3) + return job_civilian_low + if(MEDSCI) + switch(level) + if(1) + return job_medsci_high + if(2) + return job_medsci_med + if(3) + return job_medsci_low + if(ENGSEC) + switch(level) + if(1) + return job_engsec_high + if(2) + return job_engsec_med + if(3) + return job_engsec_low + return 0 + +/datum/preferences/proc/SetJobDepartment(var/datum/job/job, var/level) + if(!job || !level) return 0 + switch(level) + if(1)//Only one of these should ever be active at once so clear them all here + job_civilian_high = 0 + job_medsci_high = 0 + job_engsec_high = 0 + return 1 + if(2)//Set current highs to med, then reset them + job_civilian_med |= job_civilian_high + job_medsci_med |= job_medsci_high + job_engsec_med |= job_engsec_high + job_civilian_high = 0 + job_medsci_high = 0 + job_engsec_high = 0 + + switch(job.department_flag) + if(CIVILIAN) + switch(level) + if(2) + job_civilian_high = job.flag + job_civilian_med &= ~job.flag + if(3) + job_civilian_med |= job.flag + job_civilian_low &= ~job.flag + else + job_civilian_low |= job.flag + if(MEDSCI) + switch(level) + if(2) + job_medsci_high = job.flag + job_medsci_med &= ~job.flag + if(3) + job_medsci_med |= job.flag + job_medsci_low &= ~job.flag + else + job_medsci_low |= job.flag + if(ENGSEC) + switch(level) + if(2) + job_engsec_high = job.flag + job_engsec_med &= ~job.flag + if(3) + job_engsec_med |= job.flag + job_engsec_low &= ~job.flag + else + job_engsec_low |= job.flag + return 1 /datum/preferences/proc/process_link(mob/user, list/href_list) if(!user) return @@ -213,24 +913,778 @@ datum/preferences else user << "The forum URL is not set in the server configuration." return - else - switch(href_list["preference"]) - if("save") - save_preferences() - save_character() - if("reload") - load_preferences() - load_character() + if(href_list["preference"] == "job") + switch(href_list["task"]) + if("close") + user << browse(null, "window=mob_occupation") + ShowChoices(user) + if("reset") + ResetJobs() + SetChoices(user) + if("random") + if(alternate_option == GET_RANDOM_JOB || alternate_option == BE_ASSISTANT) + alternate_option += 1 + else if(alternate_option == RETURN_TO_LOBBY) + alternate_option = 0 + else + return 0 + SetChoices(user) + if ("alt_title") + var/datum/job/job = locate(href_list["job"]) + if (job) + var/choices = list(job.title) + job.alt_titles + var/choice = input("Pick a title for [job.title].", "Character Generation", GetPlayerAltTitle(job)) as anything in choices | null + if(choice) + SetPlayerAltTitle(job, choice) + SetChoices(user) + if("input") + SetJob(user, href_list["text"]) + else + SetChoices(user) + return 1 + else if(href_list["preference"] == "skills") + if(href_list["cancel"]) + user << browse(null, "window=show_skills") + ShowChoices(user) + else if(href_list["skillinfo"]) + var/datum/skill/S = locate(href_list["skillinfo"]) + var/HTML = "[S.name]
[S.desc]" + user << browse(HTML, "window=\ref[user]skillinfo") + else if(href_list["setskill"]) + var/datum/skill/S = locate(href_list["setskill"]) + var/value = text2num(href_list["newvalue"]) + skills[S.ID] = value + CalculateSkillPoints() + SetSkills(user) + else if(href_list["preconfigured"]) + var/selected = input(user, "Select a skillset", "Skillset") as null|anything in SKILL_PRE + if(!selected) return - if("open_load_dialog") - if(!IsGuestKey(user.key)) - open_load_dialog(user) - return 1 + ZeroSkills(1) + for(var/V in SKILL_PRE[selected]) + if(V == "field") + skill_specialization = SKILL_PRE[selected]["field"] + continue + skills[V] = SKILL_PRE[selected][V] + CalculateSkillPoints() - if("changeslot") - load_character(text2num(href_list["num"])) - close_load_dialog(user) + SetSkills(user) + else if(href_list["setspecialization"]) + skill_specialization = href_list["setspecialization"] + CalculateSkillPoints() + SetSkills(user) + else + SetSkills(user) + return 1 + + else if (href_list["preference"] == "loadout") + + if(href_list["task"] == "input") + + var/list/valid_gear_choices = list() + + for(var/gear_name in gear_datums) + var/datum/gear/G = gear_datums[gear_name] + if(G.whitelisted && !is_alien_whitelisted(user, G.whitelisted)) + continue + valid_gear_choices += gear_name + + var/choice = input(user, "Select gear to add: ") as null|anything in valid_gear_choices + + if(choice && gear_datums[choice]) + + var/total_cost = 0 + + if(isnull(gear) || !islist(gear)) gear = list() + + if(gear && gear.len) + for(var/gear_name in gear) + if(gear_datums[gear_name]) + var/datum/gear/G = gear_datums[gear_name] + total_cost += G.cost + + var/datum/gear/C = gear_datums[choice] + total_cost += C.cost + if(C && total_cost <= MAX_GEAR_COST) + gear += choice + user << "Added \the '[choice]' for [C.cost] points ([MAX_GEAR_COST - total_cost] points remaining)." + else + user << "Adding \the '[choice]' will exceed the maximum loadout cost of [MAX_GEAR_COST] points." + + else if(href_list["task"] == "remove") + var/i_remove = text2num(href_list["gear"]) + if(i_remove < 1 || i_remove > gear.len) return + gear.Cut(i_remove, i_remove + 1) + + else if(href_list["task"] == "clear") + gear.Cut() + + else if(href_list["preference"] == "flavor_text") + switch(href_list["task"]) + if("open") + SetFlavorText(user) + return + if("done") + user << browse(null, "window=flavor_text") + ShowChoices(user) + return + if("general") + var/msg = sanitize(input(usr,"Give a general description of your character. This will be shown regardless of clothing, and may include OOC notes and preferences.","Flavor Text",html_decode(flavor_texts[href_list["task"]])) as message, extra = 0) + flavor_texts[href_list["task"]] = msg + else + var/msg = sanitize(input(usr,"Set the flavor text for your [href_list["task"]].","Flavor Text",html_decode(flavor_texts[href_list["task"]])) as message, extra = 0) + flavor_texts[href_list["task"]] = msg + SetFlavorText(user) + return + + else if(href_list["preference"] == "flavour_text_robot") + switch(href_list["task"]) + if("open") + SetFlavourTextRobot(user) + return + if("done") + user << browse(null, "window=flavour_text_robot") + ShowChoices(user) + return + if("Default") + var/msg = sanitize(input(usr,"Set the default flavour text for your robot. It will be used for any module without individual setting.","Flavour Text",html_decode(flavour_texts_robot["Default"])) as message, extra = 0) + flavour_texts_robot[href_list["task"]] = msg + else + var/msg = sanitize(input(usr,"Set the flavour text for your robot with [href_list["task"]] module. If you leave this empty, default flavour text will be used for this module.","Flavour Text",html_decode(flavour_texts_robot[href_list["task"]])) as message, extra = 0) + flavour_texts_robot[href_list["task"]] = msg + SetFlavourTextRobot(user) + return + + else if(href_list["preference"] == "pAI") + paiController.recruitWindow(user, 0) + return 1 + + else if(href_list["preference"] == "records") + if(text2num(href_list["record"]) >= 1) + SetRecords(user) + return + else + user << browse(null, "window=records") + if(href_list["task"] == "med_record") + var/medmsg = sanitize(input(usr,"Set your medical notes here.","Medical Records",html_decode(med_record)) as message, MAX_PAPER_MESSAGE_LEN, extra = 0) + if(medmsg != null) + med_record = medmsg + SetRecords(user) + + if(href_list["task"] == "sec_record") + var/secmsg = sanitize(input(usr,"Set your security notes here.","Security Records",html_decode(sec_record)) as message, MAX_PAPER_MESSAGE_LEN, extra = 0) + if(secmsg != null) + sec_record = secmsg + SetRecords(user) + if(href_list["task"] == "gen_record") + var/genmsg = sanitize(input(usr,"Set your employment notes here.","Employment Records",html_decode(gen_record)) as message, MAX_PAPER_MESSAGE_LEN, extra = 0) + if(genmsg != null) + gen_record = genmsg + SetRecords(user) + + if(href_list["task"] == "exploitable_record") + var/exploitmsg = sanitize(input(usr,"Set exploitable information about you here.","Exploitable Information",html_decode(exploit_record)) as message, MAX_PAPER_MESSAGE_LEN, extra = 0) + if(exploitmsg != null) + exploit_record = exploitmsg + SetAntagoptions(user) + + else if (href_list["preference"] == "antagoptions") + if(text2num(href_list["active"]) == 0) + SetAntagoptions(user) + return + if (href_list["antagtask"] == "uplinktype") + if (uplinklocation == "PDA") + uplinklocation = "Headset" + else if(uplinklocation == "Headset") + uplinklocation = "None" + else + uplinklocation = "PDA" + SetAntagoptions(user) + if (href_list["antagtask"] == "done") + user << browse(null, "window=antagoptions") + ShowChoices(user) + return 1 + + else if (href_list["preference"] == "loadout") + + if(href_list["task"] == "input") + + var/list/valid_gear_choices = list() + + for(var/gear_name in gear_datums) + var/datum/gear/G = gear_datums[gear_name] + if(G.whitelisted && !is_alien_whitelisted(user, G.whitelisted)) + continue + valid_gear_choices += gear_name + + var/choice = input(user, "Select gear to add: ") as null|anything in valid_gear_choices + + if(choice && gear_datums[choice]) + + var/total_cost = 0 + + if(isnull(gear) || !islist(gear)) gear = list() + + if(gear && gear.len) + for(var/gear_name in gear) + if(gear_datums[gear_name]) + var/datum/gear/G = gear_datums[gear_name] + total_cost += G.cost + + var/datum/gear/C = gear_datums[choice] + total_cost += C.cost + if(C && total_cost <= MAX_GEAR_COST) + gear += choice + user << "\blue Added [choice] for [C.cost] points ([MAX_GEAR_COST - total_cost] points remaining)." + else + user << "\red That item will exceed the maximum loadout cost of [MAX_GEAR_COST] points." + + else if(href_list["task"] == "remove") + + if(isnull(gear) || !islist(gear)) + gear = list() + if(!gear.len) + return + + var/choice = input(user, "Select gear to remove: ") as null|anything in gear + if(!choice) + return + + for(var/gear_name in gear) + if(gear_name == choice) + gear -= gear_name + break + else if(href_list["preference"] == "language") + if(href_list["remove"]) + var/index = text2num(href_list["remove"]) + alternate_languages.Cut(index, index+1) + if(href_list["add"]) + var/datum/species/S = all_species[species] + if(alternate_languages.len >= S.num_alternate_languages) + alert(user, "You have already selected the maximum number of alternate languages for this species!") + else + var/list/available_languages = S.secondary_langs.Copy() + for(var/L in all_languages) + var/datum/language/lang = all_languages[L] + if(!(lang.flags & RESTRICTED) && (!config.usealienwhitelist || is_alien_whitelisted(user, L) || !(lang.flags & WHITELISTED))) + available_languages |= L + + // make sure we don't let them waste slots on the default languages + available_languages -= S.language + available_languages -= S.default_language + available_languages -= alternate_languages + + if(!available_languages.len) + alert(user, "There are no additional languages available to select.") + else + var/new_lang = input("Select an additional language", "Character Generation", null) as null|anything in available_languages + if(new_lang) + alternate_languages |= new_lang + + else if(href_list["preference"] == "language_prefix") + if(href_list["add"]) + var/char + var/keys[0] + do + char = input("Enter a single special character.\nYou may re-select the same characters.\nThe following characters are already in use by radio: ; : .\nThe following characters are already in use by special say commands: ! * ^", "Enter Character - [3 - keys.len] remaining") as null|text + if(char) + if(length(char) > 1) + alert("Only single characters allowed.", "Error", "Ok") + else if(char in list(";", ":", ".")) + alert("Radio character. Rejected.", "Error", "Ok") + else if(char in list("!","*", "^")) + alert("Say character. Rejected.", "Error", "Ok") + else if(contains_az09(char)) + alert("Non-special character. Rejected.", "Error", "Ok") + else + keys.Add(char) + while(char && keys.len < 3) + + if(keys.len == 3) + language_prefixes = keys + else if(href_list["reset"]) + language_prefixes = config.language_prefixes.Copy() + + switch(href_list["task"]) + if("change") + if(href_list["preference"] == "species") + // Actual whitelist checks are handled elsewhere, this is just for accessing the preview window. + var/choice = input("Which species would you like to look at?") as null|anything in playable_species + if(!choice) return + species_preview = choice + SetSpecies(user) + alternate_languages = list() // Reset their alternate languages. Todo: attempt to just fix it instead? + + if("random") + switch(href_list["preference"]) + if("name") + real_name = random_name(gender,species) + if("age") + age = rand(AGE_MIN, AGE_MAX) + if("hair") + r_hair = rand(0,255) + g_hair = rand(0,255) + b_hair = rand(0,255) + if("h_style") + h_style = random_hair_style(gender, species) + if("facial") + r_facial = rand(0,255) + g_facial = rand(0,255) + b_facial = rand(0,255) + if("f_style") + f_style = random_facial_hair_style(gender, species) + if("underwear") + var/r = pick(underwear_m) + underwear = underwear_m[r] + ShowChoices(user) + if("undershirt") + var/r = pick(undershirt_t) + undershirt = undershirt_t[r] + ShowChoices(user) + if("socks") + var/r = pick(socks_t) + socks = socks_t[r] + ShowChoices(user) + if("eyes") + r_eyes = rand(0,255) + g_eyes = rand(0,255) + b_eyes = rand(0,255) + if("s_tone") + s_tone = random_skin_tone() + if("s_color") + r_skin = rand(0,255) + g_skin = rand(0,255) + b_skin = rand(0,255) + if("bag") + backbag = rand(1,4) + /*if("skin_style") + h_style = random_skin_style(gender)*/ + if("all") + randomize_appearance_for() //no params needed + if("input") + switch(href_list["preference"]) + if("name") + var/raw_name = input(user, "Choose your character's name:", "Character Preference") as text|null + if (!isnull(raw_name)) // Check to ensure that the user entered text (rather than cancel.) + var/new_name = sanitizeName(raw_name) + if(new_name) + real_name = new_name + else + user << "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and ." + + if("age") + var/new_age = input(user, "Choose your character's age:\n([AGE_MIN]-[AGE_MAX])", "Character Preference") as num|null + if(new_age) + age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN) + + if("species") + user << browse(null, "window=species") + var/prev_species = species + species = href_list["newspecies"] + if(prev_species != species) + //grab one of the valid hair styles for the newly chosen species + var/list/valid_hairstyles = list() + for(var/hairstyle in hair_styles_list) + var/datum/sprite_accessory/S = hair_styles_list[hairstyle] + if(gender == MALE && S.gender == FEMALE) + continue + if(gender == FEMALE && S.gender == MALE) + continue + if( !(species in S.species_allowed)) + continue + valid_hairstyles[hairstyle] = hair_styles_list[hairstyle] + + if(valid_hairstyles.len) + h_style = pick(valid_hairstyles) + else + //this shouldn't happen + h_style = hair_styles_list["Bald"] + + //grab one of the valid facial hair styles for the newly chosen species + var/list/valid_facialhairstyles = list() + for(var/facialhairstyle in facial_hair_styles_list) + var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] + if(gender == MALE && S.gender == FEMALE) + continue + if(gender == FEMALE && S.gender == MALE) + continue + if( !(species in S.species_allowed)) + continue + + valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle] + + if(valid_facialhairstyles.len) + f_style = pick(valid_facialhairstyles) + else + //this shouldn't happen + f_style = facial_hair_styles_list["Shaved"] + + //reset hair colour and skin colour + r_hair = 0//hex2num(copytext(new_hair, 2, 4)) + g_hair = 0//hex2num(copytext(new_hair, 4, 6)) + b_hair = 0//hex2num(copytext(new_hair, 6, 8)) + + s_tone = 0 + + if("metadata") + var/new_metadata = input(user, "Enter any information you'd like others to see, such as Roleplay-preferences:", "Game Preference" , metadata) as message|null + if(new_metadata) + metadata = sanitize(new_metadata) + + if("b_type") + var/new_b_type = input(user, "Choose your character's blood-type:", "Character Preference") as null|anything in list( "A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-" ) + if(new_b_type) + b_type = new_b_type + + if("hair") + var/datum/species/S = all_species[species] + if(S && (S.appearance_flags & HAS_HAIR_COLOR)) + var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference", rgb(r_hair, g_hair, b_hair)) as color|null + if(new_hair) + r_hair = hex2num(copytext(new_hair, 2, 4)) + g_hair = hex2num(copytext(new_hair, 4, 6)) + b_hair = hex2num(copytext(new_hair, 6, 8)) + + if("h_style") + var/list/valid_hairstyles = list() + for(var/hairstyle in hair_styles_list) + var/datum/sprite_accessory/S = hair_styles_list[hairstyle] + if( !(species in S.species_allowed)) + continue + + valid_hairstyles[hairstyle] = hair_styles_list[hairstyle] + + var/new_h_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in valid_hairstyles + if(new_h_style) + h_style = new_h_style + + if("facial") + var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference", rgb(r_facial, g_facial, b_facial)) as color|null + if(new_facial) + r_facial = hex2num(copytext(new_facial, 2, 4)) + g_facial = hex2num(copytext(new_facial, 4, 6)) + b_facial = hex2num(copytext(new_facial, 6, 8)) + + if("f_style") + var/list/valid_facialhairstyles = list() + for(var/facialhairstyle in facial_hair_styles_list) + var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] + if(gender == MALE && S.gender == FEMALE) + continue + if(gender == FEMALE && S.gender == MALE) + continue + if( !(species in S.species_allowed)) + continue + + valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle] + + var/new_f_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in valid_facialhairstyles + if(new_f_style) + f_style = new_f_style + + if("underwear") + var/list/underwear_options + if(gender == MALE) + underwear_options = underwear_m + else + underwear_options = underwear_f + + var/new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in underwear_options + if(new_underwear) + underwear = underwear_options[new_underwear] + ShowChoices(user) + + if("undershirt") + var/list/undershirt_options + undershirt_options = undershirt_t + + var/new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in undershirt_options + if (new_undershirt) + undershirt = undershirt_options[new_undershirt] + ShowChoices(user) + + if("socks") + var/list/socks_options + socks_options = socks_t + + var/new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in socks_options + if (new_socks) + socks = socks_options[new_socks] + ShowChoices(user) + + if("eyes") + var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference", rgb(r_eyes, g_eyes, b_eyes)) as color|null + if(new_eyes) + r_eyes = hex2num(copytext(new_eyes, 2, 4)) + g_eyes = hex2num(copytext(new_eyes, 4, 6)) + b_eyes = hex2num(copytext(new_eyes, 6, 8)) + + if("s_tone") + if(species != "Human") + return + var/new_s_tone = input(user, "Choose your character's skin-tone:\n(Light 1 - 220 Dark)", "Character Preference") as num|null + if(new_s_tone) + s_tone = 35 - max(min( round(new_s_tone), 220),1) + + if("skin") + var/datum/species/S = all_species[species] + if(S && (S.appearance_flags & HAS_SKIN_COLOR)) + var/new_skin = input(user, "Choose your character's skin colour: ", "Character Preference", rgb(r_skin, g_skin, b_skin)) as color|null + if(new_skin) + r_skin = hex2num(copytext(new_skin, 2, 4)) + g_skin = hex2num(copytext(new_skin, 4, 6)) + b_skin = hex2num(copytext(new_skin, 6, 8)) + + if("ooccolor") + var/new_ooccolor = input(user, "Choose your OOC colour:", "Game Preference") as color|null + if(new_ooccolor) + ooccolor = new_ooccolor + + if("bag") + var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference") as null|anything in backbaglist + if(new_backbag) + backbag = backbaglist.Find(new_backbag) + + if("nt_relation") + var/new_relation = input(user, "Choose your relation to NT. Note that this represents what others can find out about your character by researching your background, not what your character actually thinks.", "Character Preference") as null|anything in COMPANY_ALIGNMENTS + if(new_relation) + nanotrasen_relation = new_relation + + if("disabilities") + if(text2num(href_list["disabilities"]) >= -1) + if(text2num(href_list["disabilities"]) >= 0) + disabilities ^= (1<= 50)) return + UI_style_alpha = UI_style_alpha_new + + if("be_special") + var/num = text2num(href_list["num"]) + be_special ^= (1<> ooccolor + S["lastchangelog"] >> lastchangelog + S["UI_style"] >> UI_style + S["be_special"] >> be_special + S["default_slot"] >> default_slot + S["toggles"] >> toggles + S["UI_style_color"] >> UI_style_color + S["UI_style_alpha"] >> UI_style_alpha + + //Sanitize + ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor)) + lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog)) + UI_style = sanitize_inlist(UI_style, all_ui_styles, initial(UI_style)) + be_special = sanitize_integer(be_special, 0, 65535, initial(be_special)) + default_slot = sanitize_integer(default_slot, 1, config.character_slots, initial(default_slot)) + toggles = sanitize_integer(toggles, 0, 65535, initial(toggles)) + UI_style_color = sanitize_hexcolor(UI_style_color, initial(UI_style_color)) + UI_style_alpha = sanitize_integer(UI_style_alpha, 0, 255, initial(UI_style_alpha)) + return 1 /datum/preferences/proc/save_preferences() @@ -57,7 +76,15 @@ S.cd = "/" S["version"] << savefile_version - player_setup.save_preferences(S) + + //general preferences + S["ooccolor"] << ooccolor + S["lastchangelog"] << lastchangelog + S["UI_style"] << UI_style + S["be_special"] << be_special + S["default_slot"] << default_slot + S["toggles"] << toggles + return 1 /datum/preferences/proc/load_character(slot) @@ -73,7 +100,184 @@ S["default_slot"] << slot S.cd = "/character[slot]" - player_setup.load_character(S) + //Character + S["OOC_Notes"] >> metadata + S["real_name"] >> real_name + S["name_is_always_random"] >> be_random_name + S["gender"] >> gender + S["age"] >> age + S["species"] >> species + S["spawnpoint"] >> spawnpoint + + S["language"] >> alternate_languages + S["language_prefixes"] >> language_prefixes + if(isnull(alternate_languages)) + alternate_languages = list() + if(isnull(language_prefixes) || !language_prefixes.len) + language_prefixes = config.language_prefixes.Copy() + if(!islist(alternate_languages)) + if(client) + // Warn them that we (probably) just broke their languages + client << "Your current character slot's languages list has been updated from an old version, and may not be what you expect." + + if(alternate_languages in all_languages) + alternate_languages = list(alternate_languages) + else + alternate_languages = list() + + // try to give them their species language + var/datum/species/SP = all_species[species] + if(SP) + alternate_languages |= SP.language + alternate_languages |= SP.default_language + + // remove the Galcom that most races have as default_language + alternate_languages -= "Galactic Common" + + //colors to be consolidated into hex strings (requires some work with dna code) + S["hair_red"] >> r_hair + S["hair_green"] >> g_hair + S["hair_blue"] >> b_hair + S["facial_red"] >> r_facial + S["facial_green"] >> g_facial + S["facial_blue"] >> b_facial + S["skin_tone"] >> s_tone + S["skin_red"] >> r_skin + S["skin_green"] >> g_skin + S["skin_blue"] >> b_skin + S["hair_style_name"] >> h_style + S["facial_style_name"] >> f_style + S["eyes_red"] >> r_eyes + S["eyes_green"] >> g_eyes + S["eyes_blue"] >> b_eyes + S["underwear"] >> underwear + S["undershirt"] >> undershirt + S["socks"] >> socks + S["backbag"] >> backbag + S["b_type"] >> b_type + + //Jobs + S["alternate_option"] >> alternate_option + S["job_civilian_high"] >> job_civilian_high + S["job_civilian_med"] >> job_civilian_med + S["job_civilian_low"] >> job_civilian_low + S["job_medsci_high"] >> job_medsci_high + S["job_medsci_med"] >> job_medsci_med + S["job_medsci_low"] >> job_medsci_low + S["job_engsec_high"] >> job_engsec_high + S["job_engsec_med"] >> job_engsec_med + S["job_engsec_low"] >> job_engsec_low + + //Flavour Text + S["flavor_texts_general"] >> flavor_texts["general"] + S["flavor_texts_head"] >> flavor_texts["head"] + S["flavor_texts_face"] >> flavor_texts["face"] + S["flavor_texts_eyes"] >> flavor_texts["eyes"] + S["flavor_texts_torso"] >> flavor_texts["torso"] + S["flavor_texts_arms"] >> flavor_texts["arms"] + S["flavor_texts_hands"] >> flavor_texts["hands"] + S["flavor_texts_legs"] >> flavor_texts["legs"] + S["flavor_texts_feet"] >> flavor_texts["feet"] + + //Flavour text for robots. + S["flavour_texts_robot_Default"] >> flavour_texts_robot["Default"] + for(var/module in robot_module_types) + S["flavour_texts_robot_[module]"] >> flavour_texts_robot[module] + + //Miscellaneous + S["med_record"] >> med_record + S["sec_record"] >> sec_record + S["gen_record"] >> gen_record + S["be_special"] >> be_special + S["disabilities"] >> disabilities + S["player_alt_titles"] >> player_alt_titles + S["used_skillpoints"] >> used_skillpoints + S["skills"] >> skills + S["skill_specialization"] >> skill_specialization + S["organ_data"] >> organ_data + S["rlimb_data"] >> rlimb_data + S["gear"] >> gear + S["home_system"] >> home_system + S["citizenship"] >> citizenship + S["faction"] >> faction + S["religion"] >> religion + + S["nanotrasen_relation"] >> nanotrasen_relation + //S["skin_style"] >> skin_style + + S["uplinklocation"] >> uplinklocation + S["exploit_record"] >> exploit_record + + S["UI_style_color"] << UI_style_color + S["UI_style_alpha"] << UI_style_alpha + + //Sanitize + metadata = sanitize_text(metadata, initial(metadata)) + real_name = sanitizeName(real_name) + + if(isnull(species) || !(species in playable_species)) + species = "Human" + + if(isnum(underwear)) + var/list/undies = gender == MALE ? underwear_m : underwear_f + underwear = undies[undies[underwear]] + + if(isnum(undershirt)) + undershirt = undershirt_t[undershirt_t[undershirt]] + + if(isnum(socks)) + socks = socks_t[socks_t[socks]] + + if(isnull(alternate_languages)) alternate_languages = list() + if(isnull(spawnpoint)) spawnpoint = "Arrivals Shuttle" + if(isnull(nanotrasen_relation)) nanotrasen_relation = initial(nanotrasen_relation) + if(!real_name) real_name = random_name(gender) + be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name)) + gender = sanitize_gender(gender) + age = sanitize_integer(age, AGE_MIN, AGE_MAX, initial(age)) + r_hair = sanitize_integer(r_hair, 0, 255, initial(r_hair)) + g_hair = sanitize_integer(g_hair, 0, 255, initial(g_hair)) + b_hair = sanitize_integer(b_hair, 0, 255, initial(b_hair)) + r_facial = sanitize_integer(r_facial, 0, 255, initial(r_facial)) + g_facial = sanitize_integer(g_facial, 0, 255, initial(g_facial)) + b_facial = sanitize_integer(b_facial, 0, 255, initial(b_facial)) + s_tone = sanitize_integer(s_tone, -185, 34, initial(s_tone)) + r_skin = sanitize_integer(r_skin, 0, 255, initial(r_skin)) + g_skin = sanitize_integer(g_skin, 0, 255, initial(g_skin)) + b_skin = sanitize_integer(b_skin, 0, 255, initial(b_skin)) + h_style = sanitize_inlist(h_style, hair_styles_list, initial(h_style)) + f_style = sanitize_inlist(f_style, facial_hair_styles_list, initial(f_style)) + r_eyes = sanitize_integer(r_eyes, 0, 255, initial(r_eyes)) + g_eyes = sanitize_integer(g_eyes, 0, 255, initial(g_eyes)) + b_eyes = sanitize_integer(b_eyes, 0, 255, initial(b_eyes)) + backbag = sanitize_integer(backbag, 1, backbaglist.len, initial(backbag)) + b_type = sanitize_text(b_type, initial(b_type)) + + alternate_option = sanitize_integer(alternate_option, 0, 2, initial(alternate_option)) + job_civilian_high = sanitize_integer(job_civilian_high, 0, 65535, initial(job_civilian_high)) + job_civilian_med = sanitize_integer(job_civilian_med, 0, 65535, initial(job_civilian_med)) + job_civilian_low = sanitize_integer(job_civilian_low, 0, 65535, initial(job_civilian_low)) + job_medsci_high = sanitize_integer(job_medsci_high, 0, 65535, initial(job_medsci_high)) + job_medsci_med = sanitize_integer(job_medsci_med, 0, 65535, initial(job_medsci_med)) + job_medsci_low = sanitize_integer(job_medsci_low, 0, 65535, initial(job_medsci_low)) + job_engsec_high = sanitize_integer(job_engsec_high, 0, 65535, initial(job_engsec_high)) + job_engsec_med = sanitize_integer(job_engsec_med, 0, 65535, initial(job_engsec_med)) + job_engsec_low = sanitize_integer(job_engsec_low, 0, 65535, initial(job_engsec_low)) + + if(!skills) skills = list() + if(!used_skillpoints) used_skillpoints= 0 + if(isnull(disabilities)) disabilities = 0 + if(!player_alt_titles) player_alt_titles = new() + if(!organ_data) src.organ_data = list() + if(!rlimb_data) src.rlimb_data = list() + if(!gear) src.gear = list() + //if(!skin_style) skin_style = "Default" + + if(!home_system) home_system = "Unset" + if(!citizenship) citizenship = "None" + if(!faction) faction = "None" + if(!religion) religion = "None" + return 1 /datum/preferences/proc/save_character() @@ -82,9 +286,94 @@ if(!S) return 0 S.cd = "/character[default_slot]" - player_setup.save_character(S) + //Character + S["OOC_Notes"] << metadata + S["real_name"] << real_name + S["name_is_always_random"] << be_random_name + S["gender"] << gender + S["age"] << age + S["species"] << species + S["language"] << alternate_languages + S["language_prefixes"] << language_prefixes + S["hair_red"] << r_hair + S["hair_green"] << g_hair + S["hair_blue"] << b_hair + S["facial_red"] << r_facial + S["facial_green"] << g_facial + S["facial_blue"] << b_facial + S["skin_tone"] << s_tone + S["skin_red"] << r_skin + S["skin_green"] << g_skin + S["skin_blue"] << b_skin + S["hair_style_name"] << h_style + S["facial_style_name"] << f_style + S["eyes_red"] << r_eyes + S["eyes_green"] << g_eyes + S["eyes_blue"] << b_eyes + S["underwear"] << underwear + S["undershirt"] << undershirt + S["socks"] << socks + S["backbag"] << backbag + S["b_type"] << b_type + S["spawnpoint"] << spawnpoint + + //Jobs + S["alternate_option"] << alternate_option + S["job_civilian_high"] << job_civilian_high + S["job_civilian_med"] << job_civilian_med + S["job_civilian_low"] << job_civilian_low + S["job_medsci_high"] << job_medsci_high + S["job_medsci_med"] << job_medsci_med + S["job_medsci_low"] << job_medsci_low + S["job_engsec_high"] << job_engsec_high + S["job_engsec_med"] << job_engsec_med + S["job_engsec_low"] << job_engsec_low + + //Flavour Text + S["flavor_texts_general"] << flavor_texts["general"] + S["flavor_texts_head"] << flavor_texts["head"] + S["flavor_texts_face"] << flavor_texts["face"] + S["flavor_texts_eyes"] << flavor_texts["eyes"] + S["flavor_texts_torso"] << flavor_texts["torso"] + S["flavor_texts_arms"] << flavor_texts["arms"] + S["flavor_texts_hands"] << flavor_texts["hands"] + S["flavor_texts_legs"] << flavor_texts["legs"] + S["flavor_texts_feet"] << flavor_texts["feet"] + + //Flavour text for robots. + S["flavour_texts_robot_Default"] << flavour_texts_robot["Default"] + for(var/module in robot_module_types) + S["flavour_texts_robot_[module]"] << flavour_texts_robot[module] + + //Miscellaneous + S["med_record"] << med_record + S["sec_record"] << sec_record + S["gen_record"] << gen_record + S["player_alt_titles"] << player_alt_titles + S["be_special"] << be_special + S["disabilities"] << disabilities + S["used_skillpoints"] << used_skillpoints + S["skills"] << skills + S["skill_specialization"] << skill_specialization + S["organ_data"] << organ_data + S["rlimb_data"] << rlimb_data + S["gear"] << gear + S["home_system"] << home_system + S["citizenship"] << citizenship + S["faction"] << faction + S["religion"] << religion + + S["nanotrasen_relation"] << nanotrasen_relation + //S["skin_style"] << skin_style + + S["uplinklocation"] << uplinklocation + S["exploit_record"] << exploit_record + + S["UI_style_color"] << UI_style_color + S["UI_style_alpha"] << UI_style_alpha + return 1 #undef SAVEFILE_VERSION_MAX -#undef SAVEFILE_VERSION_MIN \ No newline at end of file +#undef SAVEFILE_VERSION_MIN diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 894d2cb0a7c..a88ba411c2e 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -1,9 +1,7 @@ /obj/item/clothing name = "clothing" siemens_coefficient = 0.9 - var/flash_protection = FLASH_PROTECTION_NONE // Sets the item's level of flash protection. - var/tint = TINT_NONE // Sets the item's level of visual impairment tint. - var/list/species_restricted = null //Only these species can wear this kit. + var/list/species_restricted = null //Only these species can wear this kit. /* Sprites used when the clothing item is refit. This is done by setting icon_override. diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm index ffc504cd164..c5fadf44639 100644 --- a/code/modules/clothing/glasses/glasses.dm +++ b/code/modules/clothing/glasses/glasses.dm @@ -12,7 +12,6 @@ var/active = 1 var/activation_sound = 'sound/items/goggles_charge.ogg' var/obj/screen/overlay = null - var/obj/item/clothing/glasses/hud/hud = null // Hud glasses, if any /obj/item/clothing/glasses/attack_self(mob/user) if(toggleable) @@ -20,8 +19,6 @@ active = 0 icon_state = off_state user.update_inv_glasses() - flash_protection = FLASH_PROTECTION_NONE - tint = TINT_NONE usr << "You deactivate the optical matrix on the [src]." else active = 1 @@ -29,8 +26,6 @@ user.update_inv_glasses() if(activation_sound) usr << activation_sound - flash_protection = initial(flash_protection) - tint = initial(tint) usr << "You activate the optical matrix on the [src]." user.update_action_buttons() @@ -109,7 +104,7 @@ item_state = "glasses" prescription = 1 body_parts_covered = 0 - + /obj/item/clothing/glasses/regular/scanners name = "Scanning Goggles" desc = "A very oddly shaped pair of goggles with bits of wire poking out the sides. A soft humming sound emanates from it." @@ -141,7 +136,6 @@ icon_state = "sun" item_state = "sunglasses" darkness_view = -1 - flash_protection = FLASH_PROTECTION_MODERATE /obj/item/clothing/glasses/welding name = "welding goggles" @@ -150,8 +144,6 @@ item_state = "welding-g" action_button_name = "Flip Welding Goggles" var/up = 0 - flash_protection = FLASH_PROTECTION_MAJOR - tint = TINT_HEAVY /obj/item/clothing/glasses/welding/attack_self() toggle() @@ -168,16 +160,12 @@ flags_inv |= HIDEEYES body_parts_covered |= EYES icon_state = initial(icon_state) - flash_protection = initial(flash_protection) - tint = initial(tint) usr << "You flip \the [src] down to protect your eyes." else src.up = !src.up flags_inv &= ~HIDEEYES body_parts_covered &= ~EYES icon_state = "[initial(icon_state)]up" - flash_protection = FLASH_PROTECTION_NONE - tint = TINT_NONE usr << "You push \the [src] up out of your face." update_clothing_icon() usr.update_action_buttons() @@ -187,14 +175,13 @@ desc = "Welding goggles made from more expensive materials, strangely smells like potatoes." icon_state = "rwelding-g" item_state = "rwelding-g" - tint = TINT_MODERATE /obj/item/clothing/glasses/sunglasses/blindfold name = "blindfold" desc = "Covers the eyes, preventing sight." icon_state = "blindfold" item_state = "blindfold" - tint = TINT_BLIND + //vision_flags = BLIND // This flag is only supposed to be used if it causes permanent blindness, not temporary because of glasses /obj/item/clothing/glasses/sunglasses/prescription name = "prescription sunglasses" @@ -209,6 +196,7 @@ name = "HUDSunglasses" desc = "Sunglasses with a HUD." icon_state = "sunhud" + var/obj/item/clothing/glasses/hud/security/hud = null New() ..() @@ -228,8 +216,6 @@ origin_tech = list(TECH_MAGNET = 3) toggleable = 1 vision_flags = SEE_MOBS - see_invisible = SEE_INVISIBLE_NOLIGHTING - flash_protection = FLASH_PROTECTION_REDUCED emp_act(severity) if(istype(src.loc, /mob/living/carbon/human)) diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm index de6972ac01f..94e8cd29498 100644 --- a/code/modules/clothing/glasses/hud.dm +++ b/code/modules/clothing/glasses/hud.dm @@ -5,12 +5,10 @@ origin_tech = list(TECH_MAGNET = 3, TECH_BIO = 2) var/list/icon/current = list() //the current hud icons -/obj/item/clothing/glasses/proc/process_hud(var/mob/M) - if(hud) - hud.process_hud(M) + proc + process_hud(var/mob/M) return + -/obj/item/clothing/glasses/hud/process_hud(var/mob/M) - return /obj/item/clothing/glasses/hud/health name = "Health Scanner HUD" diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm index fa7bbae5598..42e830c4e48 100644 --- a/code/modules/clothing/head/misc_special.dm +++ b/code/modules/clothing/head/misc_special.dm @@ -28,8 +28,6 @@ siemens_coefficient = 0.9 w_class = 3 var/base_state - flash_protection = FLASH_PROTECTION_MAJOR - tint = TINT_HEAVY /obj/item/clothing/head/welding/attack_self() if(!base_state) @@ -47,15 +45,11 @@ src.up = !src.up body_parts_covered |= (EYES|FACE) flags_inv |= (HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE) - flash_protection = initial(flash_protection) - tint = initial(tint) icon_state = base_state usr << "You flip the [src] down to protect your eyes." else src.up = !src.up body_parts_covered &= ~(EYES|FACE) - flash_protection = FLASH_PROTECTION_NONE - tint = TINT_NONE flags_inv &= ~(HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE) icon_state = "[base_state]up" usr << "You push the [src] up out of your face." diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm index b011dd14bc2..ce8f89dc561 100644 --- a/code/modules/clothing/spacesuits/miscellaneous.dm +++ b/code/modules/clothing/spacesuits/miscellaneous.dm @@ -100,7 +100,7 @@ icon_state = "emergencyhelm" item_state = "emergencyhelm" desc = "A simple helmet with a built in light, smells like mothballs." - flash_protection = FLASH_PROTECTION_NONE + /obj/item/clothing/suit/space/emergency name = "Emergency Softsuit" diff --git a/code/modules/clothing/spacesuits/rig/suits/light.dm b/code/modules/clothing/spacesuits/rig/suits/light.dm index bc5c15fbb07..cf941f678e7 100644 --- a/code/modules/clothing/spacesuits/rig/suits/light.dm +++ b/code/modules/clothing/spacesuits/rig/suits/light.dm @@ -40,7 +40,7 @@ airtight = 0 seal_delay = 5 //not being vaccum-proof has an upside I guess - + helm_type = /obj/item/clothing/head/lightrig/hacker chest_type = /obj/item/clothing/suit/lightrig/hacker glove_type = /obj/item/clothing/gloves/lightrig/hacker diff --git a/code/modules/clothing/spacesuits/spacesuits.dm b/code/modules/clothing/spacesuits/spacesuits.dm index 677063d92e8..1f6ec964f4a 100644 --- a/code/modules/clothing/spacesuits/spacesuits.dm +++ b/code/modules/clothing/spacesuits/spacesuits.dm @@ -20,7 +20,6 @@ min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE siemens_coefficient = 0.9 species_restricted = list("exclude","Diona", "Xenomorph") - flash_protection = FLASH_PROTECTION_MAJOR var/obj/machinery/camera/camera var/list/camera_networks diff --git a/code/modules/clothing/under/accessories/badges.dm b/code/modules/clothing/under/accessories/badges.dm index 6b875ce5c8f..7c605bbcf39 100644 --- a/code/modules/clothing/under/accessories/badges.dm +++ b/code/modules/clothing/under/accessories/badges.dm @@ -38,8 +38,6 @@ /obj/item/clothing/accessory/badge/attack(mob/living/carbon/human/M, mob/living/user) if(isliving(user)) user.visible_message("[user] invades [M]'s personal space, thrusting [src] into their face insistently.","You invade [M]'s personal space, thrusting [src] into their face insistently.") - user.do_attack_animation(M) - user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) //to prevent spam //.Holobadges. /obj/item/clothing/accessory/badge/holo diff --git a/code/modules/events/blob.dm b/code/modules/events/blob.dm index 7ca66a8260a..bc1888f14df 100644 --- a/code/modules/events/blob.dm +++ b/code/modules/events/blob.dm @@ -1,5 +1,6 @@ /datum/event/blob announceWhen = 12 + endWhen = 120 var/obj/effect/blob/core/Blob @@ -7,13 +8,10 @@ level_seven_announcement() /datum/event/blob/start() - var/turf/T = pick_area_turf(/area/maintenance, list(/proc/is_station_turf, /proc/not_turf_contains_dense_objects)) + var/turf/T = pick(blobstart) if(!T) - log_and_message_admins("Blob failed to find a viable turf.") kill() return - - log_and_message_admins_with_location("Event: Blob spawned at \the [get_area(T)] ([T.x],[T.y],[T.z])", T.x, T.y, T.z) Blob = new /obj/effect/blob/core(T) for(var/i = 1; i < rand(3, 4), i++) Blob.process() diff --git a/code/modules/holodeck/HolodeckControl.dm b/code/modules/holodeck/HolodeckControl.dm index 2e62403432d..4c0d0a755e6 100644 --- a/code/modules/holodeck/HolodeckControl.dm +++ b/code/modules/holodeck/HolodeckControl.dm @@ -6,13 +6,10 @@ use_power = 1 active_power_usage = 8000 //8kW for the scenery + 500W per holoitem - - circuit = /obj/item/weapon/circuitboard/holodeckcontrol - var/item_power_usage = 500 var/area/linkedholodeck = null - var/linkedholodeck_area + var/area/target = null var/active = 0 var/list/holographic_objs = list() var/list/holographic_mobs = list() @@ -21,39 +18,34 @@ var/mob/last_to_emag = null var/last_change = 0 var/last_gravity_change = 0 - var/list/supported_programs - var/list/restricted_programs - -/obj/machinery/computer/HolodeckControl/New() - ..() - linkedholodeck = locate(linkedholodeck_area) - supported_programs = list() - restricted_programs = list() + var/list/supported_programs = list( \ + "Empty Court" = "emptycourt", \ + "Basketball Court" = "basketball", \ + "Thunderdome Court" = "thunderdomecourt", \ + "Boxing Ring"="boxingcourt", \ + "Beach" = "beach", \ + "Desert" = "desert", \ + "Space" = "space", \ + "Picnic Area" = "picnicarea", \ + "Snow Field" = "snowfield", \ + "Theatre" = "theatre", \ + "Meeting Hall" = "meetinghall", \ + "Courtroom" = "courtroom" \ + ) + var/list/restricted_programs = list("Atmospheric Burn Simulation" = "burntest", "Wildlife Simulation" = "wildlifecarp") /obj/machinery/computer/HolodeckControl/attack_ai(var/mob/user as mob) return src.attack_hand(user) /obj/machinery/computer/HolodeckControl/attack_hand(var/mob/user as mob) + if(..()) - return 1 + return user.set_machine(src) var/dat dat += "Holodeck Control System
" dat += "
Current Loaded Programs:
" - - if(!linkedholodeck) - dat += "Warning: Unable to locate holodeck.
" - user << browse(dat, "window=computer;size=400x500") - onclose(user, "computer") - return - - if(!supported_programs.len) - dat += "Warning: No supported holo-programs loaded.
" - user << browse(dat, "window=computer;size=400x500") - onclose(user, "computer") - return - for(var/prog in supported_programs) dat += "([prog])
" @@ -91,8 +83,10 @@ user << browse(dat, "window=computer;size=400x500") onclose(user, "computer") + return + /obj/machinery/computer/HolodeckControl/Topic(href, href_list) if(..()) return 1 @@ -138,9 +132,8 @@ user << "Warning. Automatic shutoff and derezing protocols have been corrupted. Please call [company_name] maintenance and do not use the simulator." log_game("[key_name(usr)] emagged the Holodeck Control Computer") return 1 - src.updateUsrDialog() - else - ..() + src.updateUsrDialog() + return /obj/machinery/computer/HolodeckControl/proc/update_projections() if (safety_disabled) @@ -157,6 +150,10 @@ if (last_to_emag) C.friends = list(last_to_emag) +/obj/machinery/computer/HolodeckControl/New() + ..() + linkedholodeck = locate(/area/holodeck/alphadeck) + //This could all be done better, but it works for now. /obj/machinery/computer/HolodeckControl/Destroy() emergencyShutdown() @@ -336,28 +333,3 @@ active = 0 use_power = 1 - -/obj/machinery/computer/HolodeckControl/Exodus - linkedholodeck_area = /area/holodeck/alphadeck - -/obj/machinery/computer/HolodeckControl/Exodus/New() - ..() - supported_programs = list( - "Empty Court" = "emptycourt", - "Basketball Court" = "basketball", - "Thunderdome Court" = "thunderdomecourt", - "Boxing Ring" = "boxingcourt", - "Beach" = "beach", - "Desert" = "desert", - "Space" = "space", - "Picnic Area" = "picnicarea", - "Snow Field" = "snowfield", - "Theatre" = "theatre", - "Meeting Hall" = "meetinghall", - "Courtroom" = "courtroom" - ) - - restricted_programs = list( - "Atmospheric Burn Simulation" = "burntest", - "Wildlife Simulation" = "wildlifecarp" - ) diff --git a/code/modules/holodeck/HolodeckObjects.dm b/code/modules/holodeck/HolodeckObjects.dm index f9536420e26..bc0f1a376c9 100644 --- a/code/modules/holodeck/HolodeckObjects.dm +++ b/code/modules/holodeck/HolodeckObjects.dm @@ -263,6 +263,9 @@ return 1 return 0 +/obj/item/weapon/holo/esword/attack(target as mob, mob/user as mob) + ..() + /obj/item/weapon/holo/esword/New() item_color = pick("red","blue","green","purple") diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 92396e7752e..5433361bbdc 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -234,22 +234,66 @@ return ..() -/obj/item/weapon/reagent_containers/food/snacks/grown/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) - . = ..() - - if(seed && seed.get_trait(TRAIT_STINGS)) - if(!reagents || reagents.total_volume <= 0) - return - reagents.remove_any(rand(1,3)) - seed.thrown_at(src, target) - sleep(-1) - if(!src) - return - if(prob(35)) - if(user) - user << "\The [src] has fallen to bits." - user.drop_from_inventory(src) - qdel(src) +/obj/item/weapon/reagent_containers/food/snacks/grown/attack(var/mob/living/carbon/M, var/mob/user, var/def_zone) + if(user == M) + return ..() + + if(user.a_intent == I_HURT) + + // This is being copypasted here because reagent_containers (WHY DOES FOOD DESCEND FROM THAT) overrides it completely. + // TODO: refactor all food paths to be less horrible and difficult to work with in this respect. ~Z + if(!istype(M) || (can_operate(M) && do_surgery(M,user,src))) return 0 + + user.lastattacked = M + M.lastattacker = user + user.attack_log += "\[[time_stamp()]\] Attacked [M.name] ([M.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" + M.attack_log += "\[[time_stamp()]\] Attacked by [user.name] ([user.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" + msg_admin_attack("[key_name(user)] attacked [key_name(M)] with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" ) + + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/hit = H.attacked_by(src, user, def_zone) + if(hit && hitsound) + playsound(loc, hitsound, 50, 1, -1) + return hit + else + if(attack_verb.len) + user.visible_message("[M] has been [pick(attack_verb)] with [src] by [user]!") + else + user.visible_message("[M] has been attacked with [src] by [user]!") + + if (hitsound) + playsound(loc, hitsound, 50, 1, -1) + switch(damtype) + if("brute") + M.take_organ_damage(force) + if(prob(33)) + var/turf/simulated/location = get_turf(M) + if(istype(location)) location.add_blood_floor(M) + if("fire") + if (!(COLD_RESISTANCE in M.mutations)) + M.take_organ_damage(0, force) + M.updatehealth() + + if(seed && seed.get_trait(TRAIT_STINGS)) + if(!reagents || reagents.total_volume <= 0) + return + reagents.remove_any(rand(1,3)) + seed.thrown_at(src,M) + sleep(-1) + if(!src) + return + if(prob(35)) + if(user) + user << "\The [src] has fallen to bits." + user.drop_from_inventory(src) + qdel(src) + + add_fingerprint(user) + return 1 + + else + ..() /obj/item/weapon/reagent_containers/food/snacks/grown/attack_self(mob/user as mob) diff --git a/code/modules/hydroponics/spreading/spreading.dm b/code/modules/hydroponics/spreading/spreading.dm index 0faf957787f..e8f2cfa9189 100644 --- a/code/modules/hydroponics/spreading/spreading.dm +++ b/code/modules/hydroponics/spreading/spreading.dm @@ -3,8 +3,15 @@ /proc/spacevine_infestation(var/potency_min=70, var/potency_max=100, var/maturation_min=5, var/maturation_max=15) spawn() //to stop the secrets panel hanging - var/turf/T = pick_area_turf(/area/hallway, list(/proc/is_station_turf, /proc/not_turf_contains_dense_objects)) - if(T) + var/list/turf/simulated/floor/turfs = list() //list of all the empty floor turfs in the hallway areas + for(var/areapath in typesof(/area/hallway)) + var/area/A = locate(areapath) + for(var/turf/simulated/floor/F in A.contents) + if(turf_clear(F)) + turfs += F + + if(turfs.len) //Pick a turf to spawn at if we can + var/turf/simulated/floor/T = pick(turfs) var/datum/seed/seed = plant_controller.create_random_seed(1) seed.set_trait(TRAIT_SPREAD,2) // So it will function properly as vines. seed.set_trait(TRAIT_POTENCY,rand(potency_min, potency_max)) // 70-100 potency will help guarantee a wide spread and powerful effects. @@ -16,9 +23,9 @@ vine.mature_time = 0 vine.process() - log_and_message_admins_with_location("Event: Spacevines spawned at [T.loc] ([T.x],[T.y],[T.z])", T.x, T.y, T.z) + message_admins("Event: Spacevines spawned at [T.loc] ([T.x],[T.y],[T.z])") return - log_and_message_admins("Event: Spacevines failed to find a viable turf.") + message_admins("Event: Spacevines failed to find a viable turf.") /obj/effect/dead_plant anchored = 1 @@ -125,7 +132,7 @@ update_icon() plant_controller.add_plant(src) // Some plants eat through plating. - if(islist(seed.chems) && !isnull(seed.chems["pacid"])) + if(!isnull(seed.chems["pacid"])) var/turf/T = get_turf(src) T.ex_act(prob(80) ? 3 : 2) @@ -181,12 +188,12 @@ icon_state = "[seed.get_trait(TRAIT_PLANT_ICON)]-[growth]" if(growth>2 && growth == max_growth) - layer = (seed && seed.force_layer) ? seed.force_layer : 5 + layer = 5 opacity = 1 - if(islist(seed.chems) && !isnull(seed.chems["woodpulp"])) + if(!isnull(seed.chems["woodpulp"])) density = 1 else - layer = (seed && seed.force_layer) ? seed.force_layer : 5 + layer = 3 density = 0 /obj/effect/plant/proc/calc_dir() diff --git a/code/modules/hydroponics/trays/tray_reagents.dm b/code/modules/hydroponics/trays/tray_reagents.dm index d89873901fc..7583deae416 100644 --- a/code/modules/hydroponics/trays/tray_reagents.dm +++ b/code/modules/hydroponics/trays/tray_reagents.dm @@ -48,6 +48,20 @@ toxicity = 8 pest_kill_str = 7 +/obj/item/weapon/material/minihoe // -- Numbers + name = "mini hoe" + desc = "It's used for removing weeds or scratching your back." + icon = 'icons/obj/weapons.dmi' + icon_state = "hoe" + item_state = "hoe" + flags = CONDUCT | NOBLUDGEON + force = 5.0 + throwforce = 7.0 + w_class = 2.0 + matter = list(DEFAULT_WALL_MATERIAL = 50) + attack_verb = list("slashed", "sliced", "cut", "clawed") + + // ************************************* // Weedkiller defines for hydroponics // ************************************* diff --git a/code/modules/library/lib_items.dm b/code/modules/library/lib_items.dm index f51c2ad9a6a..44cde40ced2 100644 --- a/code/modules/library/lib_items.dm +++ b/code/modules/library/lib_items.dm @@ -256,7 +256,6 @@ user.visible_message("You open up the book and show it to [M]. ", \ " [user] opens up a book and shows it to [M]. ") M << browse("Penned by [author].
" + "[dat]", "window=book") - user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) //to prevent spam /* diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm index a4379cf871c..fdb20ab1191 100644 --- a/code/modules/materials/material_sheets.dm +++ b/code/modules/materials/material_sheets.dm @@ -65,10 +65,9 @@ var/obj/item/stack/material/M = S if(!istype(M) || material.name != M.material.name) return 0 - var/transfer = ..(S,tamount,1) + ..(S,tamount,1) if(src) update_strings() if(M) M.update_strings() - return transfer /obj/item/stack/material/attack_self(var/mob/user) if(!material.build_windows(user, src)) @@ -208,4 +207,4 @@ desc = "This sheet is special platinum-glass alloy designed to withstand large temperatures. It is reinforced with few rods." singular_name = "reinforced borosilicate glass sheet" icon_state = "sheet-phoronrglass" - default_type = "reinforced borosilicate glass" + default_type = "reinforced borosilicate glass" \ No newline at end of file diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm index 158c9ef8760..71a669ab666 100644 --- a/code/modules/materials/materials.dm +++ b/code/modules/materials/materials.dm @@ -127,6 +127,8 @@ var/list/name_to_material var/obj/item/stack/S = new rod_product(get_turf(user)) S.add_fingerprint(user) S.add_to_stacks(user) + if(!(user.l_hand && user.r_hand)) + user.put_in_hands(S) /material/proc/build_wired_product(var/mob/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack) if(!wire_product) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 83526bfc03e..5d3915c7fd8 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -91,14 +91,11 @@ var/global/list/image/ghost_sightless_images = list() //this is a list of images /mob/dead/observer/Topic(href, href_list) if (href_list["track"]) - if(istype(href_list["track"],/mob)) - var/mob/target = locate(href_list["track"]) in mob_list - if(target) - ManualFollow(target) - else - var/atom/target = locate(href_list["track"]) - if(istype(target)) - ManualFollow(target) + var/mob/target = locate(href_list["track"]) in mob_list + if(target) + ManualFollow(target) + + /mob/dead/attackby(obj/item/W, mob/user) if(istype(W,/obj/item/weapon/book/tome)) @@ -152,7 +149,7 @@ Works together with spawning an observer, noted above. if(key) var/mob/dead/observer/ghost = new(src) //Transfer safety to observer spawning proc. ghost.can_reenter_corpse = can_reenter_corpse - ghost.timeofdeath = src.stat == DEAD ? src.timeofdeath : world.time + ghost.timeofdeath = src.timeofdeath //BS12 EDIT ghost.key = key if(ghost.client && !ghost.client.holder && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed. ghost.verbs -= /mob/dead/observer/verb/toggle_antagHUD // Poor guys, don't know what they are missing! @@ -323,7 +320,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(following && following == target) return following = target - src << "Now following \the [target]" + src << "Now following [target]" if(ismob(target)) forceMove(get_turf(target)) var/mob/M = target diff --git a/code/modules/mob/language/language.dm b/code/modules/mob/language/language.dm index b511fb432b4..c42f76623c4 100644 --- a/code/modules/mob/language/language.dm +++ b/code/modules/mob/language/language.dm @@ -212,10 +212,4 @@ else return ..() -/proc/transfer_languages(var/mob/source, var/mob/target, var/except_flags) - for(var/datum/language/L in source.languages) - if(L.flags & except_flags) - continue - target.add_language(L.name) - #undef SCRAMBLE_CACHE_LEN diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm index c60a4503cbf..4505c666fdd 100644 --- a/code/modules/mob/living/bot/bot.dm +++ b/code/modules/mob/living/bot/bot.dm @@ -123,3 +123,5 @@ /mob/living/bot/proc/explode() qdel(src) +/mob/living/bot/attack_throat() + return diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm index c67249dfe5b..548eee230b9 100644 --- a/code/modules/mob/living/carbon/alien/larva/larva.dm +++ b/code/modules/mob/living/carbon/alien/larva/larva.dm @@ -11,5 +11,4 @@ /mob/living/carbon/alien/larva/New() ..() add_language("Xenomorph") //Bonus language. - internal_organs |= new /obj/item/organ/xenos/hivenode(src) - create_reagents(100) \ No newline at end of file + internal_organs |= new /obj/item/organ/xenos/hivenode(src) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/larva/life.dm b/code/modules/mob/living/carbon/alien/larva/life.dm index 5ca32e24d0e..8d40ef9d5a5 100644 --- a/code/modules/mob/living/carbon/alien/larva/life.dm +++ b/code/modules/mob/living/carbon/alien/larva/life.dm @@ -1,34 +1,12 @@ -#define MIN_LARVA_BLOOD_DRINK 0.5 - //Larvae regenerate health and nutrition from plasma and alien weeds. /mob/living/carbon/alien/larva/handle_environment(var/datum/gas_mixture/environment) if(!environment) return var/turf/T = get_turf(src) - var/obj/effect/plant/plant = locate() in T - if(environment.gas["phoron"] > 0 || (plant && plant.seed.type == /datum/seed/xenomorph)) + if(environment.gas["phoron"] > 0 || (T && locate(/obj/effect/alien/weeds) in T.contents)) update_progression() adjustBruteLoss(-1) adjustFireLoss(-1) adjustToxLoss(-1) - adjustOxyLoss(-1) - -// Maybe not the -best- place but it's semiappropriate and fitting. -// Drink the blood of your host! -/mob/living/carbon/alien/larva/handle_chemicals_in_body() - if(!loc) - return - if(!istype(loc, /obj/item/weapon/holder)) - return - var/mob/living/carbon/human/M = loc.loc //ergh, replace with a flag sometime - if(!istype(M)) - return - if(M.vessel.total_volume > 0) - M.vessel.trans_to(src,min(M.vessel.total_volume,MIN_LARVA_BLOOD_DRINK)) - update_progression() - else - src << "This host is depleted of blood..." - leave_host() - -#undef MIN_LARVA_BLOOD_DRINK + adjustOxyLoss(-1) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/larva/powers.dm b/code/modules/mob/living/carbon/alien/larva/powers.dm deleted file mode 100644 index 57e3427163f..00000000000 --- a/code/modules/mob/living/carbon/alien/larva/powers.dm +++ /dev/null @@ -1,111 +0,0 @@ -/mob/living/carbon/alien/larva/proc/check_can_infest(var/mob/living/M) - if(!src) - return 0 - if(!istype(loc, /turf)) - src << "You cannot infest a target in your current position." - return 0 - if(incapacitated()) - src << "You cannot infest a target in your current state." - return 0 - if(!M) - return 1 - if(!M.lying) - src << "\The [M] is not prone." - return 0 - if(!(src.Adjacent(M))) - src << "\The [M] is not in range." - return 0 - return 1 - -/mob/living/carbon/alien/larva/verb/attach_host() - - set name = "Attach to host" - set desc = "Burrow into a prone victim and begin drinking their blood." - set category = "Abilities" - - if(!check_can_infest()) - return - - var/list/choices = list() - for(var/mob/living/carbon/human/H in view(1,src)) - if(isxenomorph(H)) - continue - if(src.Adjacent(H) && H.lying) - choices += H - - if(!choices.len) - src << "There are no viable hosts within range." - return - - var/mob/living/carbon/human/H = input(src,"Who do you wish to infest?") as null|anything in choices - - if(!H || !src || !H.lying) return - - visible_message("\The [src] begins questing blindly towards \the [H]'s warm flesh...") - - if(!do_after(src,30)) - return - - if(!check_can_infest(H)) - return - - var/obj/item/organ/external/E = pick(H.organs) - src << "You burrow deeply into \the [H]'s [E.name]!" - var/obj/item/weapon/holder/holder = new (loc) - src.loc = holder - holder.name = src.name - E.embed(holder,0,"\The [src] burrows deeply into \the [H]'s [E.name]!") - -/mob/living/carbon/alien/larva/verb/release_host() - set category = "Abilities" - set name = "Release Host" - set desc = "Release your host." - - if(incapacitated()) - src << "You cannot leave your host in your current state." - return - - if(!loc || !loc.loc) - src << "You are not inside a host." - return - - var/mob/living/carbon/human/H = loc.loc - - if(!istype(H)) - src << "You are not inside a host." - return - - src << "You begin writhing your way free of \the [H]'s flesh..." - - if(!do_after(src, 30)) - return - - if(!H || !src) - return - - leave_host() - -/mob/living/carbon/alien/larva/proc/leave_host() - if(!loc || !loc.loc) - src << "You are not inside a host." - return - var/mob/living/carbon/human/H = loc.loc - if(!istype(H)) - src << "You are not inside a host." - return - var/obj/item/weapon/holder/holder = loc - var/obj/item/organ/external/affected - if(istype(holder)) - for(var/obj/item/organ/external/organ in H.organs) //Grab the organ holding the implant. - for(var/obj/item/O in organ.implants) - if(O == holder) - affected = organ - break - affected.implants -= holder - holder.loc = get_turf(holder) - else - src.loc = get_turf(src) - if(affected) - src << "You crawl out of \the [H]'s [affected.name] and plop to the ground." - else - src << "You plop to the ground." \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/life.dm b/code/modules/mob/living/carbon/alien/life.dm index 4c400578123..429e82b3d00 100644 --- a/code/modules/mob/living/carbon/alien/life.dm +++ b/code/modules/mob/living/carbon/alien/life.dm @@ -9,7 +9,8 @@ ..() - if (stat != DEAD && can_progress()) + if (stat != DEAD) //still breathing + // GROW! update_progression() blinded = null @@ -17,10 +18,6 @@ //Status updates, death etc. update_icons() -/mob/living/carbon/alien/proc/can_progress() - return 1 - - /mob/living/carbon/alien/handle_mutations_and_radiation() // Currently both Dionaea and larvae like to eat radiation, so I'm defining the @@ -161,7 +158,7 @@ adjustFireLoss((environment.temperature - (T0C+66))/5) // Might be too high, check in testing. if (fire) fire.icon_state = "fire2" if(prob(20)) - src << "You feel a searing heat!" + src << "\red You feel a searing heat!" else if (fire) fire.icon_state = "fire0" diff --git a/code/modules/mob/living/carbon/alien/progression.dm b/code/modules/mob/living/carbon/alien/progression.dm index e9d099ea2a0..54c7f9a9692 100644 --- a/code/modules/mob/living/carbon/alien/progression.dm +++ b/code/modules/mob/living/carbon/alien/progression.dm @@ -1,7 +1,7 @@ /mob/living/carbon/alien/verb/evolve() - set name = "Moult" - set desc = "Moult your skin and become an adult." + set name = "Evolve" + set desc = "Evolve into your adult form." set category = "Abilities" if(stat != CONSCIOUS) @@ -12,11 +12,11 @@ return if(handcuffed || legcuffed) - src << "You cannot evolve when you are cuffed." + src << "\red You cannot evolve when you are cuffed." return if(amount_grown < max_grown) - src << "You are not fully grown." + src << "\red You are not fully grown." return // confirm_evolution() handles choices and other specific requirements. @@ -27,7 +27,6 @@ var/mob/living/carbon/human/adult = new adult_form(get_turf(src)) adult.set_species(new_species) show_evolution_blurb() - // TODO: drop a moulted skin. Ew. if(mind) mind.transfer_to(adult) diff --git a/code/modules/mob/living/carbon/breathe.dm b/code/modules/mob/living/carbon/breathe.dm index ba6dd3b4416..20f86d4dde0 100644 --- a/code/modules/mob/living/carbon/breathe.dm +++ b/code/modules/mob/living/carbon/breathe.dm @@ -54,7 +54,7 @@ breath = environment.remove_volume(volume_needed) handle_chemical_smoke(environment) //handle chemical smoke while we're at it - if(breath && breath.total_moles) + if(breath) //handle mask filtering if(istype(wear_mask, /obj/item/clothing/mask) && breath) var/obj/item/clothing/mask/M = wear_mask @@ -65,15 +65,13 @@ //Handle possble chem smoke effect /mob/living/carbon/proc/handle_chemical_smoke(var/datum/gas_mixture/environment) - if(species && environment.return_pressure() < species.breath_pressure/5) - return //pressure is too low to even breathe in. - if(wear_mask && (wear_mask.flags & BLOCK_GAS_SMOKE_EFFECT)) + if(wear_mask && (wear_mask.item_flags & BLOCK_GAS_SMOKE_EFFECT)) return for(var/obj/effect/effect/smoke/chem/smoke in view(1, src)) if(smoke.reagents.total_volume) - smoke.reagents.trans_to_mob(src, 5, CHEM_INGEST, copy = 1) - smoke.reagents.trans_to_mob(src, 5, CHEM_BLOOD, copy = 1) + smoke.reagents.trans_to_mob(src, 10, CHEM_INGEST, copy = 1) + //maybe check air pressure here or something to see if breathing in smoke is even possible. // I dunno, maybe the reagents enter the blood stream through the lungs? break // If they breathe in the nasty stuff once, no need to continue checking diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm deleted file mode 100644 index b4d9d1614d8..00000000000 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ /dev/null @@ -1,98 +0,0 @@ - -//Called when the mob is hit with an item in combat. -/mob/living/carbon/resolve_item_attack(obj/item/I, mob/living/user, var/effective_force, var/hit_zone) - if(check_attack_throat(I, user)) - return null - ..() - -/mob/living/carbon/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/hit_zone) - if(!effective_force || blocked >= 2) - return 0 - - //Hulk modifier - if(HULK in user.mutations) - effective_force *= 2 - - //Apply weapon damage - var/weapon_sharp = is_sharp(I) - var/weapon_edge = has_edge(I) - if(prob(getarmor(hit_zone, "melee"))) //melee armour provides a chance to turn sharp/edge weapon attacks into blunt ones - weapon_sharp = 0 - weapon_edge = 0 - - apply_damage(effective_force, I.damtype, hit_zone, blocked, sharp=weapon_sharp, edge=weapon_edge, used_weapon=I) - - //Melee weapon embedded object code. - if (I && I.damtype == BRUTE && !I.anchored && !is_robot_module(I)) - var/damage = effective_force - if (blocked) - damage /= blocked+1 - - //blunt objects should really not be embedding in things unless a huge amount of force is involved - var/embed_chance = weapon_sharp? damage/I.w_class : damage/(I.w_class*3) - var/embed_threshold = weapon_sharp? 5*I.w_class : 15*I.w_class - - //Sharp objects will always embed if they do enough damage. - if((weapon_sharp && damage > (10*I.w_class)) || (damage > embed_threshold && prob(embed_chance))) - src.embed(I, hit_zone) - - return 1 - -// Attacking someone with a weapon while they are neck-grabbed -/mob/living/carbon/proc/check_attack_throat(obj/item/W, mob/user) - if(user.a_intent == I_HURT) - for(var/obj/item/weapon/grab/G in src.grabbed_by) - if(G.assailant == user && G.state >= GRAB_NECK) - if(attack_throat(W, G, user)) - return 1 - return 0 - -// Knifing -/mob/living/carbon/proc/attack_throat(obj/item/W, obj/item/weapon/grab/G, mob/user) - - if(!W.edge || !W.force || W.damtype != BRUTE) - return 0 //unsuitable weapon - - user.visible_message("\The [user] begins to slit [src]'s throat with \the [W]!") - - user.next_move = world.time + 20 //also should prevent user from triggering this repeatedly - if(!do_after(user, 20)) - return 0 - if(!(G && G.assailant == user && G.affecting == src)) //check that we still have a grab - return 0 - - var/damage_mod = 1 - //presumably, if they are wearing a helmet that stops pressure effects, then it probably covers the throat as well - var/obj/item/clothing/head/helmet = get_equipped_item(slot_head) - if(istype(helmet) && (helmet.body_parts_covered & HEAD) && (helmet.flags & STOPPRESSUREDAMAGE)) - //we don't do an armor_check here because this is not an impact effect like a weapon swung with momentum, that either penetrates or glances off. - damage_mod = 1.0 - (helmet.armor["melee"]/100) - - var/total_damage = 0 - for(var/i in 1 to 3) - var/damage = min(W.force*1.5, 20)*damage_mod - apply_damage(damage, W.damtype, "head", 0, sharp=W.sharp, edge=W.edge) - total_damage += damage - - var/oxyloss = total_damage - if(total_damage >= 40) //threshold to make someone pass out - oxyloss = 60 // Brain lacks oxygen immediately, pass out - - adjustOxyLoss(min(oxyloss, 100 - getOxyLoss())) //don't put them over 100 oxyloss - - if(total_damage) - if(oxyloss >= 40) - user.visible_message("\The [user] slit [src]'s throat open with \the [W]!") - else - user.visible_message("\The [user] cut [src]'s neck with \the [W]!") - - if(W.hitsound) - playsound(loc, W.hitsound, 50, 1, -1) - - G.last_action = world.time - flick(G.hud.icon_state, G.hud) - - user.attack_log += "\[[time_stamp()]\] Knifed [name] ([ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])" - src.attack_log += "\[[time_stamp()]\] Got knifed by [user.name] ([user.ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])" - msg_admin_attack("[key_name(user)] knifed [key_name(src)] with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])" ) - return 1 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 11ae1407778..78129c4910f 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -654,17 +654,38 @@ ///eyecheck() ///Returns a number between -1 to 2 /mob/living/carbon/human/eyecheck() + var/number = 0 + if(!species.has_organ["eyes"]) //No eyes, can't hurt them. - return FLASH_PROTECTION_MAJOR + return 2 if(internal_organs_by_name["eyes"]) // Eyes are fucked, not a 'weak point'. var/obj/item/organ/I = internal_organs_by_name["eyes"] if(I.status & ORGAN_CUT_AWAY) - return FLASH_PROTECTION_MAJOR + return 2 else - return + return 2 - return flash_protection + if(istype(src.head, /obj/item/clothing/head/welding)) + if(!src.head:up) + number += 2 + if(istype(back, /obj/item/weapon/rig)) + var/obj/item/weapon/rig/O = back + if(O.helmet && O.helmet == head && (O.helmet.body_parts_covered & EYES)) + number += 2 + if(istype(src.head, /obj/item/clothing/head/helmet/space)) + number += 2 + if(istype(src.head, /obj/item/clothing/head/helmet/space/emergency)) + number -= 2 + if(istype(src.glasses, /obj/item/clothing/glasses/thermal)) + number -= 1 + if(istype(src.glasses, /obj/item/clothing/glasses/sunglasses)) + number += 1 + if(istype(src.glasses, /obj/item/clothing/glasses/welding)) + var/obj/item/clothing/glasses/welding/W = src.glasses + if(!W.up) + number += 2 + return number //Used by various things that knock people out by applying blunt trauma to the head. //Checks that the species has a "head" (brain containing organ) and that hit_zone refers to it. @@ -951,7 +972,7 @@ if(L && !L.is_bruised()) src.custom_pain("You feel a stabbing pain in your chest!", 1) - L.bruise() + L.damage = L.min_bruised_damage /* /mob/living/carbon/human/verb/simulate() @@ -1261,10 +1282,11 @@ if(C.body_parts_covered & FEET) feet_exposed = 0 - flavor_text = "" + flavor_text = flavor_texts["general"] + flavor_text += "\n\n" for (var/T in flavor_texts) if(flavor_texts[T] && flavor_texts[T] != "") - if((T == "general") || (T == "head" && head_exposed) || (T == "face" && face_exposed) || (T == "eyes" && eyes_exposed) || (T == "torso" && torso_exposed) || (T == "arms" && arms_exposed) || (T == "hands" && hands_exposed) || (T == "legs" && legs_exposed) || (T == "feet" && feet_exposed)) + if((T == "head" && head_exposed) || (T == "face" && face_exposed) || (T == "eyes" && eyes_exposed) || (T == "torso" && torso_exposed) || (T == "arms" && arms_exposed) || (T == "hands" && hands_exposed) || (T == "legs" && legs_exposed) || (T == "feet" && feet_exposed)) flavor_text += flavor_texts[T] flavor_text += "\n\n" if(!shrink) diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm index 0ec23c0758f..68680a432cf 100644 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ b/code/modules/mob/living/carbon/human/human_attackhand.dm @@ -296,6 +296,23 @@ updatehealth() return 1 +/mob/living/carbon/human/proc/attack_joint(var/obj/item/W, var/mob/living/user, var/def_zone) + if(!def_zone) def_zone = user.zone_sel.selecting + var/target_zone = get_zone_with_miss_chance(check_zone(def_zone), src) + + if(user == src) // Attacking yourself can't miss + target_zone = user.zone_sel.selecting + if(!target_zone) + return null + var/obj/item/organ/external/organ = get_organ(check_zone(target_zone)) + if(!organ || (organ.dislocated == 2) || (organ.dislocated == -1)) + return null + var/dislocation_str + if(prob(W.force)) + dislocation_str = "[src]'s [organ.joint] [pick("gives way","caves in","crumbles","collapses")]!" + organ.dislocate(1) + return dislocation_str + //Used to attack a joint through grabbing /mob/living/carbon/human/proc/grab_joint(var/mob/living/user, var/def_zone) var/has_grab = 0 diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 3d46417b2d7..4a25b7ce294 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -16,14 +16,14 @@ emp_act var/obj/item/organ/external/organ = get_organ() - //Shields + //Shields var/shield_check = check_shields(P.damage, P, null, def_zone, "the [P.name]") if(shield_check) if(shield_check < 0) return shield_check else P.on_hit(src, 2, def_zone) - return 2 + return 2 //Shrapnel if(P.can_embed()) @@ -145,77 +145,70 @@ emp_act O.emp_act(severity) ..() -/mob/living/carbon/human/resolve_item_attack(obj/item/I, mob/living/user, var/target_zone) - if(check_attack_throat(I, user)) - return null + +//Returns 1 if the attack hit, 0 if it missed. +/mob/living/carbon/human/proc/attacked_by(var/obj/item/I, var/mob/living/user, var/def_zone) + if(!I || !user) return 0 + + var/target_zone = def_zone? check_zone(def_zone) : get_zone_with_miss_chance(user.zone_sel.selecting, src) if(user == src) // Attacking yourself can't miss - return target_zone + target_zone = user.zone_sel.selecting + if(!target_zone) + visible_message("[user] misses [src] with \the [I]!") + return 1 - var/hit_zone = get_zone_with_miss_chance(target_zone, src) + var/obj/item/organ/external/affecting = get_organ(target_zone) - if(!hit_zone) - visible_message("\The [user] misses [src] with \the [I]!") - return null - - if(check_shields(I.force, I, user, target_zone, "the [I.name]")) - return null - - var/obj/item/organ/external/affecting = get_organ(hit_zone) if (!affecting || (affecting.status & ORGAN_DESTROYED) || affecting.is_stump()) user << "They are missing that limb!" - return null + return - return hit_zone + var/effective_force = I.force + if(user.a_intent == "disarm") effective_force = round(I.force/2) + var/hit_area = affecting.name -/mob/living/carbon/human/hit_with_weapon(obj/item/I, mob/living/user, var/effective_force, var/hit_zone) - var/obj/item/organ/external/affecting = get_organ(hit_zone) - if(!affecting) - return //should be prevented by attacked_with_item() but for sanity. - - visible_message("[src] has been [I.attack_verb.len? pick(I.attack_verb) : "attacked"] in the [affecting.name] with [I.name] by [user]!") - - var/blocked = run_armor_check(hit_zone, "melee", I.armor_penetration, "Your armor has protected your [affecting.name].", "Your armor has softened the blow to your [affecting.name].") - standard_weapon_hit_effects(I, user, effective_force, blocked, hit_zone) - - return blocked - -/mob/living/carbon/human/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/hit_zone) - var/obj/item/organ/external/affecting = get_organ(hit_zone) - if(!affecting) + if((user != src) && check_shields(effective_force, I, user, target_zone, "the [I.name]")) return 0 - // Handle striking to cripple. - if(user.a_intent == I_DISARM) - effective_force /= 2 //half the effective force - if(!..(I, effective_force, blocked, hit_zone)) - return 0 - - attack_joint(affecting, I, blocked) //but can dislocate joints - else if(!..()) - return 0 + if(istype(I,/obj/item/weapon/card/emag)) + if(!(affecting.status & ORGAN_ROBOT)) + user << "\red That limb isn't robotic." + return + if(affecting.sabotaged) + user << "\red [src]'s [affecting.name] is already sabotaged!" + else + user << "\red You sneakily slide [I] into the dataport on [src]'s [affecting.name] and short out the safeties." + var/obj/item/weapon/card/emag/emag = I + emag.uses-- + affecting.sabotaged = 1 + return 1 - if(effective_force > 10 || effective_force >= 5 && prob(33)) - forcesay(hit_appends) //forcesay checks stat already + if(I.attack_verb.len) + visible_message("\red [src] has been [pick(I.attack_verb)] in the [hit_area] with [I.name] by [user]!") + else + visible_message("\red [src] has been attacked in the [hit_area] with [I.name] by [user]!") - if((I.damtype == BRUTE || I.damtype == HALLOSS) && prob(25 + (effective_force * 2))) - if(!stat) - if(headcheck(hit_zone)) - //Harder to score a stun but if you do it lasts a bit longer - if(prob(effective_force)) - visible_message("[src] [species.knockout_message]") - apply_effect(20, PARALYZE, blocked) - else - //Easier to score a stun but lasts less time - if(prob(effective_force + 10)) - visible_message("[src] has been knocked down!") - apply_effect(6, WEAKEN, blocked) - - //Apply blood - if(!(I.flags & NOBLOODY)) - I.add_blood(src) - + var/armor = run_armor_check(affecting, "melee", I.armor_penetration, "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].") + var/weapon_sharp = is_sharp(I) + var/weapon_edge = has_edge(I) + if ((weapon_sharp || weapon_edge) && prob(getarmor(target_zone, "melee"))) + weapon_sharp = 0 + weapon_edge = 0 + + if(armor >= 2) return 0 + if(!effective_force) return 0 + var/Iforce = effective_force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords) + + apply_damage(effective_force, I.damtype, affecting, armor, sharp=weapon_sharp, edge=weapon_edge, used_weapon=I) + + var/bloody = 0 + if(((I.damtype == BRUTE) || (I.damtype == HALLOSS)) && prob(25 + (effective_force * 2))) + I.add_blood(src) //Make the weapon bloody, not the person. +// if(user.hand) user.update_inv_l_hand() //updates the attacker's overlay for the (now bloodied) weapon +// else user.update_inv_r_hand() //removed because weapons don't have on-mob blood overlays if(prob(33)) + bloody = 1 var/turf/location = loc if(istype(location, /turf/simulated)) location.add_blood(src) @@ -225,7 +218,21 @@ emp_act H.bloody_body(src) H.bloody_hands(src) - switch(hit_zone) + if(!stat) + if(headcheck(hit_area)) + //Harder to score a stun but if you do it lasts a bit longer + if(prob(effective_force)) + apply_effect(20, PARALYZE, armor) + visible_message("[src] [species.knockout_message]") + else + //Easier to score a stun but lasts less time + if(prob(effective_force + 10)) + apply_effect(6, WEAKEN, armor) + visible_message("[src] has been knocked down!") + + //Apply blood + if(bloody) + switch(hit_area) if("head") if(wear_mask) wear_mask.add_blood(src) @@ -239,27 +246,22 @@ emp_act if("chest") bloody_body(src) - return 1 + if(Iforce > 10 || Iforce >= 5 && prob(33)) + forcesay(hit_appends) //forcesay checks stat already -/mob/living/carbon/human/proc/attack_joint(var/obj/item/organ/external/organ, var/obj/item/W, var/blocked) - if(!organ || (organ.dislocated == 2) || (organ.dislocated == -1) || blocked >= 2) - return 0 - if(prob(W.force / (blocked+1))) - visible_message("[src]'s [organ.joint] [pick("gives way","caves in","crumbles","collapses")]!") - organ.dislocate(1) - return 1 - return 0 + //Melee weapon embedded object code. + if (I && I.damtype == BRUTE && !I.anchored && !is_robot_module(I)) + var/damage = effective_force + if (armor) + damage /= armor+1 -/mob/living/carbon/human/emag_act(var/remaining_charges, mob/user, var/emag_source) - var/obj/item/organ/external/affecting = get_organ(user.zone_sel.selecting) - if(!affecting || !(affecting.status & ORGAN_ROBOT)) - user << "That limb isn't robotic." - return -1 - if(affecting.sabotaged) - user << "[src]'s [affecting.name] is already sabotaged!" - return -1 - user << "You sneakily slide [emag_source] into the dataport on [src]'s [affecting.name] and short out the safeties." - affecting.sabotaged = 1 + //blunt objects should really not be embedding in things unless a huge amount of force is involved + var/embed_chance = weapon_sharp? damage/I.w_class : damage/(I.w_class*3) + var/embed_threshold = weapon_sharp? 5*I.w_class : 15*I.w_class + + //Sharp objects will always embed if they do enough damage. + if((weapon_sharp && damage > (10*I.w_class)) || (damage > embed_threshold && prob(embed_chance))) + affecting.embed(I) return 1 //this proc handles being hit by a thrown atom @@ -444,3 +446,4 @@ emp_act perm += perm_by_part[part] return perm + diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 8ea84562dd8..0ff79e2aa25 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -85,11 +85,3 @@ mob_bump_flag = HUMAN mob_push_flags = ~HEAVY mob_swap_flags = ~HEAVY - - var/flash_protection = 0 // Total level of flash protection - var/equipment_tint_total = 0 // Total level of visualy impairing items - var/equipment_darkness_modifier // Darkvision modifier from equipped items - var/equipment_vision_flags // Extra vision flags from equipped items - var/equipment_see_invis // Max see invibility level granted by equipped items - var/equipment_prescription // Eye prescription granted by equipped items - var/list/equipment_overlays = list() // Extra overlays from equipped items diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm deleted file mode 100644 index cd5ec50ac85..00000000000 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ /dev/null @@ -1,83 +0,0 @@ -#define HUMAN_EATING_NO_ISSUE 0 -#define HUMAN_EATING_NO_MOUTH 1 -#define HUMAN_EATING_BLOCKED_MOUTH 2 - -#define add_clothing_protection(A) \ - var/obj/item/clothing/C = A; \ - flash_protection += C.flash_protection; \ - equipment_tint_total += C.tint; - -/mob/living/carbon/human/can_eat(var/food, var/feedback = 1) - var/list/status = can_eat_status() - if(status[0] == HUMAN_EATING_NO_ISSUE) - return 1 - if(feedback) - if(status[0] == HUMAN_EATING_NO_MOUTH) - src << "Where do you intend to put \the [food]? You don't have a mouth!" - else if(status[0] == HUMAN_EATING_BLOCKED_MOUTH) - src << "\The [status[1]] is in the way!" - return 0 - -/mob/living/carbon/human/can_force_feed(var/feeder, var/food, var/feedback = 1) - var/list/status = can_eat_status() - if(status[0] == HUMAN_EATING_NO_ISSUE) - return 1 - if(feedback) - if(status[0] == HUMAN_EATING_NO_MOUTH) - feeder << "Where do you intend to put \the [food]? \The [src] doesn't have a mouth!" - else if(status[0] == HUMAN_EATING_BLOCKED_MOUTH) - feeder << "\The [status[1]] is in the way!" - return 0 - -/mob/living/carbon/human/proc/can_eat_status() - if(!check_has_mouth()) - return list(HUMAN_EATING_NO_MOUTH) - var/obj/item/blocked = check_mouth_coverage() - if(blocked) - return list(HUMAN_EATING_BLOCKED_MOUTH, blocked) - return list(HUMAN_EATING_NO_ISSUE) - -#undef HUMAN_EATING_NO_ISSUE -#undef HUMAN_EATING_NO_MOUTH -#undef HUMAN_EATING_BLOCKED_MOUTH - -/mob/living/carbon/human/proc/update_equipment_vision() - flash_protection = 0 - equipment_tint_total = 0 - equipment_see_invis = 0 - equipment_vision_flags = 0 - equipment_prescription = 0 - equipment_darkness_modifier = 0 - equipment_overlays.Cut() - - if(istype(src.head, /obj/item/clothing/head)) - add_clothing_protection(head) - if(istype(src.glasses, /obj/item/clothing/glasses)) - process_glasses(glasses) - if(istype(src.wear_mask, /obj/item/clothing/mask)) - add_clothing_protection(wear_mask) - if(istype(back,/obj/item/weapon/rig)) - process_rig(back) - -/mob/living/carbon/human/proc/process_glasses(var/obj/item/clothing/glasses/G) - if(G && G.active) - equipment_darkness_modifier += G.darkness_view - equipment_vision_flags |= G.vision_flags - equipment_prescription = equipment_prescription || G.prescription - if(G.overlay) - equipment_overlays |= G.overlay - if(G.see_invisible >= 0) - if(equipment_see_invis) - equipment_see_invis = min(equipment_see_invis, G.see_invisible) - else - equipment_see_invis = G.see_invisible - - add_clothing_protection(G) - G.process_hud(src) - -/mob/living/carbon/human/proc/process_rig(var/obj/item/weapon/rig/O) - if(O.helmet && O.helmet == head && (O.helmet.body_parts_covered & EYES)) - if((O.offline && O.offline_vision_restriction == 2) || (!O.offline && O.vision_restriction == 2)) - equipment_tint_total += TINT_BLIND - if(O.visor && O.visor.active && O.visor.vision && O.visor.vision.glasses && (!O.helmet || (head && O.helmet == head))) - process_glasses(O.visor.vision.glasses) diff --git a/code/modules/mob/living/carbon/human/human_powers.dm b/code/modules/mob/living/carbon/human/human_powers.dm index 1728b61008d..50f46b4bb41 100644 --- a/code/modules/mob/living/carbon/human/human_powers.dm +++ b/code/modules/mob/living/carbon/human/human_powers.dm @@ -224,14 +224,11 @@ set name = "Split" set desc = "Split your humanoid form into its constituent nymphs." set category = "Abilities" - diona_split_into_nymphs(5) // Separate proc to void argments being supplied when used as a verb -/mob/living/carbon/human/proc/diona_split_into_nymphs(var/number_of_resulting_nymphs) var/turf/T = get_turf(src) var/mob/living/carbon/alien/diona/S = new(T) S.set_dir(dir) - transfer_languages(src, S) if(mind) mind.transfer_to(S) @@ -242,18 +239,20 @@ for(var/mob/living/carbon/alien/diona/D in src) nymphs++ - D.forceMove(T) - transfer_languages(src, D, WHITELISTED|RESTRICTED) + D.loc = T D.set_dir(pick(NORTH, SOUTH, EAST, WEST)) - if(nymphs < number_of_resulting_nymphs) - for(var/i in nymphs to (number_of_resulting_nymphs - 1)) + if(nymphs < 5) + for(var/i in nymphs to 4) var/mob/M = new /mob/living/carbon/alien/diona(T) - transfer_languages(src, M, WHITELISTED|RESTRICTED) M.set_dir(pick(NORTH, SOUTH, EAST, WEST)) + for(var/obj/item/W in src) drop_from_inventory(W) visible_message("\The [src] quivers slightly, then splits apart with a wet slithering noise.") + qdel(src) + + diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 789fcf48573..b0a9c2e4303 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -41,6 +41,11 @@ if (transforming) return + //Apparently, the person who wrote this code designed it so that + //blinded get reset each cycle and then get activated later in the + //code. Very ugly. I dont care. Moving this stuff here so its easy + //to find it. + blinded = null fire_alert = 0 //Reset this here, because both breathe() and handle_environment() have a chance to set it. //TODO: seperate this out @@ -148,26 +153,6 @@ return ONE_ATMOSPHERE + pressure_difference /mob/living/carbon/human/handle_disabilities() - ..() - //Vision - var/obj/item/organ/vision - if(species.vision_organ) - vision = internal_organs_by_name[species.vision_organ] - - if(!vision) // Presumably if a species has no vision organs, they see via some other means. - eye_blind = 0 - blinded = 0 - eye_blurry = 0 - else if(vision.is_broken()) // Vision organs cut out or broken? Permablind. - eye_blind = 1 - blinded = 1 - eye_blurry = 1 - else - //blindness - if(!(sdisabilities & BLIND)) - if(equipment_tint_total >= TINT_BLIND) // Covered eyes, heal faster - eye_blurry = max(eye_blurry-2, 0) - if (disabilities & EPILEPSY) if ((prob(1) && paralysis < 1)) src << "\red You have a seizure!" @@ -217,7 +202,7 @@ emote("drool") */ - if(stat != DEAD) + if(stat != 2) var/rn = rand(0, 200) if(getBrainLoss() >= 5) if(0 <= rn && rn <= 3) @@ -357,28 +342,11 @@ internals.icon_state = "internal0" return null -/mob/living/carbon/human/get_breath_from_environment(var/volume_needed=BREATH_VOLUME) - var/datum/gas_mixture/breath = ..() - - if(breath) - //exposure to extreme pressures can rupture lungs - var/check_pressure = breath.return_pressure() - if(check_pressure < ONE_ATMOSPHERE / 5 || check_pressure > ONE_ATMOSPHERE * 5) - if(!is_lung_ruptured() && prob(5)) - rupture_lung() - - return breath /mob/living/carbon/human/handle_breath(datum/gas_mixture/breath) if(status_flags & GODMODE) return - //exposure to extreme pressures can rupture lungs - if(breath && (breath.total_moles < BREATH_MOLES / 5 || breath.total_moles > BREATH_MOLES * 5)) - if(!is_lung_ruptured() && prob(5)) - rupture_lung() - - //check if we actually need to process breath if(!breath || (breath.total_moles == 0) || suiciding) failed_last_breath = 1 if(suiciding) @@ -391,9 +359,10 @@ adjustOxyLoss(HUMAN_CRIT_MAX_OXYLOSS) oxygen_alert = max(oxygen_alert, 1) + return 0 - var/safe_pressure_min = species.breath_pressure // Minimum safe partial pressure of breathable gas in kPa + var/safe_pressure_min = 16 // Minimum safe partial pressure of breathable gas in kPa // Lung damage increases the minimum safe pressure. if(species.has_organ["lungs"]) @@ -985,11 +954,11 @@ for(var/atom/a in hallucinations) qdel(a) - if(halloss > 100) - src << "[species.halloss_message_self]" - src.visible_message("[src] [species.halloss_message].") - Paralyse(10) - setHalLoss(99) + if(halloss > 100) + src << "You're in too much pain to keep going..." + src.visible_message("[src] slumps to the ground, too weak to continue fighting.") + Paralyse(10) + setHalLoss(99) if(paralysis || sleeping) blinded = 1 @@ -1021,12 +990,49 @@ if(!E.len) embedded_flag = 0 + //Eyes + //Check rig first because it's two-check and other checks will override it. + if(istype(back,/obj/item/weapon/rig)) + var/obj/item/weapon/rig/O = back + if(O.helmet && O.helmet == head && (O.helmet.body_parts_covered & EYES)) + if((O.offline && O.offline_vision_restriction == 2) || (!O.offline && O.vision_restriction == 2)) + blinded = 1 + // Check everything else. //Periodically double-check embedded_flag if(embedded_flag && !(life_tick % 10)) if(!embedded_needs_process()) embedded_flag = 0 + //Vision + var/obj/item/organ/vision + if(species.vision_organ) + vision = internal_organs_by_name[species.vision_organ] + + if(!vision) // Presumably if a species has no vision organs, they see via some other means. + eye_blind = 0 + blinded = 0 + eye_blurry = 0 + else if(vision.is_broken()) // Vision organs cut out or broken? Permablind. + eye_blind = 1 + blinded = 1 + eye_blurry = 1 + else + //blindness + if(sdisabilities & BLIND) // Disabled-blind, doesn't get better on its own + blinded = 1 + else if(eye_blind) // Blindness, heals slowly over time + eye_blind = max(eye_blind-1,0) + blinded = 1 + else if(istype(glasses, /obj/item/clothing/glasses/sunglasses/blindfold)) //resting your eyes with a blindfold heals blurry eyes faster + eye_blurry = max(eye_blurry-3, 0) + blinded = 1 + + //blurry sight + if(vision.is_bruised()) // Vision organs impaired? Permablurry. + eye_blurry = 1 + if(eye_blurry) // Blurry eyes heal slowly + eye_blurry = max(eye_blurry-1, 0) //Ears if(sdisabilities & DEAF) //disabled-deaf, doesn't get better on its own @@ -1100,8 +1106,14 @@ // now handle what we see on our screen - if(!..()) - return + if(!client) + return 0 + + for(var/image/hud in client.images) + if(copytext(hud.icon_state,1,4) == "hud") //ugly, but icon comparison is worse, I believe + client.images.Remove(hud) + + client.screen.Remove(global_hud.blurry, global_hud.druggy, global_hud.vimpaired, global_hud.darkMask, global_hud.nvg, global_hud.thermal, global_hud.meson, global_hud.science) if(damageoverlay.overlays) damageoverlay.overlays = list() @@ -1173,6 +1185,60 @@ I = overlays_cache[23] damageoverlay.overlays += I + if( stat == DEAD ) + sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS|SEE_SELF + see_in_dark = 8 + if(!druggy) see_invisible = SEE_INVISIBLE_LEVEL_TWO + if(healths) healths.icon_state = "health7" //DEAD healthmeter + if(client) + if(client.view != world.view) // If mob dies while zoomed in with device, unzoom them. + for(var/obj/item/item in contents) + if(item.zoom) + item.zoom() + break + + else + sight &= ~(SEE_TURFS|SEE_MOBS|SEE_OBJS) + see_invisible = see_in_dark>2 ? SEE_INVISIBLE_LEVEL_ONE : SEE_INVISIBLE_LIVING + + if(XRAY in mutations) + sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS + see_in_dark = 8 + if(!druggy) see_invisible = SEE_INVISIBLE_LEVEL_TWO + + if(seer==1) + var/obj/effect/rune/R = locate() in loc + if(R && R.word1 == cultwords["see"] && R.word2 == cultwords["hell"] && R.word3 == cultwords["join"]) + see_invisible = SEE_INVISIBLE_CULT + else + see_invisible = SEE_INVISIBLE_LIVING + seer = 0 + + else + sight = species.get_vision_flags(src) + see_in_dark = species.darksight + see_invisible = see_in_dark>2 ? SEE_INVISIBLE_LEVEL_ONE : SEE_INVISIBLE_LIVING + var/tmp/glasses_processed = 0 + var/obj/item/weapon/rig/rig = back + if(istype(rig) && rig.visor) + if(!rig.helmet || (head && rig.helmet == head)) + if(rig.visor && rig.visor.vision && rig.visor.active && rig.visor.vision.glasses) + glasses_processed = 1 + process_glasses(rig.visor.vision.glasses) + + if(glasses && !glasses_processed) + glasses_processed = 1 + process_glasses(glasses) + if(XRAY in mutations) + sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS + see_in_dark = 8 + if(!druggy) see_invisible = SEE_INVISIBLE_LEVEL_TWO + + if(!glasses_processed && (species.get_vision_flags(src) > 0)) + sight |= species.get_vision_flags(src) + if(!seer && !glasses_processed) + see_invisible = SEE_INVISIBLE_LIVING + if(healths) if (analgesic > 100) healths.icon_state = "health_health_numb" @@ -1191,6 +1257,8 @@ if(0 to 20) healths.icon_state = "health5" else healths.icon_state = "health6" + if(!seer) + see_invisible = SEE_INVISIBLE_LIVING if(nutrition_icon) switch(nutrition) if(450 to INFINITY) nutrition_icon.icon_state = "nutrition0" @@ -1256,8 +1324,85 @@ bodytemp.icon_state = "temp-1" else bodytemp.icon_state = "temp0" + if(blind) + if(blinded) blind.layer = 18 + else blind.layer = 0 + + if(disabilities & NEARSIGHTED) //this looks meh but saves a lot of memory by not requiring to add var/prescription + if(glasses) //to every /obj/item + var/obj/item/clothing/glasses/G = glasses + if(!G.prescription) + client.screen += global_hud.vimpaired + else + client.screen += global_hud.vimpaired + + if(eye_blurry) client.screen += global_hud.blurry + if(druggy) client.screen += global_hud.druggy + + if(config.welder_vision) + var/found_welder + if(species.short_sighted) + found_welder = 1 + else + if(istype(glasses, /obj/item/clothing/glasses/welding)) + var/obj/item/clothing/glasses/welding/O = glasses + if(!O.up) + found_welder = 1 + if(!found_welder && istype(head, /obj/item/clothing/head/welding)) + var/obj/item/clothing/head/welding/O = head + if(!O.up) + found_welder = 1 + if(!found_welder && istype(back, /obj/item/weapon/rig)) + var/obj/item/weapon/rig/O = back + if(O.helmet && O.helmet == head && (O.helmet.body_parts_covered & EYES)) + if((O.offline && O.offline_vision_restriction == 1) || (!O.offline && O.vision_restriction == 1)) + found_welder = 1 + if(found_welder) + client.screen |= global_hud.darkMask + + if(machine) + var/viewflags = machine.check_eye(src) + if(viewflags < 0) + reset_view(null, 0) + else if(viewflags) + sight |= viewflags + else if(eyeobj) + if(eyeobj.owner != src) + + reset_view(null) + else + var/isRemoteObserve = 0 + if((mRemote in mutations) && remoteview_target) + if(remoteview_target.stat==CONSCIOUS) + isRemoteObserve = 1 + if(!isRemoteObserve && client && !client.adminobs) + remoteview_target = null + reset_view(null, 0) return 1 +/mob/living/carbon/human/proc/process_glasses(var/obj/item/clothing/glasses/G) + if(G && G.active) + see_in_dark += G.darkness_view + if(G.overlay) + client.screen |= G.overlay + if(G.vision_flags) + sight |= G.vision_flags + if(!druggy && !seer) + see_invisible = SEE_INVISIBLE_MINIMUM + if(G.see_invisible >= 0) + see_invisible = G.see_invisible + if(istype(G,/obj/item/clothing/glasses/night) && !seer) + see_invisible = SEE_INVISIBLE_MINIMUM +/* HUD shit goes here, as long as it doesn't modify sight flags */ +// The purpose of this is to stop xray and w/e from preventing you from using huds -- Love, Doohl + var/obj/item/clothing/glasses/hud/O = G + if(istype(G, /obj/item/clothing/glasses/sunglasses/sechud)) + var/obj/item/clothing/glasses/sunglasses/sechud/S = G + O = S.hud + if(istype(O)) + O.process_hud(src) + if(!druggy && !seer) see_invisible = SEE_INVISIBLE_LIVING + /mob/living/carbon/human/handle_random_events() if(in_stasis) return @@ -1580,37 +1725,5 @@ restore_blood() ..() -/mob/living/carbon/human/handle_vision() - if(client) - client.screen.Remove(global_hud.blurry, global_hud.druggy, global_hud.vimpaired, global_hud.darkMask, global_hud.nvg, global_hud.thermal, global_hud.meson, global_hud.science) - if(machine) - var/viewflags = machine.check_eye(src) - if(viewflags < 0) - reset_view(null, 0) - else if(viewflags) - sight |= viewflags - else if(eyeobj) - if(eyeobj.owner != src) - - reset_view(null) - else - var/isRemoteObserve = 0 - if((mRemote in mutations) && remoteview_target) - if(remoteview_target.stat==CONSCIOUS) - isRemoteObserve = 1 - if(!isRemoteObserve && client && !client.adminobs) - remoteview_target = null - reset_view(null, 0) - - update_equipment_vision() - species.handle_vision(src) - -/mob/living/carbon/human/update_sight() - ..() - if(stat == DEAD) - return - if(XRAY in mutations) - sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS - #undef HUMAN_MAX_OXYLOSS #undef HUMAN_CRIT_MAX_OXYLOSS diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index b8bdb85edd6..d77493b0b36 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -20,7 +20,6 @@ var/prone_icon // If set, draws this from icobase when mob is prone. var/eyes = "eyes_s" // Icon for eyes. - var/has_floating_eyes // Eyes will overlay over darkness (glow) var/blood_color = "#A10808" // Red. var/flesh_color = "#FFC896" // Pink. var/base_color // Used by changelings. Should also be used for icon previes.. @@ -68,12 +67,9 @@ var/death_sound var/death_message = "seizes up and falls limp, their eyes dead and lifeless..." var/knockout_message = "has been knocked unconscious!" - var/halloss_message = "slumps to the ground, too weak to continue fighting." - var/halloss_message_self = "You're in too much pain to keep going..." // Environment tolerance/life processes vars. var/reagent_tag //Used for metabolizing reagents. - var/breath_pressure = 16 // Minimum partial pressure safe for breathing, kPa var/breath_type = "oxygen" // Non-oxygen gas breathed, if any. var/poison_type = "phoron" // Poisonous air. var/exhale_type = "carbon_dioxide" // Exhaled gas type. @@ -156,9 +152,6 @@ var/pass_flags = 0 -/datum/species/proc/get_eyes(var/mob/living/carbon/human/H) - return - /datum/species/New() if(hud_type) hud = new hud_type() @@ -337,42 +330,3 @@ /datum/species/proc/get_vision_flags(var/mob/living/carbon/human/H) return vision_flags - -/datum/species/proc/handle_vision(var/mob/living/carbon/human/H) - H.update_sight() - H.sight |= get_vision_flags(H) - H.sight |= H.equipment_vision_flags - - if(H.stat == DEAD) - return 1 - - if(!H.druggy) - H.see_in_dark = (H.sight == SEE_TURFS|SEE_MOBS|SEE_OBJS) ? 8 : min(darksight + H.equipment_darkness_modifier, 8) - if(H.seer) - var/obj/effect/rune/R = locate() in H.loc - if(R && R.word1 == cultwords["see"] && R.word2 == cultwords["hell"] && R.word3 == cultwords["join"]) - H.see_invisible = SEE_INVISIBLE_CULT - if(H.see_invisible != SEE_INVISIBLE_CULT && H.equipment_see_invis) - H.see_invisible = min(H.see_invisible, H.equipment_see_invis) - - if(H.equipment_tint_total >= TINT_BLIND) - H.eye_blind = max(H.eye_blind, 1) - - if(H.blind) - H.blind.layer = (H.eye_blind ? 18 : 0) - - if(!H.client)//no client, no screen to update - return 1 - - if(config.welder_vision) - if(short_sighted || (H.equipment_tint_total >= TINT_HEAVY)) - H.client.screen += global_hud.darkMask - else if((!H.equipment_prescription && (H.disabilities & NEARSIGHTED)) || H.equipment_tint_total == TINT_MODERATE) - H.client.screen += global_hud.vimpaired - if(H.eye_blurry) H.client.screen += global_hud.blurry - if(H.druggy) H.client.screen += global_hud.druggy - - for(var/overlay in H.equipment_overlays) - H.client.screen |= overlay - - return 1 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 4fa41f1a5ba..e4c31a14471 100644 --- a/code/modules/mob/living/carbon/human/species/station/station.dm +++ b/code/modules/mob/living/carbon/human/species/station/station.dm @@ -242,7 +242,19 @@ return ..() /datum/species/diona/handle_death(var/mob/living/carbon/human/H) - H.diona_split_into_nymphs(0) + + var/mob/living/carbon/alien/diona/S = new(get_turf(H)) + + if(H.mind) + H.mind.transfer_to(S) + + for(var/mob/living/carbon/alien/diona/D in H.contents) + if(D.client) + D.loc = H.loc + else + qdel(D) + + H.visible_message("[H] splits apart with a wet slithering noise!") /datum/species/machine name = "Machine" @@ -269,8 +281,6 @@ show_ssd = "flashing a 'system offline' glyph on their monitor" death_message = "gives one shrill beep before falling lifeless." knockout_message = "encounters a hardware fault and suddenly reboots!" - halloss_message = "encounters a hardware fault and suddenly reboots." - halloss_message_self = "ERROR: Unrecoverable machine check exception.
System halted, rebooting..." warning_low_pressure = 50 hazard_low_pressure = 0 diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_embryo.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_embryo.dm new file mode 100644 index 00000000000..c60d8bca1d7 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_embryo.dm @@ -0,0 +1,159 @@ +// This is to replace the previous datum/disease/alien_embryo for slightly improved handling and maintainability +// It functions almost identically (see code/datums/diseases/alien_embryo.dm) + +/obj/item/alien_embryo + name = "alien embryo" + desc = "All slimy and yuck." + icon = 'icons/mob/alien.dmi' + icon_state = "larva0_dead" + var/mob/living/affected_mob + var/stage = 0 + +/obj/item/alien_embryo/New() + if(istype(loc, /mob/living)) + affected_mob = loc + processing_objects.Add(src) + spawn(0) + AddInfectionImages(affected_mob) + else + qdel(src) + +/obj/item/alien_embryo/Destroy() + if(affected_mob) + affected_mob.status_flags &= ~(XENO_HOST) + spawn(0) + RemoveInfectionImages(affected_mob) + ..() + +/obj/item/alien_embryo/process() + if(!affected_mob) return + if(loc != affected_mob) + affected_mob.status_flags &= ~(XENO_HOST) + processing_objects.Remove(src) + spawn(0) + RemoveInfectionImages(affected_mob) + affected_mob = null + return + + if(stage < 5 && prob(3)) + stage++ + spawn(0) + RefreshInfectionImage(affected_mob) + + switch(stage) + if(2, 3) + if(prob(1)) + affected_mob.emote("sneeze") + if(prob(1)) + affected_mob.emote("cough") + if(prob(1)) + affected_mob << "\red Your throat feels sore." + if(prob(1)) + affected_mob << "\red Mucous runs down the back of your throat." + if(4) + if(prob(1)) + affected_mob.emote("sneeze") + if(prob(1)) + affected_mob.emote("cough") + if(prob(2)) + affected_mob << "\red Your muscles ache." + if(prob(20)) + affected_mob.take_organ_damage(1) + if(prob(2)) + affected_mob << "\red Your stomach hurts." + if(prob(20)) + affected_mob.adjustToxLoss(1) + affected_mob.updatehealth() + if(5) + affected_mob << "\red You feel something tearing its way out of your stomach..." + affected_mob.adjustToxLoss(10) + affected_mob.updatehealth() + if(prob(50)) + AttemptGrow() + +/obj/item/alien_embryo/proc/AttemptGrow(var/gib_on_success = 1) + var/list/candidates = get_alien_candidates() + var/picked = null + + // To stop clientless larva, we will check that our host has a client + // if we find no ghosts to become the alien. If the host has a client + // he will become the alien but if he doesn't then we will set the stage + // to 2, so we don't do a process heavy check everytime. + + if(candidates.len) + picked = pick(candidates) + else if(affected_mob.client) + picked = affected_mob.key + else + stage = 4 // Let's try again later. + return + + if(affected_mob.lying) + affected_mob.overlays += image('icons/mob/alien.dmi', loc = affected_mob, icon_state = "burst_lie") + else + affected_mob.overlays += image('icons/mob/alien.dmi', loc = affected_mob, icon_state = "burst_stand") + spawn(6) + var/mob/living/carbon/alien/larva/new_xeno = new(affected_mob.loc) + new_xeno.key = picked + new_xeno << sound('sound/voice/hiss5.ogg',0,0,0,100) //To get the player's attention + if(gib_on_success) + affected_mob.gib() + qdel(src) + +/*---------------------------------------- +Proc: RefreshInfectionImage() +Des: Removes all infection images from aliens and places an infection image on all infected mobs for aliens. +----------------------------------------*/ +/obj/item/alien_embryo/proc/RefreshInfectionImage() + + for(var/mob/living/carbon/alien in player_list) + + if(!locate(/obj/item/organ/xenos/hivenode) in alien.internal_organs) + continue + + if(alien.client) + for(var/image/I in alien.client.images) + if(dd_hasprefix_case(I.icon_state, "infected")) + qdel(I) + for(var/mob/living/L in mob_list) + if(iscorgi(L) || iscarbon(L)) + if(L.status_flags & XENO_HOST) + var/I = image('icons/mob/alien.dmi', loc = L, icon_state = "infected[stage]") + alien.client.images += I + +/*---------------------------------------- +Proc: AddInfectionImages(C) +Des: Checks if the passed mob (C) is infected with the alien egg, then gives each alien client an infected image at C. +----------------------------------------*/ +/obj/item/alien_embryo/proc/AddInfectionImages(var/mob/living/C) + if(C) + + for(var/mob/living/carbon/alien in player_list) + + if(!locate(/obj/item/organ/xenos/hivenode) in alien.internal_organs) + continue + + if(alien.client) + if(C.status_flags & XENO_HOST) + var/I = image('icons/mob/alien.dmi', loc = C, icon_state = "infected[stage]") + alien.client.images += I + +/*---------------------------------------- +Proc: RemoveInfectionImage(C) +Des: Removes the alien infection image from all aliens in the world located in passed mob (C). +----------------------------------------*/ + +/obj/item/alien_embryo/proc/RemoveInfectionImages(var/mob/living/C) + + if(C) + + for(var/mob/living/carbon/alien in player_list) + + if(!locate(/obj/item/organ/xenos/hivenode) in alien.internal_organs) + continue + + if(alien.client) + for(var/image/I in alien.client.images) + if(I.loc == C) + if(dd_hasprefix_case(I.icon_state, "infected")) + qdel(I) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm index 691ac149bdf..335b5660924 100644 --- a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm +++ b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm @@ -32,11 +32,10 @@ var/const/MAX_ACTIVE_TIME = 400 ..() -/obj/item/clothing/mask/facehugger/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) - . = ..() +/obj/item/clothing/mask/facehugger/attack(mob/living/M as mob, mob/user as mob) + ..() user.drop_from_inventory(src) - if(hit_zone == "head") - Attach(target) + Attach(M) /obj/item/clothing/mask/facehugger/New() if(config.aliens_allowed) diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_powers.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_powers.dm index b24fdd50c37..a73e3639046 100644 --- a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_powers.dm +++ b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_powers.dm @@ -88,13 +88,13 @@ verbs -= /mob/living/carbon/human/proc/lay_egg return - if(locate(/obj/structure/alien/egg) in get_turf(src)) + if(locate(/obj/effect/alien/egg) in get_turf(src)) src << "There's already an egg here." return if(check_alien_ability(75,1,"egg sac")) visible_message("[src] has laid an egg!") - new /obj/structure/alien/egg(loc) + new /obj/effect/alien/egg(loc) return @@ -121,7 +121,7 @@ if(check_alien_ability(50,1,"resin spinner")) visible_message("[src] has planted some alien weeds!") - new /obj/structure/alien/node(loc) + new /obj/effect/alien/weeds/node(loc) return /mob/living/carbon/human/proc/corrosive_acid(O as obj|turf in oview(1)) //If they right click to corrode, an error will flash if its an invalid target./N @@ -154,7 +154,7 @@ return if(check_alien_ability(200,0,"acid gland")) - new /obj/effect/acid(get_turf(O), O) + new /obj/effect/alien/acid(get_turf(O), O) visible_message("[src] vomits globs of vile stuff all over [O]. It begins to sizzle and melt under the bubbling mess of acid!") return @@ -199,7 +199,7 @@ /mob/living/carbon/human/proc/resin() // -- TLE set name = "Secrete Resin (75)" - set desc = "Secrete tough, malleable resin." + set desc = "Secrete tough malleable resin." set category = "Abilities" var/choice = input("Choose what you wish to shape.","Resin building") as null|anything in list("resin door","resin wall","resin membrane","resin nest") //would do it through typesof but then the player choice would have the type path and we don't want the internal workings to be exposed ICly - Urist @@ -214,51 +214,9 @@ if("resin door") new /obj/structure/simple_door/resin(loc) if("resin wall") - new /obj/structure/alien/resin/wall(loc) + new /obj/effect/alien/resin/wall(loc) if("resin membrane") - new /obj/structure/alien/resin/membrane(loc) + new /obj/effect/alien/resin/membrane(loc) if("resin nest") new /obj/structure/bed/nest(loc) - return - -mob/living/carbon/human/proc/xeno_infest(mob/living/carbon/human/M as mob in oview()) - set name = "Infest (500)" - set desc = "Link a victim to the hivemind." - set category = "Abilities" - - if(!M.Adjacent(src)) - src << "They are too far away." - return - - if(!M.mind) - src << "This mindless flesh adds nothing to the hive." - return - - if(M.species.get_bodytype() == "Xenomorph" || !isnull(M.internal_organs_by_name["hive node"])) - src << "They are already part of the hive." - return - - var/obj/item/organ/affecting = M.get_organ("chest") - if(!affecting || (affecting.status & ORGAN_ROBOT)) - src << "This form is not compatible with our physiology." - return - - src.visible_message("\The [src] crouches over \the [M], extending a hideous protuberance from its head!") - - if(!do_after(src, 150)) - return - - if(!M || !M.Adjacent(src)) - src << "They are too far away." - return - - if(M.species.get_bodytype() == "Xenomorph" || !isnull(M.internal_organs_by_name["hive node"]) || !affecting || (affecting.status & ORGAN_ROBOT)) - return - - if(!check_alien_ability(500,1,"egg sac")) - return - - src.visible_message("\The [src] regurgitates something into \the [M]'s torso!") - M << "A hideous lump of alien mass strains your ribcage as it settles within!" - var/obj/item/organ/xenos/hivenode/node = new(affecting) - node.replaced(M,affecting) \ No newline at end of file + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm index 3c89ed183b0..1c5e88ce59c 100644 --- a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm +++ b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm @@ -15,8 +15,8 @@ eyes = "blank_eyes" - brute_mod = 0.25 // Hardened carapace. - burn_mod = 1.1 // Weak to fire. + brute_mod = 0.5 // Hardened carapace. + burn_mod = 2 // Weak to fire. warning_low_pressure = 50 hazard_low_pressure = -1 @@ -98,11 +98,11 @@ var/datum/gas_mixture/environment = T.return_air() if(!environment) return - var/obj/effect/plant/plant = locate() in T - if((environment.gas["phoron"] > 0 || (plant && plant.seed && plant.seed.name == "xenomorph")) && !regenerate(H)) - var/obj/item/organ/xenos/plasmavessel/P = H.internal_organs_by_name["plasma vessel"] - P.stored_plasma += weeds_plasma_rate - P.stored_plasma = min(max(P.stored_plasma,0),P.max_plasma) + if(environment.gas["phoron"] > 0 || locate(/obj/effect/alien/weeds) in T) + if(!regenerate(H)) + var/obj/item/organ/xenos/plasmavessel/P = H.internal_organs_by_name["plasma vessel"] + P.stored_plasma += weeds_plasma_rate + P.stored_plasma = min(max(P.stored_plasma,0),P.max_plasma) ..() /datum/species/xenos/proc/regenerate(var/mob/living/carbon/human/H) @@ -140,6 +140,14 @@ return 0 +/datum/species/xenos/handle_login_special(var/mob/living/carbon/human/H) + H.AddInfectionImages() + ..() + +/datum/species/xenos/handle_logout_special(var/mob/living/carbon/human/H) + H.RemoveInfectionImages() + ..() + /datum/species/xenos/drone name = "Xenomorph Drone" caste_name = "drone" @@ -270,8 +278,7 @@ /mob/living/carbon/human/proc/transfer_plasma, /mob/living/carbon/human/proc/corrosive_acid, /mob/living/carbon/human/proc/neurotoxin, - /mob/living/carbon/human/proc/resin, - /mob/living/carbon/human/proc/xeno_infest + /mob/living/carbon/human/proc/resin ) /datum/species/xenos/queen/handle_login_special(var/mob/living/carbon/human/H) diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/xenomorphs.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/xenomorphs.dm index 504577c7d33..6cb8a464756 100644 --- a/code/modules/mob/living/carbon/human/species/xenomorphs/xenomorphs.dm +++ b/code/modules/mob/living/carbon/human/species/xenomorphs/xenomorphs.dm @@ -22,3 +22,28 @@ proc/create_new_xenomorph(var/alien_caste,var/target) /mob/living/carbon/human/xqueen/New(var/new_loc) h_style = "Bald" ..(new_loc, "Xenomorph Queen") + +// I feel like we should generalize/condense down all the various icon-rendering antag procs. +/*---------------------------------------- +Proc: AddInfectionImages() +Des: Gives the client of the alien an image on each infected mob. +----------------------------------------*/ +/mob/living/carbon/human/proc/AddInfectionImages() + if (client) + for (var/mob/living/C in mob_list) + if(C.status_flags & XENO_HOST) + var/obj/item/alien_embryo/A = locate() in C + var/I = image('icons/mob/alien.dmi', loc = C, icon_state = "infected[A.stage]") + client.images += I + return + +/*---------------------------------------- +Proc: RemoveInfectionImages() +Des: Removes all infected images from the alien. +----------------------------------------*/ +/mob/living/carbon/human/proc/RemoveInfectionImages() + if (client) + for(var/image/I in client.images) + if(dd_hasprefix_case(I.icon_state, "infected")) + qdel(I) + return diff --git a/code/modules/mob/living/carbon/human/unarmed_attack.dm b/code/modules/mob/living/carbon/human/unarmed_attack.dm index 1d148b96ead..289b4a22733 100644 --- a/code/modules/mob/living/carbon/human/unarmed_attack.dm +++ b/code/modules/mob/living/carbon/human/unarmed_attack.dm @@ -32,9 +32,6 @@ /datum/unarmed_attack/proc/apply_effects(var/mob/living/carbon/human/user,var/mob/living/carbon/human/target,var/armour,var/attack_damage,var/zone) - if(target.stat == DEAD) - return - var/stun_chance = rand(0, 100) if(attack_damage >= 5 && armour < 2 && !(target == user) && stun_chance <= attack_damage * 5) // 25% standard chance @@ -236,4 +233,4 @@ switch(attack_damage) if(1 to 4) user.visible_message("[pick("[user] stomped on", "[user] slammed \his [shoes ? copytext(shoes.name, 1, -1) : "foot"] down onto")] [target]'s [organ]!") - if(5) user.visible_message("[pick("[user] landed a powerful stomp on", "[user] stomped down hard on", "[user] slammed \his [shoes ? copytext(shoes.name, 1, -1) : "foot"] down hard onto")] [target]'s [organ]!") //Devastated lol. No. We want to say that the stomp was powerful or forceful, not that it /wrought devastation/ + if(5) user.visible_message("[pick("[user] landed a powerful stomp on", "[user] stomped down hard on", "[user] slammed \his [shoes ? copytext(shoes.name, 1, -1) : "foot"] down hard onto")] [target]'s [organ]!") //Devastated lol. No. We want to say that the stomp was powerful or forceful, not that it /wrought devastation/ \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 30d2a4cd0b2..e634f5224be 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -163,8 +163,6 @@ Please contact me on #coderbus IRC. ~Carn x icon = stand_icon for(var/image/I in overlays_standing) overlays += I - if(species.has_floating_eyes) - overlays |= species.get_eyes(src) if(lying && !species.prone_icon) //Only rotate them if we're not drawing a specific icon for being prone. var/matrix/M = matrix() @@ -339,7 +337,7 @@ var/global/list/damage_icon_parts = list() if(undershirt && species.appearance_flags & HAS_UNDERWEAR) stand_icon.Blend(new /icon('icons/mob/human.dmi', undershirt), ICON_OVERLAY) - if(socks && species.appearance_flags & HAS_UNDERWEAR) + if(socks && species.flags & HAS_UNDERWEAR) stand_icon.Blend(new /icon('icons/mob/human.dmi', socks), ICON_OVERLAY) if(update_icons) diff --git a/code/modules/mob/living/carbon/metroid/items.dm b/code/modules/mob/living/carbon/metroid/items.dm index 6832f096f2a..d068e33e6c9 100644 --- a/code/modules/mob/living/carbon/metroid/items.dm +++ b/code/modules/mob/living/carbon/metroid/items.dm @@ -281,3 +281,87 @@ /mob/living/carbon/slime/has_eyes() return 0 +//////////////////////////////Old shit from metroids/RoRos, and the old cores, would not take much work to re-add them//////////////////////// + +/* +// Basically this slime Core catalyzes reactions that normally wouldn't happen anywhere +/obj/item/slime_core + name = "slime extract" + desc = "Goo extracted from a slime. Legends claim these to have \"magical powers\"." + icon = 'icons/mob/slimes.dmi' + icon_state = "slime extract" + force = 1.0 + w_class = 1.0 + throwforce = 1.0 + throw_speed = 2 + throw_range = 6 + origin_tech = list(TECH_BIO = 4) + var/POWERFLAG = 0 // sshhhhhhh + var/Flush = 30 + var/Uses = 5 // uses before it goes inert + +/obj/item/slime_core/New() + ..() + create_reagents(100) + POWERFLAG = rand(1,10) + Uses = rand(7, 25) + //flags |= NOREACT +/* + spawn() + Life() + + proc/Life() + while(src) + sleep(25) + Flush-- + if(Flush <= 0) + reagents.clear_reagents() + Flush = 30 +*/ + + + +/obj/item/weapon/reagent_containers/food/snacks/egg/slime + name = "slime egg" + desc = "A small, gelatinous egg." + icon = 'icons/mob/mob.dmi' + icon_state = "slime egg-growing" + bitesize = 12 + origin_tech = list(TECH_BIO = 4) + var/grown = 0 + +/obj/item/weapon/reagent_containers/food/snacks/egg/slime/New() + ..() + reagents.add_reagent("nutriment", 4) + reagents.add_reagent("slimejelly", 1) + spawn(rand(1200,1500))//the egg takes a while to "ripen" + Grow() + +/obj/item/weapon/reagent_containers/food/snacks/egg/slime/proc/Grow() + grown = 1 + icon_state = "slime egg-grown" + processing_objects.Add(src) + return + +/obj/item/weapon/reagent_containers/food/snacks/egg/slime/proc/Hatch() + processing_objects.Remove(src) + var/turf/T = get_turf(src) + src.visible_message(" The [name] pulsates and quivers!") + spawn(rand(50,100)) + src.visible_message(" The [name] bursts open!") + new/mob/living/carbon/slime(T) + qdel(src) + + +/obj/item/weapon/reagent_containers/food/snacks/egg/slime/process() + var/turf/location = get_turf(src) + var/datum/gas_mixture/environment = location.return_air() + if (environment.phoron > MOLES_PHORON_VISIBLE)//phoron exposure causes the egg to hatch + src.Hatch() + +/obj/item/weapon/reagent_containers/food/snacks/egg/slime/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype( W, /obj/item/weapon/pen/crayon )) + return + else + ..() +*/ diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index 0815dac4364..5e7a6e2d90f 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -126,60 +126,24 @@ adjustEarDamage(-0.05,-1) //this handles hud updates. Calls update_vision() and handle_hud_icons() -/mob/living/proc/handle_regular_hud_updates() - if(!client) return 0 +/mob/living/handle_regular_hud_updates() + if(!client) + return 0 + ..() - handle_hud_icons() handle_vision() + handle_hud_icons() return 1 /mob/living/proc/handle_vision() - client.screen.Remove(global_hud.blurry, global_hud.druggy, global_hud.vimpaired, global_hud.darkMask, global_hud.nvg, global_hud.thermal, global_hud.meson, global_hud.science) - - update_sight() - - if(stat == DEAD) - return - - if(blind) - if(eye_blind) - blind.layer = 18 - else - blind.layer = 0 - if (disabilities & NEARSIGHTED) - client.screen += global_hud.vimpaired - if (eye_blurry) - client.screen += global_hud.blurry - if (druggy) - client.screen += global_hud.druggy - if(machine) - var/viewflags = machine.check_eye(src) - if(viewflags < 0) - reset_view(null, 0) - else if(viewflags) - sight |= viewflags - else if(eyeobj && eyeobj.owner != src) - reset_view(null) - else - if(!client.adminobs) - reset_view(null) + return /mob/living/proc/update_sight() - if(stat == DEAD) - sight |= SEE_TURFS - sight |= SEE_MOBS - sight |= SEE_OBJS - see_in_dark = 8 - see_invisible = SEE_INVISIBLE_LEVEL_TWO - else - sight &= ~(SEE_TURFS|SEE_MOBS|SEE_OBJS) - see_in_dark = 2 - see_invisible = SEE_INVISIBLE_LIVING + return /mob/living/proc/handle_hud_icons() handle_hud_icons_health() - handle_hud_glasses() return /mob/living/proc/handle_hud_icons_health() diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 64ca2469b07..d7a989756d0 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -111,42 +111,6 @@ O.emp_act(severity) ..() -/mob/living/proc/resolve_item_attack(obj/item/I, mob/living/user, var/target_zone) - return target_zone - -//Called when the mob is hit with an item in combat. Returns the blocked result -/mob/living/proc/hit_with_weapon(obj/item/I, mob/living/user, var/effective_force, var/hit_zone) - visible_message("[src] has been [I.attack_verb.len? pick(I.attack_verb) : "attacked"] with [I.name] by [user]!") - - var/blocked = run_armor_check(hit_zone, "melee") - standard_weapon_hit_effects(I, user, effective_force, blocked, hit_zone) - - if(I.damtype == BRUTE && prob(33)) // Added blood for whacking non-humans too - var/turf/simulated/location = get_turf(src) - if(istype(location)) location.add_blood_floor(src) - - return blocked - -//returns 0 if the effects failed to apply for some reason, 1 otherwise. -/mob/living/proc/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/hit_zone) - if(!effective_force || blocked >= 2) - return 0 - - //Hulk modifier - if(HULK in user.mutations) - effective_force *= 2 - - //Apply weapon damage - var/weapon_sharp = is_sharp(I) - var/weapon_edge = has_edge(I) - if(prob(max(getarmor(hit_zone, "melee") - I.armor_penetration, 0))) //melee armour provides a chance to turn sharp/edge weapon attacks into blunt ones - weapon_sharp = 0 - weapon_edge = 0 - - apply_damage(effective_force, I.damtype, hit_zone, blocked, sharp=weapon_sharp, edge=weapon_edge, used_weapon=I) - - return 1 - //this proc handles being hit by a thrown atom /mob/living/hitby(atom/movable/AM as mob|obj,var/speed = THROWFORCE_SPEED_DIVISOR)//Standardization and logging -Sieve if(istype(AM,/obj/)) @@ -374,3 +338,54 @@ hud_used.hide_actions_toggle.screen_loc = hud_used.ButtonNumberToScreenCoords(button_number+1) //hud_used.SetButtonCoords(hud_used.hide_actions_toggle,button_number+1) client.screen += hud_used.hide_actions_toggle + + +//If simple_animals are ever moved under carbon, then this can probably be moved to carbon as well +/mob/living/proc/attack_throat(obj/item/W, obj/item/weapon/grab/G, mob/user) + + // Knifing + if(!W.edge || !W.force || W.damtype != BRUTE) return //unsuitable weapon + + user.visible_message("\The [user] begins to slit [src]'s throat with \the [W]!") + + user.next_move = world.time + 20 //also should prevent user from triggering this repeatedly + if(!do_after(user, 20)) + return + if(!(G && G.assailant == user && G.affecting == src)) //check that we still have a grab + return + + var/damage_mod = 1 + //presumably, if they are wearing a helmet that stops pressure effects, then it probably covers the throat as well + var/obj/item/clothing/head/helmet = get_equipped_item(slot_head) + if(istype(helmet) && (helmet.body_parts_covered & HEAD) && (helmet.item_flags & STOPPRESSUREDAMAGE)) + //we don't do an armor_check here because this is not an impact effect like a weapon swung with momentum, that either penetrates or glances off. + damage_mod = 1.0 - (helmet.armor["melee"]/100) + + var/total_damage = 0 + for(var/i in 1 to 3) + var/damage = min(W.force*1.5, 20)*damage_mod + apply_damage(damage, W.damtype, "head", 0, sharp=W.sharp, edge=W.edge) + total_damage += damage + + var/oxyloss = total_damage + if(total_damage >= 40) //threshold to make someone pass out + oxyloss = 60 // Brain lacks oxygen immediately, pass out + + adjustOxyLoss(min(oxyloss, 100 - getOxyLoss())) //don't put them over 100 oxyloss + + if(total_damage) + if(oxyloss >= 40) + user.visible_message("\The [user] slit [src]'s throat open with \the [W]!") + else + user.visible_message("\The [user] cut [src]'s neck with \the [W]!") + + if(W.hitsound) + playsound(loc, W.hitsound, 50, 1, -1) + + G.last_action = world.time + flick(G.hud.icon_state, G.hud) + + user.attack_log += "\[[time_stamp()]\] Knifed [name] ([ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])" + src.attack_log += "\[[time_stamp()]\] Got knifed by [user.name] ([user.ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])" + msg_admin_attack("[key_name(user)] knifed [key_name(src)] with [W.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(W.damtype)])" ) + return diff --git a/code/modules/mob/living/silicon/laws.dm b/code/modules/mob/living/silicon/laws.dm index 1032908c835..5f7b07489b9 100644 --- a/code/modules/mob/living/silicon/laws.dm +++ b/code/modules/mob/living/silicon/laws.dm @@ -12,7 +12,7 @@ /mob/living/silicon/proc/set_zeroth_law(var/law, var/law_borg) laws_sanity_check() laws.set_zeroth_law(law, law_borg) - log_law("has given [src] the zeroth law: '[law]'[law_borg ? " / '[law_borg]'" : ""]") + log_and_message_admins("has given [src] the zeroth laws: [law]/[law_borg ? law_borg : "N/A"]") /mob/living/silicon/robot/set_zeroth_law(var/law, var/law_borg) ..() @@ -22,40 +22,40 @@ /mob/living/silicon/proc/add_ion_law(var/law) laws_sanity_check() laws.add_ion_law(law) - log_law("has given [src] the ion law: [law]") + log_and_message_admins("has given [src] the ion law: [law]") /mob/living/silicon/proc/add_inherent_law(var/law) laws_sanity_check() laws.add_inherent_law(law) - log_law("has given [src] the inherent law: [law]") + log_and_message_admins("has given [src] the inherent law: [law]") /mob/living/silicon/proc/add_supplied_law(var/number, var/law) laws_sanity_check() laws.add_supplied_law(number, law) - log_law("has given [src] the supplied law: [law]") + log_and_message_admins("has given [src] the supplied law: [law]") /mob/living/silicon/proc/delete_law(var/datum/ai_law/law) laws_sanity_check() laws.delete_law(law) - log_law("has deleted a law belonging to [src]: [law.law]") + log_and_message_admins("has deleted a law belonging to [src]: [law.law]") /mob/living/silicon/proc/clear_inherent_laws(var/silent = 0) laws_sanity_check() laws.clear_inherent_laws() if(!silent) - log_law("cleared the inherent laws of [src]") + log_and_message_admins("cleared the inherent laws of [src]") /mob/living/silicon/proc/clear_ion_laws(var/silent = 0) laws_sanity_check() laws.clear_ion_laws() if(!silent) - log_law("cleared the ion laws of [src]") + log_and_message_admins("cleared the ion laws of [src]") /mob/living/silicon/proc/clear_supplied_laws(var/silent = 0) laws_sanity_check() laws.clear_supplied_laws() if(!silent) - log_law("cleared the supplied laws of [src]") + log_and_message_admins("cleared the supplied laws of [src]") /mob/living/silicon/proc/statelaws(var/datum/ai_laws/laws) var/prefix = "" @@ -103,7 +103,3 @@ /mob/living/silicon/proc/lawsync() laws_sanity_check() laws.sort_laws() - -/mob/living/silicon/proc/log_law(var/law_message) - log_and_message_admins(law_message) - lawchanges += "[worldtime2text()] - [usr ? "[key_name(usr)]" : "EVENT"] [law_message]" diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 33699cf6df8..f3d7ffd848e 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -91,15 +91,6 @@ var/global/list/robot_modules = list( return /obj/item/weapon/robot_module/proc/respawn_consumable(var/mob/living/silicon/robot/R, var/rate) - var/obj/item/device/flash/F = locate() in src.modules - if(F) - if(F.broken) - F.broken = 0 - F.times_used = 0 - F.icon_state = "flash" - else if(F.times_used) - F.times_used-- - if(!synths || !synths.len) return @@ -280,6 +271,7 @@ var/global/list/robot_modules = list( ..() /obj/item/weapon/robot_module/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() @@ -431,7 +423,13 @@ var/global/list/robot_modules = list( ..() /obj/item/weapon/robot_module/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) @@ -464,7 +462,6 @@ var/global/list/robot_modules = list( ..() /obj/item/weapon/robot_module/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) @@ -547,7 +544,6 @@ var/global/list/robot_modules = list( ..() /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) diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm index 16a00368a80..ece00da5ee7 100644 --- a/code/modules/mob/living/silicon/say.dm +++ b/code/modules/mob/living/silicon/say.dm @@ -68,46 +68,31 @@ if (!message) return - var/obj/machinery/hologram/holopad/H = src.holo - if(H && H.masters[src])//If there is a hologram and its master is the user. + var/obj/machinery/hologram/holopad/T = src.holo + if(T && T.masters[src])//If there is a hologram and its master is the user. + + //Human-like, sorta, heard by those who understand humans. + var/rendered_a + //Speach distorted, heard by those who do not understand AIs. + var/message_stars = stars(message) + var/rendered_b - // AI can hear their own message, this formats it for them. if(speaking) - src << "Holopad transmitted, [real_name] [speaking.format_message(message, verb)]" + rendered_a = "[name] [speaking.format_message(message, verb)]" + rendered_b = "[voice_name] [speaking.format_message(message_stars, verb)]" + src << "Holopad transmitted, [real_name] [speaking.format_message(message, verb)]"//The AI can "hear" its own message. else - src << "Holopad transmitted, [real_name] [verb], \"[message]\"" - - //This is so pAI's and people inside lockers/boxes,etc can hear the AI Holopad, the alternative being recursion through contents. - //This is much faster. - var/list/listening = list() - var/list/listening_obj = list() - var/turf/T = get_turf(H) - - if(T) - var/list/hear = hear(7, T) - var/list/hearturfs = list() - - for(var/I in hear) - if(istype(I, /mob/)) - var/mob/M = I - listening += M - hearturfs += M.locs[1] - for(var/obj/O in M.contents) - listening_obj |= O - else if(istype(I, /obj/)) - var/obj/O = I - hearturfs += O.locs[1] - listening_obj |= O - - - for(var/mob/M in player_list) - if(M.stat == DEAD && M.client && (M.client.prefs.toggles & CHAT_GHOSTEARS)) - M.hear_say(message,verb,speaking,null,null, src) - continue - if(M.loc && M.locs[1] in hearturfs) - M.hear_say(message,verb,speaking,null,null, src) - + rendered_a = "[name] [verb], \"[message]\"" + rendered_b = "[voice_name] [verb], \"[message_stars]\"" + src << "Holopad transmitted, [real_name] [verb], \"[message]\""//The AI can "hear" its own message. + for(var/mob/M in hearers(T.loc))//The location is the object, default distance. + if(M.say_understands(src))//If they understand AI speak. Humans and the like will be able to. + M.show_message(rendered_a, 2) + else//If they do not. + M.show_message(rendered_b, 2) + /*Radios "filter out" this conversation channel so we don't need to account for them. + This is another way of saying that we won't bother dealing with them.*/ else src << "No holopad connected." return 0 diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 2aafb286fd0..42d5c6e6f68 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -132,6 +132,9 @@ updatehealth() return 1*/ +/mob/living/silicon/attack_throat() + return + /proc/islinked(var/mob/living/silicon/robot/bot, var/mob/living/silicon/ai/ai) if(!istype(bot) || !istype(ai)) return 0 diff --git a/code/modules/mob/living/simple_animal/friendly/corgi.dm b/code/modules/mob/living/simple_animal/friendly/corgi.dm index 39406eb6c8d..322d08dc9ff 100644 --- a/code/modules/mob/living/simple_animal/friendly/corgi.dm +++ b/code/modules/mob/living/simple_animal/friendly/corgi.dm @@ -22,6 +22,7 @@ var/obj/item/inventory_head var/obj/item/inventory_back + var/facehugger //IAN! SQUEEEEEEEEE~ /mob/living/simple_animal/corgi/Ian @@ -122,6 +123,13 @@ var/icon/back_icon = image('icons/mob/corgi_back.dmi',back_icon_state) if(back_icon) overlays += back_icon + + if(facehugger) + if(istype(src, /mob/living/simple_animal/corgi/puppy)) + overlays += image('icons/mob/mask.dmi',"facehugger_corgipuppy") + else + overlays += image('icons/mob/mask.dmi',"facehugger_corgi") + return diff --git a/code/modules/mob/living/simple_animal/friendly/slime.dm b/code/modules/mob/living/simple_animal/friendly/slime.dm index bbd43530a84..d0a8e09207a 100644 --- a/code/modules/mob/living/simple_animal/friendly/slime.dm +++ b/code/modules/mob/living/simple_animal/friendly/slime.dm @@ -14,11 +14,6 @@ emote_see = list("jiggles", "bounces in place") var/colour = "grey" -/mob/living/simple_animal/slime/can_force_feed(var/feeder, var/food, var/feedback) - if(feedback) - feeder << "Where do you intend to put \the [food]? \The [src] doesn't have a mouth!" - return 0 - /mob/living/simple_animal/adultslime name = "pet slime" desc = "A lovable, domesticated slime." diff --git a/code/modules/mob/living/simple_animal/friendly/spiderbot.dm b/code/modules/mob/living/simple_animal/friendly/spiderbot.dm index df3c588a34c..0c578cee773 100644 --- a/code/modules/mob/living/simple_animal/friendly/spiderbot.dm +++ b/code/modules/mob/living/simple_animal/friendly/spiderbot.dm @@ -130,7 +130,7 @@ return 0 else - O.attack(src, user, user.zone_sel.selecting) + attacked_with_item(O, user) /mob/living/simple_animal/spiderbot/emag_act(var/remaining_charges, var/mob/user) if (emagged) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 3905e272f26..acce1e39b19 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -286,28 +286,28 @@ if(istype(O, /obj/item/weapon/material/knife) || istype(O, /obj/item/weapon/material/knife/butch)) harvest(user) else - if(!O.force) - visible_message("[user] gently taps [src] with \the [O].") - else - O.attack(src, user, user.zone_sel.selecting) + attacked_with_item(O, user) -/mob/living/simple_animal/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone) +//TODO: refactor mob attackby(), attacked_by(), and friends. +/mob/living/simple_animal/proc/attacked_with_item(var/obj/item/O, var/mob/user) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(!O.force) + visible_message("[user] gently taps [src] with \the [O].") + return + + if(O.force > resistance) + var/damage = O.force + if (O.damtype == HALLOSS) + damage = 0 + if(supernatural && istype(O,/obj/item/weapon/nullrod)) + damage *= 2 + purge = 3 + adjustBruteLoss(damage) + else + usr << "This weapon is ineffective, it does no damage." visible_message("\The [src] has been attacked with \the [O] by [user].") - - if(O.force <= resistance) - user << "This weapon is ineffective, it does no damage." - return 2 - - var/damage = O.force - if (O.damtype == HALLOSS) - damage = 0 - if(supernatural && istype(O,/obj/item/weapon/nullrod)) - damage *= 2 - purge = 3 - adjustBruteLoss(damage) - - return 0 + user.do_attack_animation(src) /mob/living/simple_animal/movement_delay() var/tally = 0 //Incase I need to add stuff other than "speed" later diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index fe4d6ed56de..bcb48f0bb04 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -498,12 +498,6 @@ proc/is_blind(A) /mob/proc/is_client_active(var/active = 1) return client && client.inactivity < active MINUTES -/mob/proc/can_eat() - return 1 - -/mob/proc/can_force_feed() - return 1 - #define SAFE_PERP -50 /mob/living/proc/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest) if(stat == DEAD) diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index c54ca849e02..ee5e786db8d 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -289,7 +289,7 @@ proc/AttemptLateSpawn(rank,var/spawning_at) - if(src != usr) + if (src != usr) return 0 if(!ticker || ticker.current_state != GAME_STATE_PLAYING) usr << "\red The round is either not ready, or has already finished..." @@ -323,7 +323,7 @@ character.loc = C.loc AnnounceCyborg(character, rank, "has been downloaded to the empty core in \the [character.loc.loc]") - ticker.mode.handle_latejoin(character) + ticker.mode.latespawn(character) qdel(C) qdel(src) @@ -338,7 +338,7 @@ character.buckled.loc = character.loc character.buckled.set_dir(character.dir) - ticker.mode.handle_latejoin(character) + ticker.mode.latespawn(character) if(character.mind.assigned_role != "Cyborg") data_core.manifest_inject(character) diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm index 9bbec2c528d..34546662c38 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -1,7 +1,11 @@ datum/preferences //The mob should have a gender you want before running this proc. Will run fine without H proc/randomize_appearance_for(var/mob/living/carbon/human/H) - gender = pick(MALE, FEMALE) + if(H) + if(H.gender == MALE) + gender = MALE + else + gender = FEMALE s_tone = random_skin_tone() h_style = random_hair_style(gender, species) f_style = random_facial_hair_style(gender, species) @@ -211,18 +215,18 @@ datum/preferences preview_icon.Blend(temp, ICON_OVERLAY) // Skin color - if(current_species && (current_species.appearance_flags & HAS_SKIN_COLOR)) + if(current_species && (current_species.flags & HAS_SKIN_COLOR)) preview_icon.Blend(rgb(r_skin, g_skin, b_skin), ICON_ADD) // Skin tone - if(current_species && (current_species.appearance_flags & HAS_SKIN_TONE)) + if(current_species && (current_species.flags & HAS_SKIN_TONE)) if (s_tone >= 0) preview_icon.Blend(rgb(s_tone, s_tone, s_tone), ICON_ADD) else preview_icon.Blend(rgb(-s_tone, -s_tone, -s_tone), ICON_SUBTRACT) var/icon/eyes_s = new/icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = current_species ? current_species.eyes : "eyes_s") - if ((current_species && (current_species.appearance_flags & HAS_EYE_COLOR))) + if ((current_species && (current_species.flags & HAS_EYE_COLOR))) eyes_s.Blend(rgb(r_eyes, g_eyes, b_eyes), ICON_ADD) var/datum/sprite_accessory/hair_style = hair_styles_list[h_style] @@ -238,16 +242,15 @@ datum/preferences eyes_s.Blend(facial_s, ICON_OVERLAY) var/icon/underwear_s = null - if(underwear && current_species.appearance_flags & HAS_UNDERWEAR) -// if(underwear) + if(underwear && current_species.flags & HAS_UNDERWEAR) underwear_s = new/icon("icon" = 'icons/mob/human.dmi', "icon_state" = underwear) var/icon/undershirt_s = null - if(undershirt && current_species.appearance_flags & HAS_UNDERWEAR) + if(undershirt && current_species.flags & HAS_UNDERWEAR) undershirt_s = new/icon("icon" = 'icons/mob/human.dmi', "icon_state" = undershirt) var/icon/socks_s = null - if(socks && current_species.appearance_flags & HAS_UNDERWEAR) + if(socks && current_species.flags & HAS_UNDERWEAR) socks_s = new/icon("icon" = 'icons/mob/human.dmi', "icon_state" = socks) var/icon/clothes_s = null diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index ee1d62529af..10b9d0ebbf7 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -161,6 +161,30 @@ qdel(src) return O +//human -> alien +/mob/living/carbon/human/proc/Alienize() + if (transforming) + return + for(var/obj/item/W in src) + drop_from_inventory(W) + regenerate_icons() + transforming = 1 + canmove = 0 + icon = null + invisibility = 101 + for(var/t in organs) + qdel(t) + + var/alien_caste = pick("Hunter","Sentinel","Drone") + var/mob/living/carbon/human/new_xeno = create_new_xenomorph(alien_caste,loc) + + new_xeno.a_intent = I_HURT + new_xeno.key = key + + new_xeno << "You are now an alien." + qdel(src) + return + /mob/living/carbon/human/proc/slimeize(adult as num, reproduce as num) if (transforming) return diff --git a/code/modules/nano/modules/human_appearance.dm b/code/modules/nano/modules/human_appearance.dm index 87bfc761767..995105a2bc5 100644 --- a/code/modules/nano/modules/human_appearance.dm +++ b/code/modules/nano/modules/human_appearance.dm @@ -33,7 +33,7 @@ return 1 if(href_list["skin_tone"]) if(can_change_skin_tone()) - var/new_s_tone = input(usr, "Choose your character's skin-tone:\n(Light 1 - 220 Dark)", "Skin Tone", -owner.s_tone + 35) as num|null + var/new_s_tone = input(usr, "Choose your character's skin-tone:\n(Light 1 - 220 Dark)", "Skin Tone", owner.s_tone) as num|null if(isnum(new_s_tone) && can_still_topic(state)) new_s_tone = 35 - max(min( round(new_s_tone), 220),1) return owner.change_skin_tone(new_s_tone) diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index 664e00d275c..2367ed5b436 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -240,9 +240,6 @@ var/list/organ_cache = list() if(parent && !silent) owner.custom_pain("Something inside your [parent.name] hurts a lot.", 1) -/obj/item/organ/proc/bruise() - damage = max(damage, min_bruised_damage) - /obj/item/organ/proc/robotize() //Being used to make robutt hearts, etc robotic = 2 src.status &= ~ORGAN_BROKEN diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index d535971a215..1e2f7d1e52a 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -807,46 +807,15 @@ Note that amputating the affected organ does in fact remove the infection from t "\The [holder.legcuffed.name] falls off you.") holder.drop_from_inventory(holder.legcuffed) -// checks if all wounds on the organ are bandaged -/obj/item/organ/external/proc/is_bandaged() - for(var/datum/wound/W in wounds) - if(W.internal) continue - if(!W.bandaged) - return 0 - return 1 - -// checks if all wounds on the organ are salved -/obj/item/organ/external/proc/is_salved() - for(var/datum/wound/W in wounds) - if(W.internal) continue - if(!W.salved) - return 0 - return 1 - -// checks if all wounds on the organ are disinfected -/obj/item/organ/external/proc/is_disinfected() - for(var/datum/wound/W in wounds) - if(W.internal) continue - if(!W.disinfected) - return 0 - return 1 - /obj/item/organ/external/proc/bandage() var/rval = 0 - status &= ~ORGAN_BLEEDING + src.status &= ~ORGAN_BLEEDING for(var/datum/wound/W in wounds) if(W.internal) continue rval |= !W.bandaged W.bandaged = 1 return rval -/obj/item/organ/external/proc/salve() - var/rval = 0 - for(var/datum/wound/W in wounds) - rval |= !W.salved - W.salved = 1 - return rval - /obj/item/organ/external/proc/disinfect() var/rval = 0 for(var/datum/wound/W in wounds) @@ -865,6 +834,13 @@ Note that amputating the affected organ does in fact remove the infection from t W.clamped = 1 return rval +/obj/item/organ/external/proc/salve() + var/rval = 0 + for(var/datum/wound/W in wounds) + rval |= !W.salved + W.salved = 1 + return rval + /obj/item/organ/external/proc/fracture() if(status & ORGAN_ROBOT) return //ORGAN_BROKEN doesn't have the same meaning for robot limbs @@ -963,14 +939,11 @@ Note that amputating the affected organ does in fact remove the infection from t /obj/item/organ/external/proc/is_malfunctioning() return ((status & ORGAN_ROBOT) && (brute_dam + burn_dam) >= 10 && prob(brute_dam + burn_dam)) -/obj/item/organ/external/proc/embed(var/obj/item/weapon/W, var/silent = 0, var/supplied_message) +/obj/item/organ/external/proc/embed(var/obj/item/weapon/W, var/silent = 0) if(!owner || loc != owner) return if(!silent) - if(supplied_message) - owner.visible_message("[supplied_message]") - else - owner.visible_message("\The [W] sticks in the wound!") + owner.visible_message("\The [W] sticks in the wound!") implants += W owner.embedded_flag = 1 owner.verbs += /mob/proc/yank_out_object diff --git a/code/modules/organs/subtypes/xenos.dm b/code/modules/organs/subtypes/xenos.dm index f1049da61ea..0b1233085fd 100644 --- a/code/modules/organs/subtypes/xenos.dm +++ b/code/modules/organs/subtypes/xenos.dm @@ -38,32 +38,15 @@ icon_state = "xgibtorso" organ_tag = "acid gland" -/obj/item/organ/xenos/resinspinner - name = "resin spinner" - parent_organ = "head" - icon_state = "xgibmid2" - organ_tag = "resin spinner" - /obj/item/organ/xenos/hivenode name = "hive node" parent_organ = "chest" icon_state = "xgibmid2" organ_tag = "hive node" -/obj/item/organ/xenos/hivenode/removed(var/mob/living/user) - if(owner && ishuman(owner)) - var/mob/living/carbon/human/H = owner - H << "You feel your connection to the hivemind fray and fade away..." - H.remove_language("Hivemind") - if(H.mind && H.species.get_bodytype() != "Xenomorph") - xenomorphs.remove_antagonist(H.mind) - ..(user) +/obj/item/organ/xenos/resinspinner + name = "resin spinner" + parent_organ = "head" + icon_state = "xgibmid2" + organ_tag = "resin spinner" -/obj/item/organ/xenos/hivenode/replaced(var/mob/living/carbon/human/target,var/obj/item/organ/external/affected) - ..(target, affected) - if(owner && ishuman(owner)) - var/mob/living/carbon/human/H = owner - H.add_language("Hivemind") - if(H.mind && H.species.get_bodytype() != "Xenomorph") - H << "You feel a sense of pressure as a vast intelligence meshes with your thoughts..." - xenomorphs.add_antagonist_mind(H.mind,1, xenomorphs.faction_role_text, xenomorphs.faction_welcome) diff --git a/code/modules/organs/wound.dm b/code/modules/organs/wound.dm index 7d89a07d67c..850f5114c03 100644 --- a/code/modules/organs/wound.dm +++ b/code/modules/organs/wound.dm @@ -140,15 +140,6 @@ return 0 - proc/bandage() - bandaged = 1 - - proc/salve() - salved = 1 - - proc/disinfect() - disinfected = 1 - // heal the given amount of damage, and if the given amount of damage was more // than what needed to be healed, return how much heal was left // set @heals_internal to also heal internal organ damage @@ -327,15 +318,15 @@ datum/wound/cut/massive /datum/wound/lost_limb/New(var/obj/item/organ/external/lost_limb, var/losstype, var/clean) var/damage_amt = lost_limb.max_damage if(clean) damage_amt /= 2 - + switch(losstype) if(DROPLIMB_EDGE, DROPLIMB_BLUNT) damage_type = CUT max_bleeding_stage = 3 //clotted stump and above can bleed. stages = list( "ripped stump" = damage_amt*1.3, - "bloody stump" = damage_amt, - "clotted stump" = damage_amt*0.5, + "bloody stump" = damage_amt, + "clotted stump" = damage_amt*0.5, "scarred stump" = 0 ) if(DROPLIMB_BURN) @@ -346,7 +337,7 @@ datum/wound/cut/massive "scarred stump" = damage_amt*0.5, "scarred stump" = 0 ) - + ..(damage_amt) /datum/wound/lost_limb/can_merge(var/datum/wound/other) diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index c864342c943..89f88ddc554 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -171,11 +171,6 @@ brightness_power = 2 brightness_color = "#da0205" -/obj/machinery/light/small/red - brightness_range = 5 - brightness_power = 1 - brightness_color = "#da0205" - /obj/machinery/light/spot name = "spotlight" fitting = "large tube" diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm index 3a661d6f917..232adb345b8 100644 --- a/code/modules/power/solar.dm +++ b/code/modules/power/solar.dm @@ -348,8 +348,9 @@ var/list/solars_list = list() /obj/machinery/power/solar_control/initialize() ..() - if(!connect_to_network()) return + if(!powernet) return set_panels(cdir) + connect_to_network() /obj/machinery/power/solar_control/update_icon() if(stat & BROKEN) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index a280de4ecae..8062b6e9dac 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -189,7 +189,7 @@ update_held_icon() //update timing - user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) + user.setClickCooldown(4) user.setMoveCooldown(move_delay) next_fire_time = world.time + fire_delay diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index 0bfc339ce0b..17f89ee1611 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -136,7 +136,6 @@ /obj/item/projectile/bullet/pistol/rubber //"rubber" bullets name = "rubber bullet" - check_armour = "melee" damage = 10 agony = 40 embed = 0 @@ -151,7 +150,6 @@ /obj/item/projectile/bullet/shotgun/beanbag //because beanbags are not bullets name = "beanbag" - check_armour = "melee" damage = 20 agony = 60 embed = 0 @@ -236,4 +234,4 @@ /obj/item/projectile/bullet/pistol/cap/process() loc = null - qdel(src) + qdel(src) \ No newline at end of file diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm index b7a22b560f8..063acf750b6 100644 --- a/code/modules/projectiles/projectile/energy.dm +++ b/code/modules/projectiles/projectile/energy.dm @@ -22,13 +22,13 @@ //blind adjacent people for (var/mob/living/carbon/M in viewers(T, flash_range)) - if(M.eyecheck() < FLASH_PROTECTION_MODERATE) + if(M.eyecheck() < 1) flick("e_flash", M.flash) //snap pop playsound(src, 'sound/effects/snap.ogg', 50, 1) src.visible_message("\The [src] explodes in a bright flash!") - + new /obj/effect/decal/cleanable/ash(src.loc) //always use src.loc so that ash doesn't end up inside windows new /obj/effect/effect/sparks(T) new /obj/effect/effect/smoke/illumination(T, brightness=max(flash_range*2, brightness), lifetime=light_duration) diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm index 5014003f31e..8147c0ff56e 100644 --- a/code/modules/reagents/Chemistry-Holder.dm +++ b/code/modules/reagents/Chemistry-Holder.dm @@ -304,7 +304,7 @@ trans_to(target, amount, multiplier, copy) /datum/reagents/proc/trans_id_to(var/atom/target, var/id, var/amount = 1) - if (!target || !target.reagents || !target.simulated) + if (!target || !target.reagents) return amount = min(amount, get_reagent_amount(id)) @@ -333,7 +333,7 @@ return /datum/reagents/proc/touch_mob(var/mob/target) - if(!target || !istype(target) || !target.simulated) + if(!target || !istype(target)) return for(var/datum/reagent/current in reagent_list) @@ -342,7 +342,7 @@ update_total() /datum/reagents/proc/touch_turf(var/turf/target) - if(!target || !istype(target) || !target.simulated) + if(!target || !istype(target)) return for(var/datum/reagent/current in reagent_list) @@ -351,7 +351,7 @@ update_total() /datum/reagents/proc/touch_obj(var/obj/target) - if(!target || !istype(target) || !target.simulated) + if(!target || !istype(target)) return for(var/datum/reagent/current in reagent_list) @@ -370,7 +370,7 @@ return trans_to_mob(target, amount, CHEM_TOUCH, perm, copy) /datum/reagents/proc/trans_to_mob(var/mob/target, var/amount = 1, var/type = CHEM_BLOOD, var/multiplier = 1, var/copy = 0) // Transfer after checking into which holder... - if(!target || !istype(target) || !target.simulated) + if(!target || !istype(target)) return if(iscarbon(target)) var/mob/living/carbon/C = target @@ -389,7 +389,7 @@ R.touch_mob(target) /datum/reagents/proc/trans_to_turf(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Turfs don't have any reagents (at least, for now). Just touch it. - if(!target || !target.simulated) + if(!target) return var/datum/reagents/R = new /datum/reagents(amount * multiplier) @@ -398,7 +398,7 @@ return /datum/reagents/proc/trans_to_obj(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0) // Objects may or may not; if they do, it's probably a beaker or something and we need to transfer properly; otherwise, just touch. - if(!target || !target.simulated) + if(!target) return if(!target.reagents) diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm index 1aebb805e91..d597e9d8efe 100644 --- a/code/modules/reagents/Chemistry-Machinery.dm +++ b/code/modules/reagents/Chemistry-Machinery.dm @@ -72,8 +72,13 @@ return /obj/machinery/chem_master/Topic(href, href_list) - if(..()) - return 1 + if(stat & (BROKEN|NOPOWER)) return + if(usr.stat || usr.restrained()) return + if(!in_range(src, usr)) return + + src.add_fingerprint(usr) + usr.set_machine(src) + if (href_list["ejectp"]) if(loaded_pill_bottle) @@ -223,7 +228,7 @@ return src.attack_hand(user) /obj/machinery/chem_master/attack_hand(mob/user as mob) - if(inoperable()) + if(stat & BROKEN) return user.set_machine(src) if(!(user.client in has_sprites)) @@ -332,8 +337,11 @@ /obj/machinery/computer/pandemic/Topic(href, href_list) - if(..()) - return 1 + if(stat & (NOPOWER|BROKEN)) return + if(usr.stat || usr.restrained()) return + if(!in_range(src, usr)) return + + usr.set_machine(src) if(!beaker) return if (href_list["create_vaccine"]) @@ -641,12 +649,10 @@ return 0 /obj/machinery/reagentgrinder/attack_hand(mob/user as mob) + user.set_machine(src) interact(user) /obj/machinery/reagentgrinder/interact(mob/user as mob) // The microwave Menu - if(inoperable()) - return - user.set_machine(src) var/is_chamber_empty = 0 var/is_beaker_ready = 0 var/processing_chamber = "" @@ -693,8 +699,8 @@ /obj/machinery/reagentgrinder/Topic(href, href_list) if(..()) - return 1 - + return + usr.set_machine(src) switch(href_list["action"]) if ("grind") grind() @@ -703,7 +709,7 @@ if ("detach") detach() src.updateUsrDialog() - return 1 + return /obj/machinery/reagentgrinder/proc/detach() 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 2511a715872..f1c82a900ad 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm @@ -226,10 +226,6 @@ description = "This is what makes chilis hot." reagent_state = LIQUID color = "#B31008" - var/agony_dose = 5 - var/agony_amount = 2 - var/discomfort_message = "Your insides feel uncomfortably hot!" - var/slime_temp_adj = 10 /datum/reagent/capsaicin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) if(alien == IS_DIONA) @@ -243,82 +239,82 @@ var/mob/living/carbon/human/H = M if(H.species && (H.species.flags & (NO_PAIN))) return - if(dose < agony_dose) - if(prob(5) || dose == metabolism) //dose == metabolism is a very hacky way of forcing the message the first time this procs - M << discomfort_message - else - M.apply_effect(agony_amount, AGONY, 0) + if(dose < 5 && (dose == metabolism || prob(5))) + M << "Your insides feel uncomfortably hot!" + if(dose >= 5) + M.apply_effect(2, AGONY, 0) if(prob(5)) - M.custom_emote(2, "[pick("dry heaves!","coughs!","splutters!")]") - M << "You feel like your insides are burning!" + M.visible_message("[M] [pick("dry heaves!","coughs!","splutters!")]", "You feel like your insides are burning!") if(istype(M, /mob/living/carbon/slime)) - M.bodytemperature += rand(0, 15) + slime_temp_adj + M.bodytemperature += rand(10, 25) holder.remove_reagent("frostoil", 5) -/datum/reagent/capsaicin/condensed +/datum/reagent/condensedcapsaicin name = "Condensed Capsaicin" id = "condensedcapsaicin" description = "A chemical agent used for self-defense and in police work." reagent_state = LIQUID touch_met = 50 // Get rid of it quickly color = "#B31008" - agony_dose = 0.5 - agony_amount = 4 - discomfort_message = "You feel like your insides are burning!" - slime_temp_adj = 15 -/datum/reagent/capsaicin/condensed/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) +/datum/reagent/condensedcapsaicin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + M.adjustToxLoss(0.5 * removed) + +/datum/reagent/condensedcapsaicin/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) var/eyes_covered = 0 var/mouth_covered = 0 - var/no_pain = 0 - var/obj/item/eye_protection = null - var/obj/item/face_protection = null - - var/list/protection + var/obj/item/safe_thing = null if(istype(M, /mob/living/carbon/human)) var/mob/living/carbon/human/H = M - protection = list(H.head, H.glasses, H.wear_mask) if(H.species && (H.species.flags & NO_PAIN)) - no_pain = 1 //TODO: living-level can_feel_pain() proc - else - protection = list(M.wear_mask) - - for(var/obj/item/I in protection) - if(I) - if(I.body_parts_covered & EYES) + return + if(H.head) + if(H.head.body_parts_covered & EYES) eyes_covered = 1 - eye_protection = I.name - if((I.body_parts_covered & FACE) && !(I.item_flags & FLEXIBLEMATERIAL)) + safe_thing = H.head + if((H.head.body_parts_covered & FACE) && !(H.head.item_flags & FLEXIBLEMATERIAL)) mouth_covered = 1 - face_protection = I.name - - var/message = null - if(eyes_covered) - if(!mouth_covered) - message = "Your [eye_protection] protects your eyes from the pepperspray!" - else - message = "The pepperspray gets in your eyes!" - if(mouth_covered) - M.eye_blurry = max(M.eye_blurry, 15) - M.eye_blind = max(M.eye_blind, 5) - else - M.eye_blurry = max(M.eye_blurry, 25) - M.eye_blind = max(M.eye_blind, 10) - - if(mouth_covered) - if(!message) - message = "Your [face_protection] protects you from the pepperspray!" - else if(!no_pain) - message = "Your face and throat burn!" - if(prob(25)) - M.custom_emote(2, "[pick("coughs!","coughs hysterically!","splutters!")]") + safe_thing = H.head + if(H.wear_mask) + if(!eyes_covered && H.wear_mask.body_parts_covered & EYES) + eyes_covered = 1 + safe_thing = H.wear_mask + if(!mouth_covered && (H.wear_mask.body_parts_covered & FACE) && !(H.wear_mask.item_flags & FLEXIBLEMATERIAL)) + mouth_covered = 1 + safe_thing = H.wear_mask + if(H.glasses && H.glasses.body_parts_covered & EYES) + if(!eyes_covered) + eyes_covered = 1 + if(!safe_thing) + safe_thing = H.glasses + if(eyes_covered && mouth_covered) + M << "Your [safe_thing] protects you from the pepperspray!" + return + else if(eyes_covered) + M << "Your [safe_thing] protect you from most of the pepperspray!" + M.eye_blurry = max(M.eye_blurry, 15) + M.eye_blind = max(M.eye_blind, 5) M.Stun(5) M.Weaken(5) + return + else if (mouth_covered) // Mouth cover is better than eye cover + M << "Your [safe_thing] protects your face from the pepperspray!" + M.eye_blurry = max(M.eye_blurry, 5) + return + else // Oh dear :D + M << "You're sprayed directly in the eyes with pepperspray!" + M.eye_blurry = max(M.eye_blurry, 25) + M.eye_blind = max(M.eye_blind, 10) + M.Stun(5) + M.Weaken(5) + return /datum/reagent/condensedcapsaicin/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) if(ishuman(M)) var/mob/living/carbon/human/H = M - if(H.species && (H.species.flags & NO_PAIN)) + if(H.species && (H.species.flags & (NO_PAIN))) return if(dose == metabolism) M << "You feel like your insides are burning!" diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm index df9fa65defd..d981734ec94 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm @@ -177,7 +177,11 @@ W.visible_message("The fungi are completely dissolved by the solution!") /datum/reagent/toxin/plantbgone/touch_obj(var/obj/O, var/volume) - if(istype(O, /obj/effect/plant)) + if(istype(O, /obj/effect/alien/weeds/)) + var/obj/effect/alien/weeds/alien_weeds = O + alien_weeds.health -= rand(15, 35) + alien_weeds.healthcheck() + else if(istype(O, /obj/effect/plant)) qdel(O) /datum/reagent/toxin/plantbgone/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm index c022b65d18d..f5c44ecaa6a 100644 --- a/code/modules/reagents/Chemistry-Recipes.dm +++ b/code/modules/reagents/Chemistry-Recipes.dm @@ -1094,7 +1094,7 @@ var/list/borks = typesof(/obj/item/weapon/reagent_containers/food/snacks) - /obj/item/weapon/reagent_containers/food/snacks playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1) for(var/mob/living/carbon/human/M in viewers(get_turf(holder.my_atom), null)) - if(M.eyecheck() < FLASH_PROTECTION_MODERATE) + if(M.eyecheck() <= 0) flick("e_flash", M.flash) for(var/i = 1, i <= 4 + rand(1,2), i++) diff --git a/code/modules/reagents/dispenser/dispenser2.dm b/code/modules/reagents/dispenser/dispenser2.dm index 5433b3b693c..4677214ac88 100644 --- a/code/modules/reagents/dispenser/dispenser2.dm +++ b/code/modules/reagents/dispenser/dispenser2.dm @@ -113,6 +113,9 @@ return ..() /obj/machinery/chemical_dispenser/cartridge/ui_interact(mob/user, ui_key = "main",var/datum/nanoui/ui = null, var/force_open = 1) + if(stat & (BROKEN|NOPOWER)) return + if(user.stat || user.restrained()) return + // this is the data which will be sent to the ui var/data[0] data["amount"] = amount @@ -145,8 +148,8 @@ ui.open() /obj/machinery/chemical_dispenser/cartridge/Topic(href, href_list) - if(..()) - return 1 + if(stat & (NOPOWER|BROKEN)) + return 0 // don't update UIs attached to this object if(href_list["amount"]) amount = round(text2num(href_list["amount"]), 1) // round to nearest 1 @@ -168,7 +171,9 @@ return 1 // update UIs attached to this object /obj/machinery/chemical_dispenser/cartridge/attack_ai(mob/user as mob) - ui_interact(user) + src.attack_hand(user) /obj/machinery/chemical_dispenser/cartridge/attack_hand(mob/user as mob) + if(stat & BROKEN) + return ui_interact(user) diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index c154ba8dfc5..3972213048e 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -25,6 +25,11 @@ /obj/item/weapon/reagent_containers/attack_self(mob/user as mob) return +/obj/item/weapon/reagent_containers/attack(mob/M as mob, mob/user as mob, def_zone) + if(can_operate(M))//Checks if mob is lying down on table for surgery + if(do_surgery(M, user, src)) + return + /obj/item/weapon/reagent_containers/afterattack(obj/target, mob/user, flag) return @@ -101,7 +106,6 @@ user << "\The [blocked] is in the way!" return - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) //puts a limit on how fast people can eat/drink things self_feed_message(user) reagents.trans_to_mob(user, amount_per_transfer_from_this, CHEM_INGEST) feed_sound(user) @@ -119,7 +123,6 @@ other_feed_message_start(user, target) - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(!do_mob(user, target)) return diff --git a/code/modules/reagents/reagent_containers/food/condiment.dm b/code/modules/reagents/reagent_containers/food/condiment.dm index b5fd5e53444..a8184ac8157 100644 --- a/code/modules/reagents/reagent_containers/food/condiment.dm +++ b/code/modules/reagents/reagent_containers/food/condiment.dm @@ -25,10 +25,7 @@ if(standard_feed_mob(user, M)) return - afterattack(var/obj/target, var/mob/user, var/proximity) - if(!proximity) - return - + afterattack(var/obj/target, var/mob/user, var/flag) if(standard_dispenser_refill(user, target)) return if(standard_pour_into(user, target)) diff --git a/code/modules/reagents/reagent_containers/food/drinks.dm b/code/modules/reagents/reagent_containers/food/drinks.dm index d5526c9b1d8..7fd9bec3a20 100644 --- a/code/modules/reagents/reagent_containers/food/drinks.dm +++ b/code/modules/reagents/reagent_containers/food/drinks.dm @@ -23,9 +23,6 @@ flags |= OPENCONTAINER attack(mob/M as mob, mob/user as mob, def_zone) - if(force && !(flags & NOBLUDGEON) && user.a_intent == I_HURT) - return ..() - if(standard_feed_mob(user, M)) return @@ -96,6 +93,10 @@ volume = 150 flags = CONDUCT | OPENCONTAINER +/obj/item/weapon/reagent_containers/food/drinks/golden_cup/tournament_26_06_2011 + desc = "A golden cup. It will be presented to a winner of tournament 26 june and name of the winner will be graved on it." + + ///////////////////////////////////////////////Drinks //Notes by Darem: Drinks are simply containers that start preloaded. Unlike condiments, the contents can be ingested directly // rather then having to add it to something else first. They should only contain liquids. They have a default container size of 50. diff --git a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm index c3f89b2f598..3d832bf6a28 100644 --- a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm +++ b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm @@ -32,7 +32,7 @@ var/throw_dist = get_dist(throw_source, loc) if(speed >= throw_speed && smash_check(throw_dist)) //not as reliable as smashing directly if(reagents) - hit_atom.visible_message("The contents of \the [src] splash all over [hit_atom]!") + hit_atom.visible_message("The contents of the [src] splash all over [hit_atom]!") reagents.splash(hit_atom, reagents.total_volume) src.smash(loc, hit_atom) @@ -117,36 +117,59 @@ else set_light(0) -/obj/item/weapon/reagent_containers/food/drinks/bottle/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) - var/blocked = ..() - - if(user.a_intent != I_HURT) +/obj/item/weapon/reagent_containers/food/drinks/bottle/attack(mob/living/target as mob, mob/living/user as mob) + if(!target) return - if(!smash_check(1)) - return //won't always break on the first hit - + + if(user.a_intent != I_HURT || !isGlass) + return ..() + + var/affecting = user.zone_sel.selecting //Find what the player is aiming at + + var/armor_block = 0 //Get the target's armour values for normal attack damage. + var/armor_duration = 0 //The more force the bottle has, the longer the duration. + + //Calculating duration and calculating damage. + armor_block = target.run_armor_check(affecting, "melee") + + //force will counteract armour, but will never increase duration + armor_duration = smash_duration + min(0, force - target.getarmor(affecting, "melee") + 10) + + //Apply the damage! + target.apply_damage(force, BRUTE, affecting, armor_block, sharp=0) + // You are going to knock someone out for longer if they are not wearing a helmet. - var/weaken_duration = 0 - if(blocked < 2) - weaken_duration = smash_duration + min(0, force - target.getarmor(hit_zone, "melee") + 10) - + var/do_smash = smash_check(1) //won't always break on the first hit var/mob/living/carbon/human/H = target - if(istype(H) && H.headcheck(hit_zone)) - var/obj/item/organ/affecting = H.get_organ(hit_zone) //headcheck should ensure that affecting is not null - user.visible_message("[user] smashes [src] into [H]'s [affecting.name]!") - if(weaken_duration) - target.apply_effect(min(weaken_duration, 5), WEAKEN, blocked) // Never weaken more than a flash! + if(do_smash && istype(H) && H.headcheck(affecting)) + //Display an attack message. + var/obj/item/organ/O = H.get_organ(affecting) + user.visible_message("[user] smashes [src] into [H]'s [O.name]!") + //Weaken the target for the duration that we calculated and divide it by 5. + if(armor_duration) + target.apply_effect(min(armor_duration, 5) , WEAKEN, armor_block) // Never weaken more than a flash! else - user.visible_message("\The [user] smashes [src] into [target]!") + //Default attack message and don't weaken the target. + for(var/mob/O in viewers(user, null)) + if(target != user) O.show_message(text("\red [target] has been attacked with a bottle of [src.name], by [user]!"), 1) + else O.show_message(text("\red [target] has attacked \himself with a bottle of [src.name]!"), 1) - //The reagents in the bottle splash all over the target, thanks for the idea Nodrak - if(reagents) - user.visible_message("The contents of \the [src] splash all over [target]!") - reagents.splash(target, reagents.total_volume) + //Attack logs + user.attack_log += text("\[[time_stamp()]\] Has attacked [target.name] ([target.ckey]) with a bottle!") + target.attack_log += text("\[[time_stamp()]\] Has been smashed with a bottle by [user.name] ([user.ckey])") + msg_admin_attack("[user.name] ([user.ckey]) attacked [target.name] ([target.ckey]) with a bottle. (INTENT: [uppertext(user.a_intent)]) (JMP)") - //Finally, smash the bottle. This kills (qdel) the bottle. - var/obj/item/weapon/broken_bottle/B = smash(target.loc, target) - user.put_in_active_hand(B) + if(do_smash) + //The reagents in the bottle splash all over the target, thanks for the idea Nodrak + if(reagents) + user.visible_message("The contents of the [src] splash all over [target]!") + reagents.splash(target, reagents.total_volume) + + //Finally, smash the bottle. This kills (qdel) the bottle. + var/obj/item/weapon/broken_bottle/B = src.smash(target.loc, target) + user.put_in_active_hand(B) + + return //Keeping this here for now, I'll ask if I should keep it here. /obj/item/weapon/broken_bottle @@ -430,3 +453,5 @@ New() ..() reagents.add_reagent("ale", 30) + + diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm index 6939c6553bc..12af8c4a7f6 100644 --- a/code/modules/reagents/reagent_containers/food/snacks.dm +++ b/code/modules/reagents/reagent_containers/food/snacks.dm @@ -41,8 +41,6 @@ return 0 if(istype(M, /mob/living/carbon)) - //TODO: replace with standard_feed_mob() call. - var/fullness = M.nutrition + (M.reagents.get_reagent_amount("nutriment") * 25) if(M == user) //If you're eating it yourself if(istype(M,/mob/living/carbon/human)) @@ -55,7 +53,6 @@ user << "\The [blocked] is in the way!" return - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) //puts a limit on how fast people can eat/drink things if (fullness <= 50) M << "You hungrily chew out a piece of [src] and gobble it!" if (fullness > 50 && fullness <= 150) @@ -68,23 +65,35 @@ M << "You cannot force any more of [src] to go down your throat." return 0 else - if(!M.can_force_feed(user, src)) - return + if(istype(M,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + if(!H.check_has_mouth()) + user << "Where do you intend to put \the [src]? \The [H] doesn't have a mouth!" + return + var/obj/item/blocked = H.check_mouth_coverage() + if(blocked) + user << "\The [blocked] is in the way!" + return + + if(!istype(M, /mob/living/carbon/slime)) //If you're feeding it to someone else. + + if (fullness <= (550 * (1 + M.overeatduration / 1000))) + user.visible_message("[user] attempts to feed [M] [src].") + else + user.visible_message("[user] cannot force anymore of [src] down [M]'s throat.") + return 0 + + if(!do_mob(user, M)) return + + M.attack_log += text("\[[time_stamp()]\] Has been fed [src.name] by [user.name] ([user.ckey]) Reagents: [reagentlist(src)]") + user.attack_log += text("\[[time_stamp()]\] Fed [src.name] by [M.name] ([M.ckey]) Reagents: [reagentlist(src)]") + msg_admin_attack("[key_name(user)] fed [key_name(M)] with [src.name] Reagents: [reagentlist(src)] (INTENT: [uppertext(user.a_intent)])") + + user.visible_message("[user] feeds [M] [src].") - if (fullness <= (550 * (1 + M.overeatduration / 1000))) - user.visible_message("[user] attempts to feed [M] [src].") else - user.visible_message("[user] cannot force anymore of [src] down [M]'s throat.") - return 0 - - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - if(!do_mob(user, M)) return - - M.attack_log += text("\[[time_stamp()]\] Has been fed [src.name] by [user.name] ([user.ckey]) Reagents: [reagentlist(src)]") - user.attack_log += text("\[[time_stamp()]\] Fed [src.name] by [M.name] ([M.ckey]) Reagents: [reagentlist(src)]") - msg_admin_attack("[key_name(user)] fed [key_name(M)] with [src.name] Reagents: [reagentlist(src)] (INTENT: [uppertext(user.a_intent)])") - - user.visible_message("[user] feeds [M] [src].") + user << "This creature does not seem to have a mouth!" + return if(reagents) //Handle ingestion of the reagent. playsound(M.loc,'sound/items/eatfood.ogg', rand(10,50), 1) diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 28b4704fdd7..7632f8456fc 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -37,8 +37,6 @@ user << "You cannot inject a robotic limb." return - user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) - user.do_attack_animation(M) user << "You inject [M] with [src]." M << "You feel a tiny prick!" diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index 99a6dc28f73..e31c0096770 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -18,11 +18,17 @@ icon_state = "pill[rand(1, 20)]" attack(mob/M as mob, mob/user as mob, def_zone) - //TODO: replace with standard_feed_mob() call. - if(M == user) - if(!M.can_eat(src)) - return + + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + if(!H.check_has_mouth()) + user << "Where do you intend to put \the [src]? You don't have a mouth!" + return + var/obj/item/blocked = H.check_mouth_coverage() + if(blocked) + user << "\The [blocked] is in the way!" + return M << "You swallow \the [src]." M.drop_from_inventory(src) //icon update @@ -32,12 +38,18 @@ return 1 else if(istype(M, /mob/living/carbon/human)) - if(!M.can_force_feed(user, src)) + + var/mob/living/carbon/human/H = M + if(!H.check_has_mouth()) + user << "Where do you intend to put \the [src]? \The [H] doesn't have a mouth!" + return + var/obj/item/blocked = H.check_mouth_coverage() + if(blocked) + user << "\The [blocked] is in the way!" return user.visible_message("[user] attempts to force [M] to swallow \the [src].") - user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(!do_mob(user, M)) return diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index 426783fd0b3..19ac8c62fbc 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -176,9 +176,6 @@ else user.visible_message("[user] begins hunting for an injection port on [target]'s suit!") - user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) - user.do_attack_animation(target) - if(!do_mob(user, target, injtime)) return diff --git a/code/modules/research/xenoarchaeology/artifact/artifact_unknown.dm b/code/modules/research/xenoarchaeology/artifact/artifact_unknown.dm index 13014d41c2f..a881dc65297 100644 --- a/code/modules/research/xenoarchaeology/artifact/artifact_unknown.dm +++ b/code/modules/research/xenoarchaeology/artifact/artifact_unknown.dm @@ -82,34 +82,37 @@ var/list/valid_secondary_effect_types = list(\ if(prob(75)) secondary_effect.ToggleActivate(0) - icon_num = rand(0,13) + icon_num = rand(0,11) icon_state = "ano[icon_num]0" if(icon_num == 7 || icon_num == 8) - name = "large alien crystal" + name = "large crystal" desc = pick("It shines faintly as it catches the light.",\ "It appears to have a faint inner glow.",\ "It seems to draw you inward as you look it at.",\ "Something twinkles faintly as you look at it.",\ "It's mesmerizing to behold.") - if(prob(75)) + if(prob(50)) my_effect.trigger = TRIGGER_ENERGY - else if(icon_num == 1 || icon_num == 6) - desc = "There appears to be some kind of environmental scanner on it." - if(prob(75)) - my_effect.trigger = rand(5,8) - else if(icon_num == 9 || icon_num == 11 || icon_num == 13) + else if(icon_num == 9) name = "alien computer" + desc = "It is covered in strange markings." if(prob(75)) my_effect.trigger = TRIGGER_TOUCH - else if(icon_num == 2 || icon_num == 3 || icon_num == 4) - desc = "A large alien device, there appear to be vents in the side." - if(prob(75)) - my_effect.trigger = rand(7,12) - else if(icon_num == 10 || icon_num == 12) + else if(icon_num == 10) + desc = "A large alien device, there appear to be some kind of vents in the side." + if(prob(50)) + my_effect.trigger = rand(6,12) + else if(icon_num == 11) name = "sealed alien pod" - if(prob(75)) + desc = "A strange alien device." + if(prob(25)) my_effect.trigger = rand(1,4) +#define TRIGGER_PHORON 9 +#define TRIGGER_OXY 10 +#define TRIGGER_CO2 11 +#define TRIGGER_NITRO 12 + /obj/machinery/artifact/process() var/turf/L = loc diff --git a/code/modules/spells/general/rune_write.dm b/code/modules/spells/general/rune_write.dm index c28289d60f4..c110a76ac14 100644 --- a/code/modules/spells/general/rune_write.dm +++ b/code/modules/spells/general/rune_write.dm @@ -21,10 +21,6 @@ runerandom() var/list/runes = list("Teleport", "Teleport Other", "Spawn a Tome", "Change Construct Type", "Convert", "EMP", "Drain Blood", "See Invisible", "Resurrect", "Hide Runes", "Reveal Runes", "Astral Journey", "Manifest a Ghost", "Imbue Talisman", "Sacrifice", "Wall", "Free Cultist", "Summon Cultist", "Deafen", "Blind", "BloodBoil", "Communicate", "Stun") var/r = input(user, "Choose a rune to scribe", "Rune Scribing") in runes //not cancellable. - if(locate(/obj/effect/rune) in user.loc) - user << "There is already a rune in this location." - return - var/obj/effect/rune/R = new /obj/effect/rune(user.loc) if(istype(user.loc,/turf)) var/area/A = get_area(user) diff --git a/code/modules/spells/targeted/subjugate.dm b/code/modules/spells/targeted/subjugate.dm index ac5312c3def..8f6efa3c14e 100644 --- a/code/modules/spells/targeted/subjugate.dm +++ b/code/modules/spells/targeted/subjugate.dm @@ -11,9 +11,9 @@ max_targets = 1 - amt_dizziness = 100 - amt_confused = 100 - amt_stuttering = 100 + amt_dizziness = 300 + amt_confused = 300 + amt_stuttering = 300 compatible_mobs = list(/mob/living/carbon/human) diff --git a/code/modules/surgery/encased.dm b/code/modules/surgery/encased.dm index 762c2b71c46..1744cec3d7e 100644 --- a/code/modules/surgery/encased.dm +++ b/code/modules/surgery/encased.dm @@ -172,12 +172,10 @@ affected.createwound(BRUISE, 20) affected.fracture() - - if(affected.internal_organs && affected.internal_organs.len) - if(prob(40)) - var/obj/item/organ/O = pick(affected.internal_organs) //TODO weight by organ size - user.visible_message("A wayward piece of [target]'s [affected.encased] pierces \his [O.name]!") - O.bruise() + + /*if (prob(40)) //TODO: ORGAN REMOVAL UPDATE. + user.visible_message("\red A rib pierces the lung!") + target.rupture_lung()*/ /datum/surgery_step/open_encased/mend allowed_tools = list( diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index be738c01f8b..d352c4aed48 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -12,6 +12,46 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) return affected && affected.open == (affected.encased ? 3 : 2) +////////////////////////////////////////////////////////////////// +// ALIEN EMBRYO SURGERY // +////////////////////////////////////////////////////////////////// +/datum/surgery_step/internal/remove_embryo + allowed_tools = list( + /obj/item/weapon/hemostat = 100, \ + /obj/item/weapon/wirecutters = 75, \ + /obj/item/weapon/material/kitchen/utensil/fork = 20 + ) + blood_level = 2 + + min_duration = 80 + max_duration = 100 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/embryo = 0 + for(var/obj/item/alien_embryo/A in target) + embryo = 1 + break + + if (!hasorgans(target)) + return + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return ..() && affected && embryo && affected.open == 3 && target_zone == "chest" + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/msg = "[user] starts to pull something out from [target]'s ribcage with \the [tool]." + var/self_msg = "You start to pull something out from [target]'s ribcage with \the [tool]." + user.visible_message(msg, self_msg) + target.custom_pain("Something hurts horribly in your chest!",1) + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("\red [user] rips the larva out of [target]'s ribcage!", + "You rip the larva out of [target]'s ribcage!") + + for(var/obj/item/alien_embryo/A in target) + A.loc = A.loc.loc + + ////////////////////////////////////////////////////////////////// // CHEST INTERNAL ORGAN SURGERY // ////////////////////////////////////////////////////////////////// diff --git a/html/changelog.html b/html/changelog.html index 623355b4b59..897f98072d3 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -56,78 +56,6 @@ -->
-

02 November 2015

-

Hubblenaut updated:

-
    -
  • Adds tape for atmospherics.
  • -
  • Tape graphics and algorithm changes. Looks a lot more appealing now.
  • -
  • Starting and ending tape on the same turf will connect it to all surrounding walls/windows.
  • -
  • Lifting a part of the tape will lift an entire tape section.
  • -
  • Mobs on help intent do stop for tape.
  • -
  • Crumpled tape does not affect tape breaking behavior anymore.
  • -
- -

27 October 2015

-

HarpyEagle updated:

-
    -
  • When affected by pepperspray, eye protection now prevents blindness and face protection now prevents stun, instead of face protection doing both.
  • -
- -

21 October 2015

-

Hubblenaut updated:

-
    -
  • Bruise packs are now applied per wound, not per limb.
  • -
  • Bruise packs now use a delay depending on wound severity for applying.
  • -
  • Removed instant healing ability from advanced bruise packs and ointment.
  • -
- -

14 October 2015

-

Hubblenaut updated:

-
    -
  • Airlock backup power test light properly offline when backup power down.
  • -
  • Empty flavor texts no longer draw an empty line on examination.
  • -
  • Material stacks now properly merge upon creation.
  • -
  • Messages for adding to existing stack appear again.
  • -
-

PsiOmegaDelta updated:

-
    -
  • Blobs can now spawn anywhere in maintenance, rather than picking location from a pre-determined list.
  • -
-

TheWelp updated:

-
    -
  • Removed higher Secret player requirements.
  • -
-

Zuhayr updated:

-
    -
  • Removed facehuggers, alien embryos, and embryo removal surgery.
  • -
  • Xenomorph Queens (or infested surgeons...) can now add a hive node to a victim in order to slave them to the hive.
  • -
  • Xenomorph brute/burn mods were tweaked to buff them significantly.
  • -
  • Alien larvae now hatch from eggs when ghosts click on them.
  • -
  • Alien larvae now gain progression towards adulthood from being inside a human with blood, which they drink.
  • -
  • Alien weeds now use the vine system.
  • -
- -

11 October 2015

-

HarpyEagle updated:

-
    -
  • Fabricated power cells start uncharged.
  • -
-

Hubblenaut updated:

-
    -
  • Light replacers can be refilled by clicking on a storage item.
  • -
  • Light replacers now hold up to 32 light bulbs.
  • -
  • Light replacers can be obtained through janitorial supply crates.
  • -
  • A sheet of glass fills the light replacer by 16 bulbs.
  • -
- -

10 October 2015

-

HarpyEagle updated:

-
    -
  • Rubber bullets and beanbags now are now resisted by melee armour.
  • -
  • Fixed a couple of bugs causing phoron gas fires to burn cooler and slower than they were supposed to.
  • -
  • Merc bombs are now appropriately explosive again. Same goes for bombs made by toxins.
  • -
-

26 September 2015

PsiOmegaDelta updated: