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 dba966e9fb..501c49ae55 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 7e91a26b3f..674be3fc5e 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 73b323ba77..e93bf45085 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 c72678fdc8..e99f62d2b7 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 b5987c0ce1..0000000000 --- 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 c5ecfb631a..0000000000 --- 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 3abe6c1aa1..f8a4b12b96 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 ca5c60be9d..8583628114 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 e70e3159b6..fb79b29cb9 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 3c65b03f73..0cca5569c2 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 01cbc21386..0000000000 --- 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 172a62c08e..d6fa155cfc 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 85546a79d7..3c247d6c7f 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 659bd2e21a..1f8c871ad3 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 ae099c64be..e5560e5ce0 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 a521225602..fa99f001f3 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 36f5216045..08cbeebca9 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 011ae5ebe6..faf7526a9c 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 bbae60800e..072dd88bee 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 1a3f9aa67d..056fbd1865 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 11ea718f8c..b5f62868dc 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 ca0b39aaef..4cc8afff6c 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 e8517dbf4e..98a44442dc 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 4240708cc2..c17b6c0f86 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 535161e08a..6aadd775e3 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 350401df13..795970068c 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 b17277aaae..4f7b9ab49d 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 bf68c71823..ba82a064f6 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 bbff09a636..c3ffef61bb 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 afa21ebc1e..70e2219440 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 932719c856..cba7a96ef4 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 05b2d48437..4f98bbcc2b 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 881dea4dbd..412e9033d4 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 9c79a68925..038cf351ab 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 5fcfce49c7..e1b0735b1e 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 b4409316fe..ea98f32558 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 642514115b..11f3c55ef5 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 0cd534870d..0a4846d763 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 5ca6ed82a2..cfdb25c9a5 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 1923c3fbf9..2d8753ce1a 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 de7a9d153e..7c3e903b14 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 6972aee554..12527f0877 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 9dad2ecfa9..005d9dce91 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 8570f84e74..7a4981c0fa 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 0ac412ca7e..e3ab6b151b 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 0ec94c44f9..b7a38fd8d5 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 d3694dd8d3..7926fd22be 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 04418f0860..35cd31399e 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 0a4a173144..9b7abebded 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 6d69941b81..455c6256a4 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 a8ca3f1dbe..d02d3522a4 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 24754c2270..aa9f939493 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 034ce94686..3fa93e7e46 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 ed518a6f53..9dfe1c3b19 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 fb4716043f..547931a511 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 887bfe575a..9fa9ce9ff2 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 1f6e517d58..e0d7ddad3a 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 0f00cbd1cf..cfbe33e5fd 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 a2707fd01f..21b6a0e720 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 0c5b1c4231..b88f34ef51 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 88b53bd342..4135dda5f7 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 164c3dd73c..afe50bc2b7 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 06925300da..d3ba0a96a8 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 d70333bc43..2c3fc80a31 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 53517d91b0..cc805cf95b 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 7651ac7bcb..d244fd6b5c 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 db11c4de50..0000000000 --- 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 db8a66ac72..e32b58e098 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 24f6ad53b3..484c185a14 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 6f5e2d3d53..8e3fed202d 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 46fd181a69..43b58a1726 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 387ca7ed9b..d01b380925 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 60f5b7a56f..9677a73345 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 61ea05aa26..c88ad3e641 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 655727a62a..4f168556d2 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 71a03b982c..d0e81e9548 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 fc9ac7eb32..18181df6b0 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 aab9c1a805..e6d2c995b1 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 cdb87b4d84..50be738ecc 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 3f8ed36499..a67d9e8daf 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 a76fb4f1a1..c23dfcdb51 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 92dd28c61a..0000000000 --- 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 70caa6ba36..78665633cf 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 bbe6e8890a..7a128d7cfa 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 8fca8ba8e9..15eb430a3f 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 a8e4f5ac38..a0340c1cd2 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 640c436ccf..282e7bece6 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 0f5cebc44d..35302dc5dc 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 51e97c66aa..800659307e 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 df94cf95ac..0000000000 --- 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 c16c1a182e..0000000000 --- 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 15a9062862..0000000000 --- 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 05f6bca0e7..0000000000 --- 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 852a0a3dcd..105f2987df 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 bd2b216888..a3e3ad8618 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 076c999edb..7401aac67b 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 035826d138..3d867111cc 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 0000000000..7d0bc76b18 --- /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 1faf83f441..e4840bedc6 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 87895d3950..440cc6a8a2 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 96f375d9e5..449001492b 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 dc7c19c45c..643073055e 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 32b6bde1d4..d7024147d0 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 918739ec8f..967a4375da 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 53ff4c3a75..a76565bf75 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 9154badcc6..11591be4b1 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 29d2b95d88..bd3c4be0d9 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 6f05d00de6..c842170b6b 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 eefc531da1..0000000000 --- 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 82d44027af..0000000000 --- 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 7e9a803766..0000000000 --- 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 07530881fe..0000000000 --- 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 8d9db3f28e..0000000000 --- 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 5708d3c757..0000000000 --- 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 3c2d93073b..0000000000 --- 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 09289c1068..0000000000 --- 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 7b61a86cb4..0000000000 --- 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 7944c7b6e7..0000000000 --- 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 561ffb3ec4..0000000000 --- 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 9cb4f943f8..0000000000 --- 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 1f60cd3bb7..0000000000 --- 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 82843a0555..c6a91faf86 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 894d2cb0a7..a88ba411c2 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 ffc504cd16..c5fadf4463 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 de6972ac01..94e8cd2949 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 fa7bbae559..42e830c4e4 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 b011dd14bc..ce8f89dc56 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 bc5c15fbb0..cf941f678e 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 677063d92e..1f6ec964f4 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 6b875ce5c8..7c605bbcf3 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 7ca66a8260..bc1888f14d 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 2e62403432..4c0d0a755e 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 f9536420e2..bc0f1a376c 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 92396e7752..5433361bbd 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 0faf957787..e8f2cfa918 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 d89873901f..7583deae41 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 f51c2ad9a6..44cde40ced 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 a4379cf871..fdb20ab119 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 158c9ef876..71a669ab66 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 83526bfc03..5d3915c7fd 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 b511fb432b..c42f76623c 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 c60a4503cb..4505c666fd 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 c67249dfe5..548eee230b 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 5ca32e24d0..8d40ef9d5a 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 57e3427163..0000000000 --- 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 4c40057812..429e82b3d0 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 e9d099ea2a..54c7f9a969 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 ba6dd3b441..20f86d4dde 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 b4d9d1614d..0000000000 --- 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 11ae140777..78129c4910 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 0ec23c0758..68680a432c 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 3d46417b2d..4a25b7ce29 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 8ea84562dd..0ff79e2aa2 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 cd5ec50ac8..0000000000 --- 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 1728b61008..50f46b4bb4 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 789fcf4857..b0a9c2e430 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 b8bdb85edd..d77493b0b3 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 4fa41f1a5b..e4c31a1447 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 0000000000..c60d8bca1d --- /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 691ac149bd..335b566092 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 b24fdd50c3..a73e363904 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 3c89ed183b..1c5e88ce59 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 504577c7d3..6cb8a46475 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 1d148b96ea..289b4a2273 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 30d2a4cd0b..e634f5224b 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 6832f096f2..d068e33e6c 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 0815dac436..5e7a6e2d90 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 64ca2469b0..d7a989756d 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 1032908c83..5f7b07489b 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 33699cf6df..f3d7ffd848 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 16a00368a8..ece00da5ee 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 2aafb286fd..42d5c6e6f6 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 39406eb6c8..322d08dc9f 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 bbd43530a8..d0a8e09207 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 df3c588a34..0c578cee77 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 3905e272f2..acce1e39b1 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 fe4d6ed56d..bcb48f0bb0 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 c54ca849e0..ee5e786db8 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 9bbec2c528..34546662c3 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 ee1d62529a..10b9d0ebbf 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 87bfc76176..995105a2bc 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 664e00d275..2367ed5b43 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 d535971a21..1e2f7d1e52 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 f1049da61e..0b1233085f 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 7d89a07d67..850f5114c0 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 c864342c94..89f88ddc55 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 3a661d6f91..232adb345b 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 a280de4eca..8062b6e9da 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 0bfc339ce0..17f89ee161 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 b7a22b560f..063acf750b 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 5014003f31..8147c0ff56 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 1aebb805e9..d597e9d8ef 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 2511a71587..f1c82a900a 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 df9fa65def..d981734ec9 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 c022b65d18..f5c44ecaa6 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 5433b3b693..4677214ac8 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 c154ba8dfc..3972213048 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 b5fd5e5344..a8184ac815 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 d5526c9b1d..7fd9bec3a2 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 c3f89b2f59..3d832bf6a2 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 6939c6553b..12af8c4a7f 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 28b4704fdd..7632f8456f 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 99a6dc28f7..e31c009677 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 426783fd0b..19ac8c62fb 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 13014d41c2..a881dc6529 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 c28289d60f..c110a76ac1 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 ac5312c3de..8f6efa3c14 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 762c2b71c4..1744cec3d7 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 be738c01f8..d352c4aed4 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 623355b4b5..897f98072d 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: